mirror of
				https://github.com/Klipper3d/klipper.git
				synced 2025-10-31 02:15:52 +01:00 
			
		
		
		
	Add external code for using RPMsg on the Beaglebone PRU. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
		
			
				
	
	
		
			187 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
 | |
|  *
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  *	* Redistributions of source code must retain the above copyright
 | |
|  *	  notice, this list of conditions and the following disclaimer.
 | |
|  *
 | |
|  *	* Redistributions in binary form must reproduce the above copyright
 | |
|  *	  notice, this list of conditions and the following disclaimer in the
 | |
|  *	  documentation and/or other materials provided with the
 | |
|  *	  distribution.
 | |
|  *
 | |
|  *	* Neither the name of Texas Instruments Incorporated nor the names of
 | |
|  *	  its contributors may be used to endorse or promote products derived
 | |
|  *	  from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
|  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
|  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
|  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
|  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  *  File	:	pru_rpmsg.c
 | |
|  *
 | |
|  *  Summary	:	An RPMsg implementation for the PRU to use while communicating
 | |
|  *			with the ARM host.
 | |
|  *
 | |
|  *  Notes	:
 | |
|  *  - Implementaion of the interface described in "pru_rpmsg.h"
 | |
|  */
 | |
| 
 | |
| #include <string.h>
 | |
| #include <pru_rpmsg.h>
 | |
| 
 | |
| struct pru_rpmsg_hdr {
 | |
| 	uint32_t	src;
 | |
| 	uint32_t	dst;
 | |
| 	uint32_t	reserved;
 | |
| 	uint16_t	len;
 | |
| 	uint16_t	flags;
 | |
| 	uint8_t		data[0];
 | |
| };
 | |
| 
 | |
| struct pru_rpmsg_ns_msg {
 | |
| 	char		name[RPMSG_NAME_SIZE];
 | |
| 	char		desc[RPMSG_NAME_SIZE];
 | |
| 	uint32_t	addr;
 | |
| 	uint32_t	flags;
 | |
| };
 | |
| 
 | |
| int16_t pru_rpmsg_init(
 | |
| 	struct pru_rpmsg_transport	*transport,
 | |
| 	struct fw_rsc_vdev_vring 	*vring0,
 | |
| 	struct fw_rsc_vdev_vring 	*vring1,
 | |
| 	uint32_t 			to_arm_event,
 | |
| 	uint32_t 			from_arm_event
 | |
| )
 | |
| {
 | |
| 	if (to_arm_event > MAX_VALID_EVENT || to_arm_event < MIN_VALID_EVENT)
 | |
| 		return PRU_RPMSG_INVALID_EVENT;
 | |
| 
 | |
| 	if (from_arm_event > MAX_VALID_EVENT || from_arm_event < MIN_VALID_EVENT)
 | |
| 		return PRU_RPMSG_INVALID_EVENT;
 | |
| 
 | |
| 	pru_virtqueue_init(&transport->virtqueue0, vring0, to_arm_event, from_arm_event);
 | |
| 	pru_virtqueue_init(&transport->virtqueue1, vring1, to_arm_event, from_arm_event);
 | |
| 
 | |
| 	return PRU_RPMSG_SUCCESS;
 | |
| }
 | |
| 
 | |
| int16_t pru_rpmsg_send(
 | |
|     struct pru_rpmsg_transport	*transport,
 | |
|     uint32_t			src,
 | |
|     uint32_t			dst,
 | |
|     void			*data,
 | |
|     uint16_t			len
 | |
| )
 | |
