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