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 17 struct 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 26 static inline struct jh71x0_reset * 27 jh71x0_reset_from(struct reset_controller_dev *rcdev) 28 { 29 return container_of(rcdev, struct jh71x0_reset, rcdev); 30 } 31 32 static 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 64 static int jh71x0_reset_assert(struct reset_controller_dev *rcdev, 65 unsigned long id) 66 { 67 return jh71x0_reset_update(rcdev, id, true); 68 } 69 70 static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev, 71 unsigned long id) 72 { 73 return jh71x0_reset_update(rcdev, id, false); 74 } 75 76 static 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 88 static 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 103 static 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 110 int 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 } 134 EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register); 135