xref: /openbmc/linux/drivers/clk/rockchip/softrst.c (revision ada8f95b)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
285fa0c7fSHeiko Stübner /*
385fa0c7fSHeiko Stübner  * Copyright (c) 2014 MundoReader S.L.
485fa0c7fSHeiko Stübner  * Author: Heiko Stuebner <heiko@sntech.de>
585fa0c7fSHeiko Stübner  */
685fa0c7fSHeiko Stübner 
785fa0c7fSHeiko Stübner #include <linux/slab.h>
885fa0c7fSHeiko Stübner #include <linux/io.h>
985fa0c7fSHeiko Stübner #include <linux/reset-controller.h>
1085fa0c7fSHeiko Stübner #include <linux/spinlock.h>
1185fa0c7fSHeiko Stübner #include "clk.h"
1285fa0c7fSHeiko Stübner 
1385fa0c7fSHeiko Stübner struct rockchip_softrst {
1485fa0c7fSHeiko Stübner 	struct reset_controller_dev	rcdev;
15*ada8f95bSSebastian Reichel 	const int			*lut;
1685fa0c7fSHeiko Stübner 	void __iomem			*reg_base;
1785fa0c7fSHeiko Stübner 	int				num_regs;
1885fa0c7fSHeiko Stübner 	int				num_per_reg;
1985fa0c7fSHeiko Stübner 	u8				flags;
2085fa0c7fSHeiko Stübner 	spinlock_t			lock;
2185fa0c7fSHeiko Stübner };
2285fa0c7fSHeiko Stübner 
rockchip_softrst_assert(struct reset_controller_dev * rcdev,unsigned long id)2385fa0c7fSHeiko Stübner static int rockchip_softrst_assert(struct reset_controller_dev *rcdev,
2485fa0c7fSHeiko Stübner 			      unsigned long id)
2585fa0c7fSHeiko Stübner {
2685fa0c7fSHeiko Stübner 	struct rockchip_softrst *softrst = container_of(rcdev,
2785fa0c7fSHeiko Stübner 						     struct rockchip_softrst,
2885fa0c7fSHeiko Stübner 						     rcdev);
29*ada8f95bSSebastian Reichel 	int bank, offset;
30*ada8f95bSSebastian Reichel 
31*ada8f95bSSebastian Reichel 	if (softrst->lut)
32*ada8f95bSSebastian Reichel 		id = softrst->lut[id];
33*ada8f95bSSebastian Reichel 
34*ada8f95bSSebastian Reichel 	bank = id / softrst->num_per_reg;
35*ada8f95bSSebastian Reichel 	offset = id % softrst->num_per_reg;
3685fa0c7fSHeiko Stübner 
3785fa0c7fSHeiko Stübner 	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
3885fa0c7fSHeiko Stübner 		writel(BIT(offset) | (BIT(offset) << 16),
3985fa0c7fSHeiko Stübner 		       softrst->reg_base + (bank * 4));
4085fa0c7fSHeiko Stübner 	} else {
4185fa0c7fSHeiko Stübner 		unsigned long flags;
4285fa0c7fSHeiko Stübner 		u32 reg;
4385fa0c7fSHeiko Stübner 
4485fa0c7fSHeiko Stübner 		spin_lock_irqsave(&softrst->lock, flags);
4585fa0c7fSHeiko Stübner 
4685fa0c7fSHeiko Stübner 		reg = readl(softrst->reg_base + (bank * 4));
4785fa0c7fSHeiko Stübner 		writel(reg | BIT(offset), softrst->reg_base + (bank * 4));
4885fa0c7fSHeiko Stübner 
4985fa0c7fSHeiko Stübner 		spin_unlock_irqrestore(&softrst->lock, flags);
5085fa0c7fSHeiko Stübner 	}
5185fa0c7fSHeiko Stübner 
5285fa0c7fSHeiko Stübner 	return 0;
5385fa0c7fSHeiko Stübner }
5485fa0c7fSHeiko Stübner 
rockchip_softrst_deassert(struct reset_controller_dev * rcdev,unsigned long id)5585fa0c7fSHeiko Stübner static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
5685fa0c7fSHeiko Stübner 				unsigned long id)
5785fa0c7fSHeiko Stübner {
5885fa0c7fSHeiko Stübner 	struct rockchip_softrst *softrst = container_of(rcdev,
5985fa0c7fSHeiko Stübner 						     struct rockchip_softrst,
6085fa0c7fSHeiko Stübner 						     rcdev);
61*ada8f95bSSebastian Reichel 	int bank, offset;
62*ada8f95bSSebastian Reichel 
63*ada8f95bSSebastian Reichel 	if (softrst->lut)
64*ada8f95bSSebastian Reichel 		id = softrst->lut[id];
65*ada8f95bSSebastian Reichel 
66*ada8f95bSSebastian Reichel 	bank = id / softrst->num_per_reg;
67*ada8f95bSSebastian Reichel 	offset = id % softrst->num_per_reg;
6885fa0c7fSHeiko Stübner 
6985fa0c7fSHeiko Stübner 	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
7085fa0c7fSHeiko Stübner 		writel((BIT(offset) << 16), softrst->reg_base + (bank * 4));
7185fa0c7fSHeiko Stübner 	} else {
7285fa0c7fSHeiko Stübner 		unsigned long flags;
7385fa0c7fSHeiko Stübner 		u32 reg;
7485fa0c7fSHeiko Stübner 
7585fa0c7fSHeiko Stübner 		spin_lock_irqsave(&softrst->lock, flags);
7685fa0c7fSHeiko Stübner 
7785fa0c7fSHeiko Stübner 		reg = readl(softrst->reg_base + (bank * 4));
7885fa0c7fSHeiko Stübner 		writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4));
7985fa0c7fSHeiko Stübner 
8085fa0c7fSHeiko Stübner 		spin_unlock_irqrestore(&softrst->lock, flags);
8185fa0c7fSHeiko Stübner 	}
8285fa0c7fSHeiko Stübner 
8385fa0c7fSHeiko Stübner 	return 0;
8485fa0c7fSHeiko Stübner }
8585fa0c7fSHeiko Stübner 
863fb950feSPhilipp Zabel static const struct reset_control_ops rockchip_softrst_ops = {
8785fa0c7fSHeiko Stübner 	.assert		= rockchip_softrst_assert,
8885fa0c7fSHeiko Stübner 	.deassert	= rockchip_softrst_deassert,
8985fa0c7fSHeiko Stübner };
9085fa0c7fSHeiko Stübner 
rockchip_register_softrst_lut(struct device_node * np,const int * lookup_table,unsigned int num_regs,void __iomem * base,u8 flags)91*ada8f95bSSebastian Reichel void rockchip_register_softrst_lut(struct device_node *np,
92*ada8f95bSSebastian Reichel 				   const int *lookup_table,
9385fa0c7fSHeiko Stübner 				   unsigned int num_regs,
9485fa0c7fSHeiko Stübner 				   void __iomem *base, u8 flags)
9585fa0c7fSHeiko Stübner {
9685fa0c7fSHeiko Stübner 	struct rockchip_softrst *softrst;
9785fa0c7fSHeiko Stübner 	int ret;
9885fa0c7fSHeiko Stübner 
9985fa0c7fSHeiko Stübner 	softrst = kzalloc(sizeof(*softrst), GFP_KERNEL);
10085fa0c7fSHeiko Stübner 	if (!softrst)
10185fa0c7fSHeiko Stübner 		return;
10285fa0c7fSHeiko Stübner 
10385fa0c7fSHeiko Stübner 	spin_lock_init(&softrst->lock);
10485fa0c7fSHeiko Stübner 
10585fa0c7fSHeiko Stübner 	softrst->reg_base = base;
106*ada8f95bSSebastian Reichel 	softrst->lut = lookup_table;
10785fa0c7fSHeiko Stübner 	softrst->flags = flags;
10885fa0c7fSHeiko Stübner 	softrst->num_regs = num_regs;
10985fa0c7fSHeiko Stübner 	softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16
11085fa0c7fSHeiko Stübner 								      : 32;
11185fa0c7fSHeiko Stübner 
11285fa0c7fSHeiko Stübner 	softrst->rcdev.owner = THIS_MODULE;
113*ada8f95bSSebastian Reichel 	if (lookup_table)
114*ada8f95bSSebastian Reichel 		softrst->rcdev.nr_resets = num_regs;
115*ada8f95bSSebastian Reichel 	else
11685fa0c7fSHeiko Stübner 		softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg;
11785fa0c7fSHeiko Stübner 	softrst->rcdev.ops = &rockchip_softrst_ops;
11885fa0c7fSHeiko Stübner 	softrst->rcdev.of_node = np;
11985fa0c7fSHeiko Stübner 	ret = reset_controller_register(&softrst->rcdev);
12085fa0c7fSHeiko Stübner 	if (ret) {
12185fa0c7fSHeiko Stübner 		pr_err("%s: could not register reset controller, %d\n",
12285fa0c7fSHeiko Stübner 		       __func__, ret);
12385fa0c7fSHeiko Stübner 		kfree(softrst);
12485fa0c7fSHeiko Stübner 	}
12585fa0c7fSHeiko Stübner };
126*ada8f95bSSebastian Reichel EXPORT_SYMBOL_GPL(rockchip_register_softrst_lut);
127