Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * System Control and Management Interface (SCMI) Message SMC/HVC
  4 * Transport driver
  5 *
  6 * Copyright 2020 NXP
  7 */
  8
  9#include <linux/arm-smccc.h>
 10#include <linux/device.h>
 11#include <linux/err.h>
 
 12#include <linux/mutex.h>
 13#include <linux/of.h>
 14#include <linux/of_address.h>
 
 15#include <linux/slab.h>
 16
 17#include "common.h"
 18
 19/**
 20 * struct scmi_smc - Structure representing a SCMI smc transport
 21 *
 22 * @cinfo: SCMI channel info
 23 * @shmem: Transmit/Receive shared memory area
 24 * @shmem_lock: Lock to protect access to Tx/Rx shared memory area
 25 * @func_id: smc/hvc call function id
 
 
 26 */
 27
 28struct scmi_smc {
 29	struct scmi_chan_info *cinfo;
 30	struct scmi_shared_mem __iomem *shmem;
 31	struct mutex shmem_lock;
 32	u32 func_id;
 
 
 33};
 34
 
 
 
 
 
 
 
 
 
 35static bool smc_chan_available(struct device *dev, int idx)
 36{
 37	struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0);
 38	if (!np)
 39		return false;
 40
 41	of_node_put(np);
 42	return true;
 43}
 44
 45static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 46			  bool tx)
 47{
 48	struct device *cdev = cinfo->dev;
 49	struct scmi_smc *scmi_info;
 50	resource_size_t size;
 51	struct resource res;
 52	struct device_node *np;
 53	u32 func_id;
 54	int ret;
 55
 56	if (!tx)
 57		return -ENODEV;
 58
 59	scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL);
 60	if (!scmi_info)
 61		return -ENOMEM;
 62
 63	np = of_parse_phandle(cdev->of_node, "shmem", 0);
 
 
 
 64	ret = of_address_to_resource(np, 0, &res);
 65	of_node_put(np);
 66	if (ret) {
 67		dev_err(cdev, "failed to get SCMI Tx shared memory\n");
 68		return ret;
 69	}
 70
 71	size = resource_size(&res);
 72	scmi_info->shmem = devm_ioremap(dev, res.start, size);
 73	if (!scmi_info->shmem) {
 74		dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
 75		return -EADDRNOTAVAIL;
 76	}
 77
 78	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
 79	if (ret < 0)
 80		return ret;
 81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 82	scmi_info->func_id = func_id;
 83	scmi_info->cinfo = cinfo;
 84	mutex_init(&scmi_info->shmem_lock);
 85	cinfo->transport_info = scmi_info;
 86
 87	return 0;
 88}
 89
 90static int smc_chan_free(int id, void *p, void *data)
 91{
 92	struct scmi_chan_info *cinfo = p;
 93	struct scmi_smc *scmi_info = cinfo->transport_info;
 94
 95	cinfo->transport_info = NULL;
 96	scmi_info->cinfo = NULL;
 97
 98	scmi_free_channel(cinfo, data, id);
 99
100	return 0;
101}
102
103static int smc_send_message(struct scmi_chan_info *cinfo,
104			    struct scmi_xfer *xfer)
105{
106	struct scmi_smc *scmi_info = cinfo->transport_info;
107	struct arm_smccc_res res;
108
109	mutex_lock(&scmi_info->shmem_lock);
110
111	shmem_tx_prepare(scmi_info->shmem, xfer);
112
 
 
 
113	arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
 
 
 
 
114	scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem));
115
116	mutex_unlock(&scmi_info->shmem_lock);
117
118	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
119	if (res.a0)
120		return -EOPNOTSUPP;
121	return 0;
122}
123
124static void smc_fetch_response(struct scmi_chan_info *cinfo,
125			       struct scmi_xfer *xfer)
126{
127	struct scmi_smc *scmi_info = cinfo->transport_info;
128
129	shmem_fetch_response(scmi_info->shmem, xfer);
130}
131
132static bool
133smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
134{
135	struct scmi_smc *scmi_info = cinfo->transport_info;
136
137	return shmem_poll_done(scmi_info->shmem, xfer);
138}
139
140static struct scmi_transport_ops scmi_smc_ops = {
141	.chan_available = smc_chan_available,
142	.chan_setup = smc_chan_setup,
143	.chan_free = smc_chan_free,
144	.send_message = smc_send_message,
145	.fetch_response = smc_fetch_response,
146	.poll_done = smc_poll_done,
147};
148
149const struct scmi_desc scmi_smc_desc = {
150	.ops = &scmi_smc_ops,
151	.max_rx_timeout_ms = 30,
152	.max_msg = 1,
153	.max_msg_size = 128,
154};
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * System Control and Management Interface (SCMI) Message SMC/HVC
  4 * Transport driver
  5 *
  6 * Copyright 2020 NXP
  7 */
  8
  9#include <linux/arm-smccc.h>
 10#include <linux/device.h>
 11#include <linux/err.h>
 12#include <linux/interrupt.h>
 13#include <linux/mutex.h>
 14#include <linux/of.h>
 15#include <linux/of_address.h>
 16#include <linux/of_irq.h>
 17#include <linux/slab.h>
 18
 19#include "common.h"
 20
 21/**
 22 * struct scmi_smc - Structure representing a SCMI smc transport
 23 *
 24 * @cinfo: SCMI channel info
 25 * @shmem: Transmit/Receive shared memory area
 26 * @shmem_lock: Lock to protect access to Tx/Rx shared memory area
 27 * @func_id: smc/hvc call function id
 28 * @irq: Optional; employed when platforms indicates msg completion by intr.
 29 * @tx_complete: Optional, employed only when irq is valid.
 30 */
 31
 32struct scmi_smc {
 33	struct scmi_chan_info *cinfo;
 34	struct scmi_shared_mem __iomem *shmem;
 35	struct mutex shmem_lock;
 36	u32 func_id;
 37	int irq;
 38	struct completion tx_complete;
 39};
 40
 41static irqreturn_t smc_msg_done_isr(int irq, void *data)
 42{
 43	struct scmi_smc *scmi_info = data;
 44
 45	complete(&scmi_info->tx_complete);
 46
 47	return IRQ_HANDLED;
 48}
 49
 50static bool smc_chan_available(struct device *dev, int idx)
 51{
 52	struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0);
 53	if (!np)
 54		return false;
 55
 56	of_node_put(np);
 57	return true;
 58}
 59
 60static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 61			  bool tx)
 62{
 63	struct device *cdev = cinfo->dev;
 64	struct scmi_smc *scmi_info;
 65	resource_size_t size;
 66	struct resource res;
 67	struct device_node *np;
 68	u32 func_id;
 69	int ret, irq;
 70
 71	if (!tx)
 72		return -ENODEV;
 73
 74	scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL);
 75	if (!scmi_info)
 76		return -ENOMEM;
 77
 78	np = of_parse_phandle(cdev->of_node, "shmem", 0);
 79	if (!of_device_is_compatible(np, "arm,scmi-shmem"))
 80		return -ENXIO;
 81
 82	ret = of_address_to_resource(np, 0, &res);
 83	of_node_put(np);
 84	if (ret) {
 85		dev_err(cdev, "failed to get SCMI Tx shared memory\n");
 86		return ret;
 87	}
 88
 89	size = resource_size(&res);
 90	scmi_info->shmem = devm_ioremap(dev, res.start, size);
 91	if (!scmi_info->shmem) {
 92		dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
 93		return -EADDRNOTAVAIL;
 94	}
 95
 96	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
 97	if (ret < 0)
 98		return ret;
 99
100	/*
101	 * If there is an interrupt named "a2p", then the service and
102	 * completion of a message is signaled by an interrupt rather than by
103	 * the return of the SMC call.
104	 */
105	irq = of_irq_get_byname(cdev->of_node, "a2p");
106	if (irq > 0) {
107		ret = devm_request_irq(dev, irq, smc_msg_done_isr,
108				       IRQF_NO_SUSPEND,
109				       dev_name(dev), scmi_info);
110		if (ret) {
111			dev_err(dev, "failed to setup SCMI smc irq\n");
112			return ret;
113		}
114		init_completion(&scmi_info->tx_complete);
115		scmi_info->irq = irq;
116	}
117
118	scmi_info->func_id = func_id;
119	scmi_info->cinfo = cinfo;
120	mutex_init(&scmi_info->shmem_lock);
121	cinfo->transport_info = scmi_info;
122
123	return 0;
124}
125
126static int smc_chan_free(int id, void *p, void *data)
127{
128	struct scmi_chan_info *cinfo = p;
129	struct scmi_smc *scmi_info = cinfo->transport_info;
130
131	cinfo->transport_info = NULL;
132	scmi_info->cinfo = NULL;
133
134	scmi_free_channel(cinfo, data, id);
135
136	return 0;
137}
138
139static int smc_send_message(struct scmi_chan_info *cinfo,
140			    struct scmi_xfer *xfer)
141{
142	struct scmi_smc *scmi_info = cinfo->transport_info;
143	struct arm_smccc_res res;
144
145	mutex_lock(&scmi_info->shmem_lock);
146
147	shmem_tx_prepare(scmi_info->shmem, xfer);
148
149	if (scmi_info->irq)
150		reinit_completion(&scmi_info->tx_complete);
151
152	arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
153
154	if (scmi_info->irq)
155		wait_for_completion(&scmi_info->tx_complete);
156
157	scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem));
158
159	mutex_unlock(&scmi_info->shmem_lock);
160
161	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
162	if (res.a0)
163		return -EOPNOTSUPP;
164	return 0;
165}
166
167static void smc_fetch_response(struct scmi_chan_info *cinfo,
168			       struct scmi_xfer *xfer)
169{
170	struct scmi_smc *scmi_info = cinfo->transport_info;
171
172	shmem_fetch_response(scmi_info->shmem, xfer);
173}
174
175static bool
176smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
177{
178	struct scmi_smc *scmi_info = cinfo->transport_info;
179
180	return shmem_poll_done(scmi_info->shmem, xfer);
181}
182
183static const struct scmi_transport_ops scmi_smc_ops = {
184	.chan_available = smc_chan_available,
185	.chan_setup = smc_chan_setup,
186	.chan_free = smc_chan_free,
187	.send_message = smc_send_message,
188	.fetch_response = smc_fetch_response,
189	.poll_done = smc_poll_done,
190};
191
192const struct scmi_desc scmi_smc_desc = {
193	.ops = &scmi_smc_ops,
194	.max_rx_timeout_ms = 30,
195	.max_msg = 20,
196	.max_msg_size = 128,
197};