1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2015, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15 
16 #include "hmm.h"
17 
18 #include "sh_css_sp.h"
19 
20 #if !defined(ISP2401)
21 #include "input_formatter.h"
22 #endif
23 
24 #include "dma.h"	/* N_DMA_CHANNEL_ID */
25 
26 #include "ia_css_buffer.h"
27 #include "ia_css_binary.h"
28 #include "sh_css_hrt.h"
29 #include "sh_css_defs.h"
30 #include "sh_css_internal.h"
31 #include "ia_css_control.h"
32 #include "ia_css_debug.h"
33 #include "ia_css_debug_pipe.h"
34 #include "ia_css_event_public.h"
35 #include "ia_css_mmu.h"
36 #include "ia_css_stream.h"
37 #include "ia_css_isp_param.h"
38 #include "sh_css_params.h"
39 #include "sh_css_legacy.h"
40 #include "ia_css_frame_comm.h"
41 #include "ia_css_isys.h"
42 
43 #include "gdc_device.h"				/* HRT_GDC_N */
44 
45 /*#include "sp.h"*/	/* host2sp_enqueue_frame_data() */
46 
47 
48 #include "assert_support.h"
49 
50 #include "sw_event_global.h"			/* Event IDs.*/
51 #include "ia_css_event.h"
52 #include "mmu_device.h"
53 #include "ia_css_spctrl.h"
54 #include "atomisp_internal.h"
55 
56 #ifndef offsetof
57 #define offsetof(T, x) ((unsigned int)&(((T *)0)->x))
58 #endif
59 
60 #define IA_CSS_INCLUDE_CONFIGURATIONS
61 #include "ia_css_isp_configs.h"
62 #define IA_CSS_INCLUDE_STATES
63 #include "ia_css_isp_states.h"
64 
65 #include "isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.h"
66 
67 struct sh_css_sp_group		sh_css_sp_group;
68 struct sh_css_sp_stage		sh_css_sp_stage;
69 struct sh_css_isp_stage		sh_css_isp_stage;
70 static struct sh_css_sp_output		sh_css_sp_output;
71 static struct sh_css_sp_per_frame_data per_frame_data;
72 
73 /* true if SP supports frame loop and host2sp_commands */
74 /* For the moment there is only code that sets this bool to true */
75 /* TODO: add code that sets this bool to false */
76 static bool sp_running;
77 
78 static int
79 set_output_frame_buffer(const struct ia_css_frame *frame,
80 			unsigned int idx);
81 
82 static void
83 sh_css_copy_buffer_attr_to_spbuffer(struct ia_css_buffer_sp *dest_buf,
84 				    const enum sh_css_queue_id queue_id,
85 				    const ia_css_ptr xmem_addr,
86 				    const enum ia_css_buffer_type buf_type);
87 
88 static void
89 initialize_frame_buffer_attribute(struct ia_css_buffer_sp *buf_attr);
90 
91 static void
92 initialize_stage_frames(struct ia_css_frames_sp *frames);
93 
94 /* This data is stored every frame */
95 void
96 store_sp_group_data(void)
97 {
98 	per_frame_data.sp_group_addr = sh_css_store_sp_group_to_ddr();
99 }
100 
101 static void
102 copy_isp_stage_to_sp_stage(void)
103 {
104 	/* [WW07.5]type casting will cause potential issues */
105 	sh_css_sp_stage.num_stripes = (uint8_t)
106 				      sh_css_isp_stage.binary_info.iterator.num_stripes;
107 	sh_css_sp_stage.row_stripes_height = (uint16_t)
108 					     sh_css_isp_stage.binary_info.iterator.row_stripes_height;
109 	sh_css_sp_stage.row_stripes_overlap_lines = (uint16_t)
110 		sh_css_isp_stage.binary_info.iterator.row_stripes_overlap_lines;
111 	sh_css_sp_stage.top_cropping = (uint16_t)
112 				       sh_css_isp_stage.binary_info.pipeline.top_cropping;
113 	/* moved to sh_css_sp_init_stage
114 	   sh_css_sp_stage.enable.vf_output =
115 	   sh_css_isp_stage.binary_info.enable.vf_veceven ||
116 	   sh_css_isp_stage.binary_info.num_output_pins > 1;
117 	*/
118 	sh_css_sp_stage.enable.sdis = sh_css_isp_stage.binary_info.enable.dis;
119 	sh_css_sp_stage.enable.s3a = sh_css_isp_stage.binary_info.enable.s3a;
120 }
121 
122 void
123 store_sp_stage_data(enum ia_css_pipe_id id, unsigned int pipe_num,
124 		    unsigned int stage)
125 {
126 	unsigned int thread_id;
127 
128 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
129 	copy_isp_stage_to_sp_stage();
130 	if (id != IA_CSS_PIPE_ID_COPY)
131 		sh_css_sp_stage.isp_stage_addr =
132 		    sh_css_store_isp_stage_to_ddr(pipe_num, stage);
133 	sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] =
134 	    sh_css_store_sp_stage_to_ddr(pipe_num, stage);
135 
136 	/* Clear for next frame */
137 	sh_css_sp_stage.program_input_circuit = false;
138 }
139 
140 static void
141 store_sp_per_frame_data(const struct ia_css_fw_info *fw)
142 {
143 	unsigned int HIVE_ADDR_sp_per_frame_data = 0;
144 
145 	assert(fw);
146 
147 	switch (fw->type) {
148 	case ia_css_sp_firmware:
149 		HIVE_ADDR_sp_per_frame_data = fw->info.sp.per_frame_data;
150 		break;
151 	case ia_css_acc_firmware:
152 		HIVE_ADDR_sp_per_frame_data = fw->info.acc.per_frame_data;
153 		break;
154 	case ia_css_isp_firmware:
155 		return;
156 	}
157 
158 	sp_dmem_store(SP0_ID,
159 		      (unsigned int)sp_address_of(sp_per_frame_data),
160 		      &per_frame_data,
161 		      sizeof(per_frame_data));
162 }
163 
164 static void
165 sh_css_store_sp_per_frame_data(enum ia_css_pipe_id pipe_id,
166 			       unsigned int pipe_num,
167 			       const struct ia_css_fw_info *sp_fw)
168 {
169 	if (!sp_fw)
170 		sp_fw = &sh_css_sp_fw;
171 
172 	store_sp_stage_data(pipe_id, pipe_num, 0);
173 	store_sp_group_data();
174 	store_sp_per_frame_data(sp_fw);
175 }
176 
177 #if SP_DEBUG != SP_DEBUG_NONE
178 
179 void
180 sh_css_sp_get_debug_state(struct sh_css_sp_debug_state *state)
181 {
182 	const struct ia_css_fw_info *fw = &sh_css_sp_fw;
183 	unsigned int HIVE_ADDR_sp_output = fw->info.sp.output;
184 	unsigned int i;
185 	unsigned int offset = (unsigned int)offsetof(struct sh_css_sp_output,
186 			      debug) / sizeof(int);
187 
188 	assert(state);
189 
190 	(void)HIVE_ADDR_sp_output; /* To get rid of warning in CRUN */
191 	for (i = 0; i < sizeof(*state) / sizeof(int); i++)
192 		((unsigned *)state)[i] = load_sp_array_uint(sp_output, i + offset);
193 }
194 
195 #endif
196 
197 void
198 sh_css_sp_start_binary_copy(unsigned int pipe_num,
199 			    struct ia_css_frame *out_frame,
200 			    unsigned int two_ppc)
201 {
202 	enum ia_css_pipe_id pipe_id;
203 	unsigned int thread_id;
204 	struct sh_css_sp_pipeline *pipe;
205 	u8 stage_num = 0;
206 
207 	assert(out_frame);
208 	pipe_id = IA_CSS_PIPE_ID_CAPTURE;
209 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
210 	pipe = &sh_css_sp_group.pipe[thread_id];
211 
212 	pipe->copy.bin.bytes_available = out_frame->data_bytes;
213 	pipe->num_stages = 1;
214 	pipe->pipe_id = pipe_id;
215 	pipe->pipe_num = pipe_num;
216 	pipe->thread_id = thread_id;
217 	pipe->pipe_config = 0x0; /* No parameters */
218 	pipe->pipe_qos_config = QOS_INVALID;
219 
220 	if (pipe->inout_port_config == 0) {
221 		SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config,
222 					    (uint8_t)SH_CSS_PORT_INPUT,
223 					    (uint8_t)SH_CSS_HOST_TYPE, 1);
224 		SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config,
225 					    (uint8_t)SH_CSS_PORT_OUTPUT,
226 					    (uint8_t)SH_CSS_HOST_TYPE, 1);
227 	}
228 	IA_CSS_LOG("pipe_id %d port_config %08x",
229 		   pipe->pipe_id, pipe->inout_port_config);
230 
231 #if !defined(ISP2401)
232 	sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc;
233 #else
234 	(void)two_ppc;
235 #endif
236 
237 	sh_css_sp_stage.num = stage_num;
238 	sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE;
239 	sh_css_sp_stage.func =
240 	    (unsigned int)IA_CSS_PIPELINE_BIN_COPY;
241 
242 	set_output_frame_buffer(out_frame, 0);
243 
244 	/* sp_bin_copy_init on the SP does not deal with dynamica/static yet */
245 	/* For now always update the dynamic data from out frames. */
246 	sh_css_store_sp_per_frame_data(pipe_id, pipe_num, &sh_css_sp_fw);
247 }
248 
249 static void
250 sh_css_sp_start_raw_copy(struct ia_css_frame *out_frame,
251 			 unsigned int pipe_num,
252 			 unsigned int two_ppc,
253 			 unsigned int max_input_width,
254 			 enum sh_css_pipe_config_override pipe_conf_override,
255 			 unsigned int if_config_index)
256 {
257 	enum ia_css_pipe_id pipe_id;
258 	unsigned int thread_id;
259 	u8 stage_num = 0;
260 	struct sh_css_sp_pipeline *pipe;
261 
262 	assert(out_frame);
263 
264 	{
265 		/*
266 		 * Clear sh_css_sp_stage for easy debugging.
267 		 * program_input_circuit must be saved as it is set outside
268 		 * this function.
269 		 */
270 		u8 program_input_circuit;
271 
272 		program_input_circuit = sh_css_sp_stage.program_input_circuit;
273 		memset(&sh_css_sp_stage, 0, sizeof(sh_css_sp_stage));
274 		sh_css_sp_stage.program_input_circuit = program_input_circuit;
275 	}
276 
277 	pipe_id = IA_CSS_PIPE_ID_COPY;
278 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
279 	pipe = &sh_css_sp_group.pipe[thread_id];
280 
281 	pipe->copy.raw.height	    = out_frame->frame_info.res.height;
282 	pipe->copy.raw.width	    = out_frame->frame_info.res.width;
283 	pipe->copy.raw.padded_width  = out_frame->frame_info.padded_width;
284 	pipe->copy.raw.raw_bit_depth = out_frame->frame_info.raw_bit_depth;
285 	pipe->copy.raw.max_input_width = max_input_width;
286 	pipe->num_stages = 1;
287 	pipe->pipe_id = pipe_id;
288 	/* TODO: next indicates from which queues parameters need to be
289 		 sampled, needs checking/improvement */
290 	if (pipe_conf_override == SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD)
291 		pipe->pipe_config =
292 		    (SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id);
293 	else
294 		pipe->pipe_config = pipe_conf_override;
295 
296 	pipe->pipe_qos_config = QOS_INVALID;
297 
298 	if (pipe->inout_port_config == 0) {
299 		SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config,
300 					    (uint8_t)SH_CSS_PORT_INPUT,
301 					    (uint8_t)SH_CSS_HOST_TYPE, 1);
302 		SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config,
303 					    (uint8_t)SH_CSS_PORT_OUTPUT,
304 					    (uint8_t)SH_CSS_HOST_TYPE, 1);
305 	}
306 	IA_CSS_LOG("pipe_id %d port_config %08x",
307 		   pipe->pipe_id, pipe->inout_port_config);
308 
309 #if !defined(ISP2401)
310 	sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc;
311 #else
312 	(void)two_ppc;
313 #endif
314 
315 	sh_css_sp_stage.num = stage_num;
316 	sh_css_sp_stage.xmem_bin_addr = 0x0;
317 	sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE;
318 	sh_css_sp_stage.func = (unsigned int)IA_CSS_PIPELINE_RAW_COPY;
319 	sh_css_sp_stage.if_config_index = (uint8_t)if_config_index;
320 	set_output_frame_buffer(out_frame, 0);
321 
322 	ia_css_debug_pipe_graph_dump_sp_raw_copy(out_frame);
323 }
324 
325 static void
326 sh_css_sp_start_isys_copy(struct ia_css_frame *out_frame,
327 			  unsigned int pipe_num, unsigned int max_input_width,
328 			  unsigned int if_config_index)
329 {
330 	enum ia_css_pipe_id pipe_id;
331 	unsigned int thread_id;
332 	u8 stage_num = 0;
333 	struct sh_css_sp_pipeline *pipe;
334 	enum sh_css_queue_id queue_id;
335 
336 	assert(out_frame);
337 
338 	{
339 		/*
340 		 * Clear sh_css_sp_stage for easy debugging.
341 		 * program_input_circuit must be saved as it is set outside
342 		 * this function.
343 		 */
344 		u8 program_input_circuit;
345 
346 		program_input_circuit = sh_css_sp_stage.program_input_circuit;
347 		memset(&sh_css_sp_stage, 0, sizeof(sh_css_sp_stage));
348 		sh_css_sp_stage.program_input_circuit = program_input_circuit;
349 	}
350 
351 	pipe_id = IA_CSS_PIPE_ID_COPY;
352 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
353 	pipe = &sh_css_sp_group.pipe[thread_id];
354 
355 	pipe->copy.raw.height		= out_frame->frame_info.res.height;
356 	pipe->copy.raw.width		= out_frame->frame_info.res.width;
357 	pipe->copy.raw.padded_width	= out_frame->frame_info.padded_width;
358 	pipe->copy.raw.raw_bit_depth	= out_frame->frame_info.raw_bit_depth;
359 	pipe->copy.raw.max_input_width	= max_input_width;
360 	pipe->num_stages		= 1;
361 	pipe->pipe_id			= pipe_id;
362 	pipe->pipe_config		= 0x0;	/* No parameters */
363 	pipe->pipe_qos_config		= QOS_INVALID;
364 
365 	initialize_stage_frames(&sh_css_sp_stage.frames);
366 	sh_css_sp_stage.num = stage_num;
367 	sh_css_sp_stage.xmem_bin_addr = 0x0;
368 	sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE;
369 	sh_css_sp_stage.func = (unsigned int)IA_CSS_PIPELINE_ISYS_COPY;
370 	sh_css_sp_stage.if_config_index = (uint8_t)if_config_index;
371 
372 	set_output_frame_buffer(out_frame, 0);
373 
374 	if (pipe->metadata.height > 0) {
375 		ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_METADATA, thread_id,
376 					       &queue_id);
377 		sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.metadata_buf,
378 						    queue_id, mmgr_EXCEPTION,
379 						    IA_CSS_BUFFER_TYPE_METADATA);
380 	}
381 
382 	ia_css_debug_pipe_graph_dump_sp_raw_copy(out_frame);
383 }
384 
385 unsigned int
386 sh_css_sp_get_binary_copy_size(void)
387 {
388 	const struct ia_css_fw_info *fw = &sh_css_sp_fw;
389 	unsigned int HIVE_ADDR_sp_output = fw->info.sp.output;
390 	unsigned int offset = (unsigned int)offsetof(struct sh_css_sp_output,
391 			      bin_copy_bytes_copied) / sizeof(int);
392 	(void)HIVE_ADDR_sp_output; /* To get rid of warning in CRUN */
393 	return load_sp_array_uint(sp_output, offset);
394 }
395 
396 unsigned int
397 sh_css_sp_get_sw_interrupt_value(unsigned int irq)
398 {
399 	const struct ia_css_fw_info *fw = &sh_css_sp_fw;
400 	unsigned int HIVE_ADDR_sp_output = fw->info.sp.output;
401 	unsigned int offset = (unsigned int)offsetof(struct sh_css_sp_output,
402 			      sw_interrupt_value)
403 			      / sizeof(int);
404 	(void)HIVE_ADDR_sp_output; /* To get rid of warning in CRUN */
405 	return load_sp_array_uint(sp_output, offset + irq);
406 }
407 
408 static void
409 sh_css_copy_buffer_attr_to_spbuffer(struct ia_css_buffer_sp *dest_buf,
410 				    const enum sh_css_queue_id queue_id,
411 				    const ia_css_ptr xmem_addr,
412 				    const enum ia_css_buffer_type buf_type)
413 {
414 	assert(buf_type < IA_CSS_NUM_BUFFER_TYPE);
415 	if (queue_id > SH_CSS_INVALID_QUEUE_ID) {
416 		/*
417 		 * value >=0 indicates that function init_frame_pointers()
418 		 * should use the dynamic data address
419 		 */
420 		assert(queue_id < SH_CSS_MAX_NUM_QUEUES);
421 
422 		/* Klocwork assumes assert can be disabled;
423 		   Since we can get there with any type, and it does not
424 		   know that frame_in->dynamic_data_index can only be set
425 		   for one of the types in the assert) it has to assume we
426 		   can get here for any type. however this could lead to an
427 		   out of bounds reference when indexing buf_type about 10
428 		   lines below. In order to satisfy KW an additional if
429 		   has been added. This one will always yield true.
430 		 */
431 		if ((queue_id < SH_CSS_MAX_NUM_QUEUES)) {
432 			dest_buf->buf_src.queue_id = queue_id;
433 		}
434 	} else {
435 		assert(xmem_addr != mmgr_EXCEPTION);
436 		dest_buf->buf_src.xmem_addr = xmem_addr;
437 	}
438 	dest_buf->buf_type = buf_type;
439 }
440 
441 static void
442 sh_css_copy_frame_to_spframe(struct ia_css_frame_sp *sp_frame_out,
443 			     const struct ia_css_frame *frame_in)
444 {
445 	assert(frame_in);
446 
447 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
448 			    "sh_css_copy_frame_to_spframe():\n");
449 
450 	sh_css_copy_buffer_attr_to_spbuffer(&sp_frame_out->buf_attr,
451 					    frame_in->dynamic_queue_id,
452 					    frame_in->data,
453 					    frame_in->buf_type);
454 
455 	ia_css_frame_info_to_frame_sp_info(&sp_frame_out->info, &frame_in->frame_info);
456 
457 	switch (frame_in->frame_info.format) {
458 	case IA_CSS_FRAME_FORMAT_RAW_PACKED:
459 	case IA_CSS_FRAME_FORMAT_RAW:
460 		sp_frame_out->planes.raw.offset = frame_in->planes.raw.offset;
461 		break;
462 	case IA_CSS_FRAME_FORMAT_RGB565:
463 	case IA_CSS_FRAME_FORMAT_RGBA888:
464 		sp_frame_out->planes.rgb.offset = frame_in->planes.rgb.offset;
465 		break;
466 	case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
467 		sp_frame_out->planes.planar_rgb.r.offset =
468 		    frame_in->planes.planar_rgb.r.offset;
469 		sp_frame_out->planes.planar_rgb.g.offset =
470 		    frame_in->planes.planar_rgb.g.offset;
471 		sp_frame_out->planes.planar_rgb.b.offset =
472 		    frame_in->planes.planar_rgb.b.offset;
473 		break;
474 	case IA_CSS_FRAME_FORMAT_YUYV:
475 	case IA_CSS_FRAME_FORMAT_UYVY:
476 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
477 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
478 	case IA_CSS_FRAME_FORMAT_YUV_LINE:
479 		sp_frame_out->planes.yuyv.offset = frame_in->planes.yuyv.offset;
480 		break;
481 	case IA_CSS_FRAME_FORMAT_NV11:
482 	case IA_CSS_FRAME_FORMAT_NV12:
483 	case IA_CSS_FRAME_FORMAT_NV12_16:
484 	case IA_CSS_FRAME_FORMAT_NV12_TILEY:
485 	case IA_CSS_FRAME_FORMAT_NV21:
486 	case IA_CSS_FRAME_FORMAT_NV16:
487 	case IA_CSS_FRAME_FORMAT_NV61:
488 		sp_frame_out->planes.nv.y.offset =
489 		    frame_in->planes.nv.y.offset;
490 		sp_frame_out->planes.nv.uv.offset =
491 		    frame_in->planes.nv.uv.offset;
492 		break;
493 	case IA_CSS_FRAME_FORMAT_YUV420:
494 	case IA_CSS_FRAME_FORMAT_YUV422:
495 	case IA_CSS_FRAME_FORMAT_YUV444:
496 	case IA_CSS_FRAME_FORMAT_YUV420_16:
497 	case IA_CSS_FRAME_FORMAT_YUV422_16:
498 	case IA_CSS_FRAME_FORMAT_YV12:
499 	case IA_CSS_FRAME_FORMAT_YV16:
500 		sp_frame_out->planes.yuv.y.offset =
501 		    frame_in->planes.yuv.y.offset;
502 		sp_frame_out->planes.yuv.u.offset =
503 		    frame_in->planes.yuv.u.offset;
504 		sp_frame_out->planes.yuv.v.offset =
505 		    frame_in->planes.yuv.v.offset;
506 		break;
507 	case IA_CSS_FRAME_FORMAT_QPLANE6:
508 		sp_frame_out->planes.plane6.r.offset =
509 		    frame_in->planes.plane6.r.offset;
510 		sp_frame_out->planes.plane6.r_at_b.offset =
511 		    frame_in->planes.plane6.r_at_b.offset;
512 		sp_frame_out->planes.plane6.gr.offset =
513 		    frame_in->planes.plane6.gr.offset;
514 		sp_frame_out->planes.plane6.gb.offset =
515 		    frame_in->planes.plane6.gb.offset;
516 		sp_frame_out->planes.plane6.b.offset =
517 		    frame_in->planes.plane6.b.offset;
518 		sp_frame_out->planes.plane6.b_at_r.offset =
519 		    frame_in->planes.plane6.b_at_r.offset;
520 		break;
521 	case IA_CSS_FRAME_FORMAT_BINARY_8:
522 		sp_frame_out->planes.binary.data.offset =
523 		    frame_in->planes.binary.data.offset;
524 		break;
525 	default:
526 		/* This should not happen, but in case it does,
527 		 * nullify the planes
528 		 */
529 		memset(&sp_frame_out->planes, 0, sizeof(sp_frame_out->planes));
530 		break;
531 	}
532 }
533 
534 static int
535 set_input_frame_buffer(const struct ia_css_frame *frame)
536 {
537 	if (!frame)
538 		return -EINVAL;
539 
540 	switch (frame->frame_info.format) {
541 	case IA_CSS_FRAME_FORMAT_QPLANE6:
542 	case IA_CSS_FRAME_FORMAT_YUV420_16:
543 	case IA_CSS_FRAME_FORMAT_RAW_PACKED:
544 	case IA_CSS_FRAME_FORMAT_RAW:
545 	case IA_CSS_FRAME_FORMAT_YUV420:
546 	case IA_CSS_FRAME_FORMAT_YUYV:
547 	case IA_CSS_FRAME_FORMAT_YUV_LINE:
548 	case IA_CSS_FRAME_FORMAT_NV12:
549 	case IA_CSS_FRAME_FORMAT_NV12_16:
550 	case IA_CSS_FRAME_FORMAT_NV12_TILEY:
551 	case IA_CSS_FRAME_FORMAT_NV21:
552 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
553 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
554 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_10:
555 		break;
556 	default:
557 		return -EINVAL;
558 	}
559 	sh_css_copy_frame_to_spframe(&sh_css_sp_stage.frames.in, frame);
560 
561 	return 0;
562 }
563 
564 static int
565 set_output_frame_buffer(const struct ia_css_frame *frame,
566 			unsigned int idx)
567 {
568 	if (!frame)
569 		return -EINVAL;
570 
571 	switch (frame->frame_info.format) {
572 	case IA_CSS_FRAME_FORMAT_YUV420:
573 	case IA_CSS_FRAME_FORMAT_YUV422:
574 	case IA_CSS_FRAME_FORMAT_YUV444:
575 	case IA_CSS_FRAME_FORMAT_YV12:
576 	case IA_CSS_FRAME_FORMAT_YV16:
577 	case IA_CSS_FRAME_FORMAT_YUV420_16:
578 	case IA_CSS_FRAME_FORMAT_YUV422_16:
579 	case IA_CSS_FRAME_FORMAT_NV11:
580 	case IA_CSS_FRAME_FORMAT_NV12:
581 	case IA_CSS_FRAME_FORMAT_NV12_16:
582 	case IA_CSS_FRAME_FORMAT_NV12_TILEY:
583 	case IA_CSS_FRAME_FORMAT_NV16:
584 	case IA_CSS_FRAME_FORMAT_NV21:
585 	case IA_CSS_FRAME_FORMAT_NV61:
586 	case IA_CSS_FRAME_FORMAT_YUYV:
587 	case IA_CSS_FRAME_FORMAT_UYVY:
588 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
589 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
590 	case IA_CSS_FRAME_FORMAT_YUV_LINE:
591 	case IA_CSS_FRAME_FORMAT_RGB565:
592 	case IA_CSS_FRAME_FORMAT_RGBA888:
593 	case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
594 	case IA_CSS_FRAME_FORMAT_RAW:
595 	case IA_CSS_FRAME_FORMAT_RAW_PACKED:
596 	case IA_CSS_FRAME_FORMAT_QPLANE6:
597 	case IA_CSS_FRAME_FORMAT_BINARY_8:
598 		break;
599 	default:
600 		return -EINVAL;
601 	}
602 	sh_css_copy_frame_to_spframe(&sh_css_sp_stage.frames.out[idx], frame);
603 	return 0;
604 }
605 
606 static int
607 set_view_finder_buffer(const struct ia_css_frame *frame)
608 {
609 	if (!frame)
610 		return -EINVAL;
611 
612 	switch (frame->frame_info.format) {
613 	/* the dual output pin */
614 	case IA_CSS_FRAME_FORMAT_NV12:
615 	case IA_CSS_FRAME_FORMAT_NV12_16:
616 	case IA_CSS_FRAME_FORMAT_NV21:
617 	case IA_CSS_FRAME_FORMAT_YUYV:
618 	case IA_CSS_FRAME_FORMAT_UYVY:
619 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
620 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
621 	case IA_CSS_FRAME_FORMAT_YUV420:
622 	case IA_CSS_FRAME_FORMAT_YV12:
623 	case IA_CSS_FRAME_FORMAT_NV12_TILEY:
624 
625 	/* for vf_veceven */
626 	case IA_CSS_FRAME_FORMAT_YUV_LINE:
627 		break;
628 	default:
629 		return -EINVAL;
630 	}
631 
632 	sh_css_copy_frame_to_spframe(&sh_css_sp_stage.frames.out_vf, frame);
633 	return 0;
634 }
635 
636 #if !defined(ISP2401)
637 void sh_css_sp_set_if_configs(
638     const input_formatter_cfg_t	*config_a,
639     const input_formatter_cfg_t	*config_b,
640     const uint8_t		if_config_index
641 )
642 {
643 	assert(if_config_index < SH_CSS_MAX_IF_CONFIGS);
644 	assert(config_a);
645 
646 	sh_css_sp_group.config.input_formatter.set[if_config_index].config_a =
647 	    *config_a;
648 	sh_css_sp_group.config.input_formatter.a_changed = true;
649 
650 	if (config_b) {
651 		sh_css_sp_group.config.input_formatter.set[if_config_index].config_b =
652 		    *config_b;
653 		sh_css_sp_group.config.input_formatter.b_changed = true;
654 	}
655 
656 	return;
657 }
658 #endif
659 
660 #if !defined(ISP2401)
661 void
662 sh_css_sp_program_input_circuit(int fmt_type,
663 				int ch_id,
664 				enum ia_css_input_mode input_mode)
665 {
666 	sh_css_sp_group.config.input_circuit.no_side_band = false;
667 	sh_css_sp_group.config.input_circuit.fmt_type     = fmt_type;
668 	sh_css_sp_group.config.input_circuit.ch_id	      = ch_id;
669 	sh_css_sp_group.config.input_circuit.input_mode   = input_mode;
670 	/*
671 	 * The SP group is only loaded at SP boot time and is read once
672 	 * change flags as "input_circuit_cfg_changed" must be reset on the SP
673 	 */
674 	sh_css_sp_group.config.input_circuit_cfg_changed = true;
675 	sh_css_sp_stage.program_input_circuit = true;
676 }
677 #endif
678 
679 #if !defined(ISP2401)
680 void
681 sh_css_sp_configure_sync_gen(int width, int height,
682 			     int hblank_cycles,
683 			     int vblank_cycles)
684 {
685 	sh_css_sp_group.config.sync_gen.width	       = width;
686 	sh_css_sp_group.config.sync_gen.height	       = height;
687 	sh_css_sp_group.config.sync_gen.hblank_cycles = hblank_cycles;
688 	sh_css_sp_group.config.sync_gen.vblank_cycles = vblank_cycles;
689 }
690 
691 void
692 sh_css_sp_configure_tpg(int x_mask,
693 			int y_mask,
694 			int x_delta,
695 			int y_delta,
696 			int xy_mask)
697 {
698 	sh_css_sp_group.config.tpg.x_mask  = x_mask;
699 	sh_css_sp_group.config.tpg.y_mask  = y_mask;
700 	sh_css_sp_group.config.tpg.x_delta = x_delta;
701 	sh_css_sp_group.config.tpg.y_delta = y_delta;
702 	sh_css_sp_group.config.tpg.xy_mask = xy_mask;
703 }
704 
705 void
706 sh_css_sp_configure_prbs(int seed)
707 {
708 	sh_css_sp_group.config.prbs.seed = seed;
709 }
710 #endif
711 
712 void
713 sh_css_sp_configure_enable_raw_pool_locking(bool lock_all)
714 {
715 	sh_css_sp_group.config.enable_raw_pool_locking = true;
716 	sh_css_sp_group.config.lock_all = lock_all;
717 }
718 
719 void
720 sh_css_sp_enable_isys_event_queue(bool enable)
721 {
722 	sh_css_sp_group.config.enable_isys_event_queue = enable;
723 }
724 
725 void
726 sh_css_sp_set_disable_continuous_viewfinder(bool flag)
727 {
728 	sh_css_sp_group.config.disable_cont_vf = flag;
729 }
730 
731 static int
732 sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args)
733 {
734 	int err = 0;
735 	int i;
736 
737 	assert(args);
738 
739 	if (args->in_frame)
740 		err = set_input_frame_buffer(args->in_frame);
741 	if (!err && args->out_vf_frame)
742 		err = set_view_finder_buffer(args->out_vf_frame);
743 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
744 		if (!err && args->out_frame[i])
745 			err = set_output_frame_buffer(args->out_frame[i], i);
746 	}
747 
748 	/* we don't pass this error back to the upper layer, so we add a assert here
749 	   because we actually hit the error here but it still works by accident... */
750 	if (err) assert(false);
751 	return err;
752 }
753 
754 static void
755 sh_css_sp_init_group(bool two_ppc,
756 		     enum atomisp_input_format input_format,
757 		     bool no_isp_sync,
758 		     uint8_t if_config_index)
759 {
760 #if !defined(ISP2401)
761 	sh_css_sp_group.config.input_formatter.isp_2ppc = two_ppc;
762 #else
763 	(void)two_ppc;
764 #endif
765 
766 	sh_css_sp_group.config.no_isp_sync = (uint8_t)no_isp_sync;
767 	/* decide whether the frame is processed online or offline */
768 	if (if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED) return;
769 #if !defined(ISP2401)
770 	assert(if_config_index < SH_CSS_MAX_IF_CONFIGS);
771 	sh_css_sp_group.config.input_formatter.set[if_config_index].stream_format =
772 	    input_format;
773 #else
774 	(void)input_format;
775 #endif
776 }
777 
778 void
779 sh_css_stage_write_binary_info(struct ia_css_binary_info *info)
780 {
781 	assert(info);
782 	sh_css_isp_stage.binary_info = *info;
783 }
784 
785 static int
786 copy_isp_mem_if_to_ddr(struct ia_css_binary *binary)
787 {
788 	int err;
789 
790 	err = ia_css_isp_param_copy_isp_mem_if_to_ddr(
791 	    &binary->css_params,
792 	    &binary->mem_params,
793 	    IA_CSS_PARAM_CLASS_CONFIG);
794 	if (err)
795 		return err;
796 	err = ia_css_isp_param_copy_isp_mem_if_to_ddr(
797 	    &binary->css_params,
798 	    &binary->mem_params,
799 	    IA_CSS_PARAM_CLASS_STATE);
800 	if (err)
801 		return err;
802 	return 0;
803 }
804 
805 static bool
806 is_sp_stage(struct ia_css_pipeline_stage *stage)
807 {
808 	assert(stage);
809 	return stage->sp_func != IA_CSS_PIPELINE_NO_FUNC;
810 }
811 
812 static int configure_isp_from_args(const struct sh_css_sp_pipeline *pipeline,
813 				   const struct ia_css_binary      *binary,
814 				   const struct sh_css_binary_args *args,
815 				   bool				   two_ppc,
816 				   bool				   deinterleaved)
817 {
818 	int ret;
819 
820 	ret = ia_css_fpn_configure(binary,  &binary->in_frame_info);
821 	if (ret)
822 		return ret;
823 	ret = ia_css_crop_configure(binary, ia_css_frame_get_info(args->delay_frames[0]));
824 	if (ret)
825 		return ret;
826 	ret = ia_css_qplane_configure(pipeline, binary, &binary->in_frame_info);
827 	if (ret)
828 		return ret;
829 	ret = ia_css_output0_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
830 	if (ret)
831 		return ret;
832 	ret = ia_css_output1_configure(binary, ia_css_frame_get_info(args->out_vf_frame));
833 	if (ret)
834 		return ret;
835 	ret = ia_css_copy_output_configure(binary, args->copy_output);
836 	if (ret)
837 		return ret;
838 	ret = ia_css_output0_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
839 	if (ret)
840 		return ret;
841 	ret = ia_css_iterator_configure(binary, ia_css_frame_get_info(args->in_frame));
842 	if (ret)
843 		return ret;
844 	ret = ia_css_dvs_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
845 	if (ret)
846 		return ret;
847 	ret = ia_css_output_configure(binary, ia_css_frame_get_info(args->out_frame[0]));
848 	if (ret)
849 		return ret;
850 	ret = ia_css_raw_configure(pipeline, binary, ia_css_frame_get_info(args->in_frame),
851 				   &binary->in_frame_info, two_ppc, deinterleaved);
852 	if (ret)
853 		return ret;
854 
855 	/*
856 	 * FIXME: args->delay_frames can be NULL here
857 	 *
858 	 * Somehow, the driver at the Intel Atom Yocto tree doesn't seem to
859 	 * suffer from the same issue.
860 	 *
861 	 * Anyway, the function below should now handle a NULL delay_frames
862 	 * without crashing, but the pipeline should likely be built without
863 	 * adding it at the first place (or there are a hidden bug somewhere)
864 	 */
865 	ret = ia_css_ref_configure(binary, args->delay_frames, pipeline->dvs_frame_delay);
866 	if (ret)
867 		return ret;
868 	ret = ia_css_tnr_configure(binary, args->tnr_frames);
869 	if (ret)
870 		return ret;
871 	return ia_css_bayer_io_config(binary, args);
872 }
873 
874 static void
875 initialize_isp_states(const struct ia_css_binary *binary)
876 {
877 	unsigned int i;
878 
879 	if (!binary->info->mem_offsets.offsets.state)
880 		return;
881 	for (i = 0; i < IA_CSS_NUM_STATE_IDS; i++) {
882 		ia_css_kernel_init_state[i](binary);
883 	}
884 }
885 
886 static void
887 initialize_frame_buffer_attribute(struct ia_css_buffer_sp *buf_attr)
888 {
889 	buf_attr->buf_src.queue_id = SH_CSS_INVALID_QUEUE_ID;
890 	buf_attr->buf_type = IA_CSS_BUFFER_TYPE_INVALID;
891 }
892 
893 static void
894 initialize_stage_frames(struct ia_css_frames_sp *frames)
895 {
896 	unsigned int i;
897 
898 	initialize_frame_buffer_attribute(&frames->in.buf_attr);
899 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
900 		initialize_frame_buffer_attribute(&frames->out[i].buf_attr);
901 	}
902 	initialize_frame_buffer_attribute(&frames->out_vf.buf_attr);
903 	initialize_frame_buffer_attribute(&frames->s3a_buf);
904 	initialize_frame_buffer_attribute(&frames->dvs_buf);
905 	initialize_frame_buffer_attribute(&frames->metadata_buf);
906 }
907 
908 static int
909 sh_css_sp_init_stage(struct ia_css_binary *binary,
910 		     const char *binary_name,
911 		     const struct ia_css_blob_info *blob_info,
912 		     const struct sh_css_binary_args *args,
913 		     unsigned int pipe_num,
914 		     unsigned int stage,
915 		     bool xnr,
916 		     const struct ia_css_isp_param_css_segments *isp_mem_if,
917 		     unsigned int if_config_index,
918 		     bool two_ppc)
919 {
920 	const struct ia_css_binary_xinfo *xinfo;
921 	const struct ia_css_binary_info  *info;
922 	int err = 0;
923 	int i;
924 	struct ia_css_pipe *pipe = NULL;
925 	unsigned int thread_id;
926 	enum sh_css_queue_id queue_id;
927 	bool continuous = sh_css_continuous_is_enabled((uint8_t)pipe_num);
928 
929 	assert(binary);
930 	assert(blob_info);
931 	assert(args);
932 	assert(isp_mem_if);
933 
934 	xinfo = binary->info;
935 	info  = &xinfo->sp;
936 	{
937 		/*
938 		 * Clear sh_css_sp_stage for easy debugging.
939 		 * program_input_circuit must be saved as it is set outside
940 		 * this function.
941 		 */
942 		u8 program_input_circuit;
943 
944 		program_input_circuit = sh_css_sp_stage.program_input_circuit;
945 		memset(&sh_css_sp_stage, 0, sizeof(sh_css_sp_stage));
946 		sh_css_sp_stage.program_input_circuit = (uint8_t)program_input_circuit;
947 	}
948 
949 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
950 
951 	if (!info) {
952 		sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] = mmgr_NULL;
953 		return 0;
954 	}
955 
956 	if (IS_ISP2401)
957 		sh_css_sp_stage.deinterleaved = 0;
958 	else
959 		sh_css_sp_stage.deinterleaved = ((stage == 0) && continuous);
960 
961 	initialize_stage_frames(&sh_css_sp_stage.frames);
962 	/*
963 	 * TODO: Make the Host dynamically determine
964 	 * the stage type.
965 	 */
966 	sh_css_sp_stage.stage_type = SH_CSS_ISP_STAGE_TYPE;
967 	sh_css_sp_stage.num		= (uint8_t)stage;
968 	sh_css_sp_stage.isp_online	= (uint8_t)binary->online;
969 	sh_css_sp_stage.isp_copy_vf     = (uint8_t)args->copy_vf;
970 	sh_css_sp_stage.isp_copy_output = (uint8_t)args->copy_output;
971 	sh_css_sp_stage.enable.vf_output = (args->out_vf_frame != NULL);
972 
973 	/* Copy the frame infos first, to be overwritten by the frames,
974 	   if these are present.
975 	*/
976 	sh_css_sp_stage.frames.effective_in_res.width = binary->effective_in_frame_res.width;
977 	sh_css_sp_stage.frames.effective_in_res.height = binary->effective_in_frame_res.height;
978 
979 	ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.in.info,
980 					   &binary->in_frame_info);
981 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
982 		ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.out[i].info,
983 						   &binary->out_frame_info[i]);
984 	}
985 	ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.internal_frame_info,
986 					   &binary->internal_frame_info);
987 	sh_css_sp_stage.dvs_envelope.width    = binary->dvs_envelope.width;
988 	sh_css_sp_stage.dvs_envelope.height   = binary->dvs_envelope.height;
989 	sh_css_sp_stage.isp_pipe_version      = (uint8_t)info->pipeline.isp_pipe_version;
990 	sh_css_sp_stage.isp_deci_log_factor   = (uint8_t)binary->deci_factor_log2;
991 	sh_css_sp_stage.isp_vf_downscale_bits = (uint8_t)binary->vf_downscale_log2;
992 
993 	sh_css_sp_stage.if_config_index = (uint8_t)if_config_index;
994 
995 	sh_css_sp_stage.sp_enable_xnr = (uint8_t)xnr;
996 	sh_css_sp_stage.xmem_bin_addr = xinfo->xmem_addr;
997 	sh_css_sp_stage.xmem_map_addr = sh_css_params_ddr_address_map();
998 	sh_css_isp_stage.blob_info = *blob_info;
999 	sh_css_stage_write_binary_info((struct ia_css_binary_info *)info);
1000 
1001 	/* Make sure binary name is smaller than allowed string size */
1002 	assert(strlen(binary_name) < SH_CSS_MAX_BINARY_NAME - 1);
1003 	strscpy(sh_css_isp_stage.binary_name, binary_name, SH_CSS_MAX_BINARY_NAME);
1004 	sh_css_isp_stage.mem_initializers = *isp_mem_if;
1005 
1006 	/*
1007 	 * Even when a stage does not need uds and does not params,
1008 	 * ia_css_uds_sp_scale_params() seems to be called (needs
1009 	 * further investigation). This function can not deal with
1010 	 * dx, dy = {0, 0}
1011 	 */
1012 
1013 	err = sh_css_sp_write_frame_pointers(args);
1014 	/* TODO: move it to a better place */
1015 	if (binary->info->sp.enable.s3a) {
1016 		ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_3A_STATISTICS, thread_id,
1017 					       &queue_id);
1018 		sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.s3a_buf, queue_id,
1019 						    mmgr_EXCEPTION,
1020 						    IA_CSS_BUFFER_TYPE_3A_STATISTICS);
1021 	}
1022 	if (binary->info->sp.enable.dis) {
1023 		ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_DIS_STATISTICS, thread_id,
1024 					       &queue_id);
1025 		sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.dvs_buf, queue_id,
1026 						    mmgr_EXCEPTION,
1027 						    IA_CSS_BUFFER_TYPE_DIS_STATISTICS);
1028 	}
1029 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_METADATA, thread_id, &queue_id);
1030 	sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.metadata_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_METADATA);
1031 	if (err)
1032 		return err;
1033 
1034 #ifdef ISP2401
1035 	pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num);
1036 	if (!pipe)
1037 		return -EINVAL;
1038 
1039 	if (args->in_frame)
1040 		ia_css_get_crop_offsets(pipe, &args->in_frame->frame_info);
1041 	else
1042 		ia_css_get_crop_offsets(pipe, &binary->in_frame_info);
1043 #else
1044 	(void)pipe; /*avoid build warning*/
1045 #endif
1046 
1047 	err = configure_isp_from_args(&sh_css_sp_group.pipe[thread_id],
1048 				      binary, args, two_ppc, sh_css_sp_stage.deinterleaved);
1049 	if (err)
1050 		return err;
1051 
1052 	initialize_isp_states(binary);
1053 
1054 	/* we do this only for preview pipe because in fill_binary_info function
1055 	 * we assign vf_out res to out res, but for ISP internal processing, we need
1056 	 * the original out res. for video pipe, it has two output pins --- out and
1057 	 * vf_out, so it can keep these two resolutions already. */
1058 	if (binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW &&
1059 	    (binary->vf_downscale_log2 > 0)) {
1060 		/* TODO: Remove this after preview output decimation is fixed
1061 		 * by configuring out&vf info fiels properly */
1062 		sh_css_sp_stage.frames.out[0].info.padded_width
1063 		<<= binary->vf_downscale_log2;
1064 		sh_css_sp_stage.frames.out[0].info.res.width
1065 		<<= binary->vf_downscale_log2;
1066 		sh_css_sp_stage.frames.out[0].info.res.height
1067 		<<= binary->vf_downscale_log2;
1068 	}
1069 	err = copy_isp_mem_if_to_ddr(binary);
1070 	if (err)
1071 		return err;
1072 
1073 	return 0;
1074 }
1075 
1076 static int
1077 sp_init_stage(struct ia_css_pipeline_stage *stage,
1078 	      unsigned int pipe_num,
1079 	      bool xnr,
1080 	      unsigned int if_config_index,
1081 	      bool two_ppc)
1082 {
1083 	struct ia_css_binary *binary;
1084 	const struct ia_css_fw_info *firmware;
1085 	const struct sh_css_binary_args *args;
1086 	unsigned int stage_num;
1087 	/*
1088 	 * Initialiser required because of the "else" path below.
1089 	 * Is this a valid path ?
1090 	 */
1091 	const char *binary_name = "";
1092 	const struct ia_css_binary_xinfo *info = NULL;
1093 	/* note: the var below is made static as it is quite large;
1094 	   if it is not static it ends up on the stack which could
1095 	   cause issues for drivers
1096 	*/
1097 	static struct ia_css_binary tmp_binary;
1098 	const struct ia_css_blob_info *blob_info = NULL;
1099 	struct ia_css_isp_param_css_segments isp_mem_if;
1100 	/* LA: should be ia_css_data, should not contain host pointer.
1101 	   However, CSS/DDR pointer is not available yet.
1102 	   Hack is to store it in params->ddr_ptrs and then copy it late in the SP just before vmem init.
1103 	   TODO: Call this after CSS/DDR allocation and store that pointer.
1104 	   Best is to allocate it at stage creation time together with host pointer.
1105 	   Remove vmem from params.
1106 	*/
1107 	struct ia_css_isp_param_css_segments *mem_if = &isp_mem_if;
1108 
1109 	int err = 0;
1110 
1111 	assert(stage);
1112 
1113 	binary = stage->binary;
1114 	firmware = stage->firmware;
1115 	args = &stage->args;
1116 	stage_num = stage->stage_num;
1117 
1118 	if (binary) {
1119 		info = binary->info;
1120 		binary_name = (const char *)(info->blob->name);
1121 		blob_info = &info->blob->header.blob;
1122 		ia_css_init_memory_interface(mem_if, &binary->mem_params, &binary->css_params);
1123 	} else if (firmware) {
1124 		const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL};
1125 
1126 		if (args->out_frame[0])
1127 			out_infos[0] = &args->out_frame[0]->frame_info;
1128 		info = &firmware->info.isp;
1129 		ia_css_binary_fill_info(info, false, false,
1130 					ATOMISP_INPUT_FORMAT_RAW_10,
1131 					ia_css_frame_get_info(args->in_frame),
1132 					NULL,
1133 					out_infos,
1134 					ia_css_frame_get_info(args->out_vf_frame),
1135 					&tmp_binary,
1136 					NULL,
1137 					-1, true);
1138 		binary = &tmp_binary;
1139 		binary->info = info;
1140 		binary_name = IA_CSS_EXT_ISP_PROG_NAME(firmware);
1141 		blob_info = &firmware->blob;
1142 		mem_if = (struct ia_css_isp_param_css_segments *)&firmware->mem_initializers;
1143 	} else {
1144 		/* SP stage */
1145 		assert(stage->sp_func != IA_CSS_PIPELINE_NO_FUNC);
1146 		/* binary and blob_info are now NULL.
1147 		   These will be passed to sh_css_sp_init_stage
1148 		   and dereferenced there, so passing a NULL
1149 		   pointer is no good. return an error */
1150 		return -EINVAL;
1151 	}
1152 
1153 	err = sh_css_sp_init_stage(binary,
1154 				   (const char *)binary_name,
1155 				   blob_info,
1156 				   args,
1157 				   pipe_num,
1158 				   stage_num,
1159 				   xnr,
1160 				   mem_if,
1161 				   if_config_index,
1162 				   two_ppc);
1163 	return err;
1164 }
1165 
1166 static void
1167 sp_init_sp_stage(struct ia_css_pipeline_stage *stage,
1168 		 unsigned int pipe_num,
1169 		 bool two_ppc,
1170 		 enum sh_css_pipe_config_override copy_ovrd,
1171 		 unsigned int if_config_index)
1172 {
1173 	const struct sh_css_binary_args *args = &stage->args;
1174 
1175 	assert(stage);
1176 	switch (stage->sp_func) {
1177 	case IA_CSS_PIPELINE_RAW_COPY:
1178 		sh_css_sp_start_raw_copy(args->out_frame[0],
1179 					 pipe_num, two_ppc,
1180 					 stage->max_input_width,
1181 					 copy_ovrd, if_config_index);
1182 		break;
1183 	case IA_CSS_PIPELINE_BIN_COPY:
1184 		assert(false); /* TBI */
1185 		break;
1186 	case IA_CSS_PIPELINE_ISYS_COPY:
1187 		sh_css_sp_start_isys_copy(args->out_frame[0],
1188 					  pipe_num, stage->max_input_width, if_config_index);
1189 		break;
1190 	case IA_CSS_PIPELINE_NO_FUNC:
1191 		assert(false);
1192 		break;
1193 	}
1194 }
1195 
1196 void
1197 sh_css_sp_init_pipeline(struct ia_css_pipeline *me,
1198 			enum ia_css_pipe_id id,
1199 			u8 pipe_num,
1200 			bool xnr,
1201 			bool two_ppc,
1202 			bool continuous,
1203 			bool offline,
1204 			unsigned int required_bds_factor,
1205 			enum sh_css_pipe_config_override copy_ovrd,
1206 			enum ia_css_input_mode input_mode,
1207 			const struct ia_css_metadata_config *md_config,
1208 			const struct ia_css_metadata_info *md_info,
1209 			const enum mipi_port_id port_id)
1210 {
1211 	/* Get first stage */
1212 	struct ia_css_pipeline_stage *stage        = NULL;
1213 	struct ia_css_binary	     *first_binary = NULL;
1214 	struct ia_css_pipe *pipe = NULL;
1215 	unsigned int num;
1216 	enum ia_css_pipe_id pipe_id = id;
1217 	unsigned int thread_id;
1218 	u8 if_config_index, tmp_if_config_index;
1219 
1220 	if (!me->stages) {
1221 		dev_err(atomisp_dev, "%s called on a pipeline without stages\n",
1222 			__func__);
1223 		return; /* FIXME should be able to return an error */
1224 	}
1225 
1226 	first_binary = me->stages->binary;
1227 
1228 	if (input_mode == IA_CSS_INPUT_MODE_SENSOR ||
1229 	    input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
1230 		assert(port_id < N_MIPI_PORT_ID);
1231 		if (port_id >= N_MIPI_PORT_ID) /* should not happen but KW does not know */
1232 			return; /* we should be able to return an error */
1233 		if_config_index  = (uint8_t)(port_id - MIPI_PORT0_ID);
1234 	} else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) {
1235 		if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED;
1236 	} else {
1237 		if_config_index = 0x0;
1238 	}
1239 
1240 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
1241 	memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline));
1242 
1243 	/* Count stages */
1244 	for (stage = me->stages, num = 0; stage; stage = stage->next, num++) {
1245 		stage->stage_num = num;
1246 		ia_css_debug_pipe_graph_dump_stage(stage, id);
1247 	}
1248 	me->num_stages = num;
1249 
1250 	if (first_binary) {
1251 		/* Init pipeline data */
1252 		sh_css_sp_init_group(two_ppc, first_binary->input_format,
1253 				     offline, if_config_index);
1254 	} /* if (first_binary != NULL) */
1255 
1256 	/* Signal the host immediately after start for SP_ISYS_COPY only */
1257 	if (me->num_stages == 1 &&
1258 	    me->stages->sp_func == IA_CSS_PIPELINE_ISYS_COPY)
1259 		sh_css_sp_group.config.no_isp_sync = true;
1260 
1261 	/* Init stage data */
1262 	sh_css_init_host2sp_frame_data();
1263 
1264 	sh_css_sp_group.pipe[thread_id].num_stages = 0;
1265 	sh_css_sp_group.pipe[thread_id].pipe_id = pipe_id;
1266 	sh_css_sp_group.pipe[thread_id].thread_id = thread_id;
1267 	sh_css_sp_group.pipe[thread_id].pipe_num = pipe_num;
1268 	sh_css_sp_group.pipe[thread_id].num_execs = me->num_execs;
1269 	sh_css_sp_group.pipe[thread_id].pipe_qos_config = QOS_INVALID;
1270 	sh_css_sp_group.pipe[thread_id].required_bds_factor = required_bds_factor;
1271 	sh_css_sp_group.pipe[thread_id].input_system_mode
1272 	= (uint32_t)input_mode;
1273 	sh_css_sp_group.pipe[thread_id].port_id = port_id;
1274 	sh_css_sp_group.pipe[thread_id].dvs_frame_delay = (uint32_t)me->dvs_frame_delay;
1275 
1276 	/* TODO: next indicates from which queues parameters need to be
1277 		 sampled, needs checking/improvement */
1278 	if (ia_css_pipeline_uses_params(me)) {
1279 		sh_css_sp_group.pipe[thread_id].pipe_config =
1280 		SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id;
1281 	}
1282 
1283 	/* For continuous use-cases, SP copy is responsible for sampling the
1284 	 * parameters */
1285 	if (continuous)
1286 		sh_css_sp_group.pipe[thread_id].pipe_config = 0;
1287 
1288 	sh_css_sp_group.pipe[thread_id].inout_port_config = me->inout_port_config;
1289 
1290 	pipe = find_pipe_by_num(pipe_num);
1291 	assert(pipe);
1292 	if (!pipe) {
1293 		return;
1294 	}
1295 	sh_css_sp_group.pipe[thread_id].scaler_pp_lut = sh_css_pipe_get_pp_gdc_lut(pipe);
1296 
1297 	if (md_info && md_info->size > 0) {
1298 		sh_css_sp_group.pipe[thread_id].metadata.width  = md_info->resolution.width;
1299 		sh_css_sp_group.pipe[thread_id].metadata.height = md_info->resolution.height;
1300 		sh_css_sp_group.pipe[thread_id].metadata.stride = md_info->stride;
1301 		sh_css_sp_group.pipe[thread_id].metadata.size   = md_info->size;
1302 		ia_css_isys_convert_stream_format_to_mipi_format(
1303 		    md_config->data_type, MIPI_PREDICTOR_NONE,
1304 		    &sh_css_sp_group.pipe[thread_id].metadata.format);
1305 	}
1306 
1307 	sh_css_sp_group.pipe[thread_id].output_frame_queue_id = (uint32_t)SH_CSS_INVALID_QUEUE_ID;
1308 	if (pipe_id != IA_CSS_PIPE_ID_COPY) {
1309 		ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id,
1310 					       (enum sh_css_queue_id *)(
1311 						   &sh_css_sp_group.pipe[thread_id].output_frame_queue_id));
1312 	}
1313 
1314 	IA_CSS_LOG("pipe_id %d port_config %08x",
1315 		   pipe_id, sh_css_sp_group.pipe[thread_id].inout_port_config);
1316 
1317 	for (stage = me->stages, num = 0; stage; stage = stage->next, num++) {
1318 		sh_css_sp_group.pipe[thread_id].num_stages++;
1319 		if (is_sp_stage(stage)) {
1320 			sp_init_sp_stage(stage, pipe_num, two_ppc,
1321 					 copy_ovrd, if_config_index);
1322 		} else {
1323 			if ((stage->stage_num != 0) ||
1324 			    SH_CSS_PIPE_PORT_CONFIG_IS_CONTINUOUS(me->inout_port_config))
1325 				tmp_if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED;
1326 			else
1327 				tmp_if_config_index = if_config_index;
1328 			sp_init_stage(stage, pipe_num,
1329 				      xnr, tmp_if_config_index, two_ppc);
1330 		}
1331 
1332 		store_sp_stage_data(pipe_id, pipe_num, num);
1333 	}
1334 	sh_css_sp_group.pipe[thread_id].pipe_config |= (uint32_t)
1335 		(me->acquire_isp_each_stage << IA_CSS_ACQUIRE_ISP_POS);
1336 	store_sp_group_data();
1337 }
1338 
1339 void
1340 sh_css_sp_uninit_pipeline(unsigned int pipe_num)
1341 {
1342 	unsigned int thread_id;
1343 
1344 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
1345 	/*memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline));*/
1346 	sh_css_sp_group.pipe[thread_id].num_stages = 0;
1347 }
1348 
1349 bool sh_css_write_host2sp_command(enum host2sp_commands host2sp_command)
1350 {
1351 	unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1352 	unsigned int offset = (unsigned int)offsetof(struct host_sp_communication,
1353 			      host2sp_command)
1354 			      / sizeof(int);
1355 	enum host2sp_commands last_cmd = host2sp_cmd_error;
1356 	(void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
1357 
1358 	/* Previous command must be handled by SP (by design) */
1359 	last_cmd = load_sp_array_uint(host_sp_com, offset);
1360 	if (last_cmd != host2sp_cmd_ready)
1361 		IA_CSS_ERROR("last host command not handled by SP(%d)", last_cmd);
1362 
1363 	store_sp_array_uint(host_sp_com, offset, host2sp_command);
1364 
1365 	return (last_cmd == host2sp_cmd_ready);
1366 }
1367 
1368 enum host2sp_commands
1369 sh_css_read_host2sp_command(void)
1370 {
1371 	unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1372 	unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command)
1373 	/ sizeof(int);
1374 	(void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
1375 	return (enum host2sp_commands)load_sp_array_uint(host_sp_com, offset);
1376 }
1377 
1378 /*
1379  * Frame data is no longer part of the sp_stage structure but part of a
1380  * separate structure. The aim is to make the sp_data struct static
1381  * (it defines a pipeline) and that the dynamic (per frame) data is stored
1382  * separetly.
1383  *
1384  * This function must be called first every where were you start constructing
1385  * a new pipeline by defining one or more stages with use of variable
1386  * sh_css_sp_stage. Even the special cases like accelerator and copy_frame
1387  * These have a pipeline of just 1 stage.
1388  */
1389 void
1390 sh_css_init_host2sp_frame_data(void)
1391 {
1392 	/* Clean table */
1393 	unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1394 
1395 	(void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
1396 	/*
1397 	 * rvanimme: don't clean it to save static frame info line ref_in
1398 	 * ref_out, and tnr_frames. Once this static data is in a
1399 	 * separate data struct, this may be enable (but still, there is
1400 	 * no need for it)
1401 	 */
1402 }
1403 
1404 /*
1405  * @brief Update the offline frame information in host_sp_communication.
1406  * Refer to "sh_css_sp.h" for more details.
1407  */
1408 void
1409 sh_css_update_host2sp_offline_frame(
1410     unsigned int frame_num,
1411     struct ia_css_frame *frame,
1412     struct ia_css_metadata *metadata)
1413 {
1414 	unsigned int HIVE_ADDR_host_sp_com;
1415 	unsigned int offset;
1416 
1417 	assert(frame_num < NUM_CONTINUOUS_FRAMES);
1418 
1419 	/* Write new frame data into SP DMEM */
1420 	HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1421 	offset = (unsigned int)offsetof(struct host_sp_communication,
1422 					host2sp_offline_frames)
1423 		 / sizeof(int);
1424 	offset += frame_num;
1425 	store_sp_array_uint(host_sp_com, offset, frame ? frame->data : 0);
1426 
1427 	/* Write metadata buffer into SP DMEM */
1428 	offset = (unsigned int)offsetof(struct host_sp_communication,
1429 					host2sp_offline_metadata)
1430 		 / sizeof(int);
1431 	offset += frame_num;
1432 	store_sp_array_uint(host_sp_com, offset, metadata ? metadata->address : 0);
1433 }
1434 
1435 /*
1436  * @brief Update the mipi frame information in host_sp_communication.
1437  * Refer to "sh_css_sp.h" for more details.
1438  */
1439 void
1440 sh_css_update_host2sp_mipi_frame(
1441     unsigned int frame_num,
1442     struct ia_css_frame *frame)
1443 {
1444 	unsigned int HIVE_ADDR_host_sp_com;
1445 	unsigned int offset;
1446 
1447 	/* MIPI buffers are dedicated to port, so now there are more of them. */
1448 	assert(frame_num < (N_CSI_PORTS * NUM_MIPI_FRAMES_PER_STREAM));
1449 
1450 	/* Write new frame data into SP DMEM */
1451 	HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1452 	offset = (unsigned int)offsetof(struct host_sp_communication,
1453 					host2sp_mipi_frames)
1454 		 / sizeof(int);
1455 	offset += frame_num;
1456 
1457 	store_sp_array_uint(host_sp_com, offset,
1458 			    frame ? frame->data : 0);
1459 }
1460 
1461 /*
1462  * @brief Update the mipi metadata information in host_sp_communication.
1463  * Refer to "sh_css_sp.h" for more details.
1464  */
1465 void
1466 sh_css_update_host2sp_mipi_metadata(
1467     unsigned int frame_num,
1468     struct ia_css_metadata *metadata)
1469 {
1470 	unsigned int HIVE_ADDR_host_sp_com;
1471 	unsigned int o;
1472 
1473 	/* MIPI buffers are dedicated to port, so now there are more of them. */
1474 	assert(frame_num < (N_CSI_PORTS * NUM_MIPI_FRAMES_PER_STREAM));
1475 
1476 	/* Write new frame data into SP DMEM */
1477 	HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1478 	o = offsetof(struct host_sp_communication, host2sp_mipi_metadata)
1479 	    / sizeof(int);
1480 	o += frame_num;
1481 	store_sp_array_uint(host_sp_com, o,
1482 			    metadata ? metadata->address : 0);
1483 }
1484 
1485 void
1486 sh_css_update_host2sp_num_mipi_frames(unsigned int num_frames)
1487 {
1488 	unsigned int HIVE_ADDR_host_sp_com;
1489 	unsigned int offset;
1490 
1491 	/* Write new frame data into SP DMEM */
1492 	HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1493 	offset = (unsigned int)offsetof(struct host_sp_communication,
1494 					host2sp_num_mipi_frames)
1495 		 / sizeof(int);
1496 
1497 	store_sp_array_uint(host_sp_com, offset, num_frames);
1498 }
1499 
1500 void
1501 sh_css_update_host2sp_cont_num_raw_frames(unsigned int num_frames,
1502 	bool set_avail)
1503 {
1504 	const struct ia_css_fw_info *fw;
1505 	unsigned int HIVE_ADDR_host_sp_com;
1506 	unsigned int extra_num_frames, avail_num_frames;
1507 	unsigned int offset, offset_extra;
1508 
1509 	/* Write new frame data into SP DMEM */
1510 	fw = &sh_css_sp_fw;
1511 	HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com;
1512 	if (set_avail) {
1513 		offset = (unsigned int)offsetof(struct host_sp_communication,
1514 						host2sp_cont_avail_num_raw_frames)
1515 			 / sizeof(int);
1516 		avail_num_frames = load_sp_array_uint(host_sp_com, offset);
1517 		extra_num_frames = num_frames - avail_num_frames;
1518 		offset_extra = (unsigned int)offsetof(struct host_sp_communication,
1519 						      host2sp_cont_extra_num_raw_frames)
1520 			       / sizeof(int);
1521 		store_sp_array_uint(host_sp_com, offset_extra, extra_num_frames);
1522 	} else
1523 		offset = (unsigned int)offsetof(struct host_sp_communication,
1524 						host2sp_cont_target_num_raw_frames)
1525 			 / sizeof(int);
1526 
1527 	store_sp_array_uint(host_sp_com, offset, num_frames);
1528 }
1529 
1530 void
1531 sh_css_event_init_irq_mask(void)
1532 {
1533 	int i;
1534 	unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1535 	unsigned int offset;
1536 	struct sh_css_event_irq_mask event_irq_mask_init;
1537 
1538 	event_irq_mask_init.or_mask  = IA_CSS_EVENT_TYPE_ALL;
1539 	event_irq_mask_init.and_mask = IA_CSS_EVENT_TYPE_NONE;
1540 	(void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */
1541 
1542 	assert(sizeof(event_irq_mask_init) % HRT_BUS_BYTES == 0);
1543 	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) {
1544 		offset = (unsigned int)offsetof(struct host_sp_communication,
1545 						host2sp_event_irq_mask[i]);
1546 		assert(offset % HRT_BUS_BYTES == 0);
1547 		sp_dmem_store(SP0_ID,
1548 			      (unsigned int)sp_address_of(host_sp_com) + offset,
1549 			      &event_irq_mask_init, sizeof(event_irq_mask_init));
1550 	}
1551 }
1552 
1553 int
1554 ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe,
1555 			 unsigned int or_mask,
1556 			 unsigned int and_mask)
1557 {
1558 	unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1559 	unsigned int offset;
1560 	struct sh_css_event_irq_mask event_irq_mask;
1561 	unsigned int pipe_num;
1562 
1563 	assert(pipe);
1564 
1565 	assert(IA_CSS_PIPE_ID_NUM == NR_OF_PIPELINES);
1566 	/* Linux kernel does not have UINT16_MAX
1567 	 * Therefore decided to comment out these 2 asserts for Linux
1568 	 * Alternatives that were not chosen:
1569 	 * - add a conditional #define for UINT16_MAX
1570 	 * - compare with (uint16_t)~0 or 0xffff
1571 	 * - different assert for Linux and Windows
1572 	 */
1573 
1574 	(void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
1575 
1576 	IA_CSS_LOG("or_mask=%x, and_mask=%x", or_mask, and_mask);
1577 	event_irq_mask.or_mask  = (uint16_t)or_mask;
1578 	event_irq_mask.and_mask = (uint16_t)and_mask;
1579 
1580 	pipe_num = ia_css_pipe_get_pipe_num(pipe);
1581 	if (pipe_num >= IA_CSS_PIPE_ID_NUM)
1582 		return -EINVAL;
1583 	offset = (unsigned int)offsetof(struct host_sp_communication,
1584 					host2sp_event_irq_mask[pipe_num]);
1585 	assert(offset % HRT_BUS_BYTES == 0);
1586 	sp_dmem_store(SP0_ID,
1587 		      (unsigned int)sp_address_of(host_sp_com) + offset,
1588 		      &event_irq_mask, sizeof(event_irq_mask));
1589 
1590 	return 0;
1591 }
1592 
1593 int
1594 ia_css_event_get_irq_mask(const struct ia_css_pipe *pipe,
1595 			  unsigned int *or_mask,
1596 			  unsigned int *and_mask)
1597 {
1598 	unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
1599 	unsigned int offset;
1600 	struct sh_css_event_irq_mask event_irq_mask;
1601 	unsigned int pipe_num;
1602 
1603 	(void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
1604 
1605 	IA_CSS_ENTER_LEAVE("");
1606 
1607 	assert(pipe);
1608 	assert(IA_CSS_PIPE_ID_NUM == NR_OF_PIPELINES);
1609 
1610 	pipe_num = ia_css_pipe_get_pipe_num(pipe);
1611 	if (pipe_num >= IA_CSS_PIPE_ID_NUM)
1612 		return -EINVAL;
1613 	offset = (unsigned int)offsetof(struct host_sp_communication,
1614 					host2sp_event_irq_mask[pipe_num]);
1615 	assert(offset % HRT_BUS_BYTES == 0);
1616 	sp_dmem_load(SP0_ID,
1617 		     (unsigned int)sp_address_of(host_sp_com) + offset,
1618 		     &event_irq_mask, sizeof(event_irq_mask));
1619 
1620 	if (or_mask)
1621 		*or_mask = event_irq_mask.or_mask;
1622 
1623 	if (and_mask)
1624 		*and_mask = event_irq_mask.and_mask;
1625 
1626 	return 0;
1627 }
1628 
1629 void
1630 sh_css_sp_set_sp_running(bool flag)
1631 {
1632 	sp_running = flag;
1633 }
1634 
1635 bool
1636 sh_css_sp_is_running(void)
1637 {
1638 	return sp_running;
1639 }
1640 
1641 void
1642 sh_css_sp_start_isp(void)
1643 {
1644 	const struct ia_css_fw_info *fw;
1645 	unsigned int HIVE_ADDR_sp_sw_state;
1646 
1647 	fw = &sh_css_sp_fw;
1648 	HIVE_ADDR_sp_sw_state = fw->info.sp.sw_state;
1649 
1650 	if (sp_running)
1651 		return;
1652 
1653 	(void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */
1654 
1655 	/* no longer here, sp started immediately */
1656 	/*ia_css_debug_pipe_graph_dump_epilogue();*/
1657 
1658 	store_sp_group_data();
1659 	store_sp_per_frame_data(fw);
1660 
1661 	sp_dmem_store_uint32(SP0_ID,
1662 			     (unsigned int)sp_address_of(sp_sw_state),
1663 			     (uint32_t)(IA_CSS_SP_SW_TERMINATED));
1664 
1665 	/* Note 1: The sp_start_isp function contains a wait till
1666 	 * the input network is configured by the SP.
1667 	 * Note 2: Not all SP binaries supports host2sp_commands.
1668 	 * In case a binary does support it, the host2sp_command
1669 	 * will have status cmd_ready after return of the function
1670 	 * sh_css_hrt_sp_start_isp. There is no race-condition here
1671 	 * because only after the process_frame command has been
1672 	 * received, the SP starts configuring the input network.
1673 	 */
1674 
1675 	/* we need to set sp_running before we call ia_css_mmu_invalidate_cache
1676 	 * as ia_css_mmu_invalidate_cache checks on sp_running to
1677 	 * avoid that it accesses dmem while the SP is not powered
1678 	 */
1679 	sp_running = true;
1680 	ia_css_mmu_invalidate_cache();
1681 	/* Invalidate all MMU caches */
1682 	mmu_invalidate_cache_all();
1683 
1684 	ia_css_spctrl_start(SP0_ID);
1685 }
1686 
1687 bool
1688 ia_css_isp_has_started(void)
1689 {
1690 	const struct ia_css_fw_info *fw = &sh_css_sp_fw;
1691 	unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started;
1692 	(void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */
1693 
1694 	return (bool)load_sp_uint(ia_css_ispctrl_sp_isp_started);
1695 }
1696 
1697 /*
1698  * @brief Initialize the DMA software-mask in the debug mode.
1699  * Refer to "sh_css_sp.h" for more details.
1700  */
1701 bool
1702 sh_css_sp_init_dma_sw_reg(int dma_id)
1703 {
1704 	int i;
1705 
1706 	/* enable all the DMA channels */
1707 	for (i = 0; i < N_DMA_CHANNEL_ID; i++) {
1708 		/* enable the writing request */
1709 		sh_css_sp_set_dma_sw_reg(dma_id,
1710 					 i,
1711 					 0,
1712 					 true);
1713 		/* enable the reading request */
1714 		sh_css_sp_set_dma_sw_reg(dma_id,
1715 					 i,
1716 					 1,
1717 					 true);
1718 	}
1719 
1720 	return true;
1721 }
1722 
1723 /*
1724  * @brief Set the DMA software-mask in the debug mode.
1725  * Refer to "sh_css_sp.h" for more details.
1726  */
1727 bool
1728 sh_css_sp_set_dma_sw_reg(int dma_id,
1729 			 int channel_id,
1730 			 int request_type,
1731 			 bool enable)
1732 {
1733 	u32 sw_reg;
1734 	u32 bit_val;
1735 	u32 bit_offset;
1736 	u32 bit_mask;
1737 
1738 	(void)dma_id;
1739 
1740 	assert(channel_id >= 0 && channel_id < N_DMA_CHANNEL_ID);
1741 	assert(request_type >= 0);
1742 
1743 	/* get the software-mask */
1744 	sw_reg =
1745 	    sh_css_sp_group.debug.dma_sw_reg;
1746 
1747 	/* get the offest of the target bit */
1748 	bit_offset = (8 * request_type) + channel_id;
1749 
1750 	/* clear the value of the target bit */
1751 	bit_mask = ~(1 << bit_offset);
1752 	sw_reg &= bit_mask;
1753 
1754 	/* set the value of the bit for the DMA channel */
1755 	bit_val = enable ? 1 : 0;
1756 	bit_val <<= bit_offset;
1757 	sw_reg |= bit_val;
1758 
1759 	/* update the software status of DMA channels */
1760 	sh_css_sp_group.debug.dma_sw_reg = sw_reg;
1761 
1762 	return true;
1763 }
1764 
1765 void
1766 sh_css_sp_reset_global_vars(void)
1767 {
1768 	memset(&sh_css_sp_group, 0, sizeof(struct sh_css_sp_group));
1769 	memset(&sh_css_sp_stage, 0, sizeof(struct sh_css_sp_stage));
1770 	memset(&sh_css_isp_stage, 0, sizeof(struct sh_css_isp_stage));
1771 	memset(&sh_css_sp_output, 0, sizeof(struct sh_css_sp_output));
1772 	memset(&per_frame_data, 0, sizeof(struct sh_css_sp_per_frame_data));
1773 }
1774