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
19static 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
29static 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
50int 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
93int 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
129int 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
136int 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
175void 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
186static 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
200static 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
214static 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
324int 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
366struct ipu6_fw_isys_resp_info_abi *
367ipu6_fw_isys_get_resp(void *context, unsigned int queue)
368{
369	return ipu6_recv_get_token(context, queue);
370}
371
372void ipu6_fw_isys_put_resp(void *context, unsigned int queue)
373{
374	ipu6_recv_put_token(context, queue);
375}
376
377void 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
454void
455ipu6_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