xref: /rk3399_rockchip-uboot/drivers/firmware/scmi/smt.c (revision e091b6c996a68a6a0faa2bd3ffdd90b3ba5f44ce)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
4  * Copyright (C) 2019-2020 Linaro Limited.
5  */
6 
7 #include <common.h>
8 #include <cpu_func.h>
9 #include <dm.h>
10 #include <dm/device_compat.h>
11 #include <errno.h>
12 #include <scmi_agent.h>
13 #include <asm/cache.h>
14 #include <asm/system.h>
15 #include <dm/ofnode.h>
16 #include <linux/compat.h>
17 #include <linux/io.h>
18 #include <linux/ioport.h>
19 
20 #include "smt.h"
21 
22 /**
23  * Get shared memory configuration defined by the referred DT phandle
24  * Return with a errno compliant value.
25  */
26 int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
27 {
28 	int ret;
29 	struct ofnode_phandle_args args;
30 	struct resource resource;
31 	fdt32_t faddr;
32 	phys_addr_t paddr;
33 
34 	ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);
35 	if (ret)
36 		return ret;
37 
38 	ret = ofnode_read_resource(args.node, 0, &resource);
39 	if (ret)
40 		return ret;
41 
42 	faddr = cpu_to_fdt32(resource.start);
43 	paddr = ofnode_translate_address(args.node, &faddr);
44 
45 	smt->size = resource_size(&resource);
46 	if (smt->size < sizeof(struct scmi_smt_header)) {
47 		dev_err(dev, "Shared memory buffer too small\n");
48 		return -EINVAL;
49 	}
50 
51 	smt->buf = devm_ioremap(dev, paddr, smt->size);
52 	if (!smt->buf)
53 		return -ENOMEM;
54 
55 #ifdef CONFIG_ARM
56 	if (dcache_status())
57 		mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,
58 						smt->size, DCACHE_OFF);
59 #endif
60 
61 	return 0;
62 }
63 
64 /**
65  * Write SCMI message @msg into a SMT shared buffer @smt.
66  * Return 0 on success and with a negative errno in case of error.
67  */
68 int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
69 			  struct scmi_msg *msg)
70 {
71 	struct scmi_smt_header *hdr = (void *)smt->buf;
72 
73 	if ((!msg->in_msg && msg->in_msg_sz) ||
74 	    (!msg->out_msg && msg->out_msg_sz))
75 		return -EINVAL;
76 
77 	if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
78 		dev_dbg(dev, "Channel busy\n");
79 		return -EBUSY;
80 	}
81 
82 	if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
83 	    smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
84 		dev_dbg(dev, "Buffer too small\n");
85 		return -ETOOSMALL;
86 	}
87 
88 	/* Load message in shared memory */
89 	hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
90 	hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header);
91 	hdr->msg_header = SMT_HEADER_TOKEN(0) |
92 			  SMT_HEADER_MESSAGE_TYPE(0) |
93 			  SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
94 			  SMT_HEADER_MESSAGE_ID(msg->message_id);
95 
96 	memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
97 
98 	return 0;
99 }
100 
101 /**
102  * Read SCMI message from a SMT shared buffer @smt and copy it into @msg.
103  * Return 0 on success and with a negative errno in case of error.
104  */
105 int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
106 			    struct scmi_msg *msg)
107 {
108 	struct scmi_smt_header *hdr = (void *)smt->buf;
109 
110 	if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
111 		dev_err(dev, "Channel unexpectedly busy\n");
112 		return -EBUSY;
113 	}
114 
115 	if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
116 		dev_err(dev, "Channel error reported, reset channel\n");
117 		return -ECOMM;
118 	}
119 
120 	if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) {
121 		dev_err(dev, "Buffer to small\n");
122 		return -ETOOSMALL;
123 	}
124 
125 	/* Get the data */
126 	msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header);
127 	memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
128 
129 	return 0;
130 }
131 
132 /**
133  * Clear SMT flags in shared buffer to allow further message exchange
134  */
135 void scmi_clear_smt_channel(struct scmi_smt *smt)
136 {
137 	struct scmi_smt_header *hdr = (void *)smt->buf;
138 
139 	hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
140 }
141