| {
 | |
| 	struct pru_rpmsg_hdr	*msg;
 | |
| 	uint32_t		msg_len;
 | |
| 	int16_t			head;
 | |
| 	struct pru_virtqueue	*virtqueue;
 | |
| 
 | |
| 	/*
 | |
| 	 * The length of our payload is larger than the maximum RPMsg buffer size
 | |
| 	 * allowed
 | |
| 	 */
 | |
| 	if (len > (RPMSG_BUF_SIZE - sizeof(struct pru_rpmsg_hdr)))
 | |
| 		return PRU_RPMSG_BUF_TOO_SMALL;
 | |
| 
 | |
| 	virtqueue = &transport->virtqueue0;
 | |
| 
 | |
| 	/* Get an available buffer */
 | |
| 	head = pru_virtqueue_get_avail_buf(virtqueue, (void **)&msg, &msg_len);
 | |
| 
 | |
| 	if (head < 0)
 | |
| 		return PRU_RPMSG_NO_BUF_AVAILABLE;
 | |
| 
 | |
| 	/* Copy local data buffer to the descriptor buffer address */
 | |
| 	memcpy(msg->data, data, len);
 | |
| 	msg->len = len;
 | |
| 	msg->dst = dst;
 | |
| 	msg->src = src;
 | |
| 	msg->flags = 0;
 | |
| 	msg->reserved = 0;
 | |
| 
 | |
| 	/* Add the used buffer */
 | |
| 	if (pru_virtqueue_add_used_buf(virtqueue, head, msg_len) < 0)
 | |
| 		return PRU_RPMSG_INVALID_HEAD;
 | |
| 
 | |
| 	/* Kick the ARM host */
 | |
| 	pru_virtqueue_kick(virtqueue);
 | |
| 
 | |
| 	return PRU_RPMSG_SUCCESS;
 | |
| }
 | |
| 
 | |
| int16_t pru_rpmsg_receive(
 | |
|     struct pru_rpmsg_transport	*transport,
 | |
|     uint16_t			*src,
 | |
|     uint16_t			*dst,
 | |
|     void			*data,
 | |
|     uint16_t			*len
 | |
| )
 | |
| {
 | |
| 	int16_t			head;
 | |
| 	struct pru_rpmsg_hdr	*msg;
 | |
| 	uint32_t		msg_len;
 | |
| 	struct pru_virtqueue	*virtqueue;
 | |
| 
 | |
| 	virtqueue = &transport->virtqueue1;
 | |
| 
 | |
| 	/* Get an available buffer */
 | |
| 	head = pru_virtqueue_get_avail_buf(virtqueue, (void **)&msg, &msg_len);
 | |
| 
 | |
| 	if (head < 0)
 | |
| 		return PRU_RPMSG_NO_BUF_AVAILABLE;
 | |
| 
 | |
| 
 | |
| 	/* Copy the message payload to the local data buffer provided */
 | |
| 	memcpy(data, msg->data, msg->len);
 | |
| 	*src = msg->src;
 | |
| 	*dst = msg->dst;
 | |
| 	*len = msg->len;
 | |
| 
 | |
| 	/* Add the used buffer */
 | |
| 	if (pru_virtqueue_add_used_buf(virtqueue, head, msg_len) < 0)
 | |
| 		return PRU_RPMSG_INVALID_HEAD;
 | |
| 
 | |
| 	/* Kick the ARM host */
 | |
| 	pru_virtqueue_kick(virtqueue);
 | |
| 
 | |
| 	return PRU_RPMSG_SUCCESS;
 | |
| }
 | |
| 
 | |
| int16_t pru_rpmsg_channel(
 | |
|     enum pru_rpmsg_ns_flags	flags,
 | |
|     struct pru_rpmsg_transport	*transport,
 | |
|     char			*name,
 | |
|     char			*desc,
 | |
|     int32_t			port
 | |
| )
 | |
| {
 | |
| 	struct pru_rpmsg_ns_msg	ns_msg;
 | |
| 	uint8_t			i;
 | |
| 
 | |
| 	for (i = 0; i < RPMSG_NAME_SIZE; i++) {
 | |
| 		ns_msg.name[i] = name[i];
 | |
| 		ns_msg.desc[i] = desc[i];
 | |
| 	}
 | |
| 	ns_msg.addr = port;
 | |
| 	ns_msg.flags = flags;
 | |
| 
 | |
| 	return pru_rpmsg_send(transport, port, 53, &ns_msg, sizeof(ns_msg));
 | |
| }
 |