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/dma-mapping.h> 16 #include <linux/firmware.h> 17 #include <linux/kernel.h> 18 #include <linux/of.h> 19 #include <linux/of_reserved_mem.h> 20 #include <linux/slab.h> 21 #include <linux/qcom_scm.h> 22 #include <linux/soc/qcom/mdt_loader.h> 23 24 #include "firmware.h" 25 26 #define VENUS_PAS_ID 9 27 #define VENUS_FW_MEM_SIZE SZ_8M 28 29 static void device_release_dummy(struct device *dev) 30 { 31 of_reserved_mem_device_release(dev); 32 } 33 34 int venus_boot(struct device *parent, struct device *fw_dev, const char *fwname) 35 { 36 const struct firmware *mdt; 37 phys_addr_t mem_phys; 38 ssize_t fw_size; 39 size_t mem_size; 40 void *mem_va; 41 int ret; 42 43 if (!qcom_scm_is_available()) 44 return -EPROBE_DEFER; 45 46 fw_dev->parent = parent; 47 fw_dev->release = device_release_dummy; 48 49 ret = dev_set_name(fw_dev, "%s:%s", dev_name(parent), "firmware"); 50 if (ret) 51 return ret; 52 53 ret = device_register(fw_dev); 54 if (ret < 0) 55 return ret; 56 57 ret = of_reserved_mem_device_init_by_idx(fw_dev, parent->of_node, 0); 58 if (ret) 59 goto err_unreg_device; 60 61 mem_size = VENUS_FW_MEM_SIZE; 62 63 mem_va = dmam_alloc_coherent(fw_dev, mem_size, &mem_phys, GFP_KERNEL); 64 if (!mem_va) { 65 ret = -ENOMEM; 66 goto err_unreg_device; 67 } 68 69 ret = request_firmware(&mdt, fwname, fw_dev); 70 if (ret < 0) 71 goto err_unreg_device; 72 73 fw_size = qcom_mdt_get_size(mdt); 74 if (fw_size < 0) { 75 ret = fw_size; 76 release_firmware(mdt); 77 goto err_unreg_device; 78 } 79 80 ret = qcom_mdt_load(fw_dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, 81 mem_size); 82 83 release_firmware(mdt); 84 85 if (ret) 86 goto err_unreg_device; 87 88 ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); 89 if (ret) 90 goto err_unreg_device; 91 92 return 0; 93 94 err_unreg_device: 95 device_unregister(fw_dev); 96 return ret; 97 } 98 99 int venus_shutdown(struct device *fw_dev) 100 { 101 int ret; 102 103 ret = qcom_scm_pas_shutdown(VENUS_PAS_ID); 104 device_unregister(fw_dev); 105 memset(fw_dev, 0, sizeof(*fw_dev)); 106 107 return ret; 108 } 109