blob: 1ede92300dd6e9951cb610c1be24d8f03f04720d [file] [log] [blame]
Stanimir Varbanovaf2c3832017-06-15 13:31:45 -03001/*
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
Stanimir Varbanovaf2c3832017-06-15 13:31:45 -030026#define VENUS_PAS_ID 9
27#define VENUS_FW_MEM_SIZE SZ_8M
28
29static void device_release_dummy(struct device *dev)
30{
31 of_reserved_mem_device_release(dev);
32}
33
Stanimir Varbanov50058a92017-06-15 13:31:59 -030034int venus_boot(struct device *parent, struct device *fw_dev, const char *fwname)
Stanimir Varbanovaf2c3832017-06-15 13:31:45 -030035{
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
Arnd Bergmannb8f9bdc2017-07-17 04:56:49 -040043 if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available())
Stanimir Varbanovaf2c3832017-06-15 13:31:45 -030044 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
Stanimir Varbanov50058a92017-06-15 13:31:59 -030069 ret = request_firmware(&mdt, fwname, fw_dev);
Stanimir Varbanovaf2c3832017-06-15 13:31:45 -030070 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
Stanimir Varbanov50058a92017-06-15 13:31:59 -030080 ret = qcom_mdt_load(fw_dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys,
81 mem_size);
Stanimir Varbanovaf2c3832017-06-15 13:31:45 -030082
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
94err_unreg_device:
95 device_unregister(fw_dev);
96 return ret;
97}
98
99int 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}