Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: add microchip polarfire soc system controller

This driver provides an interface for other drivers to access the
functions of the system controller on the Microchip PolarFire SoC.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Link: https://lore.kernel.org/r/20220217101349.2374873-2-conor.dooley@microchip.com

authored by

Conor Dooley and committed by
Nicolas Ferre
d0054a47 f8e0f301

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