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