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/io-64-nonatomic-lo-hi.h> 12 #include <linux/iopoll.h> 13 #include <linux/reset-controller.h> 14 #include <linux/spinlock.h> 15 16 #include "reset-starfive-jh71x0.h" 17 18 struct jh71x0_reset { 19 struct reset_controller_dev rcdev; 20 /* protect registers against concurrent read-modify-write */ 21 spinlock_t lock; 22 void __iomem *assert; 23 void __iomem *status; 24 const u64 *asserted; 25 }; 26 27 static inline struct jh71x0_reset * 28 jh71x0_reset_from(struct reset_controller_dev *rcdev) 29 { 30 return container_of(rcdev, struct jh71x0_reset, rcdev); 31 } 32 33 static int jh71x0_reset_update(struct reset_controller_dev *rcdev, 34 unsigned long id, bool assert) 35 { 36 struct jh71x0_reset *data = jh71x0_reset_from(rcdev); 37 unsigned long offset = BIT_ULL_WORD(id); 38 u64 mask = BIT_ULL_MASK(id); 39 void __iomem *reg_assert = data->assert + offset * sizeof(u64); 40 void __iomem *reg_status = data->status + offset * sizeof(u64); 41 u64 done = data->asserted ? data->asserted[offset] & mask : 0; 42 u64 value; 43 unsigned long flags; 44 int ret; 45 46 if (!assert) 47 done ^= mask; 48 49 spin_lock_irqsave(&data->lock, flags); 50 51 value = readq(reg_assert); 52 if (assert) 53 value |= mask; 54 else 55 value &= ~mask; 56 writeq(value, reg_assert); 57 58 /* if the associated clock is gated, deasserting might otherwise hang forever */ 59 ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); 60 61 spin_unlock_irqrestore(&data->lock, flags); 62 return ret; 63 } 64 65 static int jh71x0_reset_assert(struct reset_controller_dev *rcdev, 66 unsigned long id) 67 { 68 return jh71x0_reset_update(rcdev, id, true); 69 } 70 71 static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev, 72 unsigned long id) 73 { 74 return jh71x0_reset_update(rcdev, id, false); 75 } 76 77 static int jh71x0_reset_reset(struct reset_controller_dev *rcdev, 78 unsigned long id) 79 { 80 int ret; 81 82 ret = jh71x0_reset_assert(rcdev, id); 83 if (ret) 84 return ret; 85 86 return jh71x0_reset_deassert(rcdev, id); 87 } 88 89 static int jh71x0_reset_status(struct reset_controller_dev *rcdev, 90 unsigned long id) 91 { 92 struct jh71x0_reset *data = jh71x0_reset_from(rcdev); 93 unsigned long offset = BIT_ULL_WORD(id); 94 u64 mask = BIT_ULL_MASK(id); 95 void __iomem *reg_status = data->status + offset * sizeof(u64); 96 u64 value = readq(reg_status); 97 98 return !((value ^ data->asserted[offset]) & mask); 99 } 100 101 static const struct reset_control_ops jh71x0_reset_ops = { 102 .assert = jh71x0_reset_assert, 103 .deassert = jh71x0_reset_deassert, 104 .reset = jh71x0_reset_reset, 105 .status = jh71x0_reset_status, 106 }; 107 108 int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, 109 void __iomem *assert, void __iomem *status, 110 const u64 *asserted, unsigned int nr_resets, 111 struct module *owner) 112 { 113 struct jh71x0_reset *data; 114 115 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 116 if (!data) 117 return -ENOMEM; 118 119 data->rcdev.ops = &jh71x0_reset_ops; 120 data->rcdev.owner = owner; 121 data->rcdev.nr_resets = nr_resets; 122 data->rcdev.dev = dev; 123 data->rcdev.of_node = of_node; 124 125 spin_lock_init(&data->lock); 126 data->assert = assert; 127 data->status = status; 128 data->asserted = asserted; 129 130 return devm_reset_controller_register(dev, &data->rcdev); 131 } 132 EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register); 133