Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: rockchip: add reset controller

All Rockchip SoCs at least down to the ARM9-based RK28xx include the reset-
controller for SoC peripherals in their clock controller.
While the older SoCs (ARM9 and Cortex-A8) use a regular scheme to change
register values, the Cortex-A9 SoCs use a hiword-mask making locking unecessary.
To be compatible with both schemes the reset controller takes a flag to
decide which scheme to use, similar to the other HIWORD_MASK flags used in the
clock framework.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-By: Max Schwarz <max.schwarz@online.de>
Tested-By: Max Schwarz <max.schwarz@online.de>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Heiko Stübner and committed by
Mike Turquette
85fa0c7f 90c59025

+133
+1
drivers/clk/rockchip/Makefile
··· 5 5 obj-y += clk-rockchip.o 6 6 obj-y += clk.o 7 7 obj-y += clk-pll.o 8 + obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
+14
drivers/clk/rockchip/clk.h
··· 321 321 void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, 322 322 unsigned int nr_pll, int grf_lock_offset); 323 323 324 + #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) 325 + 326 + #ifdef CONFIG_RESET_CONTROLLER 327 + void rockchip_register_softrst(struct device_node *np, 328 + unsigned int num_regs, 329 + void __iomem *base, u8 flags); 330 + #else 331 + static inline void rockchip_register_softrst(struct device_node *np, 332 + unsigned int num_regs, 333 + void __iomem *base, u8 flags) 334 + { 335 + } 336 + #endif 337 + 324 338 #endif
+118
drivers/clk/rockchip/softrst.c
··· 1 + /* 2 + * Copyright (c) 2014 MundoReader S.L. 3 + * Author: Heiko Stuebner <heiko@sntech.de> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include <linux/slab.h> 17 + #include <linux/io.h> 18 + #include <linux/reset-controller.h> 19 + #include <linux/spinlock.h> 20 + #include "clk.h" 21 + 22 + struct rockchip_softrst { 23 + struct reset_controller_dev rcdev; 24 + void __iomem *reg_base; 25 + int num_regs; 26 + int num_per_reg; 27 + u8 flags; 28 + spinlock_t lock; 29 + }; 30 + 31 + static int rockchip_softrst_assert(struct reset_controller_dev *rcdev, 32 + unsigned long id) 33 + { 34 + struct rockchip_softrst *softrst = container_of(rcdev, 35 + struct rockchip_softrst, 36 + rcdev); 37 + int bank = id / softrst->num_per_reg; 38 + int offset = id % softrst->num_per_reg; 39 + 40 + if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 41 + writel(BIT(offset) | (BIT(offset) << 16), 42 + softrst->reg_base + (bank * 4)); 43 + } else { 44 + unsigned long flags; 45 + u32 reg; 46 + 47 + spin_lock_irqsave(&softrst->lock, flags); 48 + 49 + reg = readl(softrst->reg_base + (bank * 4)); 50 + writel(reg | BIT(offset), softrst->reg_base + (bank * 4)); 51 + 52 + spin_unlock_irqrestore(&softrst->lock, flags); 53 + } 54 + 55 + return 0; 56 + } 57 + 58 + static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev, 59 + unsigned long id) 60 + { 61 + struct rockchip_softrst *softrst = container_of(rcdev, 62 + struct rockchip_softrst, 63 + rcdev); 64 + int bank = id / softrst->num_per_reg; 65 + int offset = id % softrst->num_per_reg; 66 + 67 + if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { 68 + writel((BIT(offset) << 16), softrst->reg_base + (bank * 4)); 69 + } else { 70 + unsigned long flags; 71 + u32 reg; 72 + 73 + spin_lock_irqsave(&softrst->lock, flags); 74 + 75 + reg = readl(softrst->reg_base + (bank * 4)); 76 + writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4)); 77 + 78 + spin_unlock_irqrestore(&softrst->lock, flags); 79 + } 80 + 81 + return 0; 82 + } 83 + 84 + static struct reset_control_ops rockchip_softrst_ops = { 85 + .assert = rockchip_softrst_assert, 86 + .deassert = rockchip_softrst_deassert, 87 + }; 88 + 89 + void __init rockchip_register_softrst(struct device_node *np, 90 + unsigned int num_regs, 91 + void __iomem *base, u8 flags) 92 + { 93 + struct rockchip_softrst *softrst; 94 + int ret; 95 + 96 + softrst = kzalloc(sizeof(*softrst), GFP_KERNEL); 97 + if (!softrst) 98 + return; 99 + 100 + spin_lock_init(&softrst->lock); 101 + 102 + softrst->reg_base = base; 103 + softrst->flags = flags; 104 + softrst->num_regs = num_regs; 105 + softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 106 + : 32; 107 + 108 + softrst->rcdev.owner = THIS_MODULE; 109 + softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg; 110 + softrst->rcdev.ops = &rockchip_softrst_ops; 111 + softrst->rcdev.of_node = np; 112 + ret = reset_controller_register(&softrst->rcdev); 113 + if (ret) { 114 + pr_err("%s: could not register reset controller, %d\n", 115 + __func__, ret); 116 + kfree(softrst); 117 + } 118 + };