/* * SPDX-FileCopyrightText: Copyright 2021, 2023 Arm Limited and/or its affiliates * SPDX-License-Identifier: GPL-2.0-only * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software * Foundation, and any use by you of this program is subject to the terms * of such GNU licence. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you can access it online at * http://www.gnu.org/licenses/gpl-2.0.html. */ #include #include #include #include #include #include #include #define JUNO_FPGA_RESET_DRIVER_VERSION "0.1.0" struct juno_fpga_reset { struct reset_controller_dev rst; struct device *dev; void __iomem *base; }; /* Supported controller IDs */ #define JUNO_FPGA_RESET_MIN_SUPPORTED_ID 0x2010f #define JUNO_FPGA_RESET_MAX_SUPPORTED_ID 0x20113 #define JUNO_FPGA_RESET_ID(base) (base) #define JUNO_FPGA_RESET_SOFT_RESET(base) ((base) + 0x140) #define JUNO_FPGA_RESET_CPU_WAIT(base) ((base) + 0x144) #define JUNO_FPGA_RESET_SET_RESET (0x1) #define JUNO_FPGA_RESET_UNSET_RESET (0x0) #define JUNO_FPGA_RESET_SET_CPUWAIT (0x1) #define JUNO_FPGA_RESET_UNSET_CPUWAIT (0x0) static void __iomem *verify_and_remap(struct device *dev, struct resource *res) { void __iomem *base = devm_ioremap_resource(dev, res); u32 id; if (IS_ERR(base)) return base; id = readl(JUNO_FPGA_RESET_ID(base)); if (id < JUNO_FPGA_RESET_MIN_SUPPORTED_ID || id > JUNO_FPGA_RESET_MAX_SUPPORTED_ID) { dev_err(dev, "Unknown controller ID: %u", id); return IOMEM_ERR_PTR(-EINVAL); } return base; } static int juno_fpga_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { struct juno_fpga_reset *reset = container_of(rcdev, struct juno_fpga_reset, rst); /* pull reset */ dev_dbg(reset->dev, "Asserting reset"); /* set wait and reset */ writel(JUNO_FPGA_RESET_SET_RESET, JUNO_FPGA_RESET_SOFT_RESET(reset->base)); writel(JUNO_FPGA_RESET_SET_CPUWAIT, JUNO_FPGA_RESET_CPU_WAIT(reset->base)); writel(JUNO_FPGA_RESET_UNSET_RESET, JUNO_FPGA_RESET_SOFT_RESET(reset->base)); return 0; } static int juno_fpga_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { struct juno_fpga_reset *reset = container_of(rcdev, struct juno_fpga_reset, rst); /* release wait */ dev_dbg(reset->dev, "Deasserting reset"); writel(JUNO_FPGA_RESET_UNSET_CPUWAIT, JUNO_FPGA_RESET_CPU_WAIT(reset->base)); return 0; } static struct reset_control_ops juno_fpga_reset_ops = { .assert = juno_fpga_reset_assert, .deassert = juno_fpga_reset_deassert, }; static const struct of_device_id juno_fpga_reset_match[] = { { .compatible = "arm,mali_fpga_sysctl", .data = NULL }, { /* sentinel */ }, }; static int juno_fpga_reset_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct juno_fpga_reset *reset; struct resource *res; reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); if (!reset) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reset->base = verify_and_remap(dev, res); reset->dev = dev; if (IS_ERR(reset->base)) { dev_err(dev, "Failed to verify and remap base address (%ld)", PTR_ERR(reset->base)); return PTR_ERR(reset->base); } platform_set_drvdata(pdev, reset); reset->rst.owner = THIS_MODULE; reset->rst.nr_resets = 1; reset->rst.ops = &juno_fpga_reset_ops; reset->rst.of_node = pdev->dev.of_node; dev_info(dev, "registering to reset controller core"); return devm_reset_controller_register(dev, &reset->rst); } static int juno_fpga_reset_remove(struct platform_device *pdev) { return 0; } static struct platform_driver juno_fpga_reset_driver = { .probe = juno_fpga_reset_probe, .remove = juno_fpga_reset_remove, .driver = { .name = "juno-fpga-reset", .of_match_table = of_match_ptr(juno_fpga_reset_match), }, }; module_platform_driver(juno_fpga_reset_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Arm Ltd"); MODULE_DESCRIPTION("Arm Juno FPGA Reset Driver"); MODULE_VERSION(JUNO_FPGA_RESET_DRIVER_VERSION);