// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2019 NXP * */ #include #include #include #include #include #include #include #include #include #include #include static LIST_HEAD(vservice_channels); void * __weak board_imx_vservice_get_buffer(struct imx_vservice_channel *node, u32 size) { if (size <= CONFIG_IMX_VSERVICE_SHARED_BUFFER_SIZE) return (void * )CONFIG_IMX_VSERVICE_SHARED_BUFFER; return NULL; } void * imx_vservice_get_buffer(struct imx_vservice_channel *node, u32 size) { return board_imx_vservice_get_buffer(node, size); } int imx_vservice_blocking_request(struct imx_vservice_channel *node, u8 *buf, u32* size) { int ret = 0; union imx_m4_msg msg; msg.format.seq = node->msg_seq; msg.format.type = MU_MSG_REQ; msg.format.buffer = (u32)(ulong)buf; msg.format.size = *size; ret = misc_call(node->mu_dev, 1000000, &msg, 4, &msg, 4); if (ret) { printf("%s: Send request MU message failed, ret %d\n", __func__, ret); goto MU_ERR; } if (msg.format.type != MU_MSG_RESP|| msg.format.seq != node->msg_seq) { printf("%s: wrong msg response: type %d, seq %d, expect seq %d\n", __func__, msg.format.type, msg.format.seq, node->msg_seq); ret = -EIO; goto MU_ERR; } *size = msg.format.size; MU_ERR: node->msg_seq++; return ret; } static int imx_vservice_connect(struct imx_vservice_channel *node) { int ret = 0; union imx_m4_msg msg; unsigned long timeout = timer_get_us() + 2000000; /* 2s timeout */ for (;;) { msg.format.seq = 0; msg.format.type = MU_MSG_READY_A; msg.format.buffer = 0; msg.format.size = 0; ret = misc_call(node->mu_dev, 100000, &msg, 4, &msg, 4); if (!ret && msg.format.type == MU_MSG_READY_B) return 0; if (time_after(timer_get_us(), timeout)) { printf("%s: Timeout to connect peer, %d\n", __func__, ret); return -ETIMEDOUT; } } return -EIO; } struct udevice * __weak board_imx_vservice_find_mu(struct udevice *virt_dev) { int ret; struct ofnode_phandle_args args; struct udevice *mu_dev; /* Default get mu from "fsl,vservice-mu" property*/ ret = dev_read_phandle_with_args(virt_dev, "fsl,vservice-mu", NULL, 0, 0, &args); if (ret) { printf("Can't find \"fsl,vservice-mu\" property\n"); return NULL; } ret = uclass_find_device_by_ofnode(UCLASS_MISC, args.node, &mu_dev); if (ret) { printf("Can't find MU device, err %d\n", ret); return NULL; } return mu_dev; } static struct udevice * imx_vservice_find_mu(struct udevice *virt_dev) { return board_imx_vservice_find_mu(virt_dev); } struct imx_vservice_channel * imx_vservice_setup(struct udevice *virt_dev) { int ret; struct udevice *mu_dev; struct imx_vservice_channel *channel; mu_dev = imx_vservice_find_mu(virt_dev); if (mu_dev == NULL) { printf("No MU device for virtual service %s connection\n", virt_dev->name); return NULL; } ret = device_probe(mu_dev); if (ret) { printf("Probe MU device failed\n"); return NULL; } list_for_each_entry(channel, &vservice_channels, channel_head) { if (channel->mu_dev == mu_dev) return channel; } channel = malloc(sizeof(struct imx_vservice_channel)); if (!channel) { printf("Malloc vservice channel is failed\n"); return NULL; } channel->msg_seq = 0; channel->mu_dev = mu_dev; INIT_LIST_HEAD(&channel->channel_head); ret = imx_vservice_connect(channel); if (ret) { printf("VService: Connection is failed, ret %d\n", ret); free(channel); return NULL; } list_add_tail(&channel->channel_head, &vservice_channels); printf("VService: Connection is ok on MU %s\n", mu_dev->name); return channel; }