1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2014 MundoReader S.L. 4 * Author: Heiko Stuebner <heiko@sntech.de> 5 */ 6 7 #include <linux/slab.h> 8 #include <linux/io.h> 9 #include <linux/reset-controller.h> 10 #include <linux/spinlock.h> 11 #include "clk.h" 12 13 struct rockchip_softrst { 14 struct reset_controller_dev rcdev; 15 void __iomem *reg_base; 16 int num_regs; 17 int num_per_reg; 18 u8 flags; 19 spinlock_t lock; 20 }; 21 22 static int rockchip_softrst_assert(struct reset_controller_dev *rcdev, 23 unsigned long id) 24 { 25 struct rockchip_softrst *softrst = container_of(rcdev, 26 struct rockchip_softrst, 27 rcdev); 28 int bank = id / softrst->num_per_reg; 29 int offset = id % softrst->num_per_reg; 30 31 if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 32 writel(BIT(offset) | (BIT(offset) << 16), 33 softrst->reg_base + (bank * 4)); 34 } else { 35 unsigned long flags; 36 u32 reg; 37 38 spin_lock_irqsave(&softrst->lock, flags); 39 40 reg = readl(softrst->reg_base + (bank * 4)); 41 writel(reg | BIT(offset), softrst->reg_base + (bank * 4)); 42 43 spin_unlock_irqrestore(&softrst->lock, flags); 44 } 45 46 return 0; 47 } 48 49 static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev, 50 unsigned long id) 51 { 52 struct rockchip_softrst *softrst = container_of(rcdev, 53 struct rockchip_softrst, 54 rcdev); 55 int bank = id / softrst->num_per_reg; 56 int offset = id % softrst->num_per_reg; 57 58 if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 59 writel((BIT(offset) << 16), softrst->reg_base + (bank * 4)); 60 } else { 61 unsigned long flags; 62 u32 reg; 63 64 spin_lock_irqsave(&softrst->lock, flags); 65 66 reg = readl(softrst->reg_base + (bank * 4)); 67 writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4)); 68 69 spin_unlock_irqrestore(&softrst->lock, flags); 70 } 71 72 return 0; 73 } 74 75 static const struct reset_control_ops rockchip_softrst_ops = { 76 .assert = rockchip_softrst_assert, 77 .deassert = rockchip_softrst_deassert, 78 }; 79 80 void rockchip_register_softrst(struct device_node *np, 81 unsigned int num_regs, 82 void __iomem *base, u8 flags) 83 { 84 struct rockchip_softrst *softrst; 85 int ret; 86 87 softrst = kzalloc(sizeof(*softrst), GFP_KERNEL); 88 if (!softrst) 89 return; 90 91 spin_lock_init(&softrst->lock); 92 93 softrst->reg_base = base; 94 softrst->flags = flags; 95 softrst->num_regs = num_regs; 96 softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 97 : 32; 98 99 softrst->rcdev.owner = THIS_MODULE; 100 softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg; 101 softrst->rcdev.ops = &rockchip_softrst_ops; 102 softrst->rcdev.of_node = np; 103 ret = reset_controller_register(&softrst->rcdev); 104 if (ret) { 105 pr_err("%s: could not register reset controller, %d\n", 106 __func__, ret); 107 kfree(softrst); 108 } 109 }; 110 EXPORT_SYMBOL_GPL(rockchip_register_softrst); 111