| /* |
| * Copyright (C) 2013 Broadcom Corporation |
| * Copyright 2013 Linaro Limited |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation version 2. |
| * |
| * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
| * kind, whether express or implied; without even the implied warranty |
| * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include "clk-kona.h" |
| |
| #include <linux/delay.h> |
| |
| #define CCU_ACCESS_PASSWORD 0xA5A500 |
| #define CLK_GATE_DELAY_LOOP 2000 |
| |
| /* Bitfield operations */ |
| |
| /* Produces a mask of set bits covering a range of a 32-bit value */ |
| static inline u32 bitfield_mask(u32 shift, u32 width) |
| { |
| return ((1 << width) - 1) << shift; |
| } |
| |
| /* Extract the value of a bitfield found within a given register value */ |
| static inline u32 bitfield_extract(u32 reg_val, u32 shift, u32 width) |
| { |
| return (reg_val & bitfield_mask(shift, width)) >> shift; |
| } |
| |
| /* Replace the value of a bitfield found within a given register value */ |
| static inline u32 bitfield_replace(u32 reg_val, u32 shift, u32 width, u32 val) |
| { |
| u32 mask = bitfield_mask(shift, width); |
| |
| return (reg_val & ~mask) | (val << shift); |
| } |
| |
| /* Divider and scaling helpers */ |
| |
| /* |
| * Implement DIV_ROUND_CLOSEST() for 64-bit dividend and both values |
| * unsigned. Note that unlike do_div(), the remainder is discarded |
| * and the return value is the quotient (not the remainder). |
| */ |
| u64 do_div_round_closest(u64 dividend, unsigned long divisor) |
| { |
| u64 result; |
| |
| result = dividend + ((u64)divisor >> 1); |
| (void)do_div(result, divisor); |
| |
| return result; |
| } |
| |
| /* Convert a divider into the scaled divisor value it represents. */ |
| static inline u64 scaled_div_value(struct bcm_clk_div *div, u32 reg_div) |
| { |
| return (u64)reg_div + ((u64)1 << div->frac_width); |
| } |
| |
| /* |
| * Build a scaled divider value as close as possible to the |
| * given whole part (div_value) and fractional part (expressed |
| * in billionths). |
| */ |
| u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths) |
| { |
| u64 combined; |
| |
| BUG_ON(!div_value); |
| BUG_ON(billionths >= BILLION); |
| |
| combined = (u64)div_value * BILLION + billionths; |
| combined <<= div->frac_width; |
| |
| return do_div_round_closest(combined, BILLION); |
| } |
| |
| /* The scaled minimum divisor representable by a divider */ |
| static inline u64 |
| scaled_div_min(struct bcm_clk_div *div) |
| { |
| if (divider_is_fixed(div)) |
| return (u64)div->fixed; |
| |
| return scaled_div_value(div, 0); |
| } |
| |
| /* The scaled maximum divisor representable by a divider */ |
| u64 scaled_div_max(struct bcm_clk_div *div) |
| { |
| u32 reg_div; |
| |
| if (divider_is_fixed(div)) |
| return (u64)div->fixed; |
| |
| reg_div = ((u32)1 << div->width) - 1; |
| |
| return scaled_div_value(div, reg_div); |
| } |
| |
| /* |
| * Convert a scaled divisor into its divider representation as |
| * stored in a divider register field. |
| */ |
| static inline u32 |
| divider(struct bcm_clk_div *div, u64 scaled_div) |
| { |
| BUG_ON(scaled_div < scaled_div_min(div)); |
| BUG_ON(scaled_div > scaled_div_max(div)); |
| |
| return (u32)(scaled_div - ((u64)1 << div->frac_width)); |
| } |
| |
| /* Return a rate scaled for use when dividing by a scaled divisor. */ |
| static inline u64 |
| scale_rate(struct bcm_clk_div *div, u32 rate) |
| { |
| if (divider_is_fixed(div)) |
| return (u64)rate; |
| |
| return (u64)rate << div->frac_width; |
| } |
| |
| /* CCU access */ |
| |
| /* Read a 32-bit register value from a CCU's address space. */ |
| static inline u32 __ccu_read(struct ccu_data *ccu, u32 reg_offset) |
| { |
| return readl(ccu->base + reg_offset); |
| } |
| |
| /* Write a 32-bit register value into a CCU's address space. */ |
| static inline void |
| __ccu_write(struct ccu_data *ccu, u32 reg_offset, u32 reg_val) |
| { |
| writel(reg_val, ccu->base + reg_offset); |
| } |
| |
| static inline unsigned long ccu_lock(struct ccu_data *ccu) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&ccu->lock, flags); |
| |
| return flags; |
| } |
| static inline void ccu_unlock(struct ccu_data *ccu, unsigned long flags) |
| { |
| spin_unlock_irqrestore(&ccu->lock, flags); |
| } |
| |
| /* |
| * Enable/disable write access to CCU protected registers. The |
| * WR_ACCESS register for all CCUs is at offset 0. |
| */ |
| static inline void __ccu_write_enable(struct ccu_data *ccu) |
| { |
| if (ccu->write_enabled) { |
| pr_err("%s: access already enabled for %s\n", __func__, |
| ccu->name); |
| return; |
| } |
| ccu->write_enabled = true; |
| __ccu_write(ccu, 0, CCU_ACCESS_PASSWORD | 1); |
| } |
| |
| static inline void __ccu_write_disable(struct ccu_data *ccu) |
| { |
| if (!ccu->write_enabled) { |
| pr_err("%s: access wasn't enabled for %s\n", __func__, |
| ccu->name); |
| return; |
| } |
| |
| __ccu_write(ccu, 0, CCU_ACCESS_PASSWORD); |
| ccu->write_enabled = false; |
| } |
| |
| /* |
| * Poll a register in a CCU's address space, returning when the |
| * specified bit in that register's value is set (or clear). Delay |
| * a microsecond after each read of the register. Returns true if |
| * successful, or false if we gave up trying. |
| * |
| * Caller must ensure the CCU lock is held. |
| */ |
| static inline bool |
| __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want) |
| { |
| unsigned int tries; |
| u32 bit_mask = 1 << bit; |
| |
| for (tries = 0; tries < CLK_GATE_DELAY_LOOP; tries++) { |
| u32 val; |
| bool bit_val; |
| |
| val = __ccu_read(ccu, reg_offset); |
| bit_val = (val & bit_mask) != 0; |
| if (bit_val == want) |
| return true; |
| udelay(1); |
| } |
| return false; |
| } |
| |
| /* Gate operations */ |
| |
| /* Determine whether a clock is gated. CCU lock must be held. */ |
| static bool |
| __is_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate) |
| { |
| u32 bit_mask; |
| u32 reg_val; |
| |
| /* If there is no gate we can assume it's enabled. */ |
| if (!gate_exists(gate)) |
| return true; |
| |
| bit_mask = 1 << gate->status_bit; |
| reg_val = __ccu_read(ccu, gate->offset); |
| |
| return (reg_val & bit_mask) != 0; |
| } |
| |
| /* Determine whether a clock is gated. */ |
| static bool |
| is_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate) |
| { |
| long flags; |
| bool ret; |
| |
| /* Avoid taking the lock if we can */ |
| if (!gate_exists(gate)) |
| return true; |
| |
| flags = ccu_lock(ccu); |
| ret = __is_clk_gate_enabled(ccu, gate); |
| ccu_unlock(ccu, flags); |
| |
| return ret; |
| } |
| |
| /* |
| * Commit our desired gate state to the hardware. |
| * Returns true if successful, false otherwise. |
| */ |
| static bool |
| __gate_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate) |
| { |
| u32 reg_val; |
| u32 mask; |
| bool enabled = false; |
| |
| BUG_ON(!gate_exists(gate)); |
| if (!gate_is_sw_controllable(gate)) |
| return true; /* Nothing we can change */ |
| |
| reg_val = __ccu_read(ccu, gate->offset); |
| |
| /* For a hardware/software gate, set which is in control */ |
| if (gate_is_hw_controllable(gate)) { |
| mask = (u32)1 << gate->hw_sw_sel_bit; |
| if (gate_is_sw_managed(gate)) |
| reg_val |= mask; |
| else |
| reg_val &= ~mask; |
| } |
| |
| /* |
| * If software is in control, enable or disable the gate. |
| * If hardware is, clear the enabled bit for good measure. |
| * If a software controlled gate can't be disabled, we're |
| * required to write a 0 into the enable bit (but the gate |
| * will be enabled). |
| */ |
| mask = (u32)1 << gate->en_bit; |
| if (gate_is_sw_managed(gate) && (enabled = gate_is_enabled(gate)) && |
| !gate_is_no_disable(gate)) |
| reg_val |= mask; |
| else |
| reg_val &= ~mask; |
| |
| __ccu_write(ccu, gate->offset, reg_val); |
| |
| /* For a hardware controlled gate, we're done */ |
| if (!gate_is_sw_managed(gate)) |
| return true; |
| |
| /* Otherwise wait for the gate to be in desired state */ |
| return __ccu_wait_bit(ccu, gate->offset, gate->status_bit, enabled); |
| } |
| |
| /* |
| * Initialize a gate. Our desired state (hardware/software select, |
| * and if software, its enable state) is committed to hardware |
| * without the usual checks to see if it's already set up that way. |
| * Returns true if successful, false otherwise. |
| */ |
| static bool gate_init(struct ccu_data *ccu, struct bcm_clk_gate *gate) |
| { |
| if (!gate_exists(gate)) |
| return true; |
| return __gate_commit(ccu, gate); |
| } |
| |
| /* |
| * Set a gate to enabled or disabled state. Does nothing if the |
| * gate is not currently under software control, or if it is already |
| * in the requested state. Returns true if successful, false |
| * otherwise. CCU lock must be held. |
| */ |
| static bool |
| __clk_gate(struct ccu_data *ccu, struct bcm_clk_gate *gate, bool enable) |
| { |
| bool ret; |
| |
| if (!gate_exists(gate) || !gate_is_sw_managed(gate)) |
| return true; /* Nothing to do */ |
| |
| if (!enable && gate_is_no_disable(gate)) { |
| pr_warn("%s: invalid gate disable request (ignoring)\n", |
| __func__); |
| return true; |
| } |
| |
| if (enable == gate_is_enabled(gate)) |
| return true; /* No change */ |
| |
| gate_flip_enabled(gate); |
| ret = __gate_commit(ccu, gate); |
| if (!ret) |
| gate_flip_enabled(gate); /* Revert the change */ |
| |
| return ret; |
| } |
| |
| /* Enable or disable a gate. Returns 0 if successful, -EIO otherwise */ |
| static int clk_gate(struct ccu_data *ccu, const char *name, |
| struct bcm_clk_gate *gate, bool enable) |
| { |
| unsigned long flags; |
| bool success; |
| |
| /* |
| * Avoid taking the lock if we can. We quietly ignore |
| * requests to change state that don't make sense. |
| */ |
| if (!gate_exists(gate) || !gate_is_sw_managed(gate)) |
| return 0; |
| if (!enable && gate_is_no_disable(gate)) |
| return 0; |
| |
| flags = ccu_lock(ccu); |
| __ccu_write_enable(ccu); |
| |
| success = __clk_gate(ccu, gate, enable); |
| |
| __ccu_write_disable(ccu); |
| ccu_unlock(ccu, flags); |
| |
| if (success) |
| return 0; |
| |
| pr_err("%s: failed to %s gate for %s\n", __func__, |
| enable ? "enable" : "disable", name); |
| |
| return -EIO; |
| } |
| |
| /* Trigger operations */ |
| |
| /* |
| * Caller must ensure CCU lock is held and access is enabled. |
| * Returns true if successful, false otherwise. |
| */ |
| static bool __clk_trigger(struct ccu_data *ccu, struct bcm_clk_trig *trig) |
| { |
| /* Trigger the clock and wait for it to finish */ |
| __ccu_write(ccu, trig->offset, 1 << trig->bit); |
| |
| return __ccu_wait_bit(ccu, trig->offset, trig->bit, false); |
| } |
| |
| /* Divider operations */ |
| |
| /* Read a divider value and return the scaled divisor it represents. */ |
| static u64 divider_read_scaled(struct ccu_data *ccu, struct bcm_clk_div *div) |
| { |
| unsigned long flags; |
| u32 reg_val; |
| u32 reg_div; |
| |
| if (divider_is_fixed(div)) |
| return (u64)div->fixed; |
| |
| flags = ccu_lock(ccu); |
| reg_val = __ccu_read(ccu, div->offset); |
| ccu_unlock(ccu, flags); |
| |
| /* Extract the full divider field from the register value */ |
| reg_div = bitfield_extract(reg_val, div->shift, div->width); |
| |
| /* Return the scaled divisor value it represents */ |
| return scaled_div_value(div, reg_div); |
| } |
| |
| /* |
| * Convert a divider's scaled divisor value into its recorded form |
| * and commit it into the hardware divider register. |
| * |
| * Returns 0 on success. Returns -EINVAL for invalid arguments. |
| * Returns -ENXIO if gating failed, and -EIO if a trigger failed. |
| */ |
| static int __div_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, |
| struct bcm_clk_div *div, struct bcm_clk_trig *trig) |
| { |
| bool enabled; |
| u32 reg_div; |
| u32 reg_val; |
| int ret = 0; |
| |
| BUG_ON(divider_is_fixed(div)); |
| |
| /* |
| * If we're just initializing the divider, and no initial |
| * state was defined in the device tree, we just find out |
| * what its current value is rather than updating it. |
| */ |
| if (div->scaled_div == BAD_SCALED_DIV_VALUE) { |
| reg_val = __ccu_read(ccu, div->offset); |
| reg_div = bitfield_extract(reg_val, div->shift, div->width); |
| div->scaled_div = scaled_div_value(div, reg_div); |
| |
| return 0; |
| } |
| |
| /* Convert the scaled divisor to the value we need to record */ |
| reg_div = divider(div, div->scaled_div); |
| |
| /* Clock needs to be enabled before changing the rate */ |
| enabled = __is_clk_gate_enabled(ccu, gate); |
| if (!enabled && !__clk_gate(ccu, gate, true)) { |
| ret = -ENXIO; |
| goto out; |
| } |
| |
| /* Replace the divider value and record the result */ |
| reg_val = __ccu_read(ccu, div->offset); |
| reg_val = bitfield_replace(reg_val, div->shift, div->width, reg_div); |
| __ccu_write(ccu, div->offset, reg_val); |
| |
| /* If the trigger fails we still want to disable the gate */ |
| if (!__clk_trigger(ccu, trig)) |
| ret = -EIO; |
| |
| /* Disable the clock again if it was disabled to begin with */ |
| if (!enabled && !__clk_gate(ccu, gate, false)) |
| ret = ret ? ret : -ENXIO; /* return first error */ |
| out: |
| return ret; |
| } |
| |
| /* |
| * Initialize a divider by committing our desired state to hardware |
| * without the usual checks to see if it's already set up that way. |
| * Returns true if successful, false otherwise. |
| */ |
| static bool div_init(struct ccu_data *ccu, struct bcm_clk_gate *gate, |
| struct bcm_clk_div *div, struct bcm_clk_trig *trig) |
| { |
| if (!divider_exists(div) || divider_is_fixed(div)) |
| return true; |
| return !__div_commit(ccu, gate, div, trig); |
| } |
| |
| static int divider_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, |
| struct bcm_clk_div *div, struct bcm_clk_trig *trig, |
| u64 scaled_div) |
| { |
| unsigned long flags; |
| u64 previous; |
| int ret; |
| |
| BUG_ON(divider_is_fixed(div)); |
| |
| previous = div->scaled_div; |
| if (previous == scaled_div) |
| return 0; /* No change */ |
| |
| div->scaled_div = scaled_div; |
| |
| flags = ccu_lock(ccu); |
| __ccu_write_enable(ccu); |
| |
| ret = __div_commit(ccu, gate, div, trig); |
| |
| __ccu_write_disable(ccu); |
| ccu_unlock(ccu, flags); |
| |
| if (ret) |
| div->scaled_div = previous; /* Revert the change */ |
| |
| return ret; |
| |
| } |
| |
| /* Common clock rate helpers */ |
| |
| /* |
| * Implement the common clock framework recalc_rate method, taking |
| * into account a divider and an optional pre-divider. The |
| * pre-divider register pointer may be NULL. |
| */ |
| static unsigned long clk_recalc_rate(struct ccu_data *ccu, |
| struct bcm_clk_div *div, struct bcm_clk_div *pre_div, |
| unsigned long parent_rate) |
| { |
| u64 scaled_parent_rate; |
| u64 scaled_div; |
| u64 result; |
| |
| if (!divider_exists(div)) |
| return parent_rate; |
| |
| if (parent_rate > (unsigned long)LONG_MAX) |
| return 0; /* actually this would be a caller bug */ |
| |
| /* |
| * If there is a pre-divider, divide the scaled parent rate |
| * by the pre-divider value first. In this case--to improve |
| * accuracy--scale the parent rate by *both* the pre-divider |
| * value and the divider before actually computing the |
| * result of the pre-divider. |
| * |
| * If there's only one divider, just scale the parent rate. |
| */ |
| if (pre_div && divider_exists(pre_div)) { |
| u64 scaled_rate; |
| |
| scaled_rate = scale_rate(pre_div, parent_rate); |
| scaled_rate = scale_rate(div, scaled_rate); |
| scaled_div = divider_read_scaled(ccu, pre_div); |
| scaled_parent_rate = do_div_round_closest(scaled_rate, |
| scaled_div); |
| } else { |
| scaled_parent_rate = scale_rate(div, parent_rate); |
| } |
| |
| /* |
| * Get the scaled divisor value, and divide the scaled |
| * parent rate by that to determine this clock's resulting |
| * rate. |
| */ |
| scaled_div = divider_read_scaled(ccu, div); |
| result = do_div_round_closest(scaled_parent_rate, scaled_div); |
| |
| return (unsigned long)result; |
| } |
| |
| /* |
| * Compute the output rate produced when a given parent rate is fed |
| * into two dividers. The pre-divider can be NULL, and even if it's |
| * non-null it may be nonexistent. It's also OK for the divider to |
| * be nonexistent, and in that case the pre-divider is also ignored. |
| * |
| * If scaled_div is non-null, it is used to return the scaled divisor |
| * value used by the (downstream) divider to produce that rate. |
| */ |
| static long round_rate(struct ccu_data *ccu, struct bcm_clk_div *div, |
| struct bcm_clk_div *pre_div, |
| unsigned long rate, unsigned long parent_rate, |
| u64 *scaled_div) |
| { |
| u64 scaled_parent_rate; |
| u64 min_scaled_div; |
| u64 max_scaled_div; |
| u64 best_scaled_div; |
| u64 result; |
| |
| BUG_ON(!divider_exists(div)); |
| BUG_ON(!rate); |
| BUG_ON(parent_rate > (u64)LONG_MAX); |
| |
| /* |
| * If there is a pre-divider, divide the scaled parent rate |
| * by the pre-divider value first. In this case--to improve |
| * accuracy--scale the parent rate by *both* the pre-divider |
| * value and the divider before actually computing the |
| * result of the pre-divider. |
| * |
| * If there's only one divider, just scale the parent rate. |
| * |
| * For simplicity we treat the pre-divider as fixed (for now). |
| */ |
| if (divider_exists(pre_div)) { |
| u64 scaled_rate; |
| u64 scaled_pre_div; |
| |
| scaled_rate = scale_rate(pre_div, parent_rate); |
| scaled_rate = scale_rate(div, scaled_rate); |
| scaled_pre_div = divider_read_scaled(ccu, pre_div); |
| scaled_parent_rate = do_div_round_closest(scaled_rate, |
| scaled_pre_div); |
| } else { |
| scaled_parent_rate = scale_rate(div, parent_rate); |
| } |
| |
| /* |
| * Compute the best possible divider and ensure it is in |
| * range. A fixed divider can't be changed, so just report |
| * the best we can do. |
| */ |
| if (!divider_is_fixed(div)) { |
| best_scaled_div = do_div_round_closest(scaled_parent_rate, |
| rate); |
| min_scaled_div = scaled_div_min(div); |
| max_scaled_div = scaled_div_max(div); |
| if (best_scaled_div > max_scaled_div) |
| best_scaled_div = max_scaled_div; |
| else if (best_scaled_div < min_scaled_div) |
| best_scaled_div = min_scaled_div; |
| } else { |
| best_scaled_div = divider_read_scaled(ccu, div); |
| } |
| |
| /* OK, figure out the resulting rate */ |
| result = do_div_round_closest(scaled_parent_rate, best_scaled_div); |
| |
| if (scaled_div) |
| *scaled_div = best_scaled_div; |
| |
| return (long)result; |
| } |
| |
| /* Common clock parent helpers */ |
| |
| /* |
| * For a given parent selector (register field) value, find the |
| * index into a selector's parent_sel array that contains it. |
| * Returns the index, or BAD_CLK_INDEX if it's not found. |
| */ |
| static u8 parent_index(struct bcm_clk_sel *sel, u8 parent_sel) |
| { |
| u8 i; |
| |
| BUG_ON(sel->parent_count > (u32)U8_MAX); |
| for (i = 0; i < sel->parent_count; i++) |
| if (sel->parent_sel[i] == parent_sel) |
| return i; |
| return BAD_CLK_INDEX; |
| } |
| |
| /* |
| * Fetch the current value of the selector, and translate that into |
| * its corresponding index in the parent array we registered with |
| * the clock framework. |
| * |
| * Returns parent array index that corresponds with the value found, |
| * or BAD_CLK_INDEX if the found value is out of range. |
| */ |
| static u8 selector_read_index(struct ccu_data *ccu, struct bcm_clk_sel *sel) |
| { |
| unsigned long flags; |
| u32 reg_val; |
| u32 parent_sel; |
| u8 index; |
| |
| /* If there's no selector, there's only one parent */ |
| if (!selector_exists(sel)) |
| return 0; |
| |
| /* Get the value in the selector register */ |
| flags = ccu_lock(ccu); |
| reg_val = __ccu_read(ccu, sel->offset); |
| ccu_unlock(ccu, flags); |
| |
| parent_sel = bitfield_extract(reg_val, sel->shift, sel->width); |
| |
| /* Look up that selector's parent array index and return it */ |
| index = parent_index(sel, parent_sel); |
| if (index == BAD_CLK_INDEX) |
| pr_err("%s: out-of-range parent selector %u (%s 0x%04x)\n", |
| __func__, parent_sel, ccu->name, sel->offset); |
| |
| return index; |
| } |
| |
| /* |
| * Commit our desired selector value to the hardware. |
| * |
| * Returns 0 on success. Returns -EINVAL for invalid arguments. |
| * Returns -ENXIO if gating failed, and -EIO if a trigger failed. |
| */ |
| static int |
| __sel_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, |
| struct bcm_clk_sel *sel, struct bcm_clk_trig *trig) |
| { |
| u32 parent_sel; |
| u32 reg_val; |
| bool enabled; |
| int ret = 0; |
| |
| BUG_ON(!selector_exists(sel)); |
| |
| /* |
| * If we're just initializing the selector, and no initial |
| * state was defined in the device tree, we just find out |
| * what its current value is rather than updating it. |
| */ |
| if (sel->clk_index == BAD_CLK_INDEX) { |
| u8 index; |
| |
| reg_val = __ccu_read(ccu, sel->offset); |
| parent_sel = bitfield_extract(reg_val, sel->shift, sel->width); |
| index = parent_index(sel, parent_sel); |
| if (index == BAD_CLK_INDEX) |
| return -EINVAL; |
| sel->clk_index = index; |
| |
| return 0; |
| } |
| |
| BUG_ON((u32)sel->clk_index >= sel->parent_count); |
| parent_sel = sel->parent_sel[sel->clk_index]; |
| |
| /* Clock needs to be enabled before changing the parent */ |
| enabled = __is_clk_gate_enabled(ccu, gate); |
| if (!enabled && !__clk_gate(ccu, gate, true)) |
| return -ENXIO; |
| |
| /* Replace the selector value and record the result */ |
| reg_val = __ccu_read(ccu, sel->offset); |
| reg_val = bitfield_replace(reg_val, sel->shift, sel->width, parent_sel); |
| __ccu_write(ccu, sel->offset, reg_val); |
| |
| /* If the trigger fails we still want to disable the gate */ |
| if (!__clk_trigger(ccu, trig)) |
| ret = -EIO; |
| |
| /* Disable the clock again if it was disabled to begin with */ |
| if (!enabled && !__clk_gate(ccu, gate, false)) |
| ret = ret ? ret : -ENXIO; /* return first error */ |
| |
| return ret; |
| } |
| |
| /* |
| * Initialize a selector by committing our desired state to hardware |
| * without the usual checks to see if it's already set up that way. |
| * Returns true if successful, false otherwise. |
| */ |
| static bool sel_init(struct ccu_data *ccu, struct bcm_clk_gate *gate, |
| struct bcm_clk_sel *sel, struct bcm_clk_trig *trig) |
| { |
| if (!selector_exists(sel)) |
| return true; |
| return !__sel_commit(ccu, gate, sel, trig); |
| } |
| |
| /* |
| * Write a new value into a selector register to switch to a |
| * different parent clock. Returns 0 on success, or an error code |
| * (from __sel_commit()) otherwise. |
| */ |
| static int selector_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, |
| struct bcm_clk_sel *sel, struct bcm_clk_trig *trig, |
| u8 index) |
| { |
| unsigned long flags; |
| u8 previous; |
| int ret; |
| |
| previous = sel->clk_index; |
| if (previous == index) |
| return 0; /* No change */ |
| |
| sel->clk_index = index; |
| |
| flags = ccu_lock(ccu); |
| __ccu_write_enable(ccu); |
| |
| ret = __sel_commit(ccu, gate, sel, trig); |
| |
| __ccu_write_disable(ccu); |
| ccu_unlock(ccu, flags); |
| |
| if (ret) |
| sel->clk_index = previous; /* Revert the change */ |
| |
| return ret; |
| } |
| |
| /* Clock operations */ |
| |
| static int kona_peri_clk_enable(struct clk_hw *hw) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct bcm_clk_gate *gate = &bcm_clk->peri->gate; |
| |
| return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true); |
| } |
| |
| static void kona_peri_clk_disable(struct clk_hw *hw) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct bcm_clk_gate *gate = &bcm_clk->peri->gate; |
| |
| (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false); |
| } |
| |
| static int kona_peri_clk_is_enabled(struct clk_hw *hw) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct bcm_clk_gate *gate = &bcm_clk->peri->gate; |
| |
| return is_clk_gate_enabled(bcm_clk->ccu, gate) ? 1 : 0; |
| } |
| |
| static unsigned long kona_peri_clk_recalc_rate(struct clk_hw *hw, |
| unsigned long parent_rate) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct peri_clk_data *data = bcm_clk->peri; |
| |
| return clk_recalc_rate(bcm_clk->ccu, &data->div, &data->pre_div, |
| parent_rate); |
| } |
| |
| static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, |
| unsigned long *parent_rate) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct bcm_clk_div *div = &bcm_clk->peri->div; |
| |
| if (!divider_exists(div)) |
| return __clk_get_rate(hw->clk); |
| |
| /* Quietly avoid a zero rate */ |
| return round_rate(bcm_clk->ccu, div, &bcm_clk->peri->pre_div, |
| rate ? rate : 1, *parent_rate, NULL); |
| } |
| |
| static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct peri_clk_data *data = bcm_clk->peri; |
| struct bcm_clk_sel *sel = &data->sel; |
| struct bcm_clk_trig *trig; |
| int ret; |
| |
| BUG_ON(index >= sel->parent_count); |
| |
| /* If there's only one parent we don't require a selector */ |
| if (!selector_exists(sel)) |
| return 0; |
| |
| /* |
| * The regular trigger is used by default, but if there's a |
| * pre-trigger we want to use that instead. |
| */ |
| trig = trigger_exists(&data->pre_trig) ? &data->pre_trig |
| : &data->trig; |
| |
| ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); |
| if (ret == -ENXIO) { |
| pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); |
| ret = -EIO; /* Don't proliferate weird errors */ |
| } else if (ret == -EIO) { |
| pr_err("%s: %strigger failed for %s\n", __func__, |
| trig == &data->pre_trig ? "pre-" : "", |
| bcm_clk->name); |
| } |
| |
| return ret; |
| } |
| |
| static u8 kona_peri_clk_get_parent(struct clk_hw *hw) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct peri_clk_data *data = bcm_clk->peri; |
| u8 index; |
| |
| index = selector_read_index(bcm_clk->ccu, &data->sel); |
| |
| /* Not all callers would handle an out-of-range value gracefully */ |
| return index == BAD_CLK_INDEX ? 0 : index; |
| } |
| |
| static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, |
| unsigned long parent_rate) |
| { |
| struct kona_clk *bcm_clk = to_kona_clk(hw); |
| struct peri_clk_data *data = bcm_clk->peri; |
| struct bcm_clk_div *div = &data->div; |
| u64 scaled_div = 0; |
| int ret; |
| |
| if (parent_rate > (unsigned long)LONG_MAX) |
| return -EINVAL; |
| |
| if (rate == __clk_get_rate(hw->clk)) |
| return 0; |
| |
| if (!divider_exists(div)) |
| return rate == parent_rate ? 0 : -EINVAL; |
| |
| /* |
| * A fixed divider can't be changed. (Nor can a fixed |
| * pre-divider be, but for now we never actually try to |
| * change that.) Tolerate a request for a no-op change. |
| */ |
| if (divider_is_fixed(&data->div)) |
| return rate == parent_rate ? 0 : -EINVAL; |
| |
| /* |
| * Get the scaled divisor value needed to achieve a clock |
| * rate as close as possible to what was requested, given |
| * the parent clock rate supplied. |
| */ |
| (void)round_rate(bcm_clk->ccu, div, &data->pre_div, |
| rate ? rate : 1, parent_rate, &scaled_div); |
| |
| /* |
| * We aren't updating any pre-divider at this point, so |
| * we'll use the regular trigger. |
| */ |
| ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, |
| &data->trig, scaled_div); |
| if (ret == -ENXIO) { |
| pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); |
| ret = -EIO; /* Don't proliferate weird errors */ |
| } else if (ret == -EIO) { |
| pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name); |
| } |
| |
| return ret; |
| } |
| |
| struct clk_ops kona_peri_clk_ops = { |
| .enable = kona_peri_clk_enable, |
| .disable = kona_peri_clk_disable, |
| .is_enabled = kona_peri_clk_is_enabled, |
| .recalc_rate = kona_peri_clk_recalc_rate, |
| .round_rate = kona_peri_clk_round_rate, |
| .set_parent = kona_peri_clk_set_parent, |
| .get_parent = kona_peri_clk_get_parent, |
| .set_rate = kona_peri_clk_set_rate, |
| }; |
| |
| /* Put a peripheral clock into its initial state */ |
| static bool __peri_clk_init(struct kona_clk *bcm_clk) |
| { |
| struct ccu_data *ccu = bcm_clk->ccu; |
| struct peri_clk_data *peri = bcm_clk->peri; |
| const char *name = bcm_clk->name; |
| struct bcm_clk_trig *trig; |
| |
| BUG_ON(bcm_clk->type != bcm_clk_peri); |
| |
| if (!gate_init(ccu, &peri->gate)) { |
| pr_err("%s: error initializing gate for %s\n", __func__, name); |
| return false; |
| } |
| if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { |
| pr_err("%s: error initializing divider for %s\n", __func__, |
| name); |
| return false; |
| } |
| |
| /* |
| * For the pre-divider and selector, the pre-trigger is used |
| * if it's present, otherwise we just use the regular trigger. |
| */ |
| trig = trigger_exists(&peri->pre_trig) ? &peri->pre_trig |
| : &peri->trig; |
| |
| if (!div_init(ccu, &peri->gate, &peri->pre_div, trig)) { |
| pr_err("%s: error initializing pre-divider for %s\n", __func__, |
| name); |
| return false; |
| } |
| |
| if (!sel_init(ccu, &peri->gate, &peri->sel, trig)) { |
| pr_err("%s: error initializing selector for %s\n", __func__, |
| name); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool __kona_clk_init(struct kona_clk *bcm_clk) |
| { |
| switch (bcm_clk->type) { |
| case bcm_clk_peri: |
| return __peri_clk_init(bcm_clk); |
| default: |
| BUG(); |
| } |
| return -EINVAL; |
| } |
| |
| /* Set a CCU and all its clocks into their desired initial state */ |
| bool __init kona_ccu_init(struct ccu_data *ccu) |
| { |
| unsigned long flags; |
| unsigned int which; |
| struct clk **clks = ccu->data.clks; |
| bool success = true; |
| |
| flags = ccu_lock(ccu); |
| __ccu_write_enable(ccu); |
| |
| for (which = 0; which < ccu->data.clk_num; which++) { |
| struct kona_clk *bcm_clk; |
| |
| if (!clks[which]) |
| continue; |
| bcm_clk = to_kona_clk(__clk_get_hw(clks[which])); |
| success &= __kona_clk_init(bcm_clk); |
| } |
| |
| __ccu_write_disable(ccu); |
| ccu_unlock(ccu, flags); |
| return success; |
| } |