xref: /openbmc/linux/drivers/reset/reset-mpfs.c (revision bad8a8af)
105f9e363SConor Dooley // SPDX-License-Identifier: GPL-2.0-only
205f9e363SConor Dooley /*
305f9e363SConor Dooley  * PolarFire SoC (MPFS) Peripheral Clock Reset Controller
405f9e363SConor Dooley  *
505f9e363SConor Dooley  * Author: Conor Dooley <conor.dooley@microchip.com>
605f9e363SConor Dooley  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
705f9e363SConor Dooley  *
805f9e363SConor Dooley  */
905f9e363SConor Dooley #include <linux/auxiliary_bus.h>
1005f9e363SConor Dooley #include <linux/delay.h>
1105f9e363SConor Dooley #include <linux/module.h>
12*bad8a8afSRob Herring #include <linux/of.h>
1305f9e363SConor Dooley #include <linux/platform_device.h>
1405f9e363SConor Dooley #include <linux/reset-controller.h>
1505f9e363SConor Dooley #include <dt-bindings/clock/microchip,mpfs-clock.h>
1605f9e363SConor Dooley #include <soc/microchip/mpfs.h>
1705f9e363SConor Dooley 
1805f9e363SConor Dooley /*
1905f9e363SConor Dooley  * The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
2005f9e363SConor Dooley  * defines in the dt to make things easier to configure - so this is accounting
2105f9e363SConor Dooley  * for the offset of 3 there.
2205f9e363SConor Dooley  */
2305f9e363SConor Dooley #define MPFS_PERIPH_OFFSET	CLK_ENVM
2405f9e363SConor Dooley #define MPFS_NUM_RESETS		30u
2505f9e363SConor Dooley #define MPFS_SLEEP_MIN_US	100
2605f9e363SConor Dooley #define MPFS_SLEEP_MAX_US	200
2705f9e363SConor Dooley 
2805f9e363SConor Dooley /* block concurrent access to the soft reset register */
2905f9e363SConor Dooley static DEFINE_SPINLOCK(mpfs_reset_lock);
3005f9e363SConor Dooley 
3105f9e363SConor Dooley /*
3205f9e363SConor Dooley  * Peripheral clock resets
3305f9e363SConor Dooley  */
3405f9e363SConor Dooley 
mpfs_assert(struct reset_controller_dev * rcdev,unsigned long id)3505f9e363SConor Dooley static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
3605f9e363SConor Dooley {
3705f9e363SConor Dooley 	unsigned long flags;
3805f9e363SConor Dooley 	u32 reg;
3905f9e363SConor Dooley 
4005f9e363SConor Dooley 	spin_lock_irqsave(&mpfs_reset_lock, flags);
4105f9e363SConor Dooley 
4205f9e363SConor Dooley 	reg = mpfs_reset_read(rcdev->dev);
4305f9e363SConor Dooley 	reg |= BIT(id);
4405f9e363SConor Dooley 	mpfs_reset_write(rcdev->dev, reg);
4505f9e363SConor Dooley 
4605f9e363SConor Dooley 	spin_unlock_irqrestore(&mpfs_reset_lock, flags);
4705f9e363SConor Dooley 
4805f9e363SConor Dooley 	return 0;
4905f9e363SConor Dooley }
5005f9e363SConor Dooley 
mpfs_deassert(struct reset_controller_dev * rcdev,unsigned long id)5105f9e363SConor Dooley static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
5205f9e363SConor Dooley {
5305f9e363SConor Dooley 	unsigned long flags;
5405f9e363SConor Dooley 	u32 reg;
5505f9e363SConor Dooley 
5605f9e363SConor Dooley 	spin_lock_irqsave(&mpfs_reset_lock, flags);
5705f9e363SConor Dooley 
5805f9e363SConor Dooley 	reg = mpfs_reset_read(rcdev->dev);
5905f9e363SConor Dooley 	reg &= ~BIT(id);
6005f9e363SConor Dooley 	mpfs_reset_write(rcdev->dev, reg);
6105f9e363SConor Dooley 
6205f9e363SConor Dooley 	spin_unlock_irqrestore(&mpfs_reset_lock, flags);
6305f9e363SConor Dooley 
6405f9e363SConor Dooley 	return 0;
6505f9e363SConor Dooley }
6605f9e363SConor Dooley 
mpfs_status(struct reset_controller_dev * rcdev,unsigned long id)6705f9e363SConor Dooley static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
6805f9e363SConor Dooley {
6905f9e363SConor Dooley 	u32 reg = mpfs_reset_read(rcdev->dev);
7005f9e363SConor Dooley 
7105f9e363SConor Dooley 	/*
7205f9e363SConor Dooley 	 * It is safe to return here as MPFS_NUM_RESETS makes sure the sign bit
7305f9e363SConor Dooley 	 * is never hit.
7405f9e363SConor Dooley 	 */
7505f9e363SConor Dooley 	return (reg & BIT(id));
7605f9e363SConor Dooley }
7705f9e363SConor Dooley 
mpfs_reset(struct reset_controller_dev * rcdev,unsigned long id)7805f9e363SConor Dooley static int mpfs_reset(struct reset_controller_dev *rcdev, unsigned long id)
7905f9e363SConor Dooley {
8005f9e363SConor Dooley 	mpfs_assert(rcdev, id);
8105f9e363SConor Dooley 
8205f9e363SConor Dooley 	usleep_range(MPFS_SLEEP_MIN_US, MPFS_SLEEP_MAX_US);
8305f9e363SConor Dooley 
8405f9e363SConor Dooley 	mpfs_deassert(rcdev, id);
8505f9e363SConor Dooley 
8605f9e363SConor Dooley 	return 0;
8705f9e363SConor Dooley }
8805f9e363SConor Dooley 
8905f9e363SConor Dooley static const struct reset_control_ops mpfs_reset_ops = {
9005f9e363SConor Dooley 	.reset = mpfs_reset,
9105f9e363SConor Dooley 	.assert = mpfs_assert,
9205f9e363SConor Dooley 	.deassert = mpfs_deassert,
9305f9e363SConor Dooley 	.status = mpfs_status,
9405f9e363SConor Dooley };
9505f9e363SConor Dooley 
mpfs_reset_xlate(struct reset_controller_dev * rcdev,const struct of_phandle_args * reset_spec)9605f9e363SConor Dooley static int mpfs_reset_xlate(struct reset_controller_dev *rcdev,
9705f9e363SConor Dooley 			    const struct of_phandle_args *reset_spec)
9805f9e363SConor Dooley {
9905f9e363SConor Dooley 	unsigned int index = reset_spec->args[0];
10005f9e363SConor Dooley 
10105f9e363SConor Dooley 	/*
10205f9e363SConor Dooley 	 * CLK_RESERVED does not map to a clock, but it does map to a reset,
10305f9e363SConor Dooley 	 * so it has to be accounted for here. It is the reset for the fabric,
10405f9e363SConor Dooley 	 * so if this reset gets called - do not reset it.
10505f9e363SConor Dooley 	 */
10605f9e363SConor Dooley 	if (index == CLK_RESERVED) {
10705f9e363SConor Dooley 		dev_err(rcdev->dev, "Resetting the fabric is not supported\n");
10805f9e363SConor Dooley 		return -EINVAL;
10905f9e363SConor Dooley 	}
11005f9e363SConor Dooley 
11105f9e363SConor Dooley 	if (index < MPFS_PERIPH_OFFSET || index >= (MPFS_PERIPH_OFFSET + rcdev->nr_resets)) {
11205f9e363SConor Dooley 		dev_err(rcdev->dev, "Invalid reset index %u\n", index);
11305f9e363SConor Dooley 		return -EINVAL;
11405f9e363SConor Dooley 	}
11505f9e363SConor Dooley 
11605f9e363SConor Dooley 	return index - MPFS_PERIPH_OFFSET;
11705f9e363SConor Dooley }
11805f9e363SConor Dooley 
mpfs_reset_probe(struct auxiliary_device * adev,const struct auxiliary_device_id * id)11905f9e363SConor Dooley static int mpfs_reset_probe(struct auxiliary_device *adev,
12005f9e363SConor Dooley 			    const struct auxiliary_device_id *id)
12105f9e363SConor Dooley {
12205f9e363SConor Dooley 	struct device *dev = &adev->dev;
12305f9e363SConor Dooley 	struct reset_controller_dev *rcdev;
12405f9e363SConor Dooley 
12505f9e363SConor Dooley 	rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
12605f9e363SConor Dooley 	if (!rcdev)
12705f9e363SConor Dooley 		return -ENOMEM;
12805f9e363SConor Dooley 
12905f9e363SConor Dooley 	rcdev->dev = dev;
13005f9e363SConor Dooley 	rcdev->dev->parent = dev->parent;
13105f9e363SConor Dooley 	rcdev->ops = &mpfs_reset_ops;
13205f9e363SConor Dooley 	rcdev->of_node = dev->parent->of_node;
13305f9e363SConor Dooley 	rcdev->of_reset_n_cells = 1;
13405f9e363SConor Dooley 	rcdev->of_xlate = mpfs_reset_xlate;
13505f9e363SConor Dooley 	rcdev->nr_resets = MPFS_NUM_RESETS;
13605f9e363SConor Dooley 
13705f9e363SConor Dooley 	return devm_reset_controller_register(dev, rcdev);
13805f9e363SConor Dooley }
13905f9e363SConor Dooley 
14005f9e363SConor Dooley static const struct auxiliary_device_id mpfs_reset_ids[] = {
14105f9e363SConor Dooley 	{
14205f9e363SConor Dooley 		.name = "clk_mpfs.reset-mpfs",
14305f9e363SConor Dooley 	},
14405f9e363SConor Dooley 	{ }
14505f9e363SConor Dooley };
14605f9e363SConor Dooley MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids);
14705f9e363SConor Dooley 
14805f9e363SConor Dooley static struct auxiliary_driver mpfs_reset_driver = {
14905f9e363SConor Dooley 	.probe		= mpfs_reset_probe,
15005f9e363SConor Dooley 	.id_table	= mpfs_reset_ids,
15105f9e363SConor Dooley };
15205f9e363SConor Dooley 
15305f9e363SConor Dooley module_auxiliary_driver(mpfs_reset_driver);
15405f9e363SConor Dooley 
15505f9e363SConor Dooley MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
15605f9e363SConor Dooley MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
15705f9e363SConor Dooley MODULE_IMPORT_NS(MCHP_CLK_MPFS);
158