177 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.4 */5 6#include <linux/clk-provider.h>7#include <linux/slab.h>8#include <linux/io.h>9#include <linux/delay.h>10#include <linux/err.h>11 12#include <soc/tegra/fuse.h>13 14#include "clk.h"15 16static DEFINE_SPINLOCK(periph_ref_lock);17 18/* Macros to assist peripheral gate clock */19#define read_enb(gate) \20 readl_relaxed(gate->clk_base + (gate->regs->enb_reg))21#define write_enb_set(val, gate) \22 writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg))23#define write_enb_clr(val, gate) \24 writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg))25 26#define read_rst(gate) \27 readl_relaxed(gate->clk_base + (gate->regs->rst_reg))28#define write_rst_clr(val, gate) \29 writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))30 31#define periph_clk_to_bit(gate) (1 << (gate->clk_num % 32))32 33#define LVL2_CLK_GATE_OVRE 0x55434 35/* Peripheral gate clock ops */36static int clk_periph_is_enabled(struct clk_hw *hw)37{38 struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);39 int state = 1;40 41 if (!(read_enb(gate) & periph_clk_to_bit(gate)))42 state = 0;43 44 if (!(gate->flags & TEGRA_PERIPH_NO_RESET))45 if (read_rst(gate) & periph_clk_to_bit(gate))46 state = 0;47 48 return state;49}50 51static void clk_periph_enable_locked(struct clk_hw *hw)52{53 struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);54 55 write_enb_set(periph_clk_to_bit(gate), gate);56 udelay(2);57 58 if (gate->flags & TEGRA_PERIPH_WAR_1005168) {59 writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);60 writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);61 udelay(1);62 writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);63 }64}65 66static void clk_periph_disable_locked(struct clk_hw *hw)67{68 struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);69 70 /*71 * If peripheral is in the APB bus then read the APB bus to72 * flush the write operation in apb bus. This will avoid the73 * peripheral access after disabling clock74 */75 if (gate->flags & TEGRA_PERIPH_ON_APB)76 tegra_read_chipid();77 78 write_enb_clr(periph_clk_to_bit(gate), gate);79}80 81static int clk_periph_enable(struct clk_hw *hw)82{83 struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);84 unsigned long flags = 0;85 86 spin_lock_irqsave(&periph_ref_lock, flags);87 88 if (!gate->enable_refcnt[gate->clk_num]++)89 clk_periph_enable_locked(hw);90 91 spin_unlock_irqrestore(&periph_ref_lock, flags);92 93 return 0;94}95 96static void clk_periph_disable(struct clk_hw *hw)97{98 struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);99 unsigned long flags = 0;100 101 spin_lock_irqsave(&periph_ref_lock, flags);102 103 WARN_ON(!gate->enable_refcnt[gate->clk_num]);104 105 if (--gate->enable_refcnt[gate->clk_num] == 0)106 clk_periph_disable_locked(hw);107 108 spin_unlock_irqrestore(&periph_ref_lock, flags);109}110 111static void clk_periph_disable_unused(struct clk_hw *hw)112{113 struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);114 unsigned long flags = 0;115 116 spin_lock_irqsave(&periph_ref_lock, flags);117 118 /*119 * Some clocks are duplicated and some of them are marked as critical,120 * like fuse and fuse_burn for example, thus the enable_refcnt will121 * be non-zero here if the "unused" duplicate is disabled by CCF.122 */123 if (!gate->enable_refcnt[gate->clk_num])124 clk_periph_disable_locked(hw);125 126 spin_unlock_irqrestore(&periph_ref_lock, flags);127}128 129const struct clk_ops tegra_clk_periph_gate_ops = {130 .is_enabled = clk_periph_is_enabled,131 .enable = clk_periph_enable,132 .disable = clk_periph_disable,133 .disable_unused = clk_periph_disable_unused,134};135 136struct clk *tegra_clk_register_periph_gate(const char *name,137 const char *parent_name, u8 gate_flags, void __iomem *clk_base,138 unsigned long flags, int clk_num, int *enable_refcnt)139{140 struct tegra_clk_periph_gate *gate;141 struct clk *clk;142 struct clk_init_data init;143 const struct tegra_clk_periph_regs *pregs;144 145 pregs = get_reg_bank(clk_num);146 if (!pregs)147 return ERR_PTR(-EINVAL);148 149 gate = kzalloc(sizeof(*gate), GFP_KERNEL);150 if (!gate) {151 pr_err("%s: could not allocate periph gate clk\n", __func__);152 return ERR_PTR(-ENOMEM);153 }154 155 init.name = name;156 init.flags = flags;157 init.parent_names = parent_name ? &parent_name : NULL;158 init.num_parents = parent_name ? 1 : 0;159 init.ops = &tegra_clk_periph_gate_ops;160 161 gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC;162 gate->clk_base = clk_base;163 gate->clk_num = clk_num;164 gate->flags = gate_flags;165 gate->enable_refcnt = enable_refcnt;166 gate->regs = pregs;167 168 /* Data in .init is copied by clk_register(), so stack variable OK */169 gate->hw.init = &init;170 171 clk = clk_register(NULL, &gate->hw);172 if (IS_ERR(clk))173 kfree(gate);174 175 return clk;176}177