1From f9881d01669cd98e6f897214f407dce8a245bdfe Mon Sep 17 00:00:00 2001 2From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> 3Date: Mon, 19 Feb 2024 16:01:28 +0000 4Subject: [PATCH 1/6] remoteproc: Add Arm remoteproc driver 5 6introduce remoteproc support for Arm remote processors 7 8The supported remote processors are those that come with a reset 9control register and a reset status register. The driver allows to 10switch on or off the remote processor. 11 12The current use case is Corstone-1000 External System (Cortex-M3). 13 14The driver can be extended to support other remote processors 15controlled with a reset control and a reset status registers. 16 17The driver also supports control of multiple remote processors at the 18same time. 19 20Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> 21Upstream-Status: Denied [Agreement reached: https://lore.kernel.org/all/20241009094635.GA14639@e130802.arm.com/] 22--- 23 MAINTAINERS | 6 + 24 drivers/remoteproc/Kconfig | 18 ++ 25 drivers/remoteproc/Makefile | 1 + 26 drivers/remoteproc/arm_rproc.c | 395 +++++++++++++++++++++++++++++++++ 27 4 files changed, 420 insertions(+) 28 create mode 100644 drivers/remoteproc/arm_rproc.c 29 30diff --git a/MAINTAINERS b/MAINTAINERS 31index 8d1052fa6a69..54d6a40feea5 100644 32--- a/MAINTAINERS 33+++ b/MAINTAINERS 34@@ -1764,6 +1764,12 @@ S: Maintained 35 F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.yaml 36 F: drivers/irqchip/irq-vic.c 37 38+ARM REMOTEPROC DRIVER 39+M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> 40+L: linux-remoteproc@vger.kernel.org 41+S: Maintained 42+F: drivers/remoteproc/arm_rproc.c 43+ 44 ARM SMC WATCHDOG DRIVER 45 M: Julius Werner <jwerner@chromium.org> 46 R: Evan Benn <evanbenn@chromium.org> 47diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig 48index 48845dc8fa85..57fbac454a5d 100644 49--- a/drivers/remoteproc/Kconfig 50+++ b/drivers/remoteproc/Kconfig 51@@ -365,6 +365,24 @@ config XLNX_R5_REMOTEPROC 52 53 It's safe to say N if not interested in using RPU r5f cores. 54 55+config ARM_REMOTEPROC 56+ tristate "Arm remoteproc support" 57+ depends on HAS_IOMEM && ARM64 58+ default n 59+ help 60+ Say y here to support Arm remote processors via the remote 61+ processor framework. 62+ 63+ The supported processors are those that come with a reset control register 64+ and a reset status register. The design can be extended to support different 65+ processors meeting these requirements. 66+ The driver also supports control of multiple remote cores at the same time. 67+ 68+ Supported remote cores: 69+ Corstone-1000 External System (Cortex-M3) 70+ 71+ It's safe to say N here. 72+ 73 endif # REMOTEPROC 74 75 endmenu 76diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile 77index 91314a9b43ce..73126310835b 100644 78--- a/drivers/remoteproc/Makefile 79+++ b/drivers/remoteproc/Makefile 80@@ -39,3 +39,4 @@ obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o 81 obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o 82 obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o 83 obj-$(CONFIG_XLNX_R5_REMOTEPROC) += xlnx_r5_remoteproc.o 84+obj-$(CONFIG_ARM_REMOTEPROC) += arm_rproc.o 85diff --git a/drivers/remoteproc/arm_rproc.c b/drivers/remoteproc/arm_rproc.c 86new file mode 100644 87index 000000000000..6afa78ae7ad3 88--- /dev/null 89+++ b/drivers/remoteproc/arm_rproc.c 90@@ -0,0 +1,395 @@ 91+// SPDX-License-Identifier: GPL-2.0-only 92+/* 93+ * Copyright 2024 Arm Limited and/or its affiliates <open-source-office@arm.com> 94+ * 95+ * Authors: 96+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> 97+ */ 98+ 99+#include <linux/delay.h> 100+#include <linux/err.h> 101+#include <linux/firmware.h> 102+#include <linux/kernel.h> 103+#include <linux/module.h> 104+#include <linux/of.h> 105+#include <linux/platform_device.h> 106+#include <linux/remoteproc.h> 107+ 108+#include "remoteproc_internal.h" 109+ 110+/** 111+ * struct arm_rproc_reset_cfg - remote processor reset configuration 112+ * @ctrl_reg: address of the control register 113+ * @state_reg: address of the reset status register 114+ */ 115+struct arm_rproc_reset_cfg { 116+ void __iomem *ctrl_reg; 117+ void __iomem *state_reg; 118+}; 119+ 120+struct arm_rproc; 121+ 122+/** 123+ * struct arm_rproc_dcfg - Arm remote processor configuration 124+ * @stop: stop callback function 125+ * @start: start callback function 126+ */ 127+struct arm_rproc_dcfg { 128+ int (*stop)(struct rproc *rproc); 129+ int (*start)(struct rproc *rproc); 130+}; 131+ 132+/** 133+ * struct arm_rproc - Arm remote processor instance 134+ * @rproc: rproc handler 135+ * @core_dcfg: device configuration pointer 136+ * @reset_cfg: reset configuration registers 137+ */ 138+struct arm_rproc { 139+ struct rproc *rproc; 140+ const struct arm_rproc_dcfg *core_dcfg; 141+ struct arm_rproc_reset_cfg reset_cfg; 142+}; 143+ 144+/* Definitions for Arm Corstone-1000 External System */ 145+ 146+#define EXTSYS_RST_CTRL_CPUWAIT BIT(0) 147+#define EXTSYS_RST_CTRL_RST_REQ BIT(1) 148+ 149+#define EXTSYS_RST_ACK_MASK GENMASK(2, 1) 150+#define EXTSYS_RST_ST_RST_ACK(x) \ 151+ ((u8)(FIELD_GET(EXTSYS_RST_ACK_MASK, (x)))) 152+ 153+#define EXTSYS_RST_ACK_NO_RESET_REQ (0x0) 154+#define EXTSYS_RST_ACK_NOT_COMPLETE (0x1) 155+#define EXTSYS_RST_ACK_COMPLETE (0x2) 156+#define EXTSYS_RST_ACK_RESERVED (0x3) 157+ 158+#define EXTSYS_RST_ACK_POLL_TRIES (3) 159+#define EXTSYS_RST_ACK_POLL_TIMEOUT (1000) 160+ 161+/** 162+ * arm_rproc_start_cs1000_extsys() - custom start function 163+ * @rproc: pointer to the remote processor object 164+ * 165+ * Start function for Corstone-1000 External System. 166+ * Allow the External System core start execute instructions. 167+ * 168+ * Return: 169+ * 170+ * 0 on success. Otherwise, failure 171+ */ 172+static int arm_rproc_start_cs1000_extsys(struct rproc *rproc) 173+{ 174+ struct arm_rproc *priv = rproc->priv; 175+ u32 ctrl_reg; 176+ 177+ /* CPUWAIT signal of the External System is de-asserted */ 178+ ctrl_reg = readl(priv->reset_cfg.ctrl_reg); 179+ ctrl_reg &= ~EXTSYS_RST_CTRL_CPUWAIT; 180+ writel(ctrl_reg, priv->reset_cfg.ctrl_reg); 181+ 182+ return 0; 183+} 184+ 185+/** 186+ * arm_rproc_cs1000_extsys_poll_rst_ack() - poll RST_ACK bits 187+ * @rproc: pointer to the remote processor object 188+ * @exp_ack: expected bits value 189+ * @rst_ack: bits value read 190+ * 191+ * Tries to read RST_ACK bits until the timeout expires. 192+ * EXTSYS_RST_ACK_POLL_TRIES tries are made, 193+ * every EXTSYS_RST_ACK_POLL_TIMEOUT milliseconds. 194+ * 195+ * Return: 196+ * 197+ * 0 on success. Otherwise, failure 198+ */ 199+static int arm_rproc_cs1000_extsys_poll_rst_ack(struct rproc *rproc, 200+ u8 exp_ack, u8 *rst_ack) 201+{ 202+ struct arm_rproc *priv = rproc->priv; 203+ struct device *dev = rproc->dev.parent; 204+ u32 state_reg; 205+ int tries = EXTSYS_RST_ACK_POLL_TRIES; 206+ unsigned long timeout; 207+ 208+ do { 209+ state_reg = readl(priv->reset_cfg.state_reg); 210+ *rst_ack = EXTSYS_RST_ST_RST_ACK(state_reg); 211+ 212+ if (*rst_ack == EXTSYS_RST_ACK_RESERVED) { 213+ dev_err(dev, "unexpected RST_ACK value: 0x%x\n", 214+ *rst_ack); 215+ return -EINVAL; 216+ } 217+ 218+ /* expected ACK value read */ 219+ if ((*rst_ack & exp_ack) || (*rst_ack == exp_ack)) 220+ return 0; 221+ 222+ timeout = msleep_interruptible(EXTSYS_RST_ACK_POLL_TIMEOUT); 223+ 224+ if (timeout) { 225+ dev_err(dev, "polling RST_ACK aborted\n"); 226+ return -ECONNABORTED; 227+ } 228+ } while (--tries); 229+ 230+ dev_err(dev, "polling RST_ACK timed out\n"); 231+ 232+ return -ETIMEDOUT; 233+} 234+ 235+/** 236+ * arm_rproc_stop_cs1000_extsys() - custom stop function 237+ * @rproc: pointer to the remote processor object 238+ * 239+ * Reset all logic within the External System, the core will be in a halt state. 240+ * 241+ * Return: 242+ * 243+ * 0 on success. Otherwise, failure 244+ */ 245+static int arm_rproc_stop_cs1000_extsys(struct rproc *rproc) 246+{ 247+ struct arm_rproc *priv = rproc->priv; 248+ struct device *dev = rproc->dev.parent; 249+ u32 ctrl_reg; 250+ u8 rst_ack, req_status; 251+ int ret; 252+ 253+ ctrl_reg = readl(priv->reset_cfg.ctrl_reg); 254+ ctrl_reg |= EXTSYS_RST_CTRL_RST_REQ; 255+ writel(ctrl_reg, priv->reset_cfg.ctrl_reg); 256+ 257+ ret = arm_rproc_cs1000_extsys_poll_rst_ack(rproc, 258+ EXTSYS_RST_ACK_COMPLETE | 259+ EXTSYS_RST_ACK_NOT_COMPLETE, 260+ &rst_ack); 261+ if (ret) 262+ return ret; 263+ 264+ req_status = rst_ack; 265+ 266+ ctrl_reg = readl(priv->reset_cfg.ctrl_reg); 267+ ctrl_reg &= ~EXTSYS_RST_CTRL_RST_REQ; 268+ writel(ctrl_reg, priv->reset_cfg.ctrl_reg); 269+ 270+ ret = arm_rproc_cs1000_extsys_poll_rst_ack(rproc, 0, &rst_ack); 271+ if (ret) 272+ return ret; 273+ 274+ if (req_status == EXTSYS_RST_ACK_COMPLETE) { 275+ dev_dbg(dev, "the requested reset has been accepted\n"); 276+ return 0; 277+ } 278+ 279+ dev_err(dev, "the requested reset has been denied\n"); 280+ return -EACCES; 281+} 282+ 283+static const struct arm_rproc_dcfg arm_rproc_cfg_corstone1000_extsys = { 284+ .stop = arm_rproc_stop_cs1000_extsys, 285+ .start = arm_rproc_start_cs1000_extsys, 286+}; 287+ 288+/** 289+ * arm_rproc_stop() - Stop function for rproc_ops 290+ * @rproc: pointer to the remote processor object 291+ * 292+ * Calls the stop() callback of the remote core 293+ * 294+ * Return: 295+ * 296+ * 0 on success. Otherwise, failure 297+ */ 298+static int arm_rproc_stop(struct rproc *rproc) 299+{ 300+ struct arm_rproc *priv = rproc->priv; 301+ 302+ return priv->core_dcfg->stop(rproc); 303+} 304+ 305+/** 306+ * arm_rproc_start() - Start function for rproc_ops 307+ * @rproc: pointer to the remote processor object 308+ * 309+ * Calls the start() callback of the remote core 310+ * 311+ * Return: 312+ * 313+ * 0 on success. Otherwise, failure 314+ */ 315+static int arm_rproc_start(struct rproc *rproc) 316+{ 317+ struct arm_rproc *priv = rproc->priv; 318+ 319+ return priv->core_dcfg->start(rproc); 320+} 321+ 322+/** 323+ * arm_rproc_parse_fw() - Parse firmware function for rproc_ops 324+ * @rproc: pointer to the remote processor object 325+ * @fw: pointer to the firmware 326+ * 327+ * Does nothing currently. 328+ * 329+ * Return: 330+ * 331+ * 0 for success. 332+ */ 333+static int arm_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) 334+{ 335+ return 0; 336+} 337+ 338+/** 339+ * arm_rproc_load() - Load firmware to memory function for rproc_ops 340+ * @rproc: pointer to the remote processor object 341+ * @fw: pointer to the firmware 342+ * 343+ * Does nothing currently. 344+ * 345+ * Return: 346+ * 347+ * 0 for success. 348+ */ 349+static int arm_rproc_load(struct rproc *rproc, const struct firmware *fw) 350+{ 351+ return 0; 352+} 353+ 354+static const struct rproc_ops arm_rproc_ops = { 355+ .start = arm_rproc_start, 356+ .stop = arm_rproc_stop, 357+ .load = arm_rproc_load, 358+ .parse_fw = arm_rproc_parse_fw, 359+}; 360+ 361+/** 362+ * arm_rproc_probe() - the platform device probe 363+ * @pdev: the platform device 364+ * 365+ * Read from the device tree the properties needed to setup 366+ * the reset and comms for the remote processor. 367+ * Also, allocate a rproc device and register it with the remoteproc subsystem. 368+ * 369+ * Return: 370+ * 371+ * 0 on success. Otherwise, failure 372+ */ 373+static int arm_rproc_probe(struct platform_device *pdev) 374+{ 375+ const struct arm_rproc_dcfg *core_dcfg; 376+ struct device *dev = &pdev->dev; 377+ struct device_node *np = dev->of_node; 378+ struct arm_rproc *priv; 379+ struct rproc *rproc; 380+ const char *fw_name; 381+ int ret; 382+ struct resource *res; 383+ 384+ core_dcfg = of_device_get_match_data(dev); 385+ if (!core_dcfg) 386+ return -ENODEV; 387+ 388+ ret = rproc_of_parse_firmware(dev, 0, &fw_name); 389+ if (ret) { 390+ dev_err(dev, 391+ "can't parse firmware-name from device tree (%pe)\n", 392+ ERR_PTR(ret)); 393+ return ret; 394+ } 395+ 396+ dev_dbg(dev, "firmware-name: %s\n", fw_name); 397+ 398+ rproc = rproc_alloc(dev, np->name, &arm_rproc_ops, fw_name, 399+ sizeof(*priv)); 400+ if (!rproc) 401+ return -ENOMEM; 402+ 403+ priv = rproc->priv; 404+ priv->rproc = rproc; 405+ priv->core_dcfg = core_dcfg; 406+ 407+ res = platform_get_resource_byname(pdev, 408+ IORESOURCE_MEM, "reset-control"); 409+ priv->reset_cfg.ctrl_reg = devm_ioremap_resource(&pdev->dev, res); 410+ if (IS_ERR(priv->reset_cfg.ctrl_reg)) { 411+ ret = PTR_ERR(priv->reset_cfg.ctrl_reg); 412+ dev_err(dev, 413+ "can't map the reset-control register (%pe)\n", 414+ ERR_PTR((unsigned long)priv->reset_cfg.ctrl_reg)); 415+ goto err_free_rproc; 416+ } else { 417+ dev_dbg(dev, "reset-control: %p\n", priv->reset_cfg.ctrl_reg); 418+ } 419+ 420+ res = platform_get_resource_byname(pdev, 421+ IORESOURCE_MEM, "reset-status"); 422+ priv->reset_cfg.state_reg = devm_ioremap_resource(&pdev->dev, res); 423+ if (IS_ERR(priv->reset_cfg.state_reg)) { 424+ ret = PTR_ERR(priv->reset_cfg.state_reg); 425+ dev_err(dev, 426+ "can't map the reset-status register (%pe)\n", 427+ ERR_PTR((unsigned long)priv->reset_cfg.state_reg)); 428+ goto err_free_rproc; 429+ } else { 430+ dev_dbg(dev, "reset-status: %p\n", 431+ priv->reset_cfg.state_reg); 432+ } 433+ 434+ platform_set_drvdata(pdev, rproc); 435+ 436+ ret = rproc_add(rproc); 437+ if (ret) { 438+ dev_err(dev, "can't add remote processor (%pe)\n", 439+ ERR_PTR(ret)); 440+ goto err_free_rproc; 441+ } else { 442+ dev_dbg(dev, "remote processor added\n"); 443+ } 444+ 445+ return 0; 446+ 447+err_free_rproc: 448+ rproc_free(rproc); 449+ 450+ return ret; 451+} 452+ 453+/** 454+ * arm_rproc_remove() - the platform device remove 455+ * @pdev: the platform device 456+ * 457+ * Delete and free the resources used. 458+ */ 459+static void arm_rproc_remove(struct platform_device *pdev) 460+{ 461+ struct rproc *rproc = platform_get_drvdata(pdev); 462+ 463+ rproc_del(rproc); 464+ rproc_free(rproc); 465+} 466+ 467+static const struct of_device_id arm_rproc_of_match[] = { 468+ { .compatible = "arm,corstone1000-extsys", .data = &arm_rproc_cfg_corstone1000_extsys }, 469+ {}, 470+}; 471+MODULE_DEVICE_TABLE(of, arm_rproc_of_match); 472+ 473+static struct platform_driver arm_rproc_driver = { 474+ .probe = arm_rproc_probe, 475+ .remove_new = arm_rproc_remove, 476+ .driver = { 477+ .name = "arm-rproc", 478+ .of_match_table = arm_rproc_of_match, 479+ }, 480+}; 481+module_platform_driver(arm_rproc_driver); 482+ 483+MODULE_LICENSE("GPL"); 484+MODULE_DESCRIPTION("Arm Remote Processor Control Driver"); 485+MODULE_AUTHOR("Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>"); 486-- 4872.25.1 488 489