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 15 #include <linux/device.h> 16 #include <linux/firmware.h> 17 #include <linux/kernel.h> 18 #include <linux/io.h> 19 #include <linux/of.h> 20 #include <linux/of_address.h> 21 #include <linux/qcom_scm.h> 22 #include <linux/sizes.h> 23 #include <linux/soc/qcom/mdt_loader.h> 24 25 #include "firmware.h" 26 27 #define VENUS_PAS_ID 9 28 #define VENUS_FW_MEM_SIZE (6 * SZ_1M) 29 30 int venus_boot(struct device *dev, const char *fwname) 31 { 32 const struct firmware *mdt; 33 struct device_node *node; 34 phys_addr_t mem_phys; 35 struct resource r; 36 ssize_t fw_size; 37 size_t mem_size; 38 void *mem_va; 39 int ret; 40 41 if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available()) 42 return -EPROBE_DEFER; 43 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 } 49 50 ret = of_address_to_resource(node, 0, &r); 51 if (ret) 52 return ret; 53 54 mem_phys = r.start; 55 mem_size = resource_size(&r); 56 57 if (mem_size < VENUS_FW_MEM_SIZE) 58 return -EINVAL; 59 60 mem_va = memremap(r.start, mem_size, MEMREMAP_WC); 61 if (!mem_va) { 62 dev_err(dev, "unable to map memory region: %pa+%zx\n", 63 &r.start, mem_size); 64 return -ENOMEM; 65 } 66 67 ret = request_firmware(&mdt, fwname, dev); 68 if (ret < 0) 69 goto err_unmap; 70 71 fw_size = qcom_mdt_get_size(mdt); 72 if (fw_size < 0) { 73 ret = fw_size; 74 release_firmware(mdt); 75 goto err_unmap; 76 } 77 78 ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, 79 mem_size, NULL); 80 81 release_firmware(mdt); 82 83 if (ret) 84 goto err_unmap; 85 86 ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); 87 if (ret) 88 goto err_unmap; 89 90 err_unmap: 91 memunmap(mem_va); 92 return ret; 93 } 94 95 int venus_shutdown(struct device *dev) 96 { 97 return qcom_scm_pas_shutdown(VENUS_PAS_ID); 98 } 99