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