1 /*
2 * Copyright (c) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 * http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * See the Mulan PSL v2 for more details.
11 * Create: 2022-12-05
12 * Description: openamp backend
13 */
14
15 #include "rpmsg_backend.h"
16 #include "metal/device.h"
17 #include "prt_hwi.h"
18
19 static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR };
20 static struct metal_device shm_device = {
21 .name = SHM_DEVICE_NAME,
22 .bus = NULL,
23 .num_regions = 1,
24 {
25 {
26 .virt = (void *) SHM_START_ADDR,
27 .physmap = shm_physmap,
28 .size = SHM_SIZE,
29 .page_shift = DEFAULT_PAGE_SHIFT,
30 .page_mask = DEFAULT_PAGE_MASK,
31 .mem_flags = 0,
32 .ops = { NULL },
33 },
34 },
35 .node = { NULL },
36 .irq_num = 0,
37 .irq_info = NULL
38 };
39
40 static struct virtio_vring_info rvrings[2] = {
41 [0] = {
42 .info.align = VRING_ALIGNMENT,
43 },
44 [1] = {
45 .info.align = VRING_ALIGNMENT,
46 },
47 };
48
49 static struct virtqueue *vq[2];
50
virtio_get_status(struct virtio_device * vdev)51 static unsigned char virtio_get_status(struct virtio_device *vdev)
52 {
53 return sys_read8(VDEV_STATUS_ADDR);
54 }
55
virtio_set_status(struct virtio_device * vdev,unsigned char status)56 static void virtio_set_status(struct virtio_device *vdev, unsigned char status)
57 {
58 sys_write8(status, VDEV_STATUS_ADDR);
59 }
60
virtio_get_features(struct virtio_device * vdev)61 static uint32_t virtio_get_features(struct virtio_device *vdev)
62 {
63 return BIT(VIRTIO_RPMSG_F_NS);
64 }
65
virtio_set_features(struct virtio_device * vdev,uint32_t features)66 static void virtio_set_features(struct virtio_device *vdev, uint32_t features)
67 {
68 }
69
virtio_notify(struct virtqueue * vq)70 static void virtio_notify(struct virtqueue *vq)
71 {
72 uint16_t coreMask = 1;
73 OsHwiMcTrigger(coreMask, OS_HWI_IPI_NO_07);
74 }
75
76 const struct virtio_dispatch dispatch = {
77 .get_status = virtio_get_status,
78 .set_status = virtio_set_status,
79 .get_features = virtio_get_features,
80 .set_features = virtio_set_features,
81 .notify = virtio_notify,
82 };
83
rpmsg_hwi_handler(void)84 static void rpmsg_hwi_handler(void)
85 {
86 virtqueue_notification(vq[VIRTQUEUE_ID]);
87 }
88
rpmsg_hwi_init(void)89 static U32 rpmsg_hwi_init(void)
90 {
91 U32 ret;
92
93 ret = PRT_HwiSetAttr(OS_OPENAMP_NOTIFY_HWI_NUM, OS_OPENAMP_NOTIFY_HWI_PRIO, OS_HWI_MODE_ENGROSS);
94 if (ret != OS_OK) {
95 return ret;
96 }
97
98 ret = PRT_HwiCreate(OS_OPENAMP_NOTIFY_HWI_NUM, (HwiProcFunc)rpmsg_hwi_handler, 0);
99 if (ret != OS_OK) {
100 return ret;
101 }
102
103 #if (OS_GIC_VER == 3)
104 ret = PRT_HwiEnable(OS_OPENAMP_NOTIFY_HWI_NUM);
105 if (ret != OS_OK) {
106 return ret;
107 }
108 #endif
109
110 return OS_OK;
111 }
112
rpmsg_backend_init(struct metal_io_region ** io,struct virtio_device * vdev)113 int rpmsg_backend_init(struct metal_io_region **io, struct virtio_device *vdev)
114 {
115 int32_t err;
116 struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
117 struct metal_device *device;
118
119 err = rpmsg_hwi_init();
120 if (err) {
121 return err;
122 }
123
124 /* Libmetal setup */
125 err = metal_init(&metal_params);
126 if (err) {
127 return err;
128 }
129
130 err = metal_register_generic_device(&shm_device);
131 if (err) {
132 return err;
133 }
134
135 err = metal_device_open("generic", SHM_DEVICE_NAME, &device);
136 if (err) {
137 return err;
138 }
139
140 *io = metal_device_io_region(device, 0);
141 if (!*io) {
142 return err;
143 }
144
145 /* Virtqueue setup */
146 vq[0] = virtqueue_allocate(VRING_SIZE);
147 if (!vq[0]) {
148 return -ENOMEM;
149 }
150
151 vq[1] = virtqueue_allocate(VRING_SIZE);
152 if (!vq[1]) {
153 return -ENOMEM;
154 }
155
156 rvrings[0].io = *io;
157 rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS;
158 rvrings[0].info.num_descs = VRING_SIZE;
159 rvrings[0].info.align = VRING_ALIGNMENT;
160 rvrings[0].vq = vq[0];
161
162 rvrings[1].io = *io;
163 rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS;
164 rvrings[1].info.num_descs = VRING_SIZE;
165 rvrings[1].info.align = VRING_ALIGNMENT;
166 rvrings[1].vq = vq[1];
167
168 vdev->role = RPMSG_ROLE;
169 vdev->vrings_num = VRING_COUNT;
170 vdev->func = &dispatch;
171 vdev->vrings_info = &rvrings[0];
172
173 return 0;
174 }
175