xref: /linux/drivers/gpu/drm/imx/dc/dc-fu.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
1*0e177d5cSLiu Ying // SPDX-License-Identifier: GPL-2.0+
2*0e177d5cSLiu Ying /*
3*0e177d5cSLiu Ying  * Copyright 2024 NXP
4*0e177d5cSLiu Ying  */
5*0e177d5cSLiu Ying 
6*0e177d5cSLiu Ying #include <linux/bitfield.h>
7*0e177d5cSLiu Ying #include <linux/bitops.h>
8*0e177d5cSLiu Ying #include <linux/bits.h>
9*0e177d5cSLiu Ying #include <linux/math.h>
10*0e177d5cSLiu Ying 
11*0e177d5cSLiu Ying #include "dc-fu.h"
12*0e177d5cSLiu Ying #include "dc-pe.h"
13*0e177d5cSLiu Ying 
14*0e177d5cSLiu Ying /* STATICCONTROL */
15*0e177d5cSLiu Ying #define SHDLDREQSTICKY_MASK		GENMASK(31, 24)
16*0e177d5cSLiu Ying #define SHDLDREQSTICKY(x)		FIELD_PREP(SHDLDREQSTICKY_MASK, (x))
17*0e177d5cSLiu Ying #define BASEADDRESSAUTOUPDATE_MASK	GENMASK(23, 16)
18*0e177d5cSLiu Ying #define BASEADDRESSAUTOUPDATE(x)	FIELD_PREP(BASEADDRESSAUTOUPDATE_MASK, (x))
19*0e177d5cSLiu Ying 
20*0e177d5cSLiu Ying /* BURSTBUFFERMANAGEMENT */
21*0e177d5cSLiu Ying #define SETBURSTLENGTH_MASK		GENMASK(12, 8)
22*0e177d5cSLiu Ying #define SETBURSTLENGTH(x)		FIELD_PREP(SETBURSTLENGTH_MASK, (x))
23*0e177d5cSLiu Ying #define SETNUMBUFFERS_MASK		GENMASK(7, 0)
24*0e177d5cSLiu Ying #define SETNUMBUFFERS(x)		FIELD_PREP(SETNUMBUFFERS_MASK, (x))
25*0e177d5cSLiu Ying #define LINEMODE_MASK			BIT(31)
26*0e177d5cSLiu Ying 
27*0e177d5cSLiu Ying /* SOURCEBUFFERATTRIBUTES */
28*0e177d5cSLiu Ying #define BITSPERPIXEL_MASK		GENMASK(21, 16)
29*0e177d5cSLiu Ying #define BITSPERPIXEL(x)			FIELD_PREP(BITSPERPIXEL_MASK, (x))
30*0e177d5cSLiu Ying #define STRIDE_MASK			GENMASK(15, 0)
31*0e177d5cSLiu Ying #define STRIDE(x)			FIELD_PREP(STRIDE_MASK, (x) - 1)
32*0e177d5cSLiu Ying 
33*0e177d5cSLiu Ying /* SOURCEBUFFERDIMENSION */
34*0e177d5cSLiu Ying #define LINEWIDTH(x)			FIELD_PREP(GENMASK(13, 0), (x))
35*0e177d5cSLiu Ying #define LINECOUNT(x)			FIELD_PREP(GENMASK(29, 16), (x))
36*0e177d5cSLiu Ying 
37*0e177d5cSLiu Ying /* LAYEROFFSET */
38*0e177d5cSLiu Ying #define LAYERXOFFSET(x)			FIELD_PREP(GENMASK(14, 0), (x))
39*0e177d5cSLiu Ying #define LAYERYOFFSET(x)			FIELD_PREP(GENMASK(30, 16), (x))
40*0e177d5cSLiu Ying 
41*0e177d5cSLiu Ying /* CLIPWINDOWOFFSET */
42*0e177d5cSLiu Ying #define CLIPWINDOWXOFFSET(x)		FIELD_PREP(GENMASK(14, 0), (x))
43*0e177d5cSLiu Ying #define CLIPWINDOWYOFFSET(x)		FIELD_PREP(GENMASK(30, 16), (x))
44*0e177d5cSLiu Ying 
45*0e177d5cSLiu Ying /* CLIPWINDOWDIMENSIONS */
46*0e177d5cSLiu Ying #define CLIPWINDOWWIDTH(x)		FIELD_PREP(GENMASK(13, 0), (x) - 1)
47*0e177d5cSLiu Ying #define CLIPWINDOWHEIGHT(x)		FIELD_PREP(GENMASK(29, 16), (x) - 1)
48*0e177d5cSLiu Ying 
49*0e177d5cSLiu Ying enum dc_linemode {
50*0e177d5cSLiu Ying 	/*
51*0e177d5cSLiu Ying 	 * Mandatory setting for operation in the Display Controller.
52*0e177d5cSLiu Ying 	 * Works also for Blit Engine with marginal performance impact.
53*0e177d5cSLiu Ying 	 */
54*0e177d5cSLiu Ying 	LINEMODE_DISPLAY = 0,
55*0e177d5cSLiu Ying };
56*0e177d5cSLiu Ying 
57*0e177d5cSLiu Ying struct dc_fu_pixel_format {
58*0e177d5cSLiu Ying 	u32 pixel_format;
59*0e177d5cSLiu Ying 	u32 bits;
60*0e177d5cSLiu Ying 	u32 shifts;
61*0e177d5cSLiu Ying };
62*0e177d5cSLiu Ying 
63*0e177d5cSLiu Ying static const struct dc_fu_pixel_format pixel_formats[] = {
64*0e177d5cSLiu Ying 	{
65*0e177d5cSLiu Ying 		DRM_FORMAT_XRGB8888,
66*0e177d5cSLiu Ying 		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
67*0e177d5cSLiu Ying 		R_SHIFT(16) | G_SHIFT(8)  | B_SHIFT(0)  | A_SHIFT(0),
68*0e177d5cSLiu Ying 	},
69*0e177d5cSLiu Ying };
70*0e177d5cSLiu Ying 
71*0e177d5cSLiu Ying void dc_fu_get_pixel_format_bits(struct dc_fu *fu, u32 format, u32 *bits)
72*0e177d5cSLiu Ying {
73*0e177d5cSLiu Ying 	int i;
74*0e177d5cSLiu Ying 
75*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
76*0e177d5cSLiu Ying 		if (pixel_formats[i].pixel_format == format) {
77*0e177d5cSLiu Ying 			*bits = pixel_formats[i].bits;
78*0e177d5cSLiu Ying 			return;
79*0e177d5cSLiu Ying 		}
80*0e177d5cSLiu Ying 	}
81*0e177d5cSLiu Ying }
82*0e177d5cSLiu Ying 
83*0e177d5cSLiu Ying void
84*0e177d5cSLiu Ying dc_fu_get_pixel_format_shifts(struct dc_fu *fu, u32 format, u32 *shifts)
85*0e177d5cSLiu Ying {
86*0e177d5cSLiu Ying 	int i;
87*0e177d5cSLiu Ying 
88*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
89*0e177d5cSLiu Ying 		if (pixel_formats[i].pixel_format == format) {
90*0e177d5cSLiu Ying 			*shifts = pixel_formats[i].shifts;
91*0e177d5cSLiu Ying 			return;
92*0e177d5cSLiu Ying 		}
93*0e177d5cSLiu Ying 	}
94*0e177d5cSLiu Ying }
95*0e177d5cSLiu Ying 
96*0e177d5cSLiu Ying static inline void dc_fu_enable_shden(struct dc_fu *fu)
97*0e177d5cSLiu Ying {
98*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, STATICCONTROL, SHDEN, SHDEN);
99*0e177d5cSLiu Ying }
100*0e177d5cSLiu Ying 
101*0e177d5cSLiu Ying static inline void dc_fu_baddr_autoupdate(struct dc_fu *fu, u8 layer_mask)
102*0e177d5cSLiu Ying {
103*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, STATICCONTROL,
104*0e177d5cSLiu Ying 			  BASEADDRESSAUTOUPDATE_MASK,
105*0e177d5cSLiu Ying 			  BASEADDRESSAUTOUPDATE(layer_mask));
106*0e177d5cSLiu Ying }
107*0e177d5cSLiu Ying 
108*0e177d5cSLiu Ying void dc_fu_shdldreq_sticky(struct dc_fu *fu, u8 layer_mask)
109*0e177d5cSLiu Ying {
110*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, STATICCONTROL, SHDLDREQSTICKY_MASK,
111*0e177d5cSLiu Ying 			  SHDLDREQSTICKY(layer_mask));
112*0e177d5cSLiu Ying }
113*0e177d5cSLiu Ying 
114*0e177d5cSLiu Ying static inline void dc_fu_set_linemode(struct dc_fu *fu, enum dc_linemode mode)
115*0e177d5cSLiu Ying {
116*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, BURSTBUFFERMANAGEMENT, LINEMODE_MASK,
117*0e177d5cSLiu Ying 			  mode);
118*0e177d5cSLiu Ying }
119*0e177d5cSLiu Ying 
120*0e177d5cSLiu Ying static inline void dc_fu_set_numbuffers(struct dc_fu *fu, unsigned int num)
121*0e177d5cSLiu Ying {
122*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, BURSTBUFFERMANAGEMENT,
123*0e177d5cSLiu Ying 			  SETNUMBUFFERS_MASK, SETNUMBUFFERS(num));
124*0e177d5cSLiu Ying }
125*0e177d5cSLiu Ying 
126*0e177d5cSLiu Ying static void dc_fu_set_burstlength(struct dc_fu *fu, dma_addr_t baddr)
127*0e177d5cSLiu Ying {
128*0e177d5cSLiu Ying 	unsigned int burst_size, burst_length;
129*0e177d5cSLiu Ying 
130*0e177d5cSLiu Ying 	burst_size = 1 << __ffs(baddr);
131*0e177d5cSLiu Ying 	burst_size = round_up(burst_size, 8);
132*0e177d5cSLiu Ying 	burst_size = min(burst_size, 128U);
133*0e177d5cSLiu Ying 	burst_length = burst_size / 8;
134*0e177d5cSLiu Ying 
135*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, BURSTBUFFERMANAGEMENT,
136*0e177d5cSLiu Ying 			  SETBURSTLENGTH_MASK, SETBURSTLENGTH(burst_length));
137*0e177d5cSLiu Ying }
138*0e177d5cSLiu Ying 
139*0e177d5cSLiu Ying static void dc_fu_set_baseaddress(struct dc_fu *fu, enum dc_fu_frac frac,
140*0e177d5cSLiu Ying 				  dma_addr_t baddr)
141*0e177d5cSLiu Ying {
142*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_baseaddr[frac], baddr);
143*0e177d5cSLiu Ying }
144*0e177d5cSLiu Ying 
145*0e177d5cSLiu Ying void dc_fu_set_src_bpp(struct dc_fu *fu, enum dc_fu_frac frac, unsigned int bpp)
146*0e177d5cSLiu Ying {
147*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, fu->reg_sourcebufferattributes[frac],
148*0e177d5cSLiu Ying 			  BITSPERPIXEL_MASK, BITSPERPIXEL(bpp));
149*0e177d5cSLiu Ying }
150*0e177d5cSLiu Ying 
151*0e177d5cSLiu Ying static void dc_fu_set_src_stride(struct dc_fu *fu, enum dc_fu_frac frac,
152*0e177d5cSLiu Ying 				 unsigned int stride)
153*0e177d5cSLiu Ying {
154*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, fu->reg_sourcebufferattributes[frac],
155*0e177d5cSLiu Ying 			  STRIDE_MASK, STRIDE(stride));
156*0e177d5cSLiu Ying }
157*0e177d5cSLiu Ying 
158*0e177d5cSLiu Ying static void dc_fu_set_src_buf_dimensions(struct dc_fu *fu, enum dc_fu_frac frac,
159*0e177d5cSLiu Ying 					 int w, int h)
160*0e177d5cSLiu Ying {
161*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_sourcebufferdimension[frac],
162*0e177d5cSLiu Ying 		     LINEWIDTH(w) | LINECOUNT(h));
163*0e177d5cSLiu Ying }
164*0e177d5cSLiu Ying 
165*0e177d5cSLiu Ying static inline void dc_fu_layeroffset(struct dc_fu *fu, enum dc_fu_frac frac,
166*0e177d5cSLiu Ying 				     unsigned int x, unsigned int y)
167*0e177d5cSLiu Ying {
168*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_layeroffset[frac],
169*0e177d5cSLiu Ying 		     LAYERXOFFSET(x) | LAYERYOFFSET(y));
170*0e177d5cSLiu Ying }
171*0e177d5cSLiu Ying 
172*0e177d5cSLiu Ying static inline void dc_fu_clipoffset(struct dc_fu *fu, enum dc_fu_frac frac,
173*0e177d5cSLiu Ying 				    unsigned int x, unsigned int y)
174*0e177d5cSLiu Ying {
175*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_clipwindowoffset[frac],
176*0e177d5cSLiu Ying 		     CLIPWINDOWXOFFSET(x) | CLIPWINDOWYOFFSET(y));
177*0e177d5cSLiu Ying }
178*0e177d5cSLiu Ying 
179*0e177d5cSLiu Ying static inline void dc_fu_clipdimensions(struct dc_fu *fu, enum dc_fu_frac frac,
180*0e177d5cSLiu Ying 					unsigned int w, unsigned int h)
181*0e177d5cSLiu Ying {
182*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_clipwindowdimensions[frac],
183*0e177d5cSLiu Ying 		     CLIPWINDOWWIDTH(w) | CLIPWINDOWHEIGHT(h));
184*0e177d5cSLiu Ying }
185*0e177d5cSLiu Ying 
186*0e177d5cSLiu Ying static inline void
187*0e177d5cSLiu Ying dc_fu_set_pixel_blend_mode(struct dc_fu *fu, enum dc_fu_frac frac)
188*0e177d5cSLiu Ying {
189*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_layerproperty[frac], 0);
190*0e177d5cSLiu Ying 	regmap_write(fu->reg_cfg, fu->reg_constantcolor[frac], 0);
191*0e177d5cSLiu Ying }
192*0e177d5cSLiu Ying 
193*0e177d5cSLiu Ying static void dc_fu_enable_src_buf(struct dc_fu *fu, enum dc_fu_frac frac)
194*0e177d5cSLiu Ying {
195*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, fu->reg_layerproperty[frac],
196*0e177d5cSLiu Ying 			  SOURCEBUFFERENABLE, SOURCEBUFFERENABLE);
197*0e177d5cSLiu Ying }
198*0e177d5cSLiu Ying 
199*0e177d5cSLiu Ying static void dc_fu_disable_src_buf(struct dc_fu *fu, enum dc_fu_frac frac)
200*0e177d5cSLiu Ying {
201*0e177d5cSLiu Ying 	regmap_write_bits(fu->reg_cfg, fu->reg_layerproperty[frac],
202*0e177d5cSLiu Ying 			  SOURCEBUFFERENABLE, 0);
203*0e177d5cSLiu Ying 
204*0e177d5cSLiu Ying 	if (fu->lb) {
205*0e177d5cSLiu Ying 		dc_lb_pec_clken(fu->lb, CLKEN_DISABLE);
206*0e177d5cSLiu Ying 		dc_lb_mode(fu->lb, LB_NEUTRAL);
207*0e177d5cSLiu Ying 	}
208*0e177d5cSLiu Ying }
209*0e177d5cSLiu Ying 
210*0e177d5cSLiu Ying static void dc_fu_set_layerblend(struct dc_fu *fu, struct dc_lb *lb)
211*0e177d5cSLiu Ying {
212*0e177d5cSLiu Ying 	fu->lb = lb;
213*0e177d5cSLiu Ying }
214*0e177d5cSLiu Ying 
215*0e177d5cSLiu Ying static enum dc_link_id dc_fu_get_link_id(struct dc_fu *fu)
216*0e177d5cSLiu Ying {
217*0e177d5cSLiu Ying 	return fu->link_id;
218*0e177d5cSLiu Ying }
219*0e177d5cSLiu Ying 
220*0e177d5cSLiu Ying static const char *dc_fu_get_name(struct dc_fu *fu)
221*0e177d5cSLiu Ying {
222*0e177d5cSLiu Ying 	return fu->name;
223*0e177d5cSLiu Ying }
224*0e177d5cSLiu Ying 
225*0e177d5cSLiu Ying const struct dc_fu_ops dc_fu_common_ops = {
226*0e177d5cSLiu Ying 	.set_burstlength	= dc_fu_set_burstlength,
227*0e177d5cSLiu Ying 	.set_baseaddress	= dc_fu_set_baseaddress,
228*0e177d5cSLiu Ying 	.set_src_stride		= dc_fu_set_src_stride,
229*0e177d5cSLiu Ying 	.set_src_buf_dimensions = dc_fu_set_src_buf_dimensions,
230*0e177d5cSLiu Ying 	.enable_src_buf		= dc_fu_enable_src_buf,
231*0e177d5cSLiu Ying 	.disable_src_buf	= dc_fu_disable_src_buf,
232*0e177d5cSLiu Ying 	.set_layerblend		= dc_fu_set_layerblend,
233*0e177d5cSLiu Ying 	.get_link_id		= dc_fu_get_link_id,
234*0e177d5cSLiu Ying 	.get_name		= dc_fu_get_name,
235*0e177d5cSLiu Ying };
236*0e177d5cSLiu Ying 
237*0e177d5cSLiu Ying const struct dc_fu_ops *dc_fu_get_ops(struct dc_fu *fu)
238*0e177d5cSLiu Ying {
239*0e177d5cSLiu Ying 	return &fu->ops;
240*0e177d5cSLiu Ying }
241*0e177d5cSLiu Ying 
242*0e177d5cSLiu Ying void dc_fu_common_hw_init(struct dc_fu *fu)
243*0e177d5cSLiu Ying {
244*0e177d5cSLiu Ying 	enum dc_fu_frac i;
245*0e177d5cSLiu Ying 
246*0e177d5cSLiu Ying 	dc_fu_baddr_autoupdate(fu, 0x0);
247*0e177d5cSLiu Ying 	dc_fu_enable_shden(fu);
248*0e177d5cSLiu Ying 	dc_fu_set_linemode(fu, LINEMODE_DISPLAY);
249*0e177d5cSLiu Ying 	dc_fu_set_numbuffers(fu, 16);
250*0e177d5cSLiu Ying 
251*0e177d5cSLiu Ying 	for (i = DC_FETCHUNIT_FRAC0; i < DC_FETCHUNIT_FRAC_NUM; i++) {
252*0e177d5cSLiu Ying 		dc_fu_layeroffset(fu, i, 0, 0);
253*0e177d5cSLiu Ying 		dc_fu_clipoffset(fu, i, 0, 0);
254*0e177d5cSLiu Ying 		dc_fu_clipdimensions(fu, i, 1, 1);
255*0e177d5cSLiu Ying 		dc_fu_disable_src_buf(fu, i);
256*0e177d5cSLiu Ying 		dc_fu_set_pixel_blend_mode(fu, i);
257*0e177d5cSLiu Ying 	}
258*0e177d5cSLiu Ying }
259