]>
Commit | Line | Data |
---|---|---|
af2c3834 SV |
1 | /* |
2 | * Copyright (C) 2017 Linaro Ltd. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 and | |
6 | * only version 2 as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | */ | |
14 | ||
377a22d3 | 15 | #include <linux/device.h> |
af2c3834 SV |
16 | #include <linux/firmware.h> |
17 | #include <linux/kernel.h> | |
377a22d3 | 18 | #include <linux/io.h> |
af2c3834 | 19 | #include <linux/of.h> |
377a22d3 | 20 | #include <linux/of_address.h> |
af2c3834 | 21 | #include <linux/qcom_scm.h> |
377a22d3 | 22 | #include <linux/sizes.h> |
af2c3834 SV |
23 | #include <linux/soc/qcom/mdt_loader.h> |
24 | ||
25 | #include "firmware.h" | |
26 | ||
af2c3834 | 27 | #define VENUS_PAS_ID 9 |
377a22d3 | 28 | #define VENUS_FW_MEM_SIZE (6 * SZ_1M) |
af2c3834 | 29 | |
377a22d3 | 30 | int venus_boot(struct device *dev, const char *fwname) |
af2c3834 SV |
31 | { |
32 | const struct firmware *mdt; | |
377a22d3 | 33 | struct device_node *node; |
af2c3834 | 34 | phys_addr_t mem_phys; |
377a22d3 | 35 | struct resource r; |
af2c3834 SV |
36 | ssize_t fw_size; |
37 | size_t mem_size; | |
38 | void *mem_va; | |
39 | int ret; | |
40 | ||
b8f9bdc1 | 41 | if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available()) |
af2c3834 SV |
42 | return -EPROBE_DEFER; |
43 | ||
377a22d3 SV |
44 | node = of_parse_phandle(dev->of_node, "memory-region", 0); |
45 | if (!node) { | |
46 | dev_err(dev, "no memory-region specified\n"); | |
47 | return -EINVAL; | |
48 | } | |
af2c3834 | 49 | |
377a22d3 | 50 | ret = of_address_to_resource(node, 0, &r); |
af2c3834 SV |
51 | if (ret) |
52 | return ret; | |
53 | ||
377a22d3 SV |
54 | mem_phys = r.start; |
55 | mem_size = resource_size(&r); | |
af2c3834 | 56 | |
377a22d3 SV |
57 | if (mem_size < VENUS_FW_MEM_SIZE) |
58 | return -EINVAL; | |
af2c3834 | 59 | |
377a22d3 | 60 | mem_va = memremap(r.start, mem_size, MEMREMAP_WC); |
af2c3834 | 61 | if (!mem_va) { |
377a22d3 SV |
62 | dev_err(dev, "unable to map memory region: %pa+%zx\n", |
63 | &r.start, mem_size); | |
64 | return -ENOMEM; | |
af2c3834 SV |
65 | } |
66 | ||
377a22d3 | 67 | ret = request_firmware(&mdt, fwname, dev); |
af2c3834 | 68 | if (ret < 0) |
377a22d3 | 69 | goto err_unmap; |
af2c3834 SV |
70 | |
71 | fw_size = qcom_mdt_get_size(mdt); | |
72 | if (fw_size < 0) { | |
73 | ret = fw_size; | |
74 | release_firmware(mdt); | |
377a22d3 | 75 | goto err_unmap; |
af2c3834 SV |
76 | } |
77 | ||
377a22d3 | 78 | ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, |
50058a9a | 79 | mem_size); |
af2c3834 SV |
80 | |
81 | release_firmware(mdt); | |
82 | ||
83 | if (ret) | |
377a22d3 | 84 | goto err_unmap; |
af2c3834 SV |
85 | |
86 | ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); | |
87 | if (ret) | |
377a22d3 | 88 | goto err_unmap; |
af2c3834 | 89 | |
377a22d3 SV |
90 | err_unmap: |
91 | memunmap(mem_va); | |
af2c3834 SV |
92 | return ret; |
93 | } | |
94 | ||
377a22d3 | 95 | int venus_shutdown(struct device *dev) |
af2c3834 | 96 | { |
377a22d3 | 97 | return qcom_scm_pas_shutdown(VENUS_PAS_ID); |
af2c3834 | 98 | } |