1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2018 Intel Corporation
3
4#include <linux/device.h>
5#include <linux/iopoll.h>
6#include <linux/slab.h>
7
8#include "ipu3.h"
9#include "ipu3-css.h"
10#include "ipu3-css-fw.h"
11#include "ipu3-css-params.h"
12#include "ipu3-dmamap.h"
13#include "ipu3-tables.h"
14
15/* IRQ configuration */
16#define IMGU_IRQCTRL_IRQ_MASK (IMGU_IRQCTRL_IRQ_SP1 | \
17 IMGU_IRQCTRL_IRQ_SP2 | \
18 IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
19 IMGU_IRQCTRL_IRQ_SW_PIN(1))
20
21#define IPU3_CSS_FORMAT_BPP_DEN 50 /* Denominator */
22
23/* Some sane limits for resolutions */
24#define IPU3_CSS_MIN_RES 32
25#define IPU3_CSS_MAX_H 3136
26#define IPU3_CSS_MAX_W 4224
27
28/* minimal envelope size(GDC in - out) should be 4 */
29#define MIN_ENVELOPE 4
30
31/*
32 * pre-allocated buffer size for CSS ABI, auxiliary frames
33 * after BDS and before GDC. Those values should be tuned
34 * to big enough to avoid buffer re-allocation when
35 * streaming to lower streaming latency.
36 */
37#define CSS_ABI_SIZE 136
38#define CSS_BDS_SIZE (4480 * 3200 * 3)
39#define CSS_GDC_SIZE (4224 * 3200 * 12 / 8)
40
41#define IPU3_CSS_QUEUE_TO_FLAGS(q) (1 << (q))
42#define IPU3_CSS_FORMAT_FL_IN \
43 IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_IN)
44#define IPU3_CSS_FORMAT_FL_OUT \
45 IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_OUT)
46#define IPU3_CSS_FORMAT_FL_VF \
47 IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_VF)
48
49/* Formats supported by IPU3 Camera Sub System */
50static const struct imgu_css_format imgu_css_formats[] = {
51 {
52 .pixelformat = V4L2_PIX_FMT_NV12,
53 .colorspace = V4L2_COLORSPACE_SRGB,
54 .frame_format = IMGU_ABI_FRAME_FORMAT_NV12,
55 .osys_format = IMGU_ABI_OSYS_FORMAT_NV12,
56 .osys_tiling = IMGU_ABI_OSYS_TILING_NONE,
57 .chroma_decim = 4,
58 .width_align = IPU3_UAPI_ISP_VEC_ELEMS,
59 .flags = IPU3_CSS_FORMAT_FL_OUT | IPU3_CSS_FORMAT_FL_VF,
60 }, {
61 /* Each 32 bytes contains 25 10-bit pixels */
62 .pixelformat = V4L2_PIX_FMT_IPU3_SBGGR10,
63 .colorspace = V4L2_COLORSPACE_RAW,
64 .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
65 .bayer_order = IMGU_ABI_BAYER_ORDER_BGGR,
66 .bit_depth = 10,
67 .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
68 .flags = IPU3_CSS_FORMAT_FL_IN,
69 }, {
70 .pixelformat = V4L2_PIX_FMT_IPU3_SGBRG10,
71 .colorspace = V4L2_COLORSPACE_RAW,
72 .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
73 .bayer_order = IMGU_ABI_BAYER_ORDER_GBRG,
74 .bit_depth = 10,
75 .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
76 .flags = IPU3_CSS_FORMAT_FL_IN,
77 }, {
78 .pixelformat = V4L2_PIX_FMT_IPU3_SGRBG10,
79 .colorspace = V4L2_COLORSPACE_RAW,
80 .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
81 .bayer_order = IMGU_ABI_BAYER_ORDER_GRBG,
82 .bit_depth = 10,
83 .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
84 .flags = IPU3_CSS_FORMAT_FL_IN,
85 }, {
86 .pixelformat = V4L2_PIX_FMT_IPU3_SRGGB10,
87 .colorspace = V4L2_COLORSPACE_RAW,
88 .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
89 .bayer_order = IMGU_ABI_BAYER_ORDER_RGGB,
90 .bit_depth = 10,
91 .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
92 .flags = IPU3_CSS_FORMAT_FL_IN,
93 },
94};
95
96static const struct {
97 enum imgu_abi_queue_id qid;
98 size_t ptr_ofs;
99} imgu_css_queues[IPU3_CSS_QUEUES] = {
100 [IPU3_CSS_QUEUE_IN] = {
101 IMGU_ABI_QUEUE_C_ID,
102 offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
103 },
104 [IPU3_CSS_QUEUE_OUT] = {
105 IMGU_ABI_QUEUE_D_ID,
106 offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
107 },
108 [IPU3_CSS_QUEUE_VF] = {
109 IMGU_ABI_QUEUE_E_ID,
110 offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
111 },
112 [IPU3_CSS_QUEUE_STAT_3A] = {
113 IMGU_ABI_QUEUE_F_ID,
114 offsetof(struct imgu_abi_buffer, payload.s3a.data_ptr)
115 },
116};
117
118/* Initialize queue based on given format, adjust format as needed */
119static int imgu_css_queue_init(struct imgu_css_queue *queue,
120 struct v4l2_pix_format_mplane *fmt, u32 flags)
121{
122 struct v4l2_pix_format_mplane *const f = &queue->fmt.mpix;
123 unsigned int i;
124 u32 sizeimage;
125
126 INIT_LIST_HEAD(list: &queue->bufs);
127
128 queue->css_fmt = NULL; /* Disable */
129 if (!fmt)
130 return 0;
131
132 for (i = 0; i < ARRAY_SIZE(imgu_css_formats); i++) {
133 if (!(imgu_css_formats[i].flags & flags))
134 continue;
135 queue->css_fmt = &imgu_css_formats[i];
136 if (imgu_css_formats[i].pixelformat == fmt->pixelformat)
137 break;
138 }
139 if (!queue->css_fmt)
140 return -EINVAL; /* Could not find any suitable format */
141
142 queue->fmt.mpix = *fmt;
143
144 f->width = ALIGN(clamp_t(u32, f->width,
145 IPU3_CSS_MIN_RES, IPU3_CSS_MAX_W), 2);
146 f->height = ALIGN(clamp_t(u32, f->height,
147 IPU3_CSS_MIN_RES, IPU3_CSS_MAX_H), 2);
148 queue->width_pad = ALIGN(f->width, queue->css_fmt->width_align);
149 f->plane_fmt[0].bytesperline =
150 imgu_bytesperline(width: f->width, frame_format: queue->css_fmt->frame_format);
151 sizeimage = f->height * f->plane_fmt[0].bytesperline;
152 if (queue->css_fmt->chroma_decim)
153 sizeimage += 2 * sizeimage / queue->css_fmt->chroma_decim;
154
155 f->plane_fmt[0].sizeimage = sizeimage;
156 f->field = V4L2_FIELD_NONE;
157 f->num_planes = 1;
158 f->colorspace = queue->css_fmt->colorspace;
159 f->flags = 0;
160 f->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
161 f->quantization = V4L2_QUANTIZATION_DEFAULT;
162 f->xfer_func = V4L2_XFER_FUNC_DEFAULT;
163 memset(f->reserved, 0, sizeof(f->reserved));
164
165 return 0;
166}
167
168static bool imgu_css_queue_enabled(struct imgu_css_queue *q)
169{
170 return q->css_fmt;
171}
172
173/******************* css hw *******************/
174
175/* In the style of writesl() defined in include/asm-generic/io.h */
176static inline void writes(const void *mem, ssize_t count, void __iomem *addr)
177{
178 if (count >= 4) {
179 const u32 *buf = mem;
180
181 count /= 4;
182 do {
183 writel(val: *buf++, addr);
184 addr += 4;
185 } while (--count);
186 }
187}
188
189/* Wait until register `reg', masked with `mask', becomes `cmp' */
190static int imgu_hw_wait(void __iomem *base, int reg, u32 mask, u32 cmp)
191{
192 u32 val;
193
194 return readl_poll_timeout(base + reg, val, (val & mask) == cmp,
195 1000, 100 * 1000);
196}
197
198/* Initialize the IPU3 CSS hardware and associated h/w blocks */
199
200int imgu_css_set_powerup(struct device *dev, void __iomem *base,
201 unsigned int freq)
202{
203 u32 pm_ctrl, state, val;
204
205 dev_dbg(dev, "%s with freq %u\n", __func__, freq);
206 /* Clear the CSS busy signal */
207 readl(addr: base + IMGU_REG_GP_BUSY);
208 writel(val: 0, addr: base + IMGU_REG_GP_BUSY);
209
210 /* Wait for idle signal */
211 if (imgu_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
212 IMGU_STATE_IDLE_STS)) {
213 dev_err(dev, "failed to set CSS idle\n");
214 goto fail;
215 }
216
217 /* Reset the css */
218 writel(readl(addr: base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
219 addr: base + IMGU_REG_PM_CTRL);
220
221 usleep_range(min: 200, max: 300);
222
223 /** Prepare CSS */
224
225 pm_ctrl = readl(addr: base + IMGU_REG_PM_CTRL);
226 state = readl(addr: base + IMGU_REG_STATE);
227
228 dev_dbg(dev, "CSS pm_ctrl 0x%x state 0x%x (power %s)\n",
229 pm_ctrl, state, state & IMGU_STATE_POWER_DOWN ? "down" : "up");
230
231 /* Power up CSS using wrapper */
232 if (state & IMGU_STATE_POWER_DOWN) {
233 writel(IMGU_PM_CTRL_RACE_TO_HALT | IMGU_PM_CTRL_START,
234 addr: base + IMGU_REG_PM_CTRL);
235 if (imgu_hw_wait(base, IMGU_REG_PM_CTRL,
236 IMGU_PM_CTRL_START, cmp: 0)) {
237 dev_err(dev, "failed to power up CSS\n");
238 goto fail;
239 }
240 usleep_range(min: 2000, max: 3000);
241 } else {
242 writel(IMGU_PM_CTRL_RACE_TO_HALT, addr: base + IMGU_REG_PM_CTRL);
243 }
244
245 /* Set the busy bit */
246 writel(readl(addr: base + IMGU_REG_GP_BUSY) | 1, addr: base + IMGU_REG_GP_BUSY);
247
248 /* Set CSS clock frequency */
249 pm_ctrl = readl(addr: base + IMGU_REG_PM_CTRL);
250 val = pm_ctrl & ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
251 writel(val, addr: base + IMGU_REG_PM_CTRL);
252 writel(val: 0, addr: base + IMGU_REG_GP_BUSY);
253 if (imgu_hw_wait(base, IMGU_REG_STATE,
254 IMGU_STATE_PWRDNM_FSM_MASK, cmp: 0)) {
255 dev_err(dev, "failed to pwrdn CSS\n");
256 goto fail;
257 }
258 val = (freq / IMGU_SYSTEM_REQ_FREQ_DIVIDER) & IMGU_SYSTEM_REQ_FREQ_MASK;
259 writel(val, addr: base + IMGU_REG_SYSTEM_REQ);
260 writel(val: 1, addr: base + IMGU_REG_GP_BUSY);
261 writel(readl(addr: base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_HALT,
262 addr: base + IMGU_REG_PM_CTRL);
263 if (imgu_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_HALT_STS,
264 IMGU_STATE_HALT_STS)) {
265 dev_err(dev, "failed to halt CSS\n");
266 goto fail;
267 }
268
269 writel(readl(addr: base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_START,
270 addr: base + IMGU_REG_PM_CTRL);
271 if (imgu_hw_wait(base, IMGU_REG_PM_CTRL, IMGU_PM_CTRL_START, cmp: 0)) {
272 dev_err(dev, "failed to start CSS\n");
273 goto fail;
274 }
275 writel(readl(addr: base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_UNHALT,
276 addr: base + IMGU_REG_PM_CTRL);
277
278 val = readl(addr: base + IMGU_REG_PM_CTRL); /* get pm_ctrl */
279 val &= ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
280 val |= pm_ctrl & (IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
281 writel(val, addr: base + IMGU_REG_PM_CTRL);
282
283 return 0;
284
285fail:
286 imgu_css_set_powerdown(dev, base);
287 return -EIO;
288}
289
290void imgu_css_set_powerdown(struct device *dev, void __iomem *base)
291{
292 dev_dbg(dev, "%s\n", __func__);
293 /* wait for cio idle signal */
294 if (imgu_hw_wait(base, IMGU_REG_CIO_GATE_BURST_STATE,
295 IMGU_CIO_GATE_BURST_MASK, cmp: 0))
296 dev_warn(dev, "wait cio gate idle timeout");
297
298 /* wait for css idle signal */
299 if (imgu_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
300 IMGU_STATE_IDLE_STS))
301 dev_warn(dev, "wait css idle timeout\n");
302
303 /* do halt-halted handshake with css */
304 writel(val: 1, addr: base + IMGU_REG_GP_HALT);
305 if (imgu_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_HALT_STS,
306 IMGU_STATE_HALT_STS))
307 dev_warn(dev, "failed to halt css");
308
309 /* de-assert the busy bit */
310 writel(val: 0, addr: base + IMGU_REG_GP_BUSY);
311}
312
313static void imgu_css_hw_enable_irq(struct imgu_css *css)
314{
315 void __iomem *const base = css->base;
316 u32 val, i;
317
318 /* Set up interrupts */
319
320 /*
321 * Enable IRQ on the SP which signals that SP goes to idle
322 * (aka ready state) and set trigger to pulse
323 */
324 val = readl(addr: base + IMGU_REG_SP_CTRL(0)) | IMGU_CTRL_IRQ_READY;
325 writel(val, addr: base + IMGU_REG_SP_CTRL(0));
326 writel(val: val | IMGU_CTRL_IRQ_CLEAR, addr: base + IMGU_REG_SP_CTRL(0));
327
328 /* Enable IRQs from the IMGU wrapper */
329 writel(IMGU_REG_INT_CSS_IRQ, addr: base + IMGU_REG_INT_ENABLE);
330 /* Clear */
331 writel(IMGU_REG_INT_CSS_IRQ, addr: base + IMGU_REG_INT_STATUS);
332
333 /* Enable IRQs from main IRQ controller */
334 writel(val: ~0, addr: base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(IMGU_IRQCTRL_MAIN));
335 writel(val: 0, addr: base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN));
336 writel(IMGU_IRQCTRL_IRQ_MASK,
337 addr: base + IMGU_REG_IRQCTRL_EDGE(IMGU_IRQCTRL_MAIN));
338 writel(IMGU_IRQCTRL_IRQ_MASK,
339 addr: base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN));
340 writel(IMGU_IRQCTRL_IRQ_MASK,
341 addr: base + IMGU_REG_IRQCTRL_CLEAR(IMGU_IRQCTRL_MAIN));
342 writel(IMGU_IRQCTRL_IRQ_MASK,
343 addr: base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN));
344 /* Wait for write complete */
345 readl(addr: base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN));
346
347 /* Enable IRQs from SP0 and SP1 controllers */
348 for (i = IMGU_IRQCTRL_SP0; i <= IMGU_IRQCTRL_SP1; i++) {
349 writel(val: ~0, addr: base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(i));
350 writel(val: 0, addr: base + IMGU_REG_IRQCTRL_MASK(i));
351 writel(IMGU_IRQCTRL_IRQ_MASK, addr: base + IMGU_REG_IRQCTRL_EDGE(i));
352 writel(IMGU_IRQCTRL_IRQ_MASK,
353 addr: base + IMGU_REG_IRQCTRL_ENABLE(i));
354 writel(IMGU_IRQCTRL_IRQ_MASK, addr: base + IMGU_REG_IRQCTRL_CLEAR(i));
355 writel(IMGU_IRQCTRL_IRQ_MASK, addr: base + IMGU_REG_IRQCTRL_MASK(i));
356 /* Wait for write complete */
357 readl(addr: base + IMGU_REG_IRQCTRL_ENABLE(i));
358 }
359}
360
361static int imgu_css_hw_init(struct imgu_css *css)
362{
363 /* For checking that streaming monitor statuses are valid */
364 static const struct {
365 u32 reg;
366 u32 mask;
367 const char *name;
368 } stream_monitors[] = {
369 {
370 IMGU_REG_GP_SP1_STRMON_STAT,
371 IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP,
372 "ISP0 to SP0"
373 }, {
374 IMGU_REG_GP_ISP_STRMON_STAT,
375 IMGU_GP_STRMON_STAT_SP1_PORT_ISP2SP1,
376 "SP0 to ISP0"
377 }, {
378 IMGU_REG_GP_MOD_STRMON_STAT,
379 IMGU_GP_STRMON_STAT_MOD_PORT_ISP2DMA,
380 "ISP0 to DMA0"
381 }, {
382 IMGU_REG_GP_ISP_STRMON_STAT,
383 IMGU_GP_STRMON_STAT_ISP_PORT_DMA2ISP,
384 "DMA0 to ISP0"
385 }, {
386 IMGU_REG_GP_MOD_STRMON_STAT,
387 IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC,
388 "ISP0 to GDC0"
389 }, {
390 IMGU_REG_GP_MOD_STRMON_STAT,
391 IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS,
392 "GDC0 to ISP0"
393 }, {
394 IMGU_REG_GP_MOD_STRMON_STAT,
395 IMGU_GP_STRMON_STAT_MOD_PORT_SP12DMA,
396 "SP0 to DMA0"
397 }, {
398 IMGU_REG_GP_SP1_STRMON_STAT,
399 IMGU_GP_STRMON_STAT_SP1_PORT_DMA2SP1,
400 "DMA0 to SP0"
401 }, {
402 IMGU_REG_GP_MOD_STRMON_STAT,
403 IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC,
404 "SP0 to GDC0"
405 }, {
406 IMGU_REG_GP_MOD_STRMON_STAT,
407 IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS,
408 "GDC0 to SP0"
409 },
410 };
411
412 struct device *dev = css->dev;
413 void __iomem *const base = css->base;
414 u32 val, i;
415
416 /* Set instruction cache address and inv bit for ISP, SP, and SP1 */
417 for (i = 0; i < IMGU_NUM_SP; i++) {
418 struct imgu_fw_info *bi =
419 &css->fwp->binary_header[css->fw_sp[i]];
420
421 writel(val: css->binary[css->fw_sp[i]].daddr,
422 addr: base + IMGU_REG_SP_ICACHE_ADDR(bi->type));
423 writel(readl(addr: base + IMGU_REG_SP_CTRL(bi->type)) |
424 IMGU_CTRL_ICACHE_INV,
425 addr: base + IMGU_REG_SP_CTRL(bi->type));
426 }
427 writel(val: css->binary[css->fw_bl].daddr, addr: base + IMGU_REG_ISP_ICACHE_ADDR);
428 writel(readl(addr: base + IMGU_REG_ISP_CTRL) | IMGU_CTRL_ICACHE_INV,
429 addr: base + IMGU_REG_ISP_CTRL);
430
431 /* Check that IMGU hardware is ready */
432
433 if (!(readl(addr: base + IMGU_REG_SP_CTRL(0)) & IMGU_CTRL_IDLE)) {
434 dev_err(dev, "SP is not idle\n");
435 return -EIO;
436 }
437 if (!(readl(addr: base + IMGU_REG_ISP_CTRL) & IMGU_CTRL_IDLE)) {
438 dev_err(dev, "ISP is not idle\n");
439 return -EIO;
440 }
441
442 for (i = 0; i < ARRAY_SIZE(stream_monitors); i++) {
443 val = readl(addr: base + stream_monitors[i].reg);
444 if (val & stream_monitors[i].mask) {
445 dev_err(dev, "error: Stream monitor %s is valid\n",
446 stream_monitors[i].name);
447 return -EIO;
448 }
449 }
450
451 /* Initialize GDC with default values */
452
453 for (i = 0; i < ARRAY_SIZE(imgu_css_gdc_lut[0]); i++) {
454 u32 val0 = imgu_css_gdc_lut[0][i] & IMGU_GDC_LUT_MASK;
455 u32 val1 = imgu_css_gdc_lut[1][i] & IMGU_GDC_LUT_MASK;
456 u32 val2 = imgu_css_gdc_lut[2][i] & IMGU_GDC_LUT_MASK;
457 u32 val3 = imgu_css_gdc_lut[3][i] & IMGU_GDC_LUT_MASK;
458
459 writel(val: val0 | (val1 << 16),
460 addr: base + IMGU_REG_GDC_LUT_BASE + i * 8);
461 writel(val: val2 | (val3 << 16),
462 addr: base + IMGU_REG_GDC_LUT_BASE + i * 8 + 4);
463 }
464
465 return 0;
466}
467
468/* Boot the given IPU3 CSS SP */
469static int imgu_css_hw_start_sp(struct imgu_css *css, int sp)
470{
471 void __iomem *const base = css->base;
472 struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
473 struct imgu_abi_sp_init_dmem_cfg dmem_cfg = {
474 .ddr_data_addr = css->binary[css->fw_sp[sp]].daddr
475 + bi->blob.data_source,
476 .dmem_data_addr = bi->blob.data_target,
477 .dmem_bss_addr = bi->blob.bss_target,
478 .data_size = bi->blob.data_size,
479 .bss_size = bi->blob.bss_size,
480 .sp_id = sp,
481 };
482
483 writes(mem: &dmem_cfg, count: sizeof(dmem_cfg), addr: base +
484 IMGU_REG_SP_DMEM_BASE(sp) + bi->info.sp.init_dmem_data);
485
486 writel(val: bi->info.sp.sp_entry, addr: base + IMGU_REG_SP_START_ADDR(sp));
487
488 writel(readl(addr: base + IMGU_REG_SP_CTRL(sp))
489 | IMGU_CTRL_START | IMGU_CTRL_RUN, addr: base + IMGU_REG_SP_CTRL(sp));
490
491 if (imgu_hw_wait(base: css->base, IMGU_REG_SP_DMEM_BASE(sp)
492 + bi->info.sp.sw_state,
493 mask: ~0, cmp: IMGU_ABI_SP_SWSTATE_INITIALIZED))
494 return -EIO;
495
496 return 0;
497}
498
499/* Start the IPU3 CSS ImgU (Imaging Unit) and all the SPs */
500static int imgu_css_hw_start(struct imgu_css *css)
501{
502 static const u32 event_mask =
503 ((1 << IMGU_ABI_EVTTYPE_OUT_FRAME_DONE) |
504 (1 << IMGU_ABI_EVTTYPE_2ND_OUT_FRAME_DONE) |
505 (1 << IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE) |
506 (1 << IMGU_ABI_EVTTYPE_2ND_VF_OUT_FRAME_DONE) |
507 (1 << IMGU_ABI_EVTTYPE_3A_STATS_DONE) |
508 (1 << IMGU_ABI_EVTTYPE_DIS_STATS_DONE) |
509 (1 << IMGU_ABI_EVTTYPE_PIPELINE_DONE) |
510 (1 << IMGU_ABI_EVTTYPE_FRAME_TAGGED) |
511 (1 << IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE) |
512 (1 << IMGU_ABI_EVTTYPE_METADATA_DONE) |
513 (1 << IMGU_ABI_EVTTYPE_ACC_STAGE_COMPLETE))
514 << IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_OR_SHIFT;
515
516 void __iomem *const base = css->base;
517 struct imgu_fw_info *bi, *bl = &css->fwp->binary_header[css->fw_bl];
518 unsigned int i;
519
520 writel(IMGU_TLB_INVALIDATE, addr: base + IMGU_REG_TLB_INVALIDATE);
521
522 /* Start bootloader */
523
524 writel(val: IMGU_ABI_BL_SWSTATE_BUSY,
525 addr: base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.sw_state);
526 writel(IMGU_NUM_SP,
527 addr: base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.num_dma_cmds);
528
529 for (i = 0; i < IMGU_NUM_SP; i++) {
530 int j = IMGU_NUM_SP - i - 1; /* load sp1 first, then sp0 */
531 struct imgu_fw_info *sp =
532 &css->fwp->binary_header[css->fw_sp[j]];
533 struct imgu_abi_bl_dma_cmd_entry dma_cmd = {
534 .src_addr = css->binary[css->fw_sp[j]].daddr
535 + sp->blob.text_source,
536 .size = sp->blob.text_size,
537 .dst_type = IMGU_ABI_BL_DMACMD_TYPE_SP_PMEM,
538 .dst_addr = IMGU_SP_PMEM_BASE(j),
539 };
540
541 writes(mem: &dma_cmd, count: sizeof(dma_cmd),
542 addr: base + IMGU_REG_ISP_DMEM_BASE + i * sizeof(dma_cmd) +
543 bl->info.bl.dma_cmd_list);
544 }
545
546 writel(val: bl->info.bl.bl_entry, addr: base + IMGU_REG_ISP_START_ADDR);
547
548 writel(readl(addr: base + IMGU_REG_ISP_CTRL)
549 | IMGU_CTRL_START | IMGU_CTRL_RUN, addr: base + IMGU_REG_ISP_CTRL);
550 if (imgu_hw_wait(base: css->base, IMGU_REG_ISP_DMEM_BASE
551 + bl->info.bl.sw_state, mask: ~0,
552 cmp: IMGU_ABI_BL_SWSTATE_OK)) {
553 dev_err(css->dev, "failed to start bootloader\n");
554 return -EIO;
555 }
556
557 /* Start ISP */
558
559 memset(css->xmem_sp_group_ptrs.vaddr, 0,
560 sizeof(struct imgu_abi_sp_group));
561
562 bi = &css->fwp->binary_header[css->fw_sp[0]];
563
564 writel(val: css->xmem_sp_group_ptrs.daddr,
565 addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.per_frame_data);
566
567 writel(val: IMGU_ABI_SP_SWSTATE_TERMINATED,
568 addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sw_state);
569 writel(val: 1, addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb);
570
571 if (imgu_css_hw_start_sp(css, sp: 0))
572 return -EIO;
573
574 writel(val: 0, addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.isp_started);
575 writel(val: 0, addr: base + IMGU_REG_SP_DMEM_BASE(0) +
576 bi->info.sp.host_sp_queues_initialized);
577 writel(val: 0, addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sleep_mode);
578 writel(val: 0, addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb);
579 writel(IMGU_ABI_SP_COMM_COMMAND_READY, addr: base + IMGU_REG_SP_DMEM_BASE(0)
580 + bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
581
582 /* Enable all events for all queues */
583
584 for (i = 0; i < IPU3_CSS_PIPE_ID_NUM; i++)
585 writel(val: event_mask, addr: base + IMGU_REG_SP_DMEM_BASE(0)
586 + bi->info.sp.host_sp_com
587 + IMGU_ABI_SP_COMM_EVENT_IRQ_MASK(i));
588 writel(val: 1, addr: base + IMGU_REG_SP_DMEM_BASE(0) +
589 bi->info.sp.host_sp_queues_initialized);
590
591 /* Start SP1 */
592
593 bi = &css->fwp->binary_header[css->fw_sp[1]];
594
595 writel(val: IMGU_ABI_SP_SWSTATE_TERMINATED,
596 addr: base + IMGU_REG_SP_DMEM_BASE(1) + bi->info.sp.sw_state);
597
598 if (imgu_css_hw_start_sp(css, sp: 1))
599 return -EIO;
600
601 writel(IMGU_ABI_SP_COMM_COMMAND_READY, addr: base + IMGU_REG_SP_DMEM_BASE(1)
602 + bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
603
604 return 0;
605}
606
607static void imgu_css_hw_stop(struct imgu_css *css)
608{
609 void __iomem *const base = css->base;
610 struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[0]];
611
612 /* Stop fw */
613 writel(IMGU_ABI_SP_COMM_COMMAND_TERMINATE,
614 addr: base + IMGU_REG_SP_DMEM_BASE(0) +
615 bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
616 if (imgu_hw_wait(base: css->base, IMGU_REG_SP_CTRL(0),
617 IMGU_CTRL_IDLE, IMGU_CTRL_IDLE))
618 dev_err(css->dev, "wait sp0 idle timeout.\n");
619 if (readl(addr: base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sw_state) !=
620 IMGU_ABI_SP_SWSTATE_TERMINATED)
621 dev_err(css->dev, "sp0 is not terminated.\n");
622 if (imgu_hw_wait(base: css->base, IMGU_REG_ISP_CTRL,
623 IMGU_CTRL_IDLE, IMGU_CTRL_IDLE))
624 dev_err(css->dev, "wait isp idle timeout\n");
625}
626
627static void imgu_css_hw_cleanup(struct imgu_css *css)
628{
629 void __iomem *const base = css->base;
630
631 /** Reset CSS **/
632
633 /* Clear the CSS busy signal */
634 readl(addr: base + IMGU_REG_GP_BUSY);
635 writel(val: 0, addr: base + IMGU_REG_GP_BUSY);
636
637 /* Wait for idle signal */
638 if (imgu_hw_wait(base: css->base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
639 IMGU_STATE_IDLE_STS))
640 dev_err(css->dev, "failed to shut down hw cleanly\n");
641
642 /* Reset the css */
643 writel(readl(addr: base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
644 addr: base + IMGU_REG_PM_CTRL);
645
646 usleep_range(min: 200, max: 300);
647}
648
649static void imgu_css_pipeline_cleanup(struct imgu_css *css, unsigned int pipe)
650{
651 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
652 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
653 unsigned int i;
654
655 imgu_css_pool_cleanup(imgu, pool: &css_pipe->pool.parameter_set_info);
656 imgu_css_pool_cleanup(imgu, pool: &css_pipe->pool.acc);
657 imgu_css_pool_cleanup(imgu, pool: &css_pipe->pool.gdc);
658 imgu_css_pool_cleanup(imgu, pool: &css_pipe->pool.obgrid);
659
660 for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
661 imgu_css_pool_cleanup(imgu, pool: &css_pipe->pool.binary_params_p[i]);
662}
663
664/*
665 * This function initializes various stages of the
666 * IPU3 CSS ISP pipeline
667 */
668static int imgu_css_pipeline_init(struct imgu_css *css, unsigned int pipe)
669{
670 static const int BYPC = 2; /* Bytes per component */
671 static const struct imgu_abi_buffer_sp buffer_sp_init = {
672 .buf_src = {.queue_id = IMGU_ABI_QUEUE_EVENT_ID},
673 .buf_type = IMGU_ABI_BUFFER_TYPE_INVALID,
674 };
675
676 struct imgu_abi_isp_iterator_config *cfg_iter;
677 struct imgu_abi_isp_ref_config *cfg_ref;
678 struct imgu_abi_isp_dvs_config *cfg_dvs;
679 struct imgu_abi_isp_tnr3_config *cfg_tnr;
680 struct imgu_abi_isp_ref_dmem_state *cfg_ref_state;
681 struct imgu_abi_isp_tnr3_dmem_state *cfg_tnr_state;
682
683 const int stage = 0;
684 unsigned int i, j;
685
686 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
687 struct imgu_css_queue *css_queue_in =
688 &css_pipe->queue[IPU3_CSS_QUEUE_IN];
689 struct imgu_css_queue *css_queue_out =
690 &css_pipe->queue[IPU3_CSS_QUEUE_OUT];
691 struct imgu_css_queue *css_queue_vf =
692 &css_pipe->queue[IPU3_CSS_QUEUE_VF];
693 const struct imgu_fw_info *bi =
694 &css->fwp->binary_header[css_pipe->bindex];
695 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
696
697 struct imgu_fw_config_memory_offsets *cofs = (void *)css->fwp +
698 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG];
699 struct imgu_fw_state_memory_offsets *sofs = (void *)css->fwp +
700 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE];
701
702 struct imgu_abi_isp_stage *isp_stage;
703 struct imgu_abi_sp_stage *sp_stage;
704 struct imgu_abi_sp_group *sp_group;
705 struct imgu_abi_frames_sp *frames_sp;
706 struct imgu_abi_frame_sp *frame_sp;
707 struct imgu_abi_frame_sp_info *frame_sp_info;
708
709 const unsigned int bds_width_pad =
710 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
711 2 * IPU3_UAPI_ISP_VEC_ELEMS);
712
713 const enum imgu_abi_memories m0 = IMGU_ABI_MEM_ISP_DMEM0;
714 enum imgu_abi_param_class cfg = IMGU_ABI_PARAM_CLASS_CONFIG;
715 void *vaddr = css_pipe->binary_params_cs[cfg - 1][m0].vaddr;
716
717 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
718
719 dev_dbg(css->dev, "%s for pipe %d", __func__, pipe);
720
721 /* Configure iterator */
722
723 cfg_iter = imgu_css_fw_pipeline_params(css, pipe, cls: cfg, mem: m0,
724 par: &cofs->dmem.iterator,
725 par_size: sizeof(*cfg_iter), binary_params: vaddr);
726 if (!cfg_iter)
727 goto bad_firmware;
728
729 frame_sp_info = &cfg_iter->input_info;
730 frame_sp_info->res.width = css_queue_in->fmt.mpix.width;
731 frame_sp_info->res.height = css_queue_in->fmt.mpix.height;
732 frame_sp_info->padded_width = css_queue_in->width_pad;
733 frame_sp_info->format = css_queue_in->css_fmt->frame_format;
734 frame_sp_info->raw_bit_depth = css_queue_in->css_fmt->bit_depth;
735 frame_sp_info->raw_bayer_order = css_queue_in->css_fmt->bayer_order;
736 frame_sp_info->raw_type = IMGU_ABI_RAW_TYPE_BAYER;
737
738 frame_sp_info = &cfg_iter->internal_info;
739 frame_sp_info->res.width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
740 frame_sp_info->res.height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
741 frame_sp_info->padded_width = bds_width_pad;
742 frame_sp_info->format = css_queue_out->css_fmt->frame_format;
743 frame_sp_info->raw_bit_depth = css_queue_out->css_fmt->bit_depth;
744 frame_sp_info->raw_bayer_order = css_queue_out->css_fmt->bayer_order;
745 frame_sp_info->raw_type = IMGU_ABI_RAW_TYPE_BAYER;
746
747 frame_sp_info = &cfg_iter->output_info;
748 frame_sp_info->res.width = css_queue_out->fmt.mpix.width;
749 frame_sp_info->res.height = css_queue_out->fmt.mpix.height;
750 frame_sp_info->padded_width = css_queue_out->width_pad;
751 frame_sp_info->format = css_queue_out->css_fmt->frame_format;
752 frame_sp_info->raw_bit_depth = css_queue_out->css_fmt->bit_depth;
753 frame_sp_info->raw_bayer_order = css_queue_out->css_fmt->bayer_order;
754 frame_sp_info->raw_type = IMGU_ABI_RAW_TYPE_BAYER;
755
756 frame_sp_info = &cfg_iter->vf_info;
757 frame_sp_info->res.width = css_queue_vf->fmt.mpix.width;
758 frame_sp_info->res.height = css_queue_vf->fmt.mpix.height;
759 frame_sp_info->padded_width = css_queue_vf->width_pad;
760 frame_sp_info->format = css_queue_vf->css_fmt->frame_format;
761 frame_sp_info->raw_bit_depth = css_queue_vf->css_fmt->bit_depth;
762 frame_sp_info->raw_bayer_order = css_queue_vf->css_fmt->bayer_order;
763 frame_sp_info->raw_type = IMGU_ABI_RAW_TYPE_BAYER;
764
765 cfg_iter->dvs_envelope.width =
766 css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].width;
767 cfg_iter->dvs_envelope.height =
768 css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].height;
769
770 /* Configure reference (delay) frames */
771
772 cfg_ref = imgu_css_fw_pipeline_params(css, pipe, cls: cfg, mem: m0,
773 par: &cofs->dmem.ref,
774 par_size: sizeof(*cfg_ref), binary_params: vaddr);
775 if (!cfg_ref)
776 goto bad_firmware;
777
778 cfg_ref->port_b.crop = 0;
779 cfg_ref->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES / BYPC;
780 cfg_ref->port_b.width =
781 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].width;
782 cfg_ref->port_b.stride =
783 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline;
784 cfg_ref->width_a_over_b =
785 IPU3_UAPI_ISP_VEC_ELEMS / cfg_ref->port_b.elems;
786 cfg_ref->dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
787 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++) {
788 cfg_ref->ref_frame_addr_y[i] =
789 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr;
790 cfg_ref->ref_frame_addr_c[i] =
791 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr +
792 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline *
793 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
794 }
795 for (; i < IMGU_ABI_FRAMES_REF; i++) {
796 cfg_ref->ref_frame_addr_y[i] = 0;
797 cfg_ref->ref_frame_addr_c[i] = 0;
798 }
799
800 /* Configure DVS (digital video stabilization) */
801
802 cfg_dvs = imgu_css_fw_pipeline_params(css, pipe, cls: cfg, mem: m0,
803 par: &cofs->dmem.dvs, par_size: sizeof(*cfg_dvs),
804 binary_params: vaddr);
805 if (!cfg_dvs)
806 goto bad_firmware;
807
808 cfg_dvs->num_horizontal_blocks =
809 ALIGN(DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_GDC].width,
810 IMGU_DVS_BLOCK_W), 2);
811 cfg_dvs->num_vertical_blocks =
812 DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_GDC].height,
813 IMGU_DVS_BLOCK_H);
814
815 /* Configure TNR (temporal noise reduction) */
816
817 if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
818 cfg_tnr = imgu_css_fw_pipeline_params(css, pipe, cls: cfg, mem: m0,
819 par: &cofs->dmem.tnr3,
820 par_size: sizeof(*cfg_tnr),
821 binary_params: vaddr);
822 if (!cfg_tnr)
823 goto bad_firmware;
824
825 cfg_tnr->port_b.crop = 0;
826 cfg_tnr->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES;
827 cfg_tnr->port_b.width =
828 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
829 cfg_tnr->port_b.stride =
830 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline;
831 cfg_tnr->width_a_over_b =
832 IPU3_UAPI_ISP_VEC_ELEMS / cfg_tnr->port_b.elems;
833 cfg_tnr->frame_height =
834 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
835 cfg_tnr->delay_frame = IPU3_CSS_AUX_FRAMES - 1;
836 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
837 cfg_tnr->frame_addr[i] =
838 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR]
839 .mem[i].daddr;
840 for (; i < IMGU_ABI_FRAMES_TNR; i++)
841 cfg_tnr->frame_addr[i] = 0;
842 }
843
844 /* Configure ref dmem state parameters */
845
846 cfg = IMGU_ABI_PARAM_CLASS_STATE;
847 vaddr = css_pipe->binary_params_cs[cfg - 1][m0].vaddr;
848
849 cfg_ref_state = imgu_css_fw_pipeline_params(css, pipe, cls: cfg, mem: m0,
850 par: &sofs->dmem.ref,
851 par_size: sizeof(*cfg_ref_state),
852 binary_params: vaddr);
853 if (!cfg_ref_state)
854 goto bad_firmware;
855
856 cfg_ref_state->ref_in_buf_idx = 0;
857 cfg_ref_state->ref_out_buf_idx = 1;
858
859 /* Configure tnr dmem state parameters */
860 if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
861 cfg_tnr_state =
862 imgu_css_fw_pipeline_params(css, pipe, cls: cfg, mem: m0,
863 par: &sofs->dmem.tnr3,
864 par_size: sizeof(*cfg_tnr_state),
865 binary_params: vaddr);
866 if (!cfg_tnr_state)
867 goto bad_firmware;
868
869 cfg_tnr_state->in_bufidx = 0;
870 cfg_tnr_state->out_bufidx = 1;
871 cfg_tnr_state->bypass_filter = 0;
872 cfg_tnr_state->total_frame_counter = 0;
873 for (i = 0; i < IMGU_ABI_BUF_SETS_TNR; i++)
874 cfg_tnr_state->buffer_frame_counter[i] = 0;
875 }
876
877 /* Configure ISP stage */
878
879 isp_stage = css_pipe->xmem_isp_stage_ptrs[pipe][stage].vaddr;
880 memset(isp_stage, 0, sizeof(*isp_stage));
881 isp_stage->blob_info = bi->blob;
882 isp_stage->binary_info = bi->info.isp.sp;
883 strscpy(isp_stage->binary_name,
884 (char *)css->fwp + bi->blob.prog_name_offset,
885 sizeof(isp_stage->binary_name));
886 isp_stage->mem_initializers = bi->info.isp.sp.mem_initializers;
887 for (i = IMGU_ABI_PARAM_CLASS_CONFIG; i < IMGU_ABI_PARAM_CLASS_NUM; i++)
888 for (j = 0; j < IMGU_ABI_NUM_MEMORIES; j++)
889 isp_stage->mem_initializers.params[i][j].address =
890 css_pipe->binary_params_cs[i - 1][j].daddr;
891
892 /* Configure SP stage */
893
894 sp_stage = css_pipe->xmem_sp_stage_ptrs[pipe][stage].vaddr;
895 memset(sp_stage, 0, sizeof(*sp_stage));
896
897 frames_sp = &sp_stage->frames;
898 frames_sp->in.buf_attr = buffer_sp_init;
899 for (i = 0; i < IMGU_ABI_BINARY_MAX_OUTPUT_PORTS; i++)
900 frames_sp->out[i].buf_attr = buffer_sp_init;
901 frames_sp->out_vf.buf_attr = buffer_sp_init;
902 frames_sp->s3a_buf = buffer_sp_init;
903 frames_sp->dvs_buf = buffer_sp_init;
904
905 sp_stage->stage_type = IMGU_ABI_STAGE_TYPE_ISP;
906 sp_stage->num = stage;
907 sp_stage->isp_online = 0;
908 sp_stage->isp_copy_vf = 0;
909 sp_stage->isp_copy_output = 0;
910
911 sp_stage->enable.vf_output = css_pipe->vf_output_en;
912
913 frames_sp->effective_in_res.width =
914 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
915 frames_sp->effective_in_res.height =
916 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
917
918 frame_sp = &frames_sp->in;
919 frame_sp->info.res.width = css_queue_in->fmt.mpix.width;
920 frame_sp->info.res.height = css_queue_in->fmt.mpix.height;
921 frame_sp->info.padded_width = css_queue_in->width_pad;
922 frame_sp->info.format = css_queue_in->css_fmt->frame_format;
923 frame_sp->info.raw_bit_depth = css_queue_in->css_fmt->bit_depth;
924 frame_sp->info.raw_bayer_order = css_queue_in->css_fmt->bayer_order;
925 frame_sp->info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
926 frame_sp->buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_C_ID;
927 frame_sp->buf_attr.buf_type = IMGU_ABI_BUFFER_TYPE_INPUT_FRAME;
928
929 frame_sp = &frames_sp->out[0];
930 frame_sp->info.res.width = css_queue_out->fmt.mpix.width;
931 frame_sp->info.res.height = css_queue_out->fmt.mpix.height;
932 frame_sp->info.padded_width = css_queue_out->width_pad;
933 frame_sp->info.format = css_queue_out->css_fmt->frame_format;
934 frame_sp->info.raw_bit_depth = css_queue_out->css_fmt->bit_depth;
935 frame_sp->info.raw_bayer_order = css_queue_out->css_fmt->bayer_order;
936 frame_sp->info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
937 frame_sp->planes.nv.uv.offset = css_queue_out->width_pad *
938 css_queue_out->fmt.mpix.height;
939 frame_sp->buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_D_ID;
940 frame_sp->buf_attr.buf_type = IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME;
941
942 frame_sp = &frames_sp->out[1];
943 frame_sp->buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_EVENT_ID;
944
945 frame_sp_info = &frames_sp->internal_frame_info;
946 frame_sp_info->res.width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
947 frame_sp_info->res.height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
948 frame_sp_info->padded_width = bds_width_pad;
949 frame_sp_info->format = css_queue_out->css_fmt->frame_format;
950 frame_sp_info->raw_bit_depth = css_queue_out->css_fmt->bit_depth;
951 frame_sp_info->raw_bayer_order = css_queue_out->css_fmt->bayer_order;
952 frame_sp_info->raw_type = IMGU_ABI_RAW_TYPE_BAYER;
953
954 frame_sp = &frames_sp->out_vf;
955 frame_sp->info.res.width = css_queue_vf->fmt.mpix.width;
956 frame_sp->info.res.height = css_queue_vf->fmt.mpix.height;
957 frame_sp->info.padded_width = css_queue_vf->width_pad;
958 frame_sp->info.format = css_queue_vf->css_fmt->frame_format;
959 frame_sp->info.raw_bit_depth = css_queue_vf->css_fmt->bit_depth;
960 frame_sp->info.raw_bayer_order = css_queue_vf->css_fmt->bayer_order;
961 frame_sp->info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
962 frame_sp->planes.yuv.u.offset = css_queue_vf->width_pad *
963 css_queue_vf->fmt.mpix.height;
964 frame_sp->planes.yuv.v.offset = css_queue_vf->width_pad *
965 css_queue_vf->fmt.mpix.height * 5 / 4;
966 frame_sp->buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_E_ID;
967 frame_sp->buf_attr.buf_type = IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME;
968
969 frames_sp->s3a_buf.buf_src.queue_id = IMGU_ABI_QUEUE_F_ID;
970 frames_sp->s3a_buf.buf_type = IMGU_ABI_BUFFER_TYPE_3A_STATISTICS;
971
972 frames_sp->dvs_buf.buf_src.queue_id = IMGU_ABI_QUEUE_G_ID;
973 frames_sp->dvs_buf.buf_type = IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS;
974
975 sp_stage->dvs_envelope.width =
976 css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].width;
977 sp_stage->dvs_envelope.height =
978 css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].height;
979
980 sp_stage->isp_pipe_version =
981 bi->info.isp.sp.pipeline.isp_pipe_version;
982 sp_stage->isp_deci_log_factor =
983 clamp(max(fls(css_pipe->rect[IPU3_CSS_RECT_BDS].width /
984 IMGU_MAX_BQ_GRID_WIDTH),
985 fls(css_pipe->rect[IPU3_CSS_RECT_BDS].height /
986 IMGU_MAX_BQ_GRID_HEIGHT)) - 1, 3, 5);
987 sp_stage->isp_vf_downscale_bits = 0;
988 sp_stage->if_config_index = 255;
989 sp_stage->sp_enable_xnr = 0;
990 sp_stage->num_stripes = stripes;
991 sp_stage->enable.s3a = 1;
992 sp_stage->enable.dvs_stats = 0;
993
994 sp_stage->xmem_bin_addr = css->binary[css_pipe->bindex].daddr;
995 sp_stage->xmem_map_addr = css_pipe->sp_ddr_ptrs.daddr;
996 sp_stage->isp_stage_addr =
997 css_pipe->xmem_isp_stage_ptrs[pipe][stage].daddr;
998
999 /* Configure SP group */
1000
1001 sp_group = css->xmem_sp_group_ptrs.vaddr;
1002 memset(&sp_group->pipe[pipe], 0, sizeof(struct imgu_abi_sp_pipeline));
1003
1004 sp_group->pipe[pipe].num_stages = 1;
1005 sp_group->pipe[pipe].pipe_id = css_pipe->pipe_id;
1006 sp_group->pipe[pipe].thread_id = pipe;
1007 sp_group->pipe[pipe].pipe_num = pipe;
1008 sp_group->pipe[pipe].num_execs = -1;
1009 sp_group->pipe[pipe].pipe_qos_config = -1;
1010 sp_group->pipe[pipe].required_bds_factor = 0;
1011 sp_group->pipe[pipe].dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
1012 sp_group->pipe[pipe].inout_port_config =
1013 IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
1014 IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;
1015 sp_group->pipe[pipe].scaler_pp_lut = 0;
1016 sp_group->pipe[pipe].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
1017 sp_group->pipe[pipe].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
1018 sp_group->pipe[pipe].sp_stage_addr[stage] =
1019 css_pipe->xmem_sp_stage_ptrs[pipe][stage].daddr;
1020 sp_group->pipe[pipe].pipe_config =
1021 bi->info.isp.sp.enable.params ? (1 << pipe) : 0;
1022 sp_group->pipe[pipe].pipe_config |= IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP;
1023
1024 /* Initialize parameter pools */
1025
1026 if (imgu_css_pool_init(imgu, pool: &css_pipe->pool.parameter_set_info,
1027 size: sizeof(struct imgu_abi_parameter_set_info)) ||
1028 imgu_css_pool_init(imgu, pool: &css_pipe->pool.acc,
1029 size: sizeof(struct imgu_abi_acc_param)) ||
1030 imgu_css_pool_init(imgu, pool: &css_pipe->pool.gdc,
1031 size: sizeof(struct imgu_abi_gdc_warp_param) *
1032 3 * cfg_dvs->num_horizontal_blocks / 2 *
1033 cfg_dvs->num_vertical_blocks) ||
1034 imgu_css_pool_init(imgu, pool: &css_pipe->pool.obgrid,
1035 size: imgu_css_fw_obgrid_size(
1036 bi: &css->fwp->binary_header[css_pipe->bindex])))
1037 goto out_of_memory;
1038
1039 for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
1040 if (imgu_css_pool_init(imgu,
1041 pool: &css_pipe->pool.binary_params_p[i],
1042 size: bi->info.isp.sp.mem_initializers.params
1043 [IMGU_ABI_PARAM_CLASS_PARAM][i].size))
1044 goto out_of_memory;
1045
1046 return 0;
1047
1048bad_firmware:
1049 imgu_css_pipeline_cleanup(css, pipe);
1050 return -EPROTO;
1051
1052out_of_memory:
1053 imgu_css_pipeline_cleanup(css, pipe);
1054 return -ENOMEM;
1055}
1056
1057static u8 imgu_css_queue_pos(struct imgu_css *css, int queue, int thread)
1058{
1059 static const unsigned int sp;
1060 void __iomem *const base = css->base;
1061 struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
1062 struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
1063 bi->info.sp.host_sp_queue;
1064
1065 return queue >= 0 ? readb(addr: &q->host2sp_bufq_info[thread][queue].end) :
1066 readb(addr: &q->host2sp_evtq_info.end);
1067}
1068
1069/* Sent data to sp using given buffer queue, or if queue < 0, event queue. */
1070static int imgu_css_queue_data(struct imgu_css *css,
1071 int queue, int thread, u32 data)
1072{
1073 static const unsigned int sp;
1074 void __iomem *const base = css->base;
1075 struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
1076 struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
1077 bi->info.sp.host_sp_queue;
1078 u8 size, start, end, end2;
1079
1080 if (queue >= 0) {
1081 size = readb(addr: &q->host2sp_bufq_info[thread][queue].size);
1082 start = readb(addr: &q->host2sp_bufq_info[thread][queue].start);
1083 end = readb(addr: &q->host2sp_bufq_info[thread][queue].end);
1084 } else {
1085 size = readb(addr: &q->host2sp_evtq_info.size);
1086 start = readb(addr: &q->host2sp_evtq_info.start);
1087 end = readb(addr: &q->host2sp_evtq_info.end);
1088 }
1089
1090 if (size == 0)
1091 return -EIO;
1092
1093 end2 = (end + 1) % size;
1094 if (end2 == start)
1095 return -EBUSY; /* Queue full */
1096
1097 if (queue >= 0) {
1098 writel(val: data, addr: &q->host2sp_bufq[thread][queue][end]);
1099 writeb(val: end2, addr: &q->host2sp_bufq_info[thread][queue].end);
1100 } else {
1101 writel(val: data, addr: &q->host2sp_evtq[end]);
1102 writeb(val: end2, addr: &q->host2sp_evtq_info.end);
1103 }
1104
1105 return 0;
1106}
1107
1108/* Receive data using given buffer queue, or if queue < 0, event queue. */
1109static int imgu_css_dequeue_data(struct imgu_css *css, int queue, u32 *data)
1110{
1111 static const unsigned int sp;
1112 void __iomem *const base = css->base;
1113 struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
1114 struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
1115 bi->info.sp.host_sp_queue;
1116 u8 size, start, end, start2;
1117
1118 if (queue >= 0) {
1119 size = readb(addr: &q->sp2host_bufq_info[queue].size);
1120 start = readb(addr: &q->sp2host_bufq_info[queue].start);
1121 end = readb(addr: &q->sp2host_bufq_info[queue].end);
1122 } else {
1123 size = readb(addr: &q->sp2host_evtq_info.size);
1124 start = readb(addr: &q->sp2host_evtq_info.start);
1125 end = readb(addr: &q->sp2host_evtq_info.end);
1126 }
1127
1128 if (size == 0)
1129 return -EIO;
1130
1131 if (end == start)
1132 return -EBUSY; /* Queue empty */
1133
1134 start2 = (start + 1) % size;
1135
1136 if (queue >= 0) {
1137 *data = readl(addr: &q->sp2host_bufq[queue][start]);
1138 writeb(val: start2, addr: &q->sp2host_bufq_info[queue].start);
1139 } else {
1140 int r;
1141
1142 *data = readl(addr: &q->sp2host_evtq[start]);
1143 writeb(val: start2, addr: &q->sp2host_evtq_info.start);
1144
1145 /* Acknowledge events dequeued from event queue */
1146 r = imgu_css_queue_data(css, queue, thread: 0,
1147 IMGU_ABI_EVENT_EVENT_DEQUEUED);
1148 if (r < 0)
1149 return r;
1150 }
1151
1152 return 0;
1153}
1154
1155/* Free binary-specific resources */
1156static void imgu_css_binary_cleanup(struct imgu_css *css, unsigned int pipe)
1157{
1158 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
1159 unsigned int i, j;
1160
1161 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1162
1163 for (j = 0; j < IMGU_ABI_PARAM_CLASS_NUM - 1; j++)
1164 for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
1165 imgu_dmamap_free(imgu,
1166 map: &css_pipe->binary_params_cs[j][i]);
1167
1168 j = IPU3_CSS_AUX_FRAME_REF;
1169 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
1170 imgu_dmamap_free(imgu,
1171 map: &css_pipe->aux_frames[j].mem[i]);
1172
1173 j = IPU3_CSS_AUX_FRAME_TNR;
1174 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
1175 imgu_dmamap_free(imgu,
1176 map: &css_pipe->aux_frames[j].mem[i]);
1177}
1178
1179static int imgu_css_binary_preallocate(struct imgu_css *css, unsigned int pipe)
1180{
1181 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
1182 unsigned int i, j;
1183
1184 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1185
1186 for (j = IMGU_ABI_PARAM_CLASS_CONFIG;
1187 j < IMGU_ABI_PARAM_CLASS_NUM; j++)
1188 for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
1189 if (!imgu_dmamap_alloc(imgu,
1190 map: &css_pipe->binary_params_cs[j - 1][i],
1191 CSS_ABI_SIZE))
1192 goto out_of_memory;
1193
1194 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
1195 if (!imgu_dmamap_alloc(imgu,
1196 map: &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i],
1197 CSS_BDS_SIZE))
1198 goto out_of_memory;
1199
1200 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
1201 if (!imgu_dmamap_alloc(imgu,
1202 map: &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].mem[i],
1203 CSS_GDC_SIZE))
1204 goto out_of_memory;
1205
1206 return 0;
1207
1208out_of_memory:
1209 imgu_css_binary_cleanup(css, pipe);
1210 return -ENOMEM;
1211}
1212
1213/* allocate binary-specific resources */
1214static int imgu_css_binary_setup(struct imgu_css *css, unsigned int pipe)
1215{
1216 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1217 struct imgu_fw_info *bi = &css->fwp->binary_header[css_pipe->bindex];
1218 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
1219 int i, j, size;
1220 static const int BYPC = 2; /* Bytes per component */
1221 unsigned int w, h;
1222
1223 /* Allocate parameter memory blocks for this binary */
1224
1225 for (j = IMGU_ABI_PARAM_CLASS_CONFIG; j < IMGU_ABI_PARAM_CLASS_NUM; j++)
1226 for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++) {
1227 if (imgu_css_dma_buffer_resize(
1228 imgu,
1229 map: &css_pipe->binary_params_cs[j - 1][i],
1230 size: bi->info.isp.sp.mem_initializers.params[j][i].size))
1231 goto out_of_memory;
1232 }
1233
1234 /* Allocate internal frame buffers */
1235
1236 /* Reference frames for DVS, FRAME_FORMAT_YUV420_16 */
1237 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel = BYPC;
1238 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].width =
1239 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1240 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height =
1241 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1242 IMGU_DVS_BLOCK_H) + 2 * IMGU_GDC_BUF_Y;
1243 h = css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
1244 w = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
1245 2 * IPU3_UAPI_ISP_VEC_ELEMS) + 2 * IMGU_GDC_BUF_X;
1246 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline =
1247 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel * w;
1248 size = w * h * BYPC + (w / 2) * (h / 2) * BYPC * 2;
1249 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
1250 if (imgu_css_dma_buffer_resize(
1251 imgu,
1252 map: &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i],
1253 size))
1254 goto out_of_memory;
1255
1256 /* TNR frames for temporal noise reduction, FRAME_FORMAT_YUV_LINE */
1257 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperpixel = 1;
1258 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width =
1259 roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width,
1260 bi->info.isp.sp.block.block_width *
1261 IPU3_UAPI_ISP_VEC_ELEMS);
1262 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height =
1263 roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].height,
1264 bi->info.isp.sp.block.output_block_height);
1265
1266 w = css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
1267 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline = w;
1268 h = css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
1269 size = w * ALIGN(h * 3 / 2 + 3, 2); /* +3 for vf_pp prefetch */
1270 for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
1271 if (imgu_css_dma_buffer_resize(
1272 imgu,
1273 map: &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].mem[i],
1274 size))
1275 goto out_of_memory;
1276
1277 return 0;
1278
1279out_of_memory:
1280 imgu_css_binary_cleanup(css, pipe);
1281 return -ENOMEM;
1282}
1283
1284int imgu_css_start_streaming(struct imgu_css *css)
1285{
1286 u32 data;
1287 int r, pipe;
1288
1289 if (css->streaming)
1290 return -EPROTO;
1291
1292 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1293 r = imgu_css_binary_setup(css, pipe);
1294 if (r < 0)
1295 return r;
1296 }
1297
1298 r = imgu_css_hw_init(css);
1299 if (r < 0)
1300 return r;
1301
1302 r = imgu_css_hw_start(css);
1303 if (r < 0)
1304 goto fail;
1305
1306 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1307 r = imgu_css_pipeline_init(css, pipe);
1308 if (r < 0)
1309 goto fail;
1310 }
1311
1312 css->streaming = true;
1313
1314 imgu_css_hw_enable_irq(css);
1315
1316 /* Initialize parameters to default */
1317 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1318 r = imgu_css_set_parameters(css, pipe, NULL);
1319 if (r < 0)
1320 goto fail;
1321 }
1322
1323 while (!(r = imgu_css_dequeue_data(css, queue: IMGU_ABI_QUEUE_A_ID, data: &data)))
1324 ;
1325 if (r != -EBUSY)
1326 goto fail;
1327
1328 while (!(r = imgu_css_dequeue_data(css, queue: IMGU_ABI_QUEUE_B_ID, data: &data)))
1329 ;
1330 if (r != -EBUSY)
1331 goto fail;
1332
1333 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1334 r = imgu_css_queue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, thread: pipe,
1335 IMGU_ABI_EVENT_START_STREAM |
1336 pipe << 16);
1337 if (r < 0)
1338 goto fail;
1339 }
1340
1341 return 0;
1342
1343fail:
1344 css->streaming = false;
1345 imgu_css_hw_cleanup(css);
1346 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1347 imgu_css_pipeline_cleanup(css, pipe);
1348 imgu_css_binary_cleanup(css, pipe);
1349 }
1350
1351 return r;
1352}
1353
1354void imgu_css_stop_streaming(struct imgu_css *css)
1355{
1356 struct imgu_css_buffer *b, *b0;
1357 int q, r, pipe;
1358
1359 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1360 r = imgu_css_queue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, thread: pipe,
1361 IMGU_ABI_EVENT_STOP_STREAM);
1362 if (r < 0)
1363 dev_warn(css->dev, "failed on stop stream event\n");
1364 }
1365
1366 if (!css->streaming)
1367 return;
1368
1369 imgu_css_hw_stop(css);
1370
1371 imgu_css_hw_cleanup(css);
1372
1373 for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
1374 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1375
1376 imgu_css_pipeline_cleanup(css, pipe);
1377
1378 spin_lock(lock: &css_pipe->qlock);
1379 for (q = 0; q < IPU3_CSS_QUEUES; q++)
1380 list_for_each_entry_safe(b, b0,
1381 &css_pipe->queue[q].bufs,
1382 list) {
1383 b->state = IPU3_CSS_BUFFER_FAILED;
1384 list_del(entry: &b->list);
1385 }
1386 spin_unlock(lock: &css_pipe->qlock);
1387 }
1388
1389 css->streaming = false;
1390}
1391
1392bool imgu_css_pipe_queue_empty(struct imgu_css *css, unsigned int pipe)
1393{
1394 int q;
1395 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1396
1397 spin_lock(lock: &css_pipe->qlock);
1398 for (q = 0; q < IPU3_CSS_QUEUES; q++)
1399 if (!list_empty(head: &css_pipe->queue[q].bufs))
1400 break;
1401 spin_unlock(lock: &css_pipe->qlock);
1402 return (q == IPU3_CSS_QUEUES);
1403}
1404
1405bool imgu_css_queue_empty(struct imgu_css *css)
1406{
1407 unsigned int pipe;
1408 bool ret = false;
1409
1410 for (pipe = 0; pipe < IMGU_MAX_PIPE_NUM; pipe++)
1411 ret &= imgu_css_pipe_queue_empty(css, pipe);
1412
1413 return ret;
1414}
1415
1416bool imgu_css_is_streaming(struct imgu_css *css)
1417{
1418 return css->streaming;
1419}
1420
1421static int imgu_css_map_init(struct imgu_css *css, unsigned int pipe)
1422{
1423 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
1424 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1425 unsigned int p, q, i;
1426
1427 /* Allocate and map common structures with imgu hardware */
1428 for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
1429 for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
1430 if (!imgu_dmamap_alloc(imgu,
1431 map: &css_pipe->xmem_sp_stage_ptrs[p][i],
1432 len: sizeof(struct imgu_abi_sp_stage)))
1433 return -ENOMEM;
1434 if (!imgu_dmamap_alloc(imgu,
1435 map: &css_pipe->xmem_isp_stage_ptrs[p][i],
1436 len: sizeof(struct imgu_abi_isp_stage)))
1437 return -ENOMEM;
1438 }
1439
1440 if (!imgu_dmamap_alloc(imgu, map: &css_pipe->sp_ddr_ptrs,
1441 ALIGN(sizeof(struct imgu_abi_ddr_address_map),
1442 IMGU_ABI_ISP_DDR_WORD_BYTES)))
1443 return -ENOMEM;
1444
1445 for (q = 0; q < IPU3_CSS_QUEUES; q++) {
1446 unsigned int abi_buf_num = ARRAY_SIZE(css_pipe->abi_buffers[q]);
1447
1448 for (i = 0; i < abi_buf_num; i++)
1449 if (!imgu_dmamap_alloc(imgu,
1450 map: &css_pipe->abi_buffers[q][i],
1451 len: sizeof(struct imgu_abi_buffer)))
1452 return -ENOMEM;
1453 }
1454
1455 if (imgu_css_binary_preallocate(css, pipe)) {
1456 imgu_css_binary_cleanup(css, pipe);
1457 return -ENOMEM;
1458 }
1459
1460 return 0;
1461}
1462
1463static void imgu_css_pipe_cleanup(struct imgu_css *css, unsigned int pipe)
1464{
1465 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
1466 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1467 unsigned int p, q, i, abi_buf_num;
1468
1469 imgu_css_binary_cleanup(css, pipe);
1470
1471 for (q = 0; q < IPU3_CSS_QUEUES; q++) {
1472 abi_buf_num = ARRAY_SIZE(css_pipe->abi_buffers[q]);
1473 for (i = 0; i < abi_buf_num; i++)
1474 imgu_dmamap_free(imgu, map: &css_pipe->abi_buffers[q][i]);
1475 }
1476
1477 for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
1478 for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
1479 imgu_dmamap_free(imgu,
1480 map: &css_pipe->xmem_sp_stage_ptrs[p][i]);
1481 imgu_dmamap_free(imgu,
1482 map: &css_pipe->xmem_isp_stage_ptrs[p][i]);
1483 }
1484
1485 imgu_dmamap_free(imgu, map: &css_pipe->sp_ddr_ptrs);
1486}
1487
1488void imgu_css_cleanup(struct imgu_css *css)
1489{
1490 struct imgu_device *imgu = dev_get_drvdata(dev: css->dev);
1491 unsigned int pipe;
1492
1493 imgu_css_stop_streaming(css);
1494 for (pipe = 0; pipe < IMGU_MAX_PIPE_NUM; pipe++)
1495 imgu_css_pipe_cleanup(css, pipe);
1496 imgu_dmamap_free(imgu, map: &css->xmem_sp_group_ptrs);
1497 imgu_css_fw_cleanup(css);
1498}
1499
1500int imgu_css_init(struct device *dev, struct imgu_css *css,
1501 void __iomem *base, int length)
1502{
1503 struct imgu_device *imgu = dev_get_drvdata(dev);
1504 int r, q, pipe;
1505
1506 /* Initialize main data structure */
1507 css->dev = dev;
1508 css->base = base;
1509 css->iomem_length = length;
1510
1511 for (pipe = 0; pipe < IMGU_MAX_PIPE_NUM; pipe++) {
1512 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1513
1514 css_pipe->vf_output_en = false;
1515 spin_lock_init(&css_pipe->qlock);
1516 css_pipe->bindex = IPU3_CSS_DEFAULT_BINARY;
1517 css_pipe->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
1518 for (q = 0; q < IPU3_CSS_QUEUES; q++) {
1519 r = imgu_css_queue_init(queue: &css_pipe->queue[q], NULL, flags: 0);
1520 if (r)
1521 return r;
1522 }
1523 r = imgu_css_map_init(css, pipe);
1524 if (r) {
1525 imgu_css_cleanup(css);
1526 return r;
1527 }
1528 }
1529 if (!imgu_dmamap_alloc(imgu, map: &css->xmem_sp_group_ptrs,
1530 len: sizeof(struct imgu_abi_sp_group)))
1531 return -ENOMEM;
1532
1533 r = imgu_css_fw_init(css);
1534 if (r)
1535 return r;
1536
1537 return 0;
1538}
1539
1540static u32 imgu_css_adjust(u32 res, u32 align)
1541{
1542 u32 val = max_t(u32, IPU3_CSS_MIN_RES, res);
1543
1544 return DIV_ROUND_CLOSEST(val, align) * align;
1545}
1546
1547/* Select a binary matching the required resolutions and formats */
1548static int imgu_css_find_binary(struct imgu_css *css,
1549 unsigned int pipe,
1550 struct imgu_css_queue queue[IPU3_CSS_QUEUES],
1551 struct v4l2_rect rects[IPU3_CSS_RECTS])
1552{
1553 const int binary_nr = css->fwp->file_header.binary_nr;
1554 unsigned int binary_mode =
1555 (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_CAPTURE) ?
1556 IA_CSS_BINARY_MODE_PRIMARY : IA_CSS_BINARY_MODE_VIDEO;
1557 const struct v4l2_pix_format_mplane *in =
1558 &queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
1559 const struct v4l2_pix_format_mplane *out =
1560 &queue[IPU3_CSS_QUEUE_OUT].fmt.mpix;
1561 const struct v4l2_pix_format_mplane *vf =
1562 &queue[IPU3_CSS_QUEUE_VF].fmt.mpix;
1563 u32 stripe_w = 0, stripe_h = 0;
1564 const char *name;
1565 int i, j;
1566
1567 if (!imgu_css_queue_enabled(q: &queue[IPU3_CSS_QUEUE_IN]))
1568 return -EINVAL;
1569
1570 /* Find out the strip size boundary */
1571 for (i = 0; i < binary_nr; i++) {
1572 struct imgu_fw_info *bi = &css->fwp->binary_header[i];
1573
1574 u32 max_width = bi->info.isp.sp.output.max_width;
1575 u32 max_height = bi->info.isp.sp.output.max_height;
1576
1577 if (bi->info.isp.sp.iterator.num_stripes <= 1) {
1578 stripe_w = stripe_w ?
1579 min(stripe_w, max_width) : max_width;
1580 stripe_h = stripe_h ?
1581 min(stripe_h, max_height) : max_height;
1582 }
1583 }
1584
1585 for (i = 0; i < binary_nr; i++) {
1586 struct imgu_fw_info *bi = &css->fwp->binary_header[i];
1587 enum imgu_abi_frame_format q_fmt;
1588
1589 name = (void *)css->fwp + bi->blob.prog_name_offset;
1590
1591 /* Check that binary supports memory-to-memory processing */
1592 if (bi->info.isp.sp.input.source !=
1593 IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY)
1594 continue;
1595
1596 /* Check that binary supports raw10 input */
1597 if (!bi->info.isp.sp.enable.input_feeder &&
1598 !bi->info.isp.sp.enable.input_raw)
1599 continue;
1600
1601 /* Check binary mode */
1602 if (bi->info.isp.sp.pipeline.mode != binary_mode)
1603 continue;
1604
1605 /* Since input is RGGB bayer, need to process colors */
1606 if (bi->info.isp.sp.enable.luma_only)
1607 continue;
1608
1609 if (in->width < bi->info.isp.sp.input.min_width ||
1610 in->width > bi->info.isp.sp.input.max_width ||
1611 in->height < bi->info.isp.sp.input.min_height ||
1612 in->height > bi->info.isp.sp.input.max_height)
1613 continue;
1614
1615 if (imgu_css_queue_enabled(q: &queue[IPU3_CSS_QUEUE_OUT])) {
1616 if (bi->info.isp.num_output_pins <= 0)
1617 continue;
1618
1619 q_fmt = queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
1620 for (j = 0; j < bi->info.isp.num_output_formats; j++)
1621 if (bi->info.isp.output_formats[j] == q_fmt)
1622 break;
1623 if (j >= bi->info.isp.num_output_formats)
1624 continue;
1625
1626 if (out->width < bi->info.isp.sp.output.min_width ||
1627 out->width > bi->info.isp.sp.output.max_width ||
1628 out->height < bi->info.isp.sp.output.min_height ||
1629 out->height > bi->info.isp.sp.output.max_height)
1630 continue;
1631
1632 if (out->width > bi->info.isp.sp.internal.max_width ||
1633 out->height > bi->info.isp.sp.internal.max_height)
1634 continue;
1635 }
1636
1637 if (imgu_css_queue_enabled(q: &queue[IPU3_CSS_QUEUE_VF])) {
1638 if (bi->info.isp.num_output_pins <= 1)
1639 continue;
1640
1641 q_fmt = queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
1642 for (j = 0; j < bi->info.isp.num_output_formats; j++)
1643 if (bi->info.isp.output_formats[j] == q_fmt)
1644 break;
1645 if (j >= bi->info.isp.num_output_formats)
1646 continue;
1647
1648 if (vf->width < bi->info.isp.sp.output.min_width ||
1649 vf->width > bi->info.isp.sp.output.max_width ||
1650 vf->height < bi->info.isp.sp.output.min_height ||
1651 vf->height > bi->info.isp.sp.output.max_height)
1652 continue;
1653 }
1654
1655 /* All checks passed, select the binary */
1656 dev_dbg(css->dev, "using binary %s id = %u\n", name,
1657 bi->info.isp.sp.id);
1658 return i;
1659 }
1660
1661 /* Can not find suitable binary for these parameters */
1662 return -EINVAL;
1663}
1664
1665/*
1666 * Check that there is a binary matching requirements. Parameters may be
1667 * NULL indicating disabled input/output. Return negative if given
1668 * parameters can not be supported or on error, zero or positive indicating
1669 * found binary number. May modify the given parameters if not exact match
1670 * is found.
1671 */
1672int imgu_css_fmt_try(struct imgu_css *css,
1673 struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
1674 struct v4l2_rect *rects[IPU3_CSS_RECTS],
1675 unsigned int pipe)
1676{
1677 static const u32 EFF_ALIGN_W = 2;
1678 static const u32 BDS_ALIGN_W = 4;
1679 static const u32 OUT_ALIGN_W = 8;
1680 static const u32 OUT_ALIGN_H = 4;
1681 static const u32 VF_ALIGN_W = 2;
1682 static const char *qnames[IPU3_CSS_QUEUES] = {
1683 [IPU3_CSS_QUEUE_IN] = "in",
1684 [IPU3_CSS_QUEUE_PARAMS] = "params",
1685 [IPU3_CSS_QUEUE_OUT] = "out",
1686 [IPU3_CSS_QUEUE_VF] = "vf",
1687 [IPU3_CSS_QUEUE_STAT_3A] = "3a",
1688 };
1689 static const char *rnames[IPU3_CSS_RECTS] = {
1690 [IPU3_CSS_RECT_EFFECTIVE] = "effective resolution",
1691 [IPU3_CSS_RECT_BDS] = "bayer-domain scaled resolution",
1692 [IPU3_CSS_RECT_ENVELOPE] = "DVS envelope size",
1693 [IPU3_CSS_RECT_GDC] = "GDC output res",
1694 };
1695 struct v4l2_rect r[IPU3_CSS_RECTS] = { };
1696 struct v4l2_rect *const eff = &r[IPU3_CSS_RECT_EFFECTIVE];
1697 struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS];
1698 struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE];
1699 struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC];
1700 struct imgu_css_queue *q;
1701 struct v4l2_pix_format_mplane *in, *out, *vf;
1702 int i, s, ret;
1703
1704 q = kcalloc(IPU3_CSS_QUEUES, size: sizeof(struct imgu_css_queue), GFP_KERNEL);
1705 if (!q)
1706 return -ENOMEM;
1707
1708 in = &q[IPU3_CSS_QUEUE_IN].fmt.mpix;
1709 out = &q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
1710 vf = &q[IPU3_CSS_QUEUE_VF].fmt.mpix;
1711
1712 /* Adjust all formats, get statistics buffer sizes and formats */
1713 for (i = 0; i < IPU3_CSS_QUEUES; i++) {
1714 if (fmts[i])
1715 dev_dbg(css->dev, "%s %s: (%i,%i) fmt 0x%x\n", __func__,
1716 qnames[i], fmts[i]->width, fmts[i]->height,
1717 fmts[i]->pixelformat);
1718 else
1719 dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
1720 qnames[i]);
1721 if (imgu_css_queue_init(queue: &q[i], fmt: fmts[i],
1722 IPU3_CSS_QUEUE_TO_FLAGS(i))) {
1723 dev_notice(css->dev, "can not initialize queue %s\n",
1724 qnames[i]);
1725 ret = -EINVAL;
1726 goto out;
1727 }
1728 }
1729 for (i = 0; i < IPU3_CSS_RECTS; i++) {
1730 if (rects[i]) {
1731 dev_dbg(css->dev, "%s %s: (%i,%i)\n", __func__,
1732 rnames[i], rects[i]->width, rects[i]->height);
1733 r[i].width = rects[i]->width;
1734 r[i].height = rects[i]->height;
1735 } else {
1736 dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
1737 rnames[i]);
1738 }
1739 /* For now, force known good resolutions */
1740 r[i].left = 0;
1741 r[i].top = 0;
1742 }
1743
1744 /* Always require one input and vf only if out is also enabled */
1745 if (!imgu_css_queue_enabled(q: &q[IPU3_CSS_QUEUE_IN]) ||
1746 !imgu_css_queue_enabled(q: &q[IPU3_CSS_QUEUE_OUT])) {
1747 dev_warn(css->dev, "required queues are disabled\n");
1748 ret = -EINVAL;
1749 goto out;
1750 }
1751
1752 if (!imgu_css_queue_enabled(q: &q[IPU3_CSS_QUEUE_OUT])) {
1753 out->width = in->width;
1754 out->height = in->height;
1755 }
1756 if (eff->width <= 0 || eff->height <= 0) {
1757 eff->width = in->width;
1758 eff->height = in->height;
1759 }
1760 if (bds->width <= 0 || bds->height <= 0) {
1761 bds->width = out->width;
1762 bds->height = out->height;
1763 }
1764 if (gdc->width <= 0 || gdc->height <= 0) {
1765 gdc->width = out->width;
1766 gdc->height = out->height;
1767 }
1768
1769 in->width = imgu_css_adjust(res: in->width, align: 1);
1770 in->height = imgu_css_adjust(res: in->height, align: 1);
1771 eff->width = imgu_css_adjust(res: eff->width, align: EFF_ALIGN_W);
1772 eff->height = imgu_css_adjust(res: eff->height, align: 1);
1773 bds->width = imgu_css_adjust(res: bds->width, align: BDS_ALIGN_W);
1774 bds->height = imgu_css_adjust(res: bds->height, align: 1);
1775 gdc->width = imgu_css_adjust(res: gdc->width, align: OUT_ALIGN_W);
1776 gdc->height = imgu_css_adjust(res: gdc->height, align: OUT_ALIGN_H);
1777 out->width = imgu_css_adjust(res: out->width, align: OUT_ALIGN_W);
1778 out->height = imgu_css_adjust(res: out->height, align: OUT_ALIGN_H);
1779 vf->width = imgu_css_adjust(res: vf->width, align: VF_ALIGN_W);
1780 vf->height = imgu_css_adjust(res: vf->height, align: 1);
1781
1782 s = (bds->width - gdc->width) / 2;
1783 env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
1784 s = (bds->height - gdc->height) / 2;
1785 env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
1786
1787 ret = imgu_css_find_binary(css, pipe, queue: q, rects: r);
1788 if (ret < 0) {
1789 dev_err(css->dev, "failed to find suitable binary\n");
1790 ret = -EINVAL;
1791 goto out;
1792 }
1793 css->pipes[pipe].bindex = ret;
1794
1795 dev_dbg(css->dev, "Binary index %d for pipe %d found.",
1796 css->pipes[pipe].bindex, pipe);
1797
1798 /* Final adjustment and set back the queried formats */
1799 for (i = 0; i < IPU3_CSS_QUEUES; i++) {
1800 if (fmts[i]) {
1801 if (imgu_css_queue_init(queue: &q[i], fmt: &q[i].fmt.mpix,
1802 IPU3_CSS_QUEUE_TO_FLAGS(i))) {
1803 dev_err(css->dev,
1804 "final resolution adjustment failed\n");
1805 ret = -EINVAL;
1806 goto out;
1807 }
1808 *fmts[i] = q[i].fmt.mpix;
1809 }
1810 }
1811
1812 for (i = 0; i < IPU3_CSS_RECTS; i++)
1813 if (rects[i])
1814 *rects[i] = r[i];
1815
1816 dev_dbg(css->dev,
1817 "in(%u,%u) if(%u,%u) ds(%u,%u) gdc(%u,%u) out(%u,%u) vf(%u,%u)",
1818 in->width, in->height, eff->width, eff->height,
1819 bds->width, bds->height, gdc->width, gdc->height,
1820 out->width, out->height, vf->width, vf->height);
1821
1822 ret = 0;
1823out:
1824 kfree(objp: q);
1825 return ret;
1826}
1827
1828int imgu_css_fmt_set(struct imgu_css *css,
1829 struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
1830 struct v4l2_rect *rects[IPU3_CSS_RECTS],
1831 unsigned int pipe)
1832{
1833 struct v4l2_rect rect_data[IPU3_CSS_RECTS];
1834 struct v4l2_rect *all_rects[IPU3_CSS_RECTS];
1835 int i, r;
1836 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1837
1838 for (i = 0; i < IPU3_CSS_RECTS; i++) {
1839 if (rects[i])
1840 rect_data[i] = *rects[i];
1841 else
1842 memset(&rect_data[i], 0, sizeof(rect_data[i]));
1843 all_rects[i] = &rect_data[i];
1844 }
1845 r = imgu_css_fmt_try(css, fmts, rects: all_rects, pipe);
1846 if (r < 0)
1847 return r;
1848
1849 for (i = 0; i < IPU3_CSS_QUEUES; i++)
1850 if (imgu_css_queue_init(queue: &css_pipe->queue[i], fmt: fmts[i],
1851 IPU3_CSS_QUEUE_TO_FLAGS(i)))
1852 return -EINVAL;
1853 for (i = 0; i < IPU3_CSS_RECTS; i++) {
1854 css_pipe->rect[i] = rect_data[i];
1855 if (rects[i])
1856 *rects[i] = rect_data[i];
1857 }
1858
1859 return 0;
1860}
1861
1862int imgu_css_meta_fmt_set(struct v4l2_meta_format *fmt)
1863{
1864 switch (fmt->dataformat) {
1865 case V4L2_META_FMT_IPU3_PARAMS:
1866 fmt->buffersize = sizeof(struct ipu3_uapi_params);
1867
1868 /*
1869 * Sanity check for the parameter struct size. This must
1870 * not change!
1871 */
1872 BUILD_BUG_ON(sizeof(struct ipu3_uapi_params) != 39328);
1873
1874 break;
1875 case V4L2_META_FMT_IPU3_STAT_3A:
1876 fmt->buffersize = sizeof(struct ipu3_uapi_stats_3a);
1877 break;
1878 default:
1879 return -EINVAL;
1880 }
1881
1882 return 0;
1883}
1884
1885/*
1886 * Queue given buffer to CSS. imgu_css_buf_prepare() must have been first
1887 * called for the buffer. May be called from interrupt context.
1888 * Returns 0 on success, -EBUSY if the buffer queue is full, or some other
1889 * code on error conditions.
1890 */
1891int imgu_css_buf_queue(struct imgu_css *css, unsigned int pipe,
1892 struct imgu_css_buffer *b)
1893{
1894 struct imgu_abi_buffer *abi_buf;
1895 struct imgu_addr_t *buf_addr;
1896 u32 data;
1897 int r;
1898 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1899
1900 if (!css->streaming)
1901 return -EPROTO; /* CSS or buffer in wrong state */
1902
1903 if (b->queue >= IPU3_CSS_QUEUES || !imgu_css_queues[b->queue].qid)
1904 return -EINVAL;
1905
1906 b->queue_pos = imgu_css_queue_pos(css, queue: imgu_css_queues[b->queue].qid,
1907 thread: pipe);
1908
1909 if (b->queue_pos >= ARRAY_SIZE(css->pipes[pipe].abi_buffers[b->queue]))
1910 return -EIO;
1911 abi_buf = css->pipes[pipe].abi_buffers[b->queue][b->queue_pos].vaddr;
1912
1913 /* Fill struct abi_buffer for firmware */
1914 memset(abi_buf, 0, sizeof(*abi_buf));
1915
1916 buf_addr = (void *)abi_buf + imgu_css_queues[b->queue].ptr_ofs;
1917 *(imgu_addr_t *)buf_addr = b->daddr;
1918
1919 if (b->queue == IPU3_CSS_QUEUE_STAT_3A)
1920 abi_buf->payload.s3a.data.dmem.s3a_tbl = b->daddr;
1921
1922 if (b->queue == IPU3_CSS_QUEUE_OUT)
1923 abi_buf->payload.frame.padded_width =
1924 css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
1925
1926 if (b->queue == IPU3_CSS_QUEUE_VF)
1927 abi_buf->payload.frame.padded_width =
1928 css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
1929
1930 spin_lock(lock: &css_pipe->qlock);
1931 list_add_tail(new: &b->list, head: &css_pipe->queue[b->queue].bufs);
1932 spin_unlock(lock: &css_pipe->qlock);
1933 b->state = IPU3_CSS_BUFFER_QUEUED;
1934
1935 data = css->pipes[pipe].abi_buffers[b->queue][b->queue_pos].daddr;
1936 r = imgu_css_queue_data(css, queue: imgu_css_queues[b->queue].qid,
1937 thread: pipe, data);
1938 if (r < 0)
1939 goto queueing_failed;
1940
1941 data = IMGU_ABI_EVENT_BUFFER_ENQUEUED(pipe,
1942 imgu_css_queues[b->queue].qid);
1943 r = imgu_css_queue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, thread: pipe, data);
1944 if (r < 0)
1945 goto queueing_failed;
1946
1947 dev_dbg(css->dev, "queued buffer %p to css queue %i in pipe %d\n",
1948 b, b->queue, pipe);
1949
1950 return 0;
1951
1952queueing_failed:
1953 b->state = (r == -EBUSY || r == -EAGAIN) ?
1954 IPU3_CSS_BUFFER_NEW : IPU3_CSS_BUFFER_FAILED;
1955 list_del(entry: &b->list);
1956
1957 return r;
1958}
1959
1960/*
1961 * Get next ready CSS buffer. Returns -EAGAIN in which case the function
1962 * should be called again, or -EBUSY which means that there are no more
1963 * buffers available. May be called from interrupt context.
1964 */
1965struct imgu_css_buffer *imgu_css_buf_dequeue(struct imgu_css *css)
1966{
1967 static const unsigned char evtype_to_queue[] = {
1968 [IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE] = IPU3_CSS_QUEUE_IN,
1969 [IMGU_ABI_EVTTYPE_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_OUT,
1970 [IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_VF,
1971 [IMGU_ABI_EVTTYPE_3A_STATS_DONE] = IPU3_CSS_QUEUE_STAT_3A,
1972 };
1973 struct imgu_css_buffer *b = ERR_PTR(error: -EAGAIN);
1974 u32 event, daddr;
1975 int evtype, pipe, pipeid, queue, qid, r;
1976 struct imgu_css_pipe *css_pipe;
1977
1978 if (!css->streaming)
1979 return ERR_PTR(error: -EPROTO);
1980
1981 r = imgu_css_dequeue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, data: &event);
1982 if (r < 0)
1983 return ERR_PTR(error: r);
1984
1985 evtype = (event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
1986 IMGU_ABI_EVTTYPE_EVENT_SHIFT;
1987
1988 switch (evtype) {
1989 case IMGU_ABI_EVTTYPE_OUT_FRAME_DONE:
1990 case IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE:
1991 case IMGU_ABI_EVTTYPE_3A_STATS_DONE:
1992 case IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE:
1993 pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
1994 IMGU_ABI_EVTTYPE_PIPE_SHIFT;
1995 pipeid = (event & IMGU_ABI_EVTTYPE_PIPEID_MASK) >>
1996 IMGU_ABI_EVTTYPE_PIPEID_SHIFT;
1997 queue = evtype_to_queue[evtype];
1998 qid = imgu_css_queues[queue].qid;
1999
2000 if (pipe >= IMGU_MAX_PIPE_NUM) {
2001 dev_err(css->dev, "Invalid pipe: %i\n", pipe);
2002 return ERR_PTR(error: -EIO);
2003 }
2004
2005 if (qid >= IMGU_ABI_QUEUE_NUM) {
2006 dev_err(css->dev, "Invalid qid: %i\n", qid);
2007 return ERR_PTR(error: -EIO);
2008 }
2009 css_pipe = &css->pipes[pipe];
2010 dev_dbg(css->dev,
2011 "event: buffer done 0x%x queue %i pipe %i pipeid %i\n",
2012 event, queue, pipe, pipeid);
2013
2014 r = imgu_css_dequeue_data(css, queue: qid, data: &daddr);
2015 if (r < 0) {
2016 dev_err(css->dev, "failed to dequeue buffer\n");
2017 /* Force real error, not -EBUSY */
2018 return ERR_PTR(error: -EIO);
2019 }
2020
2021 r = imgu_css_queue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, thread: pipe,
2022 IMGU_ABI_EVENT_BUFFER_DEQUEUED(qid));
2023 if (r < 0) {
2024 dev_err(css->dev, "failed to queue event\n");
2025 return ERR_PTR(error: -EIO);
2026 }
2027
2028 spin_lock(lock: &css_pipe->qlock);
2029 if (list_empty(head: &css_pipe->queue[queue].bufs)) {
2030 spin_unlock(lock: &css_pipe->qlock);
2031 dev_err(css->dev, "event on empty queue\n");
2032 return ERR_PTR(error: -EIO);
2033 }
2034 b = list_first_entry(&css_pipe->queue[queue].bufs,
2035 struct imgu_css_buffer, list);
2036 if (queue != b->queue ||
2037 daddr != css_pipe->abi_buffers
2038 [b->queue][b->queue_pos].daddr) {
2039 spin_unlock(lock: &css_pipe->qlock);
2040 dev_err(css->dev, "dequeued bad buffer 0x%x\n", daddr);
2041 return ERR_PTR(error: -EIO);
2042 }
2043
2044 dev_dbg(css->dev, "buffer 0x%8x done from pipe %d\n", daddr, pipe);
2045 b->pipe = pipe;
2046 b->state = IPU3_CSS_BUFFER_DONE;
2047 list_del(entry: &b->list);
2048 spin_unlock(lock: &css_pipe->qlock);
2049 break;
2050 case IMGU_ABI_EVTTYPE_PIPELINE_DONE:
2051 pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
2052 IMGU_ABI_EVTTYPE_PIPE_SHIFT;
2053 if (pipe >= IMGU_MAX_PIPE_NUM) {
2054 dev_err(css->dev, "Invalid pipe: %i\n", pipe);
2055 return ERR_PTR(error: -EIO);
2056 }
2057
2058 css_pipe = &css->pipes[pipe];
2059 dev_dbg(css->dev, "event: pipeline done 0x%8x for pipe %d\n",
2060 event, pipe);
2061 break;
2062 case IMGU_ABI_EVTTYPE_TIMER:
2063 r = imgu_css_dequeue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, data: &event);
2064 if (r < 0)
2065 return ERR_PTR(error: r);
2066
2067 if ((event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
2068 IMGU_ABI_EVTTYPE_EVENT_SHIFT == IMGU_ABI_EVTTYPE_TIMER)
2069 dev_dbg(css->dev, "event: timer\n");
2070 else
2071 dev_warn(css->dev, "half of timer event missing\n");
2072 break;
2073 case IMGU_ABI_EVTTYPE_FW_WARNING:
2074 dev_warn(css->dev, "event: firmware warning 0x%x\n", event);
2075 break;
2076 case IMGU_ABI_EVTTYPE_FW_ASSERT:
2077 dev_err(css->dev,
2078 "event: firmware assert 0x%x module_id %i line_no %i\n",
2079 event,
2080 (event & IMGU_ABI_EVTTYPE_MODULEID_MASK) >>
2081 IMGU_ABI_EVTTYPE_MODULEID_SHIFT,
2082 swab16((event & IMGU_ABI_EVTTYPE_LINENO_MASK) >>
2083 IMGU_ABI_EVTTYPE_LINENO_SHIFT));
2084 break;
2085 default:
2086 dev_warn(css->dev, "received unknown event 0x%x\n", event);
2087 }
2088
2089 return b;
2090}
2091
2092/*
2093 * Get a new set of parameters from pool and initialize them based on
2094 * the parameters params, gdc, and obgrid. Any of these may be NULL,
2095 * in which case the previously set parameters are used.
2096 * If parameters haven't been set previously, initialize from scratch.
2097 *
2098 * Return index to css->parameter_set_info which has the newly created
2099 * parameters or negative value on error.
2100 */
2101int imgu_css_set_parameters(struct imgu_css *css, unsigned int pipe,
2102 struct ipu3_uapi_params *set_params)
2103{
2104 static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
2105 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
2106 const int stage = 0;
2107 const struct imgu_fw_info *bi;
2108 int obgrid_size;
2109 unsigned int stripes, i;
2110 struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
2111
2112 /* Destination buffers which are filled here */
2113 struct imgu_abi_parameter_set_info *param_set;
2114 struct imgu_abi_acc_param *acc = NULL;
2115 struct imgu_abi_gdc_warp_param *gdc = NULL;
2116 struct ipu3_uapi_obgrid_param *obgrid = NULL;
2117 const struct imgu_css_map *map;
2118 void *vmem0 = NULL;
2119 void *dmem0 = NULL;
2120
2121 enum imgu_abi_memories m;
2122 int r = -EBUSY;
2123
2124 if (!css->streaming)
2125 return -EPROTO;
2126
2127 dev_dbg(css->dev, "%s for pipe %d", __func__, pipe);
2128
2129 bi = &css->fwp->binary_header[css_pipe->bindex];
2130 obgrid_size = imgu_css_fw_obgrid_size(bi);
2131 stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
2132
2133 imgu_css_pool_get(pool: &css_pipe->pool.parameter_set_info);
2134 param_set = imgu_css_pool_last(pool: &css_pipe->pool.parameter_set_info,
2135 last: 0)->vaddr;
2136
2137 /* Get a new acc only if new parameters given, or none yet */
2138 map = imgu_css_pool_last(pool: &css_pipe->pool.acc, last: 0);
2139 if (set_params || !map->vaddr) {
2140 imgu_css_pool_get(pool: &css_pipe->pool.acc);
2141 map = imgu_css_pool_last(pool: &css_pipe->pool.acc, last: 0);
2142 acc = map->vaddr;
2143 }
2144
2145 /* Get new VMEM0 only if needed, or none yet */
2146 m = IMGU_ABI_MEM_ISP_VMEM0;
2147 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 0);
2148 if (!map->vaddr || (set_params && (set_params->use.lin_vmem_params ||
2149 set_params->use.tnr3_vmem_params ||
2150 set_params->use.xnr3_vmem_params))) {
2151 imgu_css_pool_get(pool: &css_pipe->pool.binary_params_p[m]);
2152 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 0);
2153 vmem0 = map->vaddr;
2154 }
2155
2156 /* Get new DMEM0 only if needed, or none yet */
2157 m = IMGU_ABI_MEM_ISP_DMEM0;
2158 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 0);
2159 if (!map->vaddr || (set_params && (set_params->use.tnr3_dmem_params ||
2160 set_params->use.xnr3_dmem_params))) {
2161 imgu_css_pool_get(pool: &css_pipe->pool.binary_params_p[m]);
2162 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 0);
2163 dmem0 = map->vaddr;
2164 }
2165
2166 /* Configure acc parameter cluster */
2167 if (acc) {
2168 /* get acc_old */
2169 map = imgu_css_pool_last(pool: &css_pipe->pool.acc, last: 1);
2170 /* user acc */
2171 r = imgu_css_cfg_acc(css, pipe, use, acc, acc_old: map->vaddr,
2172 acc_user: set_params ? &set_params->acc_param : NULL);
2173 if (r < 0)
2174 goto fail;
2175 }
2176
2177 /* Configure late binding parameters */
2178 if (vmem0) {
2179 m = IMGU_ABI_MEM_ISP_VMEM0;
2180 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 1);
2181 r = imgu_css_cfg_vmem0(css, pipe, use, vmem0,
2182 vmem0_old: map->vaddr, user: set_params);
2183 if (r < 0)
2184 goto fail;
2185 }
2186
2187 if (dmem0) {
2188 m = IMGU_ABI_MEM_ISP_DMEM0;
2189 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 1);
2190 r = imgu_css_cfg_dmem0(css, pipe, use, dmem0,
2191 dmem0_old: map->vaddr, user: set_params);
2192 if (r < 0)
2193 goto fail;
2194 }
2195
2196 /* Get a new gdc only if a new gdc is given, or none yet */
2197 if (bi->info.isp.sp.enable.dvs_6axis) {
2198 unsigned int a = IPU3_CSS_AUX_FRAME_REF;
2199 unsigned int g = IPU3_CSS_RECT_GDC;
2200 unsigned int e = IPU3_CSS_RECT_ENVELOPE;
2201
2202 map = imgu_css_pool_last(pool: &css_pipe->pool.gdc, last: 0);
2203 if (!map->vaddr) {
2204 imgu_css_pool_get(pool: &css_pipe->pool.gdc);
2205 map = imgu_css_pool_last(pool: &css_pipe->pool.gdc, last: 0);
2206 gdc = map->vaddr;
2207 imgu_css_cfg_gdc_table(gdc: map->vaddr,
2208 frame_in_x: css_pipe->aux_frames[a].bytesperline /
2209 css_pipe->aux_frames[a].bytesperpixel,
2210 frame_in_y: css_pipe->aux_frames[a].height,
2211 frame_out_x: css_pipe->rect[g].width,
2212 frame_out_y: css_pipe->rect[g].height,
2213 env_w: css_pipe->rect[e].width,
2214 env_h: css_pipe->rect[e].height);
2215 }
2216 }
2217
2218 /* Get a new obgrid only if a new obgrid is given, or none yet */
2219 map = imgu_css_pool_last(pool: &css_pipe->pool.obgrid, last: 0);
2220 if (!map->vaddr || (set_params && set_params->use.obgrid_param)) {
2221 imgu_css_pool_get(pool: &css_pipe->pool.obgrid);
2222 map = imgu_css_pool_last(pool: &css_pipe->pool.obgrid, last: 0);
2223 obgrid = map->vaddr;
2224
2225 /* Configure optical black level grid (obgrid) */
2226 if (set_params && set_params->use.obgrid_param)
2227 for (i = 0; i < obgrid_size / sizeof(*obgrid); i++)
2228 obgrid[i] = set_params->obgrid_param;
2229 else
2230 memset(obgrid, 0, obgrid_size);
2231 }
2232
2233 /* Configure parameter set info, queued to `queue_id' */
2234
2235 memset(param_set, 0, sizeof(*param_set));
2236 map = imgu_css_pool_last(pool: &css_pipe->pool.acc, last: 0);
2237 param_set->mem_map.acc_cluster_params_for_sp = map->daddr;
2238
2239 map = imgu_css_pool_last(pool: &css_pipe->pool.gdc, last: 0);
2240 param_set->mem_map.dvs_6axis_params_y = map->daddr;
2241
2242 for (i = 0; i < stripes; i++) {
2243 map = imgu_css_pool_last(pool: &css_pipe->pool.obgrid, last: 0);
2244 param_set->mem_map.obgrid_tbl[i] =
2245 map->daddr + (obgrid_size / stripes) * i;
2246 }
2247
2248 for (m = 0; m < IMGU_ABI_NUM_MEMORIES; m++) {
2249 map = imgu_css_pool_last(pool: &css_pipe->pool.binary_params_p[m], last: 0);
2250 param_set->mem_map.isp_mem_param[stage][m] = map->daddr;
2251 }
2252
2253 /* Then queue the new parameter buffer */
2254 map = imgu_css_pool_last(pool: &css_pipe->pool.parameter_set_info, last: 0);
2255 r = imgu_css_queue_data(css, queue: queue_id, thread: pipe, data: map->daddr);
2256 if (r < 0)
2257 goto fail;
2258
2259 r = imgu_css_queue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, thread: pipe,
2260 IMGU_ABI_EVENT_BUFFER_ENQUEUED(pipe,
2261 queue_id));
2262 if (r < 0)
2263 goto fail_no_put;
2264
2265 /* Finally dequeue all old parameter buffers */
2266
2267 do {
2268 u32 daddr;
2269
2270 r = imgu_css_dequeue_data(css, queue: queue_id, data: &daddr);
2271 if (r == -EBUSY)
2272 break;
2273 if (r)
2274 goto fail_no_put;
2275 r = imgu_css_queue_data(css, queue: IMGU_ABI_QUEUE_EVENT_ID, thread: pipe,
2276 IMGU_ABI_EVENT_BUFFER_DEQUEUED
2277 (queue_id));
2278 if (r < 0) {
2279 dev_err(css->dev, "failed to queue parameter event\n");
2280 goto fail_no_put;
2281 }
2282 } while (1);
2283
2284 return 0;
2285
2286fail:
2287 /*
2288 * A failure, most likely the parameter queue was full.
2289 * Return error but continue streaming. User can try submitting new
2290 * parameters again later.
2291 */
2292
2293 imgu_css_pool_put(pool: &css_pipe->pool.parameter_set_info);
2294 if (acc)
2295 imgu_css_pool_put(pool: &css_pipe->pool.acc);
2296 if (gdc)
2297 imgu_css_pool_put(pool: &css_pipe->pool.gdc);
2298 if (obgrid)
2299 imgu_css_pool_put(pool: &css_pipe->pool.obgrid);
2300 if (vmem0)
2301 imgu_css_pool_put(
2302 pool: &css_pipe->pool.binary_params_p
2303 [IMGU_ABI_MEM_ISP_VMEM0]);
2304 if (dmem0)
2305 imgu_css_pool_put(
2306 pool: &css_pipe->pool.binary_params_p
2307 [IMGU_ABI_MEM_ISP_DMEM0]);
2308
2309fail_no_put:
2310 return r;
2311}
2312
2313int imgu_css_irq_ack(struct imgu_css *css)
2314{
2315 static const int NUM_SWIRQS = 3;
2316 struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[0]];
2317 void __iomem *const base = css->base;
2318 u32 irq_status[IMGU_IRQCTRL_NUM];
2319 int i;
2320
2321 u32 imgu_status = readl(addr: base + IMGU_REG_INT_STATUS);
2322
2323 writel(val: imgu_status, addr: base + IMGU_REG_INT_STATUS);
2324 for (i = 0; i < IMGU_IRQCTRL_NUM; i++)
2325 irq_status[i] = readl(addr: base + IMGU_REG_IRQCTRL_STATUS(i));
2326
2327 for (i = 0; i < NUM_SWIRQS; i++) {
2328 if (irq_status[IMGU_IRQCTRL_SP0] & IMGU_IRQCTRL_IRQ_SW_PIN(i)) {
2329 /* SP SW interrupt */
2330 u32 cnt = readl(addr: base + IMGU_REG_SP_DMEM_BASE(0) +
2331 bi->info.sp.output);
2332 u32 val = readl(addr: base + IMGU_REG_SP_DMEM_BASE(0) +
2333 bi->info.sp.output + 4 + 4 * i);
2334
2335 dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
2336 __func__, i, cnt, val);
2337 }
2338 }
2339
2340 for (i = IMGU_IRQCTRL_NUM - 1; i >= 0; i--)
2341 if (irq_status[i]) {
2342 writel(val: irq_status[i], addr: base + IMGU_REG_IRQCTRL_CLEAR(i));
2343 /* Wait for write to complete */
2344 readl(addr: base + IMGU_REG_IRQCTRL_ENABLE(i));
2345 }
2346
2347 dev_dbg(css->dev, "%s: imgu 0x%x main 0x%x sp0 0x%x sp1 0x%x\n",
2348 __func__, imgu_status, irq_status[IMGU_IRQCTRL_MAIN],
2349 irq_status[IMGU_IRQCTRL_SP0], irq_status[IMGU_IRQCTRL_SP1]);
2350
2351 if (!imgu_status && !irq_status[IMGU_IRQCTRL_MAIN])
2352 return -ENOMSG;
2353
2354 return 0;
2355}
2356

source code of linux/drivers/staging/media/ipu3/ipu3-css.c