/* * Copyright (C) 2017 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include "firmware.h" #define VENUS_PAS_ID 9 #define VENUS_FW_MEM_SIZE SZ_8M static void device_release_dummy(struct device *dev) { of_reserved_mem_device_release(dev); } int venus_boot(struct device *parent, struct device *fw_dev, const char *fwname) { const struct firmware *mdt; phys_addr_t mem_phys; ssize_t fw_size; size_t mem_size; void *mem_va; int ret; if (!qcom_scm_is_available()) return -EPROBE_DEFER; fw_dev->parent = parent; fw_dev->release = device_release_dummy; ret = dev_set_name(fw_dev, "%s:%s", dev_name(parent), "firmware"); if (ret) return ret; ret = device_register(fw_dev); if (ret < 0) return ret; ret = of_reserved_mem_device_init_by_idx(fw_dev, parent->of_node, 0); if (ret) goto err_unreg_device; mem_size = VENUS_FW_MEM_SIZE; mem_va = dmam_alloc_coherent(fw_dev, mem_size, &mem_phys, GFP_KERNEL); if (!mem_va) { ret = -ENOMEM; goto err_unreg_device; } ret = request_firmware(&mdt, fwname, fw_dev); if (ret < 0) goto err_unreg_device; fw_size = qcom_mdt_get_size(mdt); if (fw_size < 0) { ret = fw_size; release_firmware(mdt); goto err_unreg_device; } ret = qcom_mdt_load(fw_dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, mem_size); release_firmware(mdt); if (ret) goto err_unreg_device; ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); if (ret) goto err_unreg_device; return 0; err_unreg_device: device_unregister(fw_dev); return ret; } int venus_shutdown(struct device *fw_dev) { int ret; ret = qcom_scm_pas_shutdown(VENUS_PAS_ID); device_unregister(fw_dev); memset(fw_dev, 0, sizeof(*fw_dev)); return ret; }