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