1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Microchip PolarFire SoC (MPFS) system controller driver 4 * 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/interrupt.h> 16 #include <linux/of_platform.h> 17 #include <linux/mailbox_client.h> 18 #include <linux/platform_device.h> 19 #include <soc/microchip/mpfs.h> 20 21 #define MPFS_SYS_CTRL_TIMEOUT_MS 100 22 23 static DEFINE_MUTEX(transaction_lock); 24 25 struct mpfs_sys_controller { 26 struct mbox_client client; 27 struct mbox_chan *chan; 28 struct completion c; 29 struct kref consumers; 30 }; 31 32 int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg) 33 { 34 unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS); 35 int ret; 36 37 ret = mutex_lock_interruptible(&transaction_lock); 38 if (ret) 39 return ret; 40 41 reinit_completion(&sys_controller->c); 42 43 ret = mbox_send_message(sys_controller->chan, msg); 44 if (ret < 0) 45 goto out; 46 47 if (!wait_for_completion_timeout(&sys_controller->c, timeout)) { 48 ret = -ETIMEDOUT; 49 dev_warn(sys_controller->client.dev, "MPFS sys controller transaction timeout\n"); 50 } else { 51 /* mbox_send_message() returns positive integers on success */ 52 ret = 0; 53 } 54 55 out: 56 mutex_unlock(&transaction_lock); 57 58 return ret; 59 } 60 EXPORT_SYMBOL(mpfs_blocking_transaction); 61 62 static void rx_callback(struct mbox_client *client, void *msg) 63 { 64 struct mpfs_sys_controller *sys_controller = 65 container_of(client, struct mpfs_sys_controller, client); 66 67 complete(&sys_controller->c); 68 } 69 70 static void mpfs_sys_controller_delete(struct kref *kref) 71 { 72 struct mpfs_sys_controller *sys_controller = 73 container_of(kref, struct mpfs_sys_controller, consumers); 74 75 mbox_free_channel(sys_controller->chan); 76 kfree(sys_controller); 77 } 78 79 static void mpfs_sys_controller_put(void *data) 80 { 81 struct mpfs_sys_controller *sys_controller = data; 82 83 kref_put(&sys_controller->consumers, mpfs_sys_controller_delete); 84 } 85 86 static struct platform_device subdevs[] = { 87 { 88 .name = "mpfs-rng", 89 .id = -1, 90 }, 91 { 92 .name = "mpfs-generic-service", 93 .id = -1, 94 } 95 }; 96 97 static int mpfs_sys_controller_probe(struct platform_device *pdev) 98 { 99 struct device *dev = &pdev->dev; 100 struct mpfs_sys_controller *sys_controller; 101 int i, ret; 102 103 sys_controller = kzalloc(sizeof(*sys_controller), GFP_KERNEL); 104 if (!sys_controller) 105 return -ENOMEM; 106 107 sys_controller->client.dev = dev; 108 sys_controller->client.rx_callback = rx_callback; 109 sys_controller->client.tx_block = 1U; 110 111 sys_controller->chan = mbox_request_channel(&sys_controller->client, 0); 112 if (IS_ERR(sys_controller->chan)) { 113 ret = dev_err_probe(dev, PTR_ERR(sys_controller->chan), 114 "Failed to get mbox channel\n"); 115 kfree(sys_controller); 116 return ret; 117 } 118 119 init_completion(&sys_controller->c); 120 kref_init(&sys_controller->consumers); 121 122 platform_set_drvdata(pdev, sys_controller); 123 124 dev_info(&pdev->dev, "Registered MPFS system controller\n"); 125 126 for (i = 0; i < ARRAY_SIZE(subdevs); i++) { 127 subdevs[i].dev.parent = dev; 128 if (platform_device_register(&subdevs[i])) 129 dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name); 130 } 131 132 return 0; 133 } 134 135 static int mpfs_sys_controller_remove(struct platform_device *pdev) 136 { 137 struct mpfs_sys_controller *sys_controller = platform_get_drvdata(pdev); 138 139 mpfs_sys_controller_put(sys_controller); 140 141 return 0; 142 } 143 144 static const struct of_device_id mpfs_sys_controller_of_match[] = { 145 {.compatible = "microchip,mpfs-sys-controller", }, 146 {}, 147 }; 148 MODULE_DEVICE_TABLE(of, mpfs_sys_controller_of_match); 149 150 struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev) 151 { 152 const struct of_device_id *match; 153 struct mpfs_sys_controller *sys_controller; 154 int ret; 155 156 if (!dev->parent) 157 goto err_no_device; 158 159 match = of_match_node(mpfs_sys_controller_of_match, dev->parent->of_node); 160 of_node_put(dev->parent->of_node); 161 if (!match) 162 goto err_no_device; 163 164 sys_controller = dev_get_drvdata(dev->parent); 165 if (!sys_controller) 166 goto err_bad_device; 167 168 if (!kref_get_unless_zero(&sys_controller->consumers)) 169 goto err_bad_device; 170 171 ret = devm_add_action_or_reset(dev, mpfs_sys_controller_put, sys_controller); 172 if (ret) 173 return ERR_PTR(ret); 174 175 return sys_controller; 176 177 err_no_device: 178 dev_dbg(dev, "Parent device was not an MPFS system controller\n"); 179 return ERR_PTR(-ENODEV); 180 181 err_bad_device: 182 dev_dbg(dev, "MPFS system controller found but could not register as a sub device\n"); 183 return ERR_PTR(-EPROBE_DEFER); 184 } 185 EXPORT_SYMBOL(mpfs_sys_controller_get); 186 187 static struct platform_driver mpfs_sys_controller_driver = { 188 .driver = { 189 .name = "mpfs-sys-controller", 190 .of_match_table = mpfs_sys_controller_of_match, 191 }, 192 .probe = mpfs_sys_controller_probe, 193 .remove = mpfs_sys_controller_remove, 194 }; 195 module_platform_driver(mpfs_sys_controller_driver); 196 197 MODULE_LICENSE("GPL v2"); 198 MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); 199 MODULE_DESCRIPTION("MPFS system controller driver"); 200