xref: /linux/drivers/media/platform/qcom/iris/iris_firmware.c (revision abb1f808ceab5a3275f8a6b4e37cff17f9f781c1)
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