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 const int *lut; 16 void __iomem *reg_base; 17 int num_regs; 18 int num_per_reg; 19 u8 flags; 20 spinlock_t lock; 21 }; 22 23 static int rockchip_softrst_assert(struct reset_controller_dev *rcdev, 24 unsigned long id) 25 { 26 struct rockchip_softrst *softrst = container_of(rcdev, 27 struct rockchip_softrst, 28 rcdev); 29 int bank, offset; 30 31 if (softrst->lut) 32 id = softrst->lut[id]; 33 34 bank = id / softrst->num_per_reg; 35 offset = id % softrst->num_per_reg; 36 37 if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 38 writel(BIT(offset) | (BIT(offset) << 16), 39 softrst->reg_base + (bank * 4)); 40 } else { 41 unsigned long flags; 42 u32 reg; 43 44 spin_lock_irqsave(&softrst->lock, flags); 45 46 reg = readl(softrst->reg_base + (bank * 4)); 47 writel(reg | BIT(offset), softrst->reg_base + (bank * 4)); 48 49 spin_unlock_irqrestore(&softrst->lock, flags); 50 } 51 52 return 0; 53 } 54 55 static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev, 56 unsigned long id) 57 { 58 struct rockchip_softrst *softrst = container_of(rcdev, 59 struct rockchip_softrst, 60 rcdev); 61 int bank, offset; 62 63 if (softrst->lut) 64 id = softrst->lut[id]; 65 66 bank = id / softrst->num_per_reg; 67 offset = id % softrst->num_per_reg; 68 69 if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 70 writel((BIT(offset) << 16), softrst->reg_base + (bank * 4)); 71 } else { 72 unsigned long flags; 73 u32 reg; 74 75 spin_lock_irqsave(&softrst->lock, flags); 76 77 reg = readl(softrst->reg_base + (bank * 4)); 78 writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4)); 79 80 spin_unlock_irqrestore(&softrst->lock, flags); 81 } 82 83 return 0; 84 } 85 86 static const struct reset_control_ops rockchip_softrst_ops = { 87 .assert = rockchip_softrst_assert, 88 .deassert = rockchip_softrst_deassert, 89 }; 90 91 void rockchip_register_softrst_lut(struct device_node *np, 92 const int *lookup_table, 93 unsigned int num_regs, 94 void __iomem *base, u8 flags) 95 { 96 struct rockchip_softrst *softrst; 97 int ret; 98 99 softrst = kzalloc(sizeof(*softrst), GFP_KERNEL); 100 if (!softrst) 101 return; 102 103 spin_lock_init(&softrst->lock); 104 105 softrst->reg_base = base; 106 softrst->lut = lookup_table; 107 softrst->flags = flags; 108 softrst->num_regs = num_regs; 109 softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 110 : 32; 111 112 softrst->rcdev.owner = THIS_MODULE; 113 if (lookup_table) 114 softrst->rcdev.nr_resets = num_regs; 115 else 116 softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg; 117 softrst->rcdev.ops = &rockchip_softrst_ops; 118 softrst->rcdev.of_node = np; 119 ret = reset_controller_register(&softrst->rcdev); 120 if (ret) { 121 pr_err("%s: could not register reset controller, %d\n", 122 __func__, ret); 123 kfree(softrst); 124 } 125 }; 126 EXPORT_SYMBOL_GPL(rockchip_register_softrst_lut); 127