blob: 20f071fc4f5de9828d5d9758b304a23519c2a1d0 [file] [log] [blame]
Rui Miguel Silva909ff4d2021-12-03 19:00:54 +00001/*
Bence Balogha10cf7a2024-01-30 22:59:30 +01002 * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
Rui Miguel Silva909ff4d2021-12-03 19:00:54 +00003 * 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>
Bence Balogha10cf7a2024-01-30 22:59:30 +010011#include <platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h>
Rui Miguel Silva909ff4d2021-12-03 19:00:54 +000012#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);
Bence Balogha10cf7a2024-01-30 22:59:30 +010073 if (ret < 0)
74 return -1;
Rui Miguel Silva909ff4d2021-12-03 19:00:54 +000075
76 ret = mhu_v2_x_channel_clear(rx_dev, channel);
77 if (ret != MHU_V_2_X_ERR_NONE) {
78 EMSG("openamp: mhu: failed to clear channel: %d", channel);
79 return -EPROTO;
80 }
81
82 return 0;
83}
84
85int openamp_mhu_notify_peer(struct openamp_messenger *openamp)
86{
87 struct mhu_v2_x_dev_t *tx_dev;
88 enum mhu_v2_x_error_t ret;
89 struct openamp_mhu *mhu;
90 uint32_t access_ready;
91
92 if (!openamp->transport) {
93 EMSG("openamp: mhu: notify transport not initialized");
94 return -EINVAL;
95 }
96
97 mhu = openamp->transport;
98 tx_dev = &mhu->tx_dev;
99
100 ret = mhu_v2_x_set_access_request(tx_dev);
101 if (ret != MHU_V_2_X_ERR_NONE) {
102 EMSG("openamp: mhu: set access request failed");
103 return -EPROTO;
104 }
105
106 do {
107 ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
108 if (ret != MHU_V_2_X_ERR_NONE) {
109 EMSG("openamp: mhu: failed to get access_ready");
110 return -EPROTO;
111 }
112 } while (!access_ready);
113
114 ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
115 MHU_V_2_NOTIFY_VALUE);
116 if (ret != MHU_V_2_X_ERR_NONE) {
117 EMSG("openamp: mhu: failed send over channel");
118 return -EPROTO;
119 }
120
121 ret = mhu_v2_x_reset_access_request(tx_dev);
122 if (ret != MHU_V_2_X_ERR_NONE) {
123 EMSG("openamp: mhu: failed reset access request");
124 return -EPROTO;
125 }
126
127 return 0;
128}
129
130int openamp_mhu_init(struct openamp_messenger *openamp)
131{
132 struct mhu_v2_x_dev_t *rx_dev;
133 struct mhu_v2_x_dev_t *tx_dev;
134 struct openamp_mhu *mhu;
135 int ret;
136
137 /* if we already have initialized skip this */
138 if (openamp->transport)
139 return 0;
140
141 mhu = malloc(sizeof(*mhu));
142 if (!mhu)
143 return -1;
144
145 ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
146 if (ret < 0)
147 goto free_mhu;
148
149 ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
150 if (ret < 0)
151 goto free_mhu;
152
153 rx_dev = &mhu->rx_dev;
154 tx_dev = &mhu->tx_dev;
155
156 rx_dev->base = mhu->rx_region.base_addr;
157 rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
158
159 tx_dev->base = mhu->tx_region.base_addr;
160 tx_dev->frame = MHU_V2_X_SENDER_FRAME;
161
162 ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
163 if (ret < 0)
164 goto free_mhu;
165
166 ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
167 if (ret < 0)
168 goto free_mhu;
169
170 openamp->transport = (void *)mhu;
171
172 return 0;
173
174free_mhu:
175 free(mhu);
176
177 return ret;
178}
179
180int openamp_mhu_deinit(struct openamp_messenger *openamp)
181{
182 struct openamp_mhu *mhu;
183
184 if (!openamp->transport)
185 return 0;
186
187 mhu = openamp->transport;
188 free(mhu);
189
190 openamp->transport = NULL;
191
192 return 0;
193}