blob: 0d29c2061a85a22a10a0fa5ca0a77850a3a252f1 [file] [log] [blame]
/*
* SPDX-FileCopyrightText: Copyright 2021, 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
* 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 <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#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;
}
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;
}
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 = 0 },
{ /* 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);