1
2
3
4
5
6
7#include <linux/delay.h>
8
9#include "bdisp.h"
10#include "bdisp-filter.h"
11#include "bdisp-reg.h"
12
13
14#define MAX_SRC_WIDTH 2048
15
16
17#define POLL_RST_MAX 50
18#define POLL_RST_DELAY_MS 20
19
20enum bdisp_target_plan {
21 BDISP_RGB,
22 BDISP_Y,
23 BDISP_CBCR
24};
25
26struct bdisp_op_cfg {
27 bool cconv;
28 bool hflip;
29 bool vflip;
30 bool wide;
31 bool scale;
32 u16 h_inc;
33 u16 v_inc;
34 bool src_interlaced;
35 u8 src_nbp;
36 bool src_yuv;
37 bool src_420;
38 u8 dst_nbp;
39 bool dst_yuv;
40 bool dst_420;
41};
42
43struct bdisp_filter_addr {
44 u16 min;
45 u16 max;
46 void *virt;
47 dma_addr_t paddr;
48};
49
50static 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
224static 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
355static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
356static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];
357
358
359
360
361
362
363
364
365
366
367int bdisp_hw_reset(struct bdisp_dev *bdisp)
368{
369 unsigned int i;
370
371 dev_dbg(bdisp->dev, "%s\n", __func__);
372
373
374 writel(0, bdisp->regs + BLT_ITM0);
375
376
377 writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET,
378 bdisp->regs + BLT_CTL);
379 writel(0, bdisp->regs + BLT_CTL);
380
381
382 for (i = 0; i < POLL_RST_MAX; i++) {
383 if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
384 break;
385 msleep(POLL_RST_DELAY_MS);
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
395
396
397
398
399
400
401
402int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
403{
404 u32 its;
405
406 its = readl(bdisp->regs + BLT_ITS);
407
408
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
416 writel(its, bdisp->regs + BLT_ITS);
417 writel(0, bdisp->regs + BLT_ITM0);
418
419 return 0;
420}
421
422
423
424
425
426
427
428
429
430
431void 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
442
443
444
445
446
447
448
449int 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
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
480
481
482
483
484
485
486
487void 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
498
499
500
501
502
503
504
505int bdisp_hw_alloc_filters(struct device *dev)
506{
507 unsigned int i, size;
508 void *base;
509 dma_addr_t paddr;
510
511
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
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
544
545
546
547
548
549
550
551static 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
565
566
567
568
569
570
571
572static 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
586
587
588
589
590
591
592
593
594
595static 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
610 return -EINVAL;
611
612 *inc = (u16)tmp;
613
614 return 0;
615}
616
617
618
619
620
621
622
623
624
625
626
627
628static 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
650
651
652
653
654
655
656
657
658static 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
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
707
708
709
710
711
712
713
714static 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:
729 ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT);
730 break;
731 case V4L2_PIX_FMT_RGB24:
732 ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
733 break;
734 case V4L2_PIX_FMT_ABGR32:
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
746
747
748
749
750
751
752
753
754
755
756
757static 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
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
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
796 node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF;
797 break;
798 case 2:
799
800
801
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
811
812
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
822 node->ins |= cfg->cconv ? BLT_INS_IVMX : 0;
823
824 node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ?
825 BLT_INS_SCALE : 0;
826
827
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
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
856 src_rect.top /= 2;
857 src_rect.height /= 2;
858 }
859
860 if (cfg->src_nbp == 1) {
861
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
874 if (cfg->src_420) {
875
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
897 node->s1ba = src->paddr[2];
898
899 node->s1ty = node->s2ty;
900 node->s1xy = node->s2xy;
901 }
902
903
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
913 node->s3xy = node->s2xy * 2;
914 node->s3sz = node->s2sz * 2;
915 } else {
916
917 node->s3ty |= BLT_S3TY_BLANK_ACC;
918 node->s3xy = node->s2xy;
919 node->s3sz = node->s2sz;
920 }
921 }
922
923
924 if (node->ins & BLT_INS_SCALE) {
925
926 bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv;
927
928
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
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
944 h_inc *= 2;
945 v_inc *= 2;
946 } else if (cfg->src_420 && !cfg->dst_420) {
947
948 h_inc /= 2;
949 v_inc /= 2;
950 }
951 node->rsf = v_inc << 16 | h_inc;
952
953
954 node->rzi = BLT_RZI_DEFAULT;
955
956
957 node->hfp = bdisp_hw_get_hf_addr(h_inc);
958 node->vfp = bdisp_hw_get_vf_addr(v_inc);
959
960
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
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
985
986
987
988
989
990
991
992static 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
1005 if (bdisp_hw_get_op_cfg(ctx, &cfg))
1006 return -EINVAL;
1007
1008
1009 for (i = 0; i < MAX_VERTICAL_STRIDES; i++) {
1010
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
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
1027 src_x_offset += MAX_SRC_WIDTH;
1028 if (src_x_offset >= ctx->src.crop.width)
1029 break;
1030 }
1031
1032
1033 ctx->node[nid - 1]->nip = 0;
1034
1035 return 0;
1036}
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047static 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
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
1062 for (i = 0; i < MAX_NB_NODE; i++) {
1063
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
1077
1078
1079
1080
1081
1082
1083
1084int 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
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
1101 bdisp_hw_save_request(ctx);
1102
1103
1104 writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL);
1105 writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0);
1106
1107
1108 writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP);
1109
1110
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