linux/drivers/clk/bcm/clk-kona.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2013 Broadcom Corporation
 * Copyright 2013 Linaro Limited
 */

#include "clk-kona.h"

#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/clk-provider.h>

/*
 * "Policies" affect the frequencies of bus clocks provided by a
 * CCU.  (I believe these polices are named "Deep Sleep", "Economy",
 * "Normal", and "Turbo".)  A lower policy number has lower power
 * consumption, and policy 2 is the default.
 */
#define CCU_POLICY_COUNT

#define CCU_ACCESS_PASSWORD
#define CLK_GATE_DELAY_LOOP

/* 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)
{}

/* Extract the value of a bitfield found within a given register value */
static inline u32 bitfield_extract(u32 reg_val, u32 shift, u32 width)
{}

/* 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)
{}

/* Divider and scaling helpers */

/* Convert a divider into the scaled divisor value it represents. */
static inline u64 scaled_div_value(struct bcm_clk_div *div, u32 reg_div)
{}

/*
 * 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)
{}

/* The scaled minimum divisor representable by a divider */
static inline u64
scaled_div_min(struct bcm_clk_div *div)
{}

/* The scaled maximum divisor representable by a divider */
u64 scaled_div_max(struct bcm_clk_div *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)
{}

/* Return a rate scaled for use when dividing by a scaled divisor. */
static inline u64
scale_rate(struct bcm_clk_div *div, u32 rate)
{}

/* 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)
{}

/* 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)
{}

static inline unsigned long ccu_lock(struct ccu_data *ccu)
{}
static inline void ccu_unlock(struct ccu_data *ccu, unsigned long 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)
{}

static inline void __ccu_write_disable(struct ccu_data *ccu)
{}

/*
 * 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)
{}

/* Policy operations */

static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync)
{}

static bool __ccu_policy_engine_stop(struct ccu_data *ccu)
{}

/*
 * A CCU has four operating conditions ("policies"), and some clocks
 * can be disabled or enabled based on which policy is currently in
 * effect.  Such clocks have a bit in a "policy mask" register for
 * each policy indicating whether the clock is enabled for that
 * policy or not.  The bit position for a clock is the same for all
 * four registers, and the 32-bit registers are at consecutive
 * addresses.
 */
static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy)
{}

/* 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)
{}

/* Determine whether a clock is gated. */
static bool
is_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate)
{}

/*
 * 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)
{}

/*
 * 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)
{}

/*
 * 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)
{}

/* 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)
{}

/* Hysteresis operations */

/*
 * If a clock gate requires a turn-off delay it will have
 * "hysteresis" register bits defined.  The first, if set, enables
 * the delay; and if enabled, the second bit determines whether the
 * delay is "low" or "high" (1 means high).  For now, if it's
 * defined for a clock, we set it.
 */
static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst)
{}

/* 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)
{}

/* 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)
{}

/*
 * 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)
{}

/*
 * 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)
{}

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)
{}

/* 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)
{}

/*
 * 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)
{}

/* 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)
{}

/*
 * 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)
{}

/*
 * 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)
{}

/*
 * 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)
{}

/*
 * 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)
{}

/* Clock operations */

static int kona_peri_clk_enable(struct clk_hw *hw)
{}

static void kona_peri_clk_disable(struct clk_hw *hw)
{}

static int kona_peri_clk_is_enabled(struct clk_hw *hw)
{}

static unsigned long kona_peri_clk_recalc_rate(struct clk_hw *hw,
			unsigned long parent_rate)
{}

static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
			unsigned long *parent_rate)
{}

static int kona_peri_clk_determine_rate(struct clk_hw *hw,
					struct clk_rate_request *req)
{}

static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
{}

static u8 kona_peri_clk_get_parent(struct clk_hw *hw)
{}

static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
			unsigned long parent_rate)
{}

struct clk_ops kona_peri_clk_ops =;

/* Put a peripheral clock into its initial state */
static bool __peri_clk_init(struct kona_clk *bcm_clk)
{}

static bool __kona_clk_init(struct kona_clk *bcm_clk)
{}

/* Set a CCU and all its clocks into their desired initial state */
bool __init kona_ccu_init(struct ccu_data *ccu)
{}