blob: bafba3e3702e5cbf99e700600642f78621200dbe [file] [log] [blame]
Rui Miguel Silva909ff4d2021-12-03 19:00:54 +00001/*
2 * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
3 * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include <config/interface/config_store.h>
9#include <config/interface/config_blob.h>
10#include <platform/interface/device_region.h>
11#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
12#include <trace.h>
13#include <errno.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <stddef.h>
17#include <limits.h>
18
19#include "openamp_messenger_api.h"
20
21#define MHU_V_2_NOTIFY_CHANNEL 0
22#define MHU_V_2_NOTIFY_VALUE 0xff
23
24struct openamp_mhu {
25 struct device_region rx_region;
26 struct device_region tx_region;
27 struct mhu_v2_x_dev_t rx_dev;
28 struct mhu_v2_x_dev_t tx_dev;
29};
30
31static int openamp_mhu_device_get(const char *dev,
32 struct device_region *dev_region)
33{
34 bool found;
35
36 found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
37 dev_region, sizeof(*dev_region));
38 if (!found)
39 return -EINVAL;
40
41 if (!dev_region->base_addr)
42 return -EINVAL;
43
44 IMSG("mhu: device region found: %s addr: 0x%p size: %lu", dev,
45 (void *)dev_region->base_addr, dev_region->io_region_size);
46
47 return 0;
48}
49
50int openamp_mhu_receive(struct openamp_messenger *openamp)
51{
52 struct mhu_v2_x_dev_t *rx_dev;
53 enum mhu_v2_x_error_t ret;
54 struct openamp_mhu *mhu;
55 uint32_t channel = 0;
56 uint32_t irq_status;
57
58 if (!openamp->transport) {
59 EMSG("openamp: mhu: receive transport not initialized");
60 return -EINVAL;
61 }
62
63 mhu = openamp->transport;
64 rx_dev = &mhu->rx_dev;
65
66 irq_status = 0;
67
68 do {
69 irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
70 } while(!irq_status);
71
72 ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
73
74 ret = mhu_v2_x_channel_clear(rx_dev, channel);
75 if (ret != MHU_V_2_X_ERR_NONE) {
76 EMSG("openamp: mhu: failed to clear channel: %d", channel);
77 return -EPROTO;
78 }
79
80 return 0;
81}
82
83int openamp_mhu_notify_peer(struct openamp_messenger *openamp)
84{
85 struct mhu_v2_x_dev_t *tx_dev;
86 enum mhu_v2_x_error_t ret;
87 struct openamp_mhu *mhu;
88 uint32_t access_ready;
89
90 if (!openamp->transport) {
91 EMSG("openamp: mhu: notify transport not initialized");
92 return -EINVAL;
93 }
94
95 mhu = openamp->transport;
96 tx_dev = &mhu->tx_dev;
97
98 ret = mhu_v2_x_set_access_request(tx_dev);
99 if (ret != MHU_V_2_X_ERR_NONE) {
100 EMSG("openamp: mhu: set access request failed");
101 return -EPROTO;
102 }
103
104 do {
105 ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
106 if (ret != MHU_V_2_X_ERR_NONE) {
107 EMSG("openamp: mhu: failed to get access_ready");
108 return -EPROTO;
109 }
110 } while (!access_ready);
111
112 ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
113 MHU_V_2_NOTIFY_VALUE);
114 if (ret != MHU_V_2_X_ERR_NONE) {
115 EMSG("openamp: mhu: failed send over channel");
116 return -EPROTO;
117 }
118
119 ret = mhu_v2_x_reset_access_request(tx_dev);
120 if (ret != MHU_V_2_X_ERR_NONE) {
121 EMSG("openamp: mhu: failed reset access request");
122 return -EPROTO;
123 }
124
125 return 0;
126}
127
128int openamp_mhu_init(struct openamp_messenger *openamp)
129{
130 struct mhu_v2_x_dev_t *rx_dev;
131 struct mhu_v2_x_dev_t *tx_dev;
132 struct openamp_mhu *mhu;
133 int ret;
134
135 /* if we already have initialized skip this */
136 if (openamp->transport)
137 return 0;
138
139 mhu = malloc(sizeof(*mhu));
140 if (!mhu)
141 return -1;
142
143 ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
144 if (ret < 0)
145 goto free_mhu;
146
147 ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
148 if (ret < 0)
149 goto free_mhu;
150
151 rx_dev = &mhu->rx_dev;
152 tx_dev = &mhu->tx_dev;
153
154 rx_dev->base = mhu->rx_region.base_addr;
155 rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
156
157 tx_dev->base = mhu->tx_region.base_addr;
158 tx_dev->frame = MHU_V2_X_SENDER_FRAME;
159
160 ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
161 if (ret < 0)
162 goto free_mhu;
163
164 ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
165 if (ret < 0)
166 goto free_mhu;
167
168 openamp->transport = (void *)mhu;
169
170 return 0;
171
172free_mhu:
173 free(mhu);
174
175 return ret;
176}
177
178int openamp_mhu_deinit(struct openamp_messenger *openamp)
179{
180 struct openamp_mhu *mhu;
181
182 if (!openamp->transport)
183 return 0;
184
185 mhu = openamp->transport;
186 free(mhu);
187
188 openamp->transport = NULL;
189
190 return 0;
191}