1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2022 - 2025 Intel Corporation 4 */ 5 6 #include <linux/bug.h> 7 #include <linux/delay.h> 8 #include <linux/device.h> 9 #include <linux/dma-mapping.h> 10 #include <linux/module.h> 11 #include <linux/iopoll.h> 12 #include <linux/string.h> 13 #include <linux/types.h> 14 15 #include "abi/ipu7_fw_boot_abi.h" 16 17 #include "ipu7.h" 18 #include "ipu7-boot.h" 19 #include "ipu7-bus.h" 20 #include "ipu7-buttress-regs.h" 21 #include "ipu7-dma.h" 22 #include "ipu7-platform-regs.h" 23 #include "ipu7-syscom.h" 24 25 #define IPU_FW_START_STOP_TIMEOUT 2000 26 #define IPU_BOOT_CELL_RESET_TIMEOUT (2 * USEC_PER_SEC) 27 #define BOOT_STATE_IS_CRITICAL(s) IA_GOFO_FW_BOOT_STATE_IS_CRITICAL(s) 28 #define BOOT_STATE_IS_READY(s) ((s) == IA_GOFO_FW_BOOT_STATE_READY) 29 #define BOOT_STATE_IS_INACTIVE(s) ((s) == IA_GOFO_FW_BOOT_STATE_INACTIVE) 30 31 struct ipu7_boot_context { 32 u32 base; 33 u32 dmem_address; 34 u32 status_ctrl_reg; 35 u32 fw_start_address_reg; 36 u32 fw_code_base_reg; 37 }; 38 39 static const struct ipu7_boot_context contexts[IPU_SUBSYS_NUM] = { 40 { 41 /* ISYS */ 42 .dmem_address = IPU_ISYS_DMEM_OFFSET, 43 .status_ctrl_reg = BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS, 44 .fw_start_address_reg = BUTTRESS_REG_DRV_IS_UCX_START_ADDR, 45 .fw_code_base_reg = IS_UC_CTRL_BASE 46 }, 47 { 48 /* PSYS */ 49 .dmem_address = IPU_PSYS_DMEM_OFFSET, 50 .status_ctrl_reg = BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS, 51 .fw_start_address_reg = BUTTRESS_REG_DRV_PS_UCX_START_ADDR, 52 .fw_code_base_reg = PS_UC_CTRL_BASE 53 } 54 }; 55 56 static u32 get_fw_boot_reg_addr(const struct ipu7_bus_device *adev, 57 enum ia_gofo_buttress_reg_id reg) 58 { 59 u32 base = (adev->subsys == IPU_IS) ? 0U : (u32)IA_GOFO_FW_BOOT_ID_MAX; 60 61 return BUTTRESS_FW_BOOT_PARAMS_ENTRY(base + (u32)reg); 62 } 63 64 static void write_fw_boot_param(const struct ipu7_bus_device *adev, 65 enum ia_gofo_buttress_reg_id reg, 66 u32 val) 67 { 68 void __iomem *base = adev->isp->base; 69 70 dev_dbg(&adev->auxdev.dev, 71 "write boot param reg: %d addr: %x val: 0x%x\n", 72 reg, get_fw_boot_reg_addr(adev, reg), val); 73 writel(val, base + get_fw_boot_reg_addr(adev, reg)); 74 } 75 76 static u32 read_fw_boot_param(const struct ipu7_bus_device *adev, 77 enum ia_gofo_buttress_reg_id reg) 78 { 79 void __iomem *base = adev->isp->base; 80 81 return readl(base + get_fw_boot_reg_addr(adev, reg)); 82 } 83 84 static int ipu7_boot_cell_reset(const struct ipu7_bus_device *adev) 85 { 86 const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; 87 const struct device *dev = &adev->auxdev.dev; 88 u32 ucx_ctrl_status = ctx->status_ctrl_reg; 89 u32 timeout = IPU_BOOT_CELL_RESET_TIMEOUT; 90 void __iomem *base = adev->isp->base; 91 u32 val, val2; 92 int ret; 93 94 dev_dbg(dev, "cell enter reset...\n"); 95 val = readl(base + ucx_ctrl_status); 96 dev_dbg(dev, "cell_ctrl_reg addr = 0x%x, val = 0x%x\n", 97 ucx_ctrl_status, val); 98 99 dev_dbg(dev, "force cell reset...\n"); 100 val |= UCX_CTL_RESET; 101 val &= ~UCX_CTL_RUN; 102 103 dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", 104 ucx_ctrl_status, val); 105 writel(val, base + ucx_ctrl_status); 106 107 ret = readl_poll_timeout(base + ucx_ctrl_status, val2, 108 (val2 & 0x3U) == (val & 0x3U), 100, timeout); 109 if (ret) { 110 dev_err(dev, "cell enter reset timeout. status: 0x%x\n", val2); 111 return -ETIMEDOUT; 112 } 113 114 dev_dbg(dev, "cell exit reset...\n"); 115 val = readl(base + ucx_ctrl_status); 116 WARN((!(val & UCX_CTL_RESET) || val & UCX_CTL_RUN), 117 "cell status 0x%x", val); 118 119 val &= ~(UCX_CTL_RESET | UCX_CTL_RUN); 120 dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", 121 ucx_ctrl_status, val); 122 writel(val, base + ucx_ctrl_status); 123 124 ret = readl_poll_timeout(base + ucx_ctrl_status, val2, 125 (val2 & 0x3U) == (val & 0x3U), 100, timeout); 126 if (ret) { 127 dev_err(dev, "cell exit reset timeout. status: 0x%x\n", val2); 128 return -ETIMEDOUT; 129 } 130 131 return 0; 132 } 133 134 static void ipu7_boot_cell_start(const struct ipu7_bus_device *adev) 135 { 136 const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; 137 void __iomem *base = adev->isp->base; 138 const struct device *dev = &adev->auxdev.dev; 139 u32 val; 140 141 dev_dbg(dev, "starting cell...\n"); 142 val = readl(base + ctx->status_ctrl_reg); 143 WARN_ON(val & (UCX_CTL_RESET | UCX_CTL_RUN)); 144 145 val &= ~UCX_CTL_RESET; 146 val |= UCX_CTL_RUN; 147 dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", 148 ctx->status_ctrl_reg, val); 149 writel(val, base + ctx->status_ctrl_reg); 150 } 151 152 static void ipu7_boot_cell_stop(const struct ipu7_bus_device *adev) 153 { 154 const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; 155 void __iomem *base = adev->isp->base; 156 const struct device *dev = &adev->auxdev.dev; 157 u32 val; 158 159 dev_dbg(dev, "stopping cell...\n"); 160 161 val = readl(base + ctx->status_ctrl_reg); 162 val &= ~UCX_CTL_RUN; 163 dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", 164 ctx->status_ctrl_reg, val); 165 writel(val, base + ctx->status_ctrl_reg); 166 167 /* Wait for uC transactions complete */ 168 usleep_range(10, 20); 169 170 val = readl(base + ctx->status_ctrl_reg); 171 val |= UCX_CTL_RESET; 172 dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", 173 ctx->status_ctrl_reg, val); 174 writel(val, base + ctx->status_ctrl_reg); 175 } 176 177 static int ipu7_boot_cell_init(const struct ipu7_bus_device *adev) 178 { 179 const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; 180 void __iomem *base = adev->isp->base; 181 182 dev_dbg(&adev->auxdev.dev, "write fw_start_address_reg(0x%x) to 0x%x\n", 183 ctx->fw_start_address_reg, adev->fw_entry); 184 writel(adev->fw_entry, base + ctx->fw_start_address_reg); 185 186 return ipu7_boot_cell_reset(adev); 187 } 188 189 static void init_boot_config(struct ia_gofo_boot_config *boot_config, 190 u32 length, u8 major) 191 { 192 /* syscom version, new syscom2 version */ 193 boot_config->length = length; 194 boot_config->config_version.major = 1U; 195 boot_config->config_version.minor = 0U; 196 boot_config->config_version.subminor = 0U; 197 boot_config->config_version.patch = 0U; 198 199 /* msg version for task interface */ 200 boot_config->client_version_support.num_versions = 1U; 201 boot_config->client_version_support.versions[0].major = major; 202 boot_config->client_version_support.versions[0].minor = 0U; 203 boot_config->client_version_support.versions[0].subminor = 0U; 204 boot_config->client_version_support.versions[0].patch = 0U; 205 } 206 207 int ipu7_boot_init_boot_config(struct ipu7_bus_device *adev, 208 struct syscom_queue_config *qconfigs, 209 int num_queues, u32 uc_freq, 210 dma_addr_t subsys_config, u8 major) 211 { 212 u32 total_queue_size_aligned = 0; 213 struct ipu7_syscom_context *syscom = adev->syscom; 214 struct ia_gofo_boot_config *boot_config; 215 struct syscom_queue_params_config *cfgs; 216 struct device *dev = &adev->auxdev.dev; 217 struct syscom_config_s *syscfg; 218 dma_addr_t queue_mem_dma_ptr; 219 void *queue_mem_ptr; 220 unsigned int i; 221 222 dev_dbg(dev, "boot config queues_nr: %d freq: %u sys_conf: 0x%pad\n", 223 num_queues, uc_freq, &subsys_config); 224 /* Allocate boot config. */ 225 adev->boot_config_size = 226 sizeof(*cfgs) * num_queues + sizeof(*boot_config); 227 adev->boot_config = ipu7_dma_alloc(adev, adev->boot_config_size, 228 &adev->boot_config_dma_addr, 229 GFP_KERNEL, 0); 230 if (!adev->boot_config) { 231 dev_err(dev, "Failed to allocate boot config.\n"); 232 return -ENOMEM; 233 } 234 235 boot_config = adev->boot_config; 236 memset(boot_config, 0, sizeof(struct ia_gofo_boot_config)); 237 init_boot_config(boot_config, adev->boot_config_size, major); 238 boot_config->subsys_config = subsys_config; 239 240 boot_config->uc_tile_frequency = uc_freq; 241 boot_config->uc_tile_frequency_units = 242 IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_MHZ; 243 boot_config->syscom_context_config.max_output_queues = 244 syscom->num_output_queues; 245 boot_config->syscom_context_config.max_input_queues = 246 syscom->num_input_queues; 247 248 ipu7_dma_sync_single(adev, adev->boot_config_dma_addr, 249 adev->boot_config_size); 250 251 for (i = 0; i < num_queues; i++) { 252 u32 queue_size = qconfigs[i].max_capacity * 253 qconfigs[i].token_size_in_bytes; 254 255 queue_size = ALIGN(queue_size, 64U); 256 total_queue_size_aligned += queue_size; 257 qconfigs[i].queue_size = queue_size; 258 } 259 260 /* Allocate queue memory */ 261 syscom->queue_mem = ipu7_dma_alloc(adev, total_queue_size_aligned, 262 &syscom->queue_mem_dma_addr, 263 GFP_KERNEL, 0); 264 if (!syscom->queue_mem) { 265 dev_err(dev, "Failed to allocate queue memory.\n"); 266 return -ENOMEM; 267 } 268 syscom->queue_mem_size = total_queue_size_aligned; 269 270 syscfg = &boot_config->syscom_context_config; 271 cfgs = ipu7_syscom_get_queue_config(syscfg); 272 queue_mem_ptr = syscom->queue_mem; 273 queue_mem_dma_ptr = syscom->queue_mem_dma_addr; 274 for (i = 0; i < num_queues; i++) { 275 cfgs[i].token_array_mem = queue_mem_dma_ptr; 276 cfgs[i].max_capacity = qconfigs[i].max_capacity; 277 cfgs[i].token_size_in_bytes = qconfigs[i].token_size_in_bytes; 278 qconfigs[i].token_array_mem = queue_mem_ptr; 279 queue_mem_dma_ptr += qconfigs[i].queue_size; 280 queue_mem_ptr += qconfigs[i].queue_size; 281 } 282 283 ipu7_dma_sync_single(adev, syscom->queue_mem_dma_addr, 284 total_queue_size_aligned); 285 286 return 0; 287 } 288 EXPORT_SYMBOL_NS_GPL(ipu7_boot_init_boot_config, "INTEL_IPU7"); 289 290 void ipu7_boot_release_boot_config(struct ipu7_bus_device *adev) 291 { 292 struct ipu7_syscom_context *syscom = adev->syscom; 293 294 if (syscom->queue_mem) { 295 ipu7_dma_free(adev, syscom->queue_mem_size, 296 syscom->queue_mem, 297 syscom->queue_mem_dma_addr, 0); 298 syscom->queue_mem = NULL; 299 syscom->queue_mem_dma_addr = 0; 300 } 301 302 if (adev->boot_config) { 303 ipu7_dma_free(adev, adev->boot_config_size, 304 adev->boot_config, 305 adev->boot_config_dma_addr, 0); 306 adev->boot_config = NULL; 307 adev->boot_config_dma_addr = 0; 308 } 309 } 310 EXPORT_SYMBOL_NS_GPL(ipu7_boot_release_boot_config, "INTEL_IPU7"); 311 312 int ipu7_boot_start_fw(const struct ipu7_bus_device *adev) 313 { 314 const struct device *dev = &adev->auxdev.dev; 315 u32 timeout = IPU_FW_START_STOP_TIMEOUT; 316 void __iomem *base = adev->isp->base; 317 u32 boot_state, last_boot_state; 318 u32 indices_addr, msg_ver, id; 319 int ret; 320 321 ret = ipu7_boot_cell_init(adev); 322 if (ret) 323 return ret; 324 325 dev_dbg(dev, "start booting fw...\n"); 326 /* store "uninit" state to syscom/boot state reg */ 327 write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID, 328 IA_GOFO_FW_BOOT_STATE_UNINIT); 329 /* 330 * Set registers to zero 331 * (not strictly required, but recommended for diagnostics) 332 */ 333 write_fw_boot_param(adev, 334 IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID, 0); 335 write_fw_boot_param(adev, IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID, 0); 336 /* store firmware configuration address */ 337 write_fw_boot_param(adev, IA_GOFO_FW_BOOT_CONFIG_ID, 338 adev->boot_config_dma_addr); 339 340 /* Kick uC, then wait for boot complete */ 341 ipu7_boot_cell_start(adev); 342 343 last_boot_state = IA_GOFO_FW_BOOT_STATE_UNINIT; 344 while (timeout--) { 345 boot_state = read_fw_boot_param(adev, 346 IA_GOFO_FW_BOOT_STATE_ID); 347 if (boot_state != last_boot_state) { 348 dev_dbg(dev, "boot state changed from 0x%x to 0x%x\n", 349 last_boot_state, boot_state); 350 last_boot_state = boot_state; 351 } 352 if (BOOT_STATE_IS_CRITICAL(boot_state) || 353 BOOT_STATE_IS_READY(boot_state)) 354 break; 355 usleep_range(1000, 1200); 356 } 357 358 if (BOOT_STATE_IS_CRITICAL(boot_state)) { 359 ipu7_dump_fw_error_log(adev); 360 dev_err(dev, "critical boot state error 0x%x\n", boot_state); 361 return -EINVAL; 362 } else if (!BOOT_STATE_IS_READY(boot_state)) { 363 dev_err(dev, "fw boot timeout. state: 0x%x\n", boot_state); 364 return -ETIMEDOUT; 365 } 366 dev_dbg(dev, "fw boot done.\n"); 367 368 /* Get FW syscom queue indices addr */ 369 id = IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID; 370 indices_addr = read_fw_boot_param(adev, id); 371 adev->syscom->queue_indices = base + indices_addr; 372 dev_dbg(dev, "fw queue indices offset is 0x%x\n", indices_addr); 373 374 /* Get message version. */ 375 msg_ver = read_fw_boot_param(adev, 376 IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID); 377 dev_dbg(dev, "ipu message version is 0x%08x\n", msg_ver); 378 379 return 0; 380 } 381 EXPORT_SYMBOL_NS_GPL(ipu7_boot_start_fw, "INTEL_IPU7"); 382 383 int ipu7_boot_stop_fw(const struct ipu7_bus_device *adev) 384 { 385 const struct device *dev = &adev->auxdev.dev; 386 u32 timeout = IPU_FW_START_STOP_TIMEOUT; 387 u32 boot_state; 388 389 boot_state = read_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID); 390 if (BOOT_STATE_IS_CRITICAL(boot_state) || 391 !BOOT_STATE_IS_READY(boot_state)) { 392 dev_err(dev, "fw not ready for shutdown, state 0x%x\n", 393 boot_state); 394 return -EBUSY; 395 } 396 397 /* Issue shutdown to start shutdown process */ 398 dev_dbg(dev, "stopping fw...\n"); 399 write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID, 400 IA_GOFO_FW_BOOT_STATE_SHUTDOWN_CMD); 401 while (timeout--) { 402 boot_state = read_fw_boot_param(adev, 403 IA_GOFO_FW_BOOT_STATE_ID); 404 if (BOOT_STATE_IS_CRITICAL(boot_state) || 405 BOOT_STATE_IS_INACTIVE(boot_state)) 406 break; 407 usleep_range(1000, 1200); 408 } 409 410 if (BOOT_STATE_IS_CRITICAL(boot_state)) { 411 ipu7_dump_fw_error_log(adev); 412 dev_err(dev, "critical boot state error 0x%x\n", boot_state); 413 return -EINVAL; 414 } else if (!BOOT_STATE_IS_INACTIVE(boot_state)) { 415 dev_err(dev, "stop fw timeout. state: 0x%x\n", boot_state); 416 return -ETIMEDOUT; 417 } 418 419 ipu7_boot_cell_stop(adev); 420 dev_dbg(dev, "stop fw done.\n"); 421 422 return 0; 423 } 424 EXPORT_SYMBOL_NS_GPL(ipu7_boot_stop_fw, "INTEL_IPU7"); 425 426 u32 ipu7_boot_get_boot_state(const struct ipu7_bus_device *adev) 427 { 428 return read_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID); 429 } 430 EXPORT_SYMBOL_NS_GPL(ipu7_boot_get_boot_state, "INTEL_IPU7"); 431