Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / media / platform / sti / bdisp / bdisp-hw.c
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }