提交 dc2535be 编写于 作者: L Linus Torvalds

Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk subsystem updates from Stephen Boyd:
 "We have a fairly balanced mix of clk driver updates and clk framework
  updates this time around. It's the usual pile of new drivers for new
  hardware out there and the normal small fixes and updates, but then we
  have some core framework changes too.

  In the core framework, we introduce support for a clk_get_optional()
  API to get clks that may not always be populated and a way to devm
  manage clkdev lookups registered by provider drivers. We also do some
  refactoring to simplify the interface between clkdev and the common
  clk framework so we can reuse the DT parsing and clk_get() path in
  provider drivers in the future. This work will continue in the next
  few cycles while we convert how providers specify clk parents.

  On the driver side, the biggest part of the dirstat is the Amlogic clk
  driver that got support for the G12A SoC. It dominates with almost
  half the overall diff, while the second largest part of the diff is in
  the i.MX clk driver that gained support for imx8mm SoCs. After that,
  we have the Actions Semiconductor and Qualcomm drivers rounding out
  the big part of the dirstat because they both got new hardware support
  for SoCs. The rest is just various updates and non-critical fixes for
  existing drivers.

  Core:
   - Convert a few clk bindings to JSON schema format
   - Add a {devm_}clk_get_optional() API
   - Add devm_clk_hw_register_clkdev() API to manage clkdev lookups
   - Start rewriting clk parent registration and supporting device links
     by moving around code that supports clk_get() and DT parsing of the
     'clocks' property

  New Drivers:
   - Add Qualcomm MSM8998 RPM managed clks
   - IPA clk support on Qualcomm RPMh clk controllers
   - Actions Semi S500 SoC clk support
   - Support for fixed rate clks populated from an MMIO register
   - Add RPC (QSPI/HyperFLASH) clocks on Renesas R-Car V3H
   - Add TMU (timer) clocks on Renesas RZ/G2E
   - Add Amlogic G12A Always-On Clock Controller
   - Add 32k clock generation for Amlogic AXG
   - Add support for the Mali GPU clocks on Amlogic Meson8
   - Add Amlogic G12A EE clock controller driver
   - Add missing CANFD clocks on Renesas RZ/G2M and RZ/G2E
   - Add i.MX8MM SoC clk driver support

  Removed Drivers:
   - Remove clps711x driver as the board support is gone

  Updates:
   - 3rd ECO fix for Mediatek MT2712 SoCs
   - Updates for Qualcomm MSM8998 GCC clks
   - Random static analysis fixes for clk drivers
   - Support for sleeping gpios in the clk-gpio type
   - Minor fixes for STM32MP1 clk driver (parents, critical flag, etc.)
   - Split LCDC into two clks on the Marvell MMP2 SoC
   - Various DT of_node refcount fixes
   - Get rid of CLK_IS_BASIC from TI code (yay!)
   - TI Autoidle clk support
   - Fix Amlogic Meson8 APB clock ID name
   - Claim input clocks through DT for Amlogic AXG and GXBB
   - Correct the DU (display unit) parent clock on Renesas RZ/G2E
   - Exynos5433 IMEM CMU crypto clk support (SlimSS)
   - Fix for the PLL-MIPI on the Allwinner A23
   - Fix Rockchip rk3328 PLL rate calculation
   - Add SET_RATE_PARENT flag on display clk of Rockhip rk3066
   - i.MX SCU clk driver clk_set_parent() and cpufreq support"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (150 commits)
  dt-bindings: clock: imx8mq: Fix numbering overlaps and gaps
  clk: ti: clkctrl: Fix clkdm_name regression for TI_CLK_CLKCTRL_COMPAT
  clk: fixup default index for of_clk_get_by_name()
  clk: Move of_clk_*() APIs into clk.c from clkdev.c
  clk: Inform the core about consumer devices
  clk: Introduce of_clk_get_hw_from_clkspec()
  clk: core: clarify the check for runtime PM
  clk: Combine __clk_get() and __clk_create_clk()
  clk: imx8mq: add GPIO clocks to clock tree
  clk: mediatek: correct cpu clock name for MT8173 SoC
  clk: imx: Refactor entire sccg pll clk
  clk: imx: scu: add cpu frequency scaling support
  clk: mediatek: Mark bus and DRAM related clocks as critical
  clk: mediatek: Add flags to mtk_gate
  clk: mediatek: Add MUX_FLAGS macro
  clk: qcom: gcc-sdm845: Define parent of PCIe PIPE clocks
  clk: ingenic: Remove set but not used variable 'enable'
  clk: at91: programmable: remove unneeded register read
  clk: mediatek: using CLK_MUX_ROUND_CLOSEST for the clock of dpi1_sel
  clk: mediatek: add MUX_GATE_FLAGS_2
  ...
......@@ -2,13 +2,14 @@
The Actions Semi Owl Clock Management Unit generates and supplies clock
to various controllers within the SoC. The clock binding described here is
applicable to S900 and S700 SoC's.
applicable to S900, S700 and S500 SoC's.
Required Properties:
- compatible: should be one of the following,
"actions,s900-cmu"
"actions,s700-cmu"
"actions,s500-cmu"
- reg: physical base address of the controller and length of memory mapped
region.
- clocks: Reference to the parent clocks ("hosc", "losc")
......@@ -19,8 +20,8 @@ Each clock is assigned an identifier, and client nodes can use this identifier
to specify the clock which they consume.
All available clocks are defined as preprocessor macros in corresponding
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h header and can be
used in device tree sources.
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or
actions,s500-cmu.h header and can be used in device tree sources.
External clocks:
......
......@@ -10,6 +10,7 @@ Required Properties:
- GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
- GXM (S912) : "amlogic,meson-gxm-aoclkc"
- AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc"
- G12A (S905X2, S905D2, S905Y2) : "amlogic,meson-g12a-aoclkc"
followed by the common "amlogic,meson-gx-aoclkc"
- clocks: list of clock phandle, one for each entry clock-names.
- clock-names: should contain the following:
......
......@@ -9,6 +9,7 @@ Required Properties:
"amlogic,gxbb-clkc" for GXBB SoC,
"amlogic,gxl-clkc" for GXL and GXM SoC,
"amlogic,axg-clkc" for AXG SoC.
"amlogic,g12a-clkc" for G12A SoC.
- clocks : list of clock phandle, one for each entry clock-names.
- clock-names : should contain the following:
* "xtal": the platform xtal
......
......@@ -50,6 +50,8 @@ Required Properties:
IPs.
- "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1
which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs.
- "samsung,exynos5433-cmu-imem" - clock controller compatible for CMU_IMEM
which generates clocks for SSS (Security SubSystem) and SlimSSS IPs.
- reg: physical base address of the controller and length of memory mapped
region.
......@@ -168,6 +170,12 @@ Required Properties:
- aclk_cam1_400
- aclk_cam1_552
Input clocks for imem clock controller:
- oscclk
- aclk_imem_sssx_266
- aclk_imem_266
- aclk_imem_200
Optional properties:
- power-domains: a phandle to respective power domain node as described by
generic PM domain bindings (see power/power_domain.txt for more
......@@ -469,6 +477,21 @@ Example 2: Examples of clock controller nodes are listed below.
power-domains = <&pd_cam1>;
};
cmu_imem: clock-controller@11060000 {
compatible = "samsung,exynos5433-cmu-imem";
reg = <0x11060000 0x1000>;
#clock-cells = <1>;
clock-names = "oscclk",
"aclk_imem_sssx_266",
"aclk_imem_266",
"aclk_imem_200";
clocks = <&xxti>,
<&cmu_top CLK_DIV_ACLK_IMEM_SSSX_266>,
<&cmu_top CLK_DIV_ACLK_IMEM_266>,
<&cmu_top CLK_DIV_ACLK_IMEM_200>;
};
Example 3: UART controller node that consumes the clock generated by the clock
controller.
......
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/fixed-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Binding for simple fixed-rate clock sources
maintainers:
- Michael Turquette <mturquette@baylibre.com>
- Stephen Boyd <sboyd@kernel.org>
properties:
compatible:
const: fixed-clock
"#clock-cells":
const: 0
clock-frequency: true
clock-accuracy:
description: accuracy of clock in ppb (parts per billion).
$ref: /schemas/types.yaml#/definitions/uint32
clock-output-names:
maxItems: 1
required:
- compatible
- "#clock-cells"
- clock-frequency
additionalProperties: false
examples:
- |
clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
clock-accuracy = <100>;
};
...
Binding for simple fixed factor rate clock sources.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "fixed-factor-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clock-div: fixed divider.
- clock-mult: fixed multiplier.
- clocks: parent clock.
Optional properties:
- clock-output-names : From common clock binding.
Some clocks that require special treatments are also handled by that
driver, with the compatibles:
- allwinner,sun4i-a10-pll3-2x-clk
Example:
clock {
compatible = "fixed-factor-clock";
clocks = <&parentclk>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/fixed-factor-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Binding for simple fixed factor rate clock sources
maintainers:
- Michael Turquette <mturquette@baylibre.com>
- Stephen Boyd <sboyd@kernel.org>
properties:
compatible:
enum:
- allwinner,sun4i-a10-pll3-2x-clk
- fixed-factor-clock
"#clock-cells":
const: 0
clocks:
maxItems: 1
clock-div:
description: Fixed divider
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
clock-mult:
description: Fixed multiplier
$ref: /schemas/types.yaml#/definitions/uint32
clock-output-names:
maxItems: 1
required:
- compatible
- clocks
- "#clock-cells"
- clock-div
- clock-mult
additionalProperties: false
examples:
- |
clock {
compatible = "fixed-factor-clock";
clocks = <&parentclk>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
};
...
Binding for simple fixed-rate clock sources.
Binding for simple memory mapped io fixed-rate clock sources.
The driver reads a clock frequency value from a single 32-bit memory mapped
I/O register and registers it as a fixed rate clock.
It was designed for test systems, like FPGA, not for complete, finished SoCs.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "fixed-clock".
- compatible : shall be "fixed-mmio-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clock-frequency : frequency of clock in Hz. Should be a single cell.
- reg : Address and length of the clock value register set.
Optional properties:
- clock-accuracy : accuracy of clock in ppb (parts per billion).
Should be a single cell.
- clock-output-names : From common clock binding.
Example:
clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
clock-accuracy = <100>;
};
sysclock: sysclock@fd020004 {
#clock-cells = <0>;
compatible = "fixed-mmio-clock";
reg = <0xfd020004 0x4>;
};
* Clock bindings for NXP i.MX8M Mini
Required properties:
- compatible: Should be "fsl,imx8mm-ccm"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include the following entries:
- "osc_32k"
- "osc_24m"
- "clk_ext1"
- "clk_ext2"
- "clk_ext3"
- "clk_ext4"
clk: clock-controller@30380000 {
compatible = "fsl,imx8mm-ccm";
reg = <0x0 0x30380000 0x0 0x10000>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
<&clk_ext3>, <&clk_ext4>;
clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4";
};
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mm-clock.h
for the full list of i.MX8M Mini clock IDs.
......@@ -16,6 +16,7 @@ Required properties :
"qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc"
"qcom,rpmcc-msm8996", "qcom,rpmcc"
"qcom,rpmcc-msm8998", "qcom,rpmcc"
"qcom,rpmcc-qcs404", "qcom,rpmcc"
- #clock-cells : shall contain 1
......
......@@ -242,9 +242,11 @@ certainly invest a bit more effort into libata core layer).
CLOCK
devm_clk_get()
devm_clk_get_optional()
devm_clk_put()
devm_clk_hw_register()
devm_of_clk_add_hw_provider()
devm_clk_hw_register_clkdev()
DMA
dmaenginem_async_device_register()
......
......@@ -1002,8 +1002,10 @@ static int _enable_clocks(struct omap_hwmod *oh)
clk_enable(oh->_clk);
list_for_each_entry(os, &oh->slave_ports, node) {
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
omap2_clk_deny_idle(os->_clk);
clk_enable(os->_clk);
}
}
/* The opt clocks are controlled by the device driver. */
......@@ -1055,8 +1057,10 @@ static int _disable_clocks(struct omap_hwmod *oh)
clk_disable(oh->_clk);
list_for_each_entry(os, &oh->slave_ports, node) {
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
clk_disable(os->_clk);
omap2_clk_allow_idle(os->_clk);
}
}
if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
......@@ -2436,9 +2440,13 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh)
continue;
if (os->flags & OCPIF_SWSUP_IDLE) {
/* XXX omap_iclk_deny_idle(c); */
/*
* we might have multiple users of one iclk with
* different requirements, disable autoidle when
* the module is enabled, e.g. dss iclk
*/
} else {
/* XXX omap_iclk_allow_idle(c); */
/* we are enabling autoidle afterwards anyways */
clk_enable(os->_clk);
}
}
......
......@@ -18,7 +18,7 @@
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_data/x86/clk-lpss.h>
#include <linux/platform_data/x86/pmc_atom.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
......
......@@ -290,6 +290,12 @@ config COMMON_CLK_BD718XX
This driver supports ROHM BD71837 and ROHM BD71847
PMICs clock gates.
config COMMON_CLK_FIXED_MMIO
bool "Clock driver for Memory Mapped Fixed values"
depends on COMMON_CLK && OF
help
Support for Memory Mapped IO Fixed clocks
source "drivers/clk/actions/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
......
......@@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
......@@ -78,7 +79,7 @@ obj-$(CONFIG_ARCH_K3) += keystone/
obj-$(CONFIG_ARCH_KEYSTONE) += keystone/
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
obj-y += mediatek/
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_MACH_PIC32) += microchip/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
......
......@@ -9,6 +9,11 @@ if CLK_ACTIONS
# SoC Drivers
config CLK_OWL_S500
bool "Support for the Actions Semi OWL S500 clocks"
depends on ARCH_ACTIONS || COMPILE_TEST
default ARCH_ACTIONS
config CLK_OWL_S700
bool "Support for the Actions Semi OWL S700 clocks"
depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST
......
......@@ -10,5 +10,6 @@ clk-owl-y += owl-pll.o
clk-owl-y += owl-reset.o
# SoC support
obj-$(CONFIG_CLK_OWL_S500) += owl-s500.o
obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o
obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o
......@@ -179,7 +179,7 @@ static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate,
regmap_write(common->regmap, pll_hw->reg, reg);
udelay(PLL_STABILITY_WAIT_US);
udelay(pll_hw->delay);
return 0;
}
......
......@@ -13,6 +13,8 @@
#include "owl-common.h"
#define OWL_PLL_DEF_DELAY 50
/* last entry should have rate = 0 */
struct clk_pll_table {
unsigned int val;
......@@ -27,6 +29,7 @@ struct owl_pll_hw {
u8 width;
u8 min_mul;
u8 max_mul;
u8 delay;
const struct clk_pll_table *table;
};
......@@ -36,7 +39,7 @@ struct owl_pll {
};
#define OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, _max_mul, _table) \
_width, _min_mul, _max_mul, _delay, _table) \
{ \
.reg = _reg, \
.bfreq = _bfreq, \
......@@ -45,6 +48,7 @@ struct owl_pll {
.width = _width, \
.min_mul = _min_mul, \
.max_mul = _max_mul, \
.delay = _delay, \
.table = _table, \
}
......@@ -52,8 +56,8 @@ struct owl_pll {
_shift, _width, _min_mul, _max_mul, _table, _flags) \
struct owl_pll _struct = { \
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, \
_max_mul, _table), \
_width, _min_mul, _max_mul, \
OWL_PLL_DEF_DELAY, _table), \
.common = { \
.regmap = NULL, \
.hw.init = CLK_HW_INIT(_name, \
......@@ -67,8 +71,23 @@ struct owl_pll {
_shift, _width, _min_mul, _max_mul, _table, _flags) \
struct owl_pll _struct = { \
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, \
_max_mul, _table), \
_width, _min_mul, _max_mul, \
OWL_PLL_DEF_DELAY, _table), \
.common = { \
.regmap = NULL, \
.hw.init = CLK_HW_INIT_NO_PARENT(_name, \
&owl_pll_ops, \
_flags), \
}, \
}
#define OWL_PLL_NO_PARENT_DELAY(_struct, _name, _reg, _bfreq, _bit_idx, \
_shift, _width, _min_mul, _max_mul, _delay, _table, \
_flags) \
struct owl_pll _struct = { \
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, _max_mul, \
_delay, _table), \
.common = { \
.regmap = NULL, \
.hw.init = CLK_HW_INIT_NO_PARENT(_name, \
......@@ -78,7 +97,6 @@ struct owl_pll {
}
#define mul_mask(m) ((1 << ((m)->width)) - 1)
#define PLL_STABILITY_WAIT_US (50)
static inline struct owl_pll *hw_to_owl_pll(const struct clk_hw *hw)
{
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Actions Semi Owl S500 SoC clock driver
*
* Copyright (c) 2014 Actions Semi Inc.
* Author: David Liu <liuwei@actions-semi.com>
*
* Copyright (c) 2018 Linaro Ltd.
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
*
* Copyright (c) 2018 LSI-TEC - Caninos Loucos
* Author: Edgar Bernardi Righi <edgar.righi@lsitec.org.br>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "owl-common.h"
#include "owl-composite.h"
#include "owl-divider.h"
#include "owl-factor.h"
#include "owl-fixed-factor.h"
#include "owl-gate.h"
#include "owl-mux.h"
#include "owl-pll.h"
#include <dt-bindings/clock/actions,s500-cmu.h>
#define CMU_COREPLL (0x0000)
#define CMU_DEVPLL (0x0004)
#define CMU_DDRPLL (0x0008)
#define CMU_NANDPLL (0x000C)
#define CMU_DISPLAYPLL (0x0010)
#define CMU_AUDIOPLL (0x0014)
#define CMU_TVOUTPLL (0x0018)
#define CMU_BUSCLK (0x001C)
#define CMU_SENSORCLK (0x0020)
#define CMU_LCDCLK (0x0024)
#define CMU_DSICLK (0x0028)
#define CMU_CSICLK (0x002C)
#define CMU_DECLK (0x0030)
#define CMU_BISPCLK (0x0034)
#define CMU_BUSCLK1 (0x0038)
#define CMU_VDECLK (0x0040)
#define CMU_VCECLK (0x0044)
#define CMU_NANDCCLK (0x004C)
#define CMU_SD0CLK (0x0050)
#define CMU_SD1CLK (0x0054)
#define CMU_SD2CLK (0x0058)
#define CMU_UART0CLK (0x005C)
#define CMU_UART1CLK (0x0060)
#define CMU_UART2CLK (0x0064)
#define CMU_PWM4CLK (0x0068)
#define CMU_PWM5CLK (0x006C)
#define CMU_PWM0CLK (0x0070)
#define CMU_PWM1CLK (0x0074)
#define CMU_PWM2CLK (0x0078)
#define CMU_PWM3CLK (0x007C)
#define CMU_USBPLL (0x0080)
#define CMU_ETHERNETPLL (0x0084)
#define CMU_CVBSPLL (0x0088)
#define CMU_LENSCLK (0x008C)
#define CMU_GPU3DCLK (0x0090)
#define CMU_CORECTL (0x009C)
#define CMU_DEVCLKEN0 (0x00A0)
#define CMU_DEVCLKEN1 (0x00A4)
#define CMU_DEVRST0 (0x00A8)
#define CMU_DEVRST1 (0x00AC)
#define CMU_UART3CLK (0x00B0)
#define CMU_UART4CLK (0x00B4)
#define CMU_UART5CLK (0x00B8)
#define CMU_UART6CLK (0x00BC)
#define CMU_SSCLK (0x00C0)
#define CMU_DIGITALDEBUG (0x00D0)
#define CMU_ANALOGDEBUG (0x00D4)
#define CMU_COREPLLDEBUG (0x00D8)
#define CMU_DEVPLLDEBUG (0x00DC)
#define CMU_DDRPLLDEBUG (0x00E0)
#define CMU_NANDPLLDEBUG (0x00E4)
#define CMU_DISPLAYPLLDEBUG (0x00E8)
#define CMU_TVOUTPLLDEBUG (0x00EC)
#define CMU_DEEPCOLORPLLDEBUG (0x00F4)
#define CMU_AUDIOPLL_ETHPLLDEBUG (0x00F8)
#define CMU_CVBSPLLDEBUG (0x00FC)
#define OWL_S500_COREPLL_DELAY (150)
#define OWL_S500_DDRPLL_DELAY (63)
#define OWL_S500_DEVPLL_DELAY (28)
#define OWL_S500_NANDPLL_DELAY (44)
#define OWL_S500_DISPLAYPLL_DELAY (57)
#define OWL_S500_ETHERNETPLL_DELAY (25)
#define OWL_S500_AUDIOPLL_DELAY (100)
static const struct clk_pll_table clk_audio_pll_table[] = {
{ 0, 45158400 }, { 1, 49152000 },
{ 0, 0 },
};
/* pll clocks */
static OWL_PLL_NO_PARENT_DELAY(ethernet_pll_clk, "ethernet_pll_clk", CMU_ETHERNETPLL, 500000000, 0, 0, 0, 0, 0, OWL_S500_ETHERNETPLL_DELAY, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT_DELAY(core_pll_clk, "core_pll_clk", CMU_COREPLL, 12000000, 9, 0, 8, 4, 134, OWL_S500_COREPLL_DELAY, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT_DELAY(ddr_pll_clk, "ddr_pll_clk", CMU_DDRPLL, 12000000, 8, 0, 8, 1, 67, OWL_S500_DDRPLL_DELAY, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT_DELAY(nand_pll_clk, "nand_pll_clk", CMU_NANDPLL, 6000000, 8, 0, 7, 2, 86, OWL_S500_NANDPLL_DELAY, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT_DELAY(display_pll_clk, "display_pll_clk", CMU_DISPLAYPLL, 6000000, 8, 0, 8, 2, 126, OWL_S500_DISPLAYPLL_DELAY, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT_DELAY(dev_pll_clk, "dev_pll_clk", CMU_DEVPLL, 6000000, 8, 0, 7, 8, 126, OWL_S500_DEVPLL_DELAY, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT_DELAY(audio_pll_clk, "audio_pll_clk", CMU_AUDIOPLL, 0, 4, 0, 1, 0, 0, OWL_S500_AUDIOPLL_DELAY, clk_audio_pll_table, CLK_IGNORE_UNUSED);
static const char * const dev_clk_mux_p[] = { "hosc", "dev_pll_clk" };
static const char * const bisp_clk_mux_p[] = { "display_pll_clk", "dev_clk" };
static const char * const sensor_clk_mux_p[] = { "hosc", "bisp_clk" };
static const char * const sd_clk_mux_p[] = { "dev_clk", "nand_pll_clk" };
static const char * const pwm_clk_mux_p[] = { "losc", "hosc" };
static const char * const ahbprediv_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" };
static const char * const uart_clk_mux_p[] = { "hosc", "dev_pll_clk" };
static const char * const de_clk_mux_p[] = { "display_pll_clk", "dev_clk" };
static const char * const i2s_clk_mux_p[] = { "audio_pll_clk" };
static const char * const hde_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" };
static const char * const nand_clk_mux_p[] = { "nand_pll_clk", "display_pll_clk", "dev_clk", "ddr_pll_clk" };
static struct clk_factor_table sd_factor_table[] = {
/* bit0 ~ 4 */
{ 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 },
{ 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 },
{ 8, 1, 9 }, { 9, 1, 10 }, { 10, 1, 11 }, { 11, 1, 12 },
{ 12, 1, 13 }, { 13, 1, 14 }, { 14, 1, 15 }, { 15, 1, 16 },
{ 16, 1, 17 }, { 17, 1, 18 }, { 18, 1, 19 }, { 19, 1, 20 },
{ 20, 1, 21 }, { 21, 1, 22 }, { 22, 1, 23 }, { 23, 1, 24 },
{ 24, 1, 25 }, { 25, 1, 26 }, { 26, 1, 27 }, { 27, 1, 28 },
{ 28, 1, 29 }, { 29, 1, 30 }, { 30, 1, 31 }, { 31, 1, 32 },
/* bit8: /128 */
{ 256, 1, 1 * 128 }, { 257, 1, 2 * 128 }, { 258, 1, 3 * 128 }, { 259, 1, 4 * 128 },
{ 260, 1, 5 * 128 }, { 261, 1, 6 * 128 }, { 262, 1, 7 * 128 }, { 263, 1, 8 * 128 },
{ 264, 1, 9 * 128 }, { 265, 1, 10 * 128 }, { 266, 1, 11 * 128 }, { 267, 1, 12 * 128 },
{ 268, 1, 13 * 128 }, { 269, 1, 14 * 128 }, { 270, 1, 15 * 128 }, { 271, 1, 16 * 128 },
{ 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 },
{ 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 },
{ 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 },
{ 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 },
{ 0, 0, 0 },
};
static struct clk_factor_table bisp_factor_table[] = {
{ 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 },
{ 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 },
{ 0, 0, 0 },
};
static struct clk_factor_table ahb_factor_table[] = {
{ 1, 1, 2 }, { 2, 1, 3 },
{ 0, 0, 0 },
};
static struct clk_div_table rmii_ref_div_table[] = {
{ 0, 4 }, { 1, 10 },
{ 0, 0 },
};
static struct clk_div_table i2s_div_table[] = {
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
{ 8, 24 },
{ 0, 0 },
};
static struct clk_div_table nand_div_table[] = {
{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 6 },
{ 4, 8 }, { 5, 10 }, { 6, 12 }, { 7, 14 },
{ 8, 16 }, { 9, 18 }, { 10, 20 }, { 11, 22 },
{ 0, 0 },
};
/* mux clock */
static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT);
static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT);
/* gate clocks */
static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED);
static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED);
static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED);
static OWL_GATE(spi3_clk, "spi3_clk", "ahb_clk", CMU_DEVCLKEN1, 13, 0, CLK_IGNORE_UNUSED);
static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0);
static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0);
/* divider clocks */
static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0);
/* factor clocks */
static OWL_FACTOR(ahb_clk, "ahb_clk", "h_clk", CMU_BUSCLK1, 2, 2, ahb_factor_table, 0, 0);
static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 3, bisp_factor_table, 0, 0);
static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 3, bisp_factor_table, 0, 0);
/* composite clocks */
static OWL_COMP_FACTOR(vce_clk, "vce_clk", hde_clk_mux_p,
OWL_MUX_HW(CMU_VCECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 26, 0),
OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, bisp_factor_table),
0);
static OWL_COMP_FACTOR(vde_clk, "vde_clk", hde_clk_mux_p,
OWL_MUX_HW(CMU_VDECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 25, 0),
OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, bisp_factor_table),
0);
static OWL_COMP_FACTOR(bisp_clk, "bisp_clk", bisp_clk_mux_p,
OWL_MUX_HW(CMU_BISPCLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
OWL_FACTOR_HW(CMU_BISPCLK, 0, 3, 0, bisp_factor_table),
0);
static OWL_COMP_FACTOR(sensor0_clk, "sensor0_clk", sensor_clk_mux_p,
OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
OWL_FACTOR_HW(CMU_SENSORCLK, 0, 3, 0, bisp_factor_table),
CLK_IGNORE_UNUSED);
static OWL_COMP_FACTOR(sensor1_clk, "sensor1_clk", sensor_clk_mux_p,
OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
OWL_FACTOR_HW(CMU_SENSORCLK, 8, 3, 0, bisp_factor_table),
CLK_IGNORE_UNUSED);
static OWL_COMP_FACTOR(sd0_clk, "sd0_clk", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD0CLK, 9, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 5, 0),
OWL_FACTOR_HW(CMU_SD0CLK, 0, 9, 0, sd_factor_table),
0);
static OWL_COMP_FACTOR(sd1_clk, "sd1_clk", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD1CLK, 9, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 6, 0),
OWL_FACTOR_HW(CMU_SD1CLK, 0, 9, 0, sd_factor_table),
0);
static OWL_COMP_FACTOR(sd2_clk, "sd2_clk", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD2CLK, 9, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 7, 0),
OWL_FACTOR_HW(CMU_SD2CLK, 0, 9, 0, sd_factor_table),
0);
static OWL_COMP_DIV(pwm0_clk, "pwm0_clk", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM0CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 23, 0),
OWL_DIVIDER_HW(CMU_PWM0CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(pwm1_clk, "pwm1_clk", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM1CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 24, 0),
OWL_DIVIDER_HW(CMU_PWM1CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(pwm2_clk, "pwm2_clk", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM2CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 25, 0),
OWL_DIVIDER_HW(CMU_PWM2CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(pwm3_clk, "pwm3_clk", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM3CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 26, 0),
OWL_DIVIDER_HW(CMU_PWM3CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(pwm4_clk, "pwm4_clk", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM4CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 11, 0),
OWL_DIVIDER_HW(CMU_PWM4CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(pwm5_clk, "pwm5_clk", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM5CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 0, 0),
OWL_DIVIDER_HW(CMU_PWM5CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_PASS(de_clk, "de_clk", de_clk_mux_p,
OWL_MUX_HW(CMU_DECLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 8, 0),
0);
static OWL_COMP_FIXED_FACTOR(i2c0_clk, "i2c0_clk", "ethernet_pll_clk",
OWL_GATE_HW(CMU_DEVCLKEN1, 14, 0),
1, 5, 0);
static OWL_COMP_FIXED_FACTOR(i2c1_clk, "i2c1_clk", "ethernet_pll_clk",
OWL_GATE_HW(CMU_DEVCLKEN1, 15, 0),
1, 5, 0);
static OWL_COMP_FIXED_FACTOR(i2c2_clk, "i2c2_clk", "ethernet_pll_clk",
OWL_GATE_HW(CMU_DEVCLKEN1, 30, 0),
1, 5, 0);
static OWL_COMP_FIXED_FACTOR(i2c3_clk, "i2c3_clk", "ethernet_pll_clk",
OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0),
1, 5, 0);
static OWL_COMP_DIV(uart0_clk, "uart0_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART0CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 6, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART1CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 7, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart2_clk, "uart2_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART2CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart3_clk, "uart3_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART3CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart4_clk, "uart4_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART4CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart5_clk, "uart5_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART5CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart6_clk, "uart6_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART6CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(i2srx_clk, "i2srx_clk", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 21, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 20, 4, 0, i2s_div_table),
0);
static OWL_COMP_DIV(i2stx_clk, "i2stx_clk", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 20, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 16, 4, 0, i2s_div_table),
0);
static OWL_COMP_DIV(hdmia_clk, "hdmia_clk", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 22, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 24, 4, 0, i2s_div_table),
0);
static OWL_COMP_DIV(spdif_clk, "spdif_clk", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 23, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 28, 4, 0, i2s_div_table),
0);
static OWL_COMP_DIV(nand_clk, "nand_clk", nand_clk_mux_p,
OWL_MUX_HW(CMU_NANDCCLK, 8, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0),
OWL_DIVIDER_HW(CMU_NANDCCLK, 0, 3, 0, nand_div_table),
CLK_SET_RATE_PARENT);
static OWL_COMP_DIV(ecc_clk, "ecc_clk", nand_clk_mux_p,
OWL_MUX_HW(CMU_NANDCCLK, 8, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0),
OWL_DIVIDER_HW(CMU_NANDCCLK, 4, 3, 0, nand_div_table),
CLK_SET_RATE_PARENT);
static struct owl_clk_common *s500_clks[] = {
&ethernet_pll_clk.common,
&core_pll_clk.common,
&ddr_pll_clk.common,
&dev_pll_clk.common,
&nand_pll_clk.common,
&audio_pll_clk.common,
&display_pll_clk.common,
&dev_clk.common,
&timer_clk.common,
&i2c0_clk.common,
&i2c1_clk.common,
&i2c2_clk.common,
&i2c3_clk.common,
&uart0_clk.common,
&uart1_clk.common,
&uart2_clk.common,
&uart3_clk.common,
&uart4_clk.common,
&uart5_clk.common,
&uart6_clk.common,
&pwm0_clk.common,
&pwm1_clk.common,
&pwm2_clk.common,
&pwm3_clk.common,
&pwm4_clk.common,
&pwm5_clk.common,
&sensor0_clk.common,
&sensor1_clk.common,
&sd0_clk.common,
&sd1_clk.common,
&sd2_clk.common,
&bisp_clk.common,
&ahb_clk.common,
&ahbprediv_clk.common,
&h_clk.common,
&spi0_clk.common,
&spi1_clk.common,
&spi2_clk.common,
&spi3_clk.common,
&rmii_ref_clk.common,
&de_clk.common,
&de1_clk.common,
&de2_clk.common,
&i2srx_clk.common,
&i2stx_clk.common,
&hdmia_clk.common,
&hdmi_clk.common,
&vce_clk.common,
&vde_clk.common,
&spdif_clk.common,
&nand_clk.common,
&ecc_clk.common,
};
static struct clk_hw_onecell_data s500_hw_clks = {
.hws = {
[CLK_ETHERNET_PLL] = &ethernet_pll_clk.common.hw,
[CLK_CORE_PLL] = &core_pll_clk.common.hw,
[CLK_DDR_PLL] = &ddr_pll_clk.common.hw,
[CLK_NAND_PLL] = &nand_pll_clk.common.hw,
[CLK_DISPLAY_PLL] = &display_pll_clk.common.hw,
[CLK_DEV_PLL] = &dev_pll_clk.common.hw,
[CLK_AUDIO_PLL] = &audio_pll_clk.common.hw,
[CLK_TIMER] = &timer_clk.common.hw,
[CLK_DEV] = &dev_clk.common.hw,
[CLK_DE] = &de_clk.common.hw,
[CLK_DE1] = &de1_clk.common.hw,
[CLK_DE2] = &de2_clk.common.hw,
[CLK_I2C0] = &i2c0_clk.common.hw,
[CLK_I2C1] = &i2c1_clk.common.hw,
[CLK_I2C2] = &i2c2_clk.common.hw,
[CLK_I2C3] = &i2c3_clk.common.hw,
[CLK_I2SRX] = &i2srx_clk.common.hw,
[CLK_I2STX] = &i2stx_clk.common.hw,
[CLK_UART0] = &uart0_clk.common.hw,
[CLK_UART1] = &uart1_clk.common.hw,
[CLK_UART2] = &uart2_clk.common.hw,
[CLK_UART3] = &uart3_clk.common.hw,
[CLK_UART4] = &uart4_clk.common.hw,
[CLK_UART5] = &uart5_clk.common.hw,
[CLK_UART6] = &uart6_clk.common.hw,
[CLK_PWM0] = &pwm0_clk.common.hw,
[CLK_PWM1] = &pwm1_clk.common.hw,
[CLK_PWM2] = &pwm2_clk.common.hw,
[CLK_PWM3] = &pwm3_clk.common.hw,
[CLK_PWM4] = &pwm4_clk.common.hw,
[CLK_PWM5] = &pwm5_clk.common.hw,
[CLK_SENSOR0] = &sensor0_clk.common.hw,
[CLK_SENSOR1] = &sensor1_clk.common.hw,
[CLK_SD0] = &sd0_clk.common.hw,
[CLK_SD1] = &sd1_clk.common.hw,
[CLK_SD2] = &sd2_clk.common.hw,
[CLK_BISP] = &bisp_clk.common.hw,
[CLK_SPI0] = &spi0_clk.common.hw,
[CLK_SPI1] = &spi1_clk.common.hw,
[CLK_SPI2] = &spi2_clk.common.hw,
[CLK_SPI3] = &spi3_clk.common.hw,
[CLK_AHB] = &ahb_clk.common.hw,
[CLK_H] = &h_clk.common.hw,
[CLK_AHBPREDIV] = &ahbprediv_clk.common.hw,
[CLK_RMII_REF] = &rmii_ref_clk.common.hw,
[CLK_HDMI_AUDIO] = &hdmia_clk.common.hw,
[CLK_HDMI] = &hdmi_clk.common.hw,
[CLK_VDE] = &vde_clk.common.hw,
[CLK_VCE] = &vce_clk.common.hw,
[CLK_SPDIF] = &spdif_clk.common.hw,
[CLK_NAND] = &nand_clk.common.hw,
[CLK_ECC] = &ecc_clk.common.hw,
},
.num = CLK_NR_CLKS,
};
static struct owl_clk_desc s500_clk_desc = {
.clks = s500_clks,
.num_clks = ARRAY_SIZE(s500_clks),
.hw_clks = &s500_hw_clks,
};
static int s500_clk_probe(struct platform_device *pdev)
{
struct owl_clk_desc *desc;
desc = &s500_clk_desc;
owl_clk_regmap_init(pdev, desc);
return owl_clk_probe(&pdev->dev, desc->hw_clks);
}
static const struct of_device_id s500_clk_of_match[] = {
{ .compatible = "actions,s500-cmu", },
{ /* sentinel */ }
};
static struct platform_driver s500_clk_driver = {
.probe = s500_clk_probe,
.driver = {
.name = "s500-cmu",
.of_match_table = s500_clk_of_match,
},
};
static int __init s500_clk_init(void)
{
return platform_driver_register(&s500_clk_driver);
}
core_initcall(s500_clk_init);
......@@ -340,7 +340,12 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
rate, *parent_rate);
for (div = 1; div <= AUDIO_PLL_QDPMC_MAX; div++) {
if (!rate)
return 0;
best_parent_rate = clk_round_rate(pclk->clk, 1);
div = max(best_parent_rate / rate, 1UL);
for (; div <= AUDIO_PLL_QDPMC_MAX; div++) {
best_parent_rate = clk_round_rate(pclk->clk, rate * div);
tmp_rate = best_parent_rate / div;
tmp_diff = abs(rate - tmp_rate);
......@@ -350,6 +355,8 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
best_rate = tmp_rate;
best_diff = tmp_diff;
tmp_qd = div;
if (!best_diff)
break; /* got exact match */
}
}
......
......@@ -132,11 +132,8 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout;
unsigned long div = parent_rate / rate;
unsigned int pckr;
int shift = 0;
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
if (!div)
return -EINVAL;
......
......@@ -241,13 +241,14 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "masterck";
parent_names[5] = "audiopll_pmcck";
for (i = 0; i < 3; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
parent_names, 6, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
......
......@@ -44,21 +44,21 @@ struct clps711x_clk {
struct clk_hw_onecell_data clk_data;
};
static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
u32 fref)
static void __init clps711x_clk_init_dt(struct device_node *np)
{
u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi;
u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi, fref = 0;
struct clps711x_clk *clps711x_clk;
unsigned i;
void __iomem *base;
WARN_ON(of_property_read_u32(np, "startup-frequency", &fref));
if (!base)
return ERR_PTR(-ENOMEM);
base = of_iomap(np, 0);
BUG_ON(!base);
clps711x_clk = kzalloc(struct_size(clps711x_clk, clk_data.hws,
CLPS711X_CLK_MAX),
GFP_KERNEL);
if (!clps711x_clk)
return ERR_PTR(-ENOMEM);
BUG_ON(!clps711x_clk);
spin_lock_init(&clps711x_clk->lock);
......@@ -137,52 +137,13 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10);
clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] =
clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64);
for (i = 0; i < CLPS711X_CLK_MAX; i++)
if (IS_ERR(clps711x_clk->clk_data.hws[i]))
for (tmp = 0; tmp < CLPS711X_CLK_MAX; tmp++)
if (IS_ERR(clps711x_clk->clk_data.hws[tmp]))
pr_err("clk %i: register failed with %ld\n",
i, PTR_ERR(clps711x_clk->clk_data.hws[i]));
return clps711x_clk;
}
void __init clps711x_clk_init(void __iomem *base)
{
struct clps711x_clk *clps711x_clk;
clps711x_clk = _clps711x_clk_init(base, 73728000);
BUG_ON(IS_ERR(clps711x_clk));
/* Clocksource */
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1],
NULL, "clps711x-timer.0");
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2],
NULL, "clps711x-timer.1");
/* Drivers */
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM],
NULL, "clps711x-pwm");
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART],
NULL, "clps711x-uart.0");
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART],
NULL, "clps711x-uart.1");
}
#ifdef CONFIG_OF
static void __init clps711x_clk_init_dt(struct device_node *np)
{
void __iomem *base = of_iomap(np, 0);
struct clps711x_clk *clps711x_clk;
u32 fref = 0;
WARN_ON(of_property_read_u32(np, "startup-frequency", &fref));
clps711x_clk = _clps711x_clk_init(base, fref);
BUG_ON(IS_ERR(clps711x_clk));
tmp, PTR_ERR(clps711x_clk->clk_data.hws[tmp]));
clps711x_clk->clk_data.num = CLPS711X_CLK_MAX;
of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
&clps711x_clk->clk_data);
}
CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt);
#endif
......@@ -29,6 +29,17 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
}
EXPORT_SYMBOL(devm_clk_get);
struct clk *devm_clk_get_optional(struct device *dev, const char *id)
{
struct clk *clk = devm_clk_get(dev, id);
if (clk == ERR_PTR(-ENOENT))
return NULL;
return clk;
}
EXPORT_SYMBOL(devm_clk_get_optional);
struct clk_bulk_devres {
struct clk_bulk_data *clks;
int num_clks;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Memory Mapped IO Fixed clock driver
*
* Copyright (C) 2018 Cadence Design Systems, Inc.
*
* Authors:
* Jan Kotas <jank@cadence.com>
*/
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/module.h>
#include <linux/platform_device.h>
static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node)
{
struct clk_hw *clk;
const char *clk_name = node->name;
void __iomem *base;
u32 freq;
int ret;
base = of_iomap(node, 0);
if (!base) {
pr_err("%pOFn: failed to map address\n", node);
return ERR_PTR(-EIO);
}
freq = readl(base);
iounmap(base);
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, freq);
if (IS_ERR(clk)) {
pr_err("%pOFn: failed to register fixed rate clock\n", node);
return clk;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, clk);
if (ret) {
pr_err("%pOFn: failed to add clock provider\n", node);
clk_hw_unregister(clk);
clk = ERR_PTR(ret);
}
return clk;
}
static void __init of_fixed_mmio_clk_setup(struct device_node *node)
{
fixed_mmio_clk_setup(node);
}
CLK_OF_DECLARE(fixed_mmio_clk, "fixed-mmio-clock", of_fixed_mmio_clk_setup);
/**
* This is not executed when of_fixed_mmio_clk_setup succeeded.
*/
static int of_fixed_mmio_clk_probe(struct platform_device *pdev)
{
struct clk_hw *clk;
clk = fixed_mmio_clk_setup(pdev->dev.of_node);
if (IS_ERR(clk))
return PTR_ERR(clk);
platform_set_drvdata(pdev, clk);
return 0;
}
static int of_fixed_mmio_clk_remove(struct platform_device *pdev)
{
struct clk_hw *clk = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
clk_hw_unregister_fixed_rate(clk);
return 0;
}
static const struct of_device_id of_fixed_mmio_clk_ids[] = {
{ .compatible = "fixed-mmio-clock" },
{ }
};
MODULE_DEVICE_TABLE(of, of_fixed_mmio_clk_ids);
static struct platform_driver of_fixed_mmio_clk_driver = {
.driver = {
.name = "of_fixed_mmio_clk",
.of_match_table = of_fixed_mmio_clk_ids,
},
.probe = of_fixed_mmio_clk_probe,
.remove = of_fixed_mmio_clk_remove,
};
module_platform_driver(of_fixed_mmio_clk_driver);
MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
MODULE_DESCRIPTION("Memory Mapped IO Fixed clock driver");
MODULE_LICENSE("GPL v2");
......@@ -79,7 +79,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long m, n;
u64 ret;
if (!rate || rate >= *parent_rate)
if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate))
return *parent_rate;
if (fd->approximation)
......
......@@ -58,6 +58,35 @@ const struct clk_ops clk_gpio_gate_ops = {
};
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
gpiod_set_value_cansleep(clk->gpiod, 1);
return 0;
}
static void clk_sleeping_gpio_gate_unprepare(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
gpiod_set_value_cansleep(clk->gpiod, 0);
}
static int clk_sleeping_gpio_gate_is_prepared(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
return gpiod_get_value_cansleep(clk->gpiod);
}
static const struct clk_ops clk_sleeping_gpio_gate_ops = {
.prepare = clk_sleeping_gpio_gate_prepare,
.unprepare = clk_sleeping_gpio_gate_unprepare,
.is_prepared = clk_sleeping_gpio_gate_is_prepared,
};
/**
* DOC: basic clock multiplexer which can be controlled with a gpio output
* Traits of this clock:
......@@ -144,10 +173,16 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
const char *parent_name, struct gpio_desc *gpiod,
unsigned long flags)
{
const struct clk_ops *ops;
if (gpiod_cansleep(gpiod))
ops = &clk_sleeping_gpio_gate_ops;
else
ops = &clk_gpio_gate_ops;
return clk_register_gpio(dev, name,
(parent_name ? &parent_name : NULL),
(parent_name ? 1 : 0), gpiod, flags,
&clk_gpio_gate_ops);
(parent_name ? 1 : 0), gpiod, flags, ops);
}
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate);
......
......@@ -293,6 +293,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk
/* Map system registers */
srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
hb_clk->reg = of_iomap(srnp, 0);
of_node_put(srnp);
BUG_ON(!hb_clk->reg);
hb_clk->reg += reg;
......
......@@ -235,8 +235,9 @@ static int max77686_clk_probe(struct platform_device *pdev)
return ret;
}
ret = clk_hw_register_clkdev(&max_clk_data->hw,
max_clk_data->clk_idata.name, NULL);
ret = devm_clk_hw_register_clkdev(dev, &max_clk_data->hw,
max_clk_data->clk_idata.name,
NULL);
if (ret < 0) {
dev_err(dev, "Failed to clkdev register: %d\n", ret);
return ret;
......@@ -244,8 +245,8 @@ static int max77686_clk_probe(struct platform_device *pdev)
}
if (parent->of_node) {
ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get,
drv_data);
ret = devm_of_clk_add_hw_provider(dev, of_clk_max77686_get,
drv_data);
if (ret < 0) {
dev_err(dev, "Failed to register OF clock provider: %d\n",
......@@ -261,27 +262,11 @@ static int max77686_clk_probe(struct platform_device *pdev)
1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
if (ret < 0) {
dev_err(dev, "Failed to config low-jitter: %d\n", ret);
goto remove_of_clk_provider;
return ret;
}
}
return 0;
remove_of_clk_provider:
if (parent->of_node)
of_clk_del_provider(parent->of_node);
return ret;
}
static int max77686_clk_remove(struct platform_device *pdev)
{
struct device *parent = pdev->dev.parent;
if (parent->of_node)
of_clk_del_provider(parent->of_node);
return 0;
}
static const struct platform_device_id max77686_clk_id[] = {
......@@ -297,7 +282,6 @@ static struct platform_driver max77686_clk_driver = {
.name = "max77686-clk",
},
.probe = max77686_clk_probe,
.remove = max77686_clk_remove,
.id_table = max77686_clk_id,
};
......
......@@ -1148,8 +1148,8 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
pll->div[i].clk = clk;
ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
if (ret != 0)
pr_err("%s: %s: register to lookup table failed %ld\n",
__func__, pll->div[i].name, PTR_ERR(clk));
pr_err("%s: %s: register to lookup table failed %d\n",
__func__, pll->div[i].name, ret);
}
}
......@@ -1389,6 +1389,7 @@ static void __init clockgen_init(struct device_node *np)
pr_err("%s: Couldn't map %pOF regs\n", __func__,
guts);
}
of_node_put(guts);
}
}
......
......@@ -121,7 +121,7 @@ static const char * const cpu_src[] = {
};
static const char * const axi_src[] = {
"ck_hsi", "ck_hse", "pll2_p", "pll3_p"
"ck_hsi", "ck_hse", "pll2_p"
};
static const char * const per_src[] = {
......@@ -225,19 +225,19 @@ static const char * const usart6_src[] = {
};
static const char * const fdcan_src[] = {
"ck_hse", "pll3_q", "pll4_q"
"ck_hse", "pll3_q", "pll4_q", "pll4_r"
};
static const char * const sai_src[] = {
"pll4_q", "pll3_q", "i2s_ckin", "ck_per"
"pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r"
};
static const char * const sai2_src[] = {
"pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb"
"pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r"
};
static const char * const adc12_src[] = {
"pll4_q", "ck_per"
"pll4_r", "ck_per", "pll3_q"
};
static const char * const dsi_src[] = {
......@@ -269,7 +269,7 @@ static const struct clk_div_table axi_div_table[] = {
static const struct clk_div_table mcu_div_table[] = {
{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
{ 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 },
{ 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 },
{ 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 },
{ 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 },
{ 0 },
};
......@@ -1286,10 +1286,11 @@ _clk_stm32_register_composite(struct device *dev,
MGATE_MP1(_id, _name, _parent, _flags, _mgate)
#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\
COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\
_MGATE_MP1(_mgate),\
_MMUX(_mmux),\
_NO_DIV)
COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\
CLK_SET_RATE_NO_REPARENT | _flags,\
_MGATE_MP1(_mgate),\
_MMUX(_mmux),\
_NO_DIV)
enum {
G_SAI1,
......@@ -1655,12 +1656,14 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = {
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
CLK_DIVIDER_READ_ONLY),
DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO,
RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY),
/* External / Internal Oscillators */
GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0),
GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0),
/* ck_csi is used by IO compensation and should be critical */
GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL,
RCC_OCENSETR, 4, 0),
GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0),
GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0),
GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0),
......@@ -1952,14 +1955,14 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU),
MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12),
COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE,
COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_NO_REPARENT,
_NO_GATE,
_MMUX(M_ETHCK),
_DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)),
_DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
/* RTC clock */
DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7,
CLK_DIVIDER_ALLOW_ZERO),
DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0),
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_PARENT,
......
......@@ -41,6 +41,43 @@ static int twl6040_pdmclk_is_prepared(struct clk_hw *hw)
return pdmclk->enabled;
}
static int twl6040_pdmclk_reset_one_clock(struct twl6040_pdmclk *pdmclk,
unsigned int reg)
{
const u8 reset_mask = TWL6040_HPLLRST; /* Same for HPPLL and LPPLL */
int ret;
ret = twl6040_set_bits(pdmclk->twl6040, reg, reset_mask);
if (ret < 0)
return ret;
ret = twl6040_clear_bits(pdmclk->twl6040, reg, reset_mask);
if (ret < 0)
return ret;
return 0;
}
/*
* TWL6040A2 Phoenix Audio IC erratum #6: "PDM Clock Generation Issue At
* Cold Temperature". This affects cold boot and deeper idle states it
* seems. The workaround consists of resetting HPPLL and LPPLL.
*/
static int twl6040_pdmclk_quirk_reset_clocks(struct twl6040_pdmclk *pdmclk)
{
int ret;
ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_HPPLLCTL);
if (ret)
return ret;
ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_LPPLLCTL);
if (ret)
return ret;
return 0;
}
static int twl6040_pdmclk_prepare(struct clk_hw *hw)
{
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
......@@ -48,8 +85,20 @@ static int twl6040_pdmclk_prepare(struct clk_hw *hw)
int ret;
ret = twl6040_power(pdmclk->twl6040, 1);
if (!ret)
pdmclk->enabled = 1;
if (ret)
return ret;
ret = twl6040_pdmclk_quirk_reset_clocks(pdmclk);
if (ret)
goto out_err;
pdmclk->enabled = 1;
return 0;
out_err:
dev_err(pdmclk->dev, "%s: error %i\n", __func__, ret);
twl6040_power(pdmclk->twl6040, 0);
return ret;
}
......
......@@ -57,6 +57,7 @@ struct clk_core {
struct clk_core *new_child;
unsigned long flags;
bool orphan;
bool rpm_enabled;
unsigned int enable_count;
unsigned int prepare_count;
unsigned int protect_count;
......@@ -81,6 +82,7 @@ struct clk_core {
struct clk {
struct clk_core *core;
struct device *dev;
const char *dev_id;
const char *con_id;
unsigned long min_rate;
......@@ -92,9 +94,9 @@ struct clk {
/*** runtime pm ***/
static int clk_pm_runtime_get(struct clk_core *core)
{
int ret = 0;
int ret;
if (!core->dev)
if (!core->rpm_enabled)
return 0;
ret = pm_runtime_get_sync(core->dev);
......@@ -103,7 +105,7 @@ static int clk_pm_runtime_get(struct clk_core *core)
static void clk_pm_runtime_put(struct clk_core *core)
{
if (!core->dev)
if (!core->rpm_enabled)
return;
pm_runtime_put_sync(core->dev);
......@@ -223,7 +225,7 @@ static bool clk_core_is_enabled(struct clk_core *core)
* taking enable spinlock, but the below check is needed if one tries
* to call it from other places.
*/
if (core->dev) {
if (core->rpm_enabled) {
pm_runtime_get_noresume(core->dev);
if (!pm_runtime_active(core->dev)) {
ret = false;
......@@ -233,7 +235,7 @@ static bool clk_core_is_enabled(struct clk_core *core)
ret = core->ops->is_enabled(core->hw);
done:
if (core->dev)
if (core->rpm_enabled)
pm_runtime_put(core->dev);
return ret;
......@@ -394,16 +396,19 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
{
return clk_core_is_prepared(hw->core);
}
EXPORT_SYMBOL_GPL(clk_hw_is_prepared);
bool clk_hw_rate_is_protected(const struct clk_hw *hw)
{
return clk_core_rate_is_protected(hw->core);
}
EXPORT_SYMBOL_GPL(clk_hw_rate_is_protected);
bool clk_hw_is_enabled(const struct clk_hw *hw)
{
return clk_core_is_enabled(hw->core);
}
EXPORT_SYMBOL_GPL(clk_hw_is_enabled);
bool __clk_is_enabled(struct clk *clk)
{
......@@ -3209,42 +3214,105 @@ static int __clk_core_init(struct clk_core *core)
return ret;
}
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
/**
* clk_core_link_consumer - Add a clk consumer to the list of consumers in a clk_core
* @core: clk to add consumer to
* @clk: consumer to link to a clk
*/
static void clk_core_link_consumer(struct clk_core *core, struct clk *clk)
{
clk_prepare_lock();
hlist_add_head(&clk->clks_node, &core->clks);
clk_prepare_unlock();
}
/**
* clk_core_unlink_consumer - Remove a clk consumer from the list of consumers in a clk_core
* @clk: consumer to unlink
*/
static void clk_core_unlink_consumer(struct clk *clk)
{
lockdep_assert_held(&prepare_lock);
hlist_del(&clk->clks_node);
}
/**
* alloc_clk - Allocate a clk consumer, but leave it unlinked to the clk_core
* @core: clk to allocate a consumer for
* @dev_id: string describing device name
* @con_id: connection ID string on device
*
* Returns: clk consumer left unlinked from the consumer list
*/
static struct clk *alloc_clk(struct clk_core *core, const char *dev_id,
const char *con_id)
{
struct clk *clk;
/* This is to allow this function to be chained to others */
if (IS_ERR_OR_NULL(hw))
return ERR_CAST(hw);
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk)
return ERR_PTR(-ENOMEM);
clk->core = hw->core;
clk->core = core;
clk->dev_id = dev_id;
clk->con_id = kstrdup_const(con_id, GFP_KERNEL);
clk->max_rate = ULONG_MAX;
clk_prepare_lock();
hlist_add_head(&clk->clks_node, &hw->core->clks);
clk_prepare_unlock();
return clk;
}
/* keep in sync with __clk_put */
void __clk_free_clk(struct clk *clk)
/**
* free_clk - Free a clk consumer
* @clk: clk consumer to free
*
* Note, this assumes the clk has been unlinked from the clk_core consumer
* list.
*/
static void free_clk(struct clk *clk)
{
clk_prepare_lock();
hlist_del(&clk->clks_node);
clk_prepare_unlock();
kfree_const(clk->con_id);
kfree(clk);
}
/**
* clk_hw_create_clk: Allocate and link a clk consumer to a clk_core given
* a clk_hw
* @dev: clk consumer device
* @hw: clk_hw associated with the clk being consumed
* @dev_id: string describing device name
* @con_id: connection ID string on device
*
* This is the main function used to create a clk pointer for use by clk
* consumers. It connects a consumer to the clk_core and clk_hw structures
* used by the framework and clk provider respectively.
*/
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
const char *dev_id, const char *con_id)
{
struct clk *clk;
struct clk_core *core;
/* This is to allow this function to be chained to others */
if (IS_ERR_OR_NULL(hw))
return ERR_CAST(hw);
core = hw->core;
clk = alloc_clk(core, dev_id, con_id);
if (IS_ERR(clk))
return clk;
clk->dev = dev;
if (!try_module_get(core->owner)) {
free_clk(clk);
return ERR_PTR(-ENOENT);
}
kref_get(&core->ref);
clk_core_link_consumer(core, clk);
return clk;
}
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
......@@ -3280,7 +3348,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
core->ops = hw->init->ops;
if (dev && pm_runtime_enabled(dev))
core->dev = dev;
core->rpm_enabled = true;
core->dev = dev;
if (dev && dev->driver)
core->owner = dev->driver->owner;
core->hw = hw;
......@@ -3320,17 +3389,27 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
INIT_HLIST_HEAD(&core->clks);
hw->clk = __clk_create_clk(hw, NULL, NULL);
/*
* Don't call clk_hw_create_clk() here because that would pin the
* provider module to itself and prevent it from ever being removed.
*/
hw->clk = alloc_clk(core, NULL, NULL);
if (IS_ERR(hw->clk)) {
ret = PTR_ERR(hw->clk);
goto fail_parents;
}
clk_core_link_consumer(hw->core, hw->clk);
ret = __clk_core_init(core);
if (!ret)
return hw->clk;
__clk_free_clk(hw->clk);
clk_prepare_lock();
clk_core_unlink_consumer(hw->clk);
clk_prepare_unlock();
free_clk(hw->clk);
hw->clk = NULL;
fail_parents:
......@@ -3601,20 +3680,7 @@ EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
/*
* clkdev helpers
*/
int __clk_get(struct clk *clk)
{
struct clk_core *core = !clk ? NULL : clk->core;
if (core) {
if (!try_module_get(core->owner))
return 0;
kref_get(&core->ref);
}
return 1;
}
/* keep in sync with __clk_free_clk */
void __clk_put(struct clk *clk)
{
struct module *owner;
......@@ -3648,8 +3714,7 @@ void __clk_put(struct clk *clk)
module_put(owner);
kfree_const(clk->con_id);
kfree(clk);
free_clk(clk);
}
/*** clk rate change notifiers ***/
......@@ -4006,6 +4071,49 @@ void devm_of_clk_del_provider(struct device *dev)
}
EXPORT_SYMBOL(devm_of_clk_del_provider);
/*
* Beware the return values when np is valid, but no clock provider is found.
* If name == NULL, the function returns -ENOENT.
* If name != NULL, the function returns -EINVAL. This is because
* of_parse_phandle_with_args() is called even if of_property_match_string()
* returns an error.
*/
static int of_parse_clkspec(const struct device_node *np, int index,
const char *name, struct of_phandle_args *out_args)
{
int ret = -ENOENT;
/* Walk up the tree of devices looking for a clock property that matches */
while (np) {
/*
* For named clocks, first look up the name in the
* "clock-names" property. If it cannot be found, then index
* will be an error code and of_parse_phandle_with_args() will
* return -EINVAL.
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells",
index, out_args);
if (!ret)
break;
if (name && index >= 0)
break;
/*
* No matching clock found on this node. If the parent node
* has a "clock-ranges" property, then we can try one of its
* clocks.
*/
np = np->parent;
if (np && !of_get_property(np, "clock-ranges", NULL))
break;
index = 0;
}
return ret;
}
static struct clk_hw *
__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
struct of_phandle_args *clkspec)
......@@ -4021,36 +4129,26 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider,
return __clk_get_hw(clk);
}
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
const char *dev_id, const char *con_id)
static struct clk_hw *
of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
{
struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
struct clk_hw *hw;
struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
if (!clkspec)
return ERR_PTR(-EINVAL);
/* Check if we have such a provider in our array */
mutex_lock(&of_clk_mutex);
list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == clkspec->np) {
hw = __of_clk_get_hw_from_provider(provider, clkspec);
clk = __clk_create_clk(hw, dev_id, con_id);
}
if (!IS_ERR(clk)) {
if (!__clk_get(clk)) {
__clk_free_clk(clk);
clk = ERR_PTR(-ENOENT);
}
break;
if (!IS_ERR(hw))
break;
}
}
mutex_unlock(&of_clk_mutex);
return clk;
return hw;
}
/**
......@@ -4063,10 +4161,62 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
*/
struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
{
return __of_clk_get_from_provider(clkspec, NULL, __func__);
struct clk_hw *hw = of_clk_get_hw_from_clkspec(clkspec);
return clk_hw_create_clk(NULL, hw, NULL, __func__);
}
EXPORT_SYMBOL_GPL(of_clk_get_from_provider);
struct clk_hw *of_clk_get_hw(struct device_node *np, int index,
const char *con_id)
{
int ret;
struct clk_hw *hw;
struct of_phandle_args clkspec;
ret = of_parse_clkspec(np, index, con_id, &clkspec);
if (ret)
return ERR_PTR(ret);
hw = of_clk_get_hw_from_clkspec(&clkspec);
of_node_put(clkspec.np);
return hw;
}
static struct clk *__of_clk_get(struct device_node *np,
int index, const char *dev_id,
const char *con_id)
{
struct clk_hw *hw = of_clk_get_hw(np, index, con_id);
return clk_hw_create_clk(NULL, hw, dev_id, con_id);
}
struct clk *of_clk_get(struct device_node *np, int index)
{
return __of_clk_get(np, index, np->full_name, NULL);
}
EXPORT_SYMBOL(of_clk_get);
/**
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
* @np: pointer to clock consumer node
* @name: name of consumer's clock input, or NULL for the first clock reference
*
* This function parses the clocks and clock-names properties,
* and uses them to look up the struct clk from the registered list of clock
* providers.
*/
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
{
if (!np)
return ERR_PTR(-ENOENT);
return __of_clk_get(np, 0, np->full_name, name);
}
EXPORT_SYMBOL(of_clk_get_by_name);
/**
* of_clk_get_parent_count() - Count the number of clocks a device node has
* @np: device node to count
......
......@@ -5,31 +5,36 @@
*/
struct clk_hw;
struct device;
struct of_phandle_args;
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
const char *dev_id, const char *con_id);
struct clk_hw *of_clk_get_hw(struct device_node *np,
int index, const char *con_id);
#else /* !CONFIG_COMMON_CLK || !CONFIG_OF */
static inline struct clk_hw *of_clk_get_hw(struct device_node *np,
int index, const char *con_id)
{
return ERR_PTR(-ENOENT);
}
#endif
#ifdef CONFIG_COMMON_CLK
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
const char *con_id);
void __clk_free_clk(struct clk *clk);
int __clk_get(struct clk *clk);
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
const char *dev_id, const char *con_id);
void __clk_put(struct clk *clk);
#else
/* All these casts to avoid ifdefs in clkdev... */
static inline struct clk *
__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id,
const char *con_id)
{
return (struct clk *)hw;
}
static inline void __clk_free_clk(struct clk *clk) { }
static struct clk_hw *__clk_get_hw(struct clk *clk)
{
return (struct clk_hw *)clk;
}
static inline int __clk_get(struct clk *clk) { return 1; }
static inline void __clk_put(struct clk *clk) { }
#endif
......@@ -27,99 +27,6 @@
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
static struct clk *__of_clk_get(struct device_node *np, int index,
const char *dev_id, const char *con_id)
{
struct of_phandle_args clkspec;
struct clk *clk;
int rc;
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
&clkspec);
if (rc)
return ERR_PTR(rc);
clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id);
of_node_put(clkspec.np);
return clk;
}
struct clk *of_clk_get(struct device_node *np, int index)
{
return __of_clk_get(np, index, np->full_name, NULL);
}
EXPORT_SYMBOL(of_clk_get);
static struct clk *__of_clk_get_by_name(struct device_node *np,
const char *dev_id,
const char *name)
{
struct clk *clk = ERR_PTR(-ENOENT);
/* Walk up the tree of devices looking for a clock that matches */
while (np) {
int index = 0;
/*
* For named clocks, first look up the name in the
* "clock-names" property. If it cannot be found, then
* index will be an error code, and of_clk_get() will fail.
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
clk = __of_clk_get(np, index, dev_id, name);
if (!IS_ERR(clk)) {
break;
} else if (name && index >= 0) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_err("ERROR: could not get clock %pOF:%s(%i)\n",
np, name ? name : "", index);
return clk;
}
/*
* No matching clock found on this node. If the parent node
* has a "clock-ranges" property, then we can try one of its
* clocks.
*/
np = np->parent;
if (np && !of_get_property(np, "clock-ranges", NULL))
break;
}
return clk;
}
/**
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
* @np: pointer to clock consumer node
* @name: name of consumer's clock input, or NULL for the first clock reference
*
* This function parses the clocks and clock-names properties,
* and uses them to look up the struct clk from the registered list of clock
* providers.
*/
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
{
if (!np)
return ERR_PTR(-ENOENT);
return __of_clk_get_by_name(np, np->full_name, name);
}
EXPORT_SYMBOL(of_clk_get_by_name);
#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
static struct clk *__of_clk_get_by_name(struct device_node *np,
const char *dev_id,
const char *name)
{
return ERR_PTR(-ENOENT);
}
#endif
/*
* Find the correct struct clk for the device and connection ID.
* We do slightly fuzzy matching here:
......@@ -163,7 +70,8 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
return cl;
}
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
const char *con_id)
{
struct clk_lookup *cl;
struct clk *clk = NULL;
......@@ -174,35 +82,33 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id)
if (!cl)
goto out;
clk = __clk_create_clk(cl->clk_hw, dev_id, con_id);
clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id);
if (IS_ERR(clk))
goto out;
if (!__clk_get(clk)) {
__clk_free_clk(clk);
cl = NULL;
goto out;
}
out:
mutex_unlock(&clocks_mutex);
return cl ? clk : ERR_PTR(-ENOENT);
}
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
return __clk_get_sys(NULL, dev_id, con_id);
}
EXPORT_SYMBOL(clk_get_sys);
struct clk *clk_get(struct device *dev, const char *con_id)
{
const char *dev_id = dev ? dev_name(dev) : NULL;
struct clk *clk;
struct clk_hw *hw;
if (dev && dev->of_node) {
clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
return clk;
hw = of_clk_get_hw(dev->of_node, 0, con_id);
if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER)
return clk_hw_create_clk(dev, hw, dev_id, con_id);
}
return clk_get_sys(dev_id, con_id);
return __clk_get_sys(dev, dev_id, con_id);
}
EXPORT_SYMBOL(clk_get);
......@@ -401,6 +307,23 @@ static struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw,
return cl;
}
static int do_clk_register_clkdev(struct clk_hw *hw,
struct clk_lookup **cl, const char *con_id, const char *dev_id)
{
if (IS_ERR(hw))
return PTR_ERR(hw);
/*
* Since dev_id can be NULL, and NULL is handled specially, we must
* pass it as either a NULL format string, or with "%s".
*/
if (dev_id)
*cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
else
*cl = __clk_register_clkdev(hw, con_id, NULL);
return *cl ? 0 : -ENOMEM;
}
/**
* clk_register_clkdev - register one clock lookup for a struct clk
* @clk: struct clk to associate with all clk_lookups
......@@ -423,17 +346,8 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
if (IS_ERR(clk))
return PTR_ERR(clk);
/*
* Since dev_id can be NULL, and NULL is handled specially, we must
* pass it as either a NULL format string, or with "%s".
*/
if (dev_id)
cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, "%s",
dev_id);
else
cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, NULL);
return cl ? 0 : -ENOMEM;
return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id,
dev_id);
}
EXPORT_SYMBOL(clk_register_clkdev);
......@@ -456,18 +370,75 @@ int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
{
struct clk_lookup *cl;
if (IS_ERR(hw))
return PTR_ERR(hw);
return do_clk_register_clkdev(hw, &cl, con_id, dev_id);
}
EXPORT_SYMBOL(clk_hw_register_clkdev);
/*
* Since dev_id can be NULL, and NULL is handled specially, we must
* pass it as either a NULL format string, or with "%s".
*/
if (dev_id)
cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
else
cl = __clk_register_clkdev(hw, con_id, NULL);
static void devm_clkdev_release(struct device *dev, void *res)
{
clkdev_drop(*(struct clk_lookup **)res);
}
static int devm_clk_match_clkdev(struct device *dev, void *res, void *data)
{
struct clk_lookup **l = res;
return cl ? 0 : -ENOMEM;
return *l == data;
}
EXPORT_SYMBOL(clk_hw_register_clkdev);
/**
* devm_clk_release_clkdev - Resource managed clkdev lookup release
* @dev: device this lookup is bound
* @con_id: connection ID string on device
* @dev_id: format string describing device name
*
* Drop the clkdev lookup created with devm_clk_hw_register_clkdev.
* Normally this function will not need to be called and the resource
* management code will ensure that the resource is freed.
*/
void devm_clk_release_clkdev(struct device *dev, const char *con_id,
const char *dev_id)
{
struct clk_lookup *cl;
int rval;
cl = clk_find(dev_id, con_id);
WARN_ON(!cl);
rval = devres_release(dev, devm_clkdev_release,
devm_clk_match_clkdev, cl);
WARN_ON(rval);
}
EXPORT_SYMBOL(devm_clk_release_clkdev);
/**
* devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw
* @dev: device this lookup is bound
* @hw: struct clk_hw to associate with all clk_lookups
* @con_id: connection ID string on device
* @dev_id: format string describing device name
*
* con_id or dev_id may be NULL as a wildcard, just as in the rest of
* clkdev.
*
* To make things easier for mass registration, we detect error clk_hws
* from a previous clk_hw_register_*() call, and return the error code for
* those. This is to permit this function to be called immediately
* after clk_hw_register_*().
*/
int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
const char *con_id, const char *dev_id)
{
int rval = -ENOMEM;
struct clk_lookup **cl;
cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL);
if (cl) {
rval = do_clk_register_clkdev(hw, cl, con_id, dev_id);
if (!rval)
devres_add(dev, cl);
else
devres_free(cl);
}
return rval;
}
EXPORT_SYMBOL(devm_clk_hw_register_clkdev);
......@@ -8,6 +8,12 @@ config MXC_CLK_SCU
bool
depends on IMX_SCU
config CLK_IMX8MM
bool "IMX8MM CCM Clock Driver"
depends on ARCH_MXC && ARM64
help
Build the driver for i.MX8MM CCM Clock Driver
config CLK_IMX8MQ
bool "IMX8MQ CCM Clock Driver"
depends on ARCH_MXC && ARM64
......
......@@ -18,12 +18,14 @@ obj-$(CONFIG_MXC_CLK) += \
clk-pllv2.o \
clk-pllv3.o \
clk-pllv4.o \
clk-sccg-pll.o
clk-sccg-pll.o \
clk-pll14xx.o
obj-$(CONFIG_MXC_CLK_SCU) += \
clk-scu.o \
clk-lpcg-scu.o
obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
......
......@@ -123,7 +123,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = {
};
struct clk *imx8m_clk_composite_flags(const char *name,
const char **parent_names,
const char * const *parent_names,
int num_parents, void __iomem *reg,
unsigned long flags)
{
......
......@@ -428,6 +428,7 @@ static void __init mx51_clocks_init(struct device_node *np)
clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0);
clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22);
clk[IMX5_CLK_SCC2_IPG_GATE] = imx_clk_gate2("scc2_gate", "ipg", MXC_CCM_CCGR1, 30);
clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2_flags("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2_flags("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2_flags("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10, CLK_IS_CRITICAL);
......
......@@ -471,6 +471,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
anatop_base = base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
......
......@@ -151,6 +151,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
......
......@@ -404,6 +404,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
......
......@@ -48,8 +48,8 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_SCG1_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SCG1_END),
GFP_KERNEL);
if (!clk_data)
return;
......@@ -136,8 +136,8 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_PCC2_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC2_END),
GFP_KERNEL);
if (!clk_data)
return;
......@@ -183,8 +183,8 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_PCC3_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC3_END),
GFP_KERNEL);
if (!clk_data)
return;
......@@ -228,8 +228,8 @@ static void __init imx7ulp_clk_smc1_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_SMC1_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SMC1_END),
GFP_KERNEL);
if (!clk_data)
return;
......
此差异已折叠。
此差异已折叠。
......@@ -138,6 +138,7 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
}
static const struct of_device_id imx8qxp_match[] = {
{ .compatible = "fsl,scu-clk", },
{ .compatible = "fsl,imx8qxp-clk", },
{ /* sentinel */ }
};
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2017-2018 NXP.
*/
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include "clk.h"
#define GNRL_CTL 0x0
#define DIV_CTL 0x4
#define LOCK_STATUS BIT(31)
#define LOCK_SEL_MASK BIT(29)
#define CLKE_MASK BIT(11)
#define RST_MASK BIT(9)
#define BYPASS_MASK BIT(4)
#define MDIV_SHIFT 12
#define MDIV_MASK GENMASK(21, 12)
#define PDIV_SHIFT 4
#define PDIV_MASK GENMASK(9, 4)
#define SDIV_SHIFT 0
#define SDIV_MASK GENMASK(2, 0)
#define KDIV_SHIFT 0
#define KDIV_MASK GENMASK(15, 0)
#define LOCK_TIMEOUT_US 10000
struct clk_pll14xx {
struct clk_hw hw;
void __iomem *base;
enum imx_pll14xx_type type;
const struct imx_pll14xx_rate_table *rate_table;
int rate_count;
};
#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
struct clk_pll14xx *pll, unsigned long rate)
{
const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
int i;
for (i = 0; i < pll->rate_count; i++)
if (rate == rate_table[i].rate)
return &rate_table[i];
return NULL;
}
static long clk_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
int i;
/* Assumming rate_table is in descending order */
for (i = 0; i < pll->rate_count; i++)
if (rate >= rate_table[i].rate)
return rate_table[i].rate;
/* return minimum supported value */
return rate_table[i - 1].rate;
}
static unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div;
u64 fvco = parent_rate;
pll_gnrl = readl_relaxed(pll->base);
pll_div = readl_relaxed(pll->base + 4);
mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
fvco *= mdiv;
do_div(fvco, pdiv << sdiv);
return fvco;
}
static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div_ctl0, pll_div_ctl1;
short int kdiv;
u64 fvco = parent_rate;
pll_gnrl = readl_relaxed(pll->base);
pll_div_ctl0 = readl_relaxed(pll->base + 4);
pll_div_ctl1 = readl_relaxed(pll->base + 8);
mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
kdiv = pll_div_ctl1 & KDIV_MASK;
/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
fvco *= (mdiv * 65536 + kdiv);
pdiv *= 65536;
do_div(fvco, pdiv << sdiv);
return fvco;
}
static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate,
u32 pll_div)
{
u32 old_mdiv, old_pdiv;
old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK;
old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK;
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
}
static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate,
u32 pll_div_ctl0, u32 pll_div_ctl1)
{
u32 old_mdiv, old_pdiv, old_kdiv;
old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
rate->kdiv != old_kdiv;
}
static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate,
u32 pll_div_ctl0, u32 pll_div_ctl1)
{
u32 old_mdiv, old_pdiv, old_kdiv;
old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
rate->kdiv != old_kdiv;
}
static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
{
u32 val;
return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US, 0,
LOCK_TIMEOUT_US);
}
static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate;
u32 tmp, div_val;
int ret;
rate = imx_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
drate, clk_hw_get_name(hw));
return -EINVAL;
}
tmp = readl_relaxed(pll->base + 4);
if (!clk_pll1416x_mp_change(rate, tmp)) {
tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
tmp |= rate->sdiv << SDIV_SHIFT;
writel_relaxed(tmp, pll->base + 4);
return 0;
}
/* Bypass clock and set lock to pll output lock */
tmp = readl_relaxed(pll->base);
tmp |= LOCK_SEL_MASK;
writel_relaxed(tmp, pll->base);
/* Enable RST */
tmp &= ~RST_MASK;
writel_relaxed(tmp, pll->base);
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
(rate->sdiv << SDIV_SHIFT);
writel_relaxed(div_val, pll->base + 0x4);
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
* FREF is FIN / Prediv, the prediv is [1, 63], so choose
* 3us.
*/
udelay(3);
/* Disable RST */
tmp |= RST_MASK;
writel_relaxed(tmp, pll->base);
/* Wait Lock */
ret = clk_pll14xx_wait_lock(pll);
if (ret)
return ret;
/* Bypass */
tmp &= ~BYPASS_MASK;
writel_relaxed(tmp, pll->base);
return 0;
}
static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate;
u32 tmp, div_val;
int ret;
rate = imx_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
drate, clk_hw_get_name(hw));
return -EINVAL;
}
tmp = readl_relaxed(pll->base + 4);
div_val = readl_relaxed(pll->base + 8);
if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) {
tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
tmp |= rate->sdiv << SDIV_SHIFT;
writel_relaxed(tmp, pll->base + 4);
return 0;
}
/* Enable RST */
tmp = readl_relaxed(pll->base);
tmp &= ~RST_MASK;
writel_relaxed(tmp, pll->base);
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
(rate->sdiv << SDIV_SHIFT);
writel_relaxed(div_val, pll->base + 0x4);
writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
* FREF is FIN / Prediv, the prediv is [1, 63], so choose
* 3us.
*/
udelay(3);
/* Disable RST */
tmp |= RST_MASK;
writel_relaxed(tmp, pll->base);
/* Wait Lock*/
ret = clk_pll14xx_wait_lock(pll);
if (ret)
return ret;
/* Bypass */
tmp &= ~BYPASS_MASK;
writel_relaxed(tmp, pll->base);
return 0;
}
static int clk_pll14xx_prepare(struct clk_hw *hw)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 val;
/*
* RESETB = 1 from 0, PLL starts its normal
* operation after lock time
*/
val = readl_relaxed(pll->base + GNRL_CTL);
val |= RST_MASK;
writel_relaxed(val, pll->base + GNRL_CTL);
return clk_pll14xx_wait_lock(pll);
}
static int clk_pll14xx_is_prepared(struct clk_hw *hw)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 val;
val = readl_relaxed(pll->base + GNRL_CTL);
return (val & RST_MASK) ? 1 : 0;
}
static void clk_pll14xx_unprepare(struct clk_hw *hw)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 val;
/*
* Set RST to 0, power down mode is enabled and
* every digital block is reset
*/
val = readl_relaxed(pll->base + GNRL_CTL);
val &= ~RST_MASK;
writel_relaxed(val, pll->base + GNRL_CTL);
}
static const struct clk_ops clk_pll1416x_ops = {
.prepare = clk_pll14xx_prepare,
.unprepare = clk_pll14xx_unprepare,
.is_prepared = clk_pll14xx_is_prepared,
.recalc_rate = clk_pll1416x_recalc_rate,
.round_rate = clk_pll14xx_round_rate,
.set_rate = clk_pll1416x_set_rate,
};
static const struct clk_ops clk_pll1416x_min_ops = {
.recalc_rate = clk_pll1416x_recalc_rate,
};
static const struct clk_ops clk_pll1443x_ops = {
.prepare = clk_pll14xx_prepare,
.unprepare = clk_pll14xx_unprepare,
.is_prepared = clk_pll14xx_is_prepared,
.recalc_rate = clk_pll1443x_recalc_rate,
.round_rate = clk_pll14xx_round_rate,
.set_rate = clk_pll1443x_set_rate,
};
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
{
struct clk_pll14xx *pll;
struct clk *clk;
struct clk_init_data init;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = pll_clk->flags;
init.parent_names = &parent_name;
init.num_parents = 1;
switch (pll_clk->type) {
case PLL_1416X:
if (!pll->rate_table)
init.ops = &clk_pll1416x_min_ops;
else
init.ops = &clk_pll1416x_ops;
break;
case PLL_1443X:
init.ops = &clk_pll1443x_ops;
break;
default:
pr_err("%s: Unknown pll type for pll clk %s\n",
__func__, name);
};
pll->base = base;
pll->hw.init = &init;
pll->type = pll_clk->type;
pll->rate_table = pll_clk->rate_table;
pll->rate_count = pll_clk->rate_count;
clk = clk_register(NULL, &pll->hw);
if (IS_ERR(clk)) {
pr_err("%s: failed to register pll %s %lu\n",
__func__, name, PTR_ERR(clk));
kfree(pll);
}
return clk;
}
......@@ -25,87 +25,292 @@
#define PLL_DIVF2_MASK GENMASK(12, 7)
#define PLL_DIVR1_MASK GENMASK(27, 25)
#define PLL_DIVR2_MASK GENMASK(24, 19)
#define PLL_DIVQ_MASK GENMASK(6, 1)
#define PLL_REF_MASK GENMASK(2, 0)
#define PLL_LOCK_MASK BIT(31)
#define PLL_PD_MASK BIT(7)
#define OSC_25M 25000000
#define OSC_27M 27000000
/* These are the specification limits for the SSCG PLL */
#define PLL_REF_MIN_FREQ 25000000UL
#define PLL_REF_MAX_FREQ 235000000UL
#define PLL_SCCG_LOCK_TIMEOUT 70
#define PLL_STAGE1_MIN_FREQ 1600000000UL
#define PLL_STAGE1_MAX_FREQ 2400000000UL
#define PLL_STAGE1_REF_MIN_FREQ 25000000UL
#define PLL_STAGE1_REF_MAX_FREQ 54000000UL
#define PLL_STAGE2_MIN_FREQ 1200000000UL
#define PLL_STAGE2_MAX_FREQ 2400000000UL
#define PLL_STAGE2_REF_MIN_FREQ 54000000UL
#define PLL_STAGE2_REF_MAX_FREQ 75000000UL
#define PLL_OUT_MIN_FREQ 20000000UL
#define PLL_OUT_MAX_FREQ 1200000000UL
#define PLL_DIVR1_MAX 7
#define PLL_DIVR2_MAX 63
#define PLL_DIVF1_MAX 63
#define PLL_DIVF2_MAX 63
#define PLL_DIVQ_MAX 63
#define PLL_BYPASS_NONE 0x0
#define PLL_BYPASS1 0x2
#define PLL_BYPASS2 0x1
#define SSCG_PLL_BYPASS1_MASK BIT(5)
#define SSCG_PLL_BYPASS2_MASK BIT(4)
#define SSCG_PLL_BYPASS_MASK GENMASK(5, 4)
#define PLL_SCCG_LOCK_TIMEOUT 70
struct clk_sccg_pll_setup {
int divr1, divf1;
int divr2, divf2;
int divq;
int bypass;
uint64_t vco1;
uint64_t vco2;
uint64_t fout;
uint64_t ref;
uint64_t ref_div1;
uint64_t ref_div2;
uint64_t fout_request;
int fout_error;
};
struct clk_sccg_pll {
struct clk_hw hw;
void __iomem *base;
const struct clk_ops ops;
void __iomem *base;
struct clk_sccg_pll_setup setup;
u8 parent;
u8 bypass1;
u8 bypass2;
};
#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw)
static int clk_pll_wait_lock(struct clk_sccg_pll *pll)
static int clk_sccg_pll_wait_lock(struct clk_sccg_pll *pll)
{
u32 val;
return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 0,
PLL_SCCG_LOCK_TIMEOUT);
val = readl_relaxed(pll->base + PLL_CFG0);
/* don't wait for lock if all plls are bypassed */
if (!(val & SSCG_PLL_BYPASS2_MASK))
return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK,
0, PLL_SCCG_LOCK_TIMEOUT);
return 0;
}
static int clk_pll1_is_prepared(struct clk_hw *hw)
static int clk_sccg_pll2_check_match(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
int new_diff = temp_setup->fout - temp_setup->fout_request;
int diff = temp_setup->fout_error;
val = readl_relaxed(pll->base + PLL_CFG0);
return (val & PLL_PD_MASK) ? 0 : 1;
if (abs(diff) > abs(new_diff)) {
temp_setup->fout_error = new_diff;
memcpy(setup, temp_setup, sizeof(struct clk_sccg_pll_setup));
if (temp_setup->fout_request == temp_setup->fout)
return 0;
}
return -1;
}
static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
static int clk_sccg_divq_lookup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val, divf;
int ret = -EINVAL;
for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX;
temp_setup->divq++) {
temp_setup->vco2 = temp_setup->vco1;
do_div(temp_setup->vco2, temp_setup->divr2 + 1);
temp_setup->vco2 *= 2;
temp_setup->vco2 *= temp_setup->divf2 + 1;
if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ &&
temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) {
temp_setup->fout = temp_setup->vco2;
do_div(temp_setup->fout, 2 * (temp_setup->divq + 1));
ret = clk_sccg_pll2_check_match(setup, temp_setup);
if (!ret) {
temp_setup->bypass = PLL_BYPASS1;
return ret;
}
}
}
val = readl_relaxed(pll->base + PLL_CFG2);
divf = FIELD_GET(PLL_DIVF1_MASK, val);
return ret;
}
static int clk_sccg_divf2_lookup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup)
{
int ret = -EINVAL;
for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX;
temp_setup->divf2++) {
ret = clk_sccg_divq_lookup(setup, temp_setup);
if (!ret)
return ret;
}
return parent_rate * 2 * (divf + 1);
return ret;
}
static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
static int clk_sccg_divr2_lookup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup)
{
unsigned long parent_rate = *prate;
u32 div;
int ret = -EINVAL;
for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX;
temp_setup->divr2++) {
temp_setup->ref_div2 = temp_setup->vco1;
do_div(temp_setup->ref_div2, temp_setup->divr2 + 1);
if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ &&
temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) {
ret = clk_sccg_divf2_lookup(setup, temp_setup);
if (!ret)
return ret;
}
}
return ret;
}
static int clk_sccg_pll2_find_setup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup,
uint64_t ref)
{
int ret = -EINVAL;
if (!parent_rate)
return 0;
if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
return ret;
div = rate / (parent_rate * 2);
temp_setup->vco1 = ref;
return parent_rate * div * 2;
ret = clk_sccg_divr2_lookup(setup, temp_setup);
return ret;
}
static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
static int clk_sccg_divf1_lookup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
u32 divf;
int ret = -EINVAL;
if (!parent_rate)
return -EINVAL;
for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX;
temp_setup->divf1++) {
uint64_t vco1 = temp_setup->ref;
divf = rate / (parent_rate * 2);
do_div(vco1, temp_setup->divr1 + 1);
vco1 *= 2;
vco1 *= temp_setup->divf1 + 1;
val = readl_relaxed(pll->base + PLL_CFG2);
val &= ~PLL_DIVF1_MASK;
val |= FIELD_PREP(PLL_DIVF1_MASK, divf - 1);
writel_relaxed(val, pll->base + PLL_CFG2);
ret = clk_sccg_pll2_find_setup(setup, temp_setup, vco1);
if (!ret) {
temp_setup->bypass = PLL_BYPASS_NONE;
return ret;
}
}
return ret;
}
static int clk_sccg_divr1_lookup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup)
{
int ret = -EINVAL;
for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX;
temp_setup->divr1++) {
temp_setup->ref_div1 = temp_setup->ref;
do_div(temp_setup->ref_div1, temp_setup->divr1 + 1);
if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ &&
temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) {
ret = clk_sccg_divf1_lookup(setup, temp_setup);
if (!ret)
return ret;
}
}
return ret;
}
static int clk_sccg_pll1_find_setup(struct clk_sccg_pll_setup *setup,
struct clk_sccg_pll_setup *temp_setup,
uint64_t ref)
{
int ret = -EINVAL;
if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
return ret;
temp_setup->ref = ref;
ret = clk_sccg_divr1_lookup(setup, temp_setup);
return ret;
}
static int clk_sccg_pll_find_setup(struct clk_sccg_pll_setup *setup,
uint64_t prate,
uint64_t rate, int try_bypass)
{
struct clk_sccg_pll_setup temp_setup;
int ret = -EINVAL;
memset(&temp_setup, 0, sizeof(struct clk_sccg_pll_setup));
memset(setup, 0, sizeof(struct clk_sccg_pll_setup));
temp_setup.fout_error = PLL_OUT_MAX_FREQ;
temp_setup.fout_request = rate;
switch (try_bypass) {
return clk_pll_wait_lock(pll);
case PLL_BYPASS2:
if (prate == rate) {
setup->bypass = PLL_BYPASS2;
setup->fout = rate;
ret = 0;
}
break;
case PLL_BYPASS1:
ret = clk_sccg_pll2_find_setup(setup, &temp_setup, prate);
break;
case PLL_BYPASS_NONE:
ret = clk_sccg_pll1_find_setup(setup, &temp_setup, prate);
break;
}
return ret;
}
static int clk_sccg_pll_is_prepared(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val = readl_relaxed(pll->base + PLL_CFG0);
return (val & PLL_PD_MASK) ? 0 : 1;
}
static int clk_pll1_prepare(struct clk_hw *hw)
static int clk_sccg_pll_prepare(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
......@@ -114,10 +319,10 @@ static int clk_pll1_prepare(struct clk_hw *hw)
val &= ~PLL_PD_MASK;
writel_relaxed(val, pll->base + PLL_CFG0);
return clk_pll_wait_lock(pll);
return clk_sccg_pll_wait_lock(pll);
}
static void clk_pll1_unprepare(struct clk_hw *hw)
static void clk_sccg_pll_unprepare(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
......@@ -125,121 +330,208 @@ static void clk_pll1_unprepare(struct clk_hw *hw)
val = readl_relaxed(pll->base + PLL_CFG0);
val |= PLL_PD_MASK;
writel_relaxed(val, pll->base + PLL_CFG0);
}
static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw,
static unsigned long clk_sccg_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val, ref, divr1, divf1, divr2, divf2;
u32 val, divr1, divf1, divr2, divf2, divq;
u64 temp64;
val = readl_relaxed(pll->base + PLL_CFG0);
switch (FIELD_GET(PLL_REF_MASK, val)) {
case 0:
ref = OSC_25M;
break;
case 1:
ref = OSC_27M;
break;
default:
ref = OSC_25M;
break;
}
val = readl_relaxed(pll->base + PLL_CFG2);
divr1 = FIELD_GET(PLL_DIVR1_MASK, val);
divr2 = FIELD_GET(PLL_DIVR2_MASK, val);
divf1 = FIELD_GET(PLL_DIVF1_MASK, val);
divf2 = FIELD_GET(PLL_DIVF2_MASK, val);
temp64 = ref * 2;
temp64 *= (divf1 + 1) * (divf2 + 1);
do_div(temp64, (divr1 + 1) * (divr2 + 1));
divq = FIELD_GET(PLL_DIVQ_MASK, val);
temp64 = parent_rate;
val = clk_readl(pll->base + PLL_CFG0);
if (val & SSCG_PLL_BYPASS2_MASK) {
temp64 = parent_rate;
} else if (val & SSCG_PLL_BYPASS1_MASK) {
temp64 *= divf2;
do_div(temp64, (divr2 + 1) * (divq + 1));
} else {
temp64 *= 2;
temp64 *= (divf1 + 1) * (divf2 + 1);
do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1));
}
return temp64;
}
static long clk_pll2_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
static int clk_sccg_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 div;
unsigned long parent_rate = *prate;
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
struct clk_sccg_pll_setup *setup = &pll->setup;
u32 val;
if (!parent_rate)
return 0;
/* set bypass here too since the parent might be the same */
val = clk_readl(pll->base + PLL_CFG0);
val &= ~SSCG_PLL_BYPASS_MASK;
val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);
clk_writel(val, pll->base + PLL_CFG0);
div = rate / parent_rate;
val = readl_relaxed(pll->base + PLL_CFG2);
val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);
val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK);
val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1);
val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2);
val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1);
val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2);
val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq);
writel_relaxed(val, pll->base + PLL_CFG2);
return parent_rate * div;
return clk_sccg_pll_wait_lock(pll);
}
static int clk_pll2_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
static u8 clk_sccg_pll_get_parent(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
u32 divf;
u8 ret = pll->parent;
val = clk_readl(pll->base + PLL_CFG0);
if (val & SSCG_PLL_BYPASS2_MASK)
ret = pll->bypass2;
else if (val & SSCG_PLL_BYPASS1_MASK)
ret = pll->bypass1;
return ret;
}
static int clk_sccg_pll_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
if (!parent_rate)
return -EINVAL;
val = clk_readl(pll->base + PLL_CFG0);
val &= ~SSCG_PLL_BYPASS_MASK;
val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);
clk_writel(val, pll->base + PLL_CFG0);
divf = rate / parent_rate;
return clk_sccg_pll_wait_lock(pll);
}
val = readl_relaxed(pll->base + PLL_CFG2);
val &= ~PLL_DIVF2_MASK;
val |= FIELD_PREP(PLL_DIVF2_MASK, divf - 1);
writel_relaxed(val, pll->base + PLL_CFG2);
static int __clk_sccg_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req,
uint64_t min,
uint64_t max,
uint64_t rate,
int bypass)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
struct clk_sccg_pll_setup *setup = &pll->setup;
struct clk_hw *parent_hw = NULL;
int bypass_parent_index;
int ret = -EINVAL;
req->max_rate = max;
req->min_rate = min;
switch (bypass) {
case PLL_BYPASS2:
bypass_parent_index = pll->bypass2;
break;
case PLL_BYPASS1:
bypass_parent_index = pll->bypass1;
break;
default:
bypass_parent_index = pll->parent;
break;
}
parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index);
ret = __clk_determine_rate(parent_hw, req);
if (!ret) {
ret = clk_sccg_pll_find_setup(setup, req->rate,
rate, bypass);
}
req->best_parent_hw = parent_hw;
req->best_parent_rate = req->rate;
req->rate = setup->fout;
return clk_pll_wait_lock(pll);
return ret;
}
static const struct clk_ops clk_sccg_pll1_ops = {
.is_prepared = clk_pll1_is_prepared,
.recalc_rate = clk_pll1_recalc_rate,
.round_rate = clk_pll1_round_rate,
.set_rate = clk_pll1_set_rate,
};
static int clk_sccg_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
struct clk_sccg_pll_setup *setup = &pll->setup;
uint64_t rate = req->rate;
uint64_t min = req->min_rate;
uint64_t max = req->max_rate;
int ret = -EINVAL;
if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)
return ret;
ret = __clk_sccg_pll_determine_rate(hw, req, req->rate, req->rate,
rate, PLL_BYPASS2);
if (!ret)
return ret;
ret = __clk_sccg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ,
PLL_STAGE1_REF_MAX_FREQ, rate,
PLL_BYPASS1);
if (!ret)
return ret;
ret = __clk_sccg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ,
PLL_REF_MAX_FREQ, rate,
PLL_BYPASS_NONE);
if (!ret)
return ret;
if (setup->fout >= min && setup->fout <= max)
ret = 0;
return ret;
}
static const struct clk_ops clk_sccg_pll2_ops = {
.prepare = clk_pll1_prepare,
.unprepare = clk_pll1_unprepare,
.recalc_rate = clk_pll2_recalc_rate,
.round_rate = clk_pll2_round_rate,
.set_rate = clk_pll2_set_rate,
static const struct clk_ops clk_sccg_pll_ops = {
.prepare = clk_sccg_pll_prepare,
.unprepare = clk_sccg_pll_unprepare,
.is_prepared = clk_sccg_pll_is_prepared,
.recalc_rate = clk_sccg_pll_recalc_rate,
.set_rate = clk_sccg_pll_set_rate,
.set_parent = clk_sccg_pll_set_parent,
.get_parent = clk_sccg_pll_get_parent,
.determine_rate = clk_sccg_pll_determine_rate,
};
struct clk *imx_clk_sccg_pll(const char *name,
const char *parent_name,
const char * const *parent_names,
u8 num_parents,
u8 parent, u8 bypass1, u8 bypass2,
void __iomem *base,
enum imx_sccg_pll_type pll_type)
unsigned long flags)
{
struct clk_sccg_pll *pll;
struct clk_init_data init;
struct clk_hw *hw;
int ret;
switch (pll_type) {
case SCCG_PLL1:
init.ops = &clk_sccg_pll1_ops;
break;
case SCCG_PLL2:
init.ops = &clk_sccg_pll2_ops;
break;
default:
return ERR_PTR(-EINVAL);
}
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
pll->parent = parent;
pll->bypass1 = bypass1;
pll->bypass2 = bypass2;
pll->base = base;
init.name = name;
init.flags = 0;
init.parent_names = &parent_name;
init.num_parents = 1;
init.ops = &clk_sccg_pll_ops;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
pll->base = base;
pll->hw.init = &init;
......
......@@ -4,12 +4,17 @@
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/arm-smccc.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "clk-scu.h"
#define IMX_SIP_CPUFREQ 0xC2000001
#define IMX_SIP_SET_CPUFREQ 0x00
static struct imx_sc_ipc *ccm_ipc_handle;
/*
......@@ -65,6 +70,41 @@ struct imx_sc_msg_get_clock_rate {
} data;
};
/*
* struct imx_sc_msg_get_clock_parent - clock get parent protocol
* @hdr: SCU protocol header
* @req: get parent request protocol
* @resp: get parent response protocol
*
* This structure describes the SCU protocol of clock get parent
*/
struct imx_sc_msg_get_clock_parent {
struct imx_sc_rpc_msg hdr;
union {
struct req_get_clock_parent {
__le16 resource;
u8 clk;
} __packed req;
struct resp_get_clock_parent {
u8 parent;
} resp;
} data;
};
/*
* struct imx_sc_msg_set_clock_parent - clock set parent protocol
* @hdr: SCU protocol header
* @req: set parent request protocol
*
* This structure describes the SCU protocol of clock set parent
*/
struct imx_sc_msg_set_clock_parent {
struct imx_sc_rpc_msg hdr;
__le16 resource;
u8 clk;
u8 parent;
} __packed;
/*
* struct imx_sc_msg_req_clock_enable - clock gate protocol
* @hdr: SCU protocol header
......@@ -145,6 +185,25 @@ static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
return rate;
}
static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_scu *clk = to_clk_scu(hw);
struct arm_smccc_res res;
unsigned long cluster_id;
if (clk->rsrc_id == IMX_SC_R_A35)
cluster_id = 0;
else
return -EINVAL;
/* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */
arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ,
cluster_id, rate, 0, 0, 0, 0, &res);
return 0;
}
/*
* clk_scu_set_rate - Set rate for a SCU clock
* @hw: clock to change rate for
......@@ -173,6 +232,49 @@ static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
}
static u8 clk_scu_get_parent(struct clk_hw *hw)
{
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_get_clock_parent msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
int ret;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT;
hdr->size = 2;
msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
msg.data.req.clk = clk->clk_type;
ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
if (ret) {
pr_err("%s: failed to get clock parent %d\n",
clk_hw_get_name(hw), ret);
return 0;
}
return msg.data.resp.parent;
}
static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_set_clock_parent msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT;
hdr->size = 2;
msg.resource = cpu_to_le16(clk->rsrc_id);
msg.clk = clk->clk_type;
msg.parent = index;
return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
}
static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
u8 clk, bool enable, bool autog)
{
......@@ -228,11 +330,22 @@ static const struct clk_ops clk_scu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.round_rate = clk_scu_round_rate,
.set_rate = clk_scu_set_rate,
.get_parent = clk_scu_get_parent,
.set_parent = clk_scu_set_parent,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
};
static const struct clk_ops clk_scu_cpu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.round_rate = clk_scu_round_rate,
.set_rate = clk_scu_atf_set_cpu_rate,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
};
struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type)
{
struct clk_init_data init;
struct clk_scu *clk;
......@@ -248,7 +361,13 @@ struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
init.name = name;
init.ops = &clk_scu_ops;
init.num_parents = 0;
if (rsrc_id == IMX_SC_R_A35)
init.ops = &clk_scu_cpu_ops;
else
init.ops = &clk_scu_ops;
init.parent_names = parents;
init.num_parents = num_parents;
/*
* Note on MX8, the clocks are tightly coupled with power domain
* that once the power domain is off, the clock status may be
......
......@@ -10,7 +10,21 @@
#include <linux/firmware/imx/sci.h>
int imx_clk_scu_init(void);
struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type);
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type);
static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
u8 clk_type)
{
return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type);
}
static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type)
{
return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type);
}
struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg,
......
......@@ -203,6 +203,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop");
anatop_base = of_iomap(np, 0);
BUG_ON(!anatop_base);
of_node_put(np);
np = ccm_node;
ccm_base = of_iomap(np, 0);
......
......@@ -27,6 +27,30 @@ enum imx_sccg_pll_type {
SCCG_PLL2,
};
enum imx_pll14xx_type {
PLL_1416X,
PLL_1443X,
};
/* NOTE: Rate table should be kept sorted in descending order. */
struct imx_pll14xx_rate_table {
unsigned int rate;
unsigned int pdiv;
unsigned int mdiv;
unsigned int sdiv;
unsigned int kdiv;
};
struct imx_pll14xx_clk {
enum imx_pll14xx_type type;
const struct imx_pll14xx_rate_table *rate_table;
int rate_count;
int flags;
};
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base);
......@@ -36,9 +60,12 @@ struct clk *imx_clk_pllv2(const char *name, const char *parent,
struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
void __iomem *base);
struct clk *imx_clk_sccg_pll(const char *name, const char *parent_name,
void __iomem *base,
enum imx_sccg_pll_type pll_type);
struct clk *imx_clk_sccg_pll(const char *name,
const char * const *parent_names,
u8 num_parents,
u8 parent, u8 bypass1, u8 bypass2,
void __iomem *base,
unsigned long flags);
enum imx_pllv3_type {
IMX_PLLV3_GENERIC,
......@@ -329,7 +356,8 @@ static inline struct clk *imx_clk_mux_flags(const char *name,
}
static inline struct clk *imx_clk_mux2_flags(const char *name,
void __iomem *reg, u8 shift, u8 width, const char **parents,
void __iomem *reg, u8 shift, u8 width,
const char * const *parents,
int num_parents, unsigned long flags)
{
return clk_register_mux(NULL, name, parents, num_parents,
......@@ -354,7 +382,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *step);
struct clk *imx8m_clk_composite_flags(const char *name,
const char **parent_names,
const char * const *parent_names,
int num_parents, void __iomem *reg,
unsigned long flags);
......
......@@ -83,7 +83,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
const struct ingenic_cgu_clk_info *clk_info;
const struct ingenic_cgu_pll_info *pll_info;
unsigned m, n, od_enc, od;
bool bypass, enable;
bool bypass;
unsigned long flags;
u32 ctl;
......@@ -103,7 +103,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
bypass = !pll_info->no_bypass_bit &&
!!(ctl & BIT(pll_info->bypass_bit));
enable = !!(ctl & BIT(pll_info->enable_bit));
if (bypass)
return parent_rate;
......@@ -426,16 +425,16 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;
long rate = *parent_rate;
unsigned int div = 1;
clk_info = &cgu->clock_info[ingenic_clk->idx];
if (clk_info->type & CGU_CLK_DIV)
rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
else if (clk_info->type & CGU_CLK_FIXDIV)
rate /= clk_info->fixdiv.div;
div = clk_info->fixdiv.div;
return rate;
return DIV_ROUND_UP(*parent_rate, div);
}
static int
......@@ -455,7 +454,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
if (clk_info->type & CGU_CLK_DIV) {
div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
rate = parent_rate / div;
rate = DIV_ROUND_UP(parent_rate, div);
if (rate != req_rate)
return -EINVAL;
......
......@@ -80,7 +80,7 @@ struct ingenic_cgu_mux_info {
* @reg: offset of the divider control register within the CGU
* @shift: number of bits to left shift the divide value by (ie. the index of
* the lowest bit of the divide value within its control register)
* @div: number of bits to divide the divider value by (i.e. if the
* @div: number to divide the divider value by (i.e. if the
* effective divider value is the value written to the register
* multiplied by some constant)
* @bits: the size of the divide value in bits
......
......@@ -165,7 +165,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
.mux = { CGU_REG_CPCCR, 29, 1 },
.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
.gate = { CGU_REG_SCR, 6 },
.gate = { CGU_REG_SCR, 6, true },
},
/* Gate-only clocks */
......
......@@ -157,7 +157,8 @@ struct clk *mtk_clk_register_gate(
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops)
const struct clk_ops *ops,
unsigned long flags)
{
struct mtk_clk_gate *cg;
struct clk *clk;
......@@ -172,6 +173,7 @@ struct clk *mtk_clk_register_gate(
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.ops = ops;
init.flags = flags;
cg->regmap = regmap;
cg->set_ofs = set_ofs;
......
......@@ -47,6 +47,7 @@ struct clk *mtk_clk_register_gate(
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops);
const struct clk_ops *ops,
unsigned long flags);
#endif /* __DRV_CLK_GATE_H */
......@@ -535,8 +535,8 @@ static const struct mtk_composite top_muxes[] = {
0x0080, 8, 2, 15),
MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents,
0x0080, 16, 3, 23),
MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents,
0x0080, 24, 2, 31),
MUX_GATE_FLAGS_2(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents,
0x0080, 24, 2, 31, 0, CLK_MUX_ROUND_CLOSEST),
MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents,
0x0090, 0, 3, 7),
......
......@@ -223,6 +223,8 @@ static const struct mtk_fixed_factor top_divs[] = {
4),
FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1,
3),
FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2_ck", 1,
3),
};
static const char * const axi_parents[] = {
......@@ -594,7 +596,8 @@ static const char * const a1sys_hp_parents[] = {
"apll1_ck",
"apll1_d2",
"apll1_d4",
"apll1_d8"
"apll1_d8",
"apll1_d3"
};
static const char * const a2sys_hp_parents[] = {
......@@ -602,7 +605,8 @@ static const char * const a2sys_hp_parents[] = {
"apll2_ck",
"apll2_d2",
"apll2_d4",
"apll2_d8"
"apll2_d8",
"apll2_d3"
};
static const char * const asm_l_parents[] = {
......@@ -1463,7 +1467,6 @@ static struct platform_driver clk_mt2712_drv = {
.probe = clk_mt2712_probe,
.driver = {
.name = "clk-mt2712",
.owner = THIS_MODULE,
.of_match_table = of_match_clk_mt2712,
},
};
......
此差异已折叠。
......@@ -533,7 +533,7 @@ static const char * const ca53_parents[] __initconst = {
"univpll"
};
static const char * const ca57_parents[] __initconst = {
static const char * const ca72_parents[] __initconst = {
"clk26m",
"armca15pll",
"mainpll",
......@@ -542,7 +542,7 @@ static const char * const ca57_parents[] __initconst = {
static const struct mtk_composite cpu_muxes[] __initconst = {
MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2),
MUX(CLK_INFRA_CA72SEL, "infra_ca72_sel", ca72_parents, 0x0000, 2, 2),
};
static const struct mtk_composite top_muxes[] __initconst = {
......
......@@ -130,7 +130,7 @@ int mtk_clk_register_gates(struct device_node *node,
gate->regs->set_ofs,
gate->regs->clr_ofs,
gate->regs->sta_ofs,
gate->shift, gate->ops);
gate->shift, gate->ops, gate->flags);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
......@@ -167,7 +167,7 @@ struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
mux->mask = BIT(mc->mux_width) - 1;
mux->shift = mc->mux_shift;
mux->lock = lock;
mux->flags = mc->mux_flags;
mux_hw = &mux->hw;
mux_ops = &clk_mux_ops;
......
此差异已折叠。
此差异已折叠。
#
# Makefile for Meson specific clk
#
# Amlogic clock drivers
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o
obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o
obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o
obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o
obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o
obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
# Amlogic Clock controllers
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o
此差异已折叠。
......@@ -10,18 +10,7 @@
#ifndef __AXG_AOCLKC_H
#define __AXG_AOCLKC_H
#define NR_CLKS 11
/* AO Configuration Clock registers offsets
* Register offsets from the data sheet must be multiplied by 4.
*/
#define AO_RTI_PWR_CNTL_REG1 0x0C
#define AO_RTI_PWR_CNTL_REG0 0x10
#define AO_RTI_GEN_CNTL_REG0 0x40
#define AO_OSCIN_CNTL 0x58
#define AO_CRT_CLK_CNTL1 0x68
#define AO_SAR_CLK 0x90
#define AO_RTC_ALT_CLK_CNTL0 0x94
#define AO_RTC_ALT_CLK_CNTL1 0x98
#define NR_CLKS 17
#include <dt-bindings/clock/axg-aoclkc.h>
#include <dt-bindings/reset/axg-aoclkc.h>
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部