Commit | Line | Data |
---|---|---|
f5fbb83f | 1 | // SPDX-License-Identifier: GPL-2.0 |
ad85094b MCC |
2 | /* |
3 | * Support for Clovertrail PNW Camera Imaging ISP subsystem. | |
4 | * | |
5 | * Copyright (c) 2013 Intel Corporation. All Rights Reserved. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License version | |
9 | * 2 as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * | |
17 | */ | |
18 | ||
19 | #include <media/videobuf-vmalloc.h> | |
20 | #include <media/v4l2-dev.h> | |
21 | #include <media/v4l2-event.h> | |
22 | ||
23 | #include "mmu/isp_mmu.h" | |
24 | #include "mmu/sh_mmu_mrfld.h" | |
25 | #include "hmm/hmm_bo.h" | |
26 | #include "hmm/hmm.h" | |
27 | ||
28 | #include "atomisp_compat.h" | |
29 | #include "atomisp_internal.h" | |
30 | #include "atomisp_cmd.h" | |
31 | #include "atomisp-regs.h" | |
32 | #include "atomisp_fops.h" | |
33 | #include "atomisp_ioctl.h" | |
34 | #include "atomisp_acc.h" | |
35 | ||
ad85094b MCC |
36 | #include "ia_css_debug.h" |
37 | #include "ia_css_isp_param.h" | |
38 | #include "sh_css_hrt.h" | |
39 | #include "ia_css_isys.h" | |
40 | ||
71aecd5d | 41 | #include <linux/io.h> |
ad85094b MCC |
42 | #include <linux/pm_runtime.h> |
43 | ||
44 | /* Assume max number of ACC stages */ | |
45 | #define MAX_ACC_STAGES 20 | |
46 | ||
47 | /* Ideally, this should come from CSS headers */ | |
48 | #define NO_LINK -1 | |
49 | ||
50 | /* | |
51 | * to serialize MMIO access , this is due to ISP2400 silicon issue Sighting | |
52 | * #4684168, if concurrency access happened, system may hard hang. | |
53 | */ | |
54 | static DEFINE_SPINLOCK(mmio_lock); | |
55 | ||
56 | enum frame_info_type { | |
57 | ATOMISP_CSS_VF_FRAME, | |
58 | ATOMISP_CSS_SECOND_VF_FRAME, | |
59 | ATOMISP_CSS_OUTPUT_FRAME, | |
60 | ATOMISP_CSS_SECOND_OUTPUT_FRAME, | |
61 | ATOMISP_CSS_RAW_FRAME, | |
62 | }; | |
63 | ||
64 | struct bayer_ds_factor { | |
65 | unsigned int numerator; | |
66 | unsigned int denominator; | |
67 | }; | |
68 | ||
ad85094b MCC |
69 | static void atomisp_css2_hw_store_8(hrt_address addr, uint8_t data) |
70 | { | |
71aecd5d | 71 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b MCC |
72 | unsigned long flags; |
73 | ||
74 | spin_lock_irqsave(&mmio_lock, flags); | |
71aecd5d | 75 | writeb(data, isp->base + (addr & 0x003FFFFF)); |
ad85094b MCC |
76 | spin_unlock_irqrestore(&mmio_lock, flags); |
77 | } | |
78 | ||
79 | static void atomisp_css2_hw_store_16(hrt_address addr, uint16_t data) | |
80 | { | |
71aecd5d | 81 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b MCC |
82 | unsigned long flags; |
83 | ||
84 | spin_lock_irqsave(&mmio_lock, flags); | |
71aecd5d | 85 | writew(data, isp->base + (addr & 0x003FFFFF)); |
ad85094b MCC |
86 | spin_unlock_irqrestore(&mmio_lock, flags); |
87 | } | |
88 | ||
1a16d545 | 89 | void atomisp_css2_hw_store_32(hrt_address addr, uint32_t data) |
ad85094b | 90 | { |
71aecd5d | 91 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b MCC |
92 | unsigned long flags; |
93 | ||
94 | spin_lock_irqsave(&mmio_lock, flags); | |
71aecd5d | 95 | writel(data, isp->base + (addr & 0x003FFFFF)); |
ad85094b MCC |
96 | spin_unlock_irqrestore(&mmio_lock, flags); |
97 | } | |
98 | ||
99 | static uint8_t atomisp_css2_hw_load_8(hrt_address addr) | |
100 | { | |
71aecd5d | 101 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b | 102 | unsigned long flags; |
bdfe0beb | 103 | u8 ret; |
ad85094b MCC |
104 | |
105 | spin_lock_irqsave(&mmio_lock, flags); | |
71aecd5d | 106 | ret = readb(isp->base + (addr & 0x003FFFFF)); |
ad85094b MCC |
107 | spin_unlock_irqrestore(&mmio_lock, flags); |
108 | return ret; | |
109 | } | |
110 | ||
111 | static uint16_t atomisp_css2_hw_load_16(hrt_address addr) | |
112 | { | |
71aecd5d | 113 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b | 114 | unsigned long flags; |
bdfe0beb | 115 | u16 ret; |
ad85094b MCC |
116 | |
117 | spin_lock_irqsave(&mmio_lock, flags); | |
71aecd5d | 118 | ret = readw(isp->base + (addr & 0x003FFFFF)); |
ad85094b MCC |
119 | spin_unlock_irqrestore(&mmio_lock, flags); |
120 | return ret; | |
121 | } | |
122 | ||
123 | static uint32_t atomisp_css2_hw_load_32(hrt_address addr) | |
124 | { | |
71aecd5d | 125 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b | 126 | unsigned long flags; |
bdfe0beb | 127 | u32 ret; |
ad85094b MCC |
128 | |
129 | spin_lock_irqsave(&mmio_lock, flags); | |
71aecd5d | 130 | ret = readl(isp->base + (addr & 0x003FFFFF)); |
ad85094b MCC |
131 | spin_unlock_irqrestore(&mmio_lock, flags); |
132 | return ret; | |
133 | } | |
134 | ||
71aecd5d | 135 | static void atomisp_css2_hw_store(hrt_address addr, const void *from, uint32_t n) |
ad85094b | 136 | { |
71aecd5d | 137 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b MCC |
138 | unsigned long flags; |
139 | unsigned int i; | |
ad85094b | 140 | |
71aecd5d | 141 | addr &= 0x003FFFFF; |
ad85094b | 142 | spin_lock_irqsave(&mmio_lock, flags); |
71aecd5d AS |
143 | for (i = 0; i < n; i++, from++) |
144 | writeb(*(s8 *)from, isp->base + addr + i); | |
145 | ||
ad85094b MCC |
146 | spin_unlock_irqrestore(&mmio_lock, flags); |
147 | } | |
148 | ||
149 | static void atomisp_css2_hw_load(hrt_address addr, void *to, uint32_t n) | |
150 | { | |
71aecd5d | 151 | struct atomisp_device *isp = dev_get_drvdata(atomisp_dev); |
ad85094b MCC |
152 | unsigned long flags; |
153 | unsigned int i; | |
ad85094b | 154 | |
71aecd5d | 155 | addr &= 0x003FFFFF; |
ad85094b | 156 | spin_lock_irqsave(&mmio_lock, flags); |
71aecd5d AS |
157 | for (i = 0; i < n; i++, to++) |
158 | *(s8 *)to = readb(isp->base + addr + i); | |
ad85094b MCC |
159 | spin_unlock_irqrestore(&mmio_lock, flags); |
160 | } | |
161 | ||
162 | static int atomisp_css2_dbg_print(const char *fmt, va_list args) | |
163 | { | |
164 | vprintk(fmt, args); | |
165 | return 0; | |
166 | } | |
167 | ||
168 | static int atomisp_css2_dbg_ftrace_print(const char *fmt, va_list args) | |
169 | { | |
170 | ftrace_vprintk(fmt, args); | |
171 | return 0; | |
172 | } | |
173 | ||
174 | static int atomisp_css2_err_print(const char *fmt, va_list args) | |
175 | { | |
176 | vprintk(fmt, args); | |
177 | return 0; | |
178 | } | |
179 | ||
ad85094b MCC |
180 | void atomisp_load_uint32(hrt_address addr, uint32_t *data) |
181 | { | |
182 | *data = atomisp_css2_hw_load_32(addr); | |
183 | } | |
bdfe0beb | 184 | |
250977de | 185 | static int hmm_get_mmu_base_addr(struct device *dev, unsigned int *mmu_base_addr) |
ad85094b | 186 | { |
bdfe0beb | 187 | if (!sh_mmu_mrfld.get_pd_base) { |
250977de | 188 | dev_err(dev, "get mmu base address failed.\n"); |
ad85094b MCC |
189 | return -EINVAL; |
190 | } | |
191 | ||
192 | *mmu_base_addr = sh_mmu_mrfld.get_pd_base(&bo_device.mmu, | |
eaa399eb | 193 | bo_device.mmu.base_address); |
ad85094b MCC |
194 | return 0; |
195 | } | |
196 | ||
ad85094b MCC |
197 | static void __dump_pipe_config(struct atomisp_sub_device *asd, |
198 | struct atomisp_stream_env *stream_env, | |
199 | unsigned int pipe_id) | |
200 | { | |
201 | struct atomisp_device *isp = asd->isp; | |
202 | ||
203 | if (stream_env->pipes[pipe_id]) { | |
204 | struct ia_css_pipe_config *p_config; | |
205 | struct ia_css_pipe_extra_config *pe_config; | |
206 | ||
207 | p_config = &stream_env->pipe_configs[pipe_id]; | |
208 | pe_config = &stream_env->pipe_extra_configs[pipe_id]; | |
209 | dev_dbg(isp->dev, "dumping pipe[%d] config:\n", pipe_id); | |
210 | dev_dbg(isp->dev, | |
eaa399eb | 211 | "pipe_config.pipe_mode:%d.\n", p_config->mode); |
ad85094b | 212 | dev_dbg(isp->dev, |
eaa399eb MCC |
213 | "pipe_config.output_info[0] w=%d, h=%d.\n", |
214 | p_config->output_info[0].res.width, | |
215 | p_config->output_info[0].res.height); | |
ad85094b | 216 | dev_dbg(isp->dev, |
eaa399eb MCC |
217 | "pipe_config.vf_pp_in_res w=%d, h=%d.\n", |
218 | p_config->vf_pp_in_res.width, | |
219 | p_config->vf_pp_in_res.height); | |
ad85094b | 220 | dev_dbg(isp->dev, |
eaa399eb MCC |
221 | "pipe_config.capt_pp_in_res w=%d, h=%d.\n", |
222 | p_config->capt_pp_in_res.width, | |
223 | p_config->capt_pp_in_res.height); | |
ad85094b | 224 | dev_dbg(isp->dev, |
eaa399eb MCC |
225 | "pipe_config.output.padded w=%d.\n", |
226 | p_config->output_info[0].padded_width); | |
ad85094b | 227 | dev_dbg(isp->dev, |
eaa399eb MCC |
228 | "pipe_config.vf_output_info[0] w=%d, h=%d.\n", |
229 | p_config->vf_output_info[0].res.width, | |
230 | p_config->vf_output_info[0].res.height); | |
ad85094b | 231 | dev_dbg(isp->dev, |
eaa399eb MCC |
232 | "pipe_config.bayer_ds_out_res w=%d, h=%d.\n", |
233 | p_config->bayer_ds_out_res.width, | |
234 | p_config->bayer_ds_out_res.height); | |
ad85094b | 235 | dev_dbg(isp->dev, |
eaa399eb MCC |
236 | "pipe_config.envelope w=%d, h=%d.\n", |
237 | p_config->dvs_envelope.width, | |
238 | p_config->dvs_envelope.height); | |
ad85094b | 239 | dev_dbg(isp->dev, |
eaa399eb MCC |
240 | "pipe_config.dvs_frame_delay=%d.\n", |
241 | p_config->dvs_frame_delay); | |
ad85094b | 242 | dev_dbg(isp->dev, |
eaa399eb | 243 | "pipe_config.isp_pipe_version:%d.\n", |
ad85094b MCC |
244 | p_config->isp_pipe_version); |
245 | dev_dbg(isp->dev, | |
eaa399eb MCC |
246 | "pipe_config.acc_extension=%p.\n", |
247 | p_config->acc_extension); | |
ad85094b | 248 | dev_dbg(isp->dev, |
eaa399eb MCC |
249 | "pipe_config.acc_stages=%p.\n", |
250 | p_config->acc_stages); | |
ad85094b | 251 | dev_dbg(isp->dev, |
eaa399eb MCC |
252 | "pipe_config.num_acc_stages=%d.\n", |
253 | p_config->num_acc_stages); | |
ad85094b | 254 | dev_dbg(isp->dev, |
eaa399eb MCC |
255 | "pipe_config.acc_num_execs=%d.\n", |
256 | p_config->acc_num_execs); | |
ad85094b | 257 | dev_dbg(isp->dev, |
eaa399eb MCC |
258 | "pipe_config.default_capture_config.capture_mode=%d.\n", |
259 | p_config->default_capture_config.mode); | |
ad85094b | 260 | dev_dbg(isp->dev, |
eaa399eb MCC |
261 | "pipe_config.enable_dz=%d.\n", |
262 | p_config->enable_dz); | |
ad85094b | 263 | dev_dbg(isp->dev, |
eaa399eb MCC |
264 | "pipe_config.default_capture_config.enable_xnr=%d.\n", |
265 | p_config->default_capture_config.enable_xnr); | |
ad85094b | 266 | dev_dbg(isp->dev, |
eaa399eb | 267 | "dumping pipe[%d] extra config:\n", pipe_id); |
ad85094b | 268 | dev_dbg(isp->dev, |
eaa399eb MCC |
269 | "pipe_extra_config.enable_raw_binning:%d.\n", |
270 | pe_config->enable_raw_binning); | |
ad85094b | 271 | dev_dbg(isp->dev, |
eaa399eb MCC |
272 | "pipe_extra_config.enable_yuv_ds:%d.\n", |
273 | pe_config->enable_yuv_ds); | |
ad85094b | 274 | dev_dbg(isp->dev, |
eaa399eb MCC |
275 | "pipe_extra_config.enable_high_speed:%d.\n", |
276 | pe_config->enable_high_speed); | |
ad85094b | 277 | dev_dbg(isp->dev, |
eaa399eb MCC |
278 | "pipe_extra_config.enable_dvs_6axis:%d.\n", |
279 | pe_config->enable_dvs_6axis); | |
ad85094b | 280 | dev_dbg(isp->dev, |
eaa399eb MCC |
281 | "pipe_extra_config.enable_reduced_pipe:%d.\n", |
282 | pe_config->enable_reduced_pipe); | |
ad85094b | 283 | dev_dbg(isp->dev, |
eaa399eb MCC |
284 | "pipe_(extra_)config.enable_dz:%d.\n", |
285 | p_config->enable_dz); | |
ad85094b | 286 | dev_dbg(isp->dev, |
eaa399eb MCC |
287 | "pipe_extra_config.disable_vf_pp:%d.\n", |
288 | pe_config->disable_vf_pp); | |
ad85094b MCC |
289 | } |
290 | } | |
291 | ||
292 | static void __dump_stream_config(struct atomisp_sub_device *asd, | |
eaa399eb | 293 | struct atomisp_stream_env *stream_env) |
ad85094b MCC |
294 | { |
295 | struct atomisp_device *isp = asd->isp; | |
296 | struct ia_css_stream_config *s_config; | |
297 | int j; | |
298 | bool valid_stream = false; | |
299 | ||
300 | for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) { | |
301 | if (stream_env->pipes[j]) { | |
302 | __dump_pipe_config(asd, stream_env, j); | |
303 | valid_stream = true; | |
304 | } | |
305 | } | |
306 | if (!valid_stream) | |
307 | return; | |
308 | s_config = &stream_env->stream_config; | |
309 | dev_dbg(isp->dev, "stream_config.mode=%d.\n", s_config->mode); | |
310 | ||
311 | if (s_config->mode == IA_CSS_INPUT_MODE_SENSOR || | |
312 | s_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { | |
313 | dev_dbg(isp->dev, "stream_config.source.port.port=%d.\n", | |
eaa399eb | 314 | s_config->source.port.port); |
ad85094b | 315 | dev_dbg(isp->dev, "stream_config.source.port.num_lanes=%d.\n", |
eaa399eb | 316 | s_config->source.port.num_lanes); |
ad85094b | 317 | dev_dbg(isp->dev, "stream_config.source.port.timeout=%d.\n", |
eaa399eb | 318 | s_config->source.port.timeout); |
ad85094b | 319 | dev_dbg(isp->dev, "stream_config.source.port.rxcount=0x%x.\n", |
eaa399eb | 320 | s_config->source.port.rxcount); |
ad85094b | 321 | dev_dbg(isp->dev, "stream_config.source.port.compression.type=%d.\n", |
eaa399eb MCC |
322 | s_config->source.port.compression.type); |
323 | dev_dbg(isp->dev, | |
324 | "stream_config.source.port.compression.compressed_bits_per_pixel=%d.\n", | |
325 | s_config->source.port.compression. | |
326 | compressed_bits_per_pixel); | |
327 | dev_dbg(isp->dev, | |
328 | "stream_config.source.port.compression.uncompressed_bits_per_pixel=%d.\n", | |
329 | s_config->source.port.compression. | |
330 | uncompressed_bits_per_pixel); | |
ad85094b MCC |
331 | } else if (s_config->mode == IA_CSS_INPUT_MODE_TPG) { |
332 | dev_dbg(isp->dev, "stream_config.source.tpg.id=%d.\n", | |
eaa399eb | 333 | s_config->source.tpg.id); |
ad85094b | 334 | dev_dbg(isp->dev, "stream_config.source.tpg.mode=%d.\n", |
eaa399eb | 335 | s_config->source.tpg.mode); |
ad85094b | 336 | dev_dbg(isp->dev, "stream_config.source.tpg.x_mask=%d.\n", |
eaa399eb | 337 | s_config->source.tpg.x_mask); |
ad85094b | 338 | dev_dbg(isp->dev, "stream_config.source.tpg.x_delta=%d.\n", |
eaa399eb | 339 | s_config->source.tpg.x_delta); |
ad85094b | 340 | dev_dbg(isp->dev, "stream_config.source.tpg.y_mask=%d.\n", |
eaa399eb | 341 | s_config->source.tpg.y_mask); |
ad85094b | 342 | dev_dbg(isp->dev, "stream_config.source.tpg.y_delta=%d.\n", |
eaa399eb | 343 | s_config->source.tpg.y_delta); |
ad85094b | 344 | dev_dbg(isp->dev, "stream_config.source.tpg.xy_mask=%d.\n", |
eaa399eb | 345 | s_config->source.tpg.xy_mask); |
ad85094b MCC |
346 | } else if (s_config->mode == IA_CSS_INPUT_MODE_PRBS) { |
347 | dev_dbg(isp->dev, "stream_config.source.prbs.id=%d.\n", | |
eaa399eb | 348 | s_config->source.prbs.id); |
ad85094b | 349 | dev_dbg(isp->dev, "stream_config.source.prbs.h_blank=%d.\n", |
eaa399eb | 350 | s_config->source.prbs.h_blank); |
ad85094b | 351 | dev_dbg(isp->dev, "stream_config.source.prbs.v_blank=%d.\n", |
eaa399eb | 352 | s_config->source.prbs.v_blank); |
ad85094b | 353 | dev_dbg(isp->dev, "stream_config.source.prbs.seed=%d.\n", |
eaa399eb | 354 | s_config->source.prbs.seed); |
ad85094b | 355 | dev_dbg(isp->dev, "stream_config.source.prbs.seed1=%d.\n", |
eaa399eb | 356 | s_config->source.prbs.seed1); |
ad85094b MCC |
357 | } |
358 | ||
359 | for (j = 0; j < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; j++) { | |
360 | dev_dbg(isp->dev, "stream_configisys_config[%d].input_res w=%d, h=%d.\n", | |
361 | j, | |
362 | s_config->isys_config[j].input_res.width, | |
363 | s_config->isys_config[j].input_res.height); | |
364 | ||
365 | dev_dbg(isp->dev, "stream_configisys_config[%d].linked_isys_stream_id=%d\n", | |
366 | j, | |
367 | s_config->isys_config[j].linked_isys_stream_id); | |
368 | ||
369 | dev_dbg(isp->dev, "stream_configisys_config[%d].format=%d\n", | |
370 | j, | |
371 | s_config->isys_config[j].format); | |
372 | ||
373 | dev_dbg(isp->dev, "stream_configisys_config[%d].valid=%d.\n", | |
374 | j, | |
375 | s_config->isys_config[j].valid); | |
376 | } | |
377 | ||
378 | dev_dbg(isp->dev, "stream_config.input_config.input_res w=%d, h=%d.\n", | |
379 | s_config->input_config.input_res.width, | |
380 | s_config->input_config.input_res.height); | |
381 | ||
382 | dev_dbg(isp->dev, "stream_config.input_config.effective_res w=%d, h=%d.\n", | |
383 | s_config->input_config.effective_res.width, | |
384 | s_config->input_config.effective_res.height); | |
385 | ||
386 | dev_dbg(isp->dev, "stream_config.input_config.format=%d\n", | |
387 | s_config->input_config.format); | |
388 | ||
389 | dev_dbg(isp->dev, "stream_config.input_config.bayer_order=%d.\n", | |
390 | s_config->input_config.bayer_order); | |
391 | ||
392 | dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n", | |
eaa399eb | 393 | s_config->pixels_per_clock); |
ad85094b MCC |
394 | dev_dbg(isp->dev, "stream_config.online=%d.\n", s_config->online); |
395 | dev_dbg(isp->dev, "stream_config.continuous=%d.\n", | |
eaa399eb | 396 | s_config->continuous); |
ad85094b | 397 | dev_dbg(isp->dev, "stream_config.disable_cont_viewfinder=%d.\n", |
eaa399eb | 398 | s_config->disable_cont_viewfinder); |
ad85094b | 399 | dev_dbg(isp->dev, "stream_config.channel_id=%d.\n", |
eaa399eb | 400 | s_config->channel_id); |
ad85094b | 401 | dev_dbg(isp->dev, "stream_config.init_num_cont_raw_buf=%d.\n", |
eaa399eb | 402 | s_config->init_num_cont_raw_buf); |
ad85094b | 403 | dev_dbg(isp->dev, "stream_config.target_num_cont_raw_buf=%d.\n", |
eaa399eb | 404 | s_config->target_num_cont_raw_buf); |
ad85094b | 405 | dev_dbg(isp->dev, "stream_config.left_padding=%d.\n", |
eaa399eb | 406 | s_config->left_padding); |
ad85094b | 407 | dev_dbg(isp->dev, "stream_config.sensor_binning_factor=%d.\n", |
eaa399eb | 408 | s_config->sensor_binning_factor); |
ad85094b | 409 | dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n", |
eaa399eb | 410 | s_config->pixels_per_clock); |
ad85094b | 411 | dev_dbg(isp->dev, "stream_config.pack_raw_pixels=%d.\n", |
eaa399eb | 412 | s_config->pack_raw_pixels); |
ad85094b | 413 | dev_dbg(isp->dev, "stream_config.flash_gpio_pin=%d.\n", |
eaa399eb | 414 | s_config->flash_gpio_pin); |
ad85094b | 415 | dev_dbg(isp->dev, "stream_config.mipi_buffer_config.size_mem_words=%d.\n", |
eaa399eb | 416 | s_config->mipi_buffer_config.size_mem_words); |
ad85094b | 417 | dev_dbg(isp->dev, "stream_config.mipi_buffer_config.contiguous=%d.\n", |
eaa399eb | 418 | s_config->mipi_buffer_config.contiguous); |
ad85094b | 419 | dev_dbg(isp->dev, "stream_config.metadata_config.data_type=%d.\n", |
eaa399eb | 420 | s_config->metadata_config.data_type); |
ad85094b | 421 | dev_dbg(isp->dev, "stream_config.metadata_config.resolution w=%d, h=%d.\n", |
eaa399eb MCC |
422 | s_config->metadata_config.resolution.width, |
423 | s_config->metadata_config.resolution.height); | |
ad85094b MCC |
424 | } |
425 | ||
426 | static int __destroy_stream(struct atomisp_sub_device *asd, | |
eaa399eb | 427 | struct atomisp_stream_env *stream_env, bool force) |
ad85094b MCC |
428 | { |
429 | struct atomisp_device *isp = asd->isp; | |
430 | int i; | |
431 | unsigned long timeout; | |
432 | ||
433 | if (!stream_env->stream) | |
434 | return 0; | |
435 | ||
436 | if (!force) { | |
437 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) | |
438 | if (stream_env->update_pipe[i]) | |
439 | break; | |
440 | ||
441 | if (i == IA_CSS_PIPE_ID_NUM) | |
442 | return 0; | |
443 | } | |
444 | ||
445 | if (stream_env->stream_state == CSS_STREAM_STARTED | |
41022d35 | 446 | && ia_css_stream_stop(stream_env->stream) != 0) { |
ad85094b MCC |
447 | dev_err(isp->dev, "stop stream failed.\n"); |
448 | return -EINVAL; | |
449 | } | |
450 | ||
451 | if (stream_env->stream_state == CSS_STREAM_STARTED) { | |
452 | timeout = jiffies + msecs_to_jiffies(40); | |
453 | while (1) { | |
454 | if (ia_css_stream_has_stopped(stream_env->stream)) | |
455 | break; | |
456 | ||
457 | if (time_after(jiffies, timeout)) { | |
458 | dev_warn(isp->dev, "stop stream timeout.\n"); | |
459 | break; | |
460 | } | |
461 | ||
462 | usleep_range(100, 200); | |
463 | } | |
464 | } | |
465 | ||
466 | stream_env->stream_state = CSS_STREAM_STOPPED; | |
467 | ||
41022d35 | 468 | if (ia_css_stream_destroy(stream_env->stream)) { |
ad85094b MCC |
469 | dev_err(isp->dev, "destroy stream failed.\n"); |
470 | return -EINVAL; | |
471 | } | |
472 | stream_env->stream_state = CSS_STREAM_UNINIT; | |
473 | stream_env->stream = NULL; | |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
478 | static int __destroy_streams(struct atomisp_sub_device *asd, bool force) | |
479 | { | |
480 | int ret, i; | |
481 | ||
482 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
483 | ret = __destroy_stream(asd, &asd->stream_env[i], force); | |
484 | if (ret) | |
485 | return ret; | |
486 | } | |
487 | asd->stream_prepared = false; | |
488 | return 0; | |
489 | } | |
bdfe0beb | 490 | |
ad85094b MCC |
491 | static int __create_stream(struct atomisp_sub_device *asd, |
492 | struct atomisp_stream_env *stream_env) | |
493 | { | |
494 | int pipe_index = 0, i; | |
495 | struct ia_css_pipe *multi_pipes[IA_CSS_PIPE_ID_NUM]; | |
496 | ||
497 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { | |
498 | if (stream_env->pipes[i]) | |
499 | multi_pipes[pipe_index++] = stream_env->pipes[i]; | |
500 | } | |
501 | if (pipe_index == 0) | |
502 | return 0; | |
503 | ||
504 | stream_env->stream_config.target_num_cont_raw_buf = | |
eaa399eb | 505 | asd->continuous_raw_buffer_size->val; |
ad85094b MCC |
506 | stream_env->stream_config.channel_id = stream_env->ch_id; |
507 | stream_env->stream_config.ia_css_enable_raw_buffer_locking = | |
eaa399eb | 508 | asd->enable_raw_buffer_lock->val; |
ad85094b MCC |
509 | |
510 | __dump_stream_config(asd, stream_env); | |
511 | if (ia_css_stream_create(&stream_env->stream_config, | |
41022d35 | 512 | pipe_index, multi_pipes, &stream_env->stream) != 0) |
ad85094b MCC |
513 | return -EINVAL; |
514 | if (ia_css_stream_get_info(stream_env->stream, | |
41022d35 | 515 | &stream_env->stream_info) != 0) { |
ad85094b MCC |
516 | ia_css_stream_destroy(stream_env->stream); |
517 | stream_env->stream = NULL; | |
518 | return -EINVAL; | |
519 | } | |
520 | ||
521 | stream_env->stream_state = CSS_STREAM_CREATED; | |
522 | return 0; | |
523 | } | |
524 | ||
525 | static int __create_streams(struct atomisp_sub_device *asd) | |
526 | { | |
527 | int ret, i; | |
528 | ||
529 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
530 | ret = __create_stream(asd, &asd->stream_env[i]); | |
531 | if (ret) | |
532 | goto rollback; | |
533 | } | |
534 | asd->stream_prepared = true; | |
535 | return 0; | |
536 | rollback: | |
537 | for (i--; i >= 0; i--) | |
538 | __destroy_stream(asd, &asd->stream_env[i], true); | |
539 | return ret; | |
540 | } | |
541 | ||
542 | static int __destroy_stream_pipes(struct atomisp_sub_device *asd, | |
543 | struct atomisp_stream_env *stream_env, | |
544 | bool force) | |
545 | { | |
546 | struct atomisp_device *isp = asd->isp; | |
547 | int ret = 0; | |
548 | int i; | |
549 | ||
550 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { | |
551 | if (!stream_env->pipes[i] || | |
552 | !(force || stream_env->update_pipe[i])) | |
553 | continue; | |
554 | if (ia_css_pipe_destroy(stream_env->pipes[i]) | |
41022d35 | 555 | != 0) { |
ad85094b MCC |
556 | dev_err(isp->dev, |
557 | "destroy pipe[%d]failed.cannot recover.\n", i); | |
558 | ret = -EINVAL; | |
559 | } | |
560 | stream_env->pipes[i] = NULL; | |
561 | stream_env->update_pipe[i] = false; | |
562 | } | |
563 | return ret; | |
564 | } | |
565 | ||
566 | static int __destroy_pipes(struct atomisp_sub_device *asd, bool force) | |
567 | { | |
568 | struct atomisp_device *isp = asd->isp; | |
569 | int i; | |
570 | int ret = 0; | |
571 | ||
572 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
573 | if (asd->stream_env[i].stream) { | |
ad85094b MCC |
574 | dev_err(isp->dev, |
575 | "cannot destroy css pipes for stream[%d].\n", | |
576 | i); | |
577 | continue; | |
578 | } | |
579 | ||
580 | ret = __destroy_stream_pipes(asd, &asd->stream_env[i], force); | |
581 | if (ret) | |
582 | return ret; | |
583 | } | |
584 | ||
585 | return 0; | |
586 | } | |
587 | ||
588 | void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd) | |
589 | { | |
590 | __destroy_streams(asd, true); | |
591 | __destroy_pipes(asd, true); | |
592 | } | |
593 | ||
594 | static void __apply_additional_pipe_config( | |
eaa399eb MCC |
595 | struct atomisp_sub_device *asd, |
596 | struct atomisp_stream_env *stream_env, | |
597 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
598 | { |
599 | struct atomisp_device *isp = asd->isp; | |
600 | ||
601 | if (pipe_id < 0 || pipe_id >= IA_CSS_PIPE_ID_NUM) { | |
602 | dev_err(isp->dev, | |
eaa399eb | 603 | "wrong pipe_id for additional pipe config.\n"); |
ad85094b MCC |
604 | return; |
605 | } | |
606 | ||
607 | /* apply default pipe config */ | |
608 | stream_env->pipe_configs[pipe_id].isp_pipe_version = 2; | |
609 | stream_env->pipe_configs[pipe_id].enable_dz = | |
eaa399eb | 610 | asd->disable_dz->val ? false : true; |
ad85094b MCC |
611 | /* apply isp 2.2 specific config for baytrail*/ |
612 | switch (pipe_id) { | |
613 | case IA_CSS_PIPE_ID_CAPTURE: | |
614 | /* enable capture pp/dz manually or digital zoom would | |
615 | * fail*/ | |
616 | if (stream_env->pipe_configs[pipe_id]. | |
c01d5546 | 617 | default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW) |
ad85094b | 618 | stream_env->pipe_configs[pipe_id].enable_dz = false; |
7ef17aa5 | 619 | |
469a7306 | 620 | if (IS_ISP2401) { |
7ef17aa5 MCC |
621 | /* the isp default to use ISP2.2 and the camera hal will |
622 | * control whether use isp2.7 */ | |
623 | if (asd->select_isp_version->val == ATOMISP_CSS_ISP_PIPE_VERSION_2_7) | |
624 | stream_env->pipe_configs[pipe_id].isp_pipe_version = SH_CSS_ISP_PIPE_VERSION_2_7; | |
625 | else | |
626 | stream_env->pipe_configs[pipe_id].isp_pipe_version = SH_CSS_ISP_PIPE_VERSION_2_2; | |
627 | } | |
ad85094b MCC |
628 | break; |
629 | case IA_CSS_PIPE_ID_VIDEO: | |
630 | /* enable reduced pipe to have binary | |
631 | * video_dz_2_min selected*/ | |
632 | stream_env->pipe_extra_configs[pipe_id] | |
eaa399eb | 633 | .enable_reduced_pipe = true; |
ad85094b | 634 | stream_env->pipe_configs[pipe_id] |
eaa399eb | 635 | .enable_dz = false; |
ad85094b MCC |
636 | if (ATOMISP_SOC_CAMERA(asd)) |
637 | stream_env->pipe_configs[pipe_id].enable_dz = true; | |
638 | ||
639 | if (asd->params.video_dis_en) { | |
640 | stream_env->pipe_extra_configs[pipe_id] | |
eaa399eb | 641 | .enable_dvs_6axis = true; |
ad85094b | 642 | stream_env->pipe_configs[pipe_id] |
eaa399eb MCC |
643 | .dvs_frame_delay = |
644 | ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; | |
ad85094b MCC |
645 | } |
646 | break; | |
647 | case IA_CSS_PIPE_ID_PREVIEW: | |
648 | break; | |
649 | case IA_CSS_PIPE_ID_YUVPP: | |
650 | case IA_CSS_PIPE_ID_COPY: | |
651 | if (ATOMISP_SOC_CAMERA(asd)) | |
652 | stream_env->pipe_configs[pipe_id].enable_dz = true; | |
653 | else | |
654 | stream_env->pipe_configs[pipe_id].enable_dz = false; | |
655 | break; | |
656 | case IA_CSS_PIPE_ID_ACC: | |
657 | stream_env->pipe_configs[pipe_id].mode = IA_CSS_PIPE_MODE_ACC; | |
658 | stream_env->pipe_configs[pipe_id].enable_dz = false; | |
659 | break; | |
660 | default: | |
661 | break; | |
662 | } | |
663 | } | |
664 | ||
665 | static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd, | |
eaa399eb | 666 | enum ia_css_pipe_id pipe_id) |
ad85094b MCC |
667 | { |
668 | if (!asd) | |
669 | return false; | |
670 | ||
c01d5546 | 671 | if (pipe_id == IA_CSS_PIPE_ID_ACC || pipe_id == IA_CSS_PIPE_ID_YUVPP) |
ad85094b MCC |
672 | return true; |
673 | ||
674 | if (asd->vfpp) { | |
675 | if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { | |
676 | if (pipe_id == IA_CSS_PIPE_ID_VIDEO) | |
677 | return true; | |
678 | else | |
679 | return false; | |
680 | } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { | |
681 | if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) | |
682 | return true; | |
683 | else | |
684 | return false; | |
685 | } | |
686 | } | |
687 | ||
688 | if (!asd->run_mode) | |
689 | return false; | |
690 | ||
691 | if (asd->copy_mode && pipe_id == IA_CSS_PIPE_ID_COPY) | |
692 | return true; | |
693 | ||
694 | switch (asd->run_mode->val) { | |
695 | case ATOMISP_RUN_MODE_STILL_CAPTURE: | |
696 | if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) | |
697 | return true; | |
5b552b19 MCC |
698 | |
699 | return false; | |
ad85094b MCC |
700 | case ATOMISP_RUN_MODE_PREVIEW: |
701 | if (!asd->continuous_mode->val) { | |
702 | if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) | |
703 | return true; | |
5b552b19 MCC |
704 | |
705 | return false; | |
ad85094b | 706 | } |
df561f66 | 707 | fallthrough; |
ad85094b MCC |
708 | case ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE: |
709 | if (pipe_id == IA_CSS_PIPE_ID_CAPTURE || | |
710 | pipe_id == IA_CSS_PIPE_ID_PREVIEW) | |
711 | return true; | |
5b552b19 MCC |
712 | |
713 | return false; | |
df561f66 | 714 | fallthrough; |
ad85094b MCC |
715 | case ATOMISP_RUN_MODE_VIDEO: |
716 | if (!asd->continuous_mode->val) { | |
717 | if (pipe_id == IA_CSS_PIPE_ID_VIDEO || | |
718 | pipe_id == IA_CSS_PIPE_ID_YUVPP) | |
719 | return true; | |
720 | else | |
721 | return false; | |
722 | } | |
df561f66 | 723 | fallthrough; |
ad85094b MCC |
724 | case ATOMISP_RUN_MODE_SDV: |
725 | if (pipe_id == IA_CSS_PIPE_ID_CAPTURE || | |
726 | pipe_id == IA_CSS_PIPE_ID_VIDEO) | |
727 | return true; | |
5b552b19 MCC |
728 | |
729 | return false; | |
ad85094b MCC |
730 | } |
731 | ||
732 | return false; | |
733 | } | |
734 | ||
735 | static int __create_pipe(struct atomisp_sub_device *asd, | |
736 | struct atomisp_stream_env *stream_env, | |
737 | enum ia_css_pipe_id pipe_id) | |
738 | { | |
739 | struct atomisp_device *isp = asd->isp; | |
740 | struct ia_css_pipe_extra_config extra_config; | |
41022d35 | 741 | int ret; |
ad85094b MCC |
742 | |
743 | if (pipe_id >= IA_CSS_PIPE_ID_NUM) | |
744 | return -EINVAL; | |
745 | ||
c01d5546 | 746 | if (pipe_id != IA_CSS_PIPE_ID_ACC && |
ad85094b MCC |
747 | !stream_env->pipe_configs[pipe_id].output_info[0].res.width) |
748 | return 0; | |
749 | ||
c01d5546 | 750 | if (pipe_id == IA_CSS_PIPE_ID_ACC && |
ad85094b MCC |
751 | !stream_env->pipe_configs[pipe_id].acc_extension) |
752 | return 0; | |
753 | ||
754 | if (!is_pipe_valid_to_current_run_mode(asd, pipe_id)) | |
755 | return 0; | |
756 | ||
757 | ia_css_pipe_extra_config_defaults(&extra_config); | |
758 | ||
759 | __apply_additional_pipe_config(asd, stream_env, pipe_id); | |
760 | if (!memcmp(&extra_config, | |
761 | &stream_env->pipe_extra_configs[pipe_id], | |
762 | sizeof(extra_config))) | |
763 | ret = ia_css_pipe_create( | |
eaa399eb MCC |
764 | &stream_env->pipe_configs[pipe_id], |
765 | &stream_env->pipes[pipe_id]); | |
ad85094b MCC |
766 | else |
767 | ret = ia_css_pipe_create_extra( | |
eaa399eb MCC |
768 | &stream_env->pipe_configs[pipe_id], |
769 | &stream_env->pipe_extra_configs[pipe_id], | |
770 | &stream_env->pipes[pipe_id]); | |
41022d35 | 771 | if (ret) |
ad85094b MCC |
772 | dev_err(isp->dev, "create pipe[%d] error.\n", pipe_id); |
773 | return ret; | |
774 | } | |
775 | ||
776 | static int __create_pipes(struct atomisp_sub_device *asd) | |
777 | { | |
41022d35 | 778 | int ret; |
ad85094b MCC |
779 | int i, j; |
780 | ||
781 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
782 | for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) { | |
783 | ret = __create_pipe(asd, &asd->stream_env[i], j); | |
41022d35 | 784 | if (ret) |
ad85094b MCC |
785 | break; |
786 | } | |
787 | if (j < IA_CSS_PIPE_ID_NUM) | |
788 | goto pipe_err; | |
789 | } | |
790 | return 0; | |
791 | pipe_err: | |
792 | for (; i >= 0; i--) { | |
793 | for (j--; j >= 0; j--) { | |
794 | if (asd->stream_env[i].pipes[j]) { | |
795 | ia_css_pipe_destroy(asd->stream_env[i].pipes[j]); | |
796 | asd->stream_env[i].pipes[j] = NULL; | |
797 | } | |
798 | } | |
799 | j = IA_CSS_PIPE_ID_NUM; | |
800 | } | |
801 | return -EINVAL; | |
802 | } | |
803 | ||
804 | void atomisp_create_pipes_stream(struct atomisp_sub_device *asd) | |
805 | { | |
806 | __create_pipes(asd); | |
807 | __create_streams(asd); | |
808 | } | |
809 | ||
810 | int atomisp_css_update_stream(struct atomisp_sub_device *asd) | |
811 | { | |
812 | int ret; | |
813 | struct atomisp_device *isp = asd->isp; | |
814 | ||
41022d35 | 815 | if (__destroy_streams(asd, true)) |
ad85094b MCC |
816 | dev_warn(isp->dev, "destroy stream failed.\n"); |
817 | ||
41022d35 | 818 | if (__destroy_pipes(asd, true)) |
ad85094b MCC |
819 | dev_warn(isp->dev, "destroy pipe failed.\n"); |
820 | ||
821 | ret = __create_pipes(asd); | |
41022d35 | 822 | if (ret) { |
ad85094b MCC |
823 | dev_err(isp->dev, "create pipe failed %d.\n", ret); |
824 | return -EIO; | |
825 | } | |
826 | ||
827 | ret = __create_streams(asd); | |
41022d35 | 828 | if (ret) { |
ad85094b MCC |
829 | dev_warn(isp->dev, "create stream failed %d.\n", ret); |
830 | __destroy_pipes(asd, true); | |
831 | return -EIO; | |
832 | } | |
833 | ||
834 | return 0; | |
835 | } | |
836 | ||
837 | int atomisp_css_init(struct atomisp_device *isp) | |
838 | { | |
839 | unsigned int mmu_base_addr; | |
840 | int ret; | |
41022d35 | 841 | int err; |
ad85094b | 842 | |
250977de | 843 | ret = hmm_get_mmu_base_addr(isp->dev, &mmu_base_addr); |
ad85094b MCC |
844 | if (ret) |
845 | return ret; | |
846 | ||
847 | /* Init ISP */ | |
8568fe63 | 848 | err = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL, |
ad85094b | 849 | (uint32_t)mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE); |
41022d35 | 850 | if (err) { |
ad85094b MCC |
851 | dev_err(isp->dev, "css init failed --- bad firmware?\n"); |
852 | return -EINVAL; | |
853 | } | |
854 | ia_css_enable_isys_event_queue(true); | |
855 | ||
856 | isp->css_initialized = true; | |
857 | dev_dbg(isp->dev, "sh_css_init success\n"); | |
858 | ||
859 | return 0; | |
860 | } | |
861 | ||
862 | static inline int __set_css_print_env(struct atomisp_device *isp, int opt) | |
863 | { | |
864 | int ret = 0; | |
865 | ||
866 | if (opt == 0) | |
867 | isp->css_env.isp_css_env.print_env.debug_print = NULL; | |
868 | else if (opt == 1) | |
869 | isp->css_env.isp_css_env.print_env.debug_print = | |
eaa399eb | 870 | atomisp_css2_dbg_ftrace_print; |
ad85094b MCC |
871 | else if (opt == 2) |
872 | isp->css_env.isp_css_env.print_env.debug_print = | |
eaa399eb | 873 | atomisp_css2_dbg_print; |
ad85094b MCC |
874 | else |
875 | ret = -EINVAL; | |
876 | ||
877 | return ret; | |
878 | } | |
879 | ||
ad85094b MCC |
880 | int atomisp_css_load_firmware(struct atomisp_device *isp) |
881 | { | |
41022d35 | 882 | int err; |
ad85094b MCC |
883 | |
884 | /* set css env */ | |
885 | isp->css_env.isp_css_fw.data = (void *)isp->firmware->data; | |
886 | isp->css_env.isp_css_fw.bytes = isp->firmware->size; | |
887 | ||
888 | isp->css_env.isp_css_env.hw_access_env.store_8 = | |
eaa399eb | 889 | atomisp_css2_hw_store_8; |
ad85094b | 890 | isp->css_env.isp_css_env.hw_access_env.store_16 = |
eaa399eb | 891 | atomisp_css2_hw_store_16; |
ad85094b | 892 | isp->css_env.isp_css_env.hw_access_env.store_32 = |
eaa399eb | 893 | atomisp_css2_hw_store_32; |
ad85094b MCC |
894 | |
895 | isp->css_env.isp_css_env.hw_access_env.load_8 = atomisp_css2_hw_load_8; | |
896 | isp->css_env.isp_css_env.hw_access_env.load_16 = | |
eaa399eb | 897 | atomisp_css2_hw_load_16; |
ad85094b | 898 | isp->css_env.isp_css_env.hw_access_env.load_32 = |
eaa399eb | 899 | atomisp_css2_hw_load_32; |
ad85094b MCC |
900 | |
901 | isp->css_env.isp_css_env.hw_access_env.load = atomisp_css2_hw_load; | |
902 | isp->css_env.isp_css_env.hw_access_env.store = atomisp_css2_hw_store; | |
903 | ||
904 | __set_css_print_env(isp, dbg_func); | |
905 | ||
906 | isp->css_env.isp_css_env.print_env.error_print = atomisp_css2_err_print; | |
907 | ||
908 | /* load isp fw into ISP memory */ | |
8568fe63 | 909 | err = ia_css_load_firmware(isp->dev, &isp->css_env.isp_css_env, |
ad85094b | 910 | &isp->css_env.isp_css_fw); |
41022d35 | 911 | if (err) { |
ad85094b MCC |
912 | dev_err(isp->dev, "css load fw failed.\n"); |
913 | return -EINVAL; | |
914 | } | |
915 | ||
916 | return 0; | |
917 | } | |
918 | ||
ad85094b MCC |
919 | void atomisp_css_uninit(struct atomisp_device *isp) |
920 | { | |
921 | struct atomisp_sub_device *asd; | |
922 | unsigned int i; | |
923 | ||
924 | for (i = 0; i < isp->num_of_streams; i++) { | |
925 | asd = &isp->asd[i]; | |
1a16d545 | 926 | memset(&asd->params.config, 0, sizeof(asd->params.config)); |
ad85094b MCC |
927 | asd->params.css_update_params_needed = false; |
928 | } | |
929 | ||
930 | isp->css_initialized = false; | |
931 | ia_css_uninit(); | |
932 | } | |
933 | ||
934 | void atomisp_css_suspend(struct atomisp_device *isp) | |
935 | { | |
936 | isp->css_initialized = false; | |
937 | ia_css_uninit(); | |
938 | } | |
939 | ||
940 | int atomisp_css_resume(struct atomisp_device *isp) | |
941 | { | |
942 | unsigned int mmu_base_addr; | |
943 | int ret; | |
944 | ||
250977de | 945 | ret = hmm_get_mmu_base_addr(isp->dev, &mmu_base_addr); |
ad85094b MCC |
946 | if (ret) { |
947 | dev_err(isp->dev, "get base address error.\n"); | |
948 | return -EINVAL; | |
949 | } | |
950 | ||
8568fe63 | 951 | ret = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL, |
ad85094b MCC |
952 | mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE); |
953 | if (ret) { | |
954 | dev_err(isp->dev, "re-init css failed.\n"); | |
955 | return -EINVAL; | |
956 | } | |
957 | ia_css_enable_isys_event_queue(true); | |
958 | ||
959 | isp->css_initialized = true; | |
960 | return 0; | |
961 | } | |
962 | ||
963 | int atomisp_css_irq_translate(struct atomisp_device *isp, | |
964 | unsigned int *infos) | |
965 | { | |
966 | int err; | |
967 | ||
968 | err = ia_css_irq_translate(infos); | |
41022d35 | 969 | if (err) { |
ad85094b | 970 | dev_warn(isp->dev, |
eaa399eb MCC |
971 | "%s:failed to translate irq (err = %d,infos = %d)\n", |
972 | __func__, err, *infos); | |
ad85094b MCC |
973 | return -EINVAL; |
974 | } | |
975 | ||
976 | return 0; | |
977 | } | |
978 | ||
979 | void atomisp_css_rx_get_irq_info(enum mipi_port_id port, | |
eaa399eb | 980 | unsigned int *infos) |
ad85094b MCC |
981 | { |
982 | #ifndef ISP2401_NEW_INPUT_SYSTEM | |
983 | ia_css_isys_rx_get_irq_info(port, infos); | |
984 | #else | |
985 | *infos = 0; | |
986 | #endif | |
987 | } | |
988 | ||
989 | void atomisp_css_rx_clear_irq_info(enum mipi_port_id port, | |
eaa399eb | 990 | unsigned int infos) |
ad85094b MCC |
991 | { |
992 | #ifndef ISP2401_NEW_INPUT_SYSTEM | |
993 | ia_css_isys_rx_clear_irq_info(port, infos); | |
994 | #endif | |
995 | } | |
996 | ||
997 | int atomisp_css_irq_enable(struct atomisp_device *isp, | |
c01d5546 | 998 | enum ia_css_irq_info info, bool enable) |
ad85094b | 999 | { |
69a03e36 | 1000 | dev_dbg(isp->dev, "%s: css irq info 0x%08x: %s (%d).\n", |
cf3cd3b0 | 1001 | __func__, info, |
69a03e36 | 1002 | enable ? "enable" : "disable", enable); |
41022d35 | 1003 | if (ia_css_irq_enable(info, enable)) { |
d61ba1a2 MCC |
1004 | dev_warn(isp->dev, "%s:Invalid irq info: 0x%08x when %s.\n", |
1005 | __func__, info, | |
1006 | enable ? "enabling" : "disabling"); | |
ad85094b MCC |
1007 | return -EINVAL; |
1008 | } | |
1009 | ||
1010 | return 0; | |
1011 | } | |
1012 | ||
1013 | void atomisp_css_init_struct(struct atomisp_sub_device *asd) | |
1014 | { | |
1015 | int i, j; | |
1016 | ||
1017 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
1018 | asd->stream_env[i].stream = NULL; | |
1019 | for (j = 0; j < IA_CSS_PIPE_MODE_NUM; j++) { | |
1020 | asd->stream_env[i].pipes[j] = NULL; | |
1021 | asd->stream_env[i].update_pipe[j] = false; | |
1022 | ia_css_pipe_config_defaults( | |
eaa399eb | 1023 | &asd->stream_env[i].pipe_configs[j]); |
ad85094b | 1024 | ia_css_pipe_extra_config_defaults( |
eaa399eb | 1025 | &asd->stream_env[i].pipe_extra_configs[j]); |
ad85094b MCC |
1026 | } |
1027 | ia_css_stream_config_defaults(&asd->stream_env[i].stream_config); | |
1028 | } | |
1029 | } | |
1030 | ||
1031 | int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1032 | struct videobuf_vmalloc_memory *vm_mem, |
1033 | enum atomisp_input_stream_id stream_id, | |
c01d5546 MCC |
1034 | enum ia_css_buffer_type css_buf_type, |
1035 | enum ia_css_pipe_id css_pipe_id) | |
ad85094b MCC |
1036 | { |
1037 | struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; | |
1038 | struct ia_css_buffer css_buf = {0}; | |
41022d35 | 1039 | int err; |
ad85094b MCC |
1040 | |
1041 | css_buf.type = css_buf_type; | |
1042 | css_buf.data.frame = vm_mem->vaddr; | |
1043 | ||
1044 | err = ia_css_pipe_enqueue_buffer( | |
eaa399eb | 1045 | stream_env->pipes[css_pipe_id], &css_buf); |
41022d35 | 1046 | if (err) |
ad85094b MCC |
1047 | return -EINVAL; |
1048 | ||
1049 | return 0; | |
1050 | } | |
1051 | ||
1052 | int atomisp_q_metadata_buffer_to_css(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1053 | struct atomisp_metadata_buf *metadata_buf, |
1054 | enum atomisp_input_stream_id stream_id, | |
c01d5546 | 1055 | enum ia_css_pipe_id css_pipe_id) |
ad85094b MCC |
1056 | { |
1057 | struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; | |
1058 | struct ia_css_buffer buffer = {0}; | |
1059 | struct atomisp_device *isp = asd->isp; | |
1060 | ||
1061 | buffer.type = IA_CSS_BUFFER_TYPE_METADATA; | |
1062 | buffer.data.metadata = metadata_buf->metadata; | |
1063 | if (ia_css_pipe_enqueue_buffer(stream_env->pipes[css_pipe_id], | |
eaa399eb | 1064 | &buffer)) { |
ad85094b MCC |
1065 | dev_err(isp->dev, "failed to q meta data buffer\n"); |
1066 | return -EINVAL; | |
1067 | } | |
1068 | ||
1069 | return 0; | |
1070 | } | |
1071 | ||
1072 | int atomisp_q_s3a_buffer_to_css(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1073 | struct atomisp_s3a_buf *s3a_buf, |
1074 | enum atomisp_input_stream_id stream_id, | |
c01d5546 | 1075 | enum ia_css_pipe_id css_pipe_id) |
ad85094b MCC |
1076 | { |
1077 | struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; | |
1078 | struct ia_css_buffer buffer = {0}; | |
1079 | struct atomisp_device *isp = asd->isp; | |
1080 | ||
1081 | buffer.type = IA_CSS_BUFFER_TYPE_3A_STATISTICS; | |
1082 | buffer.data.stats_3a = s3a_buf->s3a_data; | |
1083 | if (ia_css_pipe_enqueue_buffer( | |
eaa399eb MCC |
1084 | stream_env->pipes[css_pipe_id], |
1085 | &buffer)) { | |
ad85094b MCC |
1086 | dev_dbg(isp->dev, "failed to q s3a stat buffer\n"); |
1087 | return -EINVAL; | |
1088 | } | |
1089 | ||
1090 | return 0; | |
1091 | } | |
1092 | ||
1093 | int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1094 | struct atomisp_dis_buf *dis_buf, |
1095 | enum atomisp_input_stream_id stream_id, | |
c01d5546 | 1096 | enum ia_css_pipe_id css_pipe_id) |
ad85094b MCC |
1097 | { |
1098 | struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; | |
1099 | struct ia_css_buffer buffer = {0}; | |
1100 | struct atomisp_device *isp = asd->isp; | |
1101 | ||
1102 | buffer.type = IA_CSS_BUFFER_TYPE_DIS_STATISTICS; | |
1103 | buffer.data.stats_dvs = dis_buf->dis_data; | |
1104 | if (ia_css_pipe_enqueue_buffer( | |
eaa399eb MCC |
1105 | stream_env->pipes[css_pipe_id], |
1106 | &buffer)) { | |
ad85094b MCC |
1107 | dev_dbg(isp->dev, "failed to q dvs stat buffer\n"); |
1108 | return -EINVAL; | |
1109 | } | |
1110 | ||
1111 | return 0; | |
1112 | } | |
1113 | ||
ad85094b | 1114 | int atomisp_css_start(struct atomisp_sub_device *asd, |
c01d5546 | 1115 | enum ia_css_pipe_id pipe_id, bool in_reset) |
ad85094b MCC |
1116 | { |
1117 | struct atomisp_device *isp = asd->isp; | |
1118 | bool sp_is_started = false; | |
1119 | int ret = 0, i = 0; | |
1120 | ||
1121 | if (in_reset) { | |
1122 | if (__destroy_streams(asd, true)) | |
1123 | dev_warn(isp->dev, "destroy stream failed.\n"); | |
1124 | ||
1125 | if (__destroy_pipes(asd, true)) | |
1126 | dev_warn(isp->dev, "destroy pipe failed.\n"); | |
1127 | ||
1128 | if (__create_pipes(asd)) { | |
1129 | dev_err(isp->dev, "create pipe error.\n"); | |
1130 | return -EINVAL; | |
1131 | } | |
1132 | if (__create_streams(asd)) { | |
1133 | dev_err(isp->dev, "create stream error.\n"); | |
1134 | ret = -EINVAL; | |
1135 | goto stream_err; | |
1136 | } | |
1137 | /* in_reset == true, extension firmwares are reloaded after the recovery */ | |
1138 | atomisp_acc_load_extensions(asd); | |
1139 | } | |
1140 | ||
1141 | /* | |
1142 | * For dual steam case, it is possible that: | |
1143 | * 1: for this stream, it is at the stage that: | |
1144 | * - after set_fmt is called | |
1145 | * - before stream on is called | |
1146 | * 2: for the other stream, the stream off is called which css reset | |
1147 | * has been done. | |
1148 | * | |
1149 | * Thus the stream created in set_fmt get destroyed and need to be | |
1150 | * recreated in the next stream on. | |
1151 | */ | |
1152 | if (asd->stream_prepared == false) { | |
1153 | if (__create_pipes(asd)) { | |
1154 | dev_err(isp->dev, "create pipe error.\n"); | |
1155 | return -EINVAL; | |
1156 | } | |
1157 | if (__create_streams(asd)) { | |
1158 | dev_err(isp->dev, "create stream error.\n"); | |
1159 | ret = -EINVAL; | |
1160 | goto stream_err; | |
1161 | } | |
1162 | } | |
1163 | /* | |
1164 | * SP can only be started one time | |
1165 | * if atomisp_subdev_streaming_count() tell there already has some | |
1166 | * subdev at streamming, then SP should already be started previously, | |
1167 | * so need to skip start sp procedure | |
1168 | */ | |
1169 | if (atomisp_streaming_count(isp)) { | |
1170 | dev_dbg(isp->dev, "skip start sp\n"); | |
1171 | } else { | |
1172 | if (!sh_css_hrt_system_is_idle()) | |
1173 | dev_err(isp->dev, "CSS HW not idle before starting SP\n"); | |
41022d35 | 1174 | if (ia_css_start_sp()) { |
ad85094b MCC |
1175 | dev_err(isp->dev, "start sp error.\n"); |
1176 | ret = -EINVAL; | |
1177 | goto start_err; | |
1178 | } else { | |
1179 | sp_is_started = true; | |
1180 | } | |
1181 | } | |
1182 | ||
1183 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
1184 | if (asd->stream_env[i].stream) { | |
1185 | if (ia_css_stream_start(asd->stream_env[i] | |
41022d35 | 1186 | .stream) != 0) { |
ad85094b MCC |
1187 | dev_err(isp->dev, "stream[%d] start error.\n", i); |
1188 | ret = -EINVAL; | |
1189 | goto start_err; | |
1190 | } else { | |
1191 | asd->stream_env[i].stream_state = CSS_STREAM_STARTED; | |
1192 | dev_dbg(isp->dev, "stream[%d] started.\n", i); | |
1193 | } | |
1194 | } | |
1195 | } | |
1196 | ||
1197 | return 0; | |
1198 | ||
1199 | start_err: | |
1200 | __destroy_streams(asd, true); | |
1201 | stream_err: | |
1202 | __destroy_pipes(asd, true); | |
1203 | ||
1204 | /* css 2.0 API limitation: ia_css_stop_sp() could be only called after | |
1205 | * destroy all pipes | |
1206 | */ | |
1207 | /* | |
1208 | * SP can not be stop if other streams are in use | |
1209 | */ | |
1210 | if ((atomisp_streaming_count(isp) == 0) && sp_is_started) | |
1211 | ia_css_stop_sp(); | |
1212 | ||
1213 | return ret; | |
1214 | } | |
1215 | ||
1216 | void atomisp_css_update_isp_params(struct atomisp_sub_device *asd) | |
1217 | { | |
1218 | /* | |
1219 | * FIXME! | |
1220 | * for ISP2401 new input system, this api is under development. | |
1221 | * Calling it would cause kernel panic. | |
1222 | * | |
1223 | * VIED BZ: 1458 | |
1224 | * | |
1225 | * Check if it is Cherry Trail and also new input system | |
1226 | */ | |
1227 | if (asd->copy_mode) { | |
1228 | dev_warn(asd->isp->dev, | |
1229 | "%s: ia_css_stream_set_isp_config() not supported in copy mode!.\n", | |
eaa399eb | 1230 | __func__); |
ad85094b MCC |
1231 | return; |
1232 | } | |
1233 | ||
1234 | ia_css_stream_set_isp_config( | |
eaa399eb MCC |
1235 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
1236 | &asd->params.config); | |
1a16d545 | 1237 | memset(&asd->params.config, 0, sizeof(asd->params.config)); |
ad85094b MCC |
1238 | } |
1239 | ||
ad85094b | 1240 | void atomisp_css_update_isp_params_on_pipe(struct atomisp_sub_device *asd, |
eaa399eb | 1241 | struct ia_css_pipe *pipe) |
ad85094b | 1242 | { |
41022d35 | 1243 | int ret; |
ad85094b MCC |
1244 | |
1245 | if (!pipe) { | |
1246 | atomisp_css_update_isp_params(asd); | |
1247 | return; | |
1248 | } | |
1249 | ||
eaa399eb MCC |
1250 | dev_dbg(asd->isp->dev, |
1251 | "%s: apply parameter for ia_css_frame %p with isp_config_id %d on pipe %p.\n", | |
ad85094b MCC |
1252 | __func__, asd->params.config.output_frame, |
1253 | asd->params.config.isp_config_id, pipe); | |
1254 | ||
1255 | ret = ia_css_stream_set_isp_config_on_pipe( | |
eaa399eb MCC |
1256 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
1257 | &asd->params.config, pipe); | |
41022d35 | 1258 | if (ret) |
ad85094b | 1259 | dev_warn(asd->isp->dev, "%s: ia_css_stream_set_isp_config_on_pipe failed %d\n", |
eaa399eb | 1260 | __func__, ret); |
1a16d545 | 1261 | memset(&asd->params.config, 0, sizeof(asd->params.config)); |
ad85094b MCC |
1262 | } |
1263 | ||
1264 | int atomisp_css_queue_buffer(struct atomisp_sub_device *asd, | |
1265 | enum atomisp_input_stream_id stream_id, | |
c01d5546 MCC |
1266 | enum ia_css_pipe_id pipe_id, |
1267 | enum ia_css_buffer_type buf_type, | |
ad85094b MCC |
1268 | struct atomisp_css_buffer *isp_css_buffer) |
1269 | { | |
1270 | if (ia_css_pipe_enqueue_buffer( | |
1271 | asd->stream_env[stream_id].pipes[pipe_id], | |
eaa399eb | 1272 | &isp_css_buffer->css_buffer) |
41022d35 | 1273 | != 0) |
ad85094b MCC |
1274 | return -EINVAL; |
1275 | ||
1276 | return 0; | |
1277 | } | |
1278 | ||
1279 | int atomisp_css_dequeue_buffer(struct atomisp_sub_device *asd, | |
eaa399eb | 1280 | enum atomisp_input_stream_id stream_id, |
c01d5546 MCC |
1281 | enum ia_css_pipe_id pipe_id, |
1282 | enum ia_css_buffer_type buf_type, | |
eaa399eb | 1283 | struct atomisp_css_buffer *isp_css_buffer) |
ad85094b MCC |
1284 | { |
1285 | struct atomisp_device *isp = asd->isp; | |
41022d35 | 1286 | int err; |
ad85094b MCC |
1287 | |
1288 | err = ia_css_pipe_dequeue_buffer( | |
eaa399eb MCC |
1289 | asd->stream_env[stream_id].pipes[pipe_id], |
1290 | &isp_css_buffer->css_buffer); | |
41022d35 | 1291 | if (err) { |
ad85094b MCC |
1292 | dev_err(isp->dev, |
1293 | "ia_css_pipe_dequeue_buffer failed: 0x%x\n", err); | |
1294 | return -EINVAL; | |
1295 | } | |
1296 | ||
1297 | return 0; | |
1298 | } | |
1299 | ||
1300 | int atomisp_css_allocate_stat_buffers(struct atomisp_sub_device *asd, | |
bdfe0beb | 1301 | u16 stream_id, |
ad85094b MCC |
1302 | struct atomisp_s3a_buf *s3a_buf, |
1303 | struct atomisp_dis_buf *dis_buf, | |
1304 | struct atomisp_metadata_buf *md_buf) | |
1305 | { | |
1306 | struct atomisp_device *isp = asd->isp; | |
c01d5546 | 1307 | struct ia_css_dvs_grid_info *dvs_grid_info = |
eaa399eb | 1308 | atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); |
ad85094b MCC |
1309 | |
1310 | if (s3a_buf && asd->params.curr_grid_info.s3a_grid.enable) { | |
1311 | void *s3a_ptr; | |
1312 | ||
1313 | s3a_buf->s3a_data = ia_css_isp_3a_statistics_allocate( | |
eaa399eb | 1314 | &asd->params.curr_grid_info.s3a_grid); |
ad85094b MCC |
1315 | if (!s3a_buf->s3a_data) { |
1316 | dev_err(isp->dev, "3a buf allocation failed.\n"); | |
1317 | return -EINVAL; | |
1318 | } | |
1319 | ||
1320 | s3a_ptr = hmm_vmap(s3a_buf->s3a_data->data_ptr, true); | |
1321 | s3a_buf->s3a_map = ia_css_isp_3a_statistics_map_allocate( | |
eaa399eb | 1322 | s3a_buf->s3a_data, s3a_ptr); |
ad85094b MCC |
1323 | } |
1324 | ||
1325 | if (dis_buf && dvs_grid_info && dvs_grid_info->enable) { | |
1326 | void *dvs_ptr; | |
1327 | ||
1328 | dis_buf->dis_data = ia_css_isp_dvs2_statistics_allocate( | |
1329 | dvs_grid_info); | |
1330 | if (!dis_buf->dis_data) { | |
1331 | dev_err(isp->dev, "dvs buf allocation failed.\n"); | |
1332 | if (s3a_buf) | |
1333 | ia_css_isp_3a_statistics_free(s3a_buf->s3a_data); | |
1334 | return -EINVAL; | |
1335 | } | |
1336 | ||
1337 | dvs_ptr = hmm_vmap(dis_buf->dis_data->data_ptr, true); | |
1338 | dis_buf->dvs_map = ia_css_isp_dvs_statistics_map_allocate( | |
eaa399eb | 1339 | dis_buf->dis_data, dvs_ptr); |
ad85094b MCC |
1340 | } |
1341 | ||
1342 | if (asd->stream_env[stream_id].stream_info. | |
eaa399eb | 1343 | metadata_info.size && md_buf) { |
ad85094b | 1344 | md_buf->metadata = ia_css_metadata_allocate( |
eaa399eb | 1345 | &asd->stream_env[stream_id].stream_info.metadata_info); |
ad85094b MCC |
1346 | if (!md_buf->metadata) { |
1347 | if (s3a_buf) | |
1348 | ia_css_isp_3a_statistics_free(s3a_buf->s3a_data); | |
1349 | if (dis_buf) | |
1350 | ia_css_isp_dvs2_statistics_free(dis_buf->dis_data); | |
1351 | dev_err(isp->dev, "metadata buf allocation failed.\n"); | |
1352 | return -EINVAL; | |
1353 | } | |
1354 | md_buf->md_vptr = hmm_vmap(md_buf->metadata->address, false); | |
1355 | } | |
1356 | ||
1357 | return 0; | |
1358 | } | |
1359 | ||
1360 | void atomisp_css_free_3a_buffer(struct atomisp_s3a_buf *s3a_buf) | |
1361 | { | |
1362 | if (s3a_buf->s3a_data) | |
1363 | hmm_vunmap(s3a_buf->s3a_data->data_ptr); | |
1364 | ||
1365 | ia_css_isp_3a_statistics_map_free(s3a_buf->s3a_map); | |
1366 | s3a_buf->s3a_map = NULL; | |
1367 | ia_css_isp_3a_statistics_free(s3a_buf->s3a_data); | |
1368 | } | |
1369 | ||
1370 | void atomisp_css_free_dis_buffer(struct atomisp_dis_buf *dis_buf) | |
1371 | { | |
1372 | if (dis_buf->dis_data) | |
1373 | hmm_vunmap(dis_buf->dis_data->data_ptr); | |
1374 | ||
1375 | ia_css_isp_dvs_statistics_map_free(dis_buf->dvs_map); | |
1376 | dis_buf->dvs_map = NULL; | |
1377 | ia_css_isp_dvs2_statistics_free(dis_buf->dis_data); | |
1378 | } | |
1379 | ||
1380 | void atomisp_css_free_metadata_buffer(struct atomisp_metadata_buf *metadata_buf) | |
1381 | { | |
1382 | if (metadata_buf->md_vptr) { | |
1383 | hmm_vunmap(metadata_buf->metadata->address); | |
1384 | metadata_buf->md_vptr = NULL; | |
1385 | } | |
1386 | ia_css_metadata_free(metadata_buf->metadata); | |
1387 | } | |
1388 | ||
1389 | void atomisp_css_free_stat_buffers(struct atomisp_sub_device *asd) | |
1390 | { | |
1391 | struct atomisp_s3a_buf *s3a_buf, *_s3a_buf; | |
1392 | struct atomisp_dis_buf *dis_buf, *_dis_buf; | |
1393 | struct atomisp_metadata_buf *md_buf, *_md_buf; | |
c01d5546 | 1394 | struct ia_css_dvs_grid_info *dvs_grid_info = |
eaa399eb | 1395 | atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); |
ad85094b MCC |
1396 | unsigned int i; |
1397 | ||
1398 | /* 3A statistics use vmalloc, DIS use kmalloc */ | |
1399 | if (dvs_grid_info && dvs_grid_info->enable) { | |
1400 | ia_css_dvs2_coefficients_free(asd->params.css_param.dvs2_coeff); | |
1401 | ia_css_dvs2_statistics_free(asd->params.dvs_stat); | |
1402 | asd->params.css_param.dvs2_coeff = NULL; | |
1403 | asd->params.dvs_stat = NULL; | |
1404 | asd->params.dvs_hor_proj_bytes = 0; | |
1405 | asd->params.dvs_ver_proj_bytes = 0; | |
1406 | asd->params.dvs_hor_coef_bytes = 0; | |
1407 | asd->params.dvs_ver_coef_bytes = 0; | |
1408 | asd->params.dis_proj_data_valid = false; | |
1409 | list_for_each_entry_safe(dis_buf, _dis_buf, | |
eaa399eb | 1410 | &asd->dis_stats, list) { |
ad85094b MCC |
1411 | atomisp_css_free_dis_buffer(dis_buf); |
1412 | list_del(&dis_buf->list); | |
1413 | kfree(dis_buf); | |
1414 | } | |
1415 | list_for_each_entry_safe(dis_buf, _dis_buf, | |
eaa399eb | 1416 | &asd->dis_stats_in_css, list) { |
ad85094b MCC |
1417 | atomisp_css_free_dis_buffer(dis_buf); |
1418 | list_del(&dis_buf->list); | |
1419 | kfree(dis_buf); | |
1420 | } | |
1421 | } | |
1422 | if (asd->params.curr_grid_info.s3a_grid.enable) { | |
1423 | ia_css_3a_statistics_free(asd->params.s3a_user_stat); | |
1424 | asd->params.s3a_user_stat = NULL; | |
1425 | asd->params.s3a_output_bytes = 0; | |
1426 | list_for_each_entry_safe(s3a_buf, _s3a_buf, | |
eaa399eb | 1427 | &asd->s3a_stats, list) { |
ad85094b MCC |
1428 | atomisp_css_free_3a_buffer(s3a_buf); |
1429 | list_del(&s3a_buf->list); | |
1430 | kfree(s3a_buf); | |
1431 | } | |
1432 | list_for_each_entry_safe(s3a_buf, _s3a_buf, | |
eaa399eb | 1433 | &asd->s3a_stats_in_css, list) { |
ad85094b MCC |
1434 | atomisp_css_free_3a_buffer(s3a_buf); |
1435 | list_del(&s3a_buf->list); | |
1436 | kfree(s3a_buf); | |
1437 | } | |
1438 | list_for_each_entry_safe(s3a_buf, _s3a_buf, | |
eaa399eb | 1439 | &asd->s3a_stats_ready, list) { |
ad85094b MCC |
1440 | atomisp_css_free_3a_buffer(s3a_buf); |
1441 | list_del(&s3a_buf->list); | |
1442 | kfree(s3a_buf); | |
1443 | } | |
1444 | } | |
1445 | ||
1446 | if (asd->params.css_param.dvs_6axis) { | |
1447 | ia_css_dvs2_6axis_config_free(asd->params.css_param.dvs_6axis); | |
1448 | asd->params.css_param.dvs_6axis = NULL; | |
1449 | } | |
1450 | ||
1451 | for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { | |
1452 | list_for_each_entry_safe(md_buf, _md_buf, | |
eaa399eb | 1453 | &asd->metadata[i], list) { |
ad85094b MCC |
1454 | atomisp_css_free_metadata_buffer(md_buf); |
1455 | list_del(&md_buf->list); | |
1456 | kfree(md_buf); | |
1457 | } | |
1458 | list_for_each_entry_safe(md_buf, _md_buf, | |
eaa399eb | 1459 | &asd->metadata_in_css[i], list) { |
ad85094b MCC |
1460 | atomisp_css_free_metadata_buffer(md_buf); |
1461 | list_del(&md_buf->list); | |
1462 | kfree(md_buf); | |
1463 | } | |
1464 | list_for_each_entry_safe(md_buf, _md_buf, | |
eaa399eb | 1465 | &asd->metadata_ready[i], list) { |
ad85094b MCC |
1466 | atomisp_css_free_metadata_buffer(md_buf); |
1467 | list_del(&md_buf->list); | |
1468 | kfree(md_buf); | |
1469 | } | |
1470 | } | |
1471 | asd->params.metadata_width_size = 0; | |
1472 | atomisp_free_metadata_output_buf(asd); | |
1473 | } | |
1474 | ||
1475 | int atomisp_css_get_grid_info(struct atomisp_sub_device *asd, | |
c01d5546 | 1476 | enum ia_css_pipe_id pipe_id, |
eaa399eb | 1477 | int source_pad) |
ad85094b MCC |
1478 | { |
1479 | struct ia_css_pipe_info p_info; | |
1480 | struct ia_css_grid_info old_info; | |
1481 | struct atomisp_device *isp = asd->isp; | |
1482 | int stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); | |
1483 | int md_width = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. | |
eaa399eb | 1484 | stream_config.metadata_config.resolution.width; |
ad85094b MCC |
1485 | |
1486 | memset(&p_info, 0, sizeof(struct ia_css_pipe_info)); | |
1487 | memset(&old_info, 0, sizeof(struct ia_css_grid_info)); | |
1488 | ||
1489 | if (ia_css_pipe_get_info( | |
1490 | asd->stream_env[stream_index].pipes[pipe_id], | |
41022d35 | 1491 | &p_info) != 0) { |
ad85094b MCC |
1492 | dev_err(isp->dev, "ia_css_pipe_get_info failed\n"); |
1493 | return -EINVAL; | |
1494 | } | |
1495 | ||
1496 | memcpy(&old_info, &asd->params.curr_grid_info, | |
eaa399eb | 1497 | sizeof(struct ia_css_grid_info)); |
ad85094b | 1498 | memcpy(&asd->params.curr_grid_info, &p_info.grid_info, |
eaa399eb | 1499 | sizeof(struct ia_css_grid_info)); |
ad85094b MCC |
1500 | /* |
1501 | * Record which css pipe enables s3a_grid. | |
1502 | * Currently would have one css pipe that need it | |
1503 | */ | |
1504 | if (asd->params.curr_grid_info.s3a_grid.enable) { | |
c01d5546 | 1505 | if (asd->params.s3a_enabled_pipe != IA_CSS_PIPE_ID_NUM) |
ad85094b | 1506 | dev_dbg(isp->dev, "css pipe %d enabled s3a grid replaced by: %d.\n", |
eaa399eb | 1507 | asd->params.s3a_enabled_pipe, pipe_id); |
ad85094b MCC |
1508 | asd->params.s3a_enabled_pipe = pipe_id; |
1509 | } | |
1510 | ||
1511 | /* If the grid info has not changed and the buffers for 3A and | |
1512 | * DIS statistics buffers are allocated or buffer size would be zero | |
1513 | * then no need to do anything. */ | |
1514 | if (((!memcmp(&old_info, &asd->params.curr_grid_info, sizeof(old_info)) | |
eaa399eb MCC |
1515 | && asd->params.s3a_user_stat && asd->params.dvs_stat) |
1516 | || asd->params.curr_grid_info.s3a_grid.width == 0 | |
1517 | || asd->params.curr_grid_info.s3a_grid.height == 0) | |
ad85094b MCC |
1518 | && asd->params.metadata_width_size == md_width) { |
1519 | dev_dbg(isp->dev, | |
bdfe0beb | 1520 | "grid info change escape. memcmp=%d, s3a_user_stat=%d,dvs_stat=%d, s3a.width=%d, s3a.height=%d, metadata width =%d\n", |
ad85094b | 1521 | !memcmp(&old_info, &asd->params.curr_grid_info, |
eaa399eb MCC |
1522 | sizeof(old_info)), |
1523 | !!asd->params.s3a_user_stat, !!asd->params.dvs_stat, | |
1524 | asd->params.curr_grid_info.s3a_grid.width, | |
1525 | asd->params.curr_grid_info.s3a_grid.height, | |
1526 | asd->params.metadata_width_size); | |
ad85094b MCC |
1527 | return -EINVAL; |
1528 | } | |
1529 | asd->params.metadata_width_size = md_width; | |
1530 | ||
1531 | return 0; | |
1532 | } | |
1533 | ||
1534 | int atomisp_alloc_3a_output_buf(struct atomisp_sub_device *asd) | |
1535 | { | |
1536 | if (!asd->params.curr_grid_info.s3a_grid.width || | |
eaa399eb | 1537 | !asd->params.curr_grid_info.s3a_grid.height) |
ad85094b MCC |
1538 | return 0; |
1539 | ||
1540 | asd->params.s3a_user_stat = ia_css_3a_statistics_allocate( | |
eaa399eb | 1541 | &asd->params.curr_grid_info.s3a_grid); |
ad85094b MCC |
1542 | if (!asd->params.s3a_user_stat) |
1543 | return -ENOMEM; | |
1544 | /* 3A statistics. These can be big, so we use vmalloc. */ | |
1545 | asd->params.s3a_output_bytes = | |
1546 | asd->params.curr_grid_info.s3a_grid.width * | |
1547 | asd->params.curr_grid_info.s3a_grid.height * | |
1548 | sizeof(*asd->params.s3a_user_stat->data); | |
1549 | ||
1550 | return 0; | |
1551 | } | |
1552 | ||
1553 | int atomisp_alloc_dis_coef_buf(struct atomisp_sub_device *asd) | |
1554 | { | |
c01d5546 | 1555 | struct ia_css_dvs_grid_info *dvs_grid = |
eaa399eb | 1556 | atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); |
ad85094b MCC |
1557 | |
1558 | if (!dvs_grid) | |
1559 | return 0; | |
1560 | ||
1561 | if (!dvs_grid->enable) { | |
1562 | dev_dbg(asd->isp->dev, "%s: dvs_grid not enabled.\n", __func__); | |
1563 | return 0; | |
1564 | } | |
1565 | ||
1566 | /* DIS coefficients. */ | |
1567 | asd->params.css_param.dvs2_coeff = ia_css_dvs2_coefficients_allocate( | |
eaa399eb | 1568 | dvs_grid); |
ad85094b MCC |
1569 | if (!asd->params.css_param.dvs2_coeff) |
1570 | return -ENOMEM; | |
1571 | ||
1572 | asd->params.dvs_hor_coef_bytes = dvs_grid->num_hor_coefs * | |
eaa399eb | 1573 | sizeof(*asd->params.css_param.dvs2_coeff->hor_coefs.odd_real); |
ad85094b MCC |
1574 | |
1575 | asd->params.dvs_ver_coef_bytes = dvs_grid->num_ver_coefs * | |
eaa399eb | 1576 | sizeof(*asd->params.css_param.dvs2_coeff->ver_coefs.odd_real); |
ad85094b MCC |
1577 | |
1578 | /* DIS projections. */ | |
1579 | asd->params.dis_proj_data_valid = false; | |
1580 | asd->params.dvs_stat = ia_css_dvs2_statistics_allocate(dvs_grid); | |
1581 | if (!asd->params.dvs_stat) | |
1582 | return -ENOMEM; | |
1583 | ||
1584 | asd->params.dvs_hor_proj_bytes = | |
eaa399eb MCC |
1585 | dvs_grid->aligned_height * dvs_grid->aligned_width * |
1586 | sizeof(*asd->params.dvs_stat->hor_prod.odd_real); | |
ad85094b MCC |
1587 | |
1588 | asd->params.dvs_ver_proj_bytes = | |
eaa399eb MCC |
1589 | dvs_grid->aligned_height * dvs_grid->aligned_width * |
1590 | sizeof(*asd->params.dvs_stat->ver_prod.odd_real); | |
ad85094b MCC |
1591 | |
1592 | return 0; | |
1593 | } | |
1594 | ||
1595 | int atomisp_alloc_metadata_output_buf(struct atomisp_sub_device *asd) | |
1596 | { | |
1597 | int i; | |
1598 | ||
1599 | /* We allocate the cpu-side buffer used for communication with user | |
1600 | * space */ | |
1601 | for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { | |
1602 | asd->params.metadata_user[i] = kvmalloc( | |
eaa399eb MCC |
1603 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. |
1604 | stream_info.metadata_info.size, GFP_KERNEL); | |
ad85094b MCC |
1605 | if (!asd->params.metadata_user[i]) { |
1606 | while (--i >= 0) { | |
1607 | kvfree(asd->params.metadata_user[i]); | |
1608 | asd->params.metadata_user[i] = NULL; | |
1609 | } | |
1610 | return -ENOMEM; | |
1611 | } | |
1612 | } | |
1613 | ||
1614 | return 0; | |
1615 | } | |
1616 | ||
1617 | void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd) | |
1618 | { | |
1619 | unsigned int i; | |
1620 | ||
1621 | for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { | |
1622 | if (asd->params.metadata_user[i]) { | |
1623 | kvfree(asd->params.metadata_user[i]); | |
1624 | asd->params.metadata_user[i] = NULL; | |
1625 | } | |
1626 | } | |
1627 | } | |
1628 | ||
1629 | void atomisp_css_get_dis_statistics(struct atomisp_sub_device *asd, | |
1630 | struct atomisp_css_buffer *isp_css_buffer, | |
1631 | struct ia_css_isp_dvs_statistics_map *dvs_map) | |
1632 | { | |
1633 | if (asd->params.dvs_stat) { | |
1634 | if (dvs_map) | |
1635 | ia_css_translate_dvs2_statistics( | |
eaa399eb | 1636 | asd->params.dvs_stat, dvs_map); |
ad85094b MCC |
1637 | else |
1638 | ia_css_get_dvs2_statistics(asd->params.dvs_stat, | |
eaa399eb | 1639 | isp_css_buffer->css_buffer.data.stats_dvs); |
ad85094b MCC |
1640 | } |
1641 | } | |
1642 | ||
1643 | int atomisp_css_dequeue_event(struct atomisp_css_event *current_event) | |
1644 | { | |
41022d35 | 1645 | if (ia_css_dequeue_event(¤t_event->event)) |
ad85094b MCC |
1646 | return -EINVAL; |
1647 | ||
1648 | return 0; | |
1649 | } | |
1650 | ||
1651 | void atomisp_css_temp_pipe_to_pipe_id(struct atomisp_sub_device *asd, | |
eaa399eb | 1652 | struct atomisp_css_event *current_event) |
ad85094b MCC |
1653 | { |
1654 | /* | |
1655 | * FIXME! | |
1656 | * Pipe ID reported in CSS event is not correct for new system's | |
1657 | * copy pipe. | |
1658 | * VIED BZ: 1463 | |
1659 | */ | |
1660 | ia_css_temp_pipe_to_pipe_id(current_event->event.pipe, | |
1661 | ¤t_event->pipe); | |
1662 | if (asd && asd->copy_mode && | |
1663 | current_event->pipe == IA_CSS_PIPE_ID_CAPTURE) | |
1664 | current_event->pipe = IA_CSS_PIPE_ID_COPY; | |
1665 | } | |
1666 | ||
1667 | int atomisp_css_isys_set_resolution(struct atomisp_sub_device *asd, | |
1668 | enum atomisp_input_stream_id stream_id, | |
1669 | struct v4l2_mbus_framefmt *ffmt, | |
1670 | int isys_stream) | |
1671 | { | |
1672 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1673 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1674 | |
1675 | if (isys_stream >= IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH) | |
1676 | return -EINVAL; | |
1677 | ||
1678 | s_config->isys_config[isys_stream].input_res.width = ffmt->width; | |
1679 | s_config->isys_config[isys_stream].input_res.height = ffmt->height; | |
1680 | return 0; | |
1681 | } | |
1682 | ||
1683 | int atomisp_css_input_set_resolution(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1684 | enum atomisp_input_stream_id stream_id, |
1685 | struct v4l2_mbus_framefmt *ffmt) | |
ad85094b MCC |
1686 | { |
1687 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1688 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1689 | |
1690 | s_config->input_config.input_res.width = ffmt->width; | |
1691 | s_config->input_config.input_res.height = ffmt->height; | |
1692 | return 0; | |
1693 | } | |
1694 | ||
1695 | void atomisp_css_input_set_binning_factor(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1696 | enum atomisp_input_stream_id stream_id, |
1697 | unsigned int bin_factor) | |
ad85094b MCC |
1698 | { |
1699 | asd->stream_env[stream_id] | |
eaa399eb | 1700 | .stream_config.sensor_binning_factor = bin_factor; |
ad85094b MCC |
1701 | } |
1702 | ||
1703 | void atomisp_css_input_set_bayer_order(struct atomisp_sub_device *asd, | |
eaa399eb | 1704 | enum atomisp_input_stream_id stream_id, |
c01d5546 | 1705 | enum ia_css_bayer_order bayer_order) |
ad85094b MCC |
1706 | { |
1707 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1708 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1709 | s_config->input_config.bayer_order = bayer_order; |
1710 | } | |
1711 | ||
1712 | void atomisp_css_isys_set_link(struct atomisp_sub_device *asd, | |
1713 | enum atomisp_input_stream_id stream_id, | |
1714 | int link, | |
1715 | int isys_stream) | |
1716 | { | |
1717 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1718 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1719 | |
1720 | s_config->isys_config[isys_stream].linked_isys_stream_id = link; | |
1721 | } | |
1722 | ||
1723 | void atomisp_css_isys_set_valid(struct atomisp_sub_device *asd, | |
1724 | enum atomisp_input_stream_id stream_id, | |
1725 | bool valid, | |
1726 | int isys_stream) | |
1727 | { | |
1728 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1729 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1730 | |
1731 | s_config->isys_config[isys_stream].valid = valid; | |
1732 | } | |
1733 | ||
1734 | void atomisp_css_isys_set_format(struct atomisp_sub_device *asd, | |
1735 | enum atomisp_input_stream_id stream_id, | |
1736 | enum atomisp_input_format format, | |
1737 | int isys_stream) | |
1738 | { | |
ad85094b | 1739 | struct ia_css_stream_config *s_config = |
eaa399eb | 1740 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1741 | |
1742 | s_config->isys_config[isys_stream].format = format; | |
1743 | } | |
1744 | ||
1745 | void atomisp_css_input_set_format(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
1746 | enum atomisp_input_stream_id stream_id, |
1747 | enum atomisp_input_format format) | |
ad85094b | 1748 | { |
ad85094b | 1749 | struct ia_css_stream_config *s_config = |
eaa399eb | 1750 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1751 | |
1752 | s_config->input_config.format = format; | |
1753 | } | |
1754 | ||
1755 | int atomisp_css_set_default_isys_config(struct atomisp_sub_device *asd, | |
1756 | enum atomisp_input_stream_id stream_id, | |
1757 | struct v4l2_mbus_framefmt *ffmt) | |
1758 | { | |
1759 | int i; | |
1760 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1761 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1762 | /* |
1763 | * Set all isys configs to not valid. | |
1764 | * Currently we support only one stream per channel | |
1765 | */ | |
1766 | for (i = IA_CSS_STREAM_ISYS_STREAM_0; | |
1767 | i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) | |
1768 | s_config->isys_config[i].valid = false; | |
1769 | ||
1770 | atomisp_css_isys_set_resolution(asd, stream_id, ffmt, | |
1771 | IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); | |
1772 | atomisp_css_isys_set_format(asd, stream_id, | |
1773 | s_config->input_config.format, | |
1774 | IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); | |
1775 | atomisp_css_isys_set_link(asd, stream_id, NO_LINK, | |
1776 | IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); | |
1777 | atomisp_css_isys_set_valid(asd, stream_id, true, | |
1778 | IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); | |
1779 | ||
1780 | return 0; | |
1781 | } | |
1782 | ||
1783 | int atomisp_css_isys_two_stream_cfg(struct atomisp_sub_device *asd, | |
1784 | enum atomisp_input_stream_id stream_id, | |
1785 | enum atomisp_input_format input_format) | |
1786 | { | |
1787 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1788 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1789 | |
1790 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width = | |
eaa399eb | 1791 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width; |
ad85094b MCC |
1792 | |
1793 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height = | |
eaa399eb | 1794 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height / 2; |
ad85094b MCC |
1795 | |
1796 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id | |
eaa399eb | 1797 | = IA_CSS_STREAM_ISYS_STREAM_0; |
ad85094b | 1798 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format = |
eaa399eb | 1799 | ATOMISP_INPUT_FORMAT_USER_DEF1; |
ad85094b | 1800 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format = |
eaa399eb | 1801 | ATOMISP_INPUT_FORMAT_USER_DEF2; |
ad85094b MCC |
1802 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true; |
1803 | return 0; | |
1804 | } | |
1805 | ||
1806 | void atomisp_css_isys_two_stream_cfg_update_stream1( | |
eaa399eb MCC |
1807 | struct atomisp_sub_device *asd, |
1808 | enum atomisp_input_stream_id stream_id, | |
1809 | enum atomisp_input_format input_format, | |
1810 | unsigned int width, unsigned int height) | |
ad85094b MCC |
1811 | { |
1812 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1813 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1814 | |
1815 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width = | |
eaa399eb | 1816 | width; |
ad85094b | 1817 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height = |
eaa399eb | 1818 | height; |
ad85094b | 1819 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format = |
eaa399eb | 1820 | input_format; |
ad85094b MCC |
1821 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].valid = true; |
1822 | } | |
1823 | ||
1824 | void atomisp_css_isys_two_stream_cfg_update_stream2( | |
eaa399eb MCC |
1825 | struct atomisp_sub_device *asd, |
1826 | enum atomisp_input_stream_id stream_id, | |
1827 | enum atomisp_input_format input_format, | |
1828 | unsigned int width, unsigned int height) | |
ad85094b MCC |
1829 | { |
1830 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1831 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1832 | |
1833 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width = | |
eaa399eb | 1834 | width; |
ad85094b | 1835 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height = |
eaa399eb | 1836 | height; |
ad85094b | 1837 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id |
eaa399eb | 1838 | = IA_CSS_STREAM_ISYS_STREAM_0; |
ad85094b | 1839 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format = |
eaa399eb | 1840 | input_format; |
ad85094b MCC |
1841 | s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true; |
1842 | } | |
1843 | ||
1844 | int atomisp_css_input_set_effective_resolution( | |
eaa399eb MCC |
1845 | struct atomisp_sub_device *asd, |
1846 | enum atomisp_input_stream_id stream_id, | |
1847 | unsigned int width, unsigned int height) | |
ad85094b MCC |
1848 | { |
1849 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1850 | &asd->stream_env[stream_id].stream_config; |
ad85094b MCC |
1851 | s_config->input_config.effective_res.width = width; |
1852 | s_config->input_config.effective_res.height = height; | |
1853 | return 0; | |
1854 | } | |
1855 | ||
1856 | void atomisp_css_video_set_dis_envelope(struct atomisp_sub_device *asd, | |
1857 | unsigned int dvs_w, unsigned int dvs_h) | |
1858 | { | |
1859 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 1860 | .pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.width = dvs_w; |
ad85094b | 1861 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] |
eaa399eb | 1862 | .pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.height = dvs_h; |
ad85094b MCC |
1863 | } |
1864 | ||
1865 | void atomisp_css_input_set_two_pixels_per_clock( | |
eaa399eb MCC |
1866 | struct atomisp_sub_device *asd, |
1867 | bool two_ppc) | |
ad85094b MCC |
1868 | { |
1869 | int i; | |
1870 | ||
1871 | if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 1872 | .stream_config.pixels_per_clock == (two_ppc ? 2 : 1)) |
ad85094b MCC |
1873 | return; |
1874 | ||
1875 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 1876 | .stream_config.pixels_per_clock = (two_ppc ? 2 : 1); |
ad85094b MCC |
1877 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) |
1878 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
1879 | .update_pipe[i] = true; | |
1880 | } | |
1881 | ||
1882 | void atomisp_css_enable_raw_binning(struct atomisp_sub_device *asd, | |
eaa399eb | 1883 | bool enable) |
ad85094b MCC |
1884 | { |
1885 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 1886 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
1887 | unsigned int pipe; |
1888 | ||
1889 | if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) | |
1890 | pipe = IA_CSS_PIPE_ID_VIDEO; | |
1891 | else | |
1892 | pipe = IA_CSS_PIPE_ID_PREVIEW; | |
1893 | ||
1894 | stream_env->pipe_extra_configs[pipe].enable_raw_binning = enable; | |
1895 | stream_env->update_pipe[pipe] = true; | |
1896 | if (enable) | |
1897 | stream_env->pipe_configs[pipe].output_info[0].padded_width = | |
eaa399eb | 1898 | stream_env->stream_config.input_config.effective_res.width; |
ad85094b MCC |
1899 | } |
1900 | ||
1901 | void atomisp_css_enable_dz(struct atomisp_sub_device *asd, bool enable) | |
1902 | { | |
1903 | int i; | |
1904 | ||
1905 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) | |
1906 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 1907 | .pipe_configs[i].enable_dz = enable; |
ad85094b MCC |
1908 | } |
1909 | ||
1910 | void atomisp_css_capture_set_mode(struct atomisp_sub_device *asd, | |
c01d5546 | 1911 | enum ia_css_capture_mode mode) |
ad85094b MCC |
1912 | { |
1913 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 1914 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
1915 | |
1916 | if (stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE] | |
eaa399eb | 1917 | .default_capture_config.mode == mode) |
ad85094b MCC |
1918 | return; |
1919 | ||
1920 | stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]. | |
eaa399eb | 1921 | default_capture_config.mode = mode; |
ad85094b MCC |
1922 | stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true; |
1923 | } | |
1924 | ||
1925 | void atomisp_css_input_set_mode(struct atomisp_sub_device *asd, | |
c01d5546 | 1926 | enum ia_css_input_mode mode) |
ad85094b MCC |
1927 | { |
1928 | int i; | |
1929 | struct atomisp_device *isp = asd->isp; | |
1930 | unsigned int size_mem_words; | |
1931 | ||
1932 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) | |
1933 | asd->stream_env[i].stream_config.mode = mode; | |
1934 | ||
1935 | if (isp->inputs[asd->input_curr].type == TEST_PATTERN) { | |
1936 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1937 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_config; |
ad85094b MCC |
1938 | s_config->mode = IA_CSS_INPUT_MODE_TPG; |
1939 | s_config->source.tpg.mode = IA_CSS_TPG_MODE_CHECKERBOARD; | |
1940 | s_config->source.tpg.x_mask = (1 << 4) - 1; | |
1941 | s_config->source.tpg.x_delta = -2; | |
1942 | s_config->source.tpg.y_mask = (1 << 4) - 1; | |
1943 | s_config->source.tpg.y_delta = 3; | |
1944 | s_config->source.tpg.xy_mask = (1 << 8) - 1; | |
1945 | return; | |
1946 | } | |
1947 | ||
1948 | if (mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) | |
1949 | return; | |
1950 | ||
1951 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
1952 | /* | |
1953 | * TODO: sensor needs to export the embedded_data_size_words | |
1954 | * information to atomisp for each setting. | |
1955 | * Here using a large safe value. | |
1956 | */ | |
1957 | struct ia_css_stream_config *s_config = | |
eaa399eb | 1958 | &asd->stream_env[i].stream_config; |
ad85094b MCC |
1959 | |
1960 | if (s_config->input_config.input_res.width == 0) | |
1961 | continue; | |
1962 | ||
1963 | if (ia_css_mipi_frame_calculate_size( | |
eaa399eb MCC |
1964 | s_config->input_config.input_res.width, |
1965 | s_config->input_config.input_res.height, | |
1966 | s_config->input_config.format, | |
1967 | true, | |
1968 | 0x13000, | |
41022d35 | 1969 | &size_mem_words) != 0) { |
e651cc38 | 1970 | if (IS_MRFD) |
ad85094b MCC |
1971 | size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_2; |
1972 | else | |
1973 | size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_1; | |
1974 | dev_warn(asd->isp->dev, | |
eaa399eb MCC |
1975 | "ia_css_mipi_frame_calculate_size failed,applying pre-defined MIPI buffer size %u.\n", |
1976 | size_mem_words); | |
ad85094b MCC |
1977 | } |
1978 | s_config->mipi_buffer_config.size_mem_words = size_mem_words; | |
1979 | s_config->mipi_buffer_config.nof_mipi_buffers = 2; | |
1980 | } | |
1981 | } | |
1982 | ||
1983 | void atomisp_css_capture_enable_online(struct atomisp_sub_device *asd, | |
eaa399eb | 1984 | unsigned short stream_index, bool enable) |
ad85094b MCC |
1985 | { |
1986 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 1987 | &asd->stream_env[stream_index]; |
ad85094b MCC |
1988 | |
1989 | if (stream_env->stream_config.online == !!enable) | |
1990 | return; | |
1991 | ||
1992 | stream_env->stream_config.online = !!enable; | |
1993 | stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true; | |
1994 | } | |
1995 | ||
1996 | void atomisp_css_preview_enable_online(struct atomisp_sub_device *asd, | |
eaa399eb | 1997 | unsigned short stream_index, bool enable) |
ad85094b MCC |
1998 | { |
1999 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2000 | &asd->stream_env[stream_index]; |
ad85094b MCC |
2001 | int i; |
2002 | ||
2003 | if (stream_env->stream_config.online != !!enable) { | |
2004 | stream_env->stream_config.online = !!enable; | |
2005 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) | |
2006 | stream_env->update_pipe[i] = true; | |
2007 | } | |
2008 | } | |
2009 | ||
2010 | void atomisp_css_video_enable_online(struct atomisp_sub_device *asd, | |
eaa399eb | 2011 | bool enable) |
ad85094b MCC |
2012 | { |
2013 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2014 | &asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO]; |
ad85094b MCC |
2015 | int i; |
2016 | ||
2017 | if (stream_env->stream_config.online != enable) { | |
2018 | stream_env->stream_config.online = enable; | |
2019 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) | |
2020 | stream_env->update_pipe[i] = true; | |
2021 | } | |
2022 | } | |
2023 | ||
2024 | void atomisp_css_enable_continuous(struct atomisp_sub_device *asd, | |
eaa399eb | 2025 | bool enable) |
ad85094b MCC |
2026 | { |
2027 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2028 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
2029 | int i; |
2030 | ||
2031 | /* | |
2032 | * To SOC camera, there is only one YUVPP pipe in any case | |
2033 | * including ZSL/SDV/continuous viewfinder, so always set | |
2034 | * stream_config.continuous to 0. | |
2035 | */ | |
2036 | if (ATOMISP_USE_YUVPP(asd)) { | |
2037 | stream_env->stream_config.continuous = 0; | |
2038 | stream_env->stream_config.online = 1; | |
2039 | return; | |
2040 | } | |
2041 | ||
2042 | if (stream_env->stream_config.continuous != !!enable) { | |
2043 | stream_env->stream_config.continuous = !!enable; | |
2044 | stream_env->stream_config.pack_raw_pixels = true; | |
2045 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) | |
2046 | stream_env->update_pipe[i] = true; | |
2047 | } | |
2048 | } | |
2049 | ||
2050 | void atomisp_css_enable_cvf(struct atomisp_sub_device *asd, | |
eaa399eb | 2051 | bool enable) |
ad85094b MCC |
2052 | { |
2053 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2054 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
2055 | int i; |
2056 | ||
2057 | if (stream_env->stream_config.disable_cont_viewfinder != !enable) { | |
2058 | stream_env->stream_config.disable_cont_viewfinder = !enable; | |
2059 | for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) | |
2060 | stream_env->update_pipe[i] = true; | |
2061 | } | |
2062 | } | |
2063 | ||
2064 | int atomisp_css_input_configure_port( | |
eaa399eb MCC |
2065 | struct atomisp_sub_device *asd, |
2066 | enum mipi_port_id port, | |
2067 | unsigned int num_lanes, | |
2068 | unsigned int timeout, | |
2069 | unsigned int mipi_freq, | |
2070 | enum atomisp_input_format metadata_format, | |
2071 | unsigned int metadata_width, | |
2072 | unsigned int metadata_height) | |
ad85094b MCC |
2073 | { |
2074 | int i; | |
2075 | struct atomisp_stream_env *stream_env; | |
2076 | /* | |
2077 | * Calculate rx_count as follows: | |
2078 | * Input: mipi_freq : CSI-2 bus frequency in Hz | |
2079 | * UI = 1 / (2 * mipi_freq) : period of one bit on the bus | |
2080 | * min = 85e-9 + 6 * UI : Limits for rx_count in seconds | |
2081 | * max = 145e-9 + 10 * UI | |
2082 | * rxcount0 = min / (4 / mipi_freq) : convert seconds to byte clocks | |
2083 | * rxcount = rxcount0 - 2 : adjust for better results | |
2084 | * The formula below is simplified version of the above with | |
2085 | * 10-bit fixed points for improved accuracy. | |
2086 | */ | |
2087 | const unsigned int rxcount = | |
eaa399eb | 2088 | min(((mipi_freq / 46000) - 1280) >> 10, 0xffU) * 0x01010101U; |
ad85094b MCC |
2089 | |
2090 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
2091 | stream_env = &asd->stream_env[i]; | |
2092 | stream_env->stream_config.source.port.port = port; | |
2093 | stream_env->stream_config.source.port.num_lanes = num_lanes; | |
2094 | stream_env->stream_config.source.port.timeout = timeout; | |
2095 | if (mipi_freq) | |
2096 | stream_env->stream_config.source.port.rxcount = rxcount; | |
2097 | stream_env->stream_config. | |
eaa399eb | 2098 | metadata_config.data_type = metadata_format; |
ad85094b | 2099 | stream_env->stream_config. |
eaa399eb | 2100 | metadata_config.resolution.width = metadata_width; |
ad85094b | 2101 | stream_env->stream_config. |
eaa399eb | 2102 | metadata_config.resolution.height = metadata_height; |
ad85094b MCC |
2103 | } |
2104 | ||
2105 | return 0; | |
2106 | } | |
2107 | ||
ad85094b | 2108 | int atomisp_css_stop(struct atomisp_sub_device *asd, |
c01d5546 | 2109 | enum ia_css_pipe_id pipe_id, bool in_reset) |
ad85094b MCC |
2110 | { |
2111 | struct atomisp_device *isp = asd->isp; | |
2112 | struct atomisp_s3a_buf *s3a_buf; | |
2113 | struct atomisp_dis_buf *dis_buf; | |
2114 | struct atomisp_metadata_buf *md_buf; | |
2115 | unsigned long irqflags; | |
2116 | unsigned int i; | |
2117 | ||
2118 | /* if is called in atomisp_reset(), force destroy stream */ | |
2119 | if (__destroy_streams(asd, true)) | |
2120 | dev_err(isp->dev, "destroy stream failed.\n"); | |
2121 | ||
2122 | /* if is called in atomisp_reset(), force destroy all pipes */ | |
2123 | if (__destroy_pipes(asd, true)) | |
2124 | dev_err(isp->dev, "destroy pipes failed.\n"); | |
2125 | ||
2126 | atomisp_init_raw_buffer_bitmap(asd); | |
2127 | ||
2128 | /* | |
2129 | * SP can not be stop if other streams are in use | |
2130 | */ | |
2131 | if (atomisp_streaming_count(isp) == 0) | |
2132 | ia_css_stop_sp(); | |
2133 | ||
2134 | if (!in_reset) { | |
2135 | struct atomisp_stream_env *stream_env; | |
2136 | int i, j; | |
2137 | ||
2138 | for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { | |
2139 | stream_env = &asd->stream_env[i]; | |
2140 | for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) { | |
2141 | ia_css_pipe_config_defaults( | |
eaa399eb | 2142 | &stream_env->pipe_configs[j]); |
ad85094b | 2143 | ia_css_pipe_extra_config_defaults( |
eaa399eb | 2144 | &stream_env->pipe_extra_configs[j]); |
ad85094b MCC |
2145 | } |
2146 | ia_css_stream_config_defaults( | |
eaa399eb | 2147 | &stream_env->stream_config); |
ad85094b | 2148 | } |
1a16d545 | 2149 | memset(&asd->params.config, 0, sizeof(asd->params.config)); |
ad85094b MCC |
2150 | asd->params.css_update_params_needed = false; |
2151 | } | |
2152 | ||
2153 | /* move stats buffers to free queue list */ | |
2154 | while (!list_empty(&asd->s3a_stats_in_css)) { | |
2155 | s3a_buf = list_entry(asd->s3a_stats_in_css.next, | |
eaa399eb | 2156 | struct atomisp_s3a_buf, list); |
ad85094b MCC |
2157 | list_del(&s3a_buf->list); |
2158 | list_add_tail(&s3a_buf->list, &asd->s3a_stats); | |
2159 | } | |
2160 | while (!list_empty(&asd->s3a_stats_ready)) { | |
2161 | s3a_buf = list_entry(asd->s3a_stats_ready.next, | |
eaa399eb | 2162 | struct atomisp_s3a_buf, list); |
ad85094b MCC |
2163 | list_del(&s3a_buf->list); |
2164 | list_add_tail(&s3a_buf->list, &asd->s3a_stats); | |
2165 | } | |
2166 | ||
2167 | spin_lock_irqsave(&asd->dis_stats_lock, irqflags); | |
2168 | while (!list_empty(&asd->dis_stats_in_css)) { | |
2169 | dis_buf = list_entry(asd->dis_stats_in_css.next, | |
eaa399eb | 2170 | struct atomisp_dis_buf, list); |
ad85094b MCC |
2171 | list_del(&dis_buf->list); |
2172 | list_add_tail(&dis_buf->list, &asd->dis_stats); | |
2173 | } | |
2174 | asd->params.dis_proj_data_valid = false; | |
2175 | spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); | |
2176 | ||
2177 | for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { | |
2178 | while (!list_empty(&asd->metadata_in_css[i])) { | |
2179 | md_buf = list_entry(asd->metadata_in_css[i].next, | |
eaa399eb | 2180 | struct atomisp_metadata_buf, list); |
ad85094b MCC |
2181 | list_del(&md_buf->list); |
2182 | list_add_tail(&md_buf->list, &asd->metadata[i]); | |
2183 | } | |
2184 | while (!list_empty(&asd->metadata_ready[i])) { | |
2185 | md_buf = list_entry(asd->metadata_ready[i].next, | |
eaa399eb | 2186 | struct atomisp_metadata_buf, list); |
ad85094b MCC |
2187 | list_del(&md_buf->list); |
2188 | list_add_tail(&md_buf->list, &asd->metadata[i]); | |
2189 | } | |
2190 | } | |
2191 | ||
2192 | atomisp_flush_params_queue(&asd->video_out_capture); | |
2193 | atomisp_flush_params_queue(&asd->video_out_vf); | |
2194 | atomisp_flush_params_queue(&asd->video_out_preview); | |
2195 | atomisp_flush_params_queue(&asd->video_out_video_capture); | |
2196 | atomisp_free_css_parameters(&asd->params.css_param); | |
2197 | memset(&asd->params.css_param, 0, sizeof(asd->params.css_param)); | |
2198 | return 0; | |
2199 | } | |
2200 | ||
2201 | int atomisp_css_continuous_set_num_raw_frames( | |
eaa399eb MCC |
2202 | struct atomisp_sub_device *asd, |
2203 | int num_frames) | |
ad85094b MCC |
2204 | { |
2205 | if (asd->enable_raw_buffer_lock->val) { | |
2206 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
2207 | .stream_config.init_num_cont_raw_buf = | |
eaa399eb | 2208 | ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN; |
ad85094b MCC |
2209 | if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && |
2210 | asd->params.video_dis_en) | |
2211 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
2212 | .stream_config.init_num_cont_raw_buf += | |
eaa399eb | 2213 | ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; |
ad85094b MCC |
2214 | } else { |
2215 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
2216 | .stream_config.init_num_cont_raw_buf = | |
eaa399eb | 2217 | ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES; |
ad85094b MCC |
2218 | } |
2219 | ||
2220 | if (asd->params.video_dis_en) | |
2221 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb MCC |
2222 | .stream_config.init_num_cont_raw_buf += |
2223 | ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; | |
ad85094b MCC |
2224 | |
2225 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 2226 | .stream_config.target_num_cont_raw_buf = num_frames; |
ad85094b MCC |
2227 | return 0; |
2228 | } | |
2229 | ||
ad85094b | 2230 | static enum ia_css_pipe_mode __pipe_id_to_pipe_mode( |
eaa399eb MCC |
2231 | struct atomisp_sub_device *asd, |
2232 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
2233 | { |
2234 | struct atomisp_device *isp = asd->isp; | |
2235 | struct camera_mipi_info *mipi_info = atomisp_to_sensor_mipi_info( | |
eaa399eb | 2236 | isp->inputs[asd->input_curr].camera); |
ad85094b MCC |
2237 | |
2238 | switch (pipe_id) { | |
2239 | case IA_CSS_PIPE_ID_COPY: | |
2240 | /* Currently only YUVPP mode supports YUV420_Legacy format. | |
2241 | * Revert this when other pipe modes can support | |
2242 | * YUV420_Legacy format. | |
2243 | */ | |
2244 | if (mipi_info && mipi_info->input_format == | |
eaa399eb | 2245 | ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) |
ad85094b MCC |
2246 | return IA_CSS_PIPE_MODE_YUVPP; |
2247 | return IA_CSS_PIPE_MODE_COPY; | |
2248 | case IA_CSS_PIPE_ID_PREVIEW: | |
2249 | return IA_CSS_PIPE_MODE_PREVIEW; | |
2250 | case IA_CSS_PIPE_ID_CAPTURE: | |
2251 | return IA_CSS_PIPE_MODE_CAPTURE; | |
2252 | case IA_CSS_PIPE_ID_VIDEO: | |
2253 | return IA_CSS_PIPE_MODE_VIDEO; | |
2254 | case IA_CSS_PIPE_ID_ACC: | |
2255 | return IA_CSS_PIPE_MODE_ACC; | |
2256 | case IA_CSS_PIPE_ID_YUVPP: | |
2257 | return IA_CSS_PIPE_MODE_YUVPP; | |
2258 | default: | |
2259 | WARN_ON(1); | |
2260 | return IA_CSS_PIPE_MODE_PREVIEW; | |
2261 | } | |
ad85094b MCC |
2262 | } |
2263 | ||
2264 | static void __configure_output(struct atomisp_sub_device *asd, | |
2265 | unsigned int stream_index, | |
2266 | unsigned int width, unsigned int height, | |
2267 | unsigned int min_width, | |
2268 | enum ia_css_frame_format format, | |
2269 | enum ia_css_pipe_id pipe_id) | |
2270 | { | |
2271 | struct atomisp_device *isp = asd->isp; | |
2272 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2273 | &asd->stream_env[stream_index]; |
ad85094b MCC |
2274 | struct ia_css_stream_config *s_config = &stream_env->stream_config; |
2275 | ||
2276 | stream_env->pipe_configs[pipe_id].mode = | |
eaa399eb | 2277 | __pipe_id_to_pipe_mode(asd, pipe_id); |
ad85094b MCC |
2278 | stream_env->update_pipe[pipe_id] = true; |
2279 | ||
2280 | stream_env->pipe_configs[pipe_id].output_info[0].res.width = width; | |
2281 | stream_env->pipe_configs[pipe_id].output_info[0].res.height = height; | |
2282 | stream_env->pipe_configs[pipe_id].output_info[0].format = format; | |
2283 | stream_env->pipe_configs[pipe_id].output_info[0].padded_width = min_width; | |
2284 | ||
2285 | /* isp binary 2.2 specific setting*/ | |
2286 | if (width > s_config->input_config.effective_res.width || | |
2287 | height > s_config->input_config.effective_res.height) { | |
2288 | s_config->input_config.effective_res.width = width; | |
2289 | s_config->input_config.effective_res.height = height; | |
2290 | } | |
2291 | ||
2292 | dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n", | |
2293 | pipe_id, width, height, format); | |
2294 | } | |
2295 | ||
2296 | static void __configure_video_preview_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2297 | unsigned int stream_index, |
2298 | unsigned int width, unsigned int height, | |
2299 | unsigned int min_width, | |
2300 | enum ia_css_frame_format format, | |
2301 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
2302 | { |
2303 | struct atomisp_device *isp = asd->isp; | |
2304 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2305 | &asd->stream_env[stream_index]; |
ad85094b MCC |
2306 | struct ia_css_frame_info *css_output_info; |
2307 | struct ia_css_stream_config *stream_config = &stream_env->stream_config; | |
2308 | ||
2309 | stream_env->pipe_configs[pipe_id].mode = | |
eaa399eb | 2310 | __pipe_id_to_pipe_mode(asd, pipe_id); |
ad85094b MCC |
2311 | stream_env->update_pipe[pipe_id] = true; |
2312 | ||
2313 | /* | |
2314 | * second_output will be as video main output in SDV mode | |
2315 | * with SOC camera. output will be as video main output in | |
2316 | * normal video mode. | |
2317 | */ | |
2318 | if (asd->continuous_mode->val) | |
2319 | css_output_info = &stream_env->pipe_configs[pipe_id]. | |
eaa399eb | 2320 | output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; |
ad85094b MCC |
2321 | else |
2322 | css_output_info = &stream_env->pipe_configs[pipe_id]. | |
eaa399eb | 2323 | output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; |
ad85094b MCC |
2324 | |
2325 | css_output_info->res.width = width; | |
2326 | css_output_info->res.height = height; | |
2327 | css_output_info->format = format; | |
2328 | css_output_info->padded_width = min_width; | |
2329 | ||
2330 | /* isp binary 2.2 specific setting*/ | |
2331 | if (width > stream_config->input_config.effective_res.width || | |
2332 | height > stream_config->input_config.effective_res.height) { | |
2333 | stream_config->input_config.effective_res.width = width; | |
2334 | stream_config->input_config.effective_res.height = height; | |
2335 | } | |
2336 | ||
2337 | dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n", | |
2338 | pipe_id, width, height, format); | |
2339 | } | |
2340 | ||
2341 | /* | |
2342 | * For CSS2.1, capture pipe uses capture_pp_in_res to configure yuv | |
2343 | * downscaling input resolution. | |
2344 | */ | |
2345 | static void __configure_capture_pp_input(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2346 | unsigned int width, unsigned int height, |
2347 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
2348 | { |
2349 | struct atomisp_device *isp = asd->isp; | |
2350 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2351 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
2352 | struct ia_css_stream_config *stream_config = &stream_env->stream_config; |
2353 | struct ia_css_pipe_config *pipe_configs = | |
eaa399eb | 2354 | &stream_env->pipe_configs[pipe_id]; |
ad85094b | 2355 | struct ia_css_pipe_extra_config *pipe_extra_configs = |
eaa399eb | 2356 | &stream_env->pipe_extra_configs[pipe_id]; |
ad85094b MCC |
2357 | unsigned int hor_ds_factor = 0, ver_ds_factor = 0; |
2358 | ||
2359 | if (width == 0 && height == 0) | |
2360 | return; | |
2361 | ||
2362 | if (width * 9 / 10 < pipe_configs->output_info[0].res.width || | |
2363 | height * 9 / 10 < pipe_configs->output_info[0].res.height) | |
2364 | return; | |
2365 | /* here just copy the calculation in css */ | |
2366 | hor_ds_factor = CEIL_DIV(width >> 1, | |
eaa399eb | 2367 | pipe_configs->output_info[0].res.width); |
ad85094b | 2368 | ver_ds_factor = CEIL_DIV(height >> 1, |
eaa399eb | 2369 | pipe_configs->output_info[0].res.height); |
ad85094b MCC |
2370 | |
2371 | if ((asd->isp->media_dev.hw_revision < | |
eaa399eb MCC |
2372 | (ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT) || |
2373 | IS_CHT) && hor_ds_factor != ver_ds_factor) { | |
ad85094b | 2374 | dev_warn(asd->isp->dev, |
eaa399eb | 2375 | "Cropping for capture due to FW limitation"); |
ad85094b MCC |
2376 | return; |
2377 | } | |
2378 | ||
2379 | pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id); | |
2380 | stream_env->update_pipe[pipe_id] = true; | |
2381 | ||
2382 | pipe_extra_configs->enable_yuv_ds = true; | |
2383 | ||
2384 | pipe_configs->capt_pp_in_res.width = | |
eaa399eb | 2385 | stream_config->input_config.effective_res.width; |
ad85094b | 2386 | pipe_configs->capt_pp_in_res.height = |
eaa399eb | 2387 | stream_config->input_config.effective_res.height; |
ad85094b MCC |
2388 | |
2389 | dev_dbg(isp->dev, "configuring pipe[%d]capture pp input w=%d.h=%d.\n", | |
2390 | pipe_id, width, height); | |
2391 | } | |
2392 | ||
2393 | /* | |
2394 | * For CSS2.1, preview pipe could support bayer downscaling, yuv decimation and | |
2395 | * yuv downscaling, which needs addtional configurations. | |
2396 | */ | |
2397 | static void __configure_preview_pp_input(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2398 | unsigned int width, unsigned int height, |
2399 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
2400 | { |
2401 | struct atomisp_device *isp = asd->isp; | |
2402 | int out_width, out_height, yuv_ds_in_width, yuv_ds_in_height; | |
2403 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2404 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
2405 | struct ia_css_stream_config *stream_config = &stream_env->stream_config; |
2406 | struct ia_css_pipe_config *pipe_configs = | |
eaa399eb | 2407 | &stream_env->pipe_configs[pipe_id]; |
ad85094b | 2408 | struct ia_css_pipe_extra_config *pipe_extra_configs = |
eaa399eb | 2409 | &stream_env->pipe_extra_configs[pipe_id]; |
ad85094b | 2410 | struct ia_css_resolution *bayer_ds_out_res = |
eaa399eb | 2411 | &pipe_configs->bayer_ds_out_res; |
ad85094b | 2412 | struct ia_css_resolution *vf_pp_in_res = |
eaa399eb | 2413 | &pipe_configs->vf_pp_in_res; |
ad85094b | 2414 | struct ia_css_resolution *effective_res = |
eaa399eb | 2415 | &stream_config->input_config.effective_res; |
ad85094b | 2416 | |
fb259545 | 2417 | static const struct bayer_ds_factor bds_fct[] = {{2, 1}, {3, 2}, {5, 4} }; |
ad85094b MCC |
2418 | /* |
2419 | * BZ201033: YUV decimation factor of 4 causes couple of rightmost | |
2420 | * columns to be shaded. Remove this factor to work around the CSS bug. | |
2421 | * const unsigned int yuv_dec_fct[] = {4, 2}; | |
2422 | */ | |
fb259545 | 2423 | static const unsigned int yuv_dec_fct[] = { 2 }; |
ad85094b MCC |
2424 | unsigned int i; |
2425 | ||
2426 | if (width == 0 && height == 0) | |
2427 | return; | |
2428 | ||
2429 | pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id); | |
2430 | stream_env->update_pipe[pipe_id] = true; | |
2431 | ||
2432 | out_width = pipe_configs->output_info[0].res.width; | |
2433 | out_height = pipe_configs->output_info[0].res.height; | |
2434 | ||
2435 | /* | |
2436 | * The ISP could do bayer downscaling, yuv decimation and yuv | |
2437 | * downscaling: | |
2438 | * 1: Bayer Downscaling: between effective resolution and | |
2439 | * bayer_ds_res_out; | |
2440 | * 2: YUV Decimation: between bayer_ds_res_out and vf_pp_in_res; | |
2441 | * 3: YUV Downscaling: between vf_pp_in_res and final vf output | |
2442 | * | |
2443 | * Rule for Bayer Downscaling: support factor 2, 1.5 and 1.25 | |
2444 | * Rule for YUV Decimation: support factor 2, 4 | |
4636a85c | 2445 | * Rule for YUV Downscaling: arbitrary value below 2 |
ad85094b MCC |
2446 | * |
2447 | * General rule of factor distribution among these stages: | |
2448 | * 1: try to do Bayer downscaling first if not in online mode. | |
2449 | * 2: try to do maximum of 2 for YUV downscaling | |
2450 | * 3: the remainling for YUV decimation | |
2451 | * | |
2452 | * Note: | |
2453 | * Do not configure bayer_ds_out_res if: | |
2454 | * online == 1 or continuous == 0 or raw_binning = 0 | |
2455 | */ | |
2456 | if (stream_config->online || !stream_config->continuous || | |
eaa399eb | 2457 | !pipe_extra_configs->enable_raw_binning) { |
ad85094b MCC |
2458 | bayer_ds_out_res->width = 0; |
2459 | bayer_ds_out_res->height = 0; | |
2460 | } else { | |
2461 | bayer_ds_out_res->width = effective_res->width; | |
2462 | bayer_ds_out_res->height = effective_res->height; | |
2463 | ||
2464 | for (i = 0; i < ARRAY_SIZE(bds_fct); i++) { | |
2465 | if (effective_res->width >= out_width * | |
2466 | bds_fct[i].numerator / bds_fct[i].denominator && | |
2467 | effective_res->height >= out_height * | |
2468 | bds_fct[i].numerator / bds_fct[i].denominator) { | |
2469 | bayer_ds_out_res->width = | |
2470 | effective_res->width * | |
2471 | bds_fct[i].denominator / | |
2472 | bds_fct[i].numerator; | |
2473 | bayer_ds_out_res->height = | |
2474 | effective_res->height * | |
2475 | bds_fct[i].denominator / | |
2476 | bds_fct[i].numerator; | |
2477 | break; | |
2478 | } | |
2479 | } | |
2480 | } | |
2481 | /* | |
2482 | * calculate YUV Decimation, YUV downscaling facor: | |
2483 | * YUV Downscaling factor must not exceed 2. | |
2484 | * YUV Decimation factor could be 2, 4. | |
2485 | */ | |
2486 | /* first decide the yuv_ds input resolution */ | |
2487 | if (bayer_ds_out_res->width == 0) { | |
2488 | yuv_ds_in_width = effective_res->width; | |
2489 | yuv_ds_in_height = effective_res->height; | |
2490 | } else { | |
2491 | yuv_ds_in_width = bayer_ds_out_res->width; | |
2492 | yuv_ds_in_height = bayer_ds_out_res->height; | |
2493 | } | |
2494 | ||
2495 | vf_pp_in_res->width = yuv_ds_in_width; | |
2496 | vf_pp_in_res->height = yuv_ds_in_height; | |
2497 | ||
2498 | /* find out the yuv decimation factor */ | |
2499 | for (i = 0; i < ARRAY_SIZE(yuv_dec_fct); i++) { | |
2500 | if (yuv_ds_in_width >= out_width * yuv_dec_fct[i] && | |
2501 | yuv_ds_in_height >= out_height * yuv_dec_fct[i]) { | |
2502 | vf_pp_in_res->width = yuv_ds_in_width / yuv_dec_fct[i]; | |
2503 | vf_pp_in_res->height = yuv_ds_in_height / yuv_dec_fct[i]; | |
2504 | break; | |
2505 | } | |
2506 | } | |
2507 | ||
2508 | if (vf_pp_in_res->width == out_width && | |
eaa399eb | 2509 | vf_pp_in_res->height == out_height) { |
ad85094b MCC |
2510 | pipe_extra_configs->enable_yuv_ds = false; |
2511 | vf_pp_in_res->width = 0; | |
2512 | vf_pp_in_res->height = 0; | |
2513 | } else { | |
2514 | pipe_extra_configs->enable_yuv_ds = true; | |
2515 | } | |
2516 | ||
2517 | dev_dbg(isp->dev, "configuring pipe[%d]preview pp input w=%d.h=%d.\n", | |
2518 | pipe_id, width, height); | |
2519 | } | |
2520 | ||
2521 | /* | |
2522 | * For CSS2.1, offline video pipe could support bayer decimation, and | |
2523 | * yuv downscaling, which needs addtional configurations. | |
2524 | */ | |
2525 | static void __configure_video_pp_input(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2526 | unsigned int width, unsigned int height, |
2527 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
2528 | { |
2529 | struct atomisp_device *isp = asd->isp; | |
2530 | int out_width, out_height; | |
2531 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2532 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
2533 | struct ia_css_stream_config *stream_config = &stream_env->stream_config; |
2534 | struct ia_css_pipe_config *pipe_configs = | |
eaa399eb | 2535 | &stream_env->pipe_configs[pipe_id]; |
ad85094b | 2536 | struct ia_css_pipe_extra_config *pipe_extra_configs = |
eaa399eb | 2537 | &stream_env->pipe_extra_configs[pipe_id]; |
ad85094b | 2538 | struct ia_css_resolution *bayer_ds_out_res = |
eaa399eb | 2539 | &pipe_configs->bayer_ds_out_res; |
ad85094b | 2540 | struct ia_css_resolution *effective_res = |
eaa399eb | 2541 | &stream_config->input_config.effective_res; |
ad85094b | 2542 | |
fb259545 | 2543 | static const struct bayer_ds_factor bds_factors[] = { |
eaa399eb MCC |
2544 | {8, 1}, {6, 1}, {4, 1}, {3, 1}, {2, 1}, {3, 2} |
2545 | }; | |
ad85094b MCC |
2546 | unsigned int i; |
2547 | ||
2548 | if (width == 0 && height == 0) | |
2549 | return; | |
2550 | ||
2551 | pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id); | |
2552 | stream_env->update_pipe[pipe_id] = true; | |
2553 | ||
2554 | pipe_extra_configs->enable_yuv_ds = false; | |
2555 | ||
2556 | /* | |
2557 | * If DVS is enabled, video binary will take care the dvs envelope | |
2558 | * and usually the bayer_ds_out_res should be larger than 120% of | |
2559 | * destination resolution, the extra 20% will be cropped as DVS | |
2560 | * envelope. But, if the bayer_ds_out_res is less than 120% of the | |
2561 | * destination. The ISP can still work, but DVS quality is not good. | |
2562 | */ | |
2563 | /* taking at least 10% as envelope */ | |
2564 | if (asd->params.video_dis_en) { | |
2565 | out_width = pipe_configs->output_info[0].res.width * 110 / 100; | |
2566 | out_height = pipe_configs->output_info[0].res.height * 110 / 100; | |
2567 | } else { | |
2568 | out_width = pipe_configs->output_info[0].res.width; | |
2569 | out_height = pipe_configs->output_info[0].res.height; | |
2570 | } | |
2571 | ||
2572 | /* | |
2573 | * calculate bayer decimate factor: | |
2574 | * 1: only 1.5, 2, 4 and 8 get supported | |
2575 | * 2: Do not configure bayer_ds_out_res if: | |
2576 | * online == 1 or continuous == 0 or raw_binning = 0 | |
2577 | */ | |
2578 | if (stream_config->online || !stream_config->continuous) { | |
2579 | bayer_ds_out_res->width = 0; | |
2580 | bayer_ds_out_res->height = 0; | |
2581 | goto done; | |
2582 | } | |
2583 | ||
2584 | pipe_extra_configs->enable_raw_binning = true; | |
2585 | bayer_ds_out_res->width = effective_res->width; | |
2586 | bayer_ds_out_res->height = effective_res->height; | |
2587 | ||
2588 | for (i = 0; i < sizeof(bds_factors) / sizeof(struct bayer_ds_factor); | |
2589 | i++) { | |
2590 | if (effective_res->width >= out_width * | |
2591 | bds_factors[i].numerator / bds_factors[i].denominator && | |
2592 | effective_res->height >= out_height * | |
2593 | bds_factors[i].numerator / bds_factors[i].denominator) { | |
2594 | bayer_ds_out_res->width = effective_res->width * | |
eaa399eb MCC |
2595 | bds_factors[i].denominator / |
2596 | bds_factors[i].numerator; | |
ad85094b | 2597 | bayer_ds_out_res->height = effective_res->height * |
eaa399eb MCC |
2598 | bds_factors[i].denominator / |
2599 | bds_factors[i].numerator; | |
ad85094b MCC |
2600 | break; |
2601 | } | |
2602 | } | |
2603 | ||
2604 | /* | |
2605 | * DVS is cropped from BDS output, so we do not really need to set the | |
2606 | * envelope to 20% of output resolution here. always set it to 12x12 | |
2607 | * per firmware requirement. | |
2608 | */ | |
2609 | pipe_configs->dvs_envelope.width = 12; | |
2610 | pipe_configs->dvs_envelope.height = 12; | |
2611 | ||
2612 | done: | |
2613 | if (pipe_id == IA_CSS_PIPE_ID_YUVPP) | |
2614 | stream_config->left_padding = -1; | |
2615 | else | |
2616 | stream_config->left_padding = 12; | |
2617 | dev_dbg(isp->dev, "configuring pipe[%d]video pp input w=%d.h=%d.\n", | |
2618 | pipe_id, width, height); | |
2619 | } | |
2620 | ||
2621 | static void __configure_vf_output(struct atomisp_sub_device *asd, | |
2622 | unsigned int width, unsigned int height, | |
2623 | unsigned int min_width, | |
c01d5546 | 2624 | enum ia_css_frame_format format, |
ad85094b MCC |
2625 | enum ia_css_pipe_id pipe_id) |
2626 | { | |
2627 | struct atomisp_device *isp = asd->isp; | |
2628 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2629 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b | 2630 | stream_env->pipe_configs[pipe_id].mode = |
eaa399eb | 2631 | __pipe_id_to_pipe_mode(asd, pipe_id); |
ad85094b MCC |
2632 | stream_env->update_pipe[pipe_id] = true; |
2633 | ||
2634 | stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width; | |
2635 | stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height; | |
2636 | stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format; | |
2637 | stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width = | |
eaa399eb | 2638 | min_width; |
ad85094b MCC |
2639 | dev_dbg(isp->dev, |
2640 | "configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n", | |
eaa399eb | 2641 | pipe_id, width, height, format); |
ad85094b MCC |
2642 | } |
2643 | ||
2644 | static void __configure_video_vf_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2645 | unsigned int width, unsigned int height, |
2646 | unsigned int min_width, | |
c01d5546 | 2647 | enum ia_css_frame_format format, |
eaa399eb | 2648 | enum ia_css_pipe_id pipe_id) |
ad85094b MCC |
2649 | { |
2650 | struct atomisp_device *isp = asd->isp; | |
2651 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2652 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
2653 | struct ia_css_frame_info *css_output_info; |
2654 | ||
2655 | stream_env->pipe_configs[pipe_id].mode = | |
eaa399eb | 2656 | __pipe_id_to_pipe_mode(asd, pipe_id); |
ad85094b MCC |
2657 | stream_env->update_pipe[pipe_id] = true; |
2658 | ||
2659 | /* | |
2660 | * second_vf_output will be as video viewfinder in SDV mode | |
2661 | * with SOC camera. vf_output will be as video viewfinder in | |
2662 | * normal video mode. | |
2663 | */ | |
2664 | if (asd->continuous_mode->val) | |
2665 | css_output_info = &stream_env->pipe_configs[pipe_id]. | |
eaa399eb | 2666 | vf_output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; |
ad85094b MCC |
2667 | else |
2668 | css_output_info = &stream_env->pipe_configs[pipe_id]. | |
eaa399eb | 2669 | vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; |
ad85094b MCC |
2670 | |
2671 | css_output_info->res.width = width; | |
2672 | css_output_info->res.height = height; | |
2673 | css_output_info->format = format; | |
2674 | css_output_info->padded_width = min_width; | |
2675 | dev_dbg(isp->dev, | |
2676 | "configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n", | |
eaa399eb | 2677 | pipe_id, width, height, format); |
ad85094b MCC |
2678 | } |
2679 | ||
2680 | static int __get_frame_info(struct atomisp_sub_device *asd, | |
eaa399eb | 2681 | unsigned int stream_index, |
c01d5546 | 2682 | struct ia_css_frame_info *info, |
eaa399eb MCC |
2683 | enum frame_info_type type, |
2684 | enum ia_css_pipe_id pipe_id) | |
ad85094b MCC |
2685 | { |
2686 | struct atomisp_device *isp = asd->isp; | |
41022d35 | 2687 | int ret; |
ad85094b MCC |
2688 | struct ia_css_pipe_info p_info; |
2689 | ||
2690 | /* FIXME! No need to destroy/recreate all streams */ | |
2691 | if (__destroy_streams(asd, true)) | |
2692 | dev_warn(isp->dev, "destroy stream failed.\n"); | |
2693 | ||
2694 | if (__destroy_pipes(asd, true)) | |
2695 | dev_warn(isp->dev, "destroy pipe failed.\n"); | |
2696 | ||
2697 | if (__create_pipes(asd)) | |
2698 | return -EINVAL; | |
2699 | ||
2700 | if (__create_streams(asd)) | |
2701 | goto stream_err; | |
2702 | ||
2703 | ret = ia_css_pipe_get_info( | |
eaa399eb MCC |
2704 | asd->stream_env[stream_index] |
2705 | .pipes[pipe_id], &p_info); | |
41022d35 | 2706 | if (!ret) { |
ad85094b MCC |
2707 | switch (type) { |
2708 | case ATOMISP_CSS_VF_FRAME: | |
2709 | *info = p_info.vf_output_info[0]; | |
2710 | dev_dbg(isp->dev, "getting vf frame info.\n"); | |
2711 | break; | |
2712 | case ATOMISP_CSS_SECOND_VF_FRAME: | |
2713 | *info = p_info.vf_output_info[1]; | |
2714 | dev_dbg(isp->dev, "getting second vf frame info.\n"); | |
2715 | break; | |
2716 | case ATOMISP_CSS_OUTPUT_FRAME: | |
2717 | *info = p_info.output_info[0]; | |
2718 | dev_dbg(isp->dev, "getting main frame info.\n"); | |
2719 | break; | |
2720 | case ATOMISP_CSS_SECOND_OUTPUT_FRAME: | |
2721 | *info = p_info.output_info[1]; | |
2722 | dev_dbg(isp->dev, "getting second main frame info.\n"); | |
2723 | break; | |
2724 | case ATOMISP_CSS_RAW_FRAME: | |
2725 | *info = p_info.raw_output_info; | |
2726 | dev_dbg(isp->dev, "getting raw frame info.\n"); | |
2727 | } | |
2728 | dev_dbg(isp->dev, "get frame info: w=%d, h=%d, num_invalid_frames %d.\n", | |
2729 | info->res.width, info->res.height, p_info.num_invalid_frames); | |
2730 | return 0; | |
2731 | } | |
2732 | ||
2733 | stream_err: | |
2734 | __destroy_pipes(asd, true); | |
2735 | return -EINVAL; | |
2736 | } | |
2737 | ||
2738 | static unsigned int atomisp_get_pipe_index(struct atomisp_sub_device *asd, | |
eaa399eb | 2739 | uint16_t source_pad) |
ad85094b MCC |
2740 | { |
2741 | struct atomisp_device *isp = asd->isp; | |
2742 | /* | |
2743 | * to SOC camera, use yuvpp pipe. | |
2744 | */ | |
2745 | if (ATOMISP_USE_YUVPP(asd)) | |
2746 | return IA_CSS_PIPE_ID_YUVPP; | |
2747 | ||
2748 | switch (source_pad) { | |
2749 | case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: | |
2750 | if (asd->yuvpp_mode) | |
2751 | return IA_CSS_PIPE_ID_YUVPP; | |
2752 | if (asd->copy_mode) | |
2753 | return IA_CSS_PIPE_ID_COPY; | |
2754 | if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO | |
2755 | || asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) | |
2756 | return IA_CSS_PIPE_ID_VIDEO; | |
5b552b19 MCC |
2757 | |
2758 | return IA_CSS_PIPE_ID_CAPTURE; | |
ad85094b MCC |
2759 | case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: |
2760 | if (asd->copy_mode) | |
2761 | return IA_CSS_PIPE_ID_COPY; | |
5b552b19 | 2762 | |
ad85094b MCC |
2763 | return IA_CSS_PIPE_ID_CAPTURE; |
2764 | case ATOMISP_SUBDEV_PAD_SOURCE_VF: | |
5b552b19 | 2765 | if (!atomisp_is_mbuscode_raw(asd->fmt[asd->capture_pad].fmt.code)) { |
ad85094b | 2766 | return IA_CSS_PIPE_ID_CAPTURE; |
5b552b19 | 2767 | } |
df561f66 | 2768 | fallthrough; |
ad85094b MCC |
2769 | case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: |
2770 | if (asd->yuvpp_mode) | |
2771 | return IA_CSS_PIPE_ID_YUVPP; | |
2772 | if (asd->copy_mode) | |
2773 | return IA_CSS_PIPE_ID_COPY; | |
2774 | if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) | |
2775 | return IA_CSS_PIPE_ID_VIDEO; | |
5b552b19 MCC |
2776 | |
2777 | return IA_CSS_PIPE_ID_PREVIEW; | |
ad85094b MCC |
2778 | } |
2779 | dev_warn(isp->dev, | |
2780 | "invalid source pad:%d, return default preview pipe index.\n", | |
2781 | source_pad); | |
2782 | return IA_CSS_PIPE_ID_PREVIEW; | |
2783 | } | |
2784 | ||
2785 | int atomisp_get_css_frame_info(struct atomisp_sub_device *asd, | |
eaa399eb | 2786 | u16 source_pad, |
c01d5546 | 2787 | struct ia_css_frame_info *frame_info) |
ad85094b MCC |
2788 | { |
2789 | struct ia_css_pipe_info info; | |
2790 | int pipe_index = atomisp_get_pipe_index(asd, source_pad); | |
2791 | int stream_index; | |
2792 | struct atomisp_device *isp = asd->isp; | |
2793 | ||
2794 | if (ATOMISP_SOC_CAMERA(asd)) | |
2795 | stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); | |
2796 | else { | |
2797 | stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ? | |
eaa399eb MCC |
2798 | ATOMISP_INPUT_STREAM_VIDEO : |
2799 | atomisp_source_pad_to_stream_id(asd, source_pad); | |
ad85094b MCC |
2800 | } |
2801 | ||
41022d35 | 2802 | if (0 != ia_css_pipe_get_info(asd->stream_env[stream_index] |
eaa399eb | 2803 | .pipes[pipe_index], &info)) { |
ad85094b MCC |
2804 | dev_err(isp->dev, "ia_css_pipe_get_info FAILED"); |
2805 | return -EINVAL; | |
2806 | } | |
2807 | ||
2808 | switch (source_pad) { | |
2809 | case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: | |
2810 | *frame_info = info.output_info[0]; | |
2811 | break; | |
2812 | case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: | |
2813 | if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val) | |
2814 | *frame_info = info. | |
eaa399eb | 2815 | output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; |
ad85094b MCC |
2816 | else |
2817 | *frame_info = info. | |
eaa399eb | 2818 | output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; |
ad85094b MCC |
2819 | break; |
2820 | case ATOMISP_SUBDEV_PAD_SOURCE_VF: | |
2821 | if (stream_index == ATOMISP_INPUT_STREAM_POSTVIEW) | |
2822 | *frame_info = info.output_info[0]; | |
2823 | else | |
2824 | *frame_info = info.vf_output_info[0]; | |
2825 | break; | |
2826 | case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: | |
2827 | if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && | |
2828 | (pipe_index == IA_CSS_PIPE_ID_VIDEO || | |
2829 | pipe_index == IA_CSS_PIPE_ID_YUVPP)) | |
2830 | if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val) | |
2831 | *frame_info = info. | |
eaa399eb | 2832 | vf_output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; |
ad85094b MCC |
2833 | else |
2834 | *frame_info = info. | |
eaa399eb | 2835 | vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; |
ad85094b MCC |
2836 | else if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val) |
2837 | *frame_info = | |
eaa399eb | 2838 | info.output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; |
ad85094b MCC |
2839 | else |
2840 | *frame_info = | |
eaa399eb | 2841 | info.output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; |
ad85094b MCC |
2842 | |
2843 | break; | |
2844 | default: | |
2845 | frame_info = NULL; | |
2846 | break; | |
2847 | } | |
2848 | return frame_info ? 0 : -EINVAL; | |
2849 | } | |
2850 | ||
2851 | int atomisp_css_copy_configure_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2852 | unsigned int stream_index, |
2853 | unsigned int width, unsigned int height, | |
2854 | unsigned int padded_width, | |
c01d5546 | 2855 | enum ia_css_frame_format format) |
ad85094b MCC |
2856 | { |
2857 | asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_COPY]. | |
eaa399eb | 2858 | default_capture_config.mode = |
c01d5546 | 2859 | IA_CSS_CAPTURE_MODE_RAW; |
ad85094b MCC |
2860 | |
2861 | __configure_output(asd, stream_index, width, height, padded_width, | |
2862 | format, IA_CSS_PIPE_ID_COPY); | |
2863 | return 0; | |
2864 | } | |
2865 | ||
2866 | int atomisp_css_yuvpp_configure_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2867 | unsigned int stream_index, |
2868 | unsigned int width, unsigned int height, | |
2869 | unsigned int padded_width, | |
c01d5546 | 2870 | enum ia_css_frame_format format) |
ad85094b MCC |
2871 | { |
2872 | asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_YUVPP]. | |
eaa399eb | 2873 | default_capture_config.mode = |
c01d5546 | 2874 | IA_CSS_CAPTURE_MODE_RAW; |
ad85094b MCC |
2875 | |
2876 | __configure_output(asd, stream_index, width, height, padded_width, | |
2877 | format, IA_CSS_PIPE_ID_YUVPP); | |
2878 | return 0; | |
2879 | } | |
2880 | ||
2881 | int atomisp_css_yuvpp_configure_viewfinder( | |
eaa399eb MCC |
2882 | struct atomisp_sub_device *asd, |
2883 | unsigned int stream_index, | |
2884 | unsigned int width, unsigned int height, | |
2885 | unsigned int min_width, | |
c01d5546 | 2886 | enum ia_css_frame_format format) |
ad85094b MCC |
2887 | { |
2888 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 2889 | &asd->stream_env[stream_index]; |
ad85094b MCC |
2890 | enum ia_css_pipe_id pipe_id = IA_CSS_PIPE_ID_YUVPP; |
2891 | ||
2892 | stream_env->pipe_configs[pipe_id].mode = | |
eaa399eb | 2893 | __pipe_id_to_pipe_mode(asd, pipe_id); |
ad85094b MCC |
2894 | stream_env->update_pipe[pipe_id] = true; |
2895 | ||
2896 | stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width; | |
2897 | stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height; | |
2898 | stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format; | |
2899 | stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width = | |
eaa399eb | 2900 | min_width; |
ad85094b MCC |
2901 | return 0; |
2902 | } | |
2903 | ||
2904 | int atomisp_css_yuvpp_get_output_frame_info( | |
eaa399eb MCC |
2905 | struct atomisp_sub_device *asd, |
2906 | unsigned int stream_index, | |
c01d5546 | 2907 | struct ia_css_frame_info *info) |
ad85094b MCC |
2908 | { |
2909 | return __get_frame_info(asd, stream_index, info, | |
eaa399eb | 2910 | ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_YUVPP); |
ad85094b MCC |
2911 | } |
2912 | ||
2913 | int atomisp_css_yuvpp_get_viewfinder_frame_info( | |
eaa399eb MCC |
2914 | struct atomisp_sub_device *asd, |
2915 | unsigned int stream_index, | |
c01d5546 | 2916 | struct ia_css_frame_info *info) |
ad85094b MCC |
2917 | { |
2918 | return __get_frame_info(asd, stream_index, info, | |
eaa399eb | 2919 | ATOMISP_CSS_VF_FRAME, IA_CSS_PIPE_ID_YUVPP); |
ad85094b MCC |
2920 | } |
2921 | ||
2922 | int atomisp_css_preview_configure_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2923 | unsigned int width, unsigned int height, |
2924 | unsigned int min_width, | |
c01d5546 | 2925 | enum ia_css_frame_format format) |
ad85094b MCC |
2926 | { |
2927 | /* | |
2928 | * to SOC camera, use yuvpp pipe. | |
2929 | */ | |
2930 | if (ATOMISP_USE_YUVPP(asd)) | |
eaa399eb MCC |
2931 | __configure_video_preview_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, |
2932 | height, | |
2933 | min_width, format, IA_CSS_PIPE_ID_YUVPP); | |
ad85094b MCC |
2934 | else |
2935 | __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height, | |
eaa399eb | 2936 | min_width, format, IA_CSS_PIPE_ID_PREVIEW); |
ad85094b MCC |
2937 | return 0; |
2938 | } | |
2939 | ||
2940 | int atomisp_css_capture_configure_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2941 | unsigned int width, unsigned int height, |
2942 | unsigned int min_width, | |
c01d5546 | 2943 | enum ia_css_frame_format format) |
ad85094b MCC |
2944 | { |
2945 | enum ia_css_pipe_id pipe_id; | |
2946 | ||
2947 | /* | |
2948 | * to SOC camera, use yuvpp pipe. | |
2949 | */ | |
2950 | if (ATOMISP_USE_YUVPP(asd)) | |
2951 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
2952 | else | |
2953 | pipe_id = IA_CSS_PIPE_ID_CAPTURE; | |
2954 | ||
2955 | __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height, | |
eaa399eb | 2956 | min_width, format, pipe_id); |
ad85094b MCC |
2957 | return 0; |
2958 | } | |
2959 | ||
2960 | int atomisp_css_video_configure_output(struct atomisp_sub_device *asd, | |
eaa399eb MCC |
2961 | unsigned int width, unsigned int height, |
2962 | unsigned int min_width, | |
c01d5546 | 2963 | enum ia_css_frame_format format) |
ad85094b MCC |
2964 | { |
2965 | /* | |
2966 | * to SOC camera, use yuvpp pipe. | |
2967 | */ | |
2968 | if (ATOMISP_USE_YUVPP(asd)) | |
eaa399eb MCC |
2969 | __configure_video_preview_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, |
2970 | height, | |
2971 | min_width, format, IA_CSS_PIPE_ID_YUVPP); | |
ad85094b MCC |
2972 | else |
2973 | __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height, | |
eaa399eb | 2974 | min_width, format, IA_CSS_PIPE_ID_VIDEO); |
ad85094b MCC |
2975 | return 0; |
2976 | } | |
2977 | ||
2978 | int atomisp_css_video_configure_viewfinder( | |
eaa399eb MCC |
2979 | struct atomisp_sub_device *asd, |
2980 | unsigned int width, unsigned int height, | |
2981 | unsigned int min_width, | |
c01d5546 | 2982 | enum ia_css_frame_format format) |
ad85094b MCC |
2983 | { |
2984 | /* | |
2985 | * to SOC camera, video will use yuvpp pipe. | |
2986 | */ | |
2987 | if (ATOMISP_USE_YUVPP(asd)) | |
2988 | __configure_video_vf_output(asd, width, height, min_width, format, | |
eaa399eb | 2989 | IA_CSS_PIPE_ID_YUVPP); |
ad85094b MCC |
2990 | else |
2991 | __configure_vf_output(asd, width, height, min_width, format, | |
eaa399eb | 2992 | IA_CSS_PIPE_ID_VIDEO); |
ad85094b MCC |
2993 | return 0; |
2994 | } | |
2995 | ||
2996 | int atomisp_css_capture_configure_viewfinder( | |
eaa399eb MCC |
2997 | struct atomisp_sub_device *asd, |
2998 | unsigned int width, unsigned int height, | |
2999 | unsigned int min_width, | |
c01d5546 | 3000 | enum ia_css_frame_format format) |
ad85094b MCC |
3001 | { |
3002 | enum ia_css_pipe_id pipe_id; | |
3003 | ||
3004 | /* | |
3005 | * to SOC camera, video will use yuvpp pipe. | |
3006 | */ | |
3007 | if (ATOMISP_USE_YUVPP(asd)) | |
3008 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
3009 | else | |
3010 | pipe_id = IA_CSS_PIPE_ID_CAPTURE; | |
3011 | ||
3012 | __configure_vf_output(asd, width, height, min_width, format, | |
eaa399eb | 3013 | pipe_id); |
ad85094b MCC |
3014 | return 0; |
3015 | } | |
3016 | ||
3017 | int atomisp_css_video_get_viewfinder_frame_info( | |
eaa399eb | 3018 | struct atomisp_sub_device *asd, |
c01d5546 | 3019 | struct ia_css_frame_info *info) |
ad85094b MCC |
3020 | { |
3021 | enum ia_css_pipe_id pipe_id; | |
3022 | enum frame_info_type frame_type = ATOMISP_CSS_VF_FRAME; | |
3023 | ||
3024 | if (ATOMISP_USE_YUVPP(asd)) { | |
3025 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
3026 | if (asd->continuous_mode->val) | |
3027 | frame_type = ATOMISP_CSS_SECOND_VF_FRAME; | |
3028 | } else { | |
3029 | pipe_id = IA_CSS_PIPE_ID_VIDEO; | |
3030 | } | |
3031 | ||
3032 | return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, | |
eaa399eb | 3033 | frame_type, pipe_id); |
ad85094b MCC |
3034 | } |
3035 | ||
3036 | int atomisp_css_capture_get_viewfinder_frame_info( | |
eaa399eb | 3037 | struct atomisp_sub_device *asd, |
c01d5546 | 3038 | struct ia_css_frame_info *info) |
ad85094b MCC |
3039 | { |
3040 | enum ia_css_pipe_id pipe_id; | |
3041 | ||
3042 | if (ATOMISP_USE_YUVPP(asd)) | |
3043 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
3044 | else | |
3045 | pipe_id = IA_CSS_PIPE_ID_CAPTURE; | |
3046 | ||
3047 | return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, | |
eaa399eb | 3048 | ATOMISP_CSS_VF_FRAME, pipe_id); |
ad85094b MCC |
3049 | } |
3050 | ||
3051 | int atomisp_css_capture_get_output_raw_frame_info( | |
eaa399eb | 3052 | struct atomisp_sub_device *asd, |
c01d5546 | 3053 | struct ia_css_frame_info *info) |
ad85094b MCC |
3054 | { |
3055 | if (ATOMISP_USE_YUVPP(asd)) | |
3056 | return 0; | |
3057 | ||
3058 | return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, | |
eaa399eb | 3059 | ATOMISP_CSS_RAW_FRAME, IA_CSS_PIPE_ID_CAPTURE); |
ad85094b MCC |
3060 | } |
3061 | ||
3062 | int atomisp_css_copy_get_output_frame_info( | |
eaa399eb MCC |
3063 | struct atomisp_sub_device *asd, |
3064 | unsigned int stream_index, | |
c01d5546 | 3065 | struct ia_css_frame_info *info) |
ad85094b MCC |
3066 | { |
3067 | return __get_frame_info(asd, stream_index, info, | |
eaa399eb | 3068 | ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_COPY); |
ad85094b MCC |
3069 | } |
3070 | ||
3071 | int atomisp_css_preview_get_output_frame_info( | |
eaa399eb | 3072 | struct atomisp_sub_device *asd, |
c01d5546 | 3073 | struct ia_css_frame_info *info) |
ad85094b MCC |
3074 | { |
3075 | enum ia_css_pipe_id pipe_id; | |
3076 | enum frame_info_type frame_type = ATOMISP_CSS_OUTPUT_FRAME; | |
3077 | ||
3078 | if (ATOMISP_USE_YUVPP(asd)) { | |
3079 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
3080 | if (asd->continuous_mode->val) | |
3081 | frame_type = ATOMISP_CSS_SECOND_OUTPUT_FRAME; | |
3082 | } else { | |
3083 | pipe_id = IA_CSS_PIPE_ID_PREVIEW; | |
3084 | } | |
3085 | ||
3086 | return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, | |
eaa399eb | 3087 | frame_type, pipe_id); |
ad85094b MCC |
3088 | } |
3089 | ||
3090 | int atomisp_css_capture_get_output_frame_info( | |
eaa399eb | 3091 | struct atomisp_sub_device *asd, |
c01d5546 | 3092 | struct ia_css_frame_info *info) |
ad85094b MCC |
3093 | { |
3094 | enum ia_css_pipe_id pipe_id; | |
3095 | ||
3096 | if (ATOMISP_USE_YUVPP(asd)) | |
3097 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
3098 | else | |
3099 | pipe_id = IA_CSS_PIPE_ID_CAPTURE; | |
3100 | ||
3101 | return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, | |
eaa399eb | 3102 | ATOMISP_CSS_OUTPUT_FRAME, pipe_id); |
ad85094b MCC |
3103 | } |
3104 | ||
3105 | int atomisp_css_video_get_output_frame_info( | |
eaa399eb | 3106 | struct atomisp_sub_device *asd, |
c01d5546 | 3107 | struct ia_css_frame_info *info) |
ad85094b MCC |
3108 | { |
3109 | enum ia_css_pipe_id pipe_id; | |
3110 | enum frame_info_type frame_type = ATOMISP_CSS_OUTPUT_FRAME; | |
3111 | ||
3112 | if (ATOMISP_USE_YUVPP(asd)) { | |
3113 | pipe_id = IA_CSS_PIPE_ID_YUVPP; | |
3114 | if (asd->continuous_mode->val) | |
3115 | frame_type = ATOMISP_CSS_SECOND_OUTPUT_FRAME; | |
3116 | } else { | |
3117 | pipe_id = IA_CSS_PIPE_ID_VIDEO; | |
3118 | } | |
3119 | ||
3120 | return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, | |
eaa399eb | 3121 | frame_type, pipe_id); |
ad85094b MCC |
3122 | } |
3123 | ||
3124 | int atomisp_css_preview_configure_pp_input( | |
eaa399eb MCC |
3125 | struct atomisp_sub_device *asd, |
3126 | unsigned int width, unsigned int height) | |
ad85094b MCC |
3127 | { |
3128 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 3129 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b | 3130 | __configure_preview_pp_input(asd, width, height, |
eaa399eb MCC |
3131 | ATOMISP_USE_YUVPP(asd) ? |
3132 | IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_PREVIEW); | |
ad85094b MCC |
3133 | |
3134 | if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]. | |
eaa399eb | 3135 | capt_pp_in_res.width) |
ad85094b | 3136 | __configure_capture_pp_input(asd, width, height, |
eaa399eb MCC |
3137 | ATOMISP_USE_YUVPP(asd) ? |
3138 | IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE); | |
ad85094b MCC |
3139 | return 0; |
3140 | } | |
3141 | ||
3142 | int atomisp_css_capture_configure_pp_input( | |
eaa399eb MCC |
3143 | struct atomisp_sub_device *asd, |
3144 | unsigned int width, unsigned int height) | |
ad85094b MCC |
3145 | { |
3146 | __configure_capture_pp_input(asd, width, height, | |
eaa399eb MCC |
3147 | ATOMISP_USE_YUVPP(asd) ? |
3148 | IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE); | |
ad85094b MCC |
3149 | return 0; |
3150 | } | |
3151 | ||
3152 | int atomisp_css_video_configure_pp_input( | |
eaa399eb MCC |
3153 | struct atomisp_sub_device *asd, |
3154 | unsigned int width, unsigned int height) | |
ad85094b MCC |
3155 | { |
3156 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 3157 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
3158 | |
3159 | __configure_video_pp_input(asd, width, height, | |
eaa399eb MCC |
3160 | ATOMISP_USE_YUVPP(asd) ? |
3161 | IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_VIDEO); | |
ad85094b MCC |
3162 | |
3163 | if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]. | |
eaa399eb | 3164 | capt_pp_in_res.width) |
ad85094b | 3165 | __configure_capture_pp_input(asd, width, height, |
eaa399eb MCC |
3166 | ATOMISP_USE_YUVPP(asd) ? |
3167 | IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE); | |
ad85094b MCC |
3168 | return 0; |
3169 | } | |
3170 | ||
3171 | int atomisp_css_offline_capture_configure(struct atomisp_sub_device *asd, | |
eaa399eb | 3172 | int num_captures, unsigned int skip, int offset) |
ad85094b | 3173 | { |
41022d35 | 3174 | int ret; |
ad85094b | 3175 | |
ad85094b | 3176 | dev_dbg(asd->isp->dev, "%s num_capture:%d skip:%d offset:%d\n", |
eaa399eb | 3177 | __func__, num_captures, skip, offset); |
7ef17aa5 | 3178 | |
ad85094b | 3179 | ret = ia_css_stream_capture( |
eaa399eb MCC |
3180 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3181 | num_captures, skip, offset); | |
41022d35 | 3182 | if (ret) |
ad85094b MCC |
3183 | return -EINVAL; |
3184 | ||
3185 | return 0; | |
3186 | } | |
3187 | ||
3188 | int atomisp_css_exp_id_capture(struct atomisp_sub_device *asd, int exp_id) | |
3189 | { | |
41022d35 | 3190 | int ret; |
ad85094b MCC |
3191 | |
3192 | ret = ia_css_stream_capture_frame( | |
eaa399eb MCC |
3193 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3194 | exp_id); | |
41022d35 | 3195 | if (ret == -ENOBUFS) { |
ad85094b MCC |
3196 | /* capture cmd queue is full */ |
3197 | return -EBUSY; | |
41022d35 | 3198 | } else if (ret) { |
ad85094b MCC |
3199 | return -EIO; |
3200 | } | |
3201 | ||
3202 | return 0; | |
3203 | } | |
3204 | ||
3205 | int atomisp_css_exp_id_unlock(struct atomisp_sub_device *asd, int exp_id) | |
3206 | { | |
41022d35 | 3207 | int ret; |
ad85094b MCC |
3208 | |
3209 | ret = ia_css_unlock_raw_frame( | |
eaa399eb MCC |
3210 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3211 | exp_id); | |
41022d35 | 3212 | if (ret == -ENOBUFS) |
ad85094b | 3213 | return -EAGAIN; |
41022d35 | 3214 | else if (ret) |
ad85094b MCC |
3215 | return -EIO; |
3216 | ||
3217 | return 0; | |
3218 | } | |
3219 | ||
3220 | int atomisp_css_capture_enable_xnr(struct atomisp_sub_device *asd, | |
3221 | bool enable) | |
3222 | { | |
3223 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb MCC |
3224 | .pipe_configs[IA_CSS_PIPE_ID_CAPTURE] |
3225 | .default_capture_config.enable_xnr = enable; | |
ad85094b MCC |
3226 | asd->params.capture_config.enable_xnr = enable; |
3227 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 3228 | .update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true; |
ad85094b MCC |
3229 | |
3230 | return 0; | |
3231 | } | |
3232 | ||
ad85094b | 3233 | void atomisp_css_set_ctc_table(struct atomisp_sub_device *asd, |
c01d5546 | 3234 | struct ia_css_ctc_table *ctc_table) |
ad85094b MCC |
3235 | { |
3236 | int i; | |
bdfe0beb | 3237 | u16 *vamem_ptr = ctc_table->data.vamem_1; |
ad85094b MCC |
3238 | int data_size = IA_CSS_VAMEM_1_CTC_TABLE_SIZE; |
3239 | bool valid = false; | |
3240 | ||
3241 | /* workaround: if ctc_table is all 0, do not apply it */ | |
3242 | if (ctc_table->vamem_type == IA_CSS_VAMEM_TYPE_2) { | |
3243 | vamem_ptr = ctc_table->data.vamem_2; | |
3244 | data_size = IA_CSS_VAMEM_2_CTC_TABLE_SIZE; | |
3245 | } | |
3246 | ||
3247 | for (i = 0; i < data_size; i++) { | |
3248 | if (*(vamem_ptr + i)) { | |
3249 | valid = true; | |
3250 | break; | |
3251 | } | |
3252 | } | |
3253 | ||
3254 | if (valid) | |
3255 | asd->params.config.ctc_table = ctc_table; | |
3256 | else | |
3257 | dev_warn(asd->isp->dev, "Bypass the invalid ctc_table.\n"); | |
3258 | } | |
3259 | ||
3260 | void atomisp_css_set_anr_thres(struct atomisp_sub_device *asd, | |
c01d5546 | 3261 | struct ia_css_anr_thres *anr_thres) |
ad85094b MCC |
3262 | { |
3263 | asd->params.config.anr_thres = anr_thres; | |
3264 | } | |
3265 | ||
3266 | void atomisp_css_set_dvs_6axis(struct atomisp_sub_device *asd, | |
c01d5546 | 3267 | struct ia_css_dvs_6axis_config *dvs_6axis) |
ad85094b MCC |
3268 | { |
3269 | asd->params.config.dvs_6axis_config = dvs_6axis; | |
3270 | } | |
3271 | ||
ad85094b | 3272 | void atomisp_css_video_set_dis_vector(struct atomisp_sub_device *asd, |
eaa399eb | 3273 | struct atomisp_dis_vector *vector) |
ad85094b MCC |
3274 | { |
3275 | if (!asd->params.config.motion_vector) | |
3276 | asd->params.config.motion_vector = &asd->params.css_param.motion_vector; | |
3277 | ||
3278 | memset(asd->params.config.motion_vector, | |
eaa399eb | 3279 | 0, sizeof(struct ia_css_vector)); |
ad85094b MCC |
3280 | asd->params.css_param.motion_vector.x = vector->x; |
3281 | asd->params.css_param.motion_vector.y = vector->y; | |
3282 | } | |
3283 | ||
3284 | static int atomisp_compare_dvs_grid(struct atomisp_sub_device *asd, | |
eaa399eb | 3285 | struct atomisp_dvs_grid_info *atomgrid) |
ad85094b | 3286 | { |
c01d5546 | 3287 | struct ia_css_dvs_grid_info *cur = |
eaa399eb | 3288 | atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); |
ad85094b MCC |
3289 | |
3290 | if (!cur) { | |
3291 | dev_err(asd->isp->dev, "dvs grid not available!\n"); | |
3292 | return -EINVAL; | |
3293 | } | |
3294 | ||
3295 | if (sizeof(*cur) != sizeof(*atomgrid)) { | |
3296 | dev_err(asd->isp->dev, "dvs grid mis-match!\n"); | |
3297 | return -EINVAL; | |
3298 | } | |
3299 | ||
3300 | if (!cur->enable) { | |
3301 | dev_err(asd->isp->dev, "dvs not enabled!\n"); | |
3302 | return -EINVAL; | |
3303 | } | |
3304 | ||
3305 | return memcmp(atomgrid, cur, sizeof(*cur)); | |
3306 | } | |
3307 | ||
3308 | void atomisp_css_set_dvs2_coefs(struct atomisp_sub_device *asd, | |
eaa399eb | 3309 | struct ia_css_dvs2_coefficients *coefs) |
ad85094b MCC |
3310 | { |
3311 | asd->params.config.dvs2_coefs = coefs; | |
3312 | } | |
3313 | ||
3314 | int atomisp_css_set_dis_coefs(struct atomisp_sub_device *asd, | |
eaa399eb | 3315 | struct atomisp_dis_coefficients *coefs) |
ad85094b MCC |
3316 | { |
3317 | if (atomisp_compare_dvs_grid(asd, &coefs->grid_info) != 0) | |
3318 | /* If the grid info in the argument differs from the current | |
3319 | grid info, we tell the caller to reset the grid size and | |
3320 | try again. */ | |
3321 | return -EAGAIN; | |
3322 | ||
bdfe0beb MCC |
3323 | if (!coefs->hor_coefs.odd_real || |
3324 | !coefs->hor_coefs.odd_imag || | |
3325 | !coefs->hor_coefs.even_real || | |
3326 | !coefs->hor_coefs.even_imag || | |
3327 | !coefs->ver_coefs.odd_real || | |
3328 | !coefs->ver_coefs.odd_imag || | |
3329 | !coefs->ver_coefs.even_real || | |
3330 | !coefs->ver_coefs.even_imag || | |
3331 | !asd->params.css_param.dvs2_coeff->hor_coefs.odd_real || | |
3332 | !asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag || | |
3333 | !asd->params.css_param.dvs2_coeff->hor_coefs.even_real || | |
3334 | !asd->params.css_param.dvs2_coeff->hor_coefs.even_imag || | |
3335 | !asd->params.css_param.dvs2_coeff->ver_coefs.odd_real || | |
3336 | !asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag || | |
3337 | !asd->params.css_param.dvs2_coeff->ver_coefs.even_real || | |
3338 | !asd->params.css_param.dvs2_coeff->ver_coefs.even_imag) | |
ad85094b MCC |
3339 | return -EINVAL; |
3340 | ||
3341 | if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_real, | |
eaa399eb | 3342 | coefs->hor_coefs.odd_real, asd->params.dvs_hor_coef_bytes)) |
ad85094b MCC |
3343 | return -EFAULT; |
3344 | if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag, | |
eaa399eb | 3345 | coefs->hor_coefs.odd_imag, asd->params.dvs_hor_coef_bytes)) |
ad85094b MCC |
3346 | return -EFAULT; |
3347 | if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_real, | |
eaa399eb | 3348 | coefs->hor_coefs.even_real, asd->params.dvs_hor_coef_bytes)) |
ad85094b MCC |
3349 | return -EFAULT; |
3350 | if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_imag, | |
eaa399eb | 3351 | coefs->hor_coefs.even_imag, asd->params.dvs_hor_coef_bytes)) |
ad85094b MCC |
3352 | return -EFAULT; |
3353 | ||
3354 | if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_real, | |
eaa399eb | 3355 | coefs->ver_coefs.odd_real, asd->params.dvs_ver_coef_bytes)) |
ad85094b MCC |
3356 | return -EFAULT; |
3357 | if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag, | |
eaa399eb | 3358 | coefs->ver_coefs.odd_imag, asd->params.dvs_ver_coef_bytes)) |
ad85094b MCC |
3359 | return -EFAULT; |
3360 | if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_real, | |
eaa399eb | 3361 | coefs->ver_coefs.even_real, asd->params.dvs_ver_coef_bytes)) |
ad85094b MCC |
3362 | return -EFAULT; |
3363 | if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_imag, | |
eaa399eb | 3364 | coefs->ver_coefs.even_imag, asd->params.dvs_ver_coef_bytes)) |
ad85094b MCC |
3365 | return -EFAULT; |
3366 | ||
3367 | asd->params.css_param.update_flag.dvs2_coefs = | |
f8b39c65 SA |
3368 | (struct atomisp_dis_coefficients *) |
3369 | asd->params.css_param.dvs2_coeff; | |
ad85094b | 3370 | /* FIXME! */ |
eaa399eb | 3371 | /* asd->params.dis_proj_data_valid = false; */ |
ad85094b MCC |
3372 | asd->params.css_update_params_needed = true; |
3373 | ||
3374 | return 0; | |
3375 | } | |
3376 | ||
3377 | void atomisp_css_set_zoom_factor(struct atomisp_sub_device *asd, | |
eaa399eb | 3378 | unsigned int zoom) |
ad85094b MCC |
3379 | { |
3380 | struct atomisp_device *isp = asd->isp; | |
3381 | ||
3382 | if (zoom == asd->params.css_param.dz_config.dx && | |
eaa399eb | 3383 | zoom == asd->params.css_param.dz_config.dy) { |
ad85094b MCC |
3384 | dev_dbg(isp->dev, "same zoom scale. skipped.\n"); |
3385 | return; | |
3386 | } | |
3387 | ||
3388 | memset(&asd->params.css_param.dz_config, 0, | |
eaa399eb | 3389 | sizeof(struct ia_css_dz_config)); |
ad85094b MCC |
3390 | asd->params.css_param.dz_config.dx = zoom; |
3391 | asd->params.css_param.dz_config.dy = zoom; | |
3392 | ||
3393 | asd->params.css_param.update_flag.dz_config = | |
eaa399eb | 3394 | (struct atomisp_dz_config *)&asd->params.css_param.dz_config; |
ad85094b MCC |
3395 | asd->params.css_update_params_needed = true; |
3396 | } | |
3397 | ||
3398 | void atomisp_css_set_formats_config(struct atomisp_sub_device *asd, | |
c01d5546 | 3399 | struct ia_css_formats_config *formats_config) |
ad85094b MCC |
3400 | { |
3401 | asd->params.config.formats_config = formats_config; | |
3402 | } | |
3403 | ||
3404 | int atomisp_css_get_wb_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3405 | struct atomisp_wb_config *config) |
ad85094b | 3406 | { |
c01d5546 | 3407 | struct ia_css_wb_config wb_config; |
ad85094b MCC |
3408 | struct ia_css_isp_config isp_config; |
3409 | struct atomisp_device *isp = asd->isp; | |
3410 | ||
3411 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3412 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3413 | __func__); | |
3414 | return -EINVAL; | |
3415 | } | |
c01d5546 | 3416 | memset(&wb_config, 0, sizeof(struct ia_css_wb_config)); |
ad85094b MCC |
3417 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3418 | isp_config.wb_config = &wb_config; | |
3419 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3420 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3421 | &isp_config); | |
ad85094b MCC |
3422 | memcpy(config, &wb_config, sizeof(*config)); |
3423 | ||
3424 | return 0; | |
3425 | } | |
3426 | ||
3427 | int atomisp_css_get_ob_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3428 | struct atomisp_ob_config *config) |
ad85094b | 3429 | { |
c01d5546 | 3430 | struct ia_css_ob_config ob_config; |
ad85094b MCC |
3431 | struct ia_css_isp_config isp_config; |
3432 | struct atomisp_device *isp = asd->isp; | |
3433 | ||
3434 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3435 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3436 | __func__); | |
3437 | return -EINVAL; | |
3438 | } | |
c01d5546 | 3439 | memset(&ob_config, 0, sizeof(struct ia_css_ob_config)); |
ad85094b MCC |
3440 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3441 | isp_config.ob_config = &ob_config; | |
3442 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3443 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3444 | &isp_config); | |
ad85094b MCC |
3445 | memcpy(config, &ob_config, sizeof(*config)); |
3446 | ||
3447 | return 0; | |
3448 | } | |
3449 | ||
3450 | int atomisp_css_get_dp_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3451 | struct atomisp_dp_config *config) |
ad85094b | 3452 | { |
c01d5546 | 3453 | struct ia_css_dp_config dp_config; |
ad85094b MCC |
3454 | struct ia_css_isp_config isp_config; |
3455 | struct atomisp_device *isp = asd->isp; | |
3456 | ||
3457 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3458 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3459 | __func__); | |
3460 | return -EINVAL; | |
3461 | } | |
c01d5546 | 3462 | memset(&dp_config, 0, sizeof(struct ia_css_dp_config)); |
ad85094b MCC |
3463 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3464 | isp_config.dp_config = &dp_config; | |
3465 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3466 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3467 | &isp_config); | |
ad85094b MCC |
3468 | memcpy(config, &dp_config, sizeof(*config)); |
3469 | ||
3470 | return 0; | |
3471 | } | |
3472 | ||
3473 | int atomisp_css_get_de_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3474 | struct atomisp_de_config *config) |
ad85094b | 3475 | { |
c01d5546 | 3476 | struct ia_css_de_config de_config; |
ad85094b MCC |
3477 | struct ia_css_isp_config isp_config; |
3478 | struct atomisp_device *isp = asd->isp; | |
3479 | ||
3480 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3481 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3482 | __func__); | |
3483 | return -EINVAL; | |
3484 | } | |
c01d5546 | 3485 | memset(&de_config, 0, sizeof(struct ia_css_de_config)); |
ad85094b MCC |
3486 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3487 | isp_config.de_config = &de_config; | |
3488 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3489 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3490 | &isp_config); | |
ad85094b MCC |
3491 | memcpy(config, &de_config, sizeof(*config)); |
3492 | ||
3493 | return 0; | |
3494 | } | |
3495 | ||
3496 | int atomisp_css_get_nr_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3497 | struct atomisp_nr_config *config) |
ad85094b | 3498 | { |
c01d5546 | 3499 | struct ia_css_nr_config nr_config; |
ad85094b MCC |
3500 | struct ia_css_isp_config isp_config; |
3501 | struct atomisp_device *isp = asd->isp; | |
3502 | ||
3503 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3504 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3505 | __func__); | |
3506 | return -EINVAL; | |
3507 | } | |
c01d5546 | 3508 | memset(&nr_config, 0, sizeof(struct ia_css_nr_config)); |
ad85094b MCC |
3509 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3510 | ||
3511 | isp_config.nr_config = &nr_config; | |
3512 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3513 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3514 | &isp_config); | |
ad85094b MCC |
3515 | memcpy(config, &nr_config, sizeof(*config)); |
3516 | ||
3517 | return 0; | |
3518 | } | |
3519 | ||
3520 | int atomisp_css_get_ee_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3521 | struct atomisp_ee_config *config) |
ad85094b | 3522 | { |
c01d5546 | 3523 | struct ia_css_ee_config ee_config; |
ad85094b MCC |
3524 | struct ia_css_isp_config isp_config; |
3525 | struct atomisp_device *isp = asd->isp; | |
3526 | ||
3527 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3528 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
eaa399eb | 3529 | __func__); |
ad85094b MCC |
3530 | return -EINVAL; |
3531 | } | |
c01d5546 | 3532 | memset(&ee_config, 0, sizeof(struct ia_css_ee_config)); |
ad85094b MCC |
3533 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3534 | isp_config.ee_config = &ee_config; | |
3535 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3536 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3537 | &isp_config); | |
ad85094b MCC |
3538 | memcpy(config, &ee_config, sizeof(*config)); |
3539 | ||
3540 | return 0; | |
3541 | } | |
3542 | ||
3543 | int atomisp_css_get_tnr_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3544 | struct atomisp_tnr_config *config) |
ad85094b | 3545 | { |
c01d5546 | 3546 | struct ia_css_tnr_config tnr_config; |
ad85094b MCC |
3547 | struct ia_css_isp_config isp_config; |
3548 | struct atomisp_device *isp = asd->isp; | |
3549 | ||
3550 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3551 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3552 | __func__); | |
3553 | return -EINVAL; | |
3554 | } | |
c01d5546 | 3555 | memset(&tnr_config, 0, sizeof(struct ia_css_tnr_config)); |
ad85094b MCC |
3556 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3557 | isp_config.tnr_config = &tnr_config; | |
3558 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3559 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3560 | &isp_config); | |
ad85094b MCC |
3561 | memcpy(config, &tnr_config, sizeof(*config)); |
3562 | ||
3563 | return 0; | |
3564 | } | |
3565 | ||
3566 | int atomisp_css_get_ctc_table(struct atomisp_sub_device *asd, | |
eaa399eb | 3567 | struct atomisp_ctc_table *config) |
ad85094b | 3568 | { |
c01d5546 | 3569 | struct ia_css_ctc_table *tab; |
ad85094b MCC |
3570 | struct ia_css_isp_config isp_config; |
3571 | struct atomisp_device *isp = asd->isp; | |
3572 | ||
3573 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3574 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3575 | __func__); | |
3576 | return -EINVAL; | |
3577 | } | |
3578 | ||
c01d5546 | 3579 | tab = vzalloc(sizeof(struct ia_css_ctc_table)); |
ad85094b MCC |
3580 | if (!tab) |
3581 | return -ENOMEM; | |
3582 | ||
3583 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); | |
3584 | isp_config.ctc_table = tab; | |
3585 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3586 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3587 | &isp_config); | |
ad85094b MCC |
3588 | memcpy(config, tab, sizeof(*tab)); |
3589 | vfree(tab); | |
3590 | ||
3591 | return 0; | |
3592 | } | |
3593 | ||
3594 | int atomisp_css_get_gamma_table(struct atomisp_sub_device *asd, | |
eaa399eb | 3595 | struct atomisp_gamma_table *config) |
ad85094b | 3596 | { |
c01d5546 | 3597 | struct ia_css_gamma_table *tab; |
ad85094b MCC |
3598 | struct ia_css_isp_config isp_config; |
3599 | struct atomisp_device *isp = asd->isp; | |
3600 | ||
3601 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3602 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3603 | __func__); | |
3604 | return -EINVAL; | |
3605 | } | |
3606 | ||
c01d5546 | 3607 | tab = vzalloc(sizeof(struct ia_css_gamma_table)); |
ad85094b MCC |
3608 | if (!tab) |
3609 | return -ENOMEM; | |
3610 | ||
3611 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); | |
3612 | isp_config.gamma_table = tab; | |
3613 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3614 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3615 | &isp_config); | |
ad85094b MCC |
3616 | memcpy(config, tab, sizeof(*tab)); |
3617 | vfree(tab); | |
3618 | ||
3619 | return 0; | |
3620 | } | |
3621 | ||
3622 | int atomisp_css_get_gc_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3623 | struct atomisp_gc_config *config) |
ad85094b | 3624 | { |
c01d5546 | 3625 | struct ia_css_gc_config gc_config; |
ad85094b MCC |
3626 | struct ia_css_isp_config isp_config; |
3627 | struct atomisp_device *isp = asd->isp; | |
3628 | ||
3629 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3630 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3631 | __func__); | |
3632 | return -EINVAL; | |
3633 | } | |
c01d5546 | 3634 | memset(&gc_config, 0, sizeof(struct ia_css_gc_config)); |
ad85094b MCC |
3635 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3636 | isp_config.gc_config = &gc_config; | |
3637 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3638 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3639 | &isp_config); | |
ad85094b MCC |
3640 | /* Get gamma correction params from current setup */ |
3641 | memcpy(config, &gc_config, sizeof(*config)); | |
3642 | ||
3643 | return 0; | |
3644 | } | |
3645 | ||
3646 | int atomisp_css_get_3a_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3647 | struct atomisp_3a_config *config) |
ad85094b | 3648 | { |
c01d5546 | 3649 | struct ia_css_3a_config s3a_config; |
ad85094b MCC |
3650 | struct ia_css_isp_config isp_config; |
3651 | struct atomisp_device *isp = asd->isp; | |
3652 | ||
3653 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3654 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3655 | __func__); | |
3656 | return -EINVAL; | |
3657 | } | |
c01d5546 | 3658 | memset(&s3a_config, 0, sizeof(struct ia_css_3a_config)); |
ad85094b MCC |
3659 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3660 | isp_config.s3a_config = &s3a_config; | |
3661 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3662 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3663 | &isp_config); | |
ad85094b MCC |
3664 | /* Get white balance from current setup */ |
3665 | memcpy(config, &s3a_config, sizeof(*config)); | |
3666 | ||
3667 | return 0; | |
3668 | } | |
3669 | ||
3670 | int atomisp_css_get_formats_config(struct atomisp_sub_device *asd, | |
eaa399eb | 3671 | struct atomisp_formats_config *config) |
ad85094b | 3672 | { |
c01d5546 | 3673 | struct ia_css_formats_config formats_config; |
ad85094b MCC |
3674 | struct ia_css_isp_config isp_config; |
3675 | struct atomisp_device *isp = asd->isp; | |
3676 | ||
3677 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3678 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3679 | __func__); | |
3680 | return -EINVAL; | |
3681 | } | |
3682 | memset(&formats_config, 0, sizeof(formats_config)); | |
3683 | memset(&isp_config, 0, sizeof(isp_config)); | |
3684 | isp_config.formats_config = &formats_config; | |
3685 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3686 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3687 | &isp_config); | |
ad85094b MCC |
3688 | /* Get narrow gamma from current setup */ |
3689 | memcpy(config, &formats_config, sizeof(*config)); | |
3690 | ||
3691 | return 0; | |
3692 | } | |
3693 | ||
3694 | int atomisp_css_get_zoom_factor(struct atomisp_sub_device *asd, | |
eaa399eb | 3695 | unsigned int *zoom) |
ad85094b MCC |
3696 | { |
3697 | struct ia_css_dz_config dz_config; /** Digital Zoom */ | |
3698 | struct ia_css_isp_config isp_config; | |
3699 | struct atomisp_device *isp = asd->isp; | |
3700 | ||
3701 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3702 | dev_err(isp->dev, "%s called after streamoff, skipping.\n", | |
3703 | __func__); | |
3704 | return -EINVAL; | |
3705 | } | |
3706 | memset(&dz_config, 0, sizeof(struct ia_css_dz_config)); | |
3707 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); | |
3708 | isp_config.dz_config = &dz_config; | |
3709 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3710 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3711 | &isp_config); | |
ad85094b MCC |
3712 | *zoom = dz_config.dx; |
3713 | ||
3714 | return 0; | |
3715 | } | |
3716 | ||
ad85094b MCC |
3717 | /* |
3718 | * Function to set/get image stablization statistics | |
3719 | */ | |
3720 | int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd, | |
eaa399eb | 3721 | struct atomisp_dis_statistics *stats) |
ad85094b MCC |
3722 | { |
3723 | struct atomisp_device *isp = asd->isp; | |
3724 | struct atomisp_dis_buf *dis_buf; | |
3725 | unsigned long flags; | |
3726 | ||
bdfe0beb MCC |
3727 | if (!asd->params.dvs_stat->hor_prod.odd_real || |
3728 | !asd->params.dvs_stat->hor_prod.odd_imag || | |
3729 | !asd->params.dvs_stat->hor_prod.even_real || | |
3730 | !asd->params.dvs_stat->hor_prod.even_imag || | |
3731 | !asd->params.dvs_stat->ver_prod.odd_real || | |
3732 | !asd->params.dvs_stat->ver_prod.odd_imag || | |
3733 | !asd->params.dvs_stat->ver_prod.even_real || | |
3734 | !asd->params.dvs_stat->ver_prod.even_imag) | |
ad85094b MCC |
3735 | return -EINVAL; |
3736 | ||
3737 | /* isp needs to be streaming to get DIS statistics */ | |
3738 | spin_lock_irqsave(&isp->lock, flags); | |
3739 | if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) { | |
3740 | spin_unlock_irqrestore(&isp->lock, flags); | |
3741 | return -EINVAL; | |
3742 | } | |
3743 | spin_unlock_irqrestore(&isp->lock, flags); | |
3744 | ||
3745 | if (atomisp_compare_dvs_grid(asd, &stats->dvs2_stat.grid_info) != 0) | |
3746 | /* If the grid info in the argument differs from the current | |
3747 | grid info, we tell the caller to reset the grid size and | |
3748 | try again. */ | |
3749 | return -EAGAIN; | |
3750 | ||
3751 | spin_lock_irqsave(&asd->dis_stats_lock, flags); | |
3752 | if (!asd->params.dis_proj_data_valid || list_empty(&asd->dis_stats)) { | |
3753 | spin_unlock_irqrestore(&asd->dis_stats_lock, flags); | |
3754 | dev_err(isp->dev, "dis statistics is not valid.\n"); | |
3755 | return -EAGAIN; | |
3756 | } | |
3757 | ||
3758 | dis_buf = list_entry(asd->dis_stats.next, | |
eaa399eb | 3759 | struct atomisp_dis_buf, list); |
ad85094b MCC |
3760 | list_del_init(&dis_buf->list); |
3761 | spin_unlock_irqrestore(&asd->dis_stats_lock, flags); | |
3762 | ||
3763 | if (dis_buf->dvs_map) | |
3764 | ia_css_translate_dvs2_statistics( | |
eaa399eb | 3765 | asd->params.dvs_stat, dis_buf->dvs_map); |
ad85094b MCC |
3766 | else |
3767 | ia_css_get_dvs2_statistics(asd->params.dvs_stat, | |
eaa399eb | 3768 | dis_buf->dis_data); |
ad85094b MCC |
3769 | stats->exp_id = dis_buf->dis_data->exp_id; |
3770 | ||
3771 | spin_lock_irqsave(&asd->dis_stats_lock, flags); | |
3772 | list_add_tail(&dis_buf->list, &asd->dis_stats); | |
3773 | spin_unlock_irqrestore(&asd->dis_stats_lock, flags); | |
3774 | ||
3775 | if (copy_to_user(stats->dvs2_stat.ver_prod.odd_real, | |
3776 | asd->params.dvs_stat->ver_prod.odd_real, | |
3777 | asd->params.dvs_ver_proj_bytes)) | |
3778 | return -EFAULT; | |
3779 | if (copy_to_user(stats->dvs2_stat.ver_prod.odd_imag, | |
3780 | asd->params.dvs_stat->ver_prod.odd_imag, | |
3781 | asd->params.dvs_ver_proj_bytes)) | |
3782 | return -EFAULT; | |
3783 | if (copy_to_user(stats->dvs2_stat.ver_prod.even_real, | |
3784 | asd->params.dvs_stat->ver_prod.even_real, | |
3785 | asd->params.dvs_ver_proj_bytes)) | |
3786 | return -EFAULT; | |
3787 | if (copy_to_user(stats->dvs2_stat.ver_prod.even_imag, | |
3788 | asd->params.dvs_stat->ver_prod.even_imag, | |
3789 | asd->params.dvs_ver_proj_bytes)) | |
3790 | return -EFAULT; | |
3791 | if (copy_to_user(stats->dvs2_stat.hor_prod.odd_real, | |
3792 | asd->params.dvs_stat->hor_prod.odd_real, | |
3793 | asd->params.dvs_hor_proj_bytes)) | |
3794 | return -EFAULT; | |
3795 | if (copy_to_user(stats->dvs2_stat.hor_prod.odd_imag, | |
3796 | asd->params.dvs_stat->hor_prod.odd_imag, | |
3797 | asd->params.dvs_hor_proj_bytes)) | |
3798 | return -EFAULT; | |
3799 | if (copy_to_user(stats->dvs2_stat.hor_prod.even_real, | |
3800 | asd->params.dvs_stat->hor_prod.even_real, | |
3801 | asd->params.dvs_hor_proj_bytes)) | |
3802 | return -EFAULT; | |
3803 | if (copy_to_user(stats->dvs2_stat.hor_prod.even_imag, | |
3804 | asd->params.dvs_stat->hor_prod.even_imag, | |
3805 | asd->params.dvs_hor_proj_bytes)) | |
3806 | return -EFAULT; | |
3807 | ||
3808 | return 0; | |
3809 | } | |
3810 | ||
c01d5546 | 3811 | struct ia_css_shading_table *atomisp_css_shading_table_alloc( |
eaa399eb | 3812 | unsigned int width, unsigned int height) |
ad85094b MCC |
3813 | { |
3814 | return ia_css_shading_table_alloc(width, height); | |
3815 | } | |
3816 | ||
3817 | void atomisp_css_set_shading_table(struct atomisp_sub_device *asd, | |
c01d5546 | 3818 | struct ia_css_shading_table *table) |
ad85094b MCC |
3819 | { |
3820 | asd->params.config.shading_table = table; | |
3821 | } | |
3822 | ||
c01d5546 | 3823 | void atomisp_css_shading_table_free(struct ia_css_shading_table *table) |
ad85094b MCC |
3824 | { |
3825 | ia_css_shading_table_free(table); | |
3826 | } | |
3827 | ||
c01d5546 | 3828 | struct ia_css_morph_table *atomisp_css_morph_table_allocate( |
eaa399eb | 3829 | unsigned int width, unsigned int height) |
ad85094b MCC |
3830 | { |
3831 | return ia_css_morph_table_allocate(width, height); | |
3832 | } | |
3833 | ||
3834 | void atomisp_css_set_morph_table(struct atomisp_sub_device *asd, | |
c01d5546 | 3835 | struct ia_css_morph_table *table) |
ad85094b MCC |
3836 | { |
3837 | asd->params.config.morph_table = table; | |
3838 | } | |
3839 | ||
3840 | void atomisp_css_get_morph_table(struct atomisp_sub_device *asd, | |
c01d5546 | 3841 | struct ia_css_morph_table *table) |
ad85094b MCC |
3842 | { |
3843 | struct ia_css_isp_config isp_config; | |
3844 | struct atomisp_device *isp = asd->isp; | |
3845 | ||
3846 | if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { | |
3847 | dev_err(isp->dev, | |
3848 | "%s called after streamoff, skipping.\n", __func__); | |
3849 | return; | |
3850 | } | |
c01d5546 | 3851 | memset(table, 0, sizeof(struct ia_css_morph_table)); |
ad85094b MCC |
3852 | memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); |
3853 | isp_config.morph_table = table; | |
3854 | ia_css_stream_get_isp_config( | |
eaa399eb MCC |
3855 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
3856 | &isp_config); | |
ad85094b MCC |
3857 | } |
3858 | ||
c01d5546 | 3859 | void atomisp_css_morph_table_free(struct ia_css_morph_table *table) |
ad85094b MCC |
3860 | { |
3861 | ia_css_morph_table_free(table); | |
3862 | } | |
3863 | ||
3864 | void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp, | |
eaa399eb | 3865 | unsigned int overlap) |
ad85094b MCC |
3866 | { |
3867 | /* CSS 2.0 doesn't support this API. */ | |
3868 | dev_dbg(isp->dev, "set cont prev start time is not supported.\n"); | |
3869 | return; | |
3870 | } | |
3871 | ||
3872 | void atomisp_css_acc_done(struct atomisp_sub_device *asd) | |
3873 | { | |
3874 | complete(&asd->acc.acc_done); | |
3875 | } | |
3876 | ||
3877 | int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd) | |
3878 | { | |
3879 | int ret = 0; | |
3880 | struct atomisp_device *isp = asd->isp; | |
3881 | ||
3882 | /* Unlock the isp mutex taken in IOCTL handler before sleeping! */ | |
3883 | rt_mutex_unlock(&isp->mutex); | |
3884 | if (wait_for_completion_interruptible_timeout(&asd->acc.acc_done, | |
eaa399eb | 3885 | ATOMISP_ISP_TIMEOUT_DURATION) == 0) { |
ad85094b | 3886 | dev_err(isp->dev, "<%s: completion timeout\n", __func__); |
1a16d545 MCC |
3887 | ia_css_debug_dump_sp_sw_debug_info(); |
3888 | ia_css_debug_dump_debug_info(__func__); | |
ad85094b MCC |
3889 | ret = -EIO; |
3890 | } | |
3891 | rt_mutex_lock(&isp->mutex); | |
3892 | ||
3893 | return ret; | |
3894 | } | |
3895 | ||
3896 | /* Set the ACC binary arguments */ | |
3897 | int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw) | |
3898 | { | |
3899 | unsigned int mem; | |
3900 | ||
3901 | for (mem = 0; mem < ATOMISP_ACC_NR_MEMORY; mem++) { | |
3902 | if (acc_fw->args[mem].length == 0) | |
3903 | continue; | |
3904 | ||
3905 | ia_css_isp_param_set_css_mem_init(&acc_fw->fw->mem_initializers, | |
eaa399eb MCC |
3906 | IA_CSS_PARAM_CLASS_PARAM, mem, |
3907 | acc_fw->args[mem].css_ptr, | |
3908 | acc_fw->args[mem].length); | |
ad85094b MCC |
3909 | } |
3910 | ||
3911 | return 0; | |
3912 | } | |
3913 | ||
3914 | /* Load acc binary extension */ | |
3915 | int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd, | |
c01d5546 MCC |
3916 | struct ia_css_fw_info *fw, |
3917 | enum ia_css_pipe_id pipe_id, | |
ad85094b MCC |
3918 | unsigned int type) |
3919 | { | |
c01d5546 | 3920 | struct ia_css_fw_info **hd; |
ad85094b MCC |
3921 | |
3922 | fw->next = NULL; | |
3923 | hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 3924 | .pipe_configs[pipe_id].acc_extension); |
ad85094b MCC |
3925 | while (*hd) |
3926 | hd = &(*hd)->next; | |
3927 | *hd = fw; | |
3928 | ||
3929 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 3930 | .update_pipe[pipe_id] = true; |
ad85094b MCC |
3931 | return 0; |
3932 | } | |
3933 | ||
3934 | /* Unload acc binary extension */ | |
3935 | void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd, | |
c01d5546 MCC |
3936 | struct ia_css_fw_info *fw, |
3937 | enum ia_css_pipe_id pipe_id) | |
ad85094b | 3938 | { |
c01d5546 | 3939 | struct ia_css_fw_info **hd; |
ad85094b MCC |
3940 | |
3941 | hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 3942 | .pipe_configs[pipe_id].acc_extension); |
ad85094b MCC |
3943 | while (*hd && *hd != fw) |
3944 | hd = &(*hd)->next; | |
3945 | if (!*hd) { | |
3946 | dev_err(asd->isp->dev, "did not find acc fw for removal\n"); | |
3947 | return; | |
3948 | } | |
3949 | *hd = fw->next; | |
3950 | fw->next = NULL; | |
3951 | ||
3952 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] | |
eaa399eb | 3953 | .update_pipe[pipe_id] = true; |
ad85094b MCC |
3954 | } |
3955 | ||
3956 | int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd) | |
3957 | { | |
3958 | struct atomisp_device *isp = asd->isp; | |
3959 | struct ia_css_pipe_config *pipe_config; | |
3960 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 3961 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
3962 | |
3963 | if (stream_env->acc_stream) { | |
3964 | if (stream_env->acc_stream_state == CSS_STREAM_STARTED) { | |
3965 | if (ia_css_stream_stop(stream_env->acc_stream) | |
41022d35 | 3966 | != 0) { |
ad85094b MCC |
3967 | dev_err(isp->dev, "stop acc_stream failed.\n"); |
3968 | return -EBUSY; | |
3969 | } | |
3970 | } | |
3971 | ||
3972 | if (ia_css_stream_destroy(stream_env->acc_stream) | |
41022d35 | 3973 | != 0) { |
ad85094b MCC |
3974 | dev_err(isp->dev, "destroy acc_stream failed.\n"); |
3975 | return -EBUSY; | |
3976 | } | |
3977 | stream_env->acc_stream = NULL; | |
3978 | } | |
3979 | ||
c01d5546 | 3980 | pipe_config = &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]; |
ad85094b MCC |
3981 | ia_css_pipe_config_defaults(pipe_config); |
3982 | asd->acc.acc_stages = kzalloc(MAX_ACC_STAGES * | |
eaa399eb | 3983 | sizeof(void *), GFP_KERNEL); |
ad85094b MCC |
3984 | if (!asd->acc.acc_stages) |
3985 | return -ENOMEM; | |
3986 | pipe_config->acc_stages = asd->acc.acc_stages; | |
3987 | pipe_config->mode = IA_CSS_PIPE_MODE_ACC; | |
3988 | pipe_config->num_acc_stages = 0; | |
3989 | ||
3990 | /* | |
3991 | * We delay the ACC pipeline creation to atomisp_css_start_acc_pipe, | |
3992 | * because pipe configuration will soon be changed by | |
3993 | * atomisp_css_load_acc_binary() | |
3994 | */ | |
3995 | return 0; | |
3996 | } | |
3997 | ||
3998 | int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd) | |
3999 | { | |
4000 | struct atomisp_device *isp = asd->isp; | |
4001 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 4002 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b | 4003 | struct ia_css_pipe_config *pipe_config = |
eaa399eb | 4004 | &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]; |
ad85094b MCC |
4005 | |
4006 | if (ia_css_pipe_create(pipe_config, | |
41022d35 | 4007 | &stream_env->pipes[IA_CSS_PIPE_ID_ACC]) != 0) { |
ad85094b | 4008 | dev_err(isp->dev, "%s: ia_css_pipe_create failed\n", |
eaa399eb | 4009 | __func__); |
ad85094b MCC |
4010 | return -EBADE; |
4011 | } | |
4012 | ||
4013 | memset(&stream_env->acc_stream_config, 0, | |
eaa399eb | 4014 | sizeof(struct ia_css_stream_config)); |
ad85094b | 4015 | if (ia_css_stream_create(&stream_env->acc_stream_config, 1, |
eaa399eb | 4016 | &stream_env->pipes[IA_CSS_PIPE_ID_ACC], |
41022d35 | 4017 | &stream_env->acc_stream) != 0) { |
ad85094b MCC |
4018 | dev_err(isp->dev, "%s: create acc_stream error.\n", __func__); |
4019 | return -EINVAL; | |
4020 | } | |
4021 | stream_env->acc_stream_state = CSS_STREAM_CREATED; | |
4022 | ||
4023 | init_completion(&asd->acc.acc_done); | |
4024 | asd->acc.pipeline = stream_env->pipes[IA_CSS_PIPE_ID_ACC]; | |
4025 | ||
4026 | atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, false); | |
4027 | ||
41022d35 | 4028 | if (ia_css_start_sp()) { |
ad85094b MCC |
4029 | dev_err(isp->dev, "start sp error.\n"); |
4030 | return -EIO; | |
4031 | } | |
4032 | ||
4033 | if (ia_css_stream_start(stream_env->acc_stream) | |
41022d35 | 4034 | != 0) { |
ad85094b MCC |
4035 | dev_err(isp->dev, "acc_stream start error.\n"); |
4036 | return -EIO; | |
4037 | } | |
4038 | ||
4039 | stream_env->acc_stream_state = CSS_STREAM_STARTED; | |
4040 | return 0; | |
4041 | } | |
4042 | ||
4043 | int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd) | |
4044 | { | |
4045 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 4046 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
4047 | if (stream_env->acc_stream_state == CSS_STREAM_STARTED) { |
4048 | ia_css_stream_stop(stream_env->acc_stream); | |
4049 | stream_env->acc_stream_state = CSS_STREAM_STOPPED; | |
4050 | } | |
4051 | return 0; | |
4052 | } | |
4053 | ||
4054 | void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd) | |
4055 | { | |
4056 | struct atomisp_stream_env *stream_env = | |
eaa399eb | 4057 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; |
ad85094b MCC |
4058 | if (stream_env->acc_stream) { |
4059 | if (ia_css_stream_destroy(stream_env->acc_stream) | |
41022d35 | 4060 | != 0) |
ad85094b | 4061 | dev_warn(asd->isp->dev, |
eaa399eb | 4062 | "destroy acc_stream failed.\n"); |
ad85094b MCC |
4063 | stream_env->acc_stream = NULL; |
4064 | } | |
4065 | ||
4066 | if (stream_env->pipes[IA_CSS_PIPE_ID_ACC]) { | |
4067 | if (ia_css_pipe_destroy(stream_env->pipes[IA_CSS_PIPE_ID_ACC]) | |
41022d35 | 4068 | != 0) |
ad85094b | 4069 | dev_warn(asd->isp->dev, |
eaa399eb | 4070 | "destroy ACC pipe failed.\n"); |
ad85094b MCC |
4071 | stream_env->pipes[IA_CSS_PIPE_ID_ACC] = NULL; |
4072 | stream_env->update_pipe[IA_CSS_PIPE_ID_ACC] = false; | |
4073 | ia_css_pipe_config_defaults( | |
eaa399eb | 4074 | &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]); |
ad85094b | 4075 | ia_css_pipe_extra_config_defaults( |
eaa399eb | 4076 | &stream_env->pipe_extra_configs[IA_CSS_PIPE_ID_ACC]); |
ad85094b MCC |
4077 | } |
4078 | asd->acc.pipeline = NULL; | |
4079 | ||
4080 | /* css 2.0 API limitation: ia_css_stop_sp() could be only called after | |
4081 | * destroy all pipes | |
4082 | */ | |
4083 | ia_css_stop_sp(); | |
4084 | ||
4085 | kfree(asd->acc.acc_stages); | |
4086 | asd->acc.acc_stages = NULL; | |
4087 | ||
4088 | atomisp_freq_scaling(asd->isp, ATOMISP_DFS_MODE_LOW, false); | |
4089 | } | |
4090 | ||
4091 | int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd, | |
c01d5546 | 4092 | struct ia_css_fw_info *fw, |
eaa399eb | 4093 | unsigned int index) |
ad85094b MCC |
4094 | { |
4095 | struct ia_css_pipe_config *pipe_config = | |
eaa399eb MCC |
4096 | &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] |
4097 | .pipe_configs[IA_CSS_PIPE_ID_ACC]; | |
ad85094b MCC |
4098 | |
4099 | if (index >= MAX_ACC_STAGES) { | |
4100 | dev_dbg(asd->isp->dev, "%s: index(%d) out of range\n", | |
eaa399eb | 4101 | __func__, index); |
ad85094b MCC |
4102 | return -ENOMEM; |
4103 | } | |
4104 | ||
4105 | pipe_config->acc_stages[index] = fw; | |
4106 | pipe_config->num_acc_stages = index + 1; | |
4107 | pipe_config->acc_num_execs = 1; | |
4108 | ||
4109 | return 0; | |
4110 | } | |
4111 | ||
4112 | static struct atomisp_sub_device *__get_atomisp_subdev( | |
eaa399eb MCC |
4113 | struct ia_css_pipe *css_pipe, |
4114 | struct atomisp_device *isp, | |
4115 | enum atomisp_input_stream_id *stream_id) | |
ad85094b MCC |
4116 | { |
4117 | int i, j, k; | |
4118 | struct atomisp_sub_device *asd; | |
4119 | struct atomisp_stream_env *stream_env; | |
4120 | ||
4121 | for (i = 0; i < isp->num_of_streams; i++) { | |
4122 | asd = &isp->asd[i]; | |
4123 | if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED && | |
4124 | !asd->acc.pipeline) | |
4125 | continue; | |
4126 | for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) { | |
4127 | stream_env = &asd->stream_env[j]; | |
4128 | for (k = 0; k < IA_CSS_PIPE_ID_NUM; k++) { | |
4129 | if (stream_env->pipes[k] && | |
eaa399eb MCC |
4130 | stream_env->pipes[k] == css_pipe) { |
4131 | *stream_id = j; | |
4132 | return asd; | |
ad85094b | 4133 | } |
eaa399eb | 4134 | } |
ad85094b MCC |
4135 | } |
4136 | } | |
4137 | ||
4138 | return NULL; | |
4139 | } | |
4140 | ||
4141 | int atomisp_css_isr_thread(struct atomisp_device *isp, | |
4142 | bool *frame_done_found, | |
4143 | bool *css_pipe_done) | |
4144 | { | |
4145 | enum atomisp_input_stream_id stream_id = 0; | |
4146 | struct atomisp_css_event current_event; | |
4147 | struct atomisp_sub_device *asd; | |
ad85094b | 4148 | bool reset_wdt_timer[MAX_STREAM_NUM] = {false}; |
ad85094b MCC |
4149 | int i; |
4150 | ||
4151 | while (!atomisp_css_dequeue_event(¤t_event)) { | |
4152 | if (current_event.event.type == | |
eaa399eb | 4153 | IA_CSS_EVENT_TYPE_FW_ASSERT) { |
ad85094b MCC |
4154 | /* |
4155 | * Received FW assertion signal, | |
4156 | * trigger WDT to recover | |
4157 | */ | |
eaa399eb MCC |
4158 | dev_err(isp->dev, |
4159 | "%s: ISP reports FW_ASSERT event! fw_assert_module_id %d fw_assert_line_no %d\n", | |
ad85094b MCC |
4160 | __func__, |
4161 | current_event.event.fw_assert_module_id, | |
4162 | current_event.event.fw_assert_line_no); | |
4163 | for (i = 0; i < isp->num_of_streams; i++) | |
4164 | atomisp_wdt_stop(&isp->asd[i], 0); | |
7ef17aa5 | 4165 | |
469a7306 | 4166 | if (!IS_ISP2401) |
7ef17aa5 MCC |
4167 | atomisp_wdt(&isp->asd[0].wdt); |
4168 | else | |
4169 | queue_work(isp->wdt_work_queue, &isp->wdt_work); | |
4170 | ||
ad85094b MCC |
4171 | return -EINVAL; |
4172 | } else if (current_event.event.type == IA_CSS_EVENT_TYPE_FW_WARNING) { | |
4173 | dev_warn(isp->dev, "%s: ISP reports warning, code is %d, exp_id %d\n", | |
eaa399eb MCC |
4174 | __func__, current_event.event.fw_warning, |
4175 | current_event.event.exp_id); | |
ad85094b MCC |
4176 | continue; |
4177 | } | |
4178 | ||
4179 | asd = __get_atomisp_subdev(current_event.event.pipe, | |
eaa399eb | 4180 | isp, &stream_id); |
ad85094b | 4181 | if (!asd) { |
c01d5546 | 4182 | if (current_event.event.type == IA_CSS_EVENT_TYPE_TIMER) |
ad85094b MCC |
4183 | dev_dbg(isp->dev, |
4184 | "event: Timer event."); | |
4185 | else | |
4186 | dev_warn(isp->dev, "%s:no subdev.event:%d", | |
eaa399eb MCC |
4187 | __func__, |
4188 | current_event.event.type); | |
ad85094b MCC |
4189 | continue; |
4190 | } | |
4191 | ||
4192 | atomisp_css_temp_pipe_to_pipe_id(asd, ¤t_event); | |
4193 | switch (current_event.event.type) { | |
c01d5546 | 4194 | case IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE: |
27b778c5 | 4195 | dev_dbg(isp->dev, "event: Output frame done"); |
ad85094b | 4196 | frame_done_found[asd->index] = true; |
c01d5546 | 4197 | atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, |
ad85094b | 4198 | current_event.pipe, true, stream_id); |
7ef17aa5 | 4199 | |
469a7306 | 4200 | if (!IS_ISP2401) |
7ef17aa5 MCC |
4201 | reset_wdt_timer[asd->index] = true; /* ISP running */ |
4202 | ||
ad85094b | 4203 | break; |
c01d5546 | 4204 | case IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE: |
27b778c5 | 4205 | dev_dbg(isp->dev, "event: Second output frame done"); |
ad85094b | 4206 | frame_done_found[asd->index] = true; |
c01d5546 | 4207 | atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME, |
ad85094b | 4208 | current_event.pipe, true, stream_id); |
7ef17aa5 | 4209 | |
469a7306 | 4210 | if (!IS_ISP2401) |
7ef17aa5 MCC |
4211 | reset_wdt_timer[asd->index] = true; /* ISP running */ |
4212 | ||
ad85094b | 4213 | break; |
c01d5546 | 4214 | case IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE: |
27b778c5 | 4215 | dev_dbg(isp->dev, "event: 3A stats frame done"); |
ad85094b | 4216 | atomisp_buf_done(asd, 0, |
c01d5546 | 4217 | IA_CSS_BUFFER_TYPE_3A_STATISTICS, |
ad85094b MCC |
4218 | current_event.pipe, |
4219 | false, stream_id); | |
4220 | break; | |
c01d5546 | 4221 | case IA_CSS_EVENT_TYPE_METADATA_DONE: |
27b778c5 | 4222 | dev_dbg(isp->dev, "event: metadata frame done"); |
ad85094b | 4223 | atomisp_buf_done(asd, 0, |
c01d5546 | 4224 | IA_CSS_BUFFER_TYPE_METADATA, |
ad85094b MCC |
4225 | current_event.pipe, |
4226 | false, stream_id); | |
4227 | break; | |
c01d5546 | 4228 | case IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE: |
27b778c5 | 4229 | dev_dbg(isp->dev, "event: VF output frame done"); |
ad85094b | 4230 | atomisp_buf_done(asd, 0, |
c01d5546 | 4231 | IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, |
ad85094b | 4232 | current_event.pipe, true, stream_id); |
7ef17aa5 | 4233 | |
469a7306 | 4234 | if (!IS_ISP2401) |
7ef17aa5 MCC |
4235 | reset_wdt_timer[asd->index] = true; /* ISP running */ |
4236 | ||
ad85094b | 4237 | break; |
c01d5546 | 4238 | case IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE: |
27b778c5 | 4239 | dev_dbg(isp->dev, "event: second VF output frame done"); |
ad85094b | 4240 | atomisp_buf_done(asd, 0, |
c01d5546 | 4241 | IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME, |
ad85094b | 4242 | current_event.pipe, true, stream_id); |
469a7306 | 4243 | if (!IS_ISP2401) |
7ef17aa5 MCC |
4244 | reset_wdt_timer[asd->index] = true; /* ISP running */ |
4245 | ||
ad85094b | 4246 | break; |
c01d5546 | 4247 | case IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE: |
27b778c5 | 4248 | dev_dbg(isp->dev, "event: dis stats frame done"); |
ad85094b | 4249 | atomisp_buf_done(asd, 0, |
c01d5546 | 4250 | IA_CSS_BUFFER_TYPE_DIS_STATISTICS, |
ad85094b MCC |
4251 | current_event.pipe, |
4252 | false, stream_id); | |
4253 | break; | |
c01d5546 | 4254 | case IA_CSS_EVENT_TYPE_PIPELINE_DONE: |
27b778c5 | 4255 | dev_dbg(isp->dev, "event: pipeline done"); |
ad85094b MCC |
4256 | css_pipe_done[asd->index] = true; |
4257 | break; | |
c01d5546 | 4258 | case IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE: |
27b778c5 | 4259 | dev_dbg(isp->dev, "event: acc stage done"); |
ad85094b MCC |
4260 | atomisp_acc_done(asd, current_event.event.fw_handle); |
4261 | break; | |
4262 | default: | |
4263 | dev_dbg(isp->dev, "unhandled css stored event: 0x%x\n", | |
eaa399eb | 4264 | current_event.event.type); |
ad85094b MCC |
4265 | break; |
4266 | } | |
4267 | } | |
7ef17aa5 | 4268 | |
469a7306 | 4269 | if (IS_ISP2401) |
7ef17aa5 MCC |
4270 | return 0; |
4271 | ||
3117ddda | 4272 | /* ISP2400: If there are no buffers queued then delete wdt timer. */ |
ad85094b MCC |
4273 | for (i = 0; i < isp->num_of_streams; i++) { |
4274 | asd = &isp->asd[i]; | |
4275 | if (!asd) | |
4276 | continue; | |
4277 | if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) | |
4278 | continue; | |
4279 | if (!atomisp_buffers_queued(asd)) | |
4280 | atomisp_wdt_stop(asd, false); | |
4281 | else if (reset_wdt_timer[i]) | |
eaa399eb | 4282 | /* SOF irq should not reset wdt timer. */ |
ad85094b | 4283 | atomisp_wdt_refresh(asd, |
eaa399eb | 4284 | ATOMISP_WDT_KEEP_CURRENT_DELAY); |
ad85094b | 4285 | } |
ad85094b MCC |
4286 | |
4287 | return 0; | |
4288 | } | |
4289 | ||
4290 | bool atomisp_css_valid_sof(struct atomisp_device *isp) | |
4291 | { | |
4292 | unsigned int i, j; | |
4293 | ||
4294 | /* Loop for each css stream */ | |
4295 | for (i = 0; i < isp->num_of_streams; i++) { | |
4296 | struct atomisp_sub_device *asd = &isp->asd[i]; | |
4297 | /* Loop for each css vc stream */ | |
4298 | for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) { | |
69a03e36 MCC |
4299 | if (!asd->stream_env[j].stream) |
4300 | continue; | |
4301 | ||
4302 | dev_dbg(isp->dev, | |
4303 | "stream #%d: mode: %d\n", j, | |
4304 | asd->stream_env[j].stream_config.mode); | |
4305 | if (asd->stream_env[j].stream_config.mode == | |
eaa399eb | 4306 | IA_CSS_INPUT_MODE_BUFFERED_SENSOR) |
ad85094b MCC |
4307 | return false; |
4308 | } | |
4309 | } | |
4310 | ||
4311 | return true; | |
4312 | } | |
4313 | ||
4314 | int atomisp_css_debug_dump_isp_binary(void) | |
4315 | { | |
4316 | ia_css_debug_dump_isp_binary(); | |
4317 | return 0; | |
4318 | } | |
4319 | ||
4320 | int atomisp_css_dump_sp_raw_copy_linecount(bool reduced) | |
4321 | { | |
4322 | sh_css_dump_sp_raw_copy_linecount(reduced); | |
4323 | return 0; | |
4324 | } | |
4325 | ||
0cd8726c MCC |
4326 | static const char * const fw_type_name[] = { |
4327 | [ia_css_sp_firmware] = "SP", | |
4328 | [ia_css_isp_firmware] = "ISP", | |
4329 | [ia_css_bootloader_firmware] = "BootLoader", | |
4330 | [ia_css_acc_firmware] = "accel", | |
4331 | }; | |
4332 | ||
4333 | static const char * const fw_acc_type_name[] = { | |
4334 | [IA_CSS_ACC_NONE] = "Normal", | |
4335 | [IA_CSS_ACC_OUTPUT] = "Accel stage on output", | |
4336 | [IA_CSS_ACC_VIEWFINDER] = "Accel stage on viewfinder", | |
4337 | [IA_CSS_ACC_STANDALONE] = "Stand-alone acceleration", | |
4338 | }; | |
4339 | ||
250977de | 4340 | int atomisp_css_dump_blob_infor(struct atomisp_device *isp) |
ad85094b MCC |
4341 | { |
4342 | struct ia_css_blob_descr *bd = sh_css_blob_info; | |
4343 | unsigned int i, nm = sh_css_num_binaries; | |
4344 | ||
4345 | if (nm == 0) | |
4346 | return -EPERM; | |
bdfe0beb | 4347 | if (!bd) |
ad85094b MCC |
4348 | return -EPERM; |
4349 | ||
0cd8726c MCC |
4350 | /* |
4351 | * The sh_css_load_firmware function discard the initial | |
4352 | * "SPS" binaries | |
4353 | */ | |
4354 | for (i = 0; i < sh_css_num_binaries - NUM_OF_SPS; i++) { | |
4355 | switch (bd[i].header.type) { | |
4356 | case ia_css_isp_firmware: | |
250977de | 4357 | dev_dbg(isp->dev, "Num%2d type %s (%s), binary id is %2d, name is %s\n", |
0cd8726c MCC |
4358 | i + NUM_OF_SPS, |
4359 | fw_type_name[bd[i].header.type], | |
4360 | fw_acc_type_name[bd[i].header.info.isp.type], | |
4361 | bd[i].header.info.isp.sp.id, | |
4362 | bd[i].name); | |
4363 | break; | |
4364 | default: | |
250977de | 4365 | dev_dbg(isp->dev, "Num%2d type %s, name is %s\n", |
0cd8726c MCC |
4366 | i + NUM_OF_SPS, fw_type_name[bd[i].header.type], |
4367 | bd[i].name); | |
4368 | } | |
4369 | } | |
ad85094b MCC |
4370 | |
4371 | return 0; | |
4372 | } | |
4373 | ||
4374 | void atomisp_css_set_isp_config_id(struct atomisp_sub_device *asd, | |
eaa399eb | 4375 | uint32_t isp_config_id) |
ad85094b MCC |
4376 | { |
4377 | asd->params.config.isp_config_id = isp_config_id; | |
4378 | } | |
4379 | ||
4380 | void atomisp_css_set_isp_config_applied_frame(struct atomisp_sub_device *asd, | |
c01d5546 | 4381 | struct ia_css_frame *output_frame) |
ad85094b MCC |
4382 | { |
4383 | asd->params.config.output_frame = output_frame; | |
4384 | } | |
4385 | ||
4386 | int atomisp_get_css_dbgfunc(void) | |
4387 | { | |
4388 | return dbg_func; | |
4389 | } | |
4390 | ||
4391 | int atomisp_set_css_dbgfunc(struct atomisp_device *isp, int opt) | |
4392 | { | |
4393 | int ret; | |
4394 | ||
4395 | ret = __set_css_print_env(isp, opt); | |
4396 | if (ret == 0) | |
4397 | dbg_func = opt; | |
4398 | ||
4399 | return ret; | |
4400 | } | |
bdfe0beb | 4401 | |
ad85094b MCC |
4402 | void atomisp_en_dz_capt_pipe(struct atomisp_sub_device *asd, bool enable) |
4403 | { | |
4404 | ia_css_en_dz_capt_pipe( | |
eaa399eb MCC |
4405 | asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, |
4406 | enable); | |
ad85094b MCC |
4407 | } |
4408 | ||
c01d5546 MCC |
4409 | struct ia_css_dvs_grid_info *atomisp_css_get_dvs_grid_info( |
4410 | struct ia_css_grid_info *grid_info) | |
ad85094b MCC |
4411 | { |
4412 | if (!grid_info) | |
4413 | return NULL; | |
4414 | ||
4415 | #ifdef IA_CSS_DVS_STAT_GRID_INFO_SUPPORTED | |
4416 | return &grid_info->dvs_grid.dvs_grid_info; | |
4417 | #else | |
4418 | return &grid_info->dvs_grid; | |
4419 | #endif | |
4420 | } |