1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) STMicroelectronics SA 2014
4  * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
5  */
6 
7 #include <linux/delay.h>
8 
9 #include "bdisp.h"
10 #include "bdisp-filter.h"
11 #include "bdisp-reg.h"
12 
13 /* Max width of the source frame in a single node */
14 #define MAX_SRC_WIDTH           2048
15 
16 /* Reset & boot poll config */
17 #define POLL_RST_MAX            500
18 #define POLL_RST_DELAY_MS       2
19 
20 enum bdisp_target_plan {
21 	BDISP_RGB,
22 	BDISP_Y,
23 	BDISP_CBCR
24 };
25 
26 struct bdisp_op_cfg {
27 	bool cconv;          /* RGB - YUV conversion */
28 	bool hflip;          /* Horizontal flip */
29 	bool vflip;          /* Vertical flip */
30 	bool wide;           /* Wide (>MAX_SRC_WIDTH) */
31 	bool scale;          /* Scale */
32 	u16  h_inc;          /* Horizontal increment in 6.10 format */
33 	u16  v_inc;          /* Vertical increment in 6.10 format */
34 	bool src_interlaced; /* is the src an interlaced buffer */
35 	u8   src_nbp;        /* nb of planes of the src */
36 	bool src_yuv;        /* is the src a YUV color format */
37 	bool src_420;        /* is the src 4:2:0 chroma subsampled */
38 	u8   dst_nbp;        /* nb of planes of the dst */
39 	bool dst_yuv;        /* is the dst a YUV color format */
40 	bool dst_420;        /* is the dst 4:2:0 chroma subsampled */
41 };
42 
43 struct bdisp_filter_addr {
44 	u16 min;             /* Filter min scale factor (6.10 fixed point) */
45 	u16 max;             /* Filter max scale factor (6.10 fixed point) */
46 	void *virt;          /* Virtual address for filter table */
47 	dma_addr_t paddr;    /* Physical address for filter table */
48 };
49 
50 static const struct bdisp_filter_h_spec bdisp_h_spec[] = {
51 	{
52 		.min = 0,
53 		.max = 921,
54 		.coef = {
55 			0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
56 			0x00, 0x00, 0xff, 0x07, 0x3d, 0xfc, 0x01, 0x00,
57 			0x00, 0x01, 0xfd, 0x11, 0x36, 0xf9, 0x02, 0x00,
58 			0x00, 0x01, 0xfb, 0x1b, 0x2e, 0xf9, 0x02, 0x00,
59 			0x00, 0x01, 0xf9, 0x26, 0x26, 0xf9, 0x01, 0x00,
60 			0x00, 0x02, 0xf9, 0x30, 0x19, 0xfb, 0x01, 0x00,
61 			0x00, 0x02, 0xf9, 0x39, 0x0e, 0xfd, 0x01, 0x00,
62 			0x00, 0x01, 0xfc, 0x3e, 0x06, 0xff, 0x00, 0x00
63 		}
64 	},
65 	{
66 		.min = 921,
67 		.max = 1024,
68 		.coef = {
69 			0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
70 			0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
71 			0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
72 			0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
73 			0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
74 			0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
75 			0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
76 			0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
77 		}
78 	},
79 	{
80 		.min = 1024,
81 		.max = 1126,
82 		.coef = {
83 			0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
84 			0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
85 			0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
86 			0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
87 			0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
88 			0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
89 			0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
90 			0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
91 		}
92 	},
93 	{
94 		.min = 1126,
95 		.max = 1228,
96 		.coef = {
97 			0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
98 			0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
99 			0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
100 			0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
101 			0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
102 			0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
103 			0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
104 			0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
105 		}
106 	},
107 	{
108 		.min = 1228,
109 		.max = 1331,
110 		.coef = {
111 			0xfd, 0x04, 0xfc, 0x05, 0x39, 0x05, 0xfc, 0x04,
112 			0xfc, 0x06, 0xf9, 0x0c, 0x39, 0xfe, 0x00, 0x02,
113 			0xfb, 0x08, 0xf6, 0x17, 0x35, 0xf9, 0x02, 0x00,
114 			0xfc, 0x08, 0xf4, 0x20, 0x30, 0xf4, 0x05, 0xff,
115 			0xfd, 0x07, 0xf4, 0x29, 0x28, 0xf3, 0x07, 0xfd,
116 			0xff, 0x05, 0xf5, 0x31, 0x1f, 0xf3, 0x08, 0xfc,
117 			0x00, 0x02, 0xf9, 0x38, 0x14, 0xf6, 0x08, 0xfb,
118 			0x02, 0x00, 0xff, 0x3a, 0x0b, 0xf8, 0x06, 0xfc
119 		}
120 	},
121 	{
122 		.min = 1331,
123 		.max = 1433,
124 		.coef = {
125 			0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06,
126 			0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05,
127 			0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04,
128 			0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02,
129 			0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00,
130 			0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff,
131 			0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe,
132 			0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd
133 		}
134 	},
135 	{
136 		.min = 1433,
137 		.max = 1536,
138 		.coef = {
139 			0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06,
140 			0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06,
141 			0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06,
142 			0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04,
143 			0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03,
144 			0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01,
145 			0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00,
146 			0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff
147 		}
148 	},
149 	{
150 		.min = 1536,
151 		.max = 2048,
152 		.coef = {
153 			0x05, 0xfd, 0xfb, 0x13, 0x25, 0x13, 0xfb, 0xfd,
154 			0x05, 0xfc, 0xfd, 0x17, 0x24, 0x0f, 0xf9, 0xff,
155 			0x04, 0xfa, 0xff, 0x1b, 0x24, 0x0b, 0xf9, 0x00,
156 			0x03, 0xf9, 0x01, 0x1f, 0x23, 0x08, 0xf8, 0x01,
157 			0x02, 0xf9, 0x04, 0x22, 0x20, 0x04, 0xf9, 0x02,
158 			0x01, 0xf8, 0x08, 0x25, 0x1d, 0x01, 0xf9, 0x03,
159 			0x00, 0xf9, 0x0c, 0x25, 0x1a, 0xfe, 0xfa, 0x04,
160 			0xff, 0xf9, 0x10, 0x26, 0x15, 0xfc, 0xfc, 0x05
161 		}
162 	},
163 	{
164 		.min = 2048,
165 		.max = 3072,
166 		.coef = {
167 			0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd,
168 			0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc,
169 			0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc,
170 			0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb,
171 			0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb,
172 			0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb,
173 			0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb,
174 			0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc
175 		}
176 	},
177 	{
178 		.min = 3072,
179 		.max = 4096,
180 		.coef = {
181 			0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02,
182 			0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01,
183 			0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00,
184 			0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00,
185 			0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00,
186 			0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00,
187 			0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff,
188 			0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff
189 		}
190 	},
191 	{
192 		.min = 4096,
193 		.max = 5120,
194 		.coef = {
195 			0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04,
196 			0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04,
197 			0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03,
198 			0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03,
199 			0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02,
200 			0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02,
201 			0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01,
202 			0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01
203 		}
204 	},
205 	{
206 		.min = 5120,
207 		.max = 65535,
208 		.coef = {
209 			0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06,
210 			0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
211 			0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
212 			0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04,
213 			0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04,
214 			0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04,
215 			0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03,
216 			0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03
217 		}
218 	}
219 };
220 
221 #define NB_H_FILTER ARRAY_SIZE(bdisp_h_spec)
222 
223 
224 static const struct bdisp_filter_v_spec bdisp_v_spec[] = {
225 	{
226 		.min = 0,
227 		.max = 1024,
228 		.coef = {
229 			0x00, 0x00, 0x40, 0x00, 0x00,
230 			0x00, 0x06, 0x3d, 0xfd, 0x00,
231 			0xfe, 0x0f, 0x38, 0xfb, 0x00,
232 			0xfd, 0x19, 0x2f, 0xfb, 0x00,
233 			0xfc, 0x24, 0x24, 0xfc, 0x00,
234 			0xfb, 0x2f, 0x19, 0xfd, 0x00,
235 			0xfb, 0x38, 0x0f, 0xfe, 0x00,
236 			0xfd, 0x3d, 0x06, 0x00, 0x00
237 		}
238 	},
239 	{
240 		.min = 1024,
241 		.max = 1331,
242 		.coef = {
243 			0xfc, 0x05, 0x3e, 0x05, 0xfc,
244 			0xf8, 0x0e, 0x3b, 0xff, 0x00,
245 			0xf5, 0x18, 0x38, 0xf9, 0x02,
246 			0xf4, 0x21, 0x31, 0xf5, 0x05,
247 			0xf4, 0x2a, 0x27, 0xf4, 0x07,
248 			0xf6, 0x30, 0x1e, 0xf4, 0x08,
249 			0xf9, 0x35, 0x15, 0xf6, 0x07,
250 			0xff, 0x37, 0x0b, 0xf9, 0x06
251 		}
252 	},
253 	{
254 		.min = 1331,
255 		.max = 1433,
256 		.coef = {
257 			0xf8, 0x0a, 0x3c, 0x0a, 0xf8,
258 			0xf6, 0x12, 0x3b, 0x02, 0xfb,
259 			0xf4, 0x1b, 0x35, 0xfd, 0xff,
260 			0xf4, 0x23, 0x30, 0xf8, 0x01,
261 			0xf6, 0x29, 0x27, 0xf6, 0x04,
262 			0xf9, 0x2e, 0x1e, 0xf5, 0x06,
263 			0xfd, 0x31, 0x16, 0xf6, 0x06,
264 			0x02, 0x32, 0x0d, 0xf8, 0x07
265 		}
266 	},
267 	{
268 		.min = 1433,
269 		.max = 1536,
270 		.coef = {
271 			0xf6, 0x0e, 0x38, 0x0e, 0xf6,
272 			0xf5, 0x15, 0x38, 0x06, 0xf8,
273 			0xf5, 0x1d, 0x33, 0x00, 0xfb,
274 			0xf6, 0x23, 0x2d, 0xfc, 0xfe,
275 			0xf9, 0x28, 0x26, 0xf9, 0x00,
276 			0xfc, 0x2c, 0x1e, 0xf7, 0x03,
277 			0x00, 0x2e, 0x18, 0xf6, 0x04,
278 			0x05, 0x2e, 0x11, 0xf7, 0x05
279 		}
280 	},
281 	{
282 		.min = 1536,
283 		.max = 2048,
284 		.coef = {
285 			0xfb, 0x13, 0x24, 0x13, 0xfb,
286 			0xfd, 0x17, 0x23, 0x0f, 0xfa,
287 			0xff, 0x1a, 0x23, 0x0b, 0xf9,
288 			0x01, 0x1d, 0x22, 0x07, 0xf9,
289 			0x04, 0x20, 0x1f, 0x04, 0xf9,
290 			0x07, 0x22, 0x1c, 0x01, 0xfa,
291 			0x0b, 0x24, 0x17, 0xff, 0xfb,
292 			0x0f, 0x24, 0x14, 0xfd, 0xfc
293 		}
294 	},
295 	{
296 		.min = 2048,
297 		.max = 3072,
298 		.coef = {
299 			0x05, 0x10, 0x16, 0x10, 0x05,
300 			0x06, 0x11, 0x16, 0x0f, 0x04,
301 			0x08, 0x13, 0x15, 0x0e, 0x02,
302 			0x09, 0x14, 0x16, 0x0c, 0x01,
303 			0x0b, 0x15, 0x15, 0x0b, 0x00,
304 			0x0d, 0x16, 0x13, 0x0a, 0x00,
305 			0x0f, 0x17, 0x13, 0x08, 0xff,
306 			0x11, 0x18, 0x12, 0x07, 0xfe
307 		}
308 	},
309 	{
310 		.min = 3072,
311 		.max = 4096,
312 		.coef = {
313 			0x09, 0x0f, 0x10, 0x0f, 0x09,
314 			0x09, 0x0f, 0x12, 0x0e, 0x08,
315 			0x0a, 0x10, 0x11, 0x0e, 0x07,
316 			0x0b, 0x11, 0x11, 0x0d, 0x06,
317 			0x0c, 0x11, 0x12, 0x0c, 0x05,
318 			0x0d, 0x12, 0x11, 0x0c, 0x04,
319 			0x0e, 0x12, 0x11, 0x0b, 0x04,
320 			0x0f, 0x13, 0x11, 0x0a, 0x03
321 		}
322 	},
323 	{
324 		.min = 4096,
325 		.max = 5120,
326 		.coef = {
327 			0x0a, 0x0e, 0x10, 0x0e, 0x0a,
328 			0x0b, 0x0e, 0x0f, 0x0e, 0x0a,
329 			0x0b, 0x0f, 0x10, 0x0d, 0x09,
330 			0x0c, 0x0f, 0x10, 0x0d, 0x08,
331 			0x0d, 0x0f, 0x0f, 0x0d, 0x08,
332 			0x0d, 0x10, 0x10, 0x0c, 0x07,
333 			0x0e, 0x10, 0x0f, 0x0c, 0x07,
334 			0x0f, 0x10, 0x10, 0x0b, 0x06
335 		}
336 	},
337 	{
338 		.min = 5120,
339 		.max = 65535,
340 		.coef = {
341 			0x0b, 0x0e, 0x0e, 0x0e, 0x0b,
342 			0x0b, 0x0e, 0x0f, 0x0d, 0x0b,
343 			0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
344 			0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
345 			0x0d, 0x0f, 0x0e, 0x0d, 0x09,
346 			0x0d, 0x0f, 0x0f, 0x0c, 0x09,
347 			0x0e, 0x0f, 0x0e, 0x0c, 0x09,
348 			0x0e, 0x0f, 0x0f, 0x0c, 0x08
349 		}
350 	}
351 };
352 
353 #define NB_V_FILTER ARRAY_SIZE(bdisp_v_spec)
354 
355 static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
356 static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];
357 
358 /**
359  * bdisp_hw_reset
360  * @bdisp:      bdisp entity
361  *
362  * Resets HW
363  *
364  * RETURNS:
365  * 0 on success.
366  */
bdisp_hw_reset(struct bdisp_dev * bdisp)367 int bdisp_hw_reset(struct bdisp_dev *bdisp)
368 {
369 	unsigned int i;
370 
371 	dev_dbg(bdisp->dev, "%s\n", __func__);
372 
373 	/* Mask Interrupt */
374 	writel(0, bdisp->regs + BLT_ITM0);
375 
376 	/* Reset */
377 	writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET,
378 	       bdisp->regs + BLT_CTL);
379 	writel(0, bdisp->regs + BLT_CTL);
380 
381 	/* Wait for reset done */
382 	for (i = 0; i < POLL_RST_MAX; i++) {
383 		if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
384 			break;
385 		udelay(POLL_RST_DELAY_MS * 1000);
386 	}
387 	if (i == POLL_RST_MAX)
388 		dev_err(bdisp->dev, "Reset timeout\n");
389 
390 	return (i == POLL_RST_MAX) ? -EAGAIN : 0;
391 }
392 
393 /**
394  * bdisp_hw_get_and_clear_irq
395  * @bdisp:      bdisp entity
396  *
397  * Read then reset interrupt status
398  *
399  * RETURNS:
400  * 0 if expected interrupt was raised.
401  */
bdisp_hw_get_and_clear_irq(struct bdisp_dev * bdisp)402 int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
403 {
404 	u32 its;
405 
406 	its = readl(bdisp->regs + BLT_ITS);
407 
408 	/* Check for the only expected IT: LastNode of AQ1 */
409 	if (!(its & BLT_ITS_AQ1_LNA)) {
410 		dev_dbg(bdisp->dev, "Unexpected IT status: 0x%08X\n", its);
411 		writel(its, bdisp->regs + BLT_ITS);
412 		return -1;
413 	}
414 
415 	/* Clear and mask */
416 	writel(its, bdisp->regs + BLT_ITS);
417 	writel(0, bdisp->regs + BLT_ITM0);
418 
419 	return 0;
420 }
421 
422 /**
423  * bdisp_hw_free_nodes
424  * @ctx:        bdisp context
425  *
426  * Free node memory
427  *
428  * RETURNS:
429  * None
430  */
bdisp_hw_free_nodes(struct bdisp_ctx * ctx)431 void bdisp_hw_free_nodes(struct bdisp_ctx *ctx)
432 {
433 	if (ctx && ctx->node[0])
434 		dma_free_attrs(ctx->bdisp_dev->dev,
435 			       sizeof(struct bdisp_node) * MAX_NB_NODE,
436 			       ctx->node[0], ctx->node_paddr[0],
437 			       DMA_ATTR_WRITE_COMBINE);
438 }
439 
440 /**
441  * bdisp_hw_alloc_nodes
442  * @ctx:        bdisp context
443  *
444  * Allocate dma memory for nodes
445  *
446  * RETURNS:
447  * 0 on success
448  */
bdisp_hw_alloc_nodes(struct bdisp_ctx * ctx)449 int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx)
450 {
451 	struct device *dev = ctx->bdisp_dev->dev;
452 	unsigned int i, node_size = sizeof(struct bdisp_node);
453 	void *base;
454 	dma_addr_t paddr;
455 
456 	/* Allocate all the nodes within a single memory page */
457 	base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr,
458 			       GFP_KERNEL, DMA_ATTR_WRITE_COMBINE);
459 	if (!base) {
460 		dev_err(dev, "%s no mem\n", __func__);
461 		return -ENOMEM;
462 	}
463 
464 	memset(base, 0, node_size * MAX_NB_NODE);
465 
466 	for (i = 0; i < MAX_NB_NODE; i++) {
467 		ctx->node[i] = base;
468 		ctx->node_paddr[i] = paddr;
469 		dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i],
470 			&paddr);
471 		base += node_size;
472 		paddr += node_size;
473 	}
474 
475 	return 0;
476 }
477 
478 /**
479  * bdisp_hw_free_filters
480  * @dev:        device
481  *
482  * Free filters memory
483  *
484  * RETURNS:
485  * None
486  */
bdisp_hw_free_filters(struct device * dev)487 void bdisp_hw_free_filters(struct device *dev)
488 {
489 	int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
490 
491 	if (bdisp_h_filter[0].virt)
492 		dma_free_attrs(dev, size, bdisp_h_filter[0].virt,
493 			       bdisp_h_filter[0].paddr, DMA_ATTR_WRITE_COMBINE);
494 }
495 
496 /**
497  * bdisp_hw_alloc_filters
498  * @dev:        device
499  *
500  * Allocate dma memory for filters
501  *
502  * RETURNS:
503  * 0 on success
504  */
bdisp_hw_alloc_filters(struct device * dev)505 int bdisp_hw_alloc_filters(struct device *dev)
506 {
507 	unsigned int i, size;
508 	void *base;
509 	dma_addr_t paddr;
510 
511 	/* Allocate all the filters within a single memory page */
512 	size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
513 	base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL,
514 			       DMA_ATTR_WRITE_COMBINE);
515 	if (!base)
516 		return -ENOMEM;
517 
518 	/* Setup filter addresses */
519 	for (i = 0; i < NB_H_FILTER; i++) {
520 		bdisp_h_filter[i].min = bdisp_h_spec[i].min;
521 		bdisp_h_filter[i].max = bdisp_h_spec[i].max;
522 		memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB);
523 		bdisp_h_filter[i].virt = base;
524 		bdisp_h_filter[i].paddr = paddr;
525 		base += BDISP_HF_NB;
526 		paddr += BDISP_HF_NB;
527 	}
528 
529 	for (i = 0; i < NB_V_FILTER; i++) {
530 		bdisp_v_filter[i].min = bdisp_v_spec[i].min;
531 		bdisp_v_filter[i].max = bdisp_v_spec[i].max;
532 		memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB);
533 		bdisp_v_filter[i].virt = base;
534 		bdisp_v_filter[i].paddr = paddr;
535 		base += BDISP_VF_NB;
536 		paddr += BDISP_VF_NB;
537 	}
538 
539 	return 0;
540 }
541 
542 /**
543  * bdisp_hw_get_hf_addr
544  * @inc:        resize increment
545  *
546  * Find the horizontal filter table that fits the resize increment
547  *
548  * RETURNS:
549  * table physical address
550  */
bdisp_hw_get_hf_addr(u16 inc)551 static dma_addr_t bdisp_hw_get_hf_addr(u16 inc)
552 {
553 	unsigned int i;
554 
555 	for (i = NB_H_FILTER - 1; i > 0; i--)
556 		if ((bdisp_h_filter[i].min < inc) &&
557 		    (inc <= bdisp_h_filter[i].max))
558 			break;
559 
560 	return bdisp_h_filter[i].paddr;
561 }
562 
563 /**
564  * bdisp_hw_get_vf_addr
565  * @inc:        resize increment
566  *
567  * Find the vertical filter table that fits the resize increment
568  *
569  * RETURNS:
570  * table physical address
571  */
bdisp_hw_get_vf_addr(u16 inc)572 static dma_addr_t bdisp_hw_get_vf_addr(u16 inc)
573 {
574 	unsigned int i;
575 
576 	for (i = NB_V_FILTER - 1; i > 0; i--)
577 		if ((bdisp_v_filter[i].min < inc) &&
578 		    (inc <= bdisp_v_filter[i].max))
579 			break;
580 
581 	return bdisp_v_filter[i].paddr;
582 }
583 
584 /**
585  * bdisp_hw_get_inc
586  * @from:       input size
587  * @to:         output size
588  * @inc:        resize increment in 6.10 format
589  *
590  * Computes the increment (inverse of scale) in 6.10 format
591  *
592  * RETURNS:
593  * 0 on success
594  */
bdisp_hw_get_inc(u32 from,u32 to,u16 * inc)595 static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc)
596 {
597 	u32 tmp;
598 
599 	if (!to)
600 		return -EINVAL;
601 
602 	if (to == from) {
603 		*inc = 1 << 10;
604 		return 0;
605 	}
606 
607 	tmp = (from << 10) / to;
608 	if ((tmp > 0xFFFF) || (!tmp))
609 		/* overflow (downscale x 63) or too small (upscale x 1024) */
610 		return -EINVAL;
611 
612 	*inc = (u16)tmp;
613 
614 	return 0;
615 }
616 
617 /**
618  * bdisp_hw_get_hv_inc
619  * @ctx:        device context
620  * @h_inc:      horizontal increment
621  * @v_inc:      vertical increment
622  *
623  * Computes the horizontal & vertical increments (inverse of scale)
624  *
625  * RETURNS:
626  * 0 on success
627  */
bdisp_hw_get_hv_inc(struct bdisp_ctx * ctx,u16 * h_inc,u16 * v_inc)628 static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc)
629 {
630 	u32 src_w, src_h, dst_w, dst_h;
631 
632 	src_w = ctx->src.crop.width;
633 	src_h = ctx->src.crop.height;
634 	dst_w = ctx->dst.crop.width;
635 	dst_h = ctx->dst.crop.height;
636 
637 	if (bdisp_hw_get_inc(src_w, dst_w, h_inc) ||
638 	    bdisp_hw_get_inc(src_h, dst_h, v_inc)) {
639 		dev_err(ctx->bdisp_dev->dev,
640 			"scale factors failed (%dx%d)->(%dx%d)\n",
641 			src_w, src_h, dst_w, dst_h);
642 		return -EINVAL;
643 	}
644 
645 	return 0;
646 }
647 
648 /**
649  * bdisp_hw_get_op_cfg
650  * @ctx:        device context
651  * @c:          operation configuration
652  *
653  * Check which blitter operations are expected and sets the scaling increments
654  *
655  * RETURNS:
656  * 0 on success
657  */
bdisp_hw_get_op_cfg(struct bdisp_ctx * ctx,struct bdisp_op_cfg * c)658 static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c)
659 {
660 	struct device *dev = ctx->bdisp_dev->dev;
661 	struct bdisp_frame *src = &ctx->src;
662 	struct bdisp_frame *dst = &ctx->dst;
663 
664 	if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) {
665 		dev_err(dev, "Image width out of HW caps\n");
666 		return -EINVAL;
667 	}
668 
669 	c->wide = src->width > MAX_SRC_WIDTH;
670 
671 	c->hflip = ctx->hflip;
672 	c->vflip = ctx->vflip;
673 
674 	c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED);
675 
676 	c->src_nbp = src->fmt->nb_planes;
677 	c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
678 			(src->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
679 	c->src_420 = c->src_yuv;
680 
681 	c->dst_nbp = dst->fmt->nb_planes;
682 	c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
683 			(dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
684 	c->dst_420 = c->dst_yuv;
685 
686 	c->cconv = (c->src_yuv != c->dst_yuv);
687 
688 	if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) {
689 		dev_err(dev, "Scale factor out of HW caps\n");
690 		return -EINVAL;
691 	}
692 
693 	/* Deinterlacing adjustment : stretch a field to a frame */
694 	if (c->src_interlaced)
695 		c->v_inc /= 2;
696 
697 	if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10)))
698 		c->scale = true;
699 	else
700 		c->scale = false;
701 
702 	return 0;
703 }
704 
705 /**
706  * bdisp_hw_color_format
707  * @pixelformat: v4l2 pixel format
708  *
709  * v4l2 to bdisp pixel format convert
710  *
711  * RETURNS:
712  * bdisp pixel format
713  */
bdisp_hw_color_format(u32 pixelformat)714 static u32 bdisp_hw_color_format(u32 pixelformat)
715 {
716 	u32 ret;
717 
718 	switch (pixelformat) {
719 	case V4L2_PIX_FMT_YUV420:
720 		ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT);
721 		break;
722 	case V4L2_PIX_FMT_NV12:
723 		ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
724 		break;
725 	case V4L2_PIX_FMT_RGB565:
726 		ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT);
727 		break;
728 	case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */
729 		ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT);
730 		break;
731 	case V4L2_PIX_FMT_RGB24:  /* RGB888 format */
732 		ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
733 		break;
734 	case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */
735 
736 	default:
737 		ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R;
738 		break;
739 	}
740 
741 	return ret;
742 }
743 
744 /**
745  * bdisp_hw_build_node
746  * @ctx:        device context
747  * @cfg:        operation configuration
748  * @node:       node to be set
749  * @t_plan:     whether the node refers to a RGB/Y or a CbCr plane
750  * @src_x_offset: x offset in the source image
751  *
752  * Build a node
753  *
754  * RETURNS:
755  * None
756  */
bdisp_hw_build_node(struct bdisp_ctx * ctx,struct bdisp_op_cfg * cfg,struct bdisp_node * node,enum bdisp_target_plan t_plan,int src_x_offset)757 static void bdisp_hw_build_node(struct bdisp_ctx *ctx,
758 				struct bdisp_op_cfg *cfg,
759 				struct bdisp_node *node,
760 				enum bdisp_target_plan t_plan, int src_x_offset)
761 {
762 	struct bdisp_frame *src = &ctx->src;
763 	struct bdisp_frame *dst = &ctx->dst;
764 	u16 h_inc, v_inc, yh_inc, yv_inc;
765 	struct v4l2_rect src_rect = src->crop;
766 	struct v4l2_rect dst_rect = dst->crop;
767 	int dst_x_offset;
768 	s32 dst_width = dst->crop.width;
769 	u32 src_fmt, dst_fmt;
770 	const u32 *ivmx;
771 
772 	dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__);
773 
774 	memset(node, 0, sizeof(*node));
775 
776 	/* Adjust src and dst areas wrt src_x_offset */
777 	src_rect.left += src_x_offset;
778 	src_rect.width -= src_x_offset;
779 	src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width);
780 
781 	dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width;
782 	dst_rect.left += dst_x_offset;
783 	dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width;
784 
785 	/* General */
786 	src_fmt = src->fmt->pixelformat;
787 	dst_fmt = dst->fmt->pixelformat;
788 
789 	node->nip = 0;
790 	node->cic = BLT_CIC_ALL_GRP;
791 	node->ack = BLT_ACK_BYPASS_S2S3;
792 
793 	switch (cfg->src_nbp) {
794 	case 1:
795 		/* Src2 = RGB / Src1 = Src3 = off */
796 		node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF;
797 		break;
798 	case 2:
799 		/* Src3 = Y
800 		 * Src2 = CbCr or ColorFill if writing the Y plane
801 		 * Src1 = off */
802 		node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM;
803 		if (t_plan == BDISP_Y)
804 			node->ins |= BLT_INS_S2_CF;
805 		else
806 			node->ins |= BLT_INS_S2_MEM;
807 		break;
808 	case 3:
809 	default:
810 		/* Src3 = Y
811 		 * Src2 = Cb or ColorFill if writing the Y plane
812 		 * Src1 = Cr or ColorFill if writing the Y plane */
813 		node->ins = BLT_INS_S3_MEM;
814 		if (t_plan == BDISP_Y)
815 			node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF;
816 		else
817 			node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM;
818 		break;
819 	}
820 
821 	/* Color convert */
822 	node->ins |= cfg->cconv ? BLT_INS_IVMX : 0;
823 	/* Scale needed if scaling OR 4:2:0 up/downsampling */
824 	node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ?
825 			BLT_INS_SCALE : 0;
826 
827 	/* Target */
828 	node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0];
829 
830 	node->tty = dst->bytesperline;
831 	node->tty |= bdisp_hw_color_format(dst_fmt);
832 	node->tty |= BLT_TTY_DITHER;
833 	node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0;
834 	node->tty |= cfg->hflip ? BLT_TTY_HSO : 0;
835 	node->tty |= cfg->vflip ? BLT_TTY_VSO : 0;
836 
837 	if (cfg->dst_420 && (t_plan == BDISP_CBCR)) {
838 		/* 420 chroma downsampling */
839 		dst_rect.height /= 2;
840 		dst_rect.width /= 2;
841 		dst_rect.left /= 2;
842 		dst_rect.top /= 2;
843 		dst_x_offset /= 2;
844 		dst_width /= 2;
845 	}
846 
847 	node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top;
848 	node->txy <<= 16;
849 	node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) :
850 			dst_rect.left;
851 
852 	node->tsz = dst_rect.height << 16 | dst_rect.width;
853 
854 	if (cfg->src_interlaced) {
855 		/* handle only the top field which is half height of a frame */
856 		src_rect.top /= 2;
857 		src_rect.height /= 2;
858 	}
859 
860 	if (cfg->src_nbp == 1) {
861 		/* Src 2 : RGB */
862 		node->s2ba = src->paddr[0];
863 
864 		node->s2ty = src->bytesperline;
865 		if (cfg->src_interlaced)
866 			node->s2ty *= 2;
867 
868 		node->s2ty |= bdisp_hw_color_format(src_fmt);
869 
870 		node->s2xy = src_rect.top << 16 | src_rect.left;
871 		node->s2sz = src_rect.height << 16 | src_rect.width;
872 	} else {
873 		/* Src 2 : Cb or CbCr */
874 		if (cfg->src_420) {
875 			/* 420 chroma upsampling */
876 			src_rect.top /= 2;
877 			src_rect.left /= 2;
878 			src_rect.width /= 2;
879 			src_rect.height /= 2;
880 		}
881 
882 		node->s2ba = src->paddr[1];
883 
884 		node->s2ty = src->bytesperline;
885 		if (cfg->src_nbp == 3)
886 			node->s2ty /= 2;
887 		if (cfg->src_interlaced)
888 			node->s2ty *= 2;
889 
890 		node->s2ty |= bdisp_hw_color_format(src_fmt);
891 
892 		node->s2xy = src_rect.top << 16 | src_rect.left;
893 		node->s2sz = src_rect.height << 16 | src_rect.width;
894 
895 		if (cfg->src_nbp == 3) {
896 			/* Src 1 : Cr */
897 			node->s1ba = src->paddr[2];
898 
899 			node->s1ty = node->s2ty;
900 			node->s1xy = node->s2xy;
901 		}
902 
903 		/* Src 3 : Y */
904 		node->s3ba = src->paddr[0];
905 
906 		node->s3ty = src->bytesperline;
907 		if (cfg->src_interlaced)
908 			node->s3ty *= 2;
909 		node->s3ty |= bdisp_hw_color_format(src_fmt);
910 
911 		if ((t_plan != BDISP_CBCR) && cfg->src_420) {
912 			/* No chroma upsampling for output RGB / Y plane */
913 			node->s3xy = node->s2xy * 2;
914 			node->s3sz = node->s2sz * 2;
915 		} else {
916 			/* No need to read Y (Src3) when writing Chroma */
917 			node->s3ty |= BLT_S3TY_BLANK_ACC;
918 			node->s3xy = node->s2xy;
919 			node->s3sz = node->s2sz;
920 		}
921 	}
922 
923 	/* Resize (scale OR 4:2:0: chroma up/downsampling) */
924 	if (node->ins & BLT_INS_SCALE) {
925 		/* no need to compute Y when writing CbCr from RGB input */
926 		bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv;
927 
928 		/* FCTL */
929 		if (cfg->scale) {
930 			node->fctl = BLT_FCTL_HV_SCALE;
931 			if (!skip_y)
932 				node->fctl |= BLT_FCTL_Y_HV_SCALE;
933 		} else {
934 			node->fctl = BLT_FCTL_HV_SAMPLE;
935 			if (!skip_y)
936 				node->fctl |= BLT_FCTL_Y_HV_SAMPLE;
937 		}
938 
939 		/* RSF - Chroma may need to be up/downsampled */
940 		h_inc = cfg->h_inc;
941 		v_inc = cfg->v_inc;
942 		if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) {
943 			/* RGB to 4:2:0 for Chroma: downsample */
944 			h_inc *= 2;
945 			v_inc *= 2;
946 		} else if (cfg->src_420 && !cfg->dst_420) {
947 			/* 4:2:0: to RGB: upsample*/
948 			h_inc /= 2;
949 			v_inc /= 2;
950 		}
951 		node->rsf = v_inc << 16 | h_inc;
952 
953 		/* RZI */
954 		node->rzi = BLT_RZI_DEFAULT;
955 
956 		/* Filter table physical addr */
957 		node->hfp = bdisp_hw_get_hf_addr(h_inc);
958 		node->vfp = bdisp_hw_get_vf_addr(v_inc);
959 
960 		/* Y version */
961 		if (!skip_y) {
962 			yh_inc = cfg->h_inc;
963 			yv_inc = cfg->v_inc;
964 
965 			node->y_rsf = yv_inc << 16 | yh_inc;
966 			node->y_rzi = BLT_RZI_DEFAULT;
967 			node->y_hfp = bdisp_hw_get_hf_addr(yh_inc);
968 			node->y_vfp = bdisp_hw_get_vf_addr(yv_inc);
969 		}
970 	}
971 
972 	/* Versatile matrix for RGB / YUV conversion */
973 	if (cfg->cconv) {
974 		ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv;
975 
976 		node->ivmx0 = ivmx[0];
977 		node->ivmx1 = ivmx[1];
978 		node->ivmx2 = ivmx[2];
979 		node->ivmx3 = ivmx[3];
980 	}
981 }
982 
983 /**
984  * bdisp_hw_build_all_nodes
985  * @ctx:        device context
986  *
987  * Build all the nodes for the blitter operation
988  *
989  * RETURNS:
990  * 0 on success
991  */
bdisp_hw_build_all_nodes(struct bdisp_ctx * ctx)992 static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx)
993 {
994 	struct bdisp_op_cfg cfg;
995 	unsigned int i, nid = 0;
996 	int src_x_offset = 0;
997 
998 	for (i = 0; i < MAX_NB_NODE; i++)
999 		if (!ctx->node[i]) {
1000 			dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i);
1001 			return -EINVAL;
1002 		}
1003 
1004 	/* Get configuration (scale, flip, ...) */
1005 	if (bdisp_hw_get_op_cfg(ctx, &cfg))
1006 		return -EINVAL;
1007 
1008 	/* Split source in vertical strides (HW constraint) */
1009 	for (i = 0; i < MAX_VERTICAL_STRIDES; i++) {
1010 		/* Build RGB/Y node and link it to the previous node */
1011 		bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
1012 				    cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y,
1013 				    src_x_offset);
1014 		if (nid)
1015 			ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
1016 		nid++;
1017 
1018 		/* Build additional Cb(Cr) node, link it to the previous one */
1019 		if (cfg.dst_nbp > 1) {
1020 			bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
1021 					    BDISP_CBCR, src_x_offset);
1022 			ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
1023 			nid++;
1024 		}
1025 
1026 		/* Next stride until full width covered */
1027 		src_x_offset += MAX_SRC_WIDTH;
1028 		if (src_x_offset >= ctx->src.crop.width)
1029 			break;
1030 	}
1031 
1032 	/* Mark last node as the last */
1033 	ctx->node[nid - 1]->nip = 0;
1034 
1035 	return 0;
1036 }
1037 
1038 /**
1039  * bdisp_hw_save_request
1040  * @ctx:        device context
1041  *
1042  * Save a copy of the request and of the built nodes
1043  *
1044  * RETURNS:
1045  * None
1046  */
bdisp_hw_save_request(struct bdisp_ctx * ctx)1047 static void bdisp_hw_save_request(struct bdisp_ctx *ctx)
1048 {
1049 	struct bdisp_node **copy_node = ctx->bdisp_dev->dbg.copy_node;
1050 	struct bdisp_request *request = &ctx->bdisp_dev->dbg.copy_request;
1051 	struct bdisp_node **node = ctx->node;
1052 	int i;
1053 
1054 	/* Request copy */
1055 	request->src = ctx->src;
1056 	request->dst = ctx->dst;
1057 	request->hflip = ctx->hflip;
1058 	request->vflip = ctx->vflip;
1059 	request->nb_req++;
1060 
1061 	/* Nodes copy */
1062 	for (i = 0; i < MAX_NB_NODE; i++) {
1063 		/* Allocate memory if not done yet */
1064 		if (!copy_node[i]) {
1065 			copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev,
1066 						    sizeof(*copy_node[i]),
1067 						    GFP_ATOMIC);
1068 			if (!copy_node[i])
1069 				return;
1070 		}
1071 		*copy_node[i] = *node[i];
1072 	}
1073 }
1074 
1075 /**
1076  * bdisp_hw_update
1077  * @ctx:        device context
1078  *
1079  * Send the request to the HW
1080  *
1081  * RETURNS:
1082  * 0 on success
1083  */
bdisp_hw_update(struct bdisp_ctx * ctx)1084 int bdisp_hw_update(struct bdisp_ctx *ctx)
1085 {
1086 	int ret;
1087 	struct bdisp_dev *bdisp = ctx->bdisp_dev;
1088 	struct device *dev = bdisp->dev;
1089 	unsigned int node_id;
1090 
1091 	dev_dbg(dev, "%s\n", __func__);
1092 
1093 	/* build nodes */
1094 	ret = bdisp_hw_build_all_nodes(ctx);
1095 	if (ret) {
1096 		dev_err(dev, "cannot build nodes (%d)\n", ret);
1097 		return ret;
1098 	}
1099 
1100 	/* Save a copy of the request */
1101 	bdisp_hw_save_request(ctx);
1102 
1103 	/* Configure interrupt to 'Last Node Reached for AQ1' */
1104 	writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL);
1105 	writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0);
1106 
1107 	/* Write first node addr */
1108 	writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP);
1109 
1110 	/* Find and write last node addr : this starts the HW processing */
1111 	for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) {
1112 		if (!ctx->node[node_id]->nip)
1113 			break;
1114 	}
1115 	writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA);
1116 
1117 	return 0;
1118 }
1119