brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · 357272d Raw
406 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2016-2017, Linaro Ltd4 */5 6#include <linux/idr.h>7#include <linux/interrupt.h>8#include <linux/io.h>9#include <linux/list.h>10#include <linux/mfd/syscon.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/of_address.h>14#include <linux/of_irq.h>15#include <linux/platform_device.h>16#include <linux/regmap.h>17#include <linux/rpmsg.h>18#include <linux/slab.h>19#include <linux/workqueue.h>20#include <linux/mailbox_client.h>21 22#include "rpmsg_internal.h"23#include "qcom_glink_native.h"24 25#define RPM_TOC_SIZE		25626#define RPM_TOC_MAGIC		0x67727430 /* grt0 */27#define RPM_TOC_MAX_ENTRIES	((RPM_TOC_SIZE - sizeof(struct rpm_toc)) / \28				 sizeof(struct rpm_toc_entry))29 30#define RPM_TX_FIFO_ID		0x61703272 /* ap2r */31#define RPM_RX_FIFO_ID		0x72326170 /* r2ap */32 33#define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)34 35struct rpm_toc_entry {36	__le32 id;37	__le32 offset;38	__le32 size;39} __packed;40 41struct rpm_toc {42	__le32 magic;43	__le32 count;44 45	struct rpm_toc_entry entries[];46} __packed;47 48struct glink_rpm_pipe {49	struct qcom_glink_pipe native;50 51	void __iomem *tail;52	void __iomem *head;53 54	void __iomem *fifo;55};56 57struct glink_rpm {58	struct qcom_glink *glink;59 60	int irq;61 62	struct mbox_client mbox_client;63	struct mbox_chan *mbox_chan;64 65	struct glink_rpm_pipe rx_pipe;66	struct glink_rpm_pipe tx_pipe;67};68 69static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)70{71	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);72	unsigned int head;73	unsigned int tail;74 75	head = readl(pipe->head);76	tail = readl(pipe->tail);77 78	if (head < tail)79		return pipe->native.length - tail + head;80	else81		return head - tail;82}83 84static void glink_rpm_rx_peek(struct qcom_glink_pipe *glink_pipe,85			      void *data, unsigned int offset, size_t count)86{87	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);88	unsigned int tail;89	size_t len;90 91	tail = readl(pipe->tail);92	tail += offset;93	if (tail >= pipe->native.length)94		tail -= pipe->native.length;95 96	len = min_t(size_t, count, pipe->native.length - tail);97	if (len) {98		__ioread32_copy(data, pipe->fifo + tail,99				len / sizeof(u32));100	}101 102	if (len != count) {103		__ioread32_copy(data + len, pipe->fifo,104				(count - len) / sizeof(u32));105	}106}107 108static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,109				 size_t count)110{111	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);112	unsigned int tail;113 114	tail = readl(pipe->tail);115 116	tail += count;117	if (tail >= pipe->native.length)118		tail -= pipe->native.length;119 120	writel(tail, pipe->tail);121}122 123static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)124{125	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);126	unsigned int head;127	unsigned int tail;128 129	head = readl(pipe->head);130	tail = readl(pipe->tail);131 132	if (tail <= head)133		return pipe->native.length - head + tail;134	else135		return tail - head;136}137 138static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,139					   unsigned int head,140					   const void *data, size_t count)141{142	size_t len;143 144	len = min_t(size_t, count, pipe->native.length - head);145	if (len) {146		__iowrite32_copy(pipe->fifo + head, data,147				 len / sizeof(u32));148	}149 150	if (len != count) {151		__iowrite32_copy(pipe->fifo, data + len,152				 (count - len) / sizeof(u32));153	}154 155	head += count;156	if (head >= pipe->native.length)157		head -= pipe->native.length;158 159	return head;160}161 162static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,163			       const void *hdr, size_t hlen,164			       const void *data, size_t dlen)165{166	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);167	size_t tlen = hlen + dlen;168	size_t aligned_dlen;169	unsigned int head;170	char padding[8] = {0};171	size_t pad;172 173	/* Header length comes from glink native and is always 4 byte aligned */174	if (WARN(hlen % 4, "Glink Header length must be 4 bytes aligned\n"))175		return;176 177	/*178	 * Move the unaligned tail of the message to the padding chunk, to179	 * ensure word aligned accesses180	 */181	aligned_dlen = ALIGN_DOWN(dlen, 4);182	if (aligned_dlen != dlen)183		memcpy(padding, data + aligned_dlen, dlen - aligned_dlen);184 185	head = readl(pipe->head);186	head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);187	head = glink_rpm_tx_write_one(pipe, head, data, aligned_dlen);188 189	pad = ALIGN(tlen, 8) - ALIGN_DOWN(tlen, 4);190	if (pad)191		head = glink_rpm_tx_write_one(pipe, head, padding, pad);192	writel(head, pipe->head);193}194 195static void glink_rpm_tx_kick(struct qcom_glink_pipe *glink_pipe)196{197	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);198	struct glink_rpm *rpm = container_of(pipe, struct glink_rpm, tx_pipe);199 200	mbox_send_message(rpm->mbox_chan, NULL);201	mbox_client_txdone(rpm->mbox_chan, 0);202}203 204static irqreturn_t qcom_glink_rpm_intr(int irq, void *data)205{206	struct glink_rpm *rpm = data;207 208	qcom_glink_native_rx(rpm->glink);209 210	return IRQ_HANDLED;211}212 213static int glink_rpm_parse_toc(struct device *dev,214			       void __iomem *msg_ram,215			       size_t msg_ram_size,216			       struct glink_rpm_pipe *rx,217			       struct glink_rpm_pipe *tx)218{219	struct rpm_toc *toc;220	int num_entries;221	unsigned int id;222	size_t offset;223	size_t size;224	void *buf;225	int i;226 227	buf = kzalloc(RPM_TOC_SIZE, GFP_KERNEL);228	if (!buf)229		return -ENOMEM;230 231	__ioread32_copy(buf, msg_ram + msg_ram_size - RPM_TOC_SIZE,232			RPM_TOC_SIZE / sizeof(u32));233 234	toc = buf;235 236	if (le32_to_cpu(toc->magic) != RPM_TOC_MAGIC) {237		dev_err(dev, "RPM TOC has invalid magic\n");238		goto err_inval;239	}240 241	num_entries = le32_to_cpu(toc->count);242	if (num_entries > RPM_TOC_MAX_ENTRIES) {243		dev_err(dev, "Invalid number of toc entries\n");244		goto err_inval;245	}246 247	for (i = 0; i < num_entries; i++) {248		id = le32_to_cpu(toc->entries[i].id);249		offset = le32_to_cpu(toc->entries[i].offset);250		size = le32_to_cpu(toc->entries[i].size);251 252		if (offset > msg_ram_size || offset + size > msg_ram_size) {253			dev_err(dev, "TOC entry with invalid size\n");254			continue;255		}256 257		switch (id) {258		case RPM_RX_FIFO_ID:259			rx->native.length = size;260 261			rx->tail = msg_ram + offset;262			rx->head = msg_ram + offset + sizeof(u32);263			rx->fifo = msg_ram + offset + 2 * sizeof(u32);264			break;265		case RPM_TX_FIFO_ID:266			tx->native.length = size;267 268			tx->tail = msg_ram + offset;269			tx->head = msg_ram + offset + sizeof(u32);270			tx->fifo = msg_ram + offset + 2 * sizeof(u32);271			break;272		}273	}274 275	if (!rx->fifo || !tx->fifo) {276		dev_err(dev, "Unable to find rx and tx descriptors\n");277		goto err_inval;278	}279 280	kfree(buf);281	return 0;282 283err_inval:284	kfree(buf);285	return -EINVAL;286}287 288static int glink_rpm_probe(struct platform_device *pdev)289{290	struct qcom_glink *glink;291	struct glink_rpm *rpm;292	struct device_node *np;293	void __iomem *msg_ram;294	size_t msg_ram_size;295	struct device *dev = &pdev->dev;296	struct resource r;297	int ret;298 299	rpm = devm_kzalloc(&pdev->dev, sizeof(*rpm), GFP_KERNEL);300	if (!rpm)301		return -ENOMEM;302 303	np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", 0);304	ret = of_address_to_resource(np, 0, &r);305	of_node_put(np);306	if (ret)307		return ret;308 309	msg_ram = devm_ioremap(dev, r.start, resource_size(&r));310	msg_ram_size = resource_size(&r);311	if (!msg_ram)312		return -ENOMEM;313 314	ret = glink_rpm_parse_toc(dev, msg_ram, msg_ram_size,315				  &rpm->rx_pipe, &rpm->tx_pipe);316	if (ret)317		return ret;318 319	rpm->irq = of_irq_get(dev->of_node, 0);320	ret = devm_request_irq(dev, rpm->irq, qcom_glink_rpm_intr,321			       IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,322			       "glink-rpm", rpm);323	if (ret) {324		dev_err(dev, "failed to request IRQ\n");325		return ret;326	}327 328	rpm->mbox_client.dev = dev;329	rpm->mbox_client.knows_txdone = true;330	rpm->mbox_chan = mbox_request_channel(&rpm->mbox_client, 0);331	if (IS_ERR(rpm->mbox_chan))332		return dev_err_probe(dev, PTR_ERR(rpm->mbox_chan), "failed to acquire IPC channel\n");333 334	/* Pipe specific accessors */335	rpm->rx_pipe.native.avail = glink_rpm_rx_avail;336	rpm->rx_pipe.native.peek = glink_rpm_rx_peek;337	rpm->rx_pipe.native.advance = glink_rpm_rx_advance;338	rpm->tx_pipe.native.avail = glink_rpm_tx_avail;339	rpm->tx_pipe.native.write = glink_rpm_tx_write;340	rpm->tx_pipe.native.kick = glink_rpm_tx_kick;341 342	writel(0, rpm->tx_pipe.head);343	writel(0, rpm->rx_pipe.tail);344 345	glink = qcom_glink_native_probe(dev,346					0,347					&rpm->rx_pipe.native,348					&rpm->tx_pipe.native,349					true);350	if (IS_ERR(glink)) {351		mbox_free_channel(rpm->mbox_chan);352		return PTR_ERR(glink);353	}354 355	rpm->glink = glink;356 357	platform_set_drvdata(pdev, rpm);358 359	enable_irq(rpm->irq);360 361	return 0;362}363 364static void glink_rpm_remove(struct platform_device *pdev)365{366	struct glink_rpm *rpm = platform_get_drvdata(pdev);367	struct qcom_glink *glink = rpm->glink;368 369	disable_irq(rpm->irq);370 371	qcom_glink_native_remove(glink);372 373	mbox_free_channel(rpm->mbox_chan);374}375 376static const struct of_device_id glink_rpm_of_match[] = {377	{ .compatible = "qcom,glink-rpm" },378	{}379};380MODULE_DEVICE_TABLE(of, glink_rpm_of_match);381 382static struct platform_driver glink_rpm_driver = {383	.probe = glink_rpm_probe,384	.remove_new = glink_rpm_remove,385	.driver = {386		.name = "qcom_glink_rpm",387		.of_match_table = glink_rpm_of_match,388	},389};390 391static int __init glink_rpm_init(void)392{393	return platform_driver_register(&glink_rpm_driver);394}395subsys_initcall(glink_rpm_init);396 397static void __exit glink_rpm_exit(void)398{399	platform_driver_unregister(&glink_rpm_driver);400}401module_exit(glink_rpm_exit);402 403MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");404MODULE_DESCRIPTION("Qualcomm GLINK RPM driver");405MODULE_LICENSE("GPL v2");406