2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
7 #include <linux/delay.h>
10 #include "bdisp-filter.h"
11 #include "bdisp-reg.h"
13 /* Max width of the source frame in a single node */
14 #define MAX_SRC_WIDTH 2048
16 /* Reset & boot poll config */
17 #define POLL_RST_MAX 50
18 #define POLL_RST_DELAY_MS 20
20 enum bdisp_target_plan {
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 */
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 */
50 static const struct bdisp_filter_h_spec bdisp_h_spec[] = {
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
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
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
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
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
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
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
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
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
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
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
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
221 #define NB_H_FILTER ARRAY_SIZE(bdisp_h_spec)
224 static const struct bdisp_filter_v_spec bdisp_v_spec[] = {
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
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
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
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
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
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
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
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
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
353 #define NB_V_FILTER ARRAY_SIZE(bdisp_v_spec)
355 static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
356 static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];
360 * @bdisp: bdisp entity
367 int bdisp_hw_reset(struct bdisp_dev *bdisp)
371 dev_dbg(bdisp->dev, "%s\n", __func__);
374 writel(0, bdisp->regs + BLT_ITM0);
377 writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET,
378 bdisp->regs + BLT_CTL);
379 writel(0, bdisp->regs + BLT_CTL);
381 /* Wait for reset done */
382 for (i = 0; i < POLL_RST_MAX; i++) {
383 if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
385 msleep(POLL_RST_DELAY_MS);
387 if (i == POLL_RST_MAX)
388 dev_err(bdisp->dev, "Reset timeout\n");
390 return (i == POLL_RST_MAX) ? -EAGAIN : 0;
394 * bdisp_hw_get_and_clear_irq
395 * @bdisp: bdisp entity
397 * Read then reset interrupt status
400 * 0 if expected interrupt was raised.
402 int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
406 its = readl(bdisp->regs + BLT_ITS);
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);
416 writel(its, bdisp->regs + BLT_ITS);
417 writel(0, bdisp->regs + BLT_ITM0);
423 * bdisp_hw_free_nodes
424 * @ctx: bdisp context
431 void bdisp_hw_free_nodes(struct bdisp_ctx *ctx)
433 if (ctx && ctx->node[0]) {
434 DEFINE_DMA_ATTRS(attrs);
436 dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
437 dma_free_attrs(ctx->bdisp_dev->dev,
438 sizeof(struct bdisp_node) * MAX_NB_NODE,
439 ctx->node[0], ctx->node_paddr[0], &attrs);
444 * bdisp_hw_alloc_nodes
445 * @ctx: bdisp context
447 * Allocate dma memory for nodes
452 int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx)
454 struct device *dev = ctx->bdisp_dev->dev;
455 unsigned int i, node_size = sizeof(struct bdisp_node);
458 DEFINE_DMA_ATTRS(attrs);
460 /* Allocate all the nodes within a single memory page */
461 dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
462 base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr,
463 GFP_KERNEL | GFP_DMA, &attrs);
465 dev_err(dev, "%s no mem\n", __func__);
469 memset(base, 0, node_size * MAX_NB_NODE);
471 for (i = 0; i < MAX_NB_NODE; i++) {
473 ctx->node_paddr[i] = paddr;
474 dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i],
484 * bdisp_hw_free_filters
487 * Free filters memory
492 void bdisp_hw_free_filters(struct device *dev)
494 int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
496 if (bdisp_h_filter[0].virt) {
497 DEFINE_DMA_ATTRS(attrs);
499 dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
500 dma_free_attrs(dev, size, bdisp_h_filter[0].virt,
501 bdisp_h_filter[0].paddr, &attrs);
506 * bdisp_hw_alloc_filters
509 * Allocate dma memory for filters
514 int bdisp_hw_alloc_filters(struct device *dev)
516 unsigned int i, size;
519 DEFINE_DMA_ATTRS(attrs);
521 /* Allocate all the filters within a single memory page */
522 size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
523 dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
524 base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, &attrs);
528 /* Setup filter addresses */
529 for (i = 0; i < NB_H_FILTER; i++) {
530 bdisp_h_filter[i].min = bdisp_h_spec[i].min;
531 bdisp_h_filter[i].max = bdisp_h_spec[i].max;
532 memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB);
533 bdisp_h_filter[i].virt = base;
534 bdisp_h_filter[i].paddr = paddr;
536 paddr += BDISP_HF_NB;
539 for (i = 0; i < NB_V_FILTER; i++) {
540 bdisp_v_filter[i].min = bdisp_v_spec[i].min;
541 bdisp_v_filter[i].max = bdisp_v_spec[i].max;
542 memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB);
543 bdisp_v_filter[i].virt = base;
544 bdisp_v_filter[i].paddr = paddr;
546 paddr += BDISP_VF_NB;
553 * bdisp_hw_get_hf_addr
554 * @inc: resize increment
556 * Find the horizontal filter table that fits the resize increment
559 * table physical address
561 static dma_addr_t bdisp_hw_get_hf_addr(u16 inc)
565 for (i = NB_H_FILTER - 1; i > 0; i--)
566 if ((bdisp_h_filter[i].min < inc) &&
567 (inc <= bdisp_h_filter[i].max))
570 return bdisp_h_filter[i].paddr;
574 * bdisp_hw_get_vf_addr
575 * @inc: resize increment
577 * Find the vertical filter table that fits the resize increment
580 * table physical address
582 static dma_addr_t bdisp_hw_get_vf_addr(u16 inc)
586 for (i = NB_V_FILTER - 1; i > 0; i--)
587 if ((bdisp_v_filter[i].min < inc) &&
588 (inc <= bdisp_v_filter[i].max))
591 return bdisp_v_filter[i].paddr;
598 * @inc: resize increment in 6.10 format
600 * Computes the increment (inverse of scale) in 6.10 format
605 static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc)
617 tmp = (from << 10) / to;
618 if ((tmp > 0xFFFF) || (!tmp))
619 /* overflow (downscale x 63) or too small (upscale x 1024) */
628 * bdisp_hw_get_hv_inc
629 * @ctx: device context
630 * @h_inc: horizontal increment
631 * @v_inc: vertical increment
633 * Computes the horizontal & vertical increments (inverse of scale)
638 static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc)
640 u32 src_w, src_h, dst_w, dst_h;
642 src_w = ctx->src.crop.width;
643 src_h = ctx->src.crop.height;
644 dst_w = ctx->dst.crop.width;
645 dst_h = ctx->dst.crop.height;
647 if (bdisp_hw_get_inc(src_w, dst_w, h_inc) ||
648 bdisp_hw_get_inc(src_h, dst_h, v_inc)) {
649 dev_err(ctx->bdisp_dev->dev,
650 "scale factors failed (%dx%d)->(%dx%d)\n",
651 src_w, src_h, dst_w, dst_h);
659 * bdisp_hw_get_op_cfg
660 * @ctx: device context
661 * @c: operation configuration
663 * Check which blitter operations are expected and sets the scaling increments
668 static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c)
670 struct device *dev = ctx->bdisp_dev->dev;
671 struct bdisp_frame *src = &ctx->src;
672 struct bdisp_frame *dst = &ctx->dst;
674 if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) {
675 dev_err(dev, "Image width out of HW caps\n");
679 c->wide = src->width > MAX_SRC_WIDTH;
681 c->hflip = ctx->hflip;
682 c->vflip = ctx->vflip;
684 c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED);
686 c->src_nbp = src->fmt->nb_planes;
687 c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
688 (src->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
689 c->src_420 = c->src_yuv;
691 c->dst_nbp = dst->fmt->nb_planes;
692 c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
693 (dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
694 c->dst_420 = c->dst_yuv;
696 c->cconv = (c->src_yuv != c->dst_yuv);
698 if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) {
699 dev_err(dev, "Scale factor out of HW caps\n");
703 /* Deinterlacing adjustment : stretch a field to a frame */
704 if (c->src_interlaced)
707 if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10)))
716 * bdisp_hw_color_format
717 * @pixelformat: v4l2 pixel format
719 * v4l2 to bdisp pixel format convert
724 static u32 bdisp_hw_color_format(u32 pixelformat)
728 switch (pixelformat) {
729 case V4L2_PIX_FMT_YUV420:
730 ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT);
732 case V4L2_PIX_FMT_NV12:
733 ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
735 case V4L2_PIX_FMT_RGB565:
736 ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT);
738 case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */
739 ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT);
741 case V4L2_PIX_FMT_RGB24: /* RGB888 format */
742 ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
744 case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */
747 ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R;
755 * bdisp_hw_build_node
756 * @ctx: device context
757 * @cfg: operation configuration
758 * @node: node to be set
759 * @t_plan: whether the node refers to a RGB/Y or a CbCr plane
760 * @src_x_offset: x offset in the source image
767 static void bdisp_hw_build_node(struct bdisp_ctx *ctx,
768 struct bdisp_op_cfg *cfg,
769 struct bdisp_node *node,
770 enum bdisp_target_plan t_plan, int src_x_offset)
772 struct bdisp_frame *src = &ctx->src;
773 struct bdisp_frame *dst = &ctx->dst;
774 u16 h_inc, v_inc, yh_inc, yv_inc;
775 struct v4l2_rect src_rect = src->crop;
776 struct v4l2_rect dst_rect = dst->crop;
778 s32 dst_width = dst->crop.width;
779 u32 src_fmt, dst_fmt;
782 dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__);
784 memset(node, 0, sizeof(*node));
786 /* Adjust src and dst areas wrt src_x_offset */
787 src_rect.left += src_x_offset;
788 src_rect.width -= src_x_offset;
789 src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width);
791 dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width;
792 dst_rect.left += dst_x_offset;
793 dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width;
796 src_fmt = src->fmt->pixelformat;
797 dst_fmt = dst->fmt->pixelformat;
800 node->cic = BLT_CIC_ALL_GRP;
801 node->ack = BLT_ACK_BYPASS_S2S3;
803 switch (cfg->src_nbp) {
805 /* Src2 = RGB / Src1 = Src3 = off */
806 node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF;
810 * Src2 = CbCr or ColorFill if writing the Y plane
812 node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM;
813 if (t_plan == BDISP_Y)
814 node->ins |= BLT_INS_S2_CF;
816 node->ins |= BLT_INS_S2_MEM;
821 * Src2 = Cb or ColorFill if writing the Y plane
822 * Src1 = Cr or ColorFill if writing the Y plane */
823 node->ins = BLT_INS_S3_MEM;
824 if (t_plan == BDISP_Y)
825 node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF;
827 node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM;
832 node->ins |= cfg->cconv ? BLT_INS_IVMX : 0;
833 /* Scale needed if scaling OR 4:2:0 up/downsampling */
834 node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ?
838 node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0];
840 node->tty = dst->bytesperline;
841 node->tty |= bdisp_hw_color_format(dst_fmt);
842 node->tty |= BLT_TTY_DITHER;
843 node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0;
844 node->tty |= cfg->hflip ? BLT_TTY_HSO : 0;
845 node->tty |= cfg->vflip ? BLT_TTY_VSO : 0;
847 if (cfg->dst_420 && (t_plan == BDISP_CBCR)) {
848 /* 420 chroma downsampling */
849 dst_rect.height /= 2;
857 node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top;
859 node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) :
862 node->tsz = dst_rect.height << 16 | dst_rect.width;
864 if (cfg->src_interlaced) {
865 /* handle only the top field which is half height of a frame */
867 src_rect.height /= 2;
870 if (cfg->src_nbp == 1) {
872 node->s2ba = src->paddr[0];
874 node->s2ty = src->bytesperline;
875 if (cfg->src_interlaced)
878 node->s2ty |= bdisp_hw_color_format(src_fmt);
880 node->s2xy = src_rect.top << 16 | src_rect.left;
881 node->s2sz = src_rect.height << 16 | src_rect.width;
883 /* Src 2 : Cb or CbCr */
885 /* 420 chroma upsampling */
889 src_rect.height /= 2;
892 node->s2ba = src->paddr[1];
894 node->s2ty = src->bytesperline;
895 if (cfg->src_nbp == 3)
897 if (cfg->src_interlaced)
900 node->s2ty |= bdisp_hw_color_format(src_fmt);
902 node->s2xy = src_rect.top << 16 | src_rect.left;
903 node->s2sz = src_rect.height << 16 | src_rect.width;
905 if (cfg->src_nbp == 3) {
907 node->s1ba = src->paddr[2];
909 node->s1ty = node->s2ty;
910 node->s1xy = node->s2xy;
914 node->s3ba = src->paddr[0];
916 node->s3ty = src->bytesperline;
917 if (cfg->src_interlaced)
919 node->s3ty |= bdisp_hw_color_format(src_fmt);
921 if ((t_plan != BDISP_CBCR) && cfg->src_420) {
922 /* No chroma upsampling for output RGB / Y plane */
923 node->s3xy = node->s2xy * 2;
924 node->s3sz = node->s2sz * 2;
926 /* No need to read Y (Src3) when writing Chroma */
927 node->s3ty |= BLT_S3TY_BLANK_ACC;
928 node->s3xy = node->s2xy;
929 node->s3sz = node->s2sz;
933 /* Resize (scale OR 4:2:0: chroma up/downsampling) */
934 if (node->ins & BLT_INS_SCALE) {
935 /* no need to compute Y when writing CbCr from RGB input */
936 bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv;
940 node->fctl = BLT_FCTL_HV_SCALE;
942 node->fctl |= BLT_FCTL_Y_HV_SCALE;
944 node->fctl = BLT_FCTL_HV_SAMPLE;
946 node->fctl |= BLT_FCTL_Y_HV_SAMPLE;
949 /* RSF - Chroma may need to be up/downsampled */
952 if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) {
953 /* RGB to 4:2:0 for Chroma: downsample */
956 } else if (cfg->src_420 && !cfg->dst_420) {
957 /* 4:2:0: to RGB: upsample*/
961 node->rsf = v_inc << 16 | h_inc;
964 node->rzi = BLT_RZI_DEFAULT;
966 /* Filter table physical addr */
967 node->hfp = bdisp_hw_get_hf_addr(h_inc);
968 node->vfp = bdisp_hw_get_vf_addr(v_inc);
975 node->y_rsf = yv_inc << 16 | yh_inc;
976 node->y_rzi = BLT_RZI_DEFAULT;
977 node->y_hfp = bdisp_hw_get_hf_addr(yh_inc);
978 node->y_vfp = bdisp_hw_get_vf_addr(yv_inc);
982 /* Versatile matrix for RGB / YUV conversion */
984 ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv;
986 node->ivmx0 = ivmx[0];
987 node->ivmx1 = ivmx[1];
988 node->ivmx2 = ivmx[2];
989 node->ivmx3 = ivmx[3];
994 * bdisp_hw_build_all_nodes
995 * @ctx: device context
997 * Build all the nodes for the blitter operation
1002 static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx)
1004 struct bdisp_op_cfg cfg;
1005 unsigned int i, nid = 0;
1006 int src_x_offset = 0;
1008 for (i = 0; i < MAX_NB_NODE; i++)
1009 if (!ctx->node[i]) {
1010 dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i);
1014 /* Get configuration (scale, flip, ...) */
1015 if (bdisp_hw_get_op_cfg(ctx, &cfg))
1018 /* Split source in vertical strides (HW constraint) */
1019 for (i = 0; i < MAX_VERTICAL_STRIDES; i++) {
1020 /* Build RGB/Y node and link it to the previous node */
1021 bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
1022 cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y,
1025 ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
1028 /* Build additional Cb(Cr) node, link it to the previous one */
1029 if (cfg.dst_nbp > 1) {
1030 bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
1031 BDISP_CBCR, src_x_offset);
1032 ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
1036 /* Next stride until full width covered */
1037 src_x_offset += MAX_SRC_WIDTH;
1038 if (src_x_offset >= ctx->src.crop.width)
1042 /* Mark last node as the last */
1043 ctx->node[nid - 1]->nip = 0;
1049 * bdisp_hw_save_request
1050 * @ctx: device context
1052 * Save a copy of the request and of the built nodes
1057 static void bdisp_hw_save_request(struct bdisp_ctx *ctx)
1059 struct bdisp_node **copy_node = ctx->bdisp_dev->dbg.copy_node;
1060 struct bdisp_request *request = &ctx->bdisp_dev->dbg.copy_request;
1061 struct bdisp_node **node = ctx->node;
1065 request->src = ctx->src;
1066 request->dst = ctx->dst;
1067 request->hflip = ctx->hflip;
1068 request->vflip = ctx->vflip;
1072 for (i = 0; i < MAX_NB_NODE; i++) {
1073 /* Allocate memory if not done yet */
1074 if (!copy_node[i]) {
1075 copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev,
1076 sizeof(*copy_node[i]),
1081 *copy_node[i] = *node[i];
1087 * @ctx: device context
1089 * Send the request to the HW
1094 int bdisp_hw_update(struct bdisp_ctx *ctx)
1097 struct bdisp_dev *bdisp = ctx->bdisp_dev;
1098 struct device *dev = bdisp->dev;
1099 unsigned int node_id;
1101 dev_dbg(dev, "%s\n", __func__);
1104 ret = bdisp_hw_build_all_nodes(ctx);
1106 dev_err(dev, "cannot build nodes (%d)\n", ret);
1110 /* Save a copy of the request */
1111 bdisp_hw_save_request(ctx);
1113 /* Configure interrupt to 'Last Node Reached for AQ1' */
1114 writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL);
1115 writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0);
1117 /* Write first node addr */
1118 writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP);
1120 /* Find and write last node addr : this starts the HW processing */
1121 for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) {
1122 if (!ctx->node[node_id]->nip)
1125 writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA);