File Index
Files and directories
Sign in
FILE

reset-starfive-jh71x0.c

File preview with syntax highlighting.

linux-6.19.14/drivers/reset/starfive/reset-starfive-jh71x0.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Reset driver for the StarFive JH71X0 SoCs
  4 *
  5 * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
  6 */
  7
  8#include <linux/bitmap.h>
  9#include <linux/device.h>
 10#include <linux/io.h>
 11#include <linux/iopoll.h>
 12#include <linux/reset-controller.h>
 13#include <linux/spinlock.h>
 14
 15#include "reset-starfive-jh71x0.h"
 16
 17struct jh71x0_reset {
 18	struct reset_controller_dev rcdev;
 19	/* protect registers against concurrent read-modify-write */
 20	spinlock_t lock;
 21	void __iomem *assert;
 22	void __iomem *status;
 23	const u32 *asserted;
 24};
 25
 26static inline struct jh71x0_reset *
 27jh71x0_reset_from(struct reset_controller_dev *rcdev)
 28{
 29	return container_of(rcdev, struct jh71x0_reset, rcdev);
 30}
 31
 32static int jh71x0_reset_update(struct reset_controller_dev *rcdev,
 33			       unsigned long id, bool assert)
 34{
 35	struct jh71x0_reset *data = jh71x0_reset_from(rcdev);
 36	unsigned long offset = id / 32;
 37	u32 mask = BIT(id % 32);
 38	void __iomem *reg_assert = data->assert + offset * sizeof(u32);
 39	void __iomem *reg_status = data->status + offset * sizeof(u32);
 40	u32 done = data->asserted ? data->asserted[offset] & mask : 0;
 41	u32 value;
 42	unsigned long flags;
 43	int ret;
 44
 45	if (!assert)
 46		done ^= mask;
 47
 48	spin_lock_irqsave(&data->lock, flags);
 49
 50	value = readl(reg_assert);
 51	if (assert)
 52		value |= mask;
 53	else
 54		value &= ~mask;
 55	writel(value, reg_assert);
 56
 57	/* if the associated clock is gated, deasserting might otherwise hang forever */
 58	ret = readl_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000);
 59
 60	spin_unlock_irqrestore(&data->lock, flags);
 61	return ret;
 62}
 63
 64static int jh71x0_reset_assert(struct reset_controller_dev *rcdev,
 65			       unsigned long id)
 66{
 67	return jh71x0_reset_update(rcdev, id, true);
 68}
 69
 70static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev,
 71				 unsigned long id)
 72{
 73	return jh71x0_reset_update(rcdev, id, false);
 74}
 75
 76static int jh71x0_reset_reset(struct reset_controller_dev *rcdev,
 77			      unsigned long id)
 78{
 79	int ret;
 80
 81	ret = jh71x0_reset_assert(rcdev, id);
 82	if (ret)
 83		return ret;
 84
 85	return jh71x0_reset_deassert(rcdev, id);
 86}
 87
 88static int jh71x0_reset_status(struct reset_controller_dev *rcdev,
 89			       unsigned long id)
 90{
 91	struct jh71x0_reset *data = jh71x0_reset_from(rcdev);
 92	unsigned long offset = id / 32;
 93	u32 mask = BIT(id % 32);
 94	void __iomem *reg_status = data->status + offset * sizeof(u32);
 95	u32 value = readl(reg_status);
 96
 97	if (!data->asserted)
 98		return !(value & mask);
 99
100	return !((value ^ data->asserted[offset]) & mask);
101}
102
103static const struct reset_control_ops jh71x0_reset_ops = {
104	.assert		= jh71x0_reset_assert,
105	.deassert	= jh71x0_reset_deassert,
106	.reset		= jh71x0_reset_reset,
107	.status		= jh71x0_reset_status,
108};
109
110int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node,
111				   void __iomem *assert, void __iomem *status,
112				   const u32 *asserted, unsigned int nr_resets,
113				   struct module *owner)
114{
115	struct jh71x0_reset *data;
116
117	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
118	if (!data)
119		return -ENOMEM;
120
121	data->rcdev.ops = &jh71x0_reset_ops;
122	data->rcdev.owner = owner;
123	data->rcdev.nr_resets = nr_resets;
124	data->rcdev.dev = dev;
125	data->rcdev.of_node = of_node;
126
127	spin_lock_init(&data->lock);
128	data->assert = assert;
129	data->status = status;
130	data->asserted = asserted;
131
132	return devm_reset_controller_register(dev, &data->rcdev);
133}
134EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register);
~/ Read-only file preview.