1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013--2024 Intel Corporation
6 #include <linux/cacheflush.h>
7 #include <linux/delay.h>
8 #include <linux/device.h>
10 #include <linux/spinlock.h>
11 #include <linux/types.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"
19 static const char send_msg_types
[N_IPU6_FW_ISYS_SEND_TYPE
][32] = {
22 "STREAM_START_AND_CAPTURE",
29 static int handle_proxy_response(struct ipu6_isys
*isys
, unsigned int req_id
)
31 struct device
*dev
= &isys
->adev
->auxdev
.dev
;
32 struct ipu6_fw_isys_proxy_resp_info_abi
*resp
;
35 resp
= ipu6_recv_get_token(isys
->fwcom
, IPU6_BASE_PROXY_RECV_QUEUES
);
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
);
43 ret
= req_id
== resp
->request_id
? 0 : -EIO
;
45 ipu6_recv_put_token(isys
->fwcom
, IPU6_BASE_PROXY_RECV_QUEUES
);
50 int ipu6_fw_isys_send_proxy_token(struct ipu6_isys
*isys
,
53 unsigned int offset
, u32 value
)
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;
62 "proxy send: req_id 0x%x, index %d, offset 0x%x, value 0x%x\n",
63 req_id
, index
, offset
, value
);
65 token
= ipu6_send_get_token(ctx
, IPU6_BASE_PROXY_SEND_QUEUES
);
69 token
->request_id
= req_id
;
70 token
->region_index
= index
;
71 token
->offset
= offset
;
73 ipu6_send_put_token(ctx
, IPU6_BASE_PROXY_SEND_QUEUES
);
76 usleep_range(100, 110);
77 ret
= handle_proxy_response(isys
, req_id
);
81 dev_err(dev
, "Proxy respond with unexpected id\n");
85 } while (ret
&& timeout
);
88 dev_err(dev
, "Proxy response timed out\n");
93 int ipu6_fw_isys_complex_cmd(struct ipu6_isys
*isys
,
94 const unsigned int stream_handle
,
96 dma_addr_t dma_mapped_buf
,
97 size_t size
, u16 send_type
)
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
;
103 if (send_type
>= N_IPU6_FW_ISYS_SEND_TYPE
)
106 dev_dbg(dev
, "send_token: %s\n", send_msg_types
[send_type
]);
109 * Time to flush cache in case we have some payload. Not all messages
113 clflush_cache_range(cpu_mapped_buf
, size
);
115 token
= ipu6_send_get_token(ctx
,
116 stream_handle
+ IPU6_BASE_MSG_SEND_QUEUES
);
120 token
->payload
= dma_mapped_buf
;
121 token
->buf_handle
= (unsigned long)cpu_mapped_buf
;
122 token
->send_type
= send_type
;
124 ipu6_send_put_token(ctx
, stream_handle
+ IPU6_BASE_MSG_SEND_QUEUES
);
129 int ipu6_fw_isys_simple_cmd(struct ipu6_isys
*isys
,
130 const unsigned int stream_handle
, u16 send_type
)
132 return ipu6_fw_isys_complex_cmd(isys
, stream_handle
, NULL
, 0, 0,
136 int ipu6_fw_isys_close(struct ipu6_isys
*isys
)
138 struct device
*dev
= &isys
->adev
->auxdev
.dev
;
139 int retry
= IPU6_ISYS_CLOSE_RETRY
;
145 * Stop the isys fw. Actual close takes
146 * some time as the FW must stop its actions including code fetch
148 * spinlock to wait the interrupt handler to be finished
150 spin_lock_irqsave(&isys
->power_lock
, flags
);
151 ret
= ipu6_fw_com_close(isys
->fwcom
);
154 spin_unlock_irqrestore(&isys
->power_lock
, flags
);
156 dev_err(dev
, "Device close failure: %d\n", ret
);
158 /* release probably fails if the close failed. Let's try still */
160 usleep_range(400, 500);
161 ret
= ipu6_fw_com_release(fwcom
, 0);
163 } while (ret
&& retry
);
166 dev_err(dev
, "Device release time out %d\n", ret
);
167 spin_lock_irqsave(&isys
->power_lock
, flags
);
169 spin_unlock_irqrestore(&isys
->power_lock
, flags
);
175 void ipu6_fw_isys_cleanup(struct ipu6_isys
*isys
)
179 ret
= ipu6_fw_com_release(isys
->fwcom
, 1);
181 dev_warn(&isys
->adev
->auxdev
.dev
,
182 "Device busy, fw_com release failed.");
186 static void start_sp(struct ipu6_bus_device
*adev
)
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
;
195 val
|= isys
->icache_prefetch
? IPU6_ISYS_SPC_STATUS_ICACHE_PREFETCH
: 0;
197 writel(val
, spc_regs_base
+ IPU6_ISYS_REG_SPC_STATUS_CTRL
);
200 static int query_sp(struct ipu6_bus_device
*adev
)
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
;
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
;
211 return val
== IPU6_ISYS_SPC_STATUS_READY
;
214 static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys
*isys
,
215 struct ipu6_fw_com_cfg
*fwcom
,
216 unsigned int num_streams
)
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
;
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
);
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;
251 size
= sizeof(*input_queue_cfg
) * max_send_queues
;
252 input_queue_cfg
= devm_kzalloc(dev
, size
, GFP_KERNEL
);
253 if (!input_queue_cfg
)
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
)
261 fwcom
->input
= input_queue_cfg
;
262 fwcom
->output
= output_queue_cfg
;
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
];
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
];
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
;
280 isys_fw_cfg
->buffer_partition
.num_gda_pages
[i
] = 0;
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
;
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
;
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
;
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
;
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
;
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
);
324 int ipu6_fw_isys_init(struct ipu6_isys
*isys
, unsigned int num_streams
)
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
,
335 ipu6_isys_fwcom_cfg_init(isys
, &fwcom
, num_streams
);
337 isys
->fwcom
= ipu6_fw_com_prepare(&fwcom
, isys
->adev
,
340 dev_err(dev
, "isys fw com prepare failed\n");
344 ret
= ipu6_fw_com_open(isys
->fwcom
);
346 dev_err(dev
, "isys fw com open failed %d\n", ret
);
351 usleep_range(400, 500);
352 if (ipu6_fw_com_ready(isys
->fwcom
))
358 dev_err(dev
, "isys port open ready failed %d\n", ret
);
359 ipu6_fw_isys_close(isys
);
366 struct ipu6_fw_isys_resp_info_abi
*
367 ipu6_fw_isys_get_resp(void *context
, unsigned int queue
)
369 return ipu6_recv_get_token(context
, queue
);
372 void ipu6_fw_isys_put_resp(void *context
, unsigned int queue
)
374 ipu6_recv_put_token(context
, queue
);
377 void ipu6_fw_isys_dump_stream_cfg(struct device
*dev
,
378 struct ipu6_fw_isys_stream_cfg_data_abi
*cfg
)
382 dev_dbg(dev
, "-----------------------------------------------------\n");
383 dev_dbg(dev
, "IPU6_FW_ISYS_STREAM_CFG_DATA\n");
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
);
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
);
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
);
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
);
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
);
451 dev_dbg(dev
, "-----------------------------------------------------\n");
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
)
461 dev_dbg(dev
, "-----------------------------------------------------\n");
462 dev_dbg(dev
, "IPU6_FW_ISYS_FRAME_BUFF_SET\n");
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
);
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
);
486 dev_dbg(dev
, "-----------------------------------------------------\n");