18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014 MundoReader S.L. 48c2ecf20Sopenharmony_ci * Author: Heiko Stuebner <heiko@sntech.de> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 108c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 118c2ecf20Sopenharmony_ci#include "clk.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistruct rockchip_softrst { 148c2ecf20Sopenharmony_ci struct reset_controller_dev rcdev; 158c2ecf20Sopenharmony_ci void __iomem *reg_base; 168c2ecf20Sopenharmony_ci int num_regs; 178c2ecf20Sopenharmony_ci int num_per_reg; 188c2ecf20Sopenharmony_ci u8 flags; 198c2ecf20Sopenharmony_ci spinlock_t lock; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int rockchip_softrst_assert(struct reset_controller_dev *rcdev, 238c2ecf20Sopenharmony_ci unsigned long id) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct rockchip_softrst *softrst = container_of(rcdev, 268c2ecf20Sopenharmony_ci struct rockchip_softrst, 278c2ecf20Sopenharmony_ci rcdev); 288c2ecf20Sopenharmony_ci int bank = id / softrst->num_per_reg; 298c2ecf20Sopenharmony_ci int offset = id % softrst->num_per_reg; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 328c2ecf20Sopenharmony_ci writel(BIT(offset) | (BIT(offset) << 16), 338c2ecf20Sopenharmony_ci softrst->reg_base + (bank * 4)); 348c2ecf20Sopenharmony_ci } else { 358c2ecf20Sopenharmony_ci unsigned long flags; 368c2ecf20Sopenharmony_ci u32 reg; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci spin_lock_irqsave(&softrst->lock, flags); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci reg = readl(softrst->reg_base + (bank * 4)); 418c2ecf20Sopenharmony_ci writel(reg | BIT(offset), softrst->reg_base + (bank * 4)); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&softrst->lock, flags); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int rockchip_softrst_deassert(struct reset_controller_dev *rcdev, 508c2ecf20Sopenharmony_ci unsigned long id) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct rockchip_softrst *softrst = container_of(rcdev, 538c2ecf20Sopenharmony_ci struct rockchip_softrst, 548c2ecf20Sopenharmony_ci rcdev); 558c2ecf20Sopenharmony_ci int bank = id / softrst->num_per_reg; 568c2ecf20Sopenharmony_ci int offset = id % softrst->num_per_reg; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 598c2ecf20Sopenharmony_ci writel((BIT(offset) << 16), softrst->reg_base + (bank * 4)); 608c2ecf20Sopenharmony_ci } else { 618c2ecf20Sopenharmony_ci unsigned long flags; 628c2ecf20Sopenharmony_ci u32 reg; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci spin_lock_irqsave(&softrst->lock, flags); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci reg = readl(softrst->reg_base + (bank * 4)); 678c2ecf20Sopenharmony_ci writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&softrst->lock, flags); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct reset_control_ops rockchip_softrst_ops = { 768c2ecf20Sopenharmony_ci .assert = rockchip_softrst_assert, 778c2ecf20Sopenharmony_ci .deassert = rockchip_softrst_deassert, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid rockchip_register_softrst(struct device_node *np, 818c2ecf20Sopenharmony_ci unsigned int num_regs, 828c2ecf20Sopenharmony_ci void __iomem *base, u8 flags) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct rockchip_softrst *softrst; 858c2ecf20Sopenharmony_ci int ret; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci softrst = kzalloc(sizeof(*softrst), GFP_KERNEL); 888c2ecf20Sopenharmony_ci if (!softrst) 898c2ecf20Sopenharmony_ci return; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci spin_lock_init(&softrst->lock); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci softrst->reg_base = base; 948c2ecf20Sopenharmony_ci softrst->flags = flags; 958c2ecf20Sopenharmony_ci softrst->num_regs = num_regs; 968c2ecf20Sopenharmony_ci softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 978c2ecf20Sopenharmony_ci : 32; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci softrst->rcdev.owner = THIS_MODULE; 1008c2ecf20Sopenharmony_ci softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg; 1018c2ecf20Sopenharmony_ci softrst->rcdev.ops = &rockchip_softrst_ops; 1028c2ecf20Sopenharmony_ci softrst->rcdev.of_node = np; 1038c2ecf20Sopenharmony_ci ret = reset_controller_register(&softrst->rcdev); 1048c2ecf20Sopenharmony_ci if (ret) { 1058c2ecf20Sopenharmony_ci pr_err("%s: could not register reset controller, %d\n", 1068c2ecf20Sopenharmony_ci __func__, ret); 1078c2ecf20Sopenharmony_ci kfree(softrst); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_register_softrst); 111