1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 */ 5 6 #include <linux/firmware.h> 7 #include <linux/firmware/qcom/qcom_scm.h> 8 #include <linux/of_address.h> 9 #include <linux/of_reserved_mem.h> 10 #include <linux/soc/qcom/mdt_loader.h> 11 12 #include "iris_core.h" 13 #include "iris_firmware.h" 14 15 #define IRIS_PAS_ID 9 16 17 #define MAX_FIRMWARE_NAME_SIZE 128 18 19 /* Detect Gen2 firmware by scanning the blob for: 20 * QC_IMAGE_VERSION_STRING=<version> 21 * and then checking: 22 * - version starts with "vfw", OR 23 * - version matches "video-firmware.N.M" with N >= 2 24 */ 25 26 static bool iris_detect_gen2_from_fwdata(const u8 *data, size_t size) 27 { 28 static const char *marker = "QC_IMAGE_VERSION_STRING="; 29 const size_t mlen = strlen(marker); 30 static const char *vfw = "vfw"; 31 const size_t vfwlen = strlen(vfw); 32 static const char *vf = "video-firmware."; 33 const size_t vflen = strlen(vf); 34 35 for (size_t i = 0; i + mlen < size; i++) { 36 const char *found; 37 38 if (memcmp(data + i, marker, mlen)) 39 continue; 40 41 found = data + i + mlen; 42 size -= i + mlen; 43 44 /* vfw => Gen2 */ 45 if (size > vfwlen && !memcmp(found, vfw, vfwlen)) 46 return true; 47 48 if (size < vflen || 49 memcmp(found, vf, vflen)) 50 return false; 51 52 found += vflen; 53 size -= vflen; 54 55 /* 56 * video-firmware.1.x is Gen1. 57 * video-firmware.2.x and video-firmware.10.x are Gen2. 58 */ 59 return size >= 2 && 60 (*found >= '2' || (*found == '1' && found[1] != '.')); 61 } 62 63 return false; 64 } 65 66 static const struct firmware *iris_detect_firmware(struct iris_core *core, 67 const char **fw_name) 68 { 69 const struct firmware *firmware; 70 bool has_both_gens; 71 int ret; 72 73 *fw_name = NULL; 74 if (core->iris_platform_data->firmware_desc_gen2) 75 core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen2; 76 else if (core->iris_platform_data->firmware_desc_gen1) 77 core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; 78 else 79 return ERR_PTR(-EINVAL); 80 81 has_both_gens = core->iris_platform_data->firmware_desc_gen2 && 82 core->iris_platform_data->firmware_desc_gen1; 83 84 ret = of_property_read_string_index(dev_of_node(core->dev), "firmware-name", 0, fw_name); 85 if (ret) { 86 *fw_name = core->iris_firmware_desc->fwname; 87 ret = request_firmware(&firmware, *fw_name, core->dev); 88 if (ret && has_both_gens) { 89 core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; 90 *fw_name = core->iris_firmware_desc->fwname; 91 ret = request_firmware(&firmware, *fw_name, core->dev); 92 } 93 94 return ret ? ERR_PTR(ret) : firmware; 95 } 96 97 ret = request_firmware(&firmware, *fw_name, core->dev); 98 if (ret) 99 return ERR_PTR(ret); 100 101 if (has_both_gens && 102 !iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) { 103 dev_info(core->dev, "Gen1 FW detected in %s\n", *fw_name); 104 core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; 105 } 106 107 return firmware; 108 } 109 110 static int iris_load_fw_to_memory(struct iris_core *core) 111 { 112 const struct firmware *firmware = NULL; 113 struct device *dev = core->dev; 114 struct resource res; 115 phys_addr_t mem_phys; 116 const char *fw_name; 117 size_t res_size; 118 ssize_t fw_size; 119 void *mem_virt; 120 int ret; 121 122 ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); 123 if (ret) 124 return ret; 125 126 mem_phys = res.start; 127 res_size = resource_size(&res); 128 129 firmware = iris_detect_firmware(core, &fw_name); 130 if (IS_ERR(firmware)) 131 return PTR_ERR(firmware); 132 133 core->iris_firmware_data = core->iris_firmware_desc->firmware_data; 134 135 fw_size = qcom_mdt_get_size(firmware); 136 if (fw_size < 0 || res_size < (size_t)fw_size) { 137 ret = -EINVAL; 138 goto err_release_fw; 139 } 140 141 mem_virt = memremap(mem_phys, res_size, MEMREMAP_WC); 142 if (!mem_virt) { 143 ret = -ENOMEM; 144 goto err_release_fw; 145 } 146 147 ret = qcom_mdt_load(dev, firmware, fw_name, 148 IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL); 149 150 memunmap(mem_virt); 151 err_release_fw: 152 release_firmware(firmware); 153 154 return ret; 155 } 156 157 int iris_fw_load(struct iris_core *core) 158 { 159 const struct tz_cp_config *cp_config; 160 int i, ret; 161 162 ret = iris_load_fw_to_memory(core); 163 if (ret) { 164 dev_err(core->dev, "firmware download failed %d\n", ret); 165 return ret; 166 } 167 168 ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID); 169 if (ret) { 170 dev_err(core->dev, "auth and reset failed: %d\n", ret); 171 return ret; 172 } 173 174 for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { 175 cp_config = &core->iris_platform_data->tz_cp_config_data[i]; 176 ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, 177 cp_config->cp_size, 178 cp_config->cp_nonpixel_start, 179 cp_config->cp_nonpixel_size); 180 if (ret) { 181 dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret); 182 qcom_scm_pas_shutdown(IRIS_PAS_ID); 183 return ret; 184 } 185 } 186 187 return 0; 188 } 189 190 int iris_fw_unload(struct iris_core *core) 191 { 192 return qcom_scm_pas_shutdown(IRIS_PAS_ID); 193 } 194 195 int iris_set_hw_state(struct iris_core *core, bool resume) 196 { 197 return qcom_scm_set_remote_state(resume, 0); 198 } 199