Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright (C) 2016 Maxime Ripard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Maxime Ripard <maxime.ripard@free-electrons.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include "ccu_phase.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) static int ccu_phase_get_phase(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 	struct ccu_phase *phase = hw_to_ccu_phase(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 	struct clk_hw *parent, *grandparent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 	unsigned int parent_rate, grandparent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 	u16 step, parent_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 	u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	u8 delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	reg = readl(phase->common.base + phase->common.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	delay = (reg >> phase->shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	delay &= (1 << phase->width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	if (!delay)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 		return 180;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	/* Get our parent clock, it's the one that can adjust its rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	parent = clk_hw_get_parent(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	/* And its rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	parent_rate = clk_hw_get_rate(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	if (!parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	/* Now, get our parent's parent (most likely some PLL) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	grandparent = clk_hw_get_parent(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	if (!grandparent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	/* And its rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	grandparent_rate = clk_hw_get_rate(grandparent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	if (!grandparent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	/* Get our parent clock divider */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	parent_div = grandparent_rate / parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	step = DIV_ROUND_CLOSEST(360, parent_div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	return delay * step;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) static int ccu_phase_set_phase(struct clk_hw *hw, int degrees)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	struct ccu_phase *phase = hw_to_ccu_phase(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	struct clk_hw *parent, *grandparent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	unsigned int parent_rate, grandparent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	u8 delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	/* Get our parent clock, it's the one that can adjust its rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	parent = clk_hw_get_parent(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	/* And its rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	parent_rate = clk_hw_get_rate(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	if (!parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	/* Now, get our parent's parent (most likely some PLL) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	grandparent = clk_hw_get_parent(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	if (!grandparent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	/* And its rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	grandparent_rate = clk_hw_get_rate(grandparent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	if (!grandparent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	if (degrees != 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 		u16 step, parent_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		/* Get our parent divider */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		parent_div = grandparent_rate / parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		 * We can only outphase the clocks by multiple of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		 * PLL's period.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		 * Since our parent clock is only a divider, and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		 * formula to get the outphasing in degrees is deg =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		 * 360 * delta / period
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		 * If we simplify this formula, we can see that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		 * only thing that we're concerned about is the number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		 * of period we want to outphase our clock from, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		 * the divider set by our parent clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		step = DIV_ROUND_CLOSEST(360, parent_div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		delay = DIV_ROUND_CLOSEST(degrees, step);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		delay = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	spin_lock_irqsave(phase->common.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	reg = readl(phase->common.base + phase->common.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	reg &= ~GENMASK(phase->width + phase->shift - 1, phase->shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	writel(reg | (delay << phase->shift),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	       phase->common.base + phase->common.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	spin_unlock_irqrestore(phase->common.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) const struct clk_ops ccu_phase_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	.get_phase	= ccu_phase_get_phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	.set_phase	= ccu_phase_set_phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };