[PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops
Antti Laakso <[email protected]>
| Newsgroups | org.kernel.vger.linux-media |
|---|---|
| Message-ID | <[email protected]> |
The ipu7 isys firmware functions handle messaging with ipu7 hardware. Signed-off-by: Antti Laakso <[email protected]> --- drivers/media/pci/intel/ipu6/Makefile | 1 + drivers/media/pci/intel/ipu6/ipu6-bus.h | 2 + drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 3 +- .../media/pci/intel/ipu6/ipu6-isys-queue.c | 2 +- .../media/pci/intel/ipu6/ipu6-isys-queue.h | 2 + .../media/pci/intel/ipu6/ipu6-isys-video.c | 1 + .../media/pci/intel/ipu6/ipu6-isys-video.h | 1 + drivers/media/pci/intel/ipu6/ipu6-isys.c | 15 +- drivers/media/pci/intel/ipu6/ipu6-isys.h | 13 +- drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 2 + drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 465 ++++++++++++++++++ drivers/media/pci/intel/ipu6/ipu7-fw-isys.h | 258 ++++++++++ 12 files changed, 757 insertions(+), 8 deletions(-) create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile index 406e2e19df17..66986d5709ae 100644 --- a/drivers/media/pci/intel/ipu6/Makefile +++ b/drivers/media/pci/intel/ipu6/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6.o intel-ipu6-isys-y := ipu6-isys.o \ ipu6-isys-csi2.o \ ipu6-fw-isys.o \ + ipu7-fw-isys.o \ ipu6-isys-video.o \ ipu6-isys-queue.o \ ipu6-isys-subdev.o \ diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h index 62aa2b090699..aef8e4a66c4a 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-bus.h +++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h @@ -31,6 +31,7 @@ struct ipu6_bus_device { u64 *pkg_dir; dma_addr_t pkg_dir_dma_addr; unsigned int pkg_dir_size; + u32 fw_entry; }; struct ipu6_auxdrv_data { @@ -47,6 +48,7 @@ struct ipu6_auxdrv_data { #define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev) extern const struct ipu6_fw_isys_ops ipu6_fw_isys_ops; +extern const struct ipu6_fw_isys_ops ipu7_fw_isys_ops; struct ipu6_bus_device * ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent, diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c index 4ee5137f310e..3cad7d8f9ca9 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c +++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c @@ -15,6 +15,7 @@ #include "ipu6-isys.h" #include "ipu6-platform-isys-csi2-reg.h" #include "ipu6-platform-regs.h" +#include "ipu7-fw-isys.h" static const char send_msg_types[N_IPU6_FW_ISYS_SEND_TYPE][32] = { "STREAM_OPEN", @@ -602,7 +603,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev) } isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id, - struct isys_fw_msgs, ipu6.dummy); + struct isys_fw_msgs, dummy); ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg); if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS && diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c index 4cb1741445c6..38db162d64ca 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c @@ -684,7 +684,7 @@ static void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib) } } -static void +void ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id, u32 pin_addr, u64 time, bool error_check) { diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h index 51de14183ccf..5df47be0c181 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h @@ -63,4 +63,6 @@ void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl, void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream, struct ipu6_fw_isys_resp_info_abi *info); int ipu6_isys_queue_init(struct ipu6_isys_queue *aq); +void ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id, + u32 pin_addr, u64 time, bool error_check); #endif /* IPU6_ISYS_QUEUE_H */ diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c index 803450b0156e..560524e6e624 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c @@ -627,6 +627,7 @@ int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av, stream->nr_queues = nr_queues; atomic_set(&stream->sequence, 0); + atomic_set(&stream->buf_id, 0); stream->seq_index = 0; memset(stream->seq, 0, sizeof(stream->seq)); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h index 2ff53315d7b9..a7157646d563 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h @@ -44,6 +44,7 @@ struct sequence_info { struct ipu6_isys_stream { struct mutex mutex; atomic_t sequence; + atomic_t buf_id; unsigned int seq_index; struct sequence_info seq[IPU6_ISYS_MAX_PARALLEL_SOF]; int stream_source; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c index 159e769931b7..086c0f01ccda 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c @@ -931,6 +931,9 @@ void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg) spin_unlock_irqrestore(&isys->listlock, flags); } +static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data; +static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data; + static int isys_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *auxdev_id) { @@ -949,8 +952,8 @@ static int isys_probe(struct auxiliary_device *auxdev, if (!isys) return -ENOMEM; - adev->auxdrv_data = - (const struct ipu6_auxdrv_data *)auxdev_id->driver_data; + adev->auxdrv_data = IS_IPU7(isp) ? &ipu7_isys_auxdrv_data : + &ipu6_isys_auxdrv_data; adev->auxdrv = to_auxiliary_drv(auxdev->dev.driver); isys->adev = adev; isys->pdata = adev->pdata; @@ -1071,10 +1074,16 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = { .fw_ops = &ipu6_fw_isys_ops, }; +static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data = { + .isr = ipu6_isys_isr, + .isr_threaded = NULL, + .wake_isr_thread = false, + .fw_ops = &ipu7_fw_isys_ops, +}; + static const struct auxiliary_device_id ipu6_isys_id_table[] = { { .name = "intel_ipu6.isys", - .driver_data = (kernel_ulong_t)&ipu6_isys_auxdrv_data, }, { } }; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h index fa9bc2730d64..697c090cc3b1 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h @@ -17,6 +17,7 @@ #include "ipu6.h" #include "ipu6-fw-isys.h" +#include "ipu7-fw-isys.h" #include "ipu6-isys-csi2.h" #include "ipu6-isys-video.h" @@ -167,9 +168,15 @@ struct ipu6_isys { struct isys_fw_msgs { union { u64 dummy; - struct ipu6_fw_isys_frame_buff_set_abi frame; - struct ipu6_fw_isys_stream_cfg_data_abi stream; - } ipu6; + union { + struct ipu6_fw_isys_frame_buff_set_abi frame; + struct ipu6_fw_isys_stream_cfg_data_abi stream; + } ipu6; + union { + struct ipu7_fw_isys_frame_buff_set frame; + struct ipu7_fw_isys_stream_cfg stream; + } ipu7; + }; struct list_head head; dma_addr_t dma_addr; }; diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h index 10c09e759bed..097eaab99547 100644 --- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h +++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h @@ -25,6 +25,8 @@ struct ipu7_fw_com_context { dma_addr_t boot_config_dma_addr; u32 boot_config_size; u32 fw_entry; + struct ipu7_insys_config *fw_config; + dma_addr_t fw_config_dma_addr; }; struct ipu7_fw_com_queue_params_config { diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c new file mode 100644 index 000000000000..d35684a2cb58 --- /dev/null +++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Intel Corporation + */ + +#include "ipu6-bus.h" +#include "ipu6-dma.h" +#include "ipu6-isys.h" +#include "ipu7-boot.h" +#include "ipu7-fw-com.h" +#include "ipu7-fw-isys.h" + +static void ipu7_fw_isys_cleanup(struct ipu6_isys *isys) +{ + struct ipu6_bus_device *adev = isys->adev; + struct ipu7_fw_com_context *fwctx = isys->fwctx; + + if (!fwctx) + return; + + ipu7_release_boot_config(adev); + + if (fwctx->fw_config) { + ipu6_dma_free(adev, sizeof(*fwctx->fw_config), fwctx->fw_config, + fwctx->fw_config_dma_addr, 0); + fwctx->fw_config = NULL; + fwctx->fw_config_dma_addr = 0; + } + + isys->fwctx = NULL; +} + +static int ipu7_fw_isys_open(struct ipu6_isys *isys) +{ + return ipu7_boot_start_fw(isys->adev); +} + +static int ipu7_fw_isys_close(struct ipu6_isys *isys) +{ + int ret; + + ret = ipu7_boot_stop_fw(isys->adev); + if (ret) + return ret; + + ipu7_fw_isys_cleanup(isys); + + return ret; +} + +static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams) +{ + struct ipu7_fw_com_queue_config *queue_configs; + struct ipu6_bus_device *adev = isys->adev; + struct device *dev = &adev->auxdev.dev; + struct ipu7_insys_config *fw_config; + struct ipu7_fw_com_context *fwctx; + dma_addr_t fw_config_dma_addr; + unsigned int i, num_queues; + u32 freq; + int ret; + + /* Allocate and init firmware context. */ + fwctx = devm_kzalloc(dev, sizeof(struct ipu7_fw_com_context), + GFP_KERNEL); + if (!fwctx) + return -ENOMEM; + + fwctx->num_input_queues = IPU7_INSYS_MAX_INPUT_QUEUES; + fwctx->num_output_queues = IPU7_INSYS_MAX_OUTPUT_QUEUES; + num_queues = fwctx->num_input_queues + fwctx->num_output_queues; + + queue_configs = devm_kcalloc(dev, num_queues, sizeof(*queue_configs), + GFP_KERNEL); + if (!queue_configs) { + ipu7_fw_isys_cleanup(isys); + return -ENOMEM; + } + fwctx->fw_entry = adev->fw_entry; + fwctx->queue_configs = queue_configs; + queue_configs[IPU7_INSYS_OUTPUT_MSG_QUEUE].max_capacity = + IPU7_ISYS_SIZE_RECV_QUEUE; + queue_configs[IPU7_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes = + sizeof(struct ipu7_insys_resp); + queue_configs[IPU7_INSYS_OUTPUT_LOG_QUEUE].max_capacity = + IPU7_ISYS_SIZE_LOG_QUEUE; + queue_configs[IPU7_INSYS_OUTPUT_LOG_QUEUE].token_size_in_bytes = + sizeof(struct ipu7_insys_resp); + queue_configs[IPU7_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0; + queue_configs[IPU7_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0; + + queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].max_capacity = + IPU7_ISYS_MAX_STREAMS; + queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes = + sizeof(struct ipu7_insys_send_queue_token); + + for (i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) { + queue_configs[i].max_capacity = IPU7_ISYS_SIZE_SEND_QUEUE; + queue_configs[i].token_size_in_bytes = + sizeof(struct ipu7_insys_send_queue_token); + } + + /* Allocate ISYS subsys config. */ + fw_config = ipu6_dma_alloc(adev, sizeof(*fw_config), + &fw_config_dma_addr, GFP_KERNEL, 0); + if (!fw_config) { + dev_err(dev, "Failed to allocate isys subsys config.\n"); + ipu7_fw_isys_cleanup(isys); + return -ENOMEM; + } + fwctx->fw_config = fw_config; + fwctx->fw_config_dma_addr = fw_config_dma_addr; + memset(fw_config, 0, sizeof(*fw_config)); + fw_config->logger_config.use_source_severity = 0; + fw_config->logger_config.use_channels_enable_bitmask = 1; + fw_config->logger_config.channels_enable_bitmask = + IPU7_LOGGER_CFG_CHANNEL_ENABLE_SYSCOM; + fw_config->logger_config.hw_printf_buffer_base_addr = 0U; + fw_config->logger_config.hw_printf_buffer_size_bytes = 0U; + fw_config->wdt_config.wdt_timer1_us = 0; + fw_config->wdt_config.wdt_timer2_us = 0; + freq = ipu7_buttress_get_isys_freq(adev->isp); + + ipu6_dma_sync_single(adev, fw_config_dma_addr, + sizeof(struct ipu7_insys_config)); + + isys->fwctx = fwctx; + + ret = ipu7_init_boot_config(adev, queue_configs, num_queues, + freq, fw_config_dma_addr, 1U); + if (ret) { + ipu7_fw_isys_cleanup(isys); + return ret; + } + + ret = ipu7_fw_isys_open(isys); + if (ret) + ipu7_fw_isys_cleanup(isys); + + return ret; +} + +static struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu6_isys *isys) +{ + return ipu7_fw_com_get_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE); +} + +static void ipu7_fw_isys_put_resp(struct ipu6_isys *isys) +{ + ipu7_fw_com_put_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE); +} + +static int ipu7_isys_fw_pin_cfg(struct ipu6_isys_video *av, + struct ipu7_fw_isys_stream_cfg *cfg) +{ + struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad); + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity); + struct v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd); + struct ipu7_fw_isys_input_pin *input_pin; + struct ipu7_fw_isys_output_pin *output_pin; + struct ipu6_isys_stream *stream = av->stream; + struct ipu6_isys_queue *aq = &av->aq; + struct v4l2_mbus_framefmt fmt; + const struct ipu6_isys_pixelformat *pfmt = + ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0); + int input_pins = cfg->nof_input_pins++; + int output_pins; + u32 src_stream; + + src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index); + fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream); + + input_pin = &cfg->input_pins[input_pins]; + input_pin->input_res.width = fmt.width; + input_pin->input_res.height = fmt.height; + input_pin->dt = av->dt; + input_pin->disable_mipi_unpacking = 0; + if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE) + input_pin->disable_mipi_unpacking = 1; + input_pin->mapped_dt = IPU7_N_INSYS_MIPI_DATA_TYPE; + input_pin->dt_rename_mode = IPU7_INSYS_MIPI_DT_NO_RENAME; + input_pin->sync_msg_map = + IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF | + IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED | + IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF | + IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED; + + output_pins = cfg->nof_output_pins++; + aq->fw_output = output_pins; + stream->output_pins_queue[output_pins] = aq; + + output_pin = &cfg->output_pins[output_pins]; + memset(output_pin, 0, sizeof(*output_pin)); + output_pin->link.buffer_lines = 0; + output_pin->link.foreign_key = IPU7_MSG_LINK_FOREIGN_KEY_NONE; + output_pin->link.pbk_id = IPU7_MSG_LINK_PBK_ID_DONT_CARE; + output_pin->link.pbk_slot_id = IPU7_MSG_LINK_PBK_SLOT_ID_DONT_CARE; + output_pin->link.dest = 0; /* IPU_INSYS_OUTPUT_LINK_DEST_MEM */ + output_pin->link.use_sw_managed = 1; + output_pin->crop.line_top = 0; + output_pin->crop.line_bottom = 0; + output_pin->dpcm.enable = 0; + output_pin->ft = pfmt->css_pixelformat; + output_pin->stride = ipu6_isys_get_bytes_per_line(av); + output_pin->send_irq = 1; + output_pin->input_pin_id = input_pins; + + return 0; +} + +static int +ipu7_fw_isys_send_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) +{ + struct ipu7_fw_com_context *ctx = isys->fwctx; + /*struct device *dev = &isys->adev->auxdev.dev;*/ + struct ipu7_insys_send_queue_token *token; + + if (send_type >= N_IPU7_INSYS_SEND_TYPE) + return -EINVAL; + + if (cpu_mapped_buf) + clflush_cache_range(cpu_mapped_buf, size); + + token = ipu7_fw_com_get_token(ctx, stream_handle + + IPU7_INSYS_INPUT_MSG_QUEUE); + if (!token) + return -EBUSY; + + token->addr = dma_mapped_buf; + token->buf_handle = (unsigned long)cpu_mapped_buf; + token->send_type = send_type; + token->stream_id = stream_handle; + token->flag = IPU7_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE; + + ipu7_fw_com_put_token(ctx, stream_handle + IPU7_INSYS_INPUT_MSG_QUEUE); + /* now wakeup FW */ + ipu7_buttress_wakeup_isys(isys->adev->isp); + + return 0; +} + +static void ipu7_fw_isys_dump_stream_cfg(struct device *dev, + struct isys_fw_msgs *msg) +{ + struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream; + unsigned int i; + + dev_dbg(dev, "---------------------------\n"); + dev_dbg(dev, "IPU_FW_ISYS_STREAM_CFG_DATA\n"); + + dev_dbg(dev, ".port id %d\n", cfg->port_id); + dev_dbg(dev, ".vc %d\n", cfg->vc); + dev_dbg(dev, ".nof_input_pins = %d\n", cfg->nof_input_pins); + dev_dbg(dev, ".nof_output_pins = %d\n", cfg->nof_output_pins); + dev_dbg(dev, ".stream_msg_map = 0x%x\n", cfg->stream_msg_map); + + for (i = 0; i < cfg->nof_input_pins; i++) { + dev_dbg(dev, ".input_pin[%d]:\n", i); + dev_dbg(dev, "\t.dt = 0x%0x\n", + cfg->input_pins[i].dt); + dev_dbg(dev, "\t.disable_mipi_unpacking = %d\n", + cfg->input_pins[i].disable_mipi_unpacking); + dev_dbg(dev, "\t.dt_rename_mode = %d\n", + cfg->input_pins[i].dt_rename_mode); + dev_dbg(dev, "\t.mapped_dt = 0x%0x\n", + cfg->input_pins[i].mapped_dt); + dev_dbg(dev, "\t.input_res = %d x %d\n", + cfg->input_pins[i].input_res.width, + cfg->input_pins[i].input_res.height); + dev_dbg(dev, "\t.sync_msg_map = 0x%x\n", + cfg->input_pins[i].sync_msg_map); + } + + for (i = 0; i < cfg->nof_output_pins; i++) { + dev_dbg(dev, ".output_pin[%d]:\n", i); + dev_dbg(dev, "\t.input_pin_id = %d\n", + cfg->output_pins[i].input_pin_id); + dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride); + dev_dbg(dev, "\t.send_irq = %d\n", + cfg->output_pins[i].send_irq); + dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft); + + dev_dbg(dev, "\t.link.buffer_lines = %d\n", + cfg->output_pins[i].link.buffer_lines); + dev_dbg(dev, "\t.link.foreign_key = %d\n", + cfg->output_pins[i].link.foreign_key); + dev_dbg(dev, "\t.link.granularity_pointer_update = %d\n", + cfg->output_pins[i].link.granularity_pointer_update); + dev_dbg(dev, "\t.link.msg_link_streaming_mode = %d\n", + cfg->output_pins[i].link.msg_link_streaming_mode); + dev_dbg(dev, "\t.link.pbk_id = %d\n", + cfg->output_pins[i].link.pbk_id); + dev_dbg(dev, "\t.link.pbk_slot_id = %d\n", + cfg->output_pins[i].link.pbk_slot_id); + dev_dbg(dev, "\t.link.dest = %d\n", + cfg->output_pins[i].link.dest); + dev_dbg(dev, "\t.link.use_sw_managed = %d\n", + cfg->output_pins[i].link.use_sw_managed); + dev_dbg(dev, "\t.link.is_snoop = %d\n", + cfg->output_pins[i].link.is_snoop); + + dev_dbg(dev, "\t.crop.line_top = %d\n", + cfg->output_pins[i].crop.line_top); + dev_dbg(dev, "\t.crop.line_bottom = %d\n", + cfg->output_pins[i].crop.line_bottom); + + dev_dbg(dev, "\t.dpcm_enable = %d\n", + cfg->output_pins[i].dpcm.enable); + dev_dbg(dev, "\t.dpcm.type = %d\n", + cfg->output_pins[i].dpcm.type); + dev_dbg(dev, "\t.dpcm.predictor = %d\n", + cfg->output_pins[i].dpcm.predictor); + } + dev_dbg(dev, "---------------------------\n"); +} + +static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev, + struct isys_fw_msgs *msg, + unsigned int outputs) +{ + struct ipu7_fw_isys_frame_buff_set *buf = &msg->ipu7.frame; + unsigned int i; + + dev_dbg(dev, "--------------------------\n"); + dev_dbg(dev, "IPU_ISYS_BUFF_SET\n"); + dev_dbg(dev, ".capture_msg_map = %d\n", buf->capture_msg_map); + dev_dbg(dev, ".frame_id = %d\n", buf->frame_id); + dev_dbg(dev, ".skip_frame = %d\n", buf->skip_frame); + + for (i = 0; i < outputs; i++) { + dev_dbg(dev, ".output_pin[%d]:\n", i); + dev_dbg(dev, "\t.user_token = %llx\n", + buf->output_pins[i].user_token); + dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr); + } + dev_dbg(dev, "---------------------------\n"); +} + +static int ipu7_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av, + struct isys_fw_msgs *msg) +{ + struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream; + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu6_isys_stream *stream = av->stream; + struct ipu6_isys_queue *aq; + + memset(cfg, 0, sizeof(*cfg)); + cfg->port_id = stream->stream_source; + cfg->vc = stream->vc; + cfg->stream_msg_map = IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP | + IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ; + + list_for_each_entry(aq, &stream->queues, node) { + struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq); + int ret = ipu7_isys_fw_pin_cfg(__av, cfg); + + if (ret < 0) + return ret; + } + + stream->nr_output_pins = cfg->nof_output_pins; + + ipu7_fw_isys_dump_stream_cfg(dev, msg); + + return 0; +} + +static void +ipu7_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb, + struct ipu7_fw_isys_frame_buff_set *set) +{ + struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); + + set->output_pins[aq->fw_output].addr = ivb->dma_addr; + set->output_pins[aq->fw_output].user_token = (u64)(uintptr_t)set; +} + +static void +ipu7_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg, + struct ipu6_isys_stream *stream, + struct ipu6_isys_buffer_list *bl) +{ + struct ipu7_fw_isys_frame_buff_set *set = &msg->ipu7.frame; + struct ipu6_isys_buffer *ib; + + WARN_ON(!bl->nbufs); + + memset(set, 0, sizeof(*set)); + set->capture_msg_map = IPU7_INSYS_FRAME_ENABLE_MSG_SEND_RESP | + IPU7_INSYS_FRAME_ENABLE_MSG_SEND_IRQ; + set->frame_id = atomic_fetch_inc(&stream->buf_id) % 256; + + list_for_each_entry(ib, &bl->head, head) { + struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib); + + ipu7_isys_buf_to_fw_frame_buf_pin(vb, set); + } + + dev_dbg(&stream->isys->adev->auxdev.dev, + "ipu7 frame_buf: cap_map=0x%x fid=%u opin[0].addr=0x%x token=0x%llx\n", + set->capture_msg_map, set->frame_id, + set->output_pins[0].addr, set->output_pins[0].user_token); +} + +static int ipu7_fw_isys_stream_open(struct ipu6_isys *isys, + const unsigned int stream_handle, + struct isys_fw_msgs *msg) +{ + return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.stream, + msg->dma_addr, sizeof(msg->ipu7.stream), + IPU7_INSYS_SEND_TYPE_STREAM_OPEN); +} + +static int ipu7_fw_isys_stream_close(struct ipu6_isys *isys, + const unsigned int stream_handle) +{ + return ipu7_fw_isys_send_cmd(isys, stream_handle, NULL, 0, 0, + IPU7_INSYS_SEND_TYPE_STREAM_CLOSE); +} + +static int ipu7_fw_isys_stream_flush(struct ipu6_isys *isys, + const unsigned int stream_handle) +{ + return ipu7_fw_isys_send_cmd(isys, stream_handle, NULL, 0, 0, + IPU7_INSYS_SEND_TYPE_STREAM_FLUSH); +} + +static int ipu7_fw_isys_stream_start(struct ipu6_isys *isys, + const unsigned int stream_handle, + struct isys_fw_msgs *msg, bool capture) +{ + return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.frame, + msg->dma_addr, sizeof(msg->ipu7.frame), + IPU7_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE); +} + +static int ipu7_fw_isys_stream_capture(struct ipu6_isys *isys, + const unsigned int stream_handle, + struct isys_fw_msgs *msg) +{ + return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.frame, + msg->dma_addr, sizeof(msg->ipu7.frame), + IPU7_INSYS_SEND_TYPE_STREAM_CAPTURE); +} + +const struct ipu6_fw_isys_ops ipu7_fw_isys_ops = { + .init = ipu7_fw_isys_init, + .close = ipu7_fw_isys_close, + .send_cmd = ipu7_fw_isys_send_cmd, + .cleanup = ipu7_fw_isys_cleanup, + .prepare_stream_cfg = ipu7_fw_isys_prepare_stream_cfg, + .prepare_buf_set = ipu7_fw_isys_prepare_buf_set, + .stream_open = ipu7_fw_isys_stream_open, + .stream_start = ipu7_fw_isys_stream_start, + .stream_capture = ipu7_fw_isys_stream_capture, + .stream_flush = ipu7_fw_isys_stream_flush, + .stream_close = ipu7_fw_isys_stream_close, + .dump_stream_cfg = ipu7_fw_isys_dump_stream_cfg, + .dump_frame_buf_set = ipu7_fw_isys_dump_frame_buf_set, +}; diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h new file mode 100644 index 000000000000..122531065362 --- /dev/null +++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2026 Intel Corporation */ + +#ifndef IPU7_FW_ISYS_H +#define IPU7_FW_ISYS_H + +#define IPU7_FWLOG_MAX_LOGGER_SOURCES (64U) +#define IPU7_INSYS_MAX_OUTPUT_QUEUES 3U +#define IPU7_INSYS_STREAM_ID_MAX 16U +#define IPU7_INSYS_MAX_INPUT_QUEUES (IPU7_INSYS_STREAM_ID_MAX + 1U) +#define IPU7_INSYS_OUTPUT_MSG_QUEUE 0U +#define IPU7_INSYS_OUTPUT_LOG_QUEUE 1U +#define IPU7_INSYS_OUTPUT_RESERVED_QUEUE 2U +#define IPU7_INSYS_INPUT_DEV_QUEUE 3U + +#define IPU7_INSYS_INPUT_FIRST_QUEUE 3U +#define IPU7_INSYS_INPUT_MSG_QUEUE 4U +#define IPU7_INSYS_INPUT_MSG_MAX_QUEUE 16U + +#define IPU7_MSG_ERR_MAX_DETAILS 4U +#define IPU7_ISYS_SIZE_RECV_QUEUE 40U +#define IPU7_ISYS_SIZE_LOG_QUEUE 256U +#define IPU7_ISYS_SIZE_SEND_QUEUE 40U +#define IPU7_ISYS_NUM_RECV_QUEUE 1U +#define IPU7_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE 0U + +#define IPU7_LOGGER_CFG_CHANNEL_ENABLE_SYSCOM BIT(1) + +#define IPU7_ISYS_MAX_STREAMS 16U +#define IPU7_MAX_OPINS 4 +#define IPU7_MAX_IPINS 4 + +#define IPU7_N_INSYS_MIPI_DATA_TYPE 0x40 + +#define IPU7_MSG_LINK_FOREIGN_KEY_NONE (65535U) +#define IPU7_MSG_LINK_PBK_ID_DONT_CARE (255U) +#define IPU7_MSG_LINK_PBK_SLOT_ID_DONT_CARE (255U) + +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF BIT(0) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF BIT(1) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF BIT(2) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF BIT(3) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED BIT(4) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED BIT(5) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED BIT(6) +#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED BIT(7) + +#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE BIT(0) +#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE BIT(1) +#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK BIT(2) +#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK BIT(3) +#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK BIT(4) +#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK BIT(5) +#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK BIT(6) +#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK BIT(7) +#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK BIT(8) +#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK BIT(9) + +#define IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP ( \ + IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE | \ + IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK | \ + IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK | \ + IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK | \ + IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK) +#define IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ ( \ + IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE | \ + IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK | \ + IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK | \ + IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK | \ + IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK) + +#define IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK BIT(0) +#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK BIT(1) +#define IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE BIT(2) +#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE BIT(3) +#define IPU7_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY BIT(4) +#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY BIT(5) + +#define IPU7_INSYS_FRAME_ENABLE_MSG_SEND_RESP ( \ + IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK | \ + IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE | \ + IPU7_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY) +#define IPU7_INSYS_FRAME_ENABLE_MSG_SEND_IRQ ( \ + IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK | \ + IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE | \ + IPU7_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY) + +enum ipu7_insys_send_type { + IPU7_INSYS_SEND_TYPE_STREAM_OPEN = 0, + IPU7_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE = 1, + IPU7_INSYS_SEND_TYPE_STREAM_CAPTURE = 2, + IPU7_INSYS_SEND_TYPE_STREAM_ABORT = 3, + IPU7_INSYS_SEND_TYPE_STREAM_FLUSH = 4, + IPU7_INSYS_SEND_TYPE_STREAM_CLOSE = 5, + N_IPU7_INSYS_SEND_TYPE +}; + +enum ipu7_insys_resp_type { + IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE = 0, + IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK = 1, + IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK = 2, + IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK = 3, + IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK = 4, + IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK = 5, + IPU7_INSYS_RESP_TYPE_PIN_DATA_READY = 6, + IPU7_INSYS_RESP_TYPE_FRAME_SOF = 7, + IPU7_INSYS_RESP_TYPE_FRAME_EOF = 8, + IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE = 9, + IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE = 10, + IPU7_INSYS_RESP_TYPE_PWM_IRQ = 11, + N_IPU7_INSYS_RESP_TYPE +}; + +enum ipu7_insys_mipi_dt_rename_mode { + IPU7_INSYS_MIPI_DT_NO_RENAME = 0, + IPU7_INSYS_MIPI_DT_RENAMED_MODE = 1, + N_IPU7_INSYS_MIPI_DT_MODE +}; + +struct ipu7_fw_isys_logger_config { + u8 use_source_severity; + u8 source_severity[IPU7_FWLOG_MAX_LOGGER_SOURCES]; + u8 use_channels_enable_bitmask; + u8 channels_enable_bitmask; + u8 padding[1]; + u32 hw_printf_buffer_base_addr; + u32 hw_printf_buffer_size_bytes; +}; + +struct ipu7_wdt_abi { + u32 wdt_timer1_us; + u32 wdt_timer2_us; +}; + +struct ipu7_insys_config { + u32 timeout_val_ms; + struct ipu7_fw_isys_logger_config logger_config; + struct ipu7_wdt_abi wdt_config; +}; + +struct ipu7_insys_capture_output_pin_payload { + u64 user_token; + u32 addr; + u8 pad[4]; +}; + +struct ipu7_fw_isys_msg_err { + u32 err_group; + u32 err_code; + u32 err_detail[IPU7_MSG_ERR_MAX_DETAILS]; +}; + +struct ipu7_insys_resp { + u64 buf_id; + struct ipu7_insys_capture_output_pin_payload pin; + struct ipu7_fw_isys_msg_err error_info; + u32 timestamp[2]; + u8 type; + u8 msg_link_streaming_mode; + u8 stream_id; + u8 pin_id; + u8 frame_id; + u8 skip_frame; + u8 pad[2]; +}; + +struct ipu7_insys_resp_queue_token { + struct ipu7_insys_resp resp_info; +}; + +struct ipu7_insys_send_queue_token { + u64 buf_handle; + u32 addr; + u16 stream_id; + u8 send_type; + u8 flag; +}; + +struct ipu7_fw_isys_output_link { + u32 buffer_lines; + u16 foreign_key; + u16 granularity_pointer_update; + u8 msg_link_streaming_mode; + u8 pbk_id; + u8 pbk_slot_id; + u8 dest; + u8 use_sw_managed; + u8 is_snoop; + u8 pad[2]; +} __packed; + +struct ipu7_fw_isys_output_cropping { + u16 line_top; + u16 line_bottom; +} __packed; + +struct ipu7_fw_isys_output_dpcm { + u8 enable; + u8 type; + u8 predictor; + u8 pad; +} __packed; + +struct ipu7_fw_isys_output_pin { + struct ipu7_fw_isys_output_link link; + struct ipu7_fw_isys_output_cropping crop; + struct ipu7_fw_isys_output_dpcm dpcm; + u32 stride; + u16 ft; + u8 send_irq; + u8 input_pin_id; + u8 early_ack_en; + u8 pad[3]; +} __packed; + +struct ipu7_fw_isys_resolution { + u32 width; + u32 height; +} __packed; + +struct ipu7_fw_isys_input_pin { + struct ipu7_fw_isys_resolution input_res; + u16 sync_msg_map; + u8 dt; + u8 disable_mipi_unpacking; + u8 dt_rename_mode; + u8 mapped_dt; + u8 pad[2]; +} __packed; + +struct ipu7_fw_isys_stream_cfg { + struct ipu7_fw_isys_input_pin input_pins[IPU7_MAX_IPINS]; + struct ipu7_fw_isys_output_pin output_pins[IPU7_MAX_OPINS]; + u16 stream_msg_map; + u8 port_id; + u8 vc; + u8 nof_input_pins; + u8 nof_output_pins; + u8 pad[2]; +} __packed; + +struct ipu7_fw_isys_capture_output_pin { + u64 user_token; + u32 addr; + u8 pad[4]; +} __packed; + +struct ipu7_fw_isys_frame_buff_set { + struct ipu7_fw_isys_capture_output_pin output_pins[IPU7_MAX_OPINS]; + u8 capture_msg_map; + u8 frame_id; + u8 skip_frame; + u8 pad[5]; +} __packed; + +struct ipu6_fw_isys_ops *ipu7_fw_isys_get_ops(void); + +#endif -- 2.55.0