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