xref: /linux/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c (revision 6fd600d742744dc7ef7fc65ca26daa2b1163158a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013--2024 Intel Corporation
4  */
5 
6 #include <linux/cacheflush.h>
7 #include <linux/delay.h>
8 #include <linux/device.h>
9 #include <linux/io.h>
10 #include <linux/spinlock.h>
11 #include <linux/types.h>
12 
13 #include "ipu6-bus.h"
14 #include "ipu6-fw-com.h"
15 #include "ipu6-isys.h"
16 #include "ipu6-platform-isys-csi2-reg.h"
17 #include "ipu6-platform-regs.h"
18 
19 static const char send_msg_types[N_IPU6_FW_ISYS_SEND_TYPE][32] = {
20 	"STREAM_OPEN",
21 	"STREAM_START",
22 	"STREAM_START_AND_CAPTURE",
23 	"STREAM_CAPTURE",
24 	"STREAM_STOP",
25 	"STREAM_FLUSH",
26 	"STREAM_CLOSE"
27 };
28 
handle_proxy_response(struct ipu6_isys * isys,unsigned int req_id)29 static int handle_proxy_response(struct ipu6_isys *isys, unsigned int req_id)
30 {
31 	struct device *dev = &isys->adev->auxdev.dev;
32 	struct ipu6_fw_isys_proxy_resp_info_abi *resp;
33 	int ret;
34 
35 	resp = ipu6_recv_get_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
36 	if (!resp)
37 		return 1;
38 
39 	dev_dbg(dev, "Proxy response: id %u, error %u, details %u\n",
40 		resp->request_id, resp->error_info.error,
41 		resp->error_info.error_details);
42 
43 	ret = req_id == resp->request_id ? 0 : -EIO;
44 
45 	ipu6_recv_put_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
46 
47 	return ret;
48 }
49 
ipu6_fw_isys_send_proxy_token(struct ipu6_isys * isys,unsigned int req_id,unsigned int index,unsigned int offset,u32 value)50 int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
51 				  unsigned int req_id,
52 				  unsigned int index,
53 				  unsigned int offset, u32 value)
54 {
55 	struct ipu6_fw_com_context *ctx = isys->fwcom;
56 	struct device *dev = &isys->adev->auxdev.dev;
57 	struct ipu6_fw_proxy_send_queue_token *token;
58 	unsigned int timeout = 1000;
59 	int ret;
60 
61 	dev_dbg(dev,
62 		"proxy send: req_id 0x%x, index %d, offset 0x%x, value 0x%x\n",
63 		req_id, index, offset, value);
64 
65 	token = ipu6_send_get_token(ctx, IPU6_BASE_PROXY_SEND_QUEUES);
66 	if (!token)
67 		return -EBUSY;
68 
69 	token->request_id = req_id;
70 	token->region_index = index;
71 	token->offset = offset;
72 	token->value = value;
73 	ipu6_send_put_token(ctx, IPU6_BASE_PROXY_SEND_QUEUES);
74 
75 	do {
76 		usleep_range(100, 110);
77 		ret = handle_proxy_response(isys, req_id);
78 		if (!ret)
79 			break;
80 		if (ret == -EIO) {
81 			dev_err(dev, "Proxy respond with unexpected id\n");
82 			break;
83 		}
84 		timeout--;
85 	} while (ret && timeout);
86 
87 	if (!timeout)
88 		dev_err(dev, "Proxy response timed out\n");
89 
90 	return ret;
91 }
92 
ipu6_fw_isys_complex_cmd(struct ipu6_isys * isys,const unsigned int stream_handle,void * cpu_mapped_buf,dma_addr_t dma_mapped_buf,size_t size,u16 send_type)93 int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
94 			     const unsigned int stream_handle,
95 			     void *cpu_mapped_buf,
96 			     dma_addr_t dma_mapped_buf,
97 			     size_t size, u16 send_type)
98 {
99 	struct ipu6_fw_com_context *ctx = isys->fwcom;
100 	struct device *dev = &isys->adev->auxdev.dev;
101 	struct ipu6_fw_send_queue_token *token;
102 
103 	if (send_type >= N_IPU6_FW_ISYS_SEND_TYPE)
104 		return -EINVAL;
105 
106 	dev_dbg(dev, "send_token: %s\n", send_msg_types[send_type]);
107 
108 	/*
109 	 * Time to flush cache in case we have some payload. Not all messages
110 	 * have that
111 	 */
112 	if (cpu_mapped_buf)
113 		clflush_cache_range(cpu_mapped_buf, size);
114 
115 	token = ipu6_send_get_token(ctx,
116 				    stream_handle + IPU6_BASE_MSG_SEND_QUEUES);
117 	if (!token)
118 		return -EBUSY;
119 
120 	token->payload = dma_mapped_buf;
121 	token->buf_handle = (unsigned long)cpu_mapped_buf;
122 	token->send_type = send_type;
123 
124 	ipu6_send_put_token(ctx, stream_handle + IPU6_BASE_MSG_SEND_QUEUES);
125 
126 	return 0;
127 }
128 
ipu6_fw_isys_simple_cmd(struct ipu6_isys * isys,const unsigned int stream_handle,u16 send_type)129 int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
130 			    const unsigned int stream_handle, u16 send_type)
131 {
132 	return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
133 					send_type);
134 }
135 
ipu6_fw_isys_close(struct ipu6_isys * isys)136 int ipu6_fw_isys_close(struct ipu6_isys *isys)
137 {
138 	struct device *dev = &isys->adev->auxdev.dev;
139 	int retry = IPU6_ISYS_CLOSE_RETRY;
140 	unsigned long flags;
141 	void *fwcom;
142 	int ret;
143 
144 	/*
145 	 * Stop the isys fw. Actual close takes
146 	 * some time as the FW must stop its actions including code fetch
147 	 * to SP icache.
148 	 * spinlock to wait the interrupt handler to be finished
149 	 */
150 	spin_lock_irqsave(&isys->power_lock, flags);
151 	ret = ipu6_fw_com_close(isys->fwcom);
152 	fwcom = isys->fwcom;
153 	isys->fwcom = NULL;
154 	spin_unlock_irqrestore(&isys->power_lock, flags);
155 	if (ret)
156 		dev_err(dev, "Device close failure: %d\n", ret);
157 
158 	/* release probably fails if the close failed. Let's try still */
159 	do {
160 		usleep_range(400, 500);
161 		ret = ipu6_fw_com_release(fwcom, 0);
162 		retry--;
163 	} while (ret && retry);
164 
165 	if (ret) {
166 		dev_err(dev, "Device release time out %d\n", ret);
167 		spin_lock_irqsave(&isys->power_lock, flags);
168 		isys->fwcom = fwcom;
169 		spin_unlock_irqrestore(&isys->power_lock, flags);
170 	}
171 
172 	return ret;
173 }
174 
ipu6_fw_isys_cleanup(struct ipu6_isys * isys)175 void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
176 {
177 	int ret;
178 
179 	ret = ipu6_fw_com_release(isys->fwcom, 1);
180 	if (ret < 0)
181 		dev_warn(&isys->adev->auxdev.dev,
182 			 "Device busy, fw_com release failed.");
183 	isys->fwcom = NULL;
184 }
185 
start_sp(struct ipu6_bus_device * adev)186 static void start_sp(struct ipu6_bus_device *adev)
187 {
188 	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
189 	void __iomem *spc_regs_base = isys->pdata->base +
190 		isys->pdata->ipdata->hw_variant.spc_offset;
191 	u32 val = IPU6_ISYS_SPC_STATUS_START |
192 		IPU6_ISYS_SPC_STATUS_RUN |
193 		IPU6_ISYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
194 
195 	val |= isys->icache_prefetch ? IPU6_ISYS_SPC_STATUS_ICACHE_PREFETCH : 0;
196 
197 	writel(val, spc_regs_base + IPU6_ISYS_REG_SPC_STATUS_CTRL);
198 }
199 
query_sp(struct ipu6_bus_device * adev)200 static int query_sp(struct ipu6_bus_device *adev)
201 {
202 	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
203 	void __iomem *spc_regs_base = isys->pdata->base +
204 		isys->pdata->ipdata->hw_variant.spc_offset;
205 	u32 val;
206 
207 	val = readl(spc_regs_base + IPU6_ISYS_REG_SPC_STATUS_CTRL);
208 	/* return true when READY == 1, START == 0 */
209 	val &= IPU6_ISYS_SPC_STATUS_READY | IPU6_ISYS_SPC_STATUS_START;
210 
211 	return val == IPU6_ISYS_SPC_STATUS_READY;
212 }
213 
ipu6_isys_fwcom_cfg_init(struct ipu6_isys * isys,struct ipu6_fw_com_cfg * fwcom,unsigned int num_streams)214 static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
215 				    struct ipu6_fw_com_cfg *fwcom,
216 				    unsigned int num_streams)
217 {
218 	unsigned int max_send_queues, max_sram_blocks, max_devq_size;
219 	struct ipu6_fw_syscom_queue_config *input_queue_cfg;
220 	struct ipu6_fw_syscom_queue_config *output_queue_cfg;
221 	struct device *dev = &isys->adev->auxdev.dev;
222 	int type_proxy = IPU6_FW_ISYS_QUEUE_TYPE_PROXY;
223 	int type_dev = IPU6_FW_ISYS_QUEUE_TYPE_DEV;
224 	int type_msg = IPU6_FW_ISYS_QUEUE_TYPE_MSG;
225 	int base_dev_send = IPU6_BASE_DEV_SEND_QUEUES;
226 	int base_msg_send = IPU6_BASE_MSG_SEND_QUEUES;
227 	int base_msg_recv = IPU6_BASE_MSG_RECV_QUEUES;
228 	struct ipu6_fw_isys_fw_config *isys_fw_cfg;
229 	u32 num_in_message_queues;
230 	unsigned int max_streams;
231 	unsigned int size;
232 	unsigned int i;
233 
234 	max_streams = isys->pdata->ipdata->max_streams;
235 	max_send_queues = isys->pdata->ipdata->max_send_queues;
236 	max_sram_blocks = isys->pdata->ipdata->max_sram_blocks;
237 	max_devq_size = isys->pdata->ipdata->max_devq_size;
238 	num_in_message_queues = clamp(num_streams, 1U, max_streams);
239 	isys_fw_cfg = devm_kzalloc(dev, sizeof(*isys_fw_cfg), GFP_KERNEL);
240 	if (!isys_fw_cfg)
241 		return -ENOMEM;
242 
243 	isys_fw_cfg->num_send_queues[type_proxy] = IPU6_N_MAX_PROXY_SEND_QUEUES;
244 	isys_fw_cfg->num_send_queues[type_dev] = IPU6_N_MAX_DEV_SEND_QUEUES;
245 	isys_fw_cfg->num_send_queues[type_msg] = num_in_message_queues;
246 	isys_fw_cfg->num_recv_queues[type_proxy] = IPU6_N_MAX_PROXY_RECV_QUEUES;
247 	/* Common msg/dev return queue */
248 	isys_fw_cfg->num_recv_queues[type_dev] = 0;
249 	isys_fw_cfg->num_recv_queues[type_msg] = 1;
250 
251 	size = sizeof(*input_queue_cfg) * max_send_queues;
252 	input_queue_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
253 	if (!input_queue_cfg)
254 		return -ENOMEM;
255 
256 	size = sizeof(*output_queue_cfg) * IPU6_N_MAX_RECV_QUEUES;
257 	output_queue_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
258 	if (!output_queue_cfg)
259 		return -ENOMEM;
260 
261 	fwcom->input = input_queue_cfg;
262 	fwcom->output = output_queue_cfg;
263 
264 	fwcom->num_input_queues = isys_fw_cfg->num_send_queues[type_proxy] +
265 		isys_fw_cfg->num_send_queues[type_dev] +
266 		isys_fw_cfg->num_send_queues[type_msg];
267 
268 	fwcom->num_output_queues = isys_fw_cfg->num_recv_queues[type_proxy] +
269 		isys_fw_cfg->num_recv_queues[type_dev] +
270 		isys_fw_cfg->num_recv_queues[type_msg];
271 
272 	/* SRAM partitioning. Equal partitioning is set. */
273 	for (i = 0; i < max_sram_blocks; i++) {
274 		if (i < num_in_message_queues)
275 			isys_fw_cfg->buffer_partition.num_gda_pages[i] =
276 				(IPU6_DEVICE_GDA_NR_PAGES *
277 				 IPU6_DEVICE_GDA_VIRT_FACTOR) /
278 				num_in_message_queues;
279 		else
280 			isys_fw_cfg->buffer_partition.num_gda_pages[i] = 0;
281 	}
282 
283 	/* FW assumes proxy interface at fwcom queue 0 */
284 	for (i = 0; i < isys_fw_cfg->num_send_queues[type_proxy]; i++) {
285 		input_queue_cfg[i].token_size =
286 			sizeof(struct ipu6_fw_proxy_send_queue_token);
287 		input_queue_cfg[i].queue_size = IPU6_ISYS_SIZE_PROXY_SEND_QUEUE;
288 	}
289 
290 	for (i = 0; i < isys_fw_cfg->num_send_queues[type_dev]; i++) {
291 		input_queue_cfg[base_dev_send + i].token_size =
292 			sizeof(struct ipu6_fw_send_queue_token);
293 		input_queue_cfg[base_dev_send + i].queue_size = max_devq_size;
294 	}
295 
296 	for (i = 0; i < isys_fw_cfg->num_send_queues[type_msg]; i++) {
297 		input_queue_cfg[base_msg_send + i].token_size =
298 			sizeof(struct ipu6_fw_send_queue_token);
299 		input_queue_cfg[base_msg_send + i].queue_size =
300 			IPU6_ISYS_SIZE_SEND_QUEUE;
301 	}
302 
303 	for (i = 0; i < isys_fw_cfg->num_recv_queues[type_proxy]; i++) {
304 		output_queue_cfg[i].token_size =
305 			sizeof(struct ipu6_fw_proxy_resp_queue_token);
306 		output_queue_cfg[i].queue_size =
307 			IPU6_ISYS_SIZE_PROXY_RECV_QUEUE;
308 	}
309 	/* There is no recv DEV queue */
310 	for (i = 0; i < isys_fw_cfg->num_recv_queues[type_msg]; i++) {
311 		output_queue_cfg[base_msg_recv + i].token_size =
312 			sizeof(struct ipu6_fw_resp_queue_token);
313 		output_queue_cfg[base_msg_recv + i].queue_size =
314 			IPU6_ISYS_SIZE_RECV_QUEUE;
315 	}
316 
317 	fwcom->dmem_addr = isys->pdata->ipdata->hw_variant.dmem_offset;
318 	fwcom->specific_addr = isys_fw_cfg;
319 	fwcom->specific_size = sizeof(*isys_fw_cfg);
320 
321 	return 0;
322 }
323 
ipu6_fw_isys_init(struct ipu6_isys * isys,unsigned int num_streams)324 int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
325 {
326 	struct device *dev = &isys->adev->auxdev.dev;
327 	int retry = IPU6_ISYS_OPEN_RETRY;
328 	struct ipu6_fw_com_cfg fwcom = {
329 		.cell_start = start_sp,
330 		.cell_ready = query_sp,
331 		.buttress_boot_offset = SYSCOM_BUTTRESS_FW_PARAMS_ISYS_OFFSET,
332 	};
333 	int ret;
334 
335 	ipu6_isys_fwcom_cfg_init(isys, &fwcom, num_streams);
336 
337 	isys->fwcom = ipu6_fw_com_prepare(&fwcom, isys->adev,
338 					  isys->pdata->base);
339 	if (!isys->fwcom) {
340 		dev_err(dev, "isys fw com prepare failed\n");
341 		return -EIO;
342 	}
343 
344 	ret = ipu6_fw_com_open(isys->fwcom);
345 	if (ret) {
346 		dev_err(dev, "isys fw com open failed %d\n", ret);
347 		return ret;
348 	}
349 
350 	do {
351 		usleep_range(400, 500);
352 		if (ipu6_fw_com_ready(isys->fwcom))
353 			break;
354 		retry--;
355 	} while (retry > 0);
356 
357 	if (!retry) {
358 		dev_err(dev, "isys port open ready failed %d\n", ret);
359 		ipu6_fw_isys_close(isys);
360 		ret = -EIO;
361 	}
362 
363 	return ret;
364 }
365 
366 struct ipu6_fw_isys_resp_info_abi *
ipu6_fw_isys_get_resp(void * context,unsigned int queue)367 ipu6_fw_isys_get_resp(void *context, unsigned int queue)
368 {
369 	return ipu6_recv_get_token(context, queue);
370 }
371 
ipu6_fw_isys_put_resp(void * context,unsigned int queue)372 void ipu6_fw_isys_put_resp(void *context, unsigned int queue)
373 {
374 	ipu6_recv_put_token(context, queue);
375 }
376 
ipu6_fw_isys_dump_stream_cfg(struct device * dev,struct ipu6_fw_isys_stream_cfg_data_abi * cfg)377 void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
378 				  struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
379 {
380 	unsigned int i;
381 
382 	dev_dbg(dev, "-----------------------------------------------------\n");
383 	dev_dbg(dev, "IPU6_FW_ISYS_STREAM_CFG_DATA\n");
384 
385 	dev_dbg(dev, "compfmt = %d\n", cfg->vc);
386 	dev_dbg(dev, "src = %d\n", cfg->src);
387 	dev_dbg(dev, "vc = %d\n", cfg->vc);
388 	dev_dbg(dev, "isl_use = %d\n", cfg->isl_use);
389 	dev_dbg(dev, "sensor_type = %d\n", cfg->sensor_type);
390 
391 	dev_dbg(dev, "send_irq_sof_discarded = %d\n",
392 		cfg->send_irq_sof_discarded);
393 	dev_dbg(dev, "send_irq_eof_discarded = %d\n",
394 		cfg->send_irq_eof_discarded);
395 	dev_dbg(dev, "send_resp_sof_discarded = %d\n",
396 		cfg->send_resp_sof_discarded);
397 	dev_dbg(dev, "send_resp_eof_discarded = %d\n",
398 		cfg->send_resp_eof_discarded);
399 
400 	dev_dbg(dev, "crop:\n");
401 	dev_dbg(dev, "\t.left_top = [%d, %d]\n", cfg->crop.left_offset,
402 		cfg->crop.top_offset);
403 	dev_dbg(dev, "\t.right_bottom = [%d, %d]\n", cfg->crop.right_offset,
404 		cfg->crop.bottom_offset);
405 
406 	dev_dbg(dev, "nof_input_pins = %d\n", cfg->nof_input_pins);
407 	for (i = 0; i < cfg->nof_input_pins; i++) {
408 		dev_dbg(dev, "input pin[%d]:\n", i);
409 		dev_dbg(dev, "\t.dt = 0x%0x\n", cfg->input_pins[i].dt);
410 		dev_dbg(dev, "\t.mipi_store_mode = %d\n",
411 			cfg->input_pins[i].mipi_store_mode);
412 		dev_dbg(dev, "\t.bits_per_pix = %d\n",
413 			cfg->input_pins[i].bits_per_pix);
414 		dev_dbg(dev, "\t.mapped_dt = 0x%0x\n",
415 			cfg->input_pins[i].mapped_dt);
416 		dev_dbg(dev, "\t.input_res = %dx%d\n",
417 			cfg->input_pins[i].input_res.width,
418 			cfg->input_pins[i].input_res.height);
419 		dev_dbg(dev, "\t.mipi_decompression = %d\n",
420 			cfg->input_pins[i].mipi_decompression);
421 		dev_dbg(dev, "\t.capture_mode = %d\n",
422 			cfg->input_pins[i].capture_mode);
423 	}
424 
425 	dev_dbg(dev, "nof_output_pins = %d\n", cfg->nof_output_pins);
426 	for (i = 0; i < cfg->nof_output_pins; i++) {
427 		dev_dbg(dev, "output_pin[%d]:\n", i);
428 		dev_dbg(dev, "\t.input_pin_id = %d\n",
429 			cfg->output_pins[i].input_pin_id);
430 		dev_dbg(dev, "\t.output_res = %dx%d\n",
431 			cfg->output_pins[i].output_res.width,
432 			cfg->output_pins[i].output_res.height);
433 		dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride);
434 		dev_dbg(dev, "\t.pt = %d\n", cfg->output_pins[i].pt);
435 		dev_dbg(dev, "\t.payload_buf_size = %d\n",
436 			cfg->output_pins[i].payload_buf_size);
437 		dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft);
438 		dev_dbg(dev, "\t.watermark_in_lines = %d\n",
439 			cfg->output_pins[i].watermark_in_lines);
440 		dev_dbg(dev, "\t.send_irq = %d\n",
441 			cfg->output_pins[i].send_irq);
442 		dev_dbg(dev, "\t.reserve_compression = %d\n",
443 			cfg->output_pins[i].reserve_compression);
444 		dev_dbg(dev, "\t.snoopable = %d\n",
445 			cfg->output_pins[i].snoopable);
446 		dev_dbg(dev, "\t.error_handling_enable = %d\n",
447 			cfg->output_pins[i].error_handling_enable);
448 		dev_dbg(dev, "\t.sensor_type = %d\n",
449 			cfg->output_pins[i].sensor_type);
450 	}
451 	dev_dbg(dev, "-----------------------------------------------------\n");
452 }
453 
454 void
ipu6_fw_isys_dump_frame_buff_set(struct device * dev,struct ipu6_fw_isys_frame_buff_set_abi * buf,unsigned int outputs)455 ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
456 				 struct ipu6_fw_isys_frame_buff_set_abi *buf,
457 				 unsigned int outputs)
458 {
459 	unsigned int i;
460 
461 	dev_dbg(dev, "-----------------------------------------------------\n");
462 	dev_dbg(dev, "IPU6_FW_ISYS_FRAME_BUFF_SET\n");
463 
464 	for (i = 0; i < outputs; i++) {
465 		dev_dbg(dev, "output_pin[%d]:\n", i);
466 		dev_dbg(dev, "\t.out_buf_id = %llu\n",
467 			buf->output_pins[i].out_buf_id);
468 		dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr);
469 		dev_dbg(dev, "\t.compress = %d\n",
470 			buf->output_pins[i].compress);
471 	}
472 
473 	dev_dbg(dev, "send_irq_sof = 0x%x\n", buf->send_irq_sof);
474 	dev_dbg(dev, "send_irq_eof = 0x%x\n", buf->send_irq_eof);
475 	dev_dbg(dev, "send_resp_sof = 0x%x\n", buf->send_resp_sof);
476 	dev_dbg(dev, "send_resp_eof = 0x%x\n", buf->send_resp_eof);
477 	dev_dbg(dev, "send_irq_capture_ack = 0x%x\n",
478 		buf->send_irq_capture_ack);
479 	dev_dbg(dev, "send_irq_capture_done = 0x%x\n",
480 		buf->send_irq_capture_done);
481 	dev_dbg(dev, "send_resp_capture_ack = 0x%x\n",
482 		buf->send_resp_capture_ack);
483 	dev_dbg(dev, "send_resp_capture_done = 0x%x\n",
484 		buf->send_resp_capture_done);
485 
486 	dev_dbg(dev, "-----------------------------------------------------\n");
487 }
488