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