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