1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2017 Linaro Ltd.
6 #include <linux/device.h>
7 #include <linux/firmware.h>
8 #include <linux/kernel.h>
9 #include <linux/iommu.h>
12 #include <linux/of_address.h>
13 #include <linux/platform_device.h>
14 #include <linux/of_device.h>
15 #include <linux/qcom_scm.h>
16 #include <linux/sizes.h>
17 #include <linux/soc/qcom/mdt_loader.h>
21 #include "hfi_venus_io.h"
23 #define VENUS_PAS_ID 9
24 #define VENUS_FW_MEM_SIZE (6 * SZ_1M)
25 #define VENUS_FW_START_ADDR 0x0
27 static void venus_reset_cpu(struct venus_core
*core
)
29 u32 fw_size
= core
->fw
.mapped_mem_size
;
30 void __iomem
*base
= core
->base
;
32 writel(0, base
+ WRAPPER_FW_START_ADDR
);
33 writel(fw_size
, base
+ WRAPPER_FW_END_ADDR
);
34 writel(0, base
+ WRAPPER_CPA_START_ADDR
);
35 writel(fw_size
, base
+ WRAPPER_CPA_END_ADDR
);
36 writel(fw_size
, base
+ WRAPPER_NONPIX_START_ADDR
);
37 writel(fw_size
, base
+ WRAPPER_NONPIX_END_ADDR
);
38 writel(0x0, base
+ WRAPPER_CPU_CGC_DIS
);
39 writel(0x0, base
+ WRAPPER_CPU_CLOCK_CONFIG
);
41 /* Bring ARM9 out of reset */
42 writel(0, base
+ WRAPPER_A9SS_SW_RESET
);
45 int venus_set_hw_state(struct venus_core
*core
, bool resume
)
50 ret
= qcom_scm_set_remote_state(resume
, 0);
51 if (resume
&& ret
== -EINVAL
)
57 venus_reset_cpu(core
);
59 writel(1, core
->base
+ WRAPPER_A9SS_SW_RESET
);
64 static int venus_load_fw(struct venus_core
*core
, const char *fwname
,
65 phys_addr_t
*mem_phys
, size_t *mem_size
)
67 const struct firmware
*mdt
;
68 struct device_node
*node
;
79 node
= of_parse_phandle(dev
->of_node
, "memory-region", 0);
81 dev_err(dev
, "no memory-region specified\n");
85 ret
= of_address_to_resource(node
, 0, &r
);
89 ret
= request_firmware(&mdt
, fwname
, dev
);
93 fw_size
= qcom_mdt_get_size(mdt
);
100 *mem_size
= resource_size(&r
);
102 if (*mem_size
< fw_size
|| fw_size
> VENUS_FW_MEM_SIZE
) {
107 mem_va
= memremap(r
.start
, *mem_size
, MEMREMAP_WC
);
109 dev_err(dev
, "unable to map memory region: %pR\n", &r
);
115 ret
= qcom_mdt_load(dev
, mdt
, fwname
, VENUS_PAS_ID
,
116 mem_va
, *mem_phys
, *mem_size
, NULL
);
118 ret
= qcom_mdt_load_no_init(dev
, mdt
, fwname
, VENUS_PAS_ID
,
119 mem_va
, *mem_phys
, *mem_size
, NULL
);
123 release_firmware(mdt
);
129 static int venus_boot_no_tz(struct venus_core
*core
, phys_addr_t mem_phys
,
132 struct iommu_domain
*iommu
;
138 return -EPROBE_DEFER
;
140 iommu
= core
->fw
.iommu_domain
;
141 core
->fw
.mapped_mem_size
= mem_size
;
143 ret
= iommu_map(iommu
, VENUS_FW_START_ADDR
, mem_phys
, mem_size
,
144 IOMMU_READ
| IOMMU_WRITE
| IOMMU_PRIV
);
146 dev_err(dev
, "could not map video firmware region\n");
150 venus_reset_cpu(core
);
155 static int venus_shutdown_no_tz(struct venus_core
*core
)
157 const size_t mapped
= core
->fw
.mapped_mem_size
;
158 struct iommu_domain
*iommu
;
161 struct device
*dev
= core
->fw
.dev
;
162 void __iomem
*base
= core
->base
;
164 /* Assert the reset to ARM9 */
165 reg
= readl_relaxed(base
+ WRAPPER_A9SS_SW_RESET
);
166 reg
|= WRAPPER_A9SS_SW_RESET_BIT
;
167 writel_relaxed(reg
, base
+ WRAPPER_A9SS_SW_RESET
);
169 /* Make sure reset is asserted before the mapping is removed */
172 iommu
= core
->fw
.iommu_domain
;
174 if (core
->fw
.mapped_mem_size
&& iommu
) {
175 unmapped
= iommu_unmap(iommu
, VENUS_FW_START_ADDR
, mapped
);
177 if (unmapped
!= mapped
)
178 dev_err(dev
, "failed to unmap firmware\n");
180 core
->fw
.mapped_mem_size
= 0;
186 int venus_boot(struct venus_core
*core
)
188 struct device
*dev
= core
->dev
;
189 const struct venus_resources
*res
= core
->res
;
190 phys_addr_t mem_phys
;
194 if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER
) ||
195 (core
->use_tz
&& !qcom_scm_is_available()))
196 return -EPROBE_DEFER
;
198 ret
= venus_load_fw(core
, core
->res
->fwname
, &mem_phys
, &mem_size
);
200 dev_err(dev
, "fail to load video firmware\n");
205 ret
= qcom_scm_pas_auth_and_reset(VENUS_PAS_ID
);
207 ret
= venus_boot_no_tz(core
, mem_phys
, mem_size
);
212 if (core
->use_tz
&& res
->cp_size
) {
213 ret
= qcom_scm_mem_protect_video_var(res
->cp_start
,
215 res
->cp_nonpixel_start
,
216 res
->cp_nonpixel_size
);
218 qcom_scm_pas_shutdown(VENUS_PAS_ID
);
219 dev_err(dev
, "set virtual address ranges fail (%d)\n",
228 int venus_shutdown(struct venus_core
*core
)
233 ret
= qcom_scm_pas_shutdown(VENUS_PAS_ID
);
235 ret
= venus_shutdown_no_tz(core
);
240 int venus_firmware_init(struct venus_core
*core
)
242 struct platform_device_info info
;
243 struct iommu_domain
*iommu_dom
;
244 struct platform_device
*pdev
;
245 struct device_node
*np
;
248 np
= of_get_child_by_name(core
->dev
->of_node
, "video-firmware");
254 memset(&info
, 0, sizeof(info
));
255 info
.fwnode
= &np
->fwnode
;
256 info
.parent
= core
->dev
;
257 info
.name
= np
->name
;
258 info
.dma_mask
= DMA_BIT_MASK(32);
260 pdev
= platform_device_register_full(&info
);
263 return PTR_ERR(pdev
);
266 pdev
->dev
.of_node
= np
;
268 ret
= of_dma_configure(&pdev
->dev
, np
, true);
270 dev_err(core
->dev
, "dma configure fail\n");
274 core
->fw
.dev
= &pdev
->dev
;
276 iommu_dom
= iommu_domain_alloc(&platform_bus_type
);
278 dev_err(core
->fw
.dev
, "Failed to allocate iommu domain\n");
283 ret
= iommu_attach_device(iommu_dom
, core
->fw
.dev
);
285 dev_err(core
->fw
.dev
, "could not attach device\n");
289 core
->fw
.iommu_domain
= iommu_dom
;
296 iommu_domain_free(iommu_dom
);
298 platform_device_unregister(pdev
);
303 void venus_firmware_deinit(struct venus_core
*core
)
305 struct iommu_domain
*iommu
;
310 iommu
= core
->fw
.iommu_domain
;
312 iommu_detach_device(iommu
, core
->fw
.dev
);
314 if (core
->fw
.iommu_domain
) {
315 iommu_domain_free(iommu
);
316 core
->fw
.iommu_domain
= NULL
;
319 platform_device_unregister(to_platform_device(core
->fw
.dev
));