xref: /linux/drivers/staging/media/ipu7/ipu7-fw-isys.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013 - 2025 Intel Corporation
4  */
5 
6 #include <linux/cacheflush.h>
7 #include <linux/device.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/kernel.h>
10 #include <linux/string.h>
11 #include <linux/types.h>
12 
13 #include "abi/ipu7_fw_insys_config_abi.h"
14 #include "abi/ipu7_fw_isys_abi.h"
15 
16 #include "ipu7.h"
17 #include "ipu7-boot.h"
18 #include "ipu7-bus.h"
19 #include "ipu7-dma.h"
20 #include "ipu7-fw-isys.h"
21 #include "ipu7-isys.h"
22 #include "ipu7-platform-regs.h"
23 #include "ipu7-syscom.h"
24 
25 static const char * const send_msg_types[N_IPU_INSYS_SEND_TYPE] = {
26 	"STREAM_OPEN",
27 	"STREAM_START_AND_CAPTURE",
28 	"STREAM_CAPTURE",
29 	"STREAM_ABORT",
30 	"STREAM_FLUSH",
31 	"STREAM_CLOSE"
32 };
33 
34 int ipu7_fw_isys_complex_cmd(struct ipu7_isys *isys,
35 			     const unsigned int stream_handle,
36 			     void *cpu_mapped_buf,
37 			     dma_addr_t dma_mapped_buf,
38 			     size_t size, u16 send_type)
39 {
40 	struct ipu7_syscom_context *ctx = isys->adev->syscom;
41 	struct device *dev = &isys->adev->auxdev.dev;
42 	struct ipu7_insys_send_queue_token *token;
43 
44 	if (send_type >= N_IPU_INSYS_SEND_TYPE)
45 		return -EINVAL;
46 
47 	dev_dbg(dev, "send_token: %s\n", send_msg_types[send_type]);
48 
49 	/*
50 	 * Time to flush cache in case we have some payload. Not all messages
51 	 * have that
52 	 */
53 	if (cpu_mapped_buf)
54 		clflush_cache_range(cpu_mapped_buf, size);
55 
56 	token = ipu7_syscom_get_token(ctx, stream_handle +
57 				      IPU_INSYS_INPUT_MSG_QUEUE);
58 	if (!token)
59 		return -EBUSY;
60 
61 	token->addr = dma_mapped_buf;
62 	token->buf_handle = (unsigned long)cpu_mapped_buf;
63 	token->send_type = send_type;
64 	token->stream_id = stream_handle;
65 	token->flag = IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE;
66 
67 	ipu7_syscom_put_token(ctx, stream_handle + IPU_INSYS_INPUT_MSG_QUEUE);
68 	/* now wakeup FW */
69 	ipu_buttress_wakeup_is_uc(isys->adev->isp);
70 
71 	return 0;
72 }
73 
74 int ipu7_fw_isys_simple_cmd(struct ipu7_isys *isys,
75 			    const unsigned int stream_handle, u16 send_type)
76 {
77 	return ipu7_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
78 					send_type);
79 }
80 
81 int ipu7_fw_isys_init(struct ipu7_isys *isys)
82 {
83 	struct syscom_queue_config *queue_configs;
84 	struct ipu7_bus_device *adev = isys->adev;
85 	struct device *dev = &adev->auxdev.dev;
86 	struct ipu7_insys_config *isys_config;
87 	struct ipu7_syscom_context *syscom;
88 	dma_addr_t isys_config_dma_addr;
89 	unsigned int i, num_queues;
90 	u32 freq;
91 	u8 major;
92 	int ret;
93 
94 	/* Allocate and init syscom context. */
95 	syscom = devm_kzalloc(dev, sizeof(struct ipu7_syscom_context),
96 			      GFP_KERNEL);
97 	if (!syscom)
98 		return -ENOMEM;
99 
100 	adev->syscom = syscom;
101 	syscom->num_input_queues = IPU_INSYS_MAX_INPUT_QUEUES;
102 	syscom->num_output_queues = IPU_INSYS_MAX_OUTPUT_QUEUES;
103 	num_queues = syscom->num_input_queues + syscom->num_output_queues;
104 	queue_configs = devm_kzalloc(dev, FW_QUEUE_CONFIG_SIZE(num_queues),
105 				     GFP_KERNEL);
106 	if (!queue_configs) {
107 		ipu7_fw_isys_release(isys);
108 		return -ENOMEM;
109 	}
110 	syscom->queue_configs = queue_configs;
111 	queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].max_capacity =
112 		IPU_ISYS_SIZE_RECV_QUEUE;
113 	queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes =
114 		sizeof(struct ipu7_insys_resp);
115 	queue_configs[IPU_INSYS_OUTPUT_LOG_QUEUE].max_capacity =
116 		IPU_ISYS_SIZE_LOG_QUEUE;
117 	queue_configs[IPU_INSYS_OUTPUT_LOG_QUEUE].token_size_in_bytes =
118 		sizeof(struct ipu7_insys_resp);
119 	queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0;
120 	queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0;
121 
122 	queue_configs[IPU_INSYS_INPUT_DEV_QUEUE].max_capacity =
123 		IPU_ISYS_MAX_STREAMS;
124 	queue_configs[IPU_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes =
125 		sizeof(struct ipu7_insys_send_queue_token);
126 
127 	for (i = IPU_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
128 		queue_configs[i].max_capacity = IPU_ISYS_SIZE_SEND_QUEUE;
129 		queue_configs[i].token_size_in_bytes =
130 			sizeof(struct ipu7_insys_send_queue_token);
131 	}
132 
133 	/* Allocate ISYS subsys config. */
134 	isys_config = ipu7_dma_alloc(adev, sizeof(struct ipu7_insys_config),
135 				     &isys_config_dma_addr, GFP_KERNEL, 0);
136 	if (!isys_config) {
137 		dev_err(dev, "Failed to allocate isys subsys config.\n");
138 		ipu7_fw_isys_release(isys);
139 		return -ENOMEM;
140 	}
141 	isys->subsys_config = isys_config;
142 	isys->subsys_config_dma_addr = isys_config_dma_addr;
143 	memset(isys_config, 0, sizeof(struct ipu7_insys_config));
144 	isys_config->logger_config.use_source_severity = 0;
145 	isys_config->logger_config.use_channels_enable_bitmask = 1;
146 	isys_config->logger_config.channels_enable_bitmask =
147 		LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK;
148 	isys_config->logger_config.hw_printf_buffer_base_addr = 0U;
149 	isys_config->logger_config.hw_printf_buffer_size_bytes = 0U;
150 	isys_config->wdt_config.wdt_timer1_us = 0;
151 	isys_config->wdt_config.wdt_timer2_us = 0;
152 	ret = ipu_buttress_get_isys_freq(adev->isp, &freq);
153 	if (ret) {
154 		dev_err(dev, "Failed to get ISYS frequency.\n");
155 		ipu7_fw_isys_release(isys);
156 		return ret;
157 	}
158 
159 	ipu7_dma_sync_single(adev, isys_config_dma_addr,
160 			     sizeof(struct ipu7_insys_config));
161 
162 	major = is_ipu8(adev->isp->hw_ver) ? 2U : 1U;
163 	ret = ipu7_boot_init_boot_config(adev, queue_configs, num_queues,
164 					 freq, isys_config_dma_addr, major);
165 	if (ret)
166 		ipu7_fw_isys_release(isys);
167 
168 	return ret;
169 }
170 
171 void ipu7_fw_isys_release(struct ipu7_isys *isys)
172 {
173 	struct ipu7_bus_device *adev = isys->adev;
174 
175 	ipu7_boot_release_boot_config(adev);
176 	if (isys->subsys_config) {
177 		ipu7_dma_free(adev,
178 			      sizeof(struct ipu7_insys_config),
179 			      isys->subsys_config,
180 			      isys->subsys_config_dma_addr, 0);
181 		isys->subsys_config = NULL;
182 		isys->subsys_config_dma_addr = 0;
183 	}
184 }
185 
186 int ipu7_fw_isys_open(struct ipu7_isys *isys)
187 {
188 	return ipu7_boot_start_fw(isys->adev);
189 }
190 
191 int ipu7_fw_isys_close(struct ipu7_isys *isys)
192 {
193 	return ipu7_boot_stop_fw(isys->adev);
194 }
195 
196 struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu7_isys *isys)
197 {
198 	return (struct ipu7_insys_resp *)
199 		ipu7_syscom_get_token(isys->adev->syscom,
200 				      IPU_INSYS_OUTPUT_MSG_QUEUE);
201 }
202 
203 void ipu7_fw_isys_put_resp(struct ipu7_isys *isys)
204 {
205 	ipu7_syscom_put_token(isys->adev->syscom, IPU_INSYS_OUTPUT_MSG_QUEUE);
206 }
207 
208 void ipu7_fw_isys_dump_stream_cfg(struct device *dev,
209 				  struct ipu7_insys_stream_cfg *cfg)
210 {
211 	unsigned int i;
212 
213 	dev_dbg(dev, "---------------------------\n");
214 	dev_dbg(dev, "IPU_FW_ISYS_STREAM_CFG_DATA\n");
215 
216 	dev_dbg(dev, ".port id %d\n", cfg->port_id);
217 	dev_dbg(dev, ".vc %d\n", cfg->vc);
218 	dev_dbg(dev, ".nof_input_pins = %d\n", cfg->nof_input_pins);
219 	dev_dbg(dev, ".nof_output_pins = %d\n", cfg->nof_output_pins);
220 	dev_dbg(dev, ".stream_msg_map = 0x%x\n", cfg->stream_msg_map);
221 
222 	for (i = 0; i < cfg->nof_input_pins; i++) {
223 		dev_dbg(dev, ".input_pin[%d]:\n", i);
224 		dev_dbg(dev, "\t.dt = 0x%0x\n",
225 			cfg->input_pins[i].dt);
226 		dev_dbg(dev, "\t.disable_mipi_unpacking = %d\n",
227 			cfg->input_pins[i].disable_mipi_unpacking);
228 		dev_dbg(dev, "\t.dt_rename_mode = %d\n",
229 			cfg->input_pins[i].dt_rename_mode);
230 		dev_dbg(dev, "\t.mapped_dt = 0x%0x\n",
231 			cfg->input_pins[i].mapped_dt);
232 		dev_dbg(dev, "\t.input_res = %d x %d\n",
233 			cfg->input_pins[i].input_res.width,
234 			cfg->input_pins[i].input_res.height);
235 		dev_dbg(dev, "\t.sync_msg_map = 0x%x\n",
236 			cfg->input_pins[i].sync_msg_map);
237 	}
238 
239 	for (i = 0; i < cfg->nof_output_pins; i++) {
240 		dev_dbg(dev, ".output_pin[%d]:\n", i);
241 		dev_dbg(dev, "\t.input_pin_id = %d\n",
242 			cfg->output_pins[i].input_pin_id);
243 		dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride);
244 		dev_dbg(dev, "\t.send_irq = %d\n",
245 			cfg->output_pins[i].send_irq);
246 		dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft);
247 
248 		dev_dbg(dev, "\t.link.buffer_lines = %d\n",
249 			cfg->output_pins[i].link.buffer_lines);
250 		dev_dbg(dev, "\t.link.foreign_key = %d\n",
251 			cfg->output_pins[i].link.foreign_key);
252 		dev_dbg(dev, "\t.link.granularity_pointer_update = %d\n",
253 			cfg->output_pins[i].link.granularity_pointer_update);
254 		dev_dbg(dev, "\t.link.msg_link_streaming_mode = %d\n",
255 			cfg->output_pins[i].link.msg_link_streaming_mode);
256 		dev_dbg(dev, "\t.link.pbk_id = %d\n",
257 			cfg->output_pins[i].link.pbk_id);
258 		dev_dbg(dev, "\t.link.pbk_slot_id = %d\n",
259 			cfg->output_pins[i].link.pbk_slot_id);
260 		dev_dbg(dev, "\t.link.dest = %d\n",
261 			cfg->output_pins[i].link.dest);
262 		dev_dbg(dev, "\t.link.use_sw_managed = %d\n",
263 			cfg->output_pins[i].link.use_sw_managed);
264 		dev_dbg(dev, "\t.link.is_snoop = %d\n",
265 			cfg->output_pins[i].link.is_snoop);
266 
267 		dev_dbg(dev, "\t.crop.line_top = %d\n",
268 			cfg->output_pins[i].crop.line_top);
269 		dev_dbg(dev, "\t.crop.line_bottom = %d\n",
270 			cfg->output_pins[i].crop.line_bottom);
271 
272 		dev_dbg(dev, "\t.dpcm_enable = %d\n",
273 			cfg->output_pins[i].dpcm.enable);
274 		dev_dbg(dev, "\t.dpcm.type = %d\n",
275 			cfg->output_pins[i].dpcm.type);
276 		dev_dbg(dev, "\t.dpcm.predictor = %d\n",
277 			cfg->output_pins[i].dpcm.predictor);
278 	}
279 	dev_dbg(dev, "---------------------------\n");
280 }
281 
282 void ipu7_fw_isys_dump_frame_buff_set(struct device *dev,
283 				      struct ipu7_insys_buffset *buf,
284 				      unsigned int outputs)
285 {
286 	unsigned int i;
287 
288 	dev_dbg(dev, "--------------------------\n");
289 	dev_dbg(dev, "IPU_ISYS_BUFF_SET\n");
290 	dev_dbg(dev, ".capture_msg_map = %d\n", buf->capture_msg_map);
291 	dev_dbg(dev, ".frame_id = %d\n", buf->frame_id);
292 	dev_dbg(dev, ".skip_frame = %d\n", buf->skip_frame);
293 
294 	for (i = 0; i < outputs; i++) {
295 		dev_dbg(dev, ".output_pin[%d]:\n", i);
296 		dev_dbg(dev, "\t.user_token = %llx\n",
297 			buf->output_pins[i].user_token);
298 		dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr);
299 	}
300 	dev_dbg(dev, "---------------------------\n");
301 }
302