static int fdma_load_elf(const struct firmware *fw, struct fdma *fdma) { struct ELF32_info *elfinfo = NULL; int i; int fw_major, fw_minor; int hw_major, hw_minor; int res; if (!fw) { fdma_info(fdma, "Unable to load FDMA firmware: not present?\n"); return -EINVAL; } elfinfo = (struct ELF32_info *)ELF32_initFromMem((uint8_t *)fw->data, fw->size, 0); if (elfinfo == NULL) return -ENOMEM; if ((elfinfo->header->e_type != ET_EXEC) || (elfinfo->header->e_machine != EM_SLIM) || (elfinfo->header->e_flags != EF_SLIM_FDMA)) { res = -ENOMEM; goto fail; } for (i = 0; i < elfinfo->header->e_phnum; i++) if (elfinfo->progbase[i].p_type == PT_LOAD) { res = fdma_load_segment(fdma, elfinfo, i); if (res) goto fail; } ELF32_free(elfinfo); fdma_get_hw_revision(fdma, &hw_major, &hw_minor); fdma_get_fw_revision(fdma, &fw_major, &fw_minor); fdma_info(fdma, "SLIM hw %d.%d, FDMA fw %d.%d\n", hw_major, hw_minor, fw_major, fw_minor); if (fdma_run_initialise_sequence(fdma) != 0) return -ENODEV; fdma->firmware_loaded = 1; return 1; fail: ELF32_free(elfinfo); return res; }
static int stm_fdma_fw_request(struct stm_fdma_device *fdev) { const struct firmware *fw = NULL; struct ELF32_info *elfinfo = NULL; int result = 0; int fw_major, fw_minor; int hw_major, hw_minor; uint8_t *fw_data; BUG_ON(!fdev); /* Generate FDMA firmware file name */ result = snprintf(fdev->fw_name, sizeof(fdev->fw_name), "fdma_%s_%d.elf", stm_soc(), (fdev->fdma_id == -1) ? 0 : fdev->fdma_id); BUG_ON(result >= sizeof(fdev->fw_name)); dev_notice(fdev->dev, "Requesting firmware: %s\n", fdev->fw_name); /* Request the FDMA firmware */ result = request_firmware(&fw, fdev->fw_name, fdev->dev); if (result || !fw) { dev_err(fdev->dev, "Failed request firmware: not present?\n"); result = -ENODEV; goto error_no_fw; } #ifdef CONFIG_HIBERNATION /* Save a copy of the firmware data for future reload */ fw_data = devm_kzalloc(fdev->dev, fw->size, GFP_KERNEL); if (!fw_data) { dev_err(fdev->dev, "Cannot allocate memory for firmware\n"); result = -ENOMEM; goto error_elf_init; } memcpy(fw_data, fw->data, fw->size); #else /* Set pointer to the firmware data */ fw_data = (uint8_t *) fw->data; #endif /* Initialise firmware as an in-memory ELF file */ elfinfo = (struct ELF32_info *)ELF32_initFromMem(fw_data, fw->size, 0); if (elfinfo == NULL) { dev_err(fdev->dev, "Failed to initialise in-memory ELF file\n"); result = -ENOMEM; goto error_elf_init; } /* Attempt to load the ELF file */ result = stm_fdma_fw_load(fdev, elfinfo); if (result) { dev_err(fdev->dev, "Failed to load firmware\n"); goto error_elf_load; } /* Retrieve the hardware and firmware versions */ stm_fdma_hw_get_revisions(fdev, &hw_major, &hw_minor, &fw_major, &fw_minor); dev_notice(fdev->dev, "SLIM hw %d.%d, FDMA fw %d.%d\n", hw_major, hw_minor, fw_major, fw_minor); /* Indicate firmware loaded */ fdev->fw_state = STM_FDMA_FW_STATE_LOADED; /* Save pointer to ELF (which points at fw_data) for future reload */ fdev->fw_elfinfo = elfinfo; /* Wake up the wait queue */ wake_up(&fdev->fw_load_q); /* Release the firmware */ release_firmware(fw); return 0; error_elf_load: ELF32_free(elfinfo); error_elf_init: if (fw_data && fw_data != fw->data) devm_kfree(fdev->dev, fw_data); release_firmware(fw); error_no_fw: fdev->fw_state = STM_FDMA_FW_STATE_ERROR; return result; }