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
)
48 return qcom_scm_set_remote_state(resume
, 0);
51 venus_reset_cpu(core
);
53 writel(1, core
->base
+ WRAPPER_A9SS_SW_RESET
);
58 static int venus_load_fw(struct venus_core
*core
, const char *fwname
,
59 phys_addr_t
*mem_phys
, size_t *mem_size
)
61 const struct firmware
*mdt
;
62 struct device_node
*node
;
73 node
= of_parse_phandle(dev
->of_node
, "memory-region", 0);
75 dev_err(dev
, "no memory-region specified\n");
79 ret
= of_address_to_resource(node
, 0, &r
);
83 ret
= request_firmware(&mdt
, fwname
, dev
);
87 fw_size
= qcom_mdt_get_size(mdt
);
94 *mem_size
= resource_size(&r
);
96 if (*mem_size
< fw_size
|| fw_size
> VENUS_FW_MEM_SIZE
) {
101 mem_va
= memremap(r
.start
, *mem_size
, MEMREMAP_WC
);
103 dev_err(dev
, "unable to map memory region: %pa+%zx\n",
104 &r
.start
, *mem_size
);
110 ret
= qcom_mdt_load(dev
, mdt
, fwname
, VENUS_PAS_ID
,
111 mem_va
, *mem_phys
, *mem_size
, NULL
);
113 ret
= qcom_mdt_load_no_init(dev
, mdt
, fwname
, VENUS_PAS_ID
,
114 mem_va
, *mem_phys
, *mem_size
, NULL
);
118 release_firmware(mdt
);
124 static int venus_boot_no_tz(struct venus_core
*core
, phys_addr_t mem_phys
,
127 struct iommu_domain
*iommu
;
133 return -EPROBE_DEFER
;
135 iommu
= core
->fw
.iommu_domain
;
136 core
->fw
.mapped_mem_size
= mem_size
;
138 ret
= iommu_map(iommu
, VENUS_FW_START_ADDR
, mem_phys
, mem_size
,
139 IOMMU_READ
| IOMMU_WRITE
| IOMMU_PRIV
);
141 dev_err(dev
, "could not map video firmware region\n");
145 venus_reset_cpu(core
);
150 static int venus_shutdown_no_tz(struct venus_core
*core
)
152 const size_t mapped
= core
->fw
.mapped_mem_size
;
153 struct iommu_domain
*iommu
;
156 struct device
*dev
= core
->fw
.dev
;
157 void __iomem
*base
= core
->base
;
159 /* Assert the reset to ARM9 */
160 reg
= readl_relaxed(base
+ WRAPPER_A9SS_SW_RESET
);
161 reg
|= WRAPPER_A9SS_SW_RESET_BIT
;
162 writel_relaxed(reg
, base
+ WRAPPER_A9SS_SW_RESET
);
164 /* Make sure reset is asserted before the mapping is removed */
167 iommu
= core
->fw
.iommu_domain
;
169 unmapped
= iommu_unmap(iommu
, VENUS_FW_START_ADDR
, mapped
);
170 if (unmapped
!= mapped
)
171 dev_err(dev
, "failed to unmap firmware\n");
176 int venus_boot(struct venus_core
*core
)
178 struct device
*dev
= core
->dev
;
179 phys_addr_t mem_phys
;
183 if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER
) ||
184 (core
->use_tz
&& !qcom_scm_is_available()))
185 return -EPROBE_DEFER
;
187 ret
= venus_load_fw(core
, core
->res
->fwname
, &mem_phys
, &mem_size
);
189 dev_err(dev
, "fail to load video firmware\n");
194 ret
= qcom_scm_pas_auth_and_reset(VENUS_PAS_ID
);
196 ret
= venus_boot_no_tz(core
, mem_phys
, mem_size
);
201 int venus_shutdown(struct venus_core
*core
)
206 ret
= qcom_scm_pas_shutdown(VENUS_PAS_ID
);
208 ret
= venus_shutdown_no_tz(core
);
213 int venus_firmware_init(struct venus_core
*core
)
215 struct platform_device_info info
;
216 struct iommu_domain
*iommu_dom
;
217 struct platform_device
*pdev
;
218 struct device_node
*np
;
221 np
= of_get_child_by_name(core
->dev
->of_node
, "video-firmware");
227 memset(&info
, 0, sizeof(info
));
228 info
.fwnode
= &np
->fwnode
;
229 info
.parent
= core
->dev
;
230 info
.name
= np
->name
;
231 info
.dma_mask
= DMA_BIT_MASK(32);
233 pdev
= platform_device_register_full(&info
);
236 return PTR_ERR(pdev
);
239 pdev
->dev
.of_node
= np
;
241 ret
= of_dma_configure(&pdev
->dev
, np
, true);
243 dev_err(core
->dev
, "dma configure fail\n");
247 core
->fw
.dev
= &pdev
->dev
;
249 iommu_dom
= iommu_domain_alloc(&platform_bus_type
);
251 dev_err(core
->fw
.dev
, "Failed to allocate iommu domain\n");
256 ret
= iommu_attach_device(iommu_dom
, core
->fw
.dev
);
258 dev_err(core
->fw
.dev
, "could not attach device\n");
262 core
->fw
.iommu_domain
= iommu_dom
;
269 iommu_domain_free(iommu_dom
);
271 platform_device_unregister(pdev
);
276 void venus_firmware_deinit(struct venus_core
*core
)
278 struct iommu_domain
*iommu
;
283 iommu
= core
->fw
.iommu_domain
;
285 iommu_detach_device(iommu
, core
->fw
.dev
);
286 iommu_domain_free(iommu
);
288 platform_device_unregister(to_platform_device(core
->fw
.dev
));