brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 7a49360 Raw
242 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip PolarFire SoC (MPFS) system controller driver4 *5 * Copyright (c) 2020-2021 Microchip Corporation. All rights reserved.6 *7 * Author: Conor Dooley <conor.dooley@microchip.com>8 *9 */10 11#include <linux/slab.h>12#include <linux/kref.h>13#include <linux/module.h>14#include <linux/jiffies.h>15#include <linux/mtd/mtd.h>16#include <linux/spi/spi.h>17#include <linux/interrupt.h>18#include <linux/of.h>19#include <linux/mailbox_client.h>20#include <linux/platform_device.h>21#include <soc/microchip/mpfs.h>22 23/*24 * This timeout must be long, as some services (example: image authentication)25 * take significant time to complete26 */27#define MPFS_SYS_CTRL_TIMEOUT_MS 3000028 29static DEFINE_MUTEX(transaction_lock);30 31struct mpfs_sys_controller {32	struct mbox_client client;33	struct mbox_chan *chan;34	struct completion c;35	struct mtd_info *flash;36	struct kref consumers;37};38 39int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)40{41	unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);42	int ret;43 44	ret = mutex_lock_interruptible(&transaction_lock);45	if (ret)46		return ret;47 48	reinit_completion(&sys_controller->c);49 50	ret = mbox_send_message(sys_controller->chan, msg);51	if (ret < 0) {52		dev_warn(sys_controller->client.dev, "MPFS sys controller service timeout\n");53		goto out;54	}55 56	/*57	 * Unfortunately, the system controller will only deliver an interrupt58	 * if a service succeeds. mbox_send_message() will block until the busy59	 * flag is gone. If the busy flag is gone but no interrupt has arrived60	 * to trigger the rx callback then the service can be deemed to have61	 * failed.62	 * The caller can then interrogate msg::response::resp_status to63	 * determine the cause of the failure.64	 * mbox_send_message() returns positive integers in the success path, so65	 * ret needs to be cleared if we do get an interrupt.66	 */67	if (!wait_for_completion_timeout(&sys_controller->c, timeout)) {68		ret = -EBADMSG;69		dev_warn(sys_controller->client.dev,70			 "MPFS sys controller service failed with status: %d\n",71			 msg->response->resp_status);72	} else {73		ret = 0;74	}75 76out:77	mutex_unlock(&transaction_lock);78 79	return ret;80}81EXPORT_SYMBOL(mpfs_blocking_transaction);82 83static void mpfs_sys_controller_rx_callback(struct mbox_client *client, void *msg)84{85	struct mpfs_sys_controller *sys_controller =86		container_of(client, struct mpfs_sys_controller, client);87 88	complete(&sys_controller->c);89}90 91static void mpfs_sys_controller_delete(struct kref *kref)92{93	struct mpfs_sys_controller *sys_controller =94		container_of(kref, struct mpfs_sys_controller, consumers);95 96	mbox_free_channel(sys_controller->chan);97	kfree(sys_controller);98}99 100static void mpfs_sys_controller_put(void *data)101{102	struct mpfs_sys_controller *sys_controller = data;103 104	kref_put(&sys_controller->consumers, mpfs_sys_controller_delete);105}106 107struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_client)108{109	return mpfs_client->flash;110}111EXPORT_SYMBOL(mpfs_sys_controller_get_flash);112 113static struct platform_device subdevs[] = {114	{115		.name		= "mpfs-rng",116		.id		= -1,117	},118	{119		.name		= "mpfs-generic-service",120		.id		= -1,121	},122	{123		.name		= "mpfs-auto-update",124		.id		= -1,125	},126};127 128static int mpfs_sys_controller_probe(struct platform_device *pdev)129{130	struct device *dev = &pdev->dev;131	struct mpfs_sys_controller *sys_controller;132	struct device_node *np;133	int i, ret;134 135	sys_controller = kzalloc(sizeof(*sys_controller), GFP_KERNEL);136	if (!sys_controller)137		return -ENOMEM;138 139	np = of_parse_phandle(dev->of_node, "microchip,bitstream-flash", 0);140	if (!np)141		goto no_flash;142 143	sys_controller->flash = of_get_mtd_device_by_node(np);144	of_node_put(np);145	if (IS_ERR(sys_controller->flash))146		return dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");147 148no_flash:149	sys_controller->client.dev = dev;150	sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback;151	sys_controller->client.tx_block = 1U;152	sys_controller->client.tx_tout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);153 154	sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);155	if (IS_ERR(sys_controller->chan)) {156		ret = dev_err_probe(dev, PTR_ERR(sys_controller->chan),157				    "Failed to get mbox channel\n");158		kfree(sys_controller);159		return ret;160	}161 162	init_completion(&sys_controller->c);163	kref_init(&sys_controller->consumers);164 165	platform_set_drvdata(pdev, sys_controller);166 167 168	for (i = 0; i < ARRAY_SIZE(subdevs); i++) {169		subdevs[i].dev.parent = dev;170		if (platform_device_register(&subdevs[i]))171			dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name);172	}173 174	dev_info(&pdev->dev, "Registered MPFS system controller\n");175 176	return 0;177}178 179static void mpfs_sys_controller_remove(struct platform_device *pdev)180{181	struct mpfs_sys_controller *sys_controller = platform_get_drvdata(pdev);182 183	mpfs_sys_controller_put(sys_controller);184}185 186static const struct of_device_id mpfs_sys_controller_of_match[] = {187	{.compatible = "microchip,mpfs-sys-controller", },188	{},189};190MODULE_DEVICE_TABLE(of, mpfs_sys_controller_of_match);191 192struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev)193{194	const struct of_device_id *match;195	struct mpfs_sys_controller *sys_controller;196	int ret;197 198	if (!dev->parent)199		goto err_no_device;200 201	match = of_match_node(mpfs_sys_controller_of_match,  dev->parent->of_node);202	of_node_put(dev->parent->of_node);203	if (!match)204		goto err_no_device;205 206	sys_controller = dev_get_drvdata(dev->parent);207	if (!sys_controller)208		goto err_bad_device;209 210	if (!kref_get_unless_zero(&sys_controller->consumers))211		goto err_bad_device;212 213	ret = devm_add_action_or_reset(dev, mpfs_sys_controller_put, sys_controller);214	if (ret)215		return ERR_PTR(ret);216 217	return sys_controller;218 219err_no_device:220	dev_dbg(dev, "Parent device was not an MPFS system controller\n");221	return ERR_PTR(-ENODEV);222 223err_bad_device:224	dev_dbg(dev, "MPFS system controller found but could not register as a sub device\n");225	return ERR_PTR(-EPROBE_DEFER);226}227EXPORT_SYMBOL(mpfs_sys_controller_get);228 229static struct platform_driver mpfs_sys_controller_driver = {230	.driver = {231		.name = "mpfs-sys-controller",232		.of_match_table = mpfs_sys_controller_of_match,233	},234	.probe = mpfs_sys_controller_probe,235	.remove_new = mpfs_sys_controller_remove,236};237module_platform_driver(mpfs_sys_controller_driver);238 239MODULE_LICENSE("GPL v2");240MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");241MODULE_DESCRIPTION("MPFS system controller driver");242