162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013 Broadcom Corporation 462306a36Sopenharmony_ci * Copyright 2013 Linaro Limited 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "clk-kona.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/clk-provider.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * "Policies" affect the frequencies of bus clocks provided by a 1662306a36Sopenharmony_ci * CCU. (I believe these polices are named "Deep Sleep", "Economy", 1762306a36Sopenharmony_ci * "Normal", and "Turbo".) A lower policy number has lower power 1862306a36Sopenharmony_ci * consumption, and policy 2 is the default. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci#define CCU_POLICY_COUNT 4 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define CCU_ACCESS_PASSWORD 0xA5A500 2362306a36Sopenharmony_ci#define CLK_GATE_DELAY_LOOP 2000 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Bitfield operations */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Produces a mask of set bits covering a range of a 32-bit value */ 2862306a36Sopenharmony_cistatic inline u32 bitfield_mask(u32 shift, u32 width) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci return ((1 << width) - 1) << shift; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Extract the value of a bitfield found within a given register value */ 3462306a36Sopenharmony_cistatic inline u32 bitfield_extract(u32 reg_val, u32 shift, u32 width) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return (reg_val & bitfield_mask(shift, width)) >> shift; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Replace the value of a bitfield found within a given register value */ 4062306a36Sopenharmony_cistatic inline u32 bitfield_replace(u32 reg_val, u32 shift, u32 width, u32 val) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci u32 mask = bitfield_mask(shift, width); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return (reg_val & ~mask) | (val << shift); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Divider and scaling helpers */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* Convert a divider into the scaled divisor value it represents. */ 5062306a36Sopenharmony_cistatic inline u64 scaled_div_value(struct bcm_clk_div *div, u32 reg_div) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return (u64)reg_div + ((u64)1 << div->u.s.frac_width); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * Build a scaled divider value as close as possible to the 5762306a36Sopenharmony_ci * given whole part (div_value) and fractional part (expressed 5862306a36Sopenharmony_ci * in billionths). 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ciu64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci u64 combined; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci BUG_ON(!div_value); 6562306a36Sopenharmony_ci BUG_ON(billionths >= BILLION); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci combined = (u64)div_value * BILLION + billionths; 6862306a36Sopenharmony_ci combined <<= div->u.s.frac_width; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return DIV_ROUND_CLOSEST_ULL(combined, BILLION); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* The scaled minimum divisor representable by a divider */ 7462306a36Sopenharmony_cistatic inline u64 7562306a36Sopenharmony_ciscaled_div_min(struct bcm_clk_div *div) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci if (divider_is_fixed(div)) 7862306a36Sopenharmony_ci return (u64)div->u.fixed; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return scaled_div_value(div, 0); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* The scaled maximum divisor representable by a divider */ 8462306a36Sopenharmony_ciu64 scaled_div_max(struct bcm_clk_div *div) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci u32 reg_div; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (divider_is_fixed(div)) 8962306a36Sopenharmony_ci return (u64)div->u.fixed; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci reg_div = ((u32)1 << div->u.s.width) - 1; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return scaled_div_value(div, reg_div); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * Convert a scaled divisor into its divider representation as 9862306a36Sopenharmony_ci * stored in a divider register field. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic inline u32 10162306a36Sopenharmony_cidivider(struct bcm_clk_div *div, u64 scaled_div) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci BUG_ON(scaled_div < scaled_div_min(div)); 10462306a36Sopenharmony_ci BUG_ON(scaled_div > scaled_div_max(div)); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return (u32)(scaled_div - ((u64)1 << div->u.s.frac_width)); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* Return a rate scaled for use when dividing by a scaled divisor. */ 11062306a36Sopenharmony_cistatic inline u64 11162306a36Sopenharmony_ciscale_rate(struct bcm_clk_div *div, u32 rate) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci if (divider_is_fixed(div)) 11462306a36Sopenharmony_ci return (u64)rate; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return (u64)rate << div->u.s.frac_width; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* CCU access */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* Read a 32-bit register value from a CCU's address space. */ 12262306a36Sopenharmony_cistatic inline u32 __ccu_read(struct ccu_data *ccu, u32 reg_offset) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return readl(ccu->base + reg_offset); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Write a 32-bit register value into a CCU's address space. */ 12862306a36Sopenharmony_cistatic inline void 12962306a36Sopenharmony_ci__ccu_write(struct ccu_data *ccu, u32 reg_offset, u32 reg_val) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci writel(reg_val, ccu->base + reg_offset); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic inline unsigned long ccu_lock(struct ccu_data *ccu) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci unsigned long flags; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci spin_lock_irqsave(&ccu->lock, flags); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return flags; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_cistatic inline void ccu_unlock(struct ccu_data *ccu, unsigned long flags) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci spin_unlock_irqrestore(&ccu->lock, flags); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * Enable/disable write access to CCU protected registers. The 14962306a36Sopenharmony_ci * WR_ACCESS register for all CCUs is at offset 0. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic inline void __ccu_write_enable(struct ccu_data *ccu) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci if (ccu->write_enabled) { 15462306a36Sopenharmony_ci pr_err("%s: access already enabled for %s\n", __func__, 15562306a36Sopenharmony_ci ccu->name); 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci ccu->write_enabled = true; 15962306a36Sopenharmony_ci __ccu_write(ccu, 0, CCU_ACCESS_PASSWORD | 1); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic inline void __ccu_write_disable(struct ccu_data *ccu) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci if (!ccu->write_enabled) { 16562306a36Sopenharmony_ci pr_err("%s: access wasn't enabled for %s\n", __func__, 16662306a36Sopenharmony_ci ccu->name); 16762306a36Sopenharmony_ci return; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci __ccu_write(ccu, 0, CCU_ACCESS_PASSWORD); 17162306a36Sopenharmony_ci ccu->write_enabled = false; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* 17562306a36Sopenharmony_ci * Poll a register in a CCU's address space, returning when the 17662306a36Sopenharmony_ci * specified bit in that register's value is set (or clear). Delay 17762306a36Sopenharmony_ci * a microsecond after each read of the register. Returns true if 17862306a36Sopenharmony_ci * successful, or false if we gave up trying. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Caller must ensure the CCU lock is held. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_cistatic inline bool 18362306a36Sopenharmony_ci__ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci unsigned int tries; 18662306a36Sopenharmony_ci u32 bit_mask = 1 << bit; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci for (tries = 0; tries < CLK_GATE_DELAY_LOOP; tries++) { 18962306a36Sopenharmony_ci u32 val; 19062306a36Sopenharmony_ci bool bit_val; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci val = __ccu_read(ccu, reg_offset); 19362306a36Sopenharmony_ci bit_val = (val & bit_mask) != 0; 19462306a36Sopenharmony_ci if (bit_val == want) 19562306a36Sopenharmony_ci return true; 19662306a36Sopenharmony_ci udelay(1); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci pr_warn("%s: %s/0x%04x bit %u was never %s\n", __func__, 19962306a36Sopenharmony_ci ccu->name, reg_offset, bit, want ? "set" : "clear"); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return false; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* Policy operations */ 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct bcm_policy_ctl *control = &ccu->policy.control; 20962306a36Sopenharmony_ci u32 offset; 21062306a36Sopenharmony_ci u32 go_bit; 21162306a36Sopenharmony_ci u32 mask; 21262306a36Sopenharmony_ci bool ret; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* If we don't need to control policy for this CCU, we're done. */ 21562306a36Sopenharmony_ci if (!policy_ctl_exists(control)) 21662306a36Sopenharmony_ci return true; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci offset = control->offset; 21962306a36Sopenharmony_ci go_bit = control->go_bit; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Ensure we're not busy before we start */ 22262306a36Sopenharmony_ci ret = __ccu_wait_bit(ccu, offset, go_bit, false); 22362306a36Sopenharmony_ci if (!ret) { 22462306a36Sopenharmony_ci pr_err("%s: ccu %s policy engine wouldn't go idle\n", 22562306a36Sopenharmony_ci __func__, ccu->name); 22662306a36Sopenharmony_ci return false; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * If it's a synchronous request, we'll wait for the voltage 23162306a36Sopenharmony_ci * and frequency of the active load to stabilize before 23262306a36Sopenharmony_ci * returning. To do this we select the active load by 23362306a36Sopenharmony_ci * setting the ATL bit. 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * An asynchronous request instead ramps the voltage in the 23662306a36Sopenharmony_ci * background, and when that process stabilizes, the target 23762306a36Sopenharmony_ci * load is copied to the active load and the CCU frequency 23862306a36Sopenharmony_ci * is switched. We do this by selecting the target load 23962306a36Sopenharmony_ci * (ATL bit clear) and setting the request auto-copy (AC bit 24062306a36Sopenharmony_ci * set). 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * Note, we do NOT read-modify-write this register. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci mask = (u32)1 << go_bit; 24562306a36Sopenharmony_ci if (sync) 24662306a36Sopenharmony_ci mask |= 1 << control->atl_bit; 24762306a36Sopenharmony_ci else 24862306a36Sopenharmony_ci mask |= 1 << control->ac_bit; 24962306a36Sopenharmony_ci __ccu_write(ccu, offset, mask); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Wait for indication that operation is complete. */ 25262306a36Sopenharmony_ci ret = __ccu_wait_bit(ccu, offset, go_bit, false); 25362306a36Sopenharmony_ci if (!ret) 25462306a36Sopenharmony_ci pr_err("%s: ccu %s policy engine never started\n", 25562306a36Sopenharmony_ci __func__, ccu->name); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic bool __ccu_policy_engine_stop(struct ccu_data *ccu) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct bcm_lvm_en *enable = &ccu->policy.enable; 26362306a36Sopenharmony_ci u32 offset; 26462306a36Sopenharmony_ci u32 enable_bit; 26562306a36Sopenharmony_ci bool ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* If we don't need to control policy for this CCU, we're done. */ 26862306a36Sopenharmony_ci if (!policy_lvm_en_exists(enable)) 26962306a36Sopenharmony_ci return true; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Ensure we're not busy before we start */ 27262306a36Sopenharmony_ci offset = enable->offset; 27362306a36Sopenharmony_ci enable_bit = enable->bit; 27462306a36Sopenharmony_ci ret = __ccu_wait_bit(ccu, offset, enable_bit, false); 27562306a36Sopenharmony_ci if (!ret) { 27662306a36Sopenharmony_ci pr_err("%s: ccu %s policy engine already stopped\n", 27762306a36Sopenharmony_ci __func__, ccu->name); 27862306a36Sopenharmony_ci return false; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Now set the bit to stop the engine (NO read-modify-write) */ 28262306a36Sopenharmony_ci __ccu_write(ccu, offset, (u32)1 << enable_bit); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Wait for indication that it has stopped. */ 28562306a36Sopenharmony_ci ret = __ccu_wait_bit(ccu, offset, enable_bit, false); 28662306a36Sopenharmony_ci if (!ret) 28762306a36Sopenharmony_ci pr_err("%s: ccu %s policy engine never stopped\n", 28862306a36Sopenharmony_ci __func__, ccu->name); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/* 29462306a36Sopenharmony_ci * A CCU has four operating conditions ("policies"), and some clocks 29562306a36Sopenharmony_ci * can be disabled or enabled based on which policy is currently in 29662306a36Sopenharmony_ci * effect. Such clocks have a bit in a "policy mask" register for 29762306a36Sopenharmony_ci * each policy indicating whether the clock is enabled for that 29862306a36Sopenharmony_ci * policy or not. The bit position for a clock is the same for all 29962306a36Sopenharmony_ci * four registers, and the 32-bit registers are at consecutive 30062306a36Sopenharmony_ci * addresses. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_cistatic bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci u32 offset; 30562306a36Sopenharmony_ci u32 mask; 30662306a36Sopenharmony_ci int i; 30762306a36Sopenharmony_ci bool ret; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (!policy_exists(policy)) 31062306a36Sopenharmony_ci return true; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * We need to stop the CCU policy engine to allow update 31462306a36Sopenharmony_ci * of our policy bits. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci if (!__ccu_policy_engine_stop(ccu)) { 31762306a36Sopenharmony_ci pr_err("%s: unable to stop CCU %s policy engine\n", 31862306a36Sopenharmony_ci __func__, ccu->name); 31962306a36Sopenharmony_ci return false; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * For now, if a clock defines its policy bit we just mark 32462306a36Sopenharmony_ci * it "enabled" for all four policies. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci offset = policy->offset; 32762306a36Sopenharmony_ci mask = (u32)1 << policy->bit; 32862306a36Sopenharmony_ci for (i = 0; i < CCU_POLICY_COUNT; i++) { 32962306a36Sopenharmony_ci u32 reg_val; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci reg_val = __ccu_read(ccu, offset); 33262306a36Sopenharmony_ci reg_val |= mask; 33362306a36Sopenharmony_ci __ccu_write(ccu, offset, reg_val); 33462306a36Sopenharmony_ci offset += sizeof(u32); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* We're done updating; fire up the policy engine again. */ 33862306a36Sopenharmony_ci ret = __ccu_policy_engine_start(ccu, true); 33962306a36Sopenharmony_ci if (!ret) 34062306a36Sopenharmony_ci pr_err("%s: unable to restart CCU %s policy engine\n", 34162306a36Sopenharmony_ci __func__, ccu->name); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* Gate operations */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* Determine whether a clock is gated. CCU lock must be held. */ 34962306a36Sopenharmony_cistatic bool 35062306a36Sopenharmony_ci__is_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci u32 bit_mask; 35362306a36Sopenharmony_ci u32 reg_val; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* If there is no gate we can assume it's enabled. */ 35662306a36Sopenharmony_ci if (!gate_exists(gate)) 35762306a36Sopenharmony_ci return true; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci bit_mask = 1 << gate->status_bit; 36062306a36Sopenharmony_ci reg_val = __ccu_read(ccu, gate->offset); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return (reg_val & bit_mask) != 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/* Determine whether a clock is gated. */ 36662306a36Sopenharmony_cistatic bool 36762306a36Sopenharmony_ciis_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci long flags; 37062306a36Sopenharmony_ci bool ret; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Avoid taking the lock if we can */ 37362306a36Sopenharmony_ci if (!gate_exists(gate)) 37462306a36Sopenharmony_ci return true; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci flags = ccu_lock(ccu); 37762306a36Sopenharmony_ci ret = __is_clk_gate_enabled(ccu, gate); 37862306a36Sopenharmony_ci ccu_unlock(ccu, flags); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return ret; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* 38462306a36Sopenharmony_ci * Commit our desired gate state to the hardware. 38562306a36Sopenharmony_ci * Returns true if successful, false otherwise. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_cistatic bool 38862306a36Sopenharmony_ci__gate_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci u32 reg_val; 39162306a36Sopenharmony_ci u32 mask; 39262306a36Sopenharmony_ci bool enabled = false; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci BUG_ON(!gate_exists(gate)); 39562306a36Sopenharmony_ci if (!gate_is_sw_controllable(gate)) 39662306a36Sopenharmony_ci return true; /* Nothing we can change */ 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci reg_val = __ccu_read(ccu, gate->offset); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* For a hardware/software gate, set which is in control */ 40162306a36Sopenharmony_ci if (gate_is_hw_controllable(gate)) { 40262306a36Sopenharmony_ci mask = (u32)1 << gate->hw_sw_sel_bit; 40362306a36Sopenharmony_ci if (gate_is_sw_managed(gate)) 40462306a36Sopenharmony_ci reg_val |= mask; 40562306a36Sopenharmony_ci else 40662306a36Sopenharmony_ci reg_val &= ~mask; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * If software is in control, enable or disable the gate. 41162306a36Sopenharmony_ci * If hardware is, clear the enabled bit for good measure. 41262306a36Sopenharmony_ci * If a software controlled gate can't be disabled, we're 41362306a36Sopenharmony_ci * required to write a 0 into the enable bit (but the gate 41462306a36Sopenharmony_ci * will be enabled). 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci mask = (u32)1 << gate->en_bit; 41762306a36Sopenharmony_ci if (gate_is_sw_managed(gate) && (enabled = gate_is_enabled(gate)) && 41862306a36Sopenharmony_ci !gate_is_no_disable(gate)) 41962306a36Sopenharmony_ci reg_val |= mask; 42062306a36Sopenharmony_ci else 42162306a36Sopenharmony_ci reg_val &= ~mask; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci __ccu_write(ccu, gate->offset, reg_val); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* For a hardware controlled gate, we're done */ 42662306a36Sopenharmony_ci if (!gate_is_sw_managed(gate)) 42762306a36Sopenharmony_ci return true; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* Otherwise wait for the gate to be in desired state */ 43062306a36Sopenharmony_ci return __ccu_wait_bit(ccu, gate->offset, gate->status_bit, enabled); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/* 43462306a36Sopenharmony_ci * Initialize a gate. Our desired state (hardware/software select, 43562306a36Sopenharmony_ci * and if software, its enable state) is committed to hardware 43662306a36Sopenharmony_ci * without the usual checks to see if it's already set up that way. 43762306a36Sopenharmony_ci * Returns true if successful, false otherwise. 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_cistatic bool gate_init(struct ccu_data *ccu, struct bcm_clk_gate *gate) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci if (!gate_exists(gate)) 44262306a36Sopenharmony_ci return true; 44362306a36Sopenharmony_ci return __gate_commit(ccu, gate); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* 44762306a36Sopenharmony_ci * Set a gate to enabled or disabled state. Does nothing if the 44862306a36Sopenharmony_ci * gate is not currently under software control, or if it is already 44962306a36Sopenharmony_ci * in the requested state. Returns true if successful, false 45062306a36Sopenharmony_ci * otherwise. CCU lock must be held. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_cistatic bool 45362306a36Sopenharmony_ci__clk_gate(struct ccu_data *ccu, struct bcm_clk_gate *gate, bool enable) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci bool ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!gate_exists(gate) || !gate_is_sw_managed(gate)) 45862306a36Sopenharmony_ci return true; /* Nothing to do */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (!enable && gate_is_no_disable(gate)) { 46162306a36Sopenharmony_ci pr_warn("%s: invalid gate disable request (ignoring)\n", 46262306a36Sopenharmony_ci __func__); 46362306a36Sopenharmony_ci return true; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (enable == gate_is_enabled(gate)) 46762306a36Sopenharmony_ci return true; /* No change */ 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci gate_flip_enabled(gate); 47062306a36Sopenharmony_ci ret = __gate_commit(ccu, gate); 47162306a36Sopenharmony_ci if (!ret) 47262306a36Sopenharmony_ci gate_flip_enabled(gate); /* Revert the change */ 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return ret; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/* Enable or disable a gate. Returns 0 if successful, -EIO otherwise */ 47862306a36Sopenharmony_cistatic int clk_gate(struct ccu_data *ccu, const char *name, 47962306a36Sopenharmony_ci struct bcm_clk_gate *gate, bool enable) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci unsigned long flags; 48262306a36Sopenharmony_ci bool success; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* 48562306a36Sopenharmony_ci * Avoid taking the lock if we can. We quietly ignore 48662306a36Sopenharmony_ci * requests to change state that don't make sense. 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci if (!gate_exists(gate) || !gate_is_sw_managed(gate)) 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci if (!enable && gate_is_no_disable(gate)) 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci flags = ccu_lock(ccu); 49462306a36Sopenharmony_ci __ccu_write_enable(ccu); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci success = __clk_gate(ccu, gate, enable); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci __ccu_write_disable(ccu); 49962306a36Sopenharmony_ci ccu_unlock(ccu, flags); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (success) 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci pr_err("%s: failed to %s gate for %s\n", __func__, 50562306a36Sopenharmony_ci enable ? "enable" : "disable", name); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return -EIO; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/* Hysteresis operations */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/* 51362306a36Sopenharmony_ci * If a clock gate requires a turn-off delay it will have 51462306a36Sopenharmony_ci * "hysteresis" register bits defined. The first, if set, enables 51562306a36Sopenharmony_ci * the delay; and if enabled, the second bit determines whether the 51662306a36Sopenharmony_ci * delay is "low" or "high" (1 means high). For now, if it's 51762306a36Sopenharmony_ci * defined for a clock, we set it. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_cistatic bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci u32 offset; 52262306a36Sopenharmony_ci u32 reg_val; 52362306a36Sopenharmony_ci u32 mask; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!hyst_exists(hyst)) 52662306a36Sopenharmony_ci return true; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci offset = hyst->offset; 52962306a36Sopenharmony_ci mask = (u32)1 << hyst->en_bit; 53062306a36Sopenharmony_ci mask |= (u32)1 << hyst->val_bit; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci reg_val = __ccu_read(ccu, offset); 53362306a36Sopenharmony_ci reg_val |= mask; 53462306a36Sopenharmony_ci __ccu_write(ccu, offset, reg_val); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return true; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/* Trigger operations */ 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/* 54262306a36Sopenharmony_ci * Caller must ensure CCU lock is held and access is enabled. 54362306a36Sopenharmony_ci * Returns true if successful, false otherwise. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistatic bool __clk_trigger(struct ccu_data *ccu, struct bcm_clk_trig *trig) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci /* Trigger the clock and wait for it to finish */ 54862306a36Sopenharmony_ci __ccu_write(ccu, trig->offset, 1 << trig->bit); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return __ccu_wait_bit(ccu, trig->offset, trig->bit, false); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* Divider operations */ 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/* Read a divider value and return the scaled divisor it represents. */ 55662306a36Sopenharmony_cistatic u64 divider_read_scaled(struct ccu_data *ccu, struct bcm_clk_div *div) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci unsigned long flags; 55962306a36Sopenharmony_ci u32 reg_val; 56062306a36Sopenharmony_ci u32 reg_div; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (divider_is_fixed(div)) 56362306a36Sopenharmony_ci return (u64)div->u.fixed; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci flags = ccu_lock(ccu); 56662306a36Sopenharmony_ci reg_val = __ccu_read(ccu, div->u.s.offset); 56762306a36Sopenharmony_ci ccu_unlock(ccu, flags); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Extract the full divider field from the register value */ 57062306a36Sopenharmony_ci reg_div = bitfield_extract(reg_val, div->u.s.shift, div->u.s.width); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Return the scaled divisor value it represents */ 57362306a36Sopenharmony_ci return scaled_div_value(div, reg_div); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* 57762306a36Sopenharmony_ci * Convert a divider's scaled divisor value into its recorded form 57862306a36Sopenharmony_ci * and commit it into the hardware divider register. 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * Returns 0 on success. Returns -EINVAL for invalid arguments. 58162306a36Sopenharmony_ci * Returns -ENXIO if gating failed, and -EIO if a trigger failed. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_cistatic int __div_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, 58462306a36Sopenharmony_ci struct bcm_clk_div *div, struct bcm_clk_trig *trig) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci bool enabled; 58762306a36Sopenharmony_ci u32 reg_div; 58862306a36Sopenharmony_ci u32 reg_val; 58962306a36Sopenharmony_ci int ret = 0; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci BUG_ON(divider_is_fixed(div)); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* 59462306a36Sopenharmony_ci * If we're just initializing the divider, and no initial 59562306a36Sopenharmony_ci * state was defined in the device tree, we just find out 59662306a36Sopenharmony_ci * what its current value is rather than updating it. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci if (div->u.s.scaled_div == BAD_SCALED_DIV_VALUE) { 59962306a36Sopenharmony_ci reg_val = __ccu_read(ccu, div->u.s.offset); 60062306a36Sopenharmony_ci reg_div = bitfield_extract(reg_val, div->u.s.shift, 60162306a36Sopenharmony_ci div->u.s.width); 60262306a36Sopenharmony_ci div->u.s.scaled_div = scaled_div_value(div, reg_div); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Convert the scaled divisor to the value we need to record */ 60862306a36Sopenharmony_ci reg_div = divider(div, div->u.s.scaled_div); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Clock needs to be enabled before changing the rate */ 61162306a36Sopenharmony_ci enabled = __is_clk_gate_enabled(ccu, gate); 61262306a36Sopenharmony_ci if (!enabled && !__clk_gate(ccu, gate, true)) { 61362306a36Sopenharmony_ci ret = -ENXIO; 61462306a36Sopenharmony_ci goto out; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Replace the divider value and record the result */ 61862306a36Sopenharmony_ci reg_val = __ccu_read(ccu, div->u.s.offset); 61962306a36Sopenharmony_ci reg_val = bitfield_replace(reg_val, div->u.s.shift, div->u.s.width, 62062306a36Sopenharmony_ci reg_div); 62162306a36Sopenharmony_ci __ccu_write(ccu, div->u.s.offset, reg_val); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* If the trigger fails we still want to disable the gate */ 62462306a36Sopenharmony_ci if (!__clk_trigger(ccu, trig)) 62562306a36Sopenharmony_ci ret = -EIO; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Disable the clock again if it was disabled to begin with */ 62862306a36Sopenharmony_ci if (!enabled && !__clk_gate(ccu, gate, false)) 62962306a36Sopenharmony_ci ret = ret ? ret : -ENXIO; /* return first error */ 63062306a36Sopenharmony_ciout: 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci/* 63562306a36Sopenharmony_ci * Initialize a divider by committing our desired state to hardware 63662306a36Sopenharmony_ci * without the usual checks to see if it's already set up that way. 63762306a36Sopenharmony_ci * Returns true if successful, false otherwise. 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_cistatic bool div_init(struct ccu_data *ccu, struct bcm_clk_gate *gate, 64062306a36Sopenharmony_ci struct bcm_clk_div *div, struct bcm_clk_trig *trig) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci if (!divider_exists(div) || divider_is_fixed(div)) 64362306a36Sopenharmony_ci return true; 64462306a36Sopenharmony_ci return !__div_commit(ccu, gate, div, trig); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic int divider_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, 64862306a36Sopenharmony_ci struct bcm_clk_div *div, struct bcm_clk_trig *trig, 64962306a36Sopenharmony_ci u64 scaled_div) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci unsigned long flags; 65262306a36Sopenharmony_ci u64 previous; 65362306a36Sopenharmony_ci int ret; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci BUG_ON(divider_is_fixed(div)); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci previous = div->u.s.scaled_div; 65862306a36Sopenharmony_ci if (previous == scaled_div) 65962306a36Sopenharmony_ci return 0; /* No change */ 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci div->u.s.scaled_div = scaled_div; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci flags = ccu_lock(ccu); 66462306a36Sopenharmony_ci __ccu_write_enable(ccu); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci ret = __div_commit(ccu, gate, div, trig); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci __ccu_write_disable(ccu); 66962306a36Sopenharmony_ci ccu_unlock(ccu, flags); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (ret) 67262306a36Sopenharmony_ci div->u.s.scaled_div = previous; /* Revert the change */ 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* Common clock rate helpers */ 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci/* 68162306a36Sopenharmony_ci * Implement the common clock framework recalc_rate method, taking 68262306a36Sopenharmony_ci * into account a divider and an optional pre-divider. The 68362306a36Sopenharmony_ci * pre-divider register pointer may be NULL. 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_cistatic unsigned long clk_recalc_rate(struct ccu_data *ccu, 68662306a36Sopenharmony_ci struct bcm_clk_div *div, struct bcm_clk_div *pre_div, 68762306a36Sopenharmony_ci unsigned long parent_rate) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci u64 scaled_parent_rate; 69062306a36Sopenharmony_ci u64 scaled_div; 69162306a36Sopenharmony_ci u64 result; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (!divider_exists(div)) 69462306a36Sopenharmony_ci return parent_rate; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (parent_rate > (unsigned long)LONG_MAX) 69762306a36Sopenharmony_ci return 0; /* actually this would be a caller bug */ 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * If there is a pre-divider, divide the scaled parent rate 70162306a36Sopenharmony_ci * by the pre-divider value first. In this case--to improve 70262306a36Sopenharmony_ci * accuracy--scale the parent rate by *both* the pre-divider 70362306a36Sopenharmony_ci * value and the divider before actually computing the 70462306a36Sopenharmony_ci * result of the pre-divider. 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci * If there's only one divider, just scale the parent rate. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci if (pre_div && divider_exists(pre_div)) { 70962306a36Sopenharmony_ci u64 scaled_rate; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci scaled_rate = scale_rate(pre_div, parent_rate); 71262306a36Sopenharmony_ci scaled_rate = scale_rate(div, scaled_rate); 71362306a36Sopenharmony_ci scaled_div = divider_read_scaled(ccu, pre_div); 71462306a36Sopenharmony_ci scaled_parent_rate = DIV_ROUND_CLOSEST_ULL(scaled_rate, 71562306a36Sopenharmony_ci scaled_div); 71662306a36Sopenharmony_ci } else { 71762306a36Sopenharmony_ci scaled_parent_rate = scale_rate(div, parent_rate); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* 72162306a36Sopenharmony_ci * Get the scaled divisor value, and divide the scaled 72262306a36Sopenharmony_ci * parent rate by that to determine this clock's resulting 72362306a36Sopenharmony_ci * rate. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci scaled_div = divider_read_scaled(ccu, div); 72662306a36Sopenharmony_ci result = DIV_ROUND_CLOSEST_ULL(scaled_parent_rate, scaled_div); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return (unsigned long)result; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci/* 73262306a36Sopenharmony_ci * Compute the output rate produced when a given parent rate is fed 73362306a36Sopenharmony_ci * into two dividers. The pre-divider can be NULL, and even if it's 73462306a36Sopenharmony_ci * non-null it may be nonexistent. It's also OK for the divider to 73562306a36Sopenharmony_ci * be nonexistent, and in that case the pre-divider is also ignored. 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * If scaled_div is non-null, it is used to return the scaled divisor 73862306a36Sopenharmony_ci * value used by the (downstream) divider to produce that rate. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_cistatic long round_rate(struct ccu_data *ccu, struct bcm_clk_div *div, 74162306a36Sopenharmony_ci struct bcm_clk_div *pre_div, 74262306a36Sopenharmony_ci unsigned long rate, unsigned long parent_rate, 74362306a36Sopenharmony_ci u64 *scaled_div) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci u64 scaled_parent_rate; 74662306a36Sopenharmony_ci u64 min_scaled_div; 74762306a36Sopenharmony_ci u64 max_scaled_div; 74862306a36Sopenharmony_ci u64 best_scaled_div; 74962306a36Sopenharmony_ci u64 result; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci BUG_ON(!divider_exists(div)); 75262306a36Sopenharmony_ci BUG_ON(!rate); 75362306a36Sopenharmony_ci BUG_ON(parent_rate > (u64)LONG_MAX); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * If there is a pre-divider, divide the scaled parent rate 75762306a36Sopenharmony_ci * by the pre-divider value first. In this case--to improve 75862306a36Sopenharmony_ci * accuracy--scale the parent rate by *both* the pre-divider 75962306a36Sopenharmony_ci * value and the divider before actually computing the 76062306a36Sopenharmony_ci * result of the pre-divider. 76162306a36Sopenharmony_ci * 76262306a36Sopenharmony_ci * If there's only one divider, just scale the parent rate. 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * For simplicity we treat the pre-divider as fixed (for now). 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_ci if (divider_exists(pre_div)) { 76762306a36Sopenharmony_ci u64 scaled_rate; 76862306a36Sopenharmony_ci u64 scaled_pre_div; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci scaled_rate = scale_rate(pre_div, parent_rate); 77162306a36Sopenharmony_ci scaled_rate = scale_rate(div, scaled_rate); 77262306a36Sopenharmony_ci scaled_pre_div = divider_read_scaled(ccu, pre_div); 77362306a36Sopenharmony_ci scaled_parent_rate = DIV_ROUND_CLOSEST_ULL(scaled_rate, 77462306a36Sopenharmony_ci scaled_pre_div); 77562306a36Sopenharmony_ci } else { 77662306a36Sopenharmony_ci scaled_parent_rate = scale_rate(div, parent_rate); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * Compute the best possible divider and ensure it is in 78162306a36Sopenharmony_ci * range. A fixed divider can't be changed, so just report 78262306a36Sopenharmony_ci * the best we can do. 78362306a36Sopenharmony_ci */ 78462306a36Sopenharmony_ci if (!divider_is_fixed(div)) { 78562306a36Sopenharmony_ci best_scaled_div = DIV_ROUND_CLOSEST_ULL(scaled_parent_rate, 78662306a36Sopenharmony_ci rate); 78762306a36Sopenharmony_ci min_scaled_div = scaled_div_min(div); 78862306a36Sopenharmony_ci max_scaled_div = scaled_div_max(div); 78962306a36Sopenharmony_ci if (best_scaled_div > max_scaled_div) 79062306a36Sopenharmony_ci best_scaled_div = max_scaled_div; 79162306a36Sopenharmony_ci else if (best_scaled_div < min_scaled_div) 79262306a36Sopenharmony_ci best_scaled_div = min_scaled_div; 79362306a36Sopenharmony_ci } else { 79462306a36Sopenharmony_ci best_scaled_div = divider_read_scaled(ccu, div); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* OK, figure out the resulting rate */ 79862306a36Sopenharmony_ci result = DIV_ROUND_CLOSEST_ULL(scaled_parent_rate, best_scaled_div); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (scaled_div) 80162306a36Sopenharmony_ci *scaled_div = best_scaled_div; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return (long)result; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/* Common clock parent helpers */ 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/* 80962306a36Sopenharmony_ci * For a given parent selector (register field) value, find the 81062306a36Sopenharmony_ci * index into a selector's parent_sel array that contains it. 81162306a36Sopenharmony_ci * Returns the index, or BAD_CLK_INDEX if it's not found. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_cistatic u8 parent_index(struct bcm_clk_sel *sel, u8 parent_sel) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci u8 i; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci BUG_ON(sel->parent_count > (u32)U8_MAX); 81862306a36Sopenharmony_ci for (i = 0; i < sel->parent_count; i++) 81962306a36Sopenharmony_ci if (sel->parent_sel[i] == parent_sel) 82062306a36Sopenharmony_ci return i; 82162306a36Sopenharmony_ci return BAD_CLK_INDEX; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci/* 82562306a36Sopenharmony_ci * Fetch the current value of the selector, and translate that into 82662306a36Sopenharmony_ci * its corresponding index in the parent array we registered with 82762306a36Sopenharmony_ci * the clock framework. 82862306a36Sopenharmony_ci * 82962306a36Sopenharmony_ci * Returns parent array index that corresponds with the value found, 83062306a36Sopenharmony_ci * or BAD_CLK_INDEX if the found value is out of range. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_cistatic u8 selector_read_index(struct ccu_data *ccu, struct bcm_clk_sel *sel) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci unsigned long flags; 83562306a36Sopenharmony_ci u32 reg_val; 83662306a36Sopenharmony_ci u32 parent_sel; 83762306a36Sopenharmony_ci u8 index; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* If there's no selector, there's only one parent */ 84062306a36Sopenharmony_ci if (!selector_exists(sel)) 84162306a36Sopenharmony_ci return 0; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* Get the value in the selector register */ 84462306a36Sopenharmony_ci flags = ccu_lock(ccu); 84562306a36Sopenharmony_ci reg_val = __ccu_read(ccu, sel->offset); 84662306a36Sopenharmony_ci ccu_unlock(ccu, flags); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci parent_sel = bitfield_extract(reg_val, sel->shift, sel->width); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* Look up that selector's parent array index and return it */ 85162306a36Sopenharmony_ci index = parent_index(sel, parent_sel); 85262306a36Sopenharmony_ci if (index == BAD_CLK_INDEX) 85362306a36Sopenharmony_ci pr_err("%s: out-of-range parent selector %u (%s 0x%04x)\n", 85462306a36Sopenharmony_ci __func__, parent_sel, ccu->name, sel->offset); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return index; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci/* 86062306a36Sopenharmony_ci * Commit our desired selector value to the hardware. 86162306a36Sopenharmony_ci * 86262306a36Sopenharmony_ci * Returns 0 on success. Returns -EINVAL for invalid arguments. 86362306a36Sopenharmony_ci * Returns -ENXIO if gating failed, and -EIO if a trigger failed. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_cistatic int 86662306a36Sopenharmony_ci__sel_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, 86762306a36Sopenharmony_ci struct bcm_clk_sel *sel, struct bcm_clk_trig *trig) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci u32 parent_sel; 87062306a36Sopenharmony_ci u32 reg_val; 87162306a36Sopenharmony_ci bool enabled; 87262306a36Sopenharmony_ci int ret = 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci BUG_ON(!selector_exists(sel)); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* 87762306a36Sopenharmony_ci * If we're just initializing the selector, and no initial 87862306a36Sopenharmony_ci * state was defined in the device tree, we just find out 87962306a36Sopenharmony_ci * what its current value is rather than updating it. 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci if (sel->clk_index == BAD_CLK_INDEX) { 88262306a36Sopenharmony_ci u8 index; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci reg_val = __ccu_read(ccu, sel->offset); 88562306a36Sopenharmony_ci parent_sel = bitfield_extract(reg_val, sel->shift, sel->width); 88662306a36Sopenharmony_ci index = parent_index(sel, parent_sel); 88762306a36Sopenharmony_ci if (index == BAD_CLK_INDEX) 88862306a36Sopenharmony_ci return -EINVAL; 88962306a36Sopenharmony_ci sel->clk_index = index; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci BUG_ON((u32)sel->clk_index >= sel->parent_count); 89562306a36Sopenharmony_ci parent_sel = sel->parent_sel[sel->clk_index]; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Clock needs to be enabled before changing the parent */ 89862306a36Sopenharmony_ci enabled = __is_clk_gate_enabled(ccu, gate); 89962306a36Sopenharmony_ci if (!enabled && !__clk_gate(ccu, gate, true)) 90062306a36Sopenharmony_ci return -ENXIO; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* Replace the selector value and record the result */ 90362306a36Sopenharmony_ci reg_val = __ccu_read(ccu, sel->offset); 90462306a36Sopenharmony_ci reg_val = bitfield_replace(reg_val, sel->shift, sel->width, parent_sel); 90562306a36Sopenharmony_ci __ccu_write(ccu, sel->offset, reg_val); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* If the trigger fails we still want to disable the gate */ 90862306a36Sopenharmony_ci if (!__clk_trigger(ccu, trig)) 90962306a36Sopenharmony_ci ret = -EIO; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* Disable the clock again if it was disabled to begin with */ 91262306a36Sopenharmony_ci if (!enabled && !__clk_gate(ccu, gate, false)) 91362306a36Sopenharmony_ci ret = ret ? ret : -ENXIO; /* return first error */ 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return ret; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci/* 91962306a36Sopenharmony_ci * Initialize a selector by committing our desired state to hardware 92062306a36Sopenharmony_ci * without the usual checks to see if it's already set up that way. 92162306a36Sopenharmony_ci * Returns true if successful, false otherwise. 92262306a36Sopenharmony_ci */ 92362306a36Sopenharmony_cistatic bool sel_init(struct ccu_data *ccu, struct bcm_clk_gate *gate, 92462306a36Sopenharmony_ci struct bcm_clk_sel *sel, struct bcm_clk_trig *trig) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci if (!selector_exists(sel)) 92762306a36Sopenharmony_ci return true; 92862306a36Sopenharmony_ci return !__sel_commit(ccu, gate, sel, trig); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci/* 93262306a36Sopenharmony_ci * Write a new value into a selector register to switch to a 93362306a36Sopenharmony_ci * different parent clock. Returns 0 on success, or an error code 93462306a36Sopenharmony_ci * (from __sel_commit()) otherwise. 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_cistatic int selector_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, 93762306a36Sopenharmony_ci struct bcm_clk_sel *sel, struct bcm_clk_trig *trig, 93862306a36Sopenharmony_ci u8 index) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci unsigned long flags; 94162306a36Sopenharmony_ci u8 previous; 94262306a36Sopenharmony_ci int ret; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci previous = sel->clk_index; 94562306a36Sopenharmony_ci if (previous == index) 94662306a36Sopenharmony_ci return 0; /* No change */ 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci sel->clk_index = index; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci flags = ccu_lock(ccu); 95162306a36Sopenharmony_ci __ccu_write_enable(ccu); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci ret = __sel_commit(ccu, gate, sel, trig); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci __ccu_write_disable(ccu); 95662306a36Sopenharmony_ci ccu_unlock(ccu, flags); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (ret) 95962306a36Sopenharmony_ci sel->clk_index = previous; /* Revert the change */ 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci return ret; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci/* Clock operations */ 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic int kona_peri_clk_enable(struct clk_hw *hw) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 96962306a36Sopenharmony_ci struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true); 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic void kona_peri_clk_disable(struct clk_hw *hw) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 97762306a36Sopenharmony_ci struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false); 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int kona_peri_clk_is_enabled(struct clk_hw *hw) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 98562306a36Sopenharmony_ci struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci return is_clk_gate_enabled(bcm_clk->ccu, gate) ? 1 : 0; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic unsigned long kona_peri_clk_recalc_rate(struct clk_hw *hw, 99162306a36Sopenharmony_ci unsigned long parent_rate) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 99462306a36Sopenharmony_ci struct peri_clk_data *data = bcm_clk->u.peri; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return clk_recalc_rate(bcm_clk->ccu, &data->div, &data->pre_div, 99762306a36Sopenharmony_ci parent_rate); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistatic long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, 100162306a36Sopenharmony_ci unsigned long *parent_rate) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 100462306a36Sopenharmony_ci struct bcm_clk_div *div = &bcm_clk->u.peri->div; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (!divider_exists(div)) 100762306a36Sopenharmony_ci return clk_hw_get_rate(hw); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Quietly avoid a zero rate */ 101062306a36Sopenharmony_ci return round_rate(bcm_clk->ccu, div, &bcm_clk->u.peri->pre_div, 101162306a36Sopenharmony_ci rate ? rate : 1, *parent_rate, NULL); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic int kona_peri_clk_determine_rate(struct clk_hw *hw, 101562306a36Sopenharmony_ci struct clk_rate_request *req) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 101862306a36Sopenharmony_ci struct clk_hw *current_parent; 101962306a36Sopenharmony_ci unsigned long parent_rate; 102062306a36Sopenharmony_ci unsigned long best_delta; 102162306a36Sopenharmony_ci unsigned long best_rate; 102262306a36Sopenharmony_ci u32 parent_count; 102362306a36Sopenharmony_ci long rate; 102462306a36Sopenharmony_ci u32 which; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* 102762306a36Sopenharmony_ci * If there is no other parent to choose, use the current one. 102862306a36Sopenharmony_ci * Note: We don't honor (or use) CLK_SET_RATE_NO_REPARENT. 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_ci WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); 103162306a36Sopenharmony_ci parent_count = (u32)bcm_clk->init_data.num_parents; 103262306a36Sopenharmony_ci if (parent_count < 2) { 103362306a36Sopenharmony_ci rate = kona_peri_clk_round_rate(hw, req->rate, 103462306a36Sopenharmony_ci &req->best_parent_rate); 103562306a36Sopenharmony_ci if (rate < 0) 103662306a36Sopenharmony_ci return rate; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci req->rate = rate; 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* Unless we can do better, stick with current parent */ 104362306a36Sopenharmony_ci current_parent = clk_hw_get_parent(hw); 104462306a36Sopenharmony_ci parent_rate = clk_hw_get_rate(current_parent); 104562306a36Sopenharmony_ci best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate); 104662306a36Sopenharmony_ci best_delta = abs(best_rate - req->rate); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci /* Check whether any other parent clock can produce a better result */ 104962306a36Sopenharmony_ci for (which = 0; which < parent_count; which++) { 105062306a36Sopenharmony_ci struct clk_hw *parent = clk_hw_get_parent_by_index(hw, which); 105162306a36Sopenharmony_ci unsigned long delta; 105262306a36Sopenharmony_ci unsigned long other_rate; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci BUG_ON(!parent); 105562306a36Sopenharmony_ci if (parent == current_parent) 105662306a36Sopenharmony_ci continue; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* We don't support CLK_SET_RATE_PARENT */ 105962306a36Sopenharmony_ci parent_rate = clk_hw_get_rate(parent); 106062306a36Sopenharmony_ci other_rate = kona_peri_clk_round_rate(hw, req->rate, 106162306a36Sopenharmony_ci &parent_rate); 106262306a36Sopenharmony_ci delta = abs(other_rate - req->rate); 106362306a36Sopenharmony_ci if (delta < best_delta) { 106462306a36Sopenharmony_ci best_delta = delta; 106562306a36Sopenharmony_ci best_rate = other_rate; 106662306a36Sopenharmony_ci req->best_parent_hw = parent; 106762306a36Sopenharmony_ci req->best_parent_rate = parent_rate; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci req->rate = best_rate; 107262306a36Sopenharmony_ci return 0; 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 107862306a36Sopenharmony_ci struct peri_clk_data *data = bcm_clk->u.peri; 107962306a36Sopenharmony_ci struct bcm_clk_sel *sel = &data->sel; 108062306a36Sopenharmony_ci struct bcm_clk_trig *trig; 108162306a36Sopenharmony_ci int ret; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci BUG_ON(index >= sel->parent_count); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* If there's only one parent we don't require a selector */ 108662306a36Sopenharmony_ci if (!selector_exists(sel)) 108762306a36Sopenharmony_ci return 0; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* 109062306a36Sopenharmony_ci * The regular trigger is used by default, but if there's a 109162306a36Sopenharmony_ci * pre-trigger we want to use that instead. 109262306a36Sopenharmony_ci */ 109362306a36Sopenharmony_ci trig = trigger_exists(&data->pre_trig) ? &data->pre_trig 109462306a36Sopenharmony_ci : &data->trig; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); 109762306a36Sopenharmony_ci if (ret == -ENXIO) { 109862306a36Sopenharmony_ci pr_err("%s: gating failure for %s\n", __func__, 109962306a36Sopenharmony_ci bcm_clk->init_data.name); 110062306a36Sopenharmony_ci ret = -EIO; /* Don't proliferate weird errors */ 110162306a36Sopenharmony_ci } else if (ret == -EIO) { 110262306a36Sopenharmony_ci pr_err("%s: %strigger failed for %s\n", __func__, 110362306a36Sopenharmony_ci trig == &data->pre_trig ? "pre-" : "", 110462306a36Sopenharmony_ci bcm_clk->init_data.name); 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci return ret; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic u8 kona_peri_clk_get_parent(struct clk_hw *hw) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 111362306a36Sopenharmony_ci struct peri_clk_data *data = bcm_clk->u.peri; 111462306a36Sopenharmony_ci u8 index; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci index = selector_read_index(bcm_clk->ccu, &data->sel); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* Not all callers would handle an out-of-range value gracefully */ 111962306a36Sopenharmony_ci return index == BAD_CLK_INDEX ? 0 : index; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, 112362306a36Sopenharmony_ci unsigned long parent_rate) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci struct kona_clk *bcm_clk = to_kona_clk(hw); 112662306a36Sopenharmony_ci struct peri_clk_data *data = bcm_clk->u.peri; 112762306a36Sopenharmony_ci struct bcm_clk_div *div = &data->div; 112862306a36Sopenharmony_ci u64 scaled_div = 0; 112962306a36Sopenharmony_ci int ret; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (parent_rate > (unsigned long)LONG_MAX) 113262306a36Sopenharmony_ci return -EINVAL; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (rate == clk_hw_get_rate(hw)) 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!divider_exists(div)) 113862306a36Sopenharmony_ci return rate == parent_rate ? 0 : -EINVAL; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* 114162306a36Sopenharmony_ci * A fixed divider can't be changed. (Nor can a fixed 114262306a36Sopenharmony_ci * pre-divider be, but for now we never actually try to 114362306a36Sopenharmony_ci * change that.) Tolerate a request for a no-op change. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci if (divider_is_fixed(&data->div)) 114662306a36Sopenharmony_ci return rate == parent_rate ? 0 : -EINVAL; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* 114962306a36Sopenharmony_ci * Get the scaled divisor value needed to achieve a clock 115062306a36Sopenharmony_ci * rate as close as possible to what was requested, given 115162306a36Sopenharmony_ci * the parent clock rate supplied. 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci (void)round_rate(bcm_clk->ccu, div, &data->pre_div, 115462306a36Sopenharmony_ci rate ? rate : 1, parent_rate, &scaled_div); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* 115762306a36Sopenharmony_ci * We aren't updating any pre-divider at this point, so 115862306a36Sopenharmony_ci * we'll use the regular trigger. 115962306a36Sopenharmony_ci */ 116062306a36Sopenharmony_ci ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, 116162306a36Sopenharmony_ci &data->trig, scaled_div); 116262306a36Sopenharmony_ci if (ret == -ENXIO) { 116362306a36Sopenharmony_ci pr_err("%s: gating failure for %s\n", __func__, 116462306a36Sopenharmony_ci bcm_clk->init_data.name); 116562306a36Sopenharmony_ci ret = -EIO; /* Don't proliferate weird errors */ 116662306a36Sopenharmony_ci } else if (ret == -EIO) { 116762306a36Sopenharmony_ci pr_err("%s: trigger failed for %s\n", __func__, 116862306a36Sopenharmony_ci bcm_clk->init_data.name); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci return ret; 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_cistruct clk_ops kona_peri_clk_ops = { 117562306a36Sopenharmony_ci .enable = kona_peri_clk_enable, 117662306a36Sopenharmony_ci .disable = kona_peri_clk_disable, 117762306a36Sopenharmony_ci .is_enabled = kona_peri_clk_is_enabled, 117862306a36Sopenharmony_ci .recalc_rate = kona_peri_clk_recalc_rate, 117962306a36Sopenharmony_ci .determine_rate = kona_peri_clk_determine_rate, 118062306a36Sopenharmony_ci .set_parent = kona_peri_clk_set_parent, 118162306a36Sopenharmony_ci .get_parent = kona_peri_clk_get_parent, 118262306a36Sopenharmony_ci .set_rate = kona_peri_clk_set_rate, 118362306a36Sopenharmony_ci}; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci/* Put a peripheral clock into its initial state */ 118662306a36Sopenharmony_cistatic bool __peri_clk_init(struct kona_clk *bcm_clk) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci struct ccu_data *ccu = bcm_clk->ccu; 118962306a36Sopenharmony_ci struct peri_clk_data *peri = bcm_clk->u.peri; 119062306a36Sopenharmony_ci const char *name = bcm_clk->init_data.name; 119162306a36Sopenharmony_ci struct bcm_clk_trig *trig; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci BUG_ON(bcm_clk->type != bcm_clk_peri); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (!policy_init(ccu, &peri->policy)) { 119662306a36Sopenharmony_ci pr_err("%s: error initializing policy for %s\n", 119762306a36Sopenharmony_ci __func__, name); 119862306a36Sopenharmony_ci return false; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci if (!gate_init(ccu, &peri->gate)) { 120162306a36Sopenharmony_ci pr_err("%s: error initializing gate for %s\n", __func__, name); 120262306a36Sopenharmony_ci return false; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci if (!hyst_init(ccu, &peri->hyst)) { 120562306a36Sopenharmony_ci pr_err("%s: error initializing hyst for %s\n", __func__, name); 120662306a36Sopenharmony_ci return false; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { 120962306a36Sopenharmony_ci pr_err("%s: error initializing divider for %s\n", __func__, 121062306a36Sopenharmony_ci name); 121162306a36Sopenharmony_ci return false; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* 121562306a36Sopenharmony_ci * For the pre-divider and selector, the pre-trigger is used 121662306a36Sopenharmony_ci * if it's present, otherwise we just use the regular trigger. 121762306a36Sopenharmony_ci */ 121862306a36Sopenharmony_ci trig = trigger_exists(&peri->pre_trig) ? &peri->pre_trig 121962306a36Sopenharmony_ci : &peri->trig; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (!div_init(ccu, &peri->gate, &peri->pre_div, trig)) { 122262306a36Sopenharmony_ci pr_err("%s: error initializing pre-divider for %s\n", __func__, 122362306a36Sopenharmony_ci name); 122462306a36Sopenharmony_ci return false; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (!sel_init(ccu, &peri->gate, &peri->sel, trig)) { 122862306a36Sopenharmony_ci pr_err("%s: error initializing selector for %s\n", __func__, 122962306a36Sopenharmony_ci name); 123062306a36Sopenharmony_ci return false; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci return true; 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic bool __kona_clk_init(struct kona_clk *bcm_clk) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci switch (bcm_clk->type) { 123962306a36Sopenharmony_ci case bcm_clk_peri: 124062306a36Sopenharmony_ci return __peri_clk_init(bcm_clk); 124162306a36Sopenharmony_ci default: 124262306a36Sopenharmony_ci BUG(); 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci return false; 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci/* Set a CCU and all its clocks into their desired initial state */ 124862306a36Sopenharmony_cibool __init kona_ccu_init(struct ccu_data *ccu) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci unsigned long flags; 125162306a36Sopenharmony_ci unsigned int which; 125262306a36Sopenharmony_ci struct kona_clk *kona_clks = ccu->kona_clks; 125362306a36Sopenharmony_ci bool success = true; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci flags = ccu_lock(ccu); 125662306a36Sopenharmony_ci __ccu_write_enable(ccu); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci for (which = 0; which < ccu->clk_num; which++) { 125962306a36Sopenharmony_ci struct kona_clk *bcm_clk = &kona_clks[which]; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (!bcm_clk->ccu) 126262306a36Sopenharmony_ci continue; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci success &= __kona_clk_init(bcm_clk); 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci __ccu_write_disable(ccu); 126862306a36Sopenharmony_ci ccu_unlock(ccu, flags); 126962306a36Sopenharmony_ci return success; 127062306a36Sopenharmony_ci} 1271