diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-09 14:50:09 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-09 14:50:09 -0700 |
commit | ea5aee6d97fd2d4499b1eebc233861c1def70f06 (patch) | |
tree | 6b332e66bb0ec00b2e35c074ec3f09fb7cf56a1e | |
parent | 8e4ff713ce313dcabbb60e6ede1ffc193e67631f (diff) | |
parent | c1157f60d72e8b20efc670cef28883832f42406c (diff) | |
download | linux-ea5aee6d97fd2d4499b1eebc233861c1def70f06.tar.bz2 |
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk framework updates from Stephen Boyd:
"We have a couple new features and changes in the core clk framework
this time around because we've finally gotten around to fixing some
long standing issues. There's still work to do though, so this pull
request is largely laying down the foundation for all the driver
changes to come in the next merge window.
The first problem we're alleviating is how parents of clks are
specified. With the new method, we should see lots of drivers migrate
away from the current design of string comparisons on the entire clk
tree to a more direct method where they can use clk_hw pointers or
more localized names specified in DT or via clkdev. This should reduce
our reliance on string comparisons for all the topology description
logic that we've been using for years and hopefully speed some things
up while avoiding problems we have with generating clk names.
Beyond that we also got rid of the CLK_IS_BASIC flag because it wasn't
really helping anyone and we introduced big-endian versions of the
basic clk types so that we can get rid of clk_{readl,writel}(). Both
of these are things that driver developers have tried to use over the
years that I typically bat away during code reviews because they're
not useful. It's great to see these two things go away so maintainers
can save time not worrying about these things.
On the driver side we got the usual collection of new SoC support and
non-critical fixes and updates to existing code. The big topics that
stand out are the new driver support for Mediatek MT8183 and MT8516
SoCs, Amlogic Meson8b and G12a SoCs, and the SiFive FU540 SoC. The
other patches in the driver pile are mostly fixes for things that are
being used for the first time or additions for clks that couldn't be
tested before because there wasn't a consumer driver that exercised
them. Details are below and also in the sub-maintainer tags.
Core:
- Remove clk_readl() and introduce BE versions of basic clk types
- Rewrite how clk parents can be specified to allow DT/clkdev lookups
- Removal of the CLK_IS_BASIC clk flag
- Framework documentation updates and fixes
New Drivers:
- Support for STM32F769
- AT91 sam9x60 PMC support
- SiFive FU540 PRCI and PLL support
- Qualcomm QCS404 CDSP clk support
- Qualcomm QCS404 Turing clk support
- Mediatek MT8183 clock support
- Mediatek MT8516 clock support
- Milbeaut M10V clk controller support
- Support for Cirrus Logic Lochnagar clks
Updates:
- Rework AT91 sckc DT bindings
- Fix slow RC oscillator issue on sama5d3
- Mark UFS clk as critical on Hi-Silicon hi3660 SoCs
- Various static analysis fixes/finds and const markings
- Video Engine (ECLK) support on Aspeed SoCs
- Xilinx ZynqMP Versal platform support
- Convert Xilinx ZynqMP driver to be struct oriented
- Fixes for Rockchip rk3328 and rk3288 SoCs
- Sub-type for Rockchip SoCs where mux and divider aren't a single register
- Remove SNVS clock from i.MX7UPL clock driver and bindings
- Improve i.MX5 clock driver for i.MX50 support
- Addition of ADC clock definition for Exynos 5410 SoC (Odroid XU)
- Export a new clock for the MBUS controller on the A13
- Allwinner H6 fixes to support a finer clocking of the video and VPU engines
- Add g12a support in the Amlogic axg audio clock controller
- Add missing PCI USB clock on Rensas RZ/N1
- Add Z2 (Cortex-A53) clocks on Rensas R-Car E3 and RZ/G2E
- A new helper DIV64_U64_ROUND_CLOSEST() in <linux/math64.h>
- VPU and Video Decoder clocks on Amlogic Meson8b
- Finally remove the wrong ABP Meson8b clock id
- Add Video Decoder, PCIe PLL, and CPU Clocks on Amlogic G12A
- Re-expose SAR_ADC_SEL and CTS_OSCIN on Amlogic G12A AO clock controller
- Un-expose some Amlogic AXG-Audio input clocks IDs"
* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (172 commits)
clk: Cache core in clk_fetch_parent_index() without names
clk: imx: correct pfdv2 gate_bit/vld_bit operations
clk: sifive: add a driver for the SiFive FU540 PRCI IP block
clk: analogbits: add Wide-Range PLL library
clk: imx: clk-pllv3: mark expected switch fall-throughs
clk: imx8mq: Add dsi_ipg_div
clk: imx: pllv4: add fractional-N pll support
clk: sunxi-ng: Use the correct style for SPDX License Identifier
clk: sprd: Use the correct style for SPDX License Identifier
clk: renesas: Use the correct style for SPDX License Identifier
clk: qcom: Use the correct style for SPDX License Identifier
clk: davinci: Use the correct style for SPDX License Identifier
clk: actions: Use the correct style for SPDX License Identifier
clk: imx: keep uart clock on during system boot
clk: imx: correct i.MX7D AV PLL num/denom offset
dt-bindings: clk: add documentation for the SiFive PRCI driver
clk: stm32mp1: Add ddrperfm clock
clk: Remove CLK_IS_BASIC clk flag
clock: milbeaut: Add Milbeaut M10V clock controller
dt-bindings: clock: milbeaut: add Milbeaut clock description
...
214 files changed, 11543 insertions, 1465 deletions
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt index de4075413d91..161e63a6c254 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt @@ -14,6 +14,8 @@ Required Properties: - "mediatek,mt7629-apmixedsys" - "mediatek,mt8135-apmixedsys" - "mediatek,mt8173-apmixedsys" + - "mediatek,mt8183-apmixedsys", "syscon" + - "mediatek,mt8516-apmixedsys" - #clock-cells: Must be 1 The apmixedsys controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt index d1606b2c3e63..f3cef1a6d95c 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt @@ -9,6 +9,7 @@ Required Properties: - "mediatek,mt2701-audsys", "syscon" - "mediatek,mt7622-audsys", "syscon" - "mediatek,mt7623-audsys", "mediatek,mt2701-audsys", "syscon" + - "mediatek,mt8183-audiosys", "syscon" - #clock-cells: Must be 1 The AUDSYS controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,camsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,camsys.txt new file mode 100644 index 000000000000..d8930f64aa98 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,camsys.txt @@ -0,0 +1,22 @@ +MediaTek CAMSYS controller +============================ + +The MediaTek camsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt8183-camsys", "syscon" +- #clock-cells: Must be 1 + +The camsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +camsys: camsys@1a000000 { + compatible = "mediatek,mt8183-camsys", "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt index 3f99672163e3..e3bc4a1e7a6e 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt @@ -11,6 +11,7 @@ Required Properties: - "mediatek,mt6797-imgsys", "syscon" - "mediatek,mt7623-imgsys", "mediatek,mt2701-imgsys", "syscon" - "mediatek,mt8173-imgsys", "syscon" + - "mediatek,mt8183-imgsys", "syscon" - #clock-cells: Must be 1 The imgsys controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt index 417bd83d1378..a90913988d7e 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt @@ -15,6 +15,8 @@ Required Properties: - "mediatek,mt7629-infracfg", "syscon" - "mediatek,mt8135-infracfg", "syscon" - "mediatek,mt8173-infracfg", "syscon" + - "mediatek,mt8183-infracfg", "syscon" + - "mediatek,mt8516-infracfg", "syscon" - #clock-cells: Must be 1 - #reset-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipu.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipu.txt new file mode 100644 index 000000000000..aabc8c5c8ed2 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipu.txt @@ -0,0 +1,43 @@ +Mediatek IPU controller +============================ + +The Mediatek ipu controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt8183-ipu_conn", "syscon" + - "mediatek,mt8183-ipu_adl", "syscon" + - "mediatek,mt8183-ipu_core0", "syscon" + - "mediatek,mt8183-ipu_core1", "syscon" +- #clock-cells: Must be 1 + +The ipu controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +ipu_conn: syscon@19000000 { + compatible = "mediatek,mt8183-ipu_conn", "syscon"; + reg = <0 0x19000000 0 0x1000>; + #clock-cells = <1>; +}; + +ipu_adl: syscon@19010000 { + compatible = "mediatek,mt8183-ipu_adl", "syscon"; + reg = <0 0x19010000 0 0x1000>; + #clock-cells = <1>; +}; + +ipu_core0: syscon@19180000 { + compatible = "mediatek,mt8183-ipu_core0", "syscon"; + reg = <0 0x19180000 0 0x1000>; + #clock-cells = <1>; +}; + +ipu_core1: syscon@19280000 { + compatible = "mediatek,mt8183-ipu_core1", "syscon"; + reg = <0 0x19280000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt index b8fb03f3613e..2b882b7ca72e 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt @@ -7,6 +7,7 @@ Required Properties: - compatible: Should be one of: - "mediatek,mt2712-mcucfg", "syscon" + - "mediatek,mt8183-mcucfg", "syscon" - #clock-cells: Must be 1 The mcucfg controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt index 859e67b416d5..72787e7dd227 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt @@ -7,6 +7,7 @@ Required Properties: - compatible: Should be one of: - "mediatek,mt2712-mfgcfg", "syscon" + - "mediatek,mt8183-mfgcfg", "syscon" - #clock-cells: Must be 1 The mfgcfg controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt index 15d977afad31..545eab717c96 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt @@ -11,6 +11,7 @@ Required Properties: - "mediatek,mt6797-mmsys", "syscon" - "mediatek,mt7623-mmsys", "mediatek,mt2701-mmsys", "syscon" - "mediatek,mt8173-mmsys", "syscon" + - "mediatek,mt8183-mmsys", "syscon" - #clock-cells: Must be 1 The mmsys controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt index d160c2b4b6fe..a023b8338960 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt @@ -14,6 +14,8 @@ Required Properties: - "mediatek,mt7629-topckgen" - "mediatek,mt8135-topckgen" - "mediatek,mt8173-topckgen" + - "mediatek,mt8183-topckgen", "syscon" + - "mediatek,mt8516-topckgen" - #clock-cells: Must be 1 The topckgen controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt index 3212afc753c8..57176bb8dbb5 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt @@ -11,6 +11,7 @@ Required Properties: - "mediatek,mt6797-vdecsys", "syscon" - "mediatek,mt7623-vdecsys", "mediatek,mt2701-vdecsys", "syscon" - "mediatek,mt8173-vdecsys", "syscon" + - "mediatek,mt8183-vdecsys", "syscon" - #clock-cells: Must be 1 The vdecsys controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt index 851545357e94..c9faa6269087 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt @@ -9,6 +9,7 @@ Required Properties: - "mediatek,mt2712-vencsys", "syscon" - "mediatek,mt6797-vencsys", "syscon" - "mediatek,mt8173-vencsys", "syscon" + - "mediatek,mt8183-vencsys", "syscon" - #clock-cells: Must be 1 The vencsys controller uses the common clk binding from diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt index 61777ad24f61..0f777749f4f1 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt @@ -6,7 +6,8 @@ devices. Required Properties: -- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D +- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D, + "amlogic,g12a-audio-clkc" for G12A. - reg : physical base address of the clock controller and length of memory mapped region. - clocks : a list of phandle + clock-specifier pairs for the clocks listed diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index e9f70fcdfe80..b520280e33ff 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -8,35 +8,30 @@ Slow Clock controller: Required properties: - compatible : shall be one of the following: - "atmel,at91sam9x5-sckc" or + "atmel,at91sam9x5-sckc", + "atmel,sama5d3-sckc" or "atmel,sama5d4-sckc": at91 SCKC (Slow Clock Controller) - This node contains the slow clock definitions. - - "atmel,at91sam9x5-clk-slow-osc": - at91 slow oscillator - - "atmel,at91sam9x5-clk-slow-rc-osc": - at91 internal slow RC oscillator -- reg : defines the IO memory reserved for the SCKC. -- #size-cells : shall be 0 (reg is used to encode clk id). -- #address-cells : shall be 1 (reg is used to encode clk id). +- #clock-cells : shall be 0. +- clocks : shall be the input parent clock phandle for the clock. +Optional properties: +- atmel,osc-bypass : boolean property. Set this when a clock signal is directly + provided on XIN. For example: - sckc: sckc@fffffe50 { - compatible = "atmel,sama5d3-pmc"; - reg = <0xfffffe50 0x4> - #size-cells = <0>; - #address-cells = <1>; - - /* put at91 slow clocks here */ + sckc@fffffe50 { + compatible = "atmel,at91sam9x5-sckc"; + reg = <0xfffffe50 0x4>; + clocks = <&slow_xtal>; + #clock-cells = <0>; }; Power Management Controller (PMC): Required properties: -- compatible : shall be "atmel,<chip>-pmc", "syscon": +- compatible : shall be "atmel,<chip>-pmc", "syscon" or + "microchip,sam9x60-pmc" <chip> can be: at91rm9200, at91sam9260, at91sam9261, at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9g15, at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35, at91sam9x5, diff --git a/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt new file mode 100644 index 000000000000..b8d8ef3bdc5f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt @@ -0,0 +1,93 @@ +Cirrus Logic Lochnagar Audio Development Board + +Lochnagar is an evaluation and development board for Cirrus Logic +Smart CODEC and Amp devices. It allows the connection of most Cirrus +Logic devices on mini-cards, as well as allowing connection of +various application processor systems to provide a full evaluation +platform. Audio system topology, clocking and power can all be +controlled through the Lochnagar, allowing the device under test +to be used in a variety of possible use cases. + +This binding document describes the binding for the clock portion of +the driver. + +Also see these documents for generic binding information: + [1] Clock : ../clock/clock-bindings.txt + +And these for relevant defines: + [2] include/dt-bindings/clock/lochnagar.h + +This binding must be part of the Lochnagar MFD binding: + [3] ../mfd/cirrus,lochnagar.txt + +Required properties: + + - compatible : One of the following strings: + "cirrus,lochnagar1-clk" + "cirrus,lochnagar2-clk" + + - #clock-cells : Must be 1. The first cell indicates the clock + number, see [2] for available clocks and [1]. + +Optional properties: + + - clocks : Must contain an entry for each clock in clock-names. + - clock-names : May contain entries for each of the following + clocks: + - ln-cdc-clkout : Output clock from CODEC card. + - ln-dsp-clkout : Output clock from DSP card. + - ln-gf-mclk1,ln-gf-mclk2,ln-gf-mclk3,ln-gf-mclk4 : Optional + input audio clocks from host system. + - ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from + external connector. + - ln-spdif-clkout : Optional input audio clock from SPDIF. + - ln-adat-mclk : Optional input audio clock from ADAT. + - ln-pmic-32k : On board fixed clock. + - ln-clk-12m : On board fixed clock. + - ln-clk-11m : On board fixed clock. + - ln-clk-24m : On board fixed clock. + - ln-clk-22m : On board fixed clock. + - ln-clk-8m : On board fixed clock. + - ln-usb-clk-24m : On board fixed clock. + - ln-usb-clk-12m : On board fixed clock. + + - assigned-clocks : A list of Lochnagar clocks to be reparented, see + [2] for available clocks. + - assigned-clock-parents : Parents to be assigned to the clocks + listed in "assigned-clocks". + +Optional nodes: + + - fixed-clock nodes may be registered for the following on board clocks: + - ln-pmic-32k : 32768 Hz + - ln-clk-12m : 12288000 Hz + - ln-clk-11m : 11298600 Hz + - ln-clk-24m : 24576000 Hz + - ln-clk-22m : 22579200 Hz + - ln-clk-8m : 8192000 Hz + - ln-usb-clk-24m : 24576000 Hz + - ln-usb-clk-12m : 12288000 Hz + +Example: + +lochnagar { + lochnagar-clk { + compatible = "cirrus,lochnagar2-clk"; + + #clock-cells = <1>; + + clocks = <&clk-audio>, <&clk_pmic>; + clock-names = "ln-gf-mclk2", "ln-pmic-32k"; + + assigned-clocks = <&lochnagar-clk LOCHNAGAR_CDC_MCLK1>, + <&lochnagar-clk LOCHNAGAR_CDC_MCLK2>; + assigned-clock-parents = <&clk-audio>, + <&clk-pmic>; + }; + + clk-pmic: clk-pmic { + compatible = "fixed-clock"; + clock-cells = <0>; + clock-frequency = <32768>; + }; +}; diff --git a/Documentation/devicetree/bindings/clock/milbeaut-clock.yaml b/Documentation/devicetree/bindings/clock/milbeaut-clock.yaml new file mode 100644 index 000000000000..5cf0b811821e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/milbeaut-clock.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/clock/milbeaut-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Milbeaut SoCs Clock Controller Binding + +maintainers: + - Taichi Sugaya <sugaya.taichi@socionext.com> + +description: | + Milbeaut SoCs Clock controller is an integrated clock controller, which + generates and supplies to all modules. + + This binding uses common clock bindings + [1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +properties: + compatible: + oneOf: + - items: + - enum: + - socionext,milbeaut-m10v-ccu + clocks: + maxItems: 1 + description: external clock + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +examples: + # Clock controller node: + - | + m10v-clk-ctrl@1d021000 { + compatible = "socionext,milbeaut-m10v-clk-ccu"; + reg = <0x1d021000 0x4000>; + #clock-cells = <1>; + clocks = <&clki40mhz>; + }; + + # Required an external clock for Clock controller node: + - | + clocks { + clki40mhz: clki40mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <40000000>; + }; + /* other clocks */ + }; + + # The clock consumer shall specify the desired clock-output of the clock + # controller as below by specifying output-id in its "clk" phandle cell. + # 2: uart + # 4: 32-bit timer + # 7: UHS-I/II + - | + serial@1e700010 { + compatible = "socionext,milbeaut-usio-uart"; + reg = <0x1e700010 0x10>; + interrupts = <0 141 0x4>, <0 149 0x4>; + interrupt-names = "rx", "tx"; + clocks = <&clk 2>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/qcom,turingcc.txt b/Documentation/devicetree/bindings/clock/qcom,turingcc.txt new file mode 100644 index 000000000000..126517de5f9a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,turingcc.txt @@ -0,0 +1,19 @@ +Qualcomm Turing Clock & Reset Controller Binding +------------------------------------------------ + +Required properties : +- compatible: shall contain "qcom,qcs404-turingcc". +- reg: shall contain base register location and length. +- clocks: ahb clock for the TuringCC +- #clock-cells: from common clock binding, shall contain 1. +- #reset-cells: from common reset binding, shall contain 1. + +Example: + turingcc: clock-controller@800000 { + compatible = "qcom,qcs404-turingcc"; + reg = <0x00800000 0x30000>; + clocks = <&gcc GCC_CDSP_CFG_AHB_CLK>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/qoriq-clock.txt b/Documentation/devicetree/bindings/clock/qoriq-clock.txt index c655f28d5918..f7d48f23da44 100644 --- a/Documentation/devicetree/bindings/clock/qoriq-clock.txt +++ b/Documentation/devicetree/bindings/clock/qoriq-clock.txt @@ -39,6 +39,7 @@ Required properties: * "fsl,b4860-clockgen" * "fsl,ls1012a-clockgen" * "fsl,ls1021a-clockgen" + * "fsl,ls1028a-clockgen" * "fsl,ls1043a-clockgen" * "fsl,ls1046a-clockgen" * "fsl,ls1088a-clockgen" @@ -83,8 +84,8 @@ second cell is the clock index for the specified type. 1 cmux index (n in CLKCnCSR) 2 hwaccel index (n in CLKCGnHWACSR) 3 fman 0 for fm1, 1 for fm2 - 4 platform pll 0=pll, 1=pll/2, 2=pll/3, 3=pll/4 - 4=pll/5, 5=pll/6, 6=pll/7, 7=pll/8 + 4 platform pll n=pll/(n+1). For example, when n=1, + that means output_freq=PLL_freq/2. 5 coreclk must be 0 3. Example diff --git a/Documentation/devicetree/bindings/clock/sifive/fu540-prci.txt b/Documentation/devicetree/bindings/clock/sifive/fu540-prci.txt new file mode 100644 index 000000000000..349808f4fb8c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sifive/fu540-prci.txt @@ -0,0 +1,46 @@ +SiFive FU540 PRCI bindings + +On the FU540 family of SoCs, most system-wide clock and reset integration +is via the PRCI IP block. + +Required properties: +- compatible: Should be "sifive,<chip>-prci". Only one value is + supported: "sifive,fu540-c000-prci" +- reg: Should describe the PRCI's register target physical address region +- clocks: Should point to the hfclk device tree node and the rtcclk + device tree node. The RTC clock here is not a time-of-day clock, + but is instead a high-stability clock source for system timers + and cycle counters. +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock via the clock ID +macros defined in include/dt-bindings/clock/sifive-fu540-prci.h. +These macros begin with PRCI_CLK_. + +The hfclk and rtcclk nodes are required, and represent physical +crystals or resonators located on the PCB. These nodes should be present +underneath /, rather than /soc. + +Examples: + +/* under /, in PCB-specific DT data */ +hfclk: hfclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <33333333>; + clock-output-names = "hfclk"; +}; +rtcclk: rtcclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <1000000>; + clock-output-names = "rtcclk"; +}; + +/* under /soc, in SoC-specific DT data */ +prci: clock-controller@10000000 { + compatible = "sifive,fu540-c000-prci"; + reg = <0x0 0x10000000 0x0 0x1000>; + clocks = <&hfclk>, <&rtcclk>; + #clock-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt index b240121d2ac9..cfa04b614d8a 100644 --- a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt +++ b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt @@ -11,6 +11,8 @@ Required properties: "st,stm32f42xx-rcc" "st,stm32f469-rcc" "st,stm32f746-rcc" + "st,stm32f769-rcc" + - reg: should be register base and length as documented in the datasheet - #reset-cells: 1, see below @@ -102,6 +104,10 @@ The secondary index is bound with the following magic numbers: 28 CLK_I2C3 29 CLK_I2C4 30 CLK_LPTIMER (LPTimer1 clock) + 31 CLK_PLL_SRC + 32 CLK_DFSDM1 + 33 CLK_ADFSDM1 + 34 CLK_F769_DSI ) Example: diff --git a/MAINTAINERS b/MAINTAINERS index a3143515e134..960070e36bd9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -979,6 +979,12 @@ F: drivers/iio/adc/ltc2497* X: drivers/iio/*/adjd* F: drivers/staging/iio/*/ad* +ANALOGBITS PLL LIBRARIES +M: Paul Walmsley <paul.walmsley@sifive.com> +S: Supported +F: drivers/clk/analogbits/* +F: include/linux/clk/analogbits* + ANDES ARCHITECTURE M: Greentime Hu <green.hu@gmail.com> M: Vincent Chen <deanbo422@gmail.com> diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 42881f21cede..3e0f09cc0028 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -119,6 +119,9 @@ void __init ti_clk_init_features(void) if (cpu_is_omap343x()) features.flags |= TI_CLK_DPLL_HAS_FREQSEL; + if (omap_type() == OMAP2_DEVICE_TYPE_GP) + features.flags |= TI_CLK_DEVICE_TYPE_GP; + /* Idlest value for interface clocks. * 24xx uses 0 to indicate not ready, and 1 to indicate ready. * 34xx reverses this, just to keep us on our toes diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3a04c73ac03c..baadddf9aad4 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -648,10 +648,10 @@ static struct clockdomain *_get_clkdm(struct omap_hwmod *oh) if (oh->clkdm) { return oh->clkdm; } else if (oh->_clk) { - if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC) + if (!omap2_clk_is_hw_omap(__clk_get_hw(oh->_clk))) return NULL; clk = to_clk_hw_omap(__clk_get_hw(oh->_clk)); - return clk->clkdm; + return clk->clkdm; } return NULL; } diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index d129475fd40d..a95a894aceaf 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -160,7 +160,7 @@ static struct clk __init *alchemy_clk_setup_cpu(const char *parent_name, id.name = ALCHEMY_CPU_CLK; id.parent_names = &parent_name; id.num_parents = 1; - id.flags = CLK_IS_BASIC; + id.flags = 0; id.ops = &alchemy_clkops_cpu; h->init = &id; diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c index b3097fe6441b..af265ae40a61 100644 --- a/arch/powerpc/platforms/512x/clock-commonclk.c +++ b/arch/powerpc/platforms/512x/clock-commonclk.c @@ -239,6 +239,7 @@ static inline struct clk *mpc512x_clk_divider( const char *name, const char *parent_name, u8 clkflags, u32 __iomem *reg, u8 pos, u8 len, int divflags) { + divflags |= CLK_DIVIDER_BIG_ENDIAN; return clk_register_divider(NULL, name, parent_name, clkflags, reg, pos, len, divflags, &clklock); } @@ -250,7 +251,7 @@ static inline struct clk *mpc512x_clk_divtable( { u8 divflags; - divflags = 0; + divflags = CLK_DIVIDER_BIG_ENDIAN; return clk_register_divider_table(NULL, name, parent_name, 0, reg, pos, len, divflags, divtab, &clklock); @@ -261,10 +262,12 @@ static inline struct clk *mpc512x_clk_gated( u32 __iomem *reg, u8 pos) { int clkflags; + u8 gateflags; clkflags = CLK_SET_RATE_PARENT; + gateflags = CLK_GATE_BIG_ENDIAN; return clk_register_gate(NULL, name, parent_name, clkflags, - reg, pos, 0, &clklock); + reg, pos, gateflags, &clklock); } static inline struct clk *mpc512x_clk_muxed(const char *name, @@ -275,7 +278,7 @@ static inline struct clk *mpc512x_clk_muxed(const char *name, u8 muxflags; clkflags = CLK_SET_RATE_PARENT; - muxflags = 0; + muxflags = CLK_MUX_BIG_ENDIAN; return clk_register_mux(NULL, name, parent_names, parent_count, clkflags, reg, pos, len, muxflags, &clklock); diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e705aab9e38b..fc1e0cf44995 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config CLKDEV_LOOKUP bool @@ -219,6 +220,13 @@ config COMMON_CLK_XGENE ---help--- Sypport for the APM X-Gene SoC reference, PLL, and device clocks. +config COMMON_CLK_LOCHNAGAR + tristate "Cirrus Logic Lochnagar clock driver" + depends on MFD_LOCHNAGAR + help + This driver supports the clocking features of the Cirrus Logic + Lochnagar audio development board. + config COMMON_CLK_NXP def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX) select REGMAP_MMIO if ARCH_LPC32XX @@ -297,6 +305,7 @@ config COMMON_CLK_FIXED_MMIO Support for Memory Mapped IO Fixed clocks source "drivers/clk/actions/Kconfig" +source "drivers/clk/analogbits/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imgtec/Kconfig" @@ -309,7 +318,9 @@ source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/samsung/Kconfig" +source "drivers/clk/sifive/Kconfig" source "drivers/clk/sprd/Kconfig" +source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" source "drivers/clk/ti/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1db133652f0c..9ef4305d55e0 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -32,8 +32,10 @@ obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o +obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o +obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o @@ -64,6 +66,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o # please keep this section sorted lexicographically by directory path name obj-y += actions/ +obj-y += analogbits/ obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_ARCH_ARTPEC) += axis/ obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ @@ -93,6 +96,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ +obj-$(CONFIG_CLK_SIFIVE) += sifive/ obj-$(CONFIG_ARCH_SIRF) += sirf/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/clk/actions/owl-common.h b/drivers/clk/actions/owl-common.h index 5a866a8b913d..c000a431471e 100644 --- a/drivers/clk/actions/owl-common.h +++ b/drivers/clk/actions/owl-common.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL common clock driver // diff --git a/drivers/clk/actions/owl-composite.h b/drivers/clk/actions/owl-composite.h index b410ed5bf308..bca38bf8f218 100644 --- a/drivers/clk/actions/owl-composite.h +++ b/drivers/clk/actions/owl-composite.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL composite clock driver // diff --git a/drivers/clk/actions/owl-divider.h b/drivers/clk/actions/owl-divider.h index 92d3e3d23967..083be6d80954 100644 --- a/drivers/clk/actions/owl-divider.h +++ b/drivers/clk/actions/owl-divider.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL divider clock driver // diff --git a/drivers/clk/actions/owl-factor.h b/drivers/clk/actions/owl-factor.h index f1a7ffe896e1..04b89cbfdccb 100644 --- a/drivers/clk/actions/owl-factor.h +++ b/drivers/clk/actions/owl-factor.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL factor clock driver // diff --git a/drivers/clk/actions/owl-fixed-factor.h b/drivers/clk/actions/owl-fixed-factor.h index cc9fe36c0964..3dfd7fd7d292 100644 --- a/drivers/clk/actions/owl-fixed-factor.h +++ b/drivers/clk/actions/owl-fixed-factor.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL fixed factor clock driver // diff --git a/drivers/clk/actions/owl-gate.h b/drivers/clk/actions/owl-gate.h index c2d61ceebce2..c2f161c93fda 100644 --- a/drivers/clk/actions/owl-gate.h +++ b/drivers/clk/actions/owl-gate.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL gate clock driver // diff --git a/drivers/clk/actions/owl-mux.h b/drivers/clk/actions/owl-mux.h index 834284c8c3ae..53b9ab665294 100644 --- a/drivers/clk/actions/owl-mux.h +++ b/drivers/clk/actions/owl-mux.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL mux clock driver // diff --git a/drivers/clk/actions/owl-pll.h b/drivers/clk/actions/owl-pll.h index 6fb0d45bb088..78e5fc360b03 100644 --- a/drivers/clk/actions/owl-pll.h +++ b/drivers/clk/actions/owl-pll.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ // // OWL pll clock driver // diff --git a/drivers/clk/actions/owl-reset.h b/drivers/clk/actions/owl-reset.h index 10f5774979a6..a947ffcb5a02 100644 --- a/drivers/clk/actions/owl-reset.h +++ b/drivers/clk/actions/owl-reset.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ // // Actions Semi Owl SoCs Reset Management Unit driver // diff --git a/drivers/clk/analogbits/Kconfig b/drivers/clk/analogbits/Kconfig new file mode 100644 index 000000000000..b5fd60c7f136 --- /dev/null +++ b/drivers/clk/analogbits/Kconfig @@ -0,0 +1,2 @@ +config CLK_ANALOGBITS_WRPLL_CLN28HPC + bool diff --git a/drivers/clk/analogbits/Makefile b/drivers/clk/analogbits/Makefile new file mode 100644 index 000000000000..bf017447451e --- /dev/null +++ b/drivers/clk/analogbits/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o diff --git a/drivers/clk/analogbits/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c new file mode 100644 index 000000000000..776ead319ae9 --- /dev/null +++ b/drivers/clk/analogbits/wrpll-cln28hpc.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018-2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * + * This library supports configuration parsing and reprogramming of + * the CLN28HPC variant of the Analog Bits Wide Range PLL. The + * intention is for this library to be reusable for any device that + * integrates this PLL; thus the register structure and programming + * details are expected to be provided by a separate IP block driver. + * + * The bulk of this code is primarily useful for clock configurations + * that must operate at arbitrary rates, as opposed to clock configurations + * that are restricted by software or manufacturer guidance to a small, + * pre-determined set of performance points. + * + * References: + * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01 + * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset" + * https://static.dev.sifive.com/FU540-C000-v1.0.pdf + */ + +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/log2.h> +#include <linux/math64.h> +#include <linux/clk/analogbits-wrpll-cln28hpc.h> + +/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */ +#define MIN_INPUT_FREQ 7000000 + +/* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */ +#define MAX_INPUT_FREQ 600000000 + +/* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */ +#define MIN_POST_DIVR_FREQ 7000000 + +/* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */ +#define MAX_POST_DIVR_FREQ 200000000 + +/* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */ +#define MIN_VCO_FREQ 2400000000UL + +/* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */ +#define MAX_VCO_FREQ 4800000000ULL + +/* MAX_DIVQ_DIVISOR: maximum output divisor. Selected by DIVQ = 6 */ +#define MAX_DIVQ_DIVISOR 64 + +/* MAX_DIVR_DIVISOR: maximum reference divisor. Selected by DIVR = 63 */ +#define MAX_DIVR_DIVISOR 64 + +/* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */ +#define MAX_LOCK_US 70 + +/* + * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding + * algorithm + */ +#define ROUND_SHIFT 20 + +/* + * Private functions + */ + +/** + * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth + * @post_divr_freq: input clock rate after the R divider + * + * Select the value to be presented to the PLL RANGE input signals, based + * on the input clock frequency after the post-R-divider @post_divr_freq. + * This code follows the recommendations in the PLL datasheet for filter + * range selection. + * + * Return: The RANGE value to be presented to the PLL configuration inputs, + * or a negative return code upon error. + */ +static int __wrpll_calc_filter_range(unsigned long post_divr_freq) +{ + if (post_divr_freq < MIN_POST_DIVR_FREQ || + post_divr_freq > MAX_POST_DIVR_FREQ) { + WARN(1, "%s: post-divider reference freq out of range: %lu", + __func__, post_divr_freq); + return -ERANGE; + } + + switch (post_divr_freq) { + case 0 ... 10999999: + return 1; + case 11000000 ... 17999999: + return 2; + case 18000000 ... 29999999: + return 3; + case 30000000 ... 49999999: + return 4; + case 50000000 ... 79999999: + return 5; + case 80000000 ... 129999999: + return 6; + } + + return 7; +} + +/** + * __wrpll_calc_fbdiv() - return feedback fixed divide value + * @c: ptr to a struct wrpll_cfg record to read from + * + * The internal feedback path includes a fixed by-two divider; the + * external feedback path does not. Return the appropriate divider + * value (2 or 1) depending on whether internal or external feedback + * is enabled. This code doesn't test for invalid configurations + * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies + * on the caller to do so. + * + * Context: Any context. Caller must protect the memory pointed to by + * @c from simultaneous modification. + * + * Return: 2 if internal feedback is enabled or 1 if external feedback + * is enabled. + */ +static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c) +{ + return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1; +} + +/** + * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate + * @target_rate: target PLL output clock rate + * @vco_rate: pointer to a u64 to store the computed VCO rate into + * + * Determine a reasonable value for the PLL Q post-divider, based on the + * target output rate @target_rate for the PLL. Along with returning the + * computed Q divider value as the return value, this function stores the + * desired target VCO rate into the variable pointed to by @vco_rate. + * + * Context: Any context. Caller must protect the memory pointed to by + * @vco_rate from simultaneous access or modification. + * + * Return: a positive integer DIVQ value to be programmed into the hardware + * upon success, or 0 upon error (since 0 is an invalid DIVQ value) + */ +static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate) +{ + u64 s; + u8 divq = 0; + + if (!vco_rate) { + WARN_ON(1); + goto wcd_out; + } + + s = div_u64(MAX_VCO_FREQ, target_rate); + if (s <= 1) { + divq = 1; + *vco_rate = MAX_VCO_FREQ; + } else if (s > MAX_DIVQ_DIVISOR) { + divq = ilog2(MAX_DIVQ_DIVISOR); + *vco_rate = MIN_VCO_FREQ; + } else { + divq = ilog2(s); + *vco_rate = (u64)target_rate << divq; + } + +wcd_out: + return divq; +} + +/** + * __wrpll_update_parent_rate() - update PLL data when parent rate changes + * @c: ptr to a struct wrpll_cfg record to write PLL data to + * @parent_rate: PLL input refclk rate (pre-R-divider) + * + * Pre-compute some data used by the PLL configuration algorithm when + * the PLL's reference clock rate changes. The intention is to avoid + * computation when the parent rate remains constant - expected to be + * the common case. + * + * Returns: 0 upon success or -ERANGE if the reference clock rate is + * out of range. + */ +static int __wrpll_update_parent_rate(struct wrpll_cfg *c, + unsigned long parent_rate) +{ + u8 max_r_for_parent; + + if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ) + return -ERANGE; + + c->parent_rate = parent_rate; + max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ); + c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent); + + c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ); + + return 0; +} + +/** + * wrpll_configure() - compute PLL configuration for a target rate + * @c: ptr to a struct wrpll_cfg record to write into + * @target_rate: target PLL output clock rate (post-Q-divider) + * @parent_rate: PLL input refclk rate (pre-R-divider) + * + * Compute the appropriate PLL signal configuration values and store + * in PLL context @c. PLL reprogramming is not glitchless, so the + * caller should switch any downstream logic to a different clock + * source or clock-gate it before presenting these values to the PLL + * configuration signals. + * + * The caller must pass this function a pre-initialized struct + * wrpll_cfg record: either initialized to zero (with the + * exception of the .name and .flags fields) or read from the PLL. + * + * Context: Any context. Caller must protect the memory pointed to by @c + * from simultaneous access or modification. + * + * Return: 0 upon success; anything else upon failure. + */ +int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate, + unsigned long parent_rate) +{ + unsigned long ratio; + u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre; + u32 best_f, f, post_divr_freq; + u8 fbdiv, divq, best_r, r; + int range; + + if (c->flags == 0) { + WARN(1, "%s called with uninitialized PLL config", __func__); + return -EINVAL; + } + + /* Initialize rounding data if it hasn't been initialized already */ + if (parent_rate != c->parent_rate) { + if (__wrpll_update_parent_rate(c, parent_rate)) { + pr_err("%s: PLL input rate is out of range\n", + __func__); + return -ERANGE; + } + } + + c->flags &= ~WRPLL_FLAGS_RESET_MASK; + + /* Put the PLL into bypass if the user requests the parent clock rate */ + if (target_rate == parent_rate) { + c->flags |= WRPLL_FLAGS_BYPASS_MASK; + return 0; + } + + c->flags &= ~WRPLL_FLAGS_BYPASS_MASK; + + /* Calculate the Q shift and target VCO rate */ + divq = __wrpll_calc_divq(target_rate, &target_vco_rate); + if (!divq) + return -1; + c->divq = divq; + + /* Precalculate the pre-Q divider target ratio */ + ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate); + + fbdiv = __wrpll_calc_fbdiv(c); + best_r = 0; + best_f = 0; + best_delta = MAX_VCO_FREQ; + + /* + * Consider all values for R which land within + * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R + */ + for (r = c->init_r; r <= c->max_r; ++r) { + f_pre_div = ratio * r; + f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT; + f >>= (fbdiv - 1); + + post_divr_freq = div_u64(parent_rate, r); + vco_pre = fbdiv * post_divr_freq; + vco = vco_pre * f; + + /* Ensure rounding didn't take us out of range */ + if (vco > target_vco_rate) { + --f; + vco = vco_pre * f; + } else if (vco < MIN_VCO_FREQ) { + ++f; + vco = vco_pre * f; + } + + delta = abs(target_rate - vco); + if (delta < best_delta) { + best_delta = delta; + best_r = r; + best_f = f; + } + } + + c->divr = best_r - 1; + c->divf = best_f - 1; + + post_divr_freq = div_u64(parent_rate, best_r); + + /* Pick the best PLL jitter filter */ + range = __wrpll_calc_filter_range(post_divr_freq); + if (range < 0) + return range; + c->range = range; + + return 0; +} + +/** + * wrpll_calc_output_rate() - calculate the PLL's target output rate + * @c: ptr to a struct wrpll_cfg record to read from + * @parent_rate: PLL refclk rate + * + * Given a pointer to the PLL's current input configuration @c and the + * PLL's input reference clock rate @parent_rate (before the R + * pre-divider), calculate the PLL's output clock rate (after the Q + * post-divider). + * + * Context: Any context. Caller must protect the memory pointed to by @c + * from simultaneous modification. + * + * Return: the PLL's output clock rate, in Hz. The return value from + * this function is intended to be convenient to pass directly + * to the Linux clock framework; thus there is no explicit + * error return value. + */ +unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c, + unsigned long parent_rate) +{ + u8 fbdiv; + u64 n; + + if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) { + WARN(1, "external feedback mode not yet supported"); + return ULONG_MAX; + } + + fbdiv = __wrpll_calc_fbdiv(c); + n = parent_rate * fbdiv * (c->divf + 1); + n = div_u64(n, c->divr + 1); + n >>= c->divq; + + return n; +} + +/** + * wrpll_calc_max_lock_us() - return the time for the PLL to lock + * @c: ptr to a struct wrpll_cfg record to read from + * + * Return the minimum amount of time (in microseconds) that the caller + * must wait after reprogramming the PLL to ensure that it is locked + * to the input frequency and stable. This is likely to depend on the DIVR + * value; this is under discussion with the manufacturer. + * + * Return: the minimum amount of time the caller must wait for the PLL + * to lock (in microseconds) + */ +unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c) +{ + return MAX_LOCK_US; +} diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index c75df1cad60e..3732241352ce 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o +obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o +obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c index b1af5a395423..0aabe49aed09 100644 --- a/drivers/clk/at91/at91sam9260.c +++ b/drivers/clk/at91/at91sam9260.c @@ -41,7 +41,7 @@ static u8 sam9260_plla_out[] = { 0, 2 }; static u16 sam9260_plla_icpll[] = { 1, 1 }; -static struct clk_range sam9260_plla_outputs[] = { +static const struct clk_range sam9260_plla_outputs[] = { { .min = 80000000, .max = 160000000 }, { .min = 150000000, .max = 240000000 }, }; @@ -58,7 +58,7 @@ static u8 sam9260_pllb_out[] = { 1 }; static u16 sam9260_pllb_icpll[] = { 1 }; -static struct clk_range sam9260_pllb_outputs[] = { +static const struct clk_range sam9260_pllb_outputs[] = { { .min = 70000000, .max = 130000000 }, }; @@ -128,7 +128,7 @@ static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; -static struct clk_range sam9g20_plla_outputs[] = { +static const struct clk_range sam9g20_plla_outputs[] = { { .min = 745000000, .max = 800000000 }, { .min = 695000000, .max = 750000000 }, { .min = 645000000, .max = 700000000 }, @@ -151,7 +151,7 @@ static u8 sam9g20_pllb_out[] = { 0 }; static u16 sam9g20_pllb_icpll[] = { 0 }; -static struct clk_range sam9g20_pllb_outputs[] = { +static const struct clk_range sam9g20_pllb_outputs[] = { { .min = 30000000, .max = 100000000 }, }; @@ -182,7 +182,7 @@ static const struct clk_master_characteristics sam9261_mck_characteristics = { .divisors = { 1, 2, 4, 0 }, }; -static struct clk_range sam9261_plla_outputs[] = { +static const struct clk_range sam9261_plla_outputs[] = { { .min = 80000000, .max = 200000000 }, { .min = 190000000, .max = 240000000 }, }; @@ -199,7 +199,7 @@ static u8 sam9261_pllb_out[] = { 1 }; static u16 sam9261_pllb_icpll[] = { 1 }; -static struct clk_range sam9261_pllb_outputs[] = { +static const struct clk_range sam9261_pllb_outputs[] = { { .min = 70000000, .max = 130000000 }, }; @@ -262,7 +262,7 @@ static const struct clk_master_characteristics sam9263_mck_characteristics = { .divisors = { 1, 2, 4, 0 }, }; -static struct clk_range sam9263_pll_outputs[] = { +static const struct clk_range sam9263_pll_outputs[] = { { .min = 80000000, .max = 200000000 }, { .min = 190000000, .max = 240000000 }, }; diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c index 5aeef68b4bdd..0ac34cdaa106 100644 --- a/drivers/clk/at91/at91sam9rl.c +++ b/drivers/clk/at91/at91sam9rl.c @@ -14,7 +14,7 @@ static const struct clk_master_characteristics sam9rl_mck_characteristics = { static u8 sam9rl_plla_out[] = { 0, 2 }; -static struct clk_range sam9rl_plla_outputs[] = { +static const struct clk_range sam9rl_plla_outputs[] = { { .min = 80000000, .max = 200000000 }, { .min = 190000000, .max = 240000000 }, }; diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c index 3487e03d4bc6..0855f3a80cc7 100644 --- a/drivers/clk/at91/at91sam9x5.c +++ b/drivers/clk/at91/at91sam9x5.c @@ -17,7 +17,7 @@ static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 745000000, .max = 800000000 }, { .min = 695000000, .max = 750000000 }, { .min = 645000000, .max = 700000000 }, @@ -49,6 +49,13 @@ static const struct { { .n = "pck1", .p = "prog1", .id = 9 }, }; +static const struct clk_pcr_layout at91sam9x5_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + struct pck { char *n; u8 id; @@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9x5_pcr_layout, at91sam9x5_periphck[i].n, "masterck", at91sam9x5_periphck[i].id, @@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, for (i = 0; extra_pcks[i].id; i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9x5_pcr_layout, extra_pcks[i].n, "masterck", extra_pcks[i].id, diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 66e7f7baf958..5f18847965c1 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -11,6 +11,7 @@ * */ +#include <linux/bitfield.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> #include <linux/clk/at91_pmc.h> @@ -31,6 +32,7 @@ struct clk_generated { spinlock_t *lock; u32 id; u32 gckdiv; + const struct clk_pcr_layout *layout; u8 parent_id; bool audio_pll_allowed; }; @@ -47,14 +49,14 @@ static int clk_generated_enable(struct clk_hw *hw) __func__, gck->gckdiv, gck->parent_id); spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(gck->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK | - AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, - AT91_PMC_PCR_GCKCSS(gck->parent_id) | - AT91_PMC_PCR_CMD | - AT91_PMC_PCR_GCKDIV(gck->gckdiv) | + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_update_bits(gck->regmap, gck->layout->offset, + AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask | + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + field_prep(gck->layout->gckcss_mask, gck->parent_id) | + gck->layout->cmd | + FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) | AT91_PMC_PCR_GCKEN); spin_unlock_irqrestore(gck->lock, flags); return 0; @@ -66,11 +68,11 @@ static void clk_generated_disable(struct clk_hw *hw) unsigned long flags; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(gck->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, - AT91_PMC_PCR_CMD); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_update_bits(gck->regmap, gck->layout->offset, + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd); spin_unlock_irqrestore(gck->lock, flags); } @@ -81,9 +83,9 @@ static int clk_generated_is_enabled(struct clk_hw *hw) unsigned int status; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(gck->regmap, AT91_PMC_PCR, &status); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_read(gck->regmap, gck->layout->offset, &status); spin_unlock_irqrestore(gck->lock, flags); return status & AT91_PMC_PCR_GCKEN ? 1 : 0; @@ -259,19 +261,18 @@ static void clk_generated_startup(struct clk_generated *gck) unsigned long flags; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(gck->regmap, AT91_PMC_PCR, &tmp); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_read(gck->regmap, gck->layout->offset, &tmp); spin_unlock_irqrestore(gck->lock, flags); - gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) - >> AT91_PMC_PCR_GCKCSS_OFFSET; - gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK) - >> AT91_PMC_PCR_GCKDIV_OFFSET; + gck->parent_id = field_get(gck->layout->gckcss_mask, tmp); + gck->gckdiv = FIELD_GET(AT91_PMC_PCR_GCKDIV_MASK, tmp); } struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char **parent_names, u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range) @@ -298,6 +299,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, gck->lock = lock; gck->range = *range; gck->audio_pll_allowed = pll_audio; + gck->layout = layout; clk_generated_startup(gck); hw = &gck->hw; diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index eb53b4a8fab6..12b5bf4cc7bb 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -29,6 +29,7 @@ struct clk_master { struct regmap *regmap; const struct clk_master_layout *layout; const struct clk_master_characteristics *characteristics; + u32 mckr; }; static inline bool clk_master_ready(struct regmap *regmap) @@ -69,7 +70,7 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, master->characteristics; unsigned int mckr; - regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + regmap_read(master->regmap, master->layout->offset, &mckr); mckr &= layout->mask; pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; @@ -95,7 +96,7 @@ static u8 clk_master_get_parent(struct clk_hw *hw) struct clk_master *master = to_clk_master(hw); unsigned int mckr; - regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + regmap_read(master->regmap, master->layout->offset, &mckr); return mckr & AT91_PMC_CSS; } @@ -147,13 +148,14 @@ at91_clk_register_master(struct regmap *regmap, return hw; } - const struct clk_master_layout at91rm9200_master_layout = { .mask = 0x31F, .pres_shift = 2, + .offset = AT91_PMC_MCKR, }; const struct clk_master_layout at91sam9x5_master_layout = { .mask = 0x373, .pres_shift = 4, + .offset = AT91_PMC_MCKR, }; diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index 65c1defa78e4..6b7748b9588a 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -8,6 +8,7 @@ * */ +#include <linux/bitops.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> #include <linux/clk/at91_pmc.h> @@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock); #define PERIPHERAL_ID_MAX 31 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) -#define PERIPHERAL_RSHIFT_MASK 0x3 -#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK) - #define PERIPHERAL_MAX_SHIFT 3 struct clk_peripheral { @@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral { spinlock_t *lock; u32 id; u32 div; + const struct clk_pcr_layout *layout; bool auto_div; }; @@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) return 0; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(periph->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_update_bits(periph->regmap, periph->layout->offset, + periph->layout->div_mask | periph->layout->cmd | AT91_PMC_PCR_EN, - AT91_PMC_PCR_DIV(periph->div) | - AT91_PMC_PCR_CMD | + field_prep(periph->layout->div_mask, periph->div) | + periph->layout->cmd | AT91_PMC_PCR_EN); spin_unlock_irqrestore(periph->lock, flags); @@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) return; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(periph->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, - AT91_PMC_PCR_CMD); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_update_bits(periph->regmap, periph->layout->offset, + AT91_PMC_PCR_EN | periph->layout->cmd, + periph->layout->cmd); spin_unlock_irqrestore(periph->lock, flags); } @@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) return 1; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(periph->regmap, AT91_PMC_PCR, &status); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_read(periph->regmap, periph->layout->offset, &status); spin_unlock_irqrestore(periph->lock, flags); return status & AT91_PMC_PCR_EN ? 1 : 0; @@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, return parent_rate; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(periph->regmap, AT91_PMC_PCR, &status); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_read(periph->regmap, periph->layout->offset, &status); spin_unlock_irqrestore(periph->lock, flags); if (status & AT91_PMC_PCR_EN) { - periph->div = PERIPHERAL_RSHIFT(status); + periph->div = field_get(periph->layout->div_mask, status); periph->auto_div = false; } else { clk_sam9x5_peripheral_autodiv(periph); @@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = { struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range) { @@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, periph->div = 0; periph->regmap = regmap; periph->lock = lock; - periph->auto_div = true; + if (layout->div_mask) + periph->auto_div = true; + periph->layout = layout; periph->range = *range; hw = &periph->hw; diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c new file mode 100644 index 000000000000..34b817825b22 --- /dev/null +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Microchip Technology Inc. + * + */ + +#include <linux/bitfield.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + +#include "pmc.h" + +#define PMC_PLL_CTRL0 0xc +#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) +#define PMC_PLL_CTRL0_ENPLL BIT(28) +#define PMC_PLL_CTRL0_ENPLLCK BIT(29) +#define PMC_PLL_CTRL0_ENLOCK BIT(31) + +#define PMC_PLL_CTRL1 0x10 +#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0) +#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24) + +#define PMC_PLL_ACR 0x18 +#define PMC_PLL_ACR_DEFAULT 0x1b040010UL +#define PMC_PLL_ACR_UTMIVR BIT(12) +#define PMC_PLL_ACR_UTMIBG BIT(13) +#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24) + +#define PMC_PLL_UPDT 0x1c +#define PMC_PLL_UPDT_UPDATE BIT(8) + +#define PMC_PLL_ISR0 0xec + +#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1) +#define UPLL_DIV 2 +#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) + +#define PLL_MAX_ID 1 + +struct sam9x60_pll { + struct clk_hw hw; + struct regmap *regmap; + spinlock_t *lock; + const struct clk_pll_characteristics *characteristics; + u32 frac; + u8 id; + u8 div; + u16 mul; +}; + +#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw) + +static inline bool sam9x60_pll_ready(struct regmap *regmap, int id) +{ + unsigned int status; + + regmap_read(regmap, PMC_PLL_ISR0, &status); + + return !!(status & BIT(id)); +} + +static int sam9x60_pll_prepare(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + struct regmap *regmap = pll->regmap; + unsigned long flags; + u8 div; + u16 mul; + u32 val; + + spin_lock_irqsave(pll->lock, flags); + regmap_write(regmap, PMC_PLL_UPDT, pll->id); + + regmap_read(regmap, PMC_PLL_CTRL0, &val); + div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); + + regmap_read(regmap, PMC_PLL_CTRL1, &val); + mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val); + + if (sam9x60_pll_ready(regmap, pll->id) && + (div == pll->div && mul == pll->mul)) { + spin_unlock_irqrestore(pll->lock, flags); + return 0; + } + + /* Recommended value for PMC_PLL_ACR */ + val = PMC_PLL_ACR_DEFAULT; + regmap_write(regmap, PMC_PLL_ACR, val); + + regmap_write(regmap, PMC_PLL_CTRL1, + FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul)); + + if (pll->characteristics->upll) { + /* Enable the UTMI internal bandgap */ + val |= PMC_PLL_ACR_UTMIBG; + regmap_write(regmap, PMC_PLL_ACR, val); + + udelay(10); + + /* Enable the UTMI internal regulator */ + val |= PMC_PLL_ACR_UTMIVR; + regmap_write(regmap, PMC_PLL_ACR, val); + + udelay(10); + } + + regmap_update_bits(regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + regmap_write(regmap, PMC_PLL_CTRL0, + PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL | + PMC_PLL_CTRL0_ENPLLCK | pll->div); + + regmap_update_bits(regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + while (!sam9x60_pll_ready(regmap, pll->id)) + cpu_relax(); + + spin_unlock_irqrestore(pll->lock, flags); + + return 0; +} + +static int sam9x60_pll_is_prepared(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_ready(pll->regmap, pll->id); +} + +static void sam9x60_pll_unprepare(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + unsigned long flags; + + spin_lock_irqsave(pll->lock, flags); + + regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id); + + regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, + PMC_PLL_CTRL0_ENPLLCK, 0); + + regmap_update_bits(pll->regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0); + + if (pll->characteristics->upll) + regmap_update_bits(pll->regmap, PMC_PLL_ACR, + PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0); + + regmap_update_bits(pll->regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + spin_unlock_irqrestore(pll->lock, flags); +} + +static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return (parent_rate * (pll->mul + 1)) / (pll->div + 1); +} + +static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll, + unsigned long rate, + unsigned long parent_rate, + bool update) +{ + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + unsigned long bestremainder = ULONG_MAX; + unsigned long maxdiv, mindiv, tmpdiv; + long bestrate = -ERANGE; + unsigned long bestdiv = 0; + unsigned long bestmul = 0; + unsigned long bestfrac = 0; + + if (rate < characteristics->output[0].min || + rate > characteristics->output[0].max) + return -ERANGE; + + if (!pll->characteristics->upll) { + mindiv = parent_rate / rate; + if (mindiv < 2) + mindiv = 2; + + maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate); + if (maxdiv > PLL_DIV_MAX) + maxdiv = PLL_DIV_MAX; + } else { + mindiv = maxdiv = UPLL_DIV; + } + + for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { + unsigned long remainder; + unsigned long tmprate; + unsigned long tmpmul; + unsigned long tmpfrac = 0; + + /* + * Calculate the multiplier associated with the current + * divider that provide the closest rate to the requested one. + */ + tmpmul = mult_frac(rate, tmpdiv, parent_rate); + tmprate = mult_frac(parent_rate, tmpmul, tmpdiv); + remainder = rate - tmprate; + + if (remainder) { + tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22), + parent_rate); + + tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate, + tmpdiv * (1 << 22)); + + if (tmprate > rate) + remainder = tmprate - rate; + else + remainder = rate - tmprate; + } + + /* + * Compare the remainder with the best remainder found until + * now and elect a new best multiplier/divider pair if the + * current remainder is smaller than the best one. + */ + if (remainder < bestremainder) { + bestremainder = remainder; + bestdiv = tmpdiv; + bestmul = tmpmul; + bestrate = tmprate; + bestfrac = tmpfrac; + } + + /* We've found a perfect match! */ + if (!remainder) + break; + } + + /* Check if bestrate is a valid output rate */ + if (bestrate < characteristics->output[0].min && + bestrate > characteristics->output[0].max) + return -ERANGE; + + if (update) { + pll->div = bestdiv - 1; + pll->mul = bestmul - 1; + pll->frac = bestfrac; + } + + return bestrate; +} + +static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false); +} + +static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true); +} + +static const struct clk_ops pll_ops = { + .prepare = sam9x60_pll_prepare, + .unprepare = sam9x60_pll_unprepare, + .is_prepared = sam9x60_pll_is_prepared, + .recalc_rate = sam9x60_pll_recalc_rate, + .round_rate = sam9x60_pll_round_rate, + .set_rate = sam9x60_pll_set_rate, +}; + +struct clk_hw * __init +sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics) +{ + struct sam9x60_pll *pll; + struct clk_hw *hw; + struct clk_init_data init; + unsigned int pllr; + int ret; + + if (id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + pll->id = id; + pll->hw.init = &init; + pll->characteristics = characteristics; + pll->regmap = regmap; + pll->lock = lock; + + regmap_write(regmap, PMC_PLL_UPDT, id); + regmap_read(regmap, PMC_PLL_CTRL0, &pllr); + pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr); + regmap_read(regmap, PMC_PLL_CTRL1, &pllr); + pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr); + + hw = &pll->hw; + ret = clk_hw_register(NULL, hw); + if (ret) { + kfree(pll); + hw = ERR_PTR(ret); + } + + return hw; +} + diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 79ee1c760f2a..ebc37ee33518 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -23,9 +23,13 @@ #define RM9200_USB_DIV_SHIFT 28 #define RM9200_USB_DIV_TAB_SIZE 4 +#define SAM9X5_USBS_MASK GENMASK(0, 0) +#define SAM9X60_USBS_MASK GENMASK(1, 0) + struct at91sam9x5_clk_usb { struct clk_hw hw; struct regmap *regmap; + u32 usbs_mask; }; #define to_at91sam9x5_clk_usb(hw) \ @@ -111,8 +115,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) if (index > 1) return -EINVAL; - regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, - index ? AT91_PMC_USBS : 0); + regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index); return 0; } @@ -124,7 +127,7 @@ static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) regmap_read(usb->regmap, AT91_PMC_USB, &usbr); - return usbr & AT91_PMC_USBS; + return usbr & usb->usbs_mask; } static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, @@ -190,9 +193,10 @@ static const struct clk_ops at91sam9n12_usb_ops = { .set_rate = at91sam9x5_clk_usb_set_rate, }; -struct clk_hw * __init -at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, - const char **parent_names, u8 num_parents) +static struct clk_hw * __init +_at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents, + u32 usbs_mask) { struct at91sam9x5_clk_usb *usb; struct clk_hw *hw; @@ -212,6 +216,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; + usb->usbs_mask = SAM9X5_USBS_MASK; hw = &usb->hw; ret = clk_hw_register(NULL, &usb->hw); @@ -224,6 +229,22 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, } struct clk_hw * __init +at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) +{ + return _at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents, SAM9X5_USBS_MASK); +} + +struct clk_hw * __init +sam9x60_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) +{ + return _at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents, SAM9X60_USBS_MASK); +} + +struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name) { diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index b95bb4e2a927..aa1754eac59f 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, of_sama5d2_clk_audio_pll_pmc_setup); #endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ +static const struct clk_pcr_layout dt_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), + .gckcss_mask = GENMASK(10, 8), +}; + #ifdef CONFIG_HAVE_AT91_GENERATED_CLK #define GENERATED_SOURCE_MAX 6 @@ -146,7 +154,8 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) id == GCK_ID_CLASSD)) pll_audio = true; - hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &dt_pcr_layout, name, parent_names, num_parents, id, pll_audio, &range); if (IS_ERR(hw)) @@ -448,6 +457,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &dt_pcr_layout, name, parent_name, id, &range); diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index a0e5ce9c9b9e..2311204948be 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -38,6 +38,7 @@ struct clk_range { #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} struct clk_master_layout { + u32 offset; u32 mask; u8 pres_shift; }; @@ -65,9 +66,10 @@ extern const struct clk_pll_layout sama5d3_pll_layout; struct clk_pll_characteristics { struct clk_range input; int num_output; - struct clk_range *output; + const struct clk_range *output; u16 *icpll; u8 *out; + u8 upll : 1; }; struct clk_programmable_layout { @@ -82,6 +84,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout; extern const struct clk_programmable_layout at91sam9g45_programmable_layout; extern const struct clk_programmable_layout at91sam9x5_programmable_layout; +struct clk_pcr_layout { + u32 offset; + u32 cmd; + u32 div_mask; + u32 gckcss_mask; + u32 pid_mask; +}; + +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + #define ndck(a, s) (a[s - 1].id + 1) #define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, @@ -107,6 +120,7 @@ at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char **parent_names, u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range); @@ -145,6 +159,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name, const char *parent_name, u32 id); struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range); @@ -158,6 +173,11 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name, const char *parent_name); struct clk_hw * __init +sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics); + +struct clk_hw * __init at91_clk_register_programmable(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents, u8 id, const struct clk_programmable_layout *layout); @@ -183,6 +203,9 @@ struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name); struct clk_hw * __init +sam9x60_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents); +struct clk_hw * __init at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name, const u32 *divisors); diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c new file mode 100644 index 000000000000..9790ddfa5b3c --- /dev/null +++ b/drivers/clk/at91/sam9x60.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> + +#include <dt-bindings/clock/at91.h> + +#include "pmc.h" + +static DEFINE_SPINLOCK(pmc_pll_lock); + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 140000000, .max = 200000000 }, + .divisors = { 1, 2, 4, 3 }, + .have_div3_pres = 1, +}; + +static const struct clk_master_layout sam9x60_master_layout = { + .mask = 0x373, + .pres_shift = 4, + .offset = 0x28, +}; + +static const struct clk_range plla_outputs[] = { + { .min = 300000000, .max = 600000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 12000000, .max = 48000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, +}; + +static const struct clk_range upll_outputs[] = { + { .min = 300000000, .max = 500000000 }, +}; + +static const struct clk_pll_characteristics upll_characteristics = { + .input = { .min = 12000000, .max = 48000000 }, + .num_output = ARRAY_SIZE(upll_outputs), + .output = upll_outputs, + .upll = true, +}; + +static const struct clk_programmable_layout sam9x60_programmable_layout = { + .pres_shift = 8, + .css_mask = 0x1f, + .have_slck_mck = 0, +}; + +static const struct clk_pcr_layout sam9x60_pcr_layout = { + .offset = 0x88, + .cmd = BIT(31), + .gckcss_mask = GENMASK(12, 8), + .pid_mask = GENMASK(6, 0), +}; + +static const struct { + char *n; + char *p; + u8 id; +} sam9x60_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "qspick", .p = "masterck", .id = 19 }, +}; + +static const struct { + char *n; + u8 id; +} sam9x60_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "flex0_clk", .id = 5, }, + { .n = "flex1_clk", .id = 6, }, + { .n = "flex2_clk", .id = 7, }, + { .n = "flex3_clk", .id = 8, }, + { .n = "flex6_clk", .id = 9, }, + { .n = "flex7_clk", .id = 10, }, + { .n = "flex8_clk", .id = 11, }, + { .n = "sdmmc0_clk", .id = 12, }, + { .n = "flex4_clk", .id = 13, }, + { .n = "flex5_clk", .id = 14, }, + { .n = "flex9_clk", .id = 15, }, + { .n = "flex10_clk", .id = 16, }, + { .n = "tcb0_clk", .id = 17, }, + { .n = "pwm_clk", .id = 18, }, + { .n = "adc_clk", .id = 19, }, + { .n = "dma0_clk", .id = 20, }, + { .n = "matrix_clk", .id = 21, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "udphs_clk", .id = 23, }, + { .n = "macb0_clk", .id = 24, }, + { .n = "lcd_clk", .id = 25, }, + { .n = "sdmmc1_clk", .id = 26, }, + { .n = "macb1_clk", .id = 27, }, + { .n = "ssc_clk", .id = 28, }, + { .n = "can0_clk", .id = 29, }, + { .n = "can1_clk", .id = 30, }, + { .n = "flex11_clk", .id = 32, }, + { .n = "flex12_clk", .id = 33, }, + { .n = "i2s_clk", .id = 34, }, + { .n = "qspi_clk", .id = 35, }, + { .n = "gfx2d_clk", .id = 36, }, + { .n = "pit64b_clk", .id = 37, }, + { .n = "trng_clk", .id = 38, }, + { .n = "aes_clk", .id = 39, }, + { .n = "tdes_clk", .id = 40, }, + { .n = "sha_clk", .id = 41, }, + { .n = "classd_clk", .id = 42, }, + { .n = "isi_clk", .id = 43, }, + { .n = "pioD_clk", .id = 44, }, + { .n = "tcb1_clk", .id = 45, }, + { .n = "dbgu_clk", .id = 47, }, + { .n = "mpddr_clk", .id = 49, }, +}; + +static const struct { + char *n; + u8 id; + struct clk_range r; + bool pll; +} sam9x60_gck[] = { + { .n = "flex0_gclk", .id = 5, }, + { .n = "flex1_gclk", .id = 6, }, + { .n = "flex2_gclk", .id = 7, }, + { .n = "flex3_gclk", .id = 8, }, + { .n = "flex6_gclk", .id = 9, }, + { .n = "flex7_gclk", .id = 10, }, + { .n = "flex8_gclk", .id = 11, }, + { .n = "sdmmc0_gclk", .id = 12, .r = { .min = 0, .max = 105000000 }, }, + { .n = "flex4_gclk", .id = 13, }, + { .n = "flex5_gclk", .id = 14, }, + { .n = "flex9_gclk", .id = 15, }, + { .n = "flex10_gclk", .id = 16, }, + { .n = "tcb0_gclk", .id = 17, }, + { .n = "adc_gclk", .id = 19, }, + { .n = "lcd_gclk", .id = 25, .r = { .min = 0, .max = 140000000 }, }, + { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, }, + { .n = "flex11_gclk", .id = 32, }, + { .n = "flex12_gclk", .id = 33, }, + { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, + .pll = true, }, + { .n = "pit64b_gclk", .id = 37, }, + { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, + .pll = true, }, + { .n = "tcb1_gclk", .id = 45, }, + { .n = "dbgu_gclk", .id = 47, }, +}; + +static void __init sam9x60_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *td_slck_name, *md_slck_name, *mainxtal_name; + struct pmc_data *sam9x60_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "td_slck"); + if (i < 0) + return; + + td_slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "md_slck"); + if (i < 0) + return; + + md_slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(sam9x60_systemck), + nck(sam9x60_periphck), + nck(sam9x60_gck)); + if (!sam9x60_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_MAIN] = hw; + + hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack", + "mainck", 0, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck", + "main_osc", 1, &upll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = md_slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + hw = at91_clk_register_master(regmap, "masterck", 3, parent_names, + &sam9x60_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = "pllack"; + parent_names[1] = "upllck"; + parent_names[2] = "mainck"; + parent_names[3] = "mainck"; + hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = md_slck_name; + parent_names[1] = td_slck_name; + parent_names[2] = "mainck"; + parent_names[3] = "masterck"; + parent_names[4] = "pllack"; + parent_names[5] = "upllck"; + for (i = 0; i < 8; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 6, i, + &sam9x60_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) { + hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n, + sam9x60_systemck[i].p, + sam9x60_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->shws[sam9x60_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sam9x60_pcr_layout, + sam9x60_periphck[i].n, + "masterck", + sam9x60_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->phws[sam9x60_periphck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) { + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sam9x60_pcr_layout, + sam9x60_gck[i].n, + parent_names, 6, + sam9x60_gck[i].id, + sam9x60_gck[i].pll, + &sam9x60_gck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->ghws[sam9x60_gck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x60_pmc); + + return; + +err_free: + pmc_data_free(sam9x60_pmc); +} +/* Some clks are used for a clocksource */ +CLK_OF_DECLARE(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup); diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 81943fac4537..6509d0934804 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 }; static u16 plla_icpll[] = { 0 }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 600000000, .max = 1200000000 }, }; @@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = { .out = plla_out, }; +static const struct clk_pcr_layout sama5d2_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .gckcss_mask = GENMASK(10, 8), + .pid_mask = GENMASK(6, 0), +}; + static const struct { char *n; char *p; @@ -274,6 +281,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_periphck[i].n, "masterck", sama5d2_periphck[i].id, @@ -286,6 +294,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_periph32ck[i].n, "h32mxck", sama5d2_periph32ck[i].id, @@ -304,6 +313,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[5] = "audiopll_pmcck"; for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) { hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_gck[i].n, parent_names, 6, sama5d2_gck[i].id, diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c index b645a9d59cdb..25b156d4e645 100644 --- a/drivers/clk/at91/sama5d4.c +++ b/drivers/clk/at91/sama5d4.c @@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 }; static u16 plla_icpll[] = { 0 }; -static struct clk_range plla_outputs[] = { +static const struct clk_range plla_outputs[] = { { .min = 600000000, .max = 1200000000 }, }; @@ -28,6 +28,12 @@ static const struct clk_pll_characteristics plla_characteristics = { .out = plla_out, }; +static const struct clk_pcr_layout sama5d4_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(6, 0), +}; + static const struct { char *n; char *p; @@ -232,6 +238,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d4_pcr_layout, sama5d4_periphck[i].n, "masterck", sama5d4_periphck[i].id, @@ -244,6 +251,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d4_pcr_layout, sama5d4_periph32ck[i].n, "h32mxck", sama5d4_periph32ck[i].id, diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index ab6ecefc49ad..e76b1d64e905 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -152,28 +152,6 @@ at91_clk_register_slow_osc(void __iomem *sckcr, return hw; } -static void __init -of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - u32 startup; - bool bypass; - - parent_name = of_clk_get_parent_name(np, 0); - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "atmel,startup-time-usec", &startup); - bypass = of_property_read_bool(np, "atmel,osc-bypass"); - - hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, - bypass); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -266,28 +244,6 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, return hw; } -static void __init -of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) -{ - struct clk_hw *hw; - u32 frequency = 0; - u32 accuracy = 0; - u32 startup = 0; - const char *name = np->name; - - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "clock-frequency", &frequency); - of_property_read_u32(np, "clock-accuracy", &accuracy); - of_property_read_u32(np, "atmel,startup-time-usec", &startup); - - hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, - startup); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) { struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); @@ -365,68 +321,72 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, return hw; } -static void __init -of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) +static void __init at91sam9x5_sckc_register(struct device_node *np, + unsigned int rc_osc_startup_us) { + const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; + void __iomem *regbase = of_iomap(np, 0); + struct device_node *child = NULL; + const char *xtal_name; struct clk_hw *hw; - const char *parent_names[2]; - unsigned int num_parents; - const char *name = np->name; + bool bypass; - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > 2) + if (!regbase) + return; + + hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768, + 50000000, rc_osc_startup_us); + if (IS_ERR(hw)) return; - of_clk_parent_fill(np, parent_names, num_parents); + xtal_name = of_clk_get_parent_name(np, 0); + if (!xtal_name) { + /* DT backward compatibility */ + child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc"); + if (!child) + return; + + xtal_name = of_clk_get_parent_name(child, 0); + bypass = of_property_read_bool(child, "atmel,osc-bypass"); + + child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow"); + } else { + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + } + + if (!xtal_name) + return; - of_property_read_string(np, "clock-output-names", &name); + hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name, + 1200000, bypass); + if (IS_ERR(hw)) + return; - hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, - num_parents); + hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); if (IS_ERR(hw)) return; of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -static const struct of_device_id sckc_clk_ids[] __initconst = { - /* Slow clock */ - { - .compatible = "atmel,at91sam9x5-clk-slow-osc", - .data = of_at91sam9x5_clk_slow_osc_setup, - }, - { - .compatible = "atmel,at91sam9x5-clk-slow-rc-osc", - .data = of_at91sam9x5_clk_slow_rc_osc_setup, - }, - { - .compatible = "atmel,at91sam9x5-clk-slow", - .data = of_at91sam9x5_clk_slow_setup, - }, - { /*sentinel*/ } -}; + /* DT backward compatibility */ + if (child) + of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw); +} static void __init of_at91sam9x5_sckc_setup(struct device_node *np) { - struct device_node *childnp; - void (*clk_setup)(struct device_node *, void __iomem *); - const struct of_device_id *clk_id; - void __iomem *regbase = of_iomap(np, 0); - - if (!regbase) - return; - - for_each_child_of_node(np, childnp) { - clk_id = of_match_node(sckc_clk_ids, childnp); - if (!clk_id) - continue; - clk_setup = clk_id->data; - clk_setup(childnp, regbase); - } + at91sam9x5_sckc_register(np, 75); } CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", of_at91sam9x5_sckc_setup); +static void __init of_sama5d3_sckc_setup(struct device_node *np) +{ + at91sam9x5_sckc_register(np, 500); +} +CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc", + of_sama5d3_sckc_setup); + static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) { struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 596136793fc4..42b4df6ba249 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -87,10 +87,10 @@ struct aspeed_clk_gate { /* TODO: ask Aspeed about the actual parent data */ static const struct aspeed_gate_data aspeed_gates[] = { /* clk rst name parent flags */ - [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */ + [ASPEED_CLK_GATE_ECLK] = { 0, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */ [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */ [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */ - [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */ + [ASPEED_CLK_GATE_VCLK] = { 3, -1, "vclk-gate", NULL, 0 }, /* Video Capture */ [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", CLK_IS_CRITICAL }, /* PCIe/PCI */ [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, CLK_IS_CRITICAL }, /* DAC */ [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL }, @@ -113,6 +113,24 @@ static const struct aspeed_gate_data aspeed_gates[] = { [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ }; +static const char * const eclk_parent_names[] = { + "mpll", + "hpll", + "dpll", +}; + +static const struct clk_div_table ast2500_eclk_div_table[] = { + { 0x0, 2 }, + { 0x1, 2 }, + { 0x2, 3 }, + { 0x3, 4 }, + { 0x4, 5 }, + { 0x5, 6 }, + { 0x6, 7 }, + { 0x7, 8 }, + { 0 } +}; + static const struct clk_div_table ast2500_mac_div_table[] = { { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */ { 0x1, 4 }, @@ -192,18 +210,21 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val) struct aspeed_clk_soc_data { const struct clk_div_table *div_table; + const struct clk_div_table *eclk_div_table; const struct clk_div_table *mac_div_table; struct clk_hw *(*calc_pll)(const char *name, u32 val); }; static const struct aspeed_clk_soc_data ast2500_data = { .div_table = ast2500_div_table, + .eclk_div_table = ast2500_eclk_div_table, .mac_div_table = ast2500_mac_div_table, .calc_pll = aspeed_ast2500_calc_pll, }; static const struct aspeed_clk_soc_data ast2400_data = { .div_table = ast2400_div_table, + .eclk_div_table = ast2400_div_table, .mac_div_table = ast2400_div_table, .calc_pll = aspeed_ast2400_calc_pll, }; @@ -522,6 +543,22 @@ static int aspeed_clk_probe(struct platform_device *pdev) return PTR_ERR(hw); aspeed_clk_data->hws[ASPEED_CLK_24M] = hw; + hw = clk_hw_register_mux(dev, "eclk-mux", eclk_parent_names, + ARRAY_SIZE(eclk_parent_names), 0, + scu_base + ASPEED_CLK_SELECTION, 2, 0x3, 0, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_ECLK_MUX] = hw; + + hw = clk_hw_register_divider_table(dev, "eclk", "eclk-mux", 0, + scu_base + ASPEED_CLK_SELECTION, 28, + 3, 0, soc_data->eclk_div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_ECLK] = hw; + /* * TODO: There are a number of clocks that not included in this driver * as more information is required: @@ -531,7 +568,6 @@ static int aspeed_clk_probe(struct platform_device *pdev) * RGMII * RMII * UART[1..5] clock source mux - * Video Engine (ECLK) mux and clock divider */ for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) { diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 46604214bba0..b06038b8f658 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -218,7 +218,7 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); init.name = name; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; hw = &composite->hw; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index e5a17265cfaf..3f9ff78c4a2a 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -25,6 +25,22 @@ * parent - fixed parent. No clk_set_parent support */ +static inline u32 clk_div_readl(struct clk_divider *divider) +{ + if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) + return ioread32be(divider->reg); + + return readl(divider->reg); +} + +static inline void clk_div_writel(struct clk_divider *divider, u32 val) +{ + if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) + iowrite32be(val, divider->reg); + else + writel(val, divider->reg); +} + static unsigned int _get_table_maxdiv(const struct clk_div_table *table, u8 width) { @@ -135,7 +151,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, struct clk_divider *divider = to_clk_divider(hw); unsigned int val; - val = clk_readl(divider->reg) >> divider->shift; + val = clk_div_readl(divider) >> divider->shift; val &= clk_div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, @@ -370,7 +386,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_READ_ONLY) { u32 val; - val = clk_readl(divider->reg) >> divider->shift; + val = clk_div_readl(divider) >> divider->shift; val &= clk_div_mask(divider->width); return divider_ro_round_rate(hw, rate, prate, divider->table, @@ -420,11 +436,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { val = clk_div_mask(divider->width) << (divider->shift + 16); } else { - val = clk_readl(divider->reg); + val = clk_div_readl(divider); val &= ~(clk_div_mask(divider->width) << divider->shift); } val |= (u32)value << divider->shift; - clk_writel(val, divider->reg); + clk_div_writel(divider, val); if (divider->lock) spin_unlock_irqrestore(divider->lock, flags); @@ -475,7 +491,7 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name, init.ops = &clk_divider_ro_ops; else init.ops = &clk_divider_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 241b3f8c61a9..8b343e59dc61 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -64,12 +64,14 @@ const struct clk_ops clk_fixed_factor_ops = { }; EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); -struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - unsigned int mult, unsigned int div) +static struct clk_hw * +__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, + const char *name, const char *parent_name, int index, + unsigned long flags, unsigned int mult, unsigned int div) { struct clk_fixed_factor *fix; - struct clk_init_data init; + struct clk_init_data init = { }; + struct clk_parent_data pdata = { .index = index }; struct clk_hw *hw; int ret; @@ -84,12 +86,18 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, init.name = name; init.ops = &clk_fixed_factor_ops; - init.flags = flags | CLK_IS_BASIC; - init.parent_names = &parent_name; + init.flags = flags; + if (parent_name) + init.parent_names = &parent_name; + else + init.parent_data = &pdata; init.num_parents = 1; hw = &fix->hw; - ret = clk_hw_register(dev, hw); + if (dev) + ret = clk_hw_register(dev, hw); + else + ret = of_clk_hw_register(np, hw); if (ret) { kfree(fix); hw = ERR_PTR(ret); @@ -97,6 +105,14 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, return hw; } + +struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1, + flags, mult, div); +} EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor); struct clk *clk_register_fixed_factor(struct device *dev, const char *name, @@ -143,11 +159,10 @@ static const struct of_device_id set_rate_parent_matches[] = { { /* Sentinel */ }, }; -static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) +static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) { - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; - const char *parent_name; unsigned long flags = 0; u32 div, mult; int ret; @@ -165,30 +180,28 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) } of_property_read_string(node, "clock-output-names", &clk_name); - parent_name = of_clk_get_parent_name(node, 0); if (of_match_node(set_rate_parent_matches, node)) flags |= CLK_SET_RATE_PARENT; - clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, - mult, div); - if (IS_ERR(clk)) { + hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0, + flags, mult, div); + if (IS_ERR(hw)) { /* - * If parent clock is not registered, registration would fail. * Clear OF_POPULATED flag so that clock registration can be * attempted again from probe function. */ of_node_clear_flag(node, OF_POPULATED); - return clk; + return ERR_CAST(hw); } - ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); if (ret) { - clk_unregister(clk); + clk_hw_unregister_fixed_factor(hw); return ERR_PTR(ret); } - return clk; + return hw; } /** @@ -203,17 +216,17 @@ CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock", static int of_fixed_factor_clk_remove(struct platform_device *pdev) { - struct clk *clk = platform_get_drvdata(pdev); + struct clk_hw *clk = platform_get_drvdata(pdev); of_clk_del_provider(pdev->dev.of_node); - clk_unregister_fixed_factor(clk); + clk_hw_unregister_fixed_factor(clk); return 0; } static int of_fixed_factor_clk_probe(struct platform_device *pdev) { - struct clk *clk; + struct clk_hw *clk; /* * This function is not executed when of_fixed_factor_clk_setup diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 00ef4f5e53fe..a7e4aef7a376 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -68,7 +68,7 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, init.name = name; init.ops = &clk_fixed_rate_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdfe2e423d15..d81f1d2e9129 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -13,6 +13,22 @@ #include <linux/slab.h> #include <linux/rational.h> +static inline u32 clk_fd_readl(struct clk_fractional_divider *fd) +{ + if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) + return ioread32be(fd->reg); + + return readl(fd->reg); +} + +static inline void clk_fd_writel(struct clk_fractional_divider *fd, u32 val) +{ + if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) + iowrite32be(val, fd->reg); + else + writel(val, fd->reg); +} + static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -27,7 +43,7 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, else __acquire(fd->lock); - val = clk_readl(fd->reg); + val = clk_fd_readl(fd); if (fd->lock) spin_unlock_irqrestore(fd->lock, flags); @@ -115,10 +131,10 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, else __acquire(fd->lock); - val = clk_readl(fd->reg); + val = clk_fd_readl(fd); val &= ~(fd->mmask | fd->nmask); val |= (m << fd->mshift) | (n << fd->nshift); - clk_writel(val, fd->reg); + clk_fd_writel(fd, val); if (fd->lock) spin_unlock_irqrestore(fd->lock, flags); @@ -151,7 +167,7 @@ struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, init.name = name; init.ops = &clk_fractional_divider_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index f05823cd9b21..1b99fc962745 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -23,6 +23,22 @@ * parent - fixed parent. No clk_set_parent support */ +static inline u32 clk_gate_readl(struct clk_gate *gate) +{ + if (gate->flags & CLK_GATE_BIG_ENDIAN) + return ioread32be(gate->reg); + + return readl(gate->reg); +} + +static inline void clk_gate_writel(struct clk_gate *gate, u32 val) +{ + if (gate->flags & CLK_GATE_BIG_ENDIAN) + iowrite32be(val, gate->reg); + else + writel(val, gate->reg); +} + /* * It works on following logic: * @@ -55,7 +71,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) if (set) reg |= BIT(gate->bit_idx); } else { - reg = clk_readl(gate->reg); + reg = clk_gate_readl(gate); if (set) reg |= BIT(gate->bit_idx); @@ -63,7 +79,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) reg &= ~BIT(gate->bit_idx); } - clk_writel(reg, gate->reg); + clk_gate_writel(gate, reg); if (gate->lock) spin_unlock_irqrestore(gate->lock, flags); @@ -88,7 +104,7 @@ int clk_gate_is_enabled(struct clk_hw *hw) u32 reg; struct clk_gate *gate = to_clk_gate(hw); - reg = clk_readl(gate->reg); + reg = clk_gate_readl(gate); /* if a set bit disables this clk, flip it before masking */ if (gate->flags & CLK_GATE_SET_TO_DISABLE) @@ -142,7 +158,7 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, init.name = name; init.ops = &clk_gate_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index c2f07f0d077c..9d930edd6516 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -137,7 +137,7 @@ static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, init.name = name; init.ops = clk_gpio_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 8e4581004695..bd328b0eb243 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/err.h> -#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/of.h> @@ -272,7 +271,7 @@ static const struct clk_ops periclk_ops = { .set_rate = clk_periclk_set_rate, }; -static __init struct clk *hb_clk_init(struct device_node *node, const struct clk_ops *ops) +static void __init hb_clk_init(struct device_node *node, const struct clk_ops *ops, unsigned long clkflags) { u32 reg; struct hb_clk *hb_clk; @@ -284,11 +283,11 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk rc = of_property_read_u32(node, "reg", ®); if (WARN_ON(rc)) - return NULL; + return; hb_clk = kzalloc(sizeof(*hb_clk), GFP_KERNEL); if (WARN_ON(!hb_clk)) - return NULL; + return; /* Map system registers */ srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); @@ -301,7 +300,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk init.name = clk_name; init.ops = ops; - init.flags = 0; + init.flags = clkflags; parent_name = of_clk_get_parent_name(node, 0); init.parent_names = &parent_name; init.num_parents = 1; @@ -311,33 +310,31 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk rc = clk_hw_register(NULL, &hb_clk->hw); if (WARN_ON(rc)) { kfree(hb_clk); - return NULL; + return; } - rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &hb_clk->hw); - return hb_clk->hw.clk; + of_clk_add_hw_provider(node, of_clk_hw_simple_get, &hb_clk->hw); } static void __init hb_pll_init(struct device_node *node) { - hb_clk_init(node, &clk_pll_ops); + hb_clk_init(node, &clk_pll_ops, 0); } CLK_OF_DECLARE(hb_pll, "calxeda,hb-pll-clock", hb_pll_init); static void __init hb_a9periph_init(struct device_node *node) { - hb_clk_init(node, &a9periphclk_ops); + hb_clk_init(node, &a9periphclk_ops, 0); } CLK_OF_DECLARE(hb_a9periph, "calxeda,hb-a9periph-clock", hb_a9periph_init); static void __init hb_a9bus_init(struct device_node *node) { - struct clk *clk = hb_clk_init(node, &a9bclk_ops); - clk_prepare_enable(clk); + hb_clk_init(node, &a9bclk_ops, CLK_IS_CRITICAL); } CLK_OF_DECLARE(hb_a9bus, "calxeda,hb-a9bus-clock", hb_a9bus_init); static void __init hb_emmc_init(struct device_node *node) { - hb_clk_init(node, &periclk_ops); + hb_clk_init(node, &periclk_ops, 0); } CLK_OF_DECLARE(hb_emmc, "calxeda,hb-emmc-clock", hb_emmc_init); diff --git a/drivers/clk/clk-lochnagar.c b/drivers/clk/clk-lochnagar.c new file mode 100644 index 000000000000..a2f31e58ee48 --- /dev/null +++ b/drivers/clk/clk-lochnagar.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Lochnagar clock control + * + * Copyright (c) 2017-2018 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + * + * Author: Charles Keepax <ckeepax@opensource.cirrus.com> + */ + +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <linux/mfd/lochnagar.h> +#include <linux/mfd/lochnagar1_regs.h> +#include <linux/mfd/lochnagar2_regs.h> + +#include <dt-bindings/clk/lochnagar.h> + +#define LOCHNAGAR_NUM_CLOCKS (LOCHNAGAR_SPDIF_CLKOUT + 1) + +struct lochnagar_clk { + const char * const name; + struct clk_hw hw; + + struct lochnagar_clk_priv *priv; + + u16 cfg_reg; + u16 ena_mask; + + u16 src_reg; + u16 src_mask; +}; + +struct lochnagar_clk_priv { + struct device *dev; + struct regmap *regmap; + enum lochnagar_type type; + + const char **parents; + unsigned int nparents; + + struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS]; +}; + +static const char * const lochnagar1_clk_parents[] = { + "ln-none", + "ln-spdif-mclk", + "ln-psia1-mclk", + "ln-psia2-mclk", + "ln-cdc-clkout", + "ln-dsp-clkout", + "ln-pmic-32k", + "ln-gf-mclk1", + "ln-gf-mclk3", + "ln-gf-mclk2", + "ln-gf-mclk4", +}; + +static const char * const lochnagar2_clk_parents[] = { + "ln-none", + "ln-cdc-clkout", + "ln-dsp-clkout", + "ln-pmic-32k", + "ln-spdif-mclk", + "ln-clk-12m", + "ln-clk-11m", + "ln-clk-24m", + "ln-clk-22m", + "ln-clk-8m", + "ln-usb-clk-24m", + "ln-gf-mclk1", + "ln-gf-mclk3", + "ln-gf-mclk2", + "ln-psia1-mclk", + "ln-psia2-mclk", + "ln-spdif-clkout", + "ln-adat-mclk", + "ln-usb-clk-12m", +}; + +#define LN1_CLK(ID, NAME, REG) \ + [LOCHNAGAR_##ID] = { \ + .name = NAME, \ + .cfg_reg = LOCHNAGAR1_##REG, \ + .ena_mask = LOCHNAGAR1_##ID##_ENA_MASK, \ + .src_reg = LOCHNAGAR1_##ID##_SEL, \ + .src_mask = LOCHNAGAR1_SRC_MASK, \ + } + +#define LN2_CLK(ID, NAME) \ + [LOCHNAGAR_##ID] = { \ + .name = NAME, \ + .cfg_reg = LOCHNAGAR2_##ID##_CTRL, \ + .src_reg = LOCHNAGAR2_##ID##_CTRL, \ + .ena_mask = LOCHNAGAR2_CLK_ENA_MASK, \ + .src_mask = LOCHNAGAR2_CLK_SRC_MASK, \ + } + +static const struct lochnagar_clk lochnagar1_clks[LOCHNAGAR_NUM_CLOCKS] = { + LN1_CLK(CDC_MCLK1, "ln-cdc-mclk1", CDC_AIF_CTRL2), + LN1_CLK(CDC_MCLK2, "ln-cdc-mclk2", CDC_AIF_CTRL2), + LN1_CLK(DSP_CLKIN, "ln-dsp-clkin", DSP_AIF), + LN1_CLK(GF_CLKOUT1, "ln-gf-clkout1", GF_AIF1), +}; + +static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = { + LN2_CLK(CDC_MCLK1, "ln-cdc-mclk1"), + LN2_CLK(CDC_MCLK2, "ln-cdc-mclk2"), + LN2_CLK(DSP_CLKIN, "ln-dsp-clkin"), + LN2_CLK(GF_CLKOUT1, "ln-gf-clkout1"), + LN2_CLK(GF_CLKOUT2, "ln-gf-clkout2"), + LN2_CLK(PSIA1_MCLK, "ln-psia1-mclk"), + LN2_CLK(PSIA2_MCLK, "ln-psia2-mclk"), + LN2_CLK(SPDIF_MCLK, "ln-spdif-mclk"), + LN2_CLK(ADAT_MCLK, "ln-adat-mclk"), + LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"), +}; + +static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw) +{ + return container_of(hw, struct lochnagar_clk, hw); +} + +static int lochnagar_clk_prepare(struct clk_hw *hw) +{ + struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw); + struct lochnagar_clk_priv *priv = lclk->priv; + struct regmap *regmap = priv->regmap; + int ret; + + ret = regmap_update_bits(regmap, lclk->cfg_reg, + lclk->ena_mask, lclk->ena_mask); + if (ret < 0) + dev_dbg(priv->dev, "Failed to prepare %s: %d\n", + lclk->name, ret); + + return ret; +} + +static void lochnagar_clk_unprepare(struct clk_hw *hw) +{ + struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw); + struct lochnagar_clk_priv *priv = lclk->priv; + struct regmap *regmap = priv->regmap; + int ret; + + ret = regmap_update_bits(regmap, lclk->cfg_reg, lclk->ena_mask, 0); + if (ret < 0) + dev_dbg(priv->dev, "Failed to unprepare %s: %d\n", + lclk->name, ret); +} + +static int lochnagar_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw); + struct lochnagar_clk_priv *priv = lclk->priv; + struct regmap *regmap = priv->regmap; + int ret; + + ret = regmap_update_bits(regmap, lclk->src_reg, lclk->src_mask, index); + if (ret < 0) + dev_dbg(priv->dev, "Failed to reparent %s: %d\n", + lclk->name, ret); + + return ret; +} + +static u8 lochnagar_clk_get_parent(struct clk_hw *hw) +{ + struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw); + struct lochnagar_clk_priv *priv = lclk->priv; + struct regmap *regmap = priv->regmap; + unsigned int val; + int ret; + + ret = regmap_read(regmap, lclk->src_reg, &val); + if (ret < 0) { + dev_dbg(priv->dev, "Failed to read parent of %s: %d\n", + lclk->name, ret); + return priv->nparents; + } + + val &= lclk->src_mask; + + return val; +} + +static const struct clk_ops lochnagar_clk_ops = { + .prepare = lochnagar_clk_prepare, + .unprepare = lochnagar_clk_unprepare, + .set_parent = lochnagar_clk_set_parent, + .get_parent = lochnagar_clk_get_parent, +}; + +static int lochnagar_init_parents(struct lochnagar_clk_priv *priv) +{ + struct device_node *np = priv->dev->of_node; + int i, j; + + switch (priv->type) { + case LOCHNAGAR1: + memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks)); + + priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents); + priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents, + sizeof(lochnagar1_clk_parents), + GFP_KERNEL); + break; + case LOCHNAGAR2: + memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks)); + + priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents); + priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents, + sizeof(lochnagar2_clk_parents), + GFP_KERNEL); + break; + default: + dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type); + return -EINVAL; + } + + if (!priv->parents) + return -ENOMEM; + + for (i = 0; i < priv->nparents; i++) { + j = of_property_match_string(np, "clock-names", + priv->parents[i]); + if (j >= 0) + priv->parents[i] = of_clk_get_parent_name(np, j); + } + + return 0; +} + +static struct clk_hw * +lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data) +{ + struct lochnagar_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(priv->lclks)) { + dev_err(priv->dev, "Invalid index %u\n", idx); + return ERR_PTR(-EINVAL); + } + + return &priv->lclks[idx].hw; +} + +static int lochnagar_init_clks(struct lochnagar_clk_priv *priv) +{ + struct clk_init_data clk_init = { + .ops = &lochnagar_clk_ops, + .parent_names = priv->parents, + .num_parents = priv->nparents, + }; + struct lochnagar_clk *lclk; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) { + lclk = &priv->lclks[i]; + + if (!lclk->name) + continue; + + clk_init.name = lclk->name; + + lclk->priv = priv; + lclk->hw.init = &clk_init; + + ret = devm_clk_hw_register(priv->dev, &lclk->hw); + if (ret) { + dev_err(priv->dev, "Failed to register %s: %d\n", + lclk->name, ret); + return ret; + } + } + + ret = devm_of_clk_add_hw_provider(priv->dev, lochnagar_of_clk_hw_get, + priv); + if (ret < 0) + dev_err(priv->dev, "Failed to register provider: %d\n", ret); + + return ret; +} + +static const struct of_device_id lochnagar_of_match[] = { + { .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 }, + { .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 }, + {} +}; +MODULE_DEVICE_TABLE(of, lochnagar_of_match); + +static int lochnagar_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lochnagar_clk_priv *priv; + const struct of_device_id *of_id; + int ret; + + of_id = of_match_device(lochnagar_of_match, dev); + if (!of_id) + return -EINVAL; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->regmap = dev_get_regmap(dev->parent, NULL); + priv->type = (enum lochnagar_type)of_id->data; + + ret = lochnagar_init_parents(priv); + if (ret) + return ret; + + return lochnagar_init_clks(priv); +} + +static struct platform_driver lochnagar_clk_driver = { + .driver = { + .name = "lochnagar-clk", + .of_match_table = lochnagar_of_match, + }, + .probe = lochnagar_clk_probe, +}; +module_platform_driver(lochnagar_clk_driver); + +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>"); +MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c new file mode 100644 index 000000000000..5fc78faf820c --- /dev/null +++ b/drivers/clk/clk-milbeaut.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Socionext Inc. + * Copyright (C) 2016 Linaro Ltd. + */ + +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#define M10V_CLKSEL1 0x0 +#define CLKSEL(n) (((n) - 1) * 4 + M10V_CLKSEL1) + +#define M10V_PLL1 "pll1" +#define M10V_PLL1DIV2 "pll1-2" +#define M10V_PLL2 "pll2" +#define M10V_PLL2DIV2 "pll2-2" +#define M10V_PLL6 "pll6" +#define M10V_PLL6DIV2 "pll6-2" +#define M10V_PLL6DIV3 "pll6-3" +#define M10V_PLL7 "pll7" +#define M10V_PLL7DIV2 "pll7-2" +#define M10V_PLL7DIV5 "pll7-5" +#define M10V_PLL9 "pll9" +#define M10V_PLL10 "pll10" +#define M10V_PLL10DIV2 "pll10-2" +#define M10V_PLL11 "pll11" + +#define M10V_SPI_PARENT0 "spi-parent0" +#define M10V_SPI_PARENT1 "spi-parent1" +#define M10V_SPI_PARENT2 "spi-parent2" +#define M10V_UHS1CLK2_PARENT0 "uhs1clk2-parent0" +#define M10V_UHS1CLK2_PARENT1 "uhs1clk2-parent1" +#define M10V_UHS1CLK2_PARENT2 "uhs1clk2-parent2" +#define M10V_UHS1CLK1_PARENT0 "uhs1clk1-parent0" +#define M10V_UHS1CLK1_PARENT1 "uhs1clk1-parent1" +#define M10V_NFCLK_PARENT0 "nfclk-parent0" +#define M10V_NFCLK_PARENT1 "nfclk-parent1" +#define M10V_NFCLK_PARENT2 "nfclk-parent2" +#define M10V_NFCLK_PARENT3 "nfclk-parent3" +#define M10V_NFCLK_PARENT4 "nfclk-parent4" +#define M10V_NFCLK_PARENT5 "nfclk-parent5" + +#define M10V_DCHREQ 1 +#define M10V_UPOLL_RATE 1 +#define M10V_UTIMEOUT 250 + +#define M10V_EMMCCLK_ID 0 +#define M10V_ACLK_ID 1 +#define M10V_HCLK_ID 2 +#define M10V_PCLK_ID 3 +#define M10V_RCLK_ID 4 +#define M10V_SPICLK_ID 5 +#define M10V_NFCLK_ID 6 +#define M10V_UHS1CLK2_ID 7 +#define M10V_NUM_CLKS 8 + +#define to_m10v_div(_hw) container_of(_hw, struct m10v_clk_divider, hw) + +static struct clk_hw_onecell_data *m10v_clk_data; + +static DEFINE_SPINLOCK(m10v_crglock); + +struct m10v_clk_div_factors { + const char *name; + const char *parent_name; + u32 offset; + u8 shift; + u8 width; + const struct clk_div_table *table; + unsigned long div_flags; + int onecell_idx; +}; + +struct m10v_clk_div_fixed_data { + const char *name; + const char *parent_name; + u8 div; + u8 mult; + int onecell_idx; +}; + +struct m10v_clk_mux_factors { + const char *name; + const char * const *parent_names; + u8 num_parents; + u32 offset; + u8 shift; + u8 mask; + u32 *table; + unsigned long mux_flags; + int onecell_idx; +}; + +static const struct clk_div_table emmcclk_table[] = { + { .val = 0, .div = 8 }, + { .val = 1, .div = 9 }, + { .val = 2, .div = 10 }, + { .val = 3, .div = 15 }, + { .div = 0 }, +}; + +static const struct clk_div_table mclk400_table[] = { + { .val = 1, .div = 2 }, + { .val = 3, .div = 4 }, + { .div = 0 }, +}; + +static const struct clk_div_table mclk200_table[] = { + { .val = 3, .div = 4 }, + { .val = 7, .div = 8 }, + { .div = 0 }, +}; + +static const struct clk_div_table aclk400_table[] = { + { .val = 1, .div = 2 }, + { .val = 3, .div = 4 }, + { .div = 0 }, +}; + +static const struct clk_div_table aclk300_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 3 }, + { .div = 0 }, +}; + +static const struct clk_div_table aclk_table[] = { + { .val = 3, .div = 4 }, + { .val = 7, .div = 8 }, + { .div = 0 }, +}; + +static const struct clk_div_table aclkexs_table[] = { + { .val = 3, .div = 4 }, + { .val = 4, .div = 5 }, + { .val = 5, .div = 6 }, + { .val = 7, .div = 8 }, + { .div = 0 }, +}; + +static const struct clk_div_table hclk_table[] = { + { .val = 7, .div = 8 }, + { .val = 15, .div = 16 }, + { .div = 0 }, +}; + +static const struct clk_div_table hclkbmh_table[] = { + { .val = 3, .div = 4 }, + { .val = 7, .div = 8 }, + { .div = 0 }, +}; + +static const struct clk_div_table pclk_table[] = { + { .val = 15, .div = 16 }, + { .val = 31, .div = 32 }, + { .div = 0 }, +}; + +static const struct clk_div_table rclk_table[] = { + { .val = 0, .div = 8 }, + { .val = 1, .div = 16 }, + { .val = 2, .div = 24 }, + { .val = 3, .div = 32 }, + { .div = 0 }, +}; + +static const struct clk_div_table uhs1clk0_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 3 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { .val = 4, .div = 16 }, + { .div = 0 }, +}; + +static const struct clk_div_table uhs2clk_table[] = { + { .val = 0, .div = 9 }, + { .val = 1, .div = 10 }, + { .val = 2, .div = 11 }, + { .val = 3, .div = 12 }, + { .val = 4, .div = 13 }, + { .val = 5, .div = 14 }, + { .val = 6, .div = 16 }, + { .val = 7, .div = 18 }, + { .div = 0 }, +}; + +static u32 spi_mux_table[] = {0, 1, 2}; +static const char * const spi_mux_names[] = { + M10V_SPI_PARENT0, M10V_SPI_PARENT1, M10V_SPI_PARENT2 +}; + +static u32 uhs1clk2_mux_table[] = {2, 3, 4, 8}; +static const char * const uhs1clk2_mux_names[] = { + M10V_UHS1CLK2_PARENT0, M10V_UHS1CLK2_PARENT1, + M10V_UHS1CLK2_PARENT2, M10V_PLL6DIV2 +}; + +static u32 uhs1clk1_mux_table[] = {3, 4, 8}; +static const char * const uhs1clk1_mux_names[] = { + M10V_UHS1CLK1_PARENT0, M10V_UHS1CLK1_PARENT1, M10V_PLL6DIV2 +}; + +static u32 nfclk_mux_table[] = {0, 1, 2, 3, 4, 8}; +static const char * const nfclk_mux_names[] = { + M10V_NFCLK_PARENT0, M10V_NFCLK_PARENT1, M10V_NFCLK_PARENT2, + M10V_NFCLK_PARENT3, M10V_NFCLK_PARENT4, M10V_NFCLK_PARENT5 +}; + +static const struct m10v_clk_div_fixed_data m10v_pll_fixed_data[] = { + {M10V_PLL1, NULL, 1, 40, -1}, + {M10V_PLL2, NULL, 1, 30, -1}, + {M10V_PLL6, NULL, 1, 35, -1}, + {M10V_PLL7, NULL, 1, 40, -1}, + {M10V_PLL9, NULL, 1, 33, -1}, + {M10V_PLL10, NULL, 5, 108, -1}, + {M10V_PLL10DIV2, M10V_PLL10, 2, 1, -1}, + {M10V_PLL11, NULL, 2, 75, -1}, +}; + +static const struct m10v_clk_div_fixed_data m10v_div_fixed_data[] = { + {"usb2", NULL, 2, 1, -1}, + {"pcisuppclk", NULL, 20, 1, -1}, + {M10V_PLL1DIV2, M10V_PLL1, 2, 1, -1}, + {M10V_PLL2DIV2, M10V_PLL2, 2, 1, -1}, + {M10V_PLL6DIV2, M10V_PLL6, 2, 1, -1}, + {M10V_PLL6DIV3, M10V_PLL6, 3, 1, -1}, + {M10V_PLL7DIV2, M10V_PLL7, 2, 1, -1}, + {M10V_PLL7DIV5, M10V_PLL7, 5, 1, -1}, + {"ca7wd", M10V_PLL2DIV2, 12, 1, -1}, + {"pclkca7wd", M10V_PLL1DIV2, 16, 1, -1}, + {M10V_SPI_PARENT0, M10V_PLL10DIV2, 2, 1, -1}, + {M10V_SPI_PARENT1, M10V_PLL10DIV2, 4, 1, -1}, + {M10V_SPI_PARENT2, M10V_PLL7DIV2, 8, 1, -1}, + {M10V_UHS1CLK2_PARENT0, M10V_PLL7, 4, 1, -1}, + {M10V_UHS1CLK2_PARENT1, M10V_PLL7, 8, 1, -1}, + {M10V_UHS1CLK2_PARENT2, M10V_PLL7, 16, 1, -1}, + {M10V_UHS1CLK1_PARENT0, M10V_PLL7, 8, 1, -1}, + {M10V_UHS1CLK1_PARENT1, M10V_PLL7, 16, 1, -1}, + {M10V_NFCLK_PARENT0, M10V_PLL7DIV2, 8, 1, -1}, + {M10V_NFCLK_PARENT1, M10V_PLL7DIV2, 10, 1, -1}, + {M10V_NFCLK_PARENT2, M10V_PLL7DIV2, 13, 1, -1}, + {M10V_NFCLK_PARENT3, M10V_PLL7DIV2, 16, 1, -1}, + {M10V_NFCLK_PARENT4, M10V_PLL7DIV2, 40, 1, -1}, + {M10V_NFCLK_PARENT5, M10V_PLL7DIV5, 10, 1, -1}, +}; + +static const struct m10v_clk_div_factors m10v_div_factor_data[] = { + {"emmc", M10V_PLL11, CLKSEL(1), 28, 3, emmcclk_table, 0, + M10V_EMMCCLK_ID}, + {"mclk400", M10V_PLL1DIV2, CLKSEL(10), 7, 3, mclk400_table, 0, -1}, + {"mclk200", M10V_PLL1DIV2, CLKSEL(10), 3, 4, mclk200_table, 0, -1}, + {"aclk400", M10V_PLL1DIV2, CLKSEL(10), 0, 3, aclk400_table, 0, -1}, + {"aclk300", M10V_PLL2DIV2, CLKSEL(12), 0, 2, aclk300_table, 0, -1}, + {"aclk", M10V_PLL1DIV2, CLKSEL(9), 20, 4, aclk_table, 0, M10V_ACLK_ID}, + {"aclkexs", M10V_PLL1DIV2, CLKSEL(9), 16, 4, aclkexs_table, 0, -1}, + {"hclk", M10V_PLL1DIV2, CLKSEL(9), 7, 5, hclk_table, 0, M10V_HCLK_ID}, + {"hclkbmh", M10V_PLL1DIV2, CLKSEL(9), 12, 4, hclkbmh_table, 0, -1}, + {"pclk", M10V_PLL1DIV2, CLKSEL(9), 0, 7, pclk_table, 0, M10V_PCLK_ID}, + {"uhs1clk0", M10V_PLL7, CLKSEL(1), 3, 5, uhs1clk0_table, 0, -1}, + {"uhs2clk", M10V_PLL6DIV3, CLKSEL(1), 18, 4, uhs2clk_table, 0, -1}, +}; + +static const struct m10v_clk_mux_factors m10v_mux_factor_data[] = { + {"spi", spi_mux_names, ARRAY_SIZE(spi_mux_names), + CLKSEL(8), 3, 7, spi_mux_table, 0, M10V_SPICLK_ID}, + {"uhs1clk2", uhs1clk2_mux_names, ARRAY_SIZE(uhs1clk2_mux_names), + CLKSEL(1), 13, 31, uhs1clk2_mux_table, 0, M10V_UHS1CLK2_ID}, + {"uhs1clk1", uhs1clk1_mux_names, ARRAY_SIZE(uhs1clk1_mux_names), + CLKSEL(1), 8, 31, uhs1clk1_mux_table, 0, -1}, + {"nfclk", nfclk_mux_names, ARRAY_SIZE(nfclk_mux_names), + CLKSEL(1), 22, 127, nfclk_mux_table, 0, M10V_NFCLK_ID}, +}; + +static u8 m10v_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + + val = readl(mux->reg) >> mux->shift; + val &= mux->mask; + + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int m10v_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val = clk_mux_index_to_val(mux->table, mux->flags, index); + unsigned long flags = 0; + u32 reg; + u32 write_en = BIT(fls(mux->mask) - 1); + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); + + reg = readl(mux->reg); + reg &= ~(mux->mask << mux->shift); + + val = (val | write_en) << mux->shift; + reg |= val; + writel(reg, mux->reg); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); + + return 0; +} + +static const struct clk_ops m10v_mux_ops = { + .get_parent = m10v_mux_get_parent, + .set_parent = m10v_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk_hw *m10v_clk_hw_register_mux(struct device *dev, + const char *name, const char * const *parent_names, + u8 num_parents, unsigned long flags, void __iomem *reg, + u8 shift, u32 mask, u8 clk_mux_flags, u32 *table, + spinlock_t *lock) +{ + struct clk_mux *mux; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &m10v_mux_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + + mux->reg = reg; + mux->shift = shift; + mux->mask = mask; + mux->flags = clk_mux_flags; + mux->lock = lock; + mux->table = table; + mux->hw.init = &init; + + hw = &mux->hw; + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(mux); + hw = ERR_PTR(ret); + } + + return hw; + +} + +struct m10v_clk_divider { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; + spinlock_t *lock; + void __iomem *write_valid_reg; +}; + +static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct m10v_clk_divider *divider = to_m10v_div(hw); + unsigned int val; + + val = readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + +static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct m10v_clk_divider *divider = to_m10v_div(hw); + + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { + u32 val; + + val = readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags, + val); + } + + return divider_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags); +} + +static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct m10v_clk_divider *divider = to_m10v_div(hw); + int value; + unsigned long flags = 0; + u32 val; + u32 write_en = BIT(divider->width - 1); + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + val = readl(divider->reg); + val &= ~(clk_div_mask(divider->width) << divider->shift); + + val |= ((u32)value | write_en) << divider->shift; + writel(val, divider->reg); + + if (divider->write_valid_reg) { + writel(M10V_DCHREQ, divider->write_valid_reg); + if (readl_poll_timeout(divider->write_valid_reg, val, + !val, M10V_UPOLL_RATE, M10V_UTIMEOUT)) + pr_err("%s:%s couldn't stabilize\n", + __func__, divider->hw.init->name); + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +static const struct clk_ops m10v_clk_divider_ops = { + .recalc_rate = m10v_clk_divider_recalc_rate, + .round_rate = m10v_clk_divider_round_rate, + .set_rate = m10v_clk_divider_set_rate, +}; + +static struct clk_hw *m10v_clk_hw_register_divider(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, const struct clk_div_table *table, + spinlock_t *lock, void __iomem *write_valid_reg) +{ + struct m10v_clk_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &m10v_clk_divider_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->reg = reg; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + div->write_valid_reg = write_valid_reg; + + /* register the clock */ + hw = &div->hw; + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(div); + hw = ERR_PTR(ret); + } + + return hw; +} + +static void m10v_reg_div_pre(const struct m10v_clk_div_factors *factors, + struct clk_hw_onecell_data *clk_data, + void __iomem *base) +{ + struct clk_hw *hw; + void __iomem *write_valid_reg; + + /* + * The registers on CLKSEL(9) or CLKSEL(10) need additional + * writing to become valid. + */ + if ((factors->offset == CLKSEL(9)) || (factors->offset == CLKSEL(10))) + write_valid_reg = base + CLKSEL(11); + else + write_valid_reg = NULL; + + hw = m10v_clk_hw_register_divider(NULL, factors->name, + factors->parent_name, + CLK_SET_RATE_PARENT, + base + factors->offset, + factors->shift, + factors->width, factors->div_flags, + factors->table, + &m10v_crglock, write_valid_reg); + + if (factors->onecell_idx >= 0) + clk_data->hws[factors->onecell_idx] = hw; +} + +static void m10v_reg_fixed_pre(const struct m10v_clk_div_fixed_data *factors, + struct clk_hw_onecell_data *clk_data, + const char *parent_name) +{ + struct clk_hw *hw; + const char *pn = factors->parent_name ? + factors->parent_name : parent_name; + + hw = clk_hw_register_fixed_factor(NULL, factors->name, pn, 0, + factors->mult, factors->div); + + if (factors->onecell_idx >= 0) + clk_data->hws[factors->onecell_idx] = hw; +} + +static void m10v_reg_mux_pre(const struct m10v_clk_mux_factors *factors, + struct clk_hw_onecell_data *clk_data, + void __iomem *base) +{ + struct clk_hw *hw; + + hw = m10v_clk_hw_register_mux(NULL, factors->name, + factors->parent_names, + factors->num_parents, + CLK_SET_RATE_PARENT, + base + factors->offset, factors->shift, + factors->mask, factors->mux_flags, + factors->table, &m10v_crglock); + + if (factors->onecell_idx >= 0) + clk_data->hws[factors->onecell_idx] = hw; +} + +static int m10v_clk_probe(struct platform_device *pdev) +{ + int id; + struct resource *res; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *base; + const char *parent_name; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + parent_name = of_clk_get_parent_name(np, 0); + + for (id = 0; id < ARRAY_SIZE(m10v_div_factor_data); ++id) + m10v_reg_div_pre(&m10v_div_factor_data[id], + m10v_clk_data, base); + + for (id = 0; id < ARRAY_SIZE(m10v_div_fixed_data); ++id) + m10v_reg_fixed_pre(&m10v_div_fixed_data[id], + m10v_clk_data, parent_name); + + for (id = 0; id < ARRAY_SIZE(m10v_mux_factor_data); ++id) + m10v_reg_mux_pre(&m10v_mux_factor_data[id], + m10v_clk_data, base); + + for (id = 0; id < M10V_NUM_CLKS; id++) { + if (IS_ERR(m10v_clk_data->hws[id])) + return PTR_ERR(m10v_clk_data->hws[id]); + } + + return 0; +} + +static const struct of_device_id m10v_clk_dt_ids[] = { + { .compatible = "socionext,milbeaut-m10v-ccu", }, + { } +}; + +static struct platform_driver m10v_clk_driver = { + .probe = m10v_clk_probe, + .driver = { + .name = "m10v-ccu", + .of_match_table = m10v_clk_dt_ids, + }, +}; +builtin_platform_driver(m10v_clk_driver); + +static void __init m10v_cc_init(struct device_node *np) +{ + int id; + void __iomem *base; + const char *parent_name; + struct clk_hw *hw; + + m10v_clk_data = kzalloc(struct_size(m10v_clk_data, hws, + M10V_NUM_CLKS), + GFP_KERNEL); + + if (!m10v_clk_data) + return; + + base = of_iomap(np, 0); + if (!base) { + kfree(m10v_clk_data); + return; + } + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) { + kfree(m10v_clk_data); + iounmap(base); + return; + } + + /* + * This way all clocks fetched before the platform device probes, + * except those we assign here for early use, will be deferred. + */ + for (id = 0; id < M10V_NUM_CLKS; id++) + m10v_clk_data->hws[id] = ERR_PTR(-EPROBE_DEFER); + + /* + * PLLs are set by bootloader so this driver registers them as the + * fixed factor. + */ + for (id = 0; id < ARRAY_SIZE(m10v_pll_fixed_data); ++id) + m10v_reg_fixed_pre(&m10v_pll_fixed_data[id], + m10v_clk_data, parent_name); + + /* + * timer consumes "rclk" so it needs to register here. + */ + hw = m10v_clk_hw_register_divider(NULL, "rclk", M10V_PLL10DIV2, 0, + base + CLKSEL(1), 0, 3, 0, rclk_table, + &m10v_crglock, NULL); + m10v_clk_data->hws[M10V_RCLK_ID] = hw; + + m10v_clk_data->num = M10V_NUM_CLKS; + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, m10v_clk_data); +} +CLK_OF_DECLARE_DRIVER(m10v_cc, "socionext,milbeaut-m10v-ccu", m10v_cc_init); diff --git a/drivers/clk/clk-multiplier.c b/drivers/clk/clk-multiplier.c index 3c86f859c199..94470b4eadf4 100644 --- a/drivers/clk/clk-multiplier.c +++ b/drivers/clk/clk-multiplier.c @@ -11,6 +11,22 @@ #include <linux/of.h> #include <linux/slab.h> +static inline u32 clk_mult_readl(struct clk_multiplier *mult) +{ + if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN) + return ioread32be(mult->reg); + + return readl(mult->reg); +} + +static inline void clk_mult_writel(struct clk_multiplier *mult, u32 val) +{ + if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN) + iowrite32be(val, mult->reg); + else + writel(val, mult->reg); +} + static unsigned long __get_mult(struct clk_multiplier *mult, unsigned long rate, unsigned long parent_rate) @@ -27,7 +43,7 @@ static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw, struct clk_multiplier *mult = to_clk_multiplier(hw); unsigned long val; - val = clk_readl(mult->reg) >> mult->shift; + val = clk_mult_readl(mult) >> mult->shift; val &= GENMASK(mult->width - 1, 0); if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS) @@ -118,10 +134,10 @@ static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate, else __acquire(mult->lock); - val = clk_readl(mult->reg); + val = clk_mult_readl(mult); val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift); val |= factor << mult->shift; - clk_writel(val, mult->reg); + clk_mult_writel(mult, val); if (mult->lock) spin_unlock_irqrestore(mult->lock, flags); diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 2ad2df2e8909..66e91f740508 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -23,6 +23,22 @@ * parent - parent is adjustable through clk_set_parent */ +static inline u32 clk_mux_readl(struct clk_mux *mux) +{ + if (mux->flags & CLK_MUX_BIG_ENDIAN) + return ioread32be(mux->reg); + + return readl(mux->reg); +} + +static inline void clk_mux_writel(struct clk_mux *mux, u32 val) +{ + if (mux->flags & CLK_MUX_BIG_ENDIAN) + iowrite32be(val, mux->reg); + else + writel(val, mux->reg); +} + int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, unsigned int val) { @@ -73,7 +89,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) struct clk_mux *mux = to_clk_mux(hw); u32 val; - val = clk_readl(mux->reg) >> mux->shift; + val = clk_mux_readl(mux) >> mux->shift; val &= mux->mask; return clk_mux_val_to_index(hw, mux->table, mux->flags, val); @@ -94,12 +110,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) if (mux->flags & CLK_MUX_HIWORD_MASK) { reg = mux->mask << (mux->shift + 16); } else { - reg = clk_readl(mux->reg); + reg = clk_mux_readl(mux); reg &= ~(mux->mask << mux->shift); } val = val << mux->shift; reg |= val; - clk_writel(reg, mux->reg); + clk_mux_writel(mux, reg); if (mux->lock) spin_unlock_irqrestore(mux->lock, flags); @@ -159,7 +175,7 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, init.ops = &clk_mux_ro_ops; else init.ops = &clk_mux_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 8cb9d117fdbf..02b472a1f9b0 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -101,7 +101,7 @@ static int clk_pwm_probe(struct platform_device *pdev) init.name = clk_name; init.ops = &clk_pwm_ops; - init.flags = CLK_IS_BASIC; + init.flags = 0; init.num_parents = 0; clk_pwm->pwm = pwm; diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 1212a9be7e80..4739a47ec8bd 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -34,6 +34,7 @@ #define CGA_PLL4 4 /* only on clockgen-1.0, which lacks CGB */ #define CGB_PLL1 4 #define CGB_PLL2 5 +#define MAX_PLL_DIV 16 struct clockgen_pll_div { struct clk *clk; @@ -41,7 +42,7 @@ struct clockgen_pll_div { }; struct clockgen_pll { - struct clockgen_pll_div div[8]; + struct clockgen_pll_div div[MAX_PLL_DIV]; }; #define CLKSEL_VALID 1 @@ -79,7 +80,7 @@ struct clockgen_chipinfo { const struct clockgen_muxinfo *cmux_groups[2]; const struct clockgen_muxinfo *hwaccel[NUM_HWACCEL]; void (*init_periph)(struct clockgen *cg); - int cmux_to_group[NUM_CMUX]; /* -1 terminates if fewer than NUM_CMUX */ + int cmux_to_group[NUM_CMUX + 1]; /* array should be -1 terminated */ u32 pll_mask; /* 1 << n bit set if PLL n is valid */ u32 flags; /* CG_xxx */ }; @@ -245,6 +246,58 @@ static const struct clockgen_muxinfo clockgen2_cmux_cgb = { }, }; +static const struct clockgen_muxinfo ls1028a_hwa1 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1028a_hwa2 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1028a_hwa3 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1028a_hwa4 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + }, +}; + static const struct clockgen_muxinfo ls1043a_hwa1 = { { {}, @@ -508,6 +561,21 @@ static const struct clockgen_chipinfo chipinfo[] = { .pll_mask = 0x03, }, { + .compat = "fsl,ls1028a-clockgen", + .cmux_groups = { + &clockgen2_cmux_cga12 + }, + .hwaccel = { + &ls1028a_hwa1, &ls1028a_hwa2, + &ls1028a_hwa3, &ls1028a_hwa4 + }, + .cmux_to_group = { + 0, 0, 0, 0, -1 + }, + .pll_mask = 0x07, + .flags = CG_VER3 | CG_LITTLE_ENDIAN, + }, + { .compat = "fsl,ls1043a-clockgen", .init_periph = t2080_init_periph, .cmux_groups = { @@ -601,7 +669,7 @@ static const struct clockgen_chipinfo chipinfo[] = { &p4080_cmux_grp1, &p4080_cmux_grp2 }, .cmux_to_group = { - 0, 0, 0, 0, 1, 1, 1, 1 + 0, 0, 0, 0, 1, 1, 1, 1, -1 }, .pll_mask = 0x1f, }, @@ -1128,7 +1196,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx) int ret; /* - * For platform PLL, there are 8 divider clocks. + * For platform PLL, there are MAX_PLL_DIV divider clocks. * For core PLL, there are 4 divider clocks at most. */ if (idx != PLATFORM_PLL && i >= 4) @@ -1423,6 +1491,7 @@ CLK_OF_DECLARE(qoriq_clockgen_b4420, "fsl,b4420-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_b4860, "fsl,b4860-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init); +CLK_OF_DECLARE(qoriq_clockgen_ls1028a, "fsl,ls1028a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init); diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index cdaa567c8042..fdac33a9be2f 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -300,6 +300,85 @@ static const struct stm32f4_gate_data stm32f746_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; +static const struct stm32f4_gate_data stm32f769_gates[] __initconst = { + { STM32F4_RCC_AHB1ENR, 0, "gpioa", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 1, "gpiob", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 2, "gpioc", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 3, "gpiod", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 4, "gpioe", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 5, "gpiof", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 6, "gpiog", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 7, "gpioh", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 8, "gpioi", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 9, "gpioj", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 10, "gpiok", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 12, "crc", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 18, "bkpsra", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 20, "dtcmram", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 21, "dma1", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 22, "dma2", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 23, "dma2d", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 25, "ethmac", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 26, "ethmactx", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 27, "ethmacrx", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 28, "ethmacptp", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 29, "otghs", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 30, "otghsulpi", "ahb_div" }, + + { STM32F4_RCC_AHB2ENR, 0, "dcmi", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 1, "jpeg", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 4, "cryp", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 5, "hash", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 6, "rng", "pll48" }, + { STM32F4_RCC_AHB2ENR, 7, "otgfs", "pll48" }, + + { STM32F4_RCC_AHB3ENR, 0, "fmc", "ahb_div", + CLK_IGNORE_UNUSED }, + { STM32F4_RCC_AHB3ENR, 1, "qspi", "ahb_div", + CLK_IGNORE_UNUSED }, + + { STM32F4_RCC_APB1ENR, 0, "tim2", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 1, "tim3", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 2, "tim4", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 3, "tim5", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 4, "tim6", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 5, "tim7", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 6, "tim12", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 7, "tim13", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 8, "tim14", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 10, "rtcapb", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 11, "wwdg", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 13, "can3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 14, "spi2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 15, "spi3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 16, "spdifrx", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 25, "can1", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 26, "can2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 27, "cec", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 28, "pwr", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 29, "dac", "apb1_div" }, + + { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 7, "sdmmc2", "sdmux2" }, + { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 11, "sdmmc1", "sdmux1" }, + { STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 16, "tim9", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 17, "tim10", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 18, "tim11", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 20, "spi5", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 23, "sai2", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 30, "mdio", "apb2_div" }, +}; + /* * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx * have gate bits associated with them. Its combined hweight is 71. @@ -318,6 +397,10 @@ static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, 0x0000000000000003ull, 0x04f77f833e01c9ffull }; +static const u64 stm32f769_gate_map[MAX_GATE_MAP] = { 0x000000f37ef417ffull, + 0x0000000000000003ull, + 0x44F77F833E01EDFFull }; + static const u64 *stm32f4_gate_map; static struct clk_hw **clks; @@ -1048,6 +1131,10 @@ static const char *rtc_parents[4] = { "no-clock", "lse", "lsi", "hse-rtc" }; +static const char *pll_src = "pll-src"; + +static const char *pllsrc_parent[2] = { "hsi", NULL }; + static const char *dsi_parent[2] = { NULL, "pll-r" }; static const char *lcd_parent[1] = { "pllsai-r-div" }; @@ -1072,6 +1159,9 @@ static const char *uart_parents2[4] = { "apb1_div", "sys", "hsi", "lse" }; static const char *i2c_parents[4] = { "apb1_div", "sys", "hsi", "no-clock" }; +static const char * const dfsdm1_src[] = { "apb2_div", "sys" }; +static const char * const adsfdm1_parent[] = { "sai1_clk", "sai2_clk" }; + struct stm32_aux_clk { int idx; const char *name; @@ -1313,6 +1403,177 @@ static const struct stm32_aux_clk stm32f746_aux_clk[] = { }, }; +static const struct stm32_aux_clk stm32f769_aux_clk[] = { + { + CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent), + NO_MUX, 0, 0, + STM32F4_RCC_APB2ENR, 26, + CLK_SET_RATE_PARENT + }, + { + CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents), + STM32F4_RCC_CFGR, 23, 1, + NO_GATE, 0, + CLK_SET_RATE_PARENT + }, + { + CLK_SAI1, "sai1_clk", sai_parents, ARRAY_SIZE(sai_parents), + STM32F4_RCC_DCKCFGR, 20, 3, + STM32F4_RCC_APB2ENR, 22, + CLK_SET_RATE_PARENT + }, + { + CLK_SAI2, "sai2_clk", sai_parents, ARRAY_SIZE(sai_parents), + STM32F4_RCC_DCKCFGR, 22, 3, + STM32F4_RCC_APB2ENR, 23, + CLK_SET_RATE_PARENT + }, + { + NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents), + STM32F7_RCC_DCKCFGR2, 27, 1, + NO_GATE, 0, + 0 + }, + { + NO_IDX, "sdmux1", sdmux_parents, ARRAY_SIZE(sdmux_parents), + STM32F7_RCC_DCKCFGR2, 28, 1, + NO_GATE, 0, + 0 + }, + { + NO_IDX, "sdmux2", sdmux_parents, ARRAY_SIZE(sdmux_parents), + STM32F7_RCC_DCKCFGR2, 29, 1, + NO_GATE, 0, + 0 + }, + { + CLK_HDMI_CEC, "hdmi-cec", + hdmi_parents, ARRAY_SIZE(hdmi_parents), + STM32F7_RCC_DCKCFGR2, 26, 1, + NO_GATE, 0, + 0 + }, + { + CLK_SPDIF, "spdif-rx", + spdif_parent, ARRAY_SIZE(spdif_parent), + STM32F7_RCC_DCKCFGR2, 22, 3, + STM32F4_RCC_APB2ENR, 23, + CLK_SET_RATE_PARENT + }, + { + CLK_USART1, "usart1", + uart_parents1, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 0, 3, + STM32F4_RCC_APB2ENR, 4, + CLK_SET_RATE_PARENT, + }, + { + CLK_USART2, "usart2", + uart_parents2, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 2, 3, + STM32F4_RCC_APB1ENR, 17, + CLK_SET_RATE_PARENT, + }, + { + CLK_USART3, "usart3", + uart_parents2, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 4, 3, + STM32F4_RCC_APB1ENR, 18, + CLK_SET_RATE_PARENT, + }, + { + CLK_UART4, "uart4", + uart_parents2, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 6, 3, + STM32F4_RCC_APB1ENR, 19, + CLK_SET_RATE_PARENT, + }, + { + CLK_UART5, "uart5", + uart_parents2, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 8, 3, + STM32F4_RCC_APB1ENR, 20, + CLK_SET_RATE_PARENT, + }, + { + CLK_USART6, "usart6", + uart_parents1, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 10, 3, + STM32F4_RCC_APB2ENR, 5, + CLK_SET_RATE_PARENT, + }, + { + CLK_UART7, "uart7", + uart_parents2, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 12, 3, + STM32F4_RCC_APB1ENR, 30, + CLK_SET_RATE_PARENT, + }, + { + CLK_UART8, "uart8", + uart_parents2, ARRAY_SIZE(uart_parents1), + STM32F7_RCC_DCKCFGR2, 14, 3, + STM32F4_RCC_APB1ENR, 31, + CLK_SET_RATE_PARENT, + }, + { + CLK_I2C1, "i2c1", + i2c_parents, ARRAY_SIZE(i2c_parents), + STM32F7_RCC_DCKCFGR2, 16, 3, + STM32F4_RCC_APB1ENR, 21, + CLK_SET_RATE_PARENT, + }, + { + CLK_I2C2, "i2c2", + i2c_parents, ARRAY_SIZE(i2c_parents), + STM32F7_RCC_DCKCFGR2, 18, 3, + STM32F4_RCC_APB1ENR, 22, + CLK_SET_RATE_PARENT, + }, + { + CLK_I2C3, "i2c3", + i2c_parents, ARRAY_SIZE(i2c_parents), + STM32F7_RCC_DCKCFGR2, 20, 3, + STM32F4_RCC_APB1ENR, 23, + CLK_SET_RATE_PARENT, + }, + { + CLK_I2C4, "i2c4", + i2c_parents, ARRAY_SIZE(i2c_parents), + STM32F7_RCC_DCKCFGR2, 22, 3, + STM32F4_RCC_APB1ENR, 24, + CLK_SET_RATE_PARENT, + }, + { + CLK_LPTIMER, "lptim1", + lptim_parent, ARRAY_SIZE(lptim_parent), + STM32F7_RCC_DCKCFGR2, 24, 3, + STM32F4_RCC_APB1ENR, 9, + CLK_SET_RATE_PARENT + }, + { + CLK_F769_DSI, "dsi", + dsi_parent, ARRAY_SIZE(dsi_parent), + STM32F7_RCC_DCKCFGR2, 0, 1, + STM32F4_RCC_APB2ENR, 27, + CLK_SET_RATE_PARENT + }, + { + CLK_DFSDM1, "dfsdm1", + dfsdm1_src, ARRAY_SIZE(dfsdm1_src), + STM32F4_RCC_DCKCFGR, 25, 1, + STM32F4_RCC_APB2ENR, 29, + CLK_SET_RATE_PARENT + }, + { + CLK_ADFSDM1, "adfsdm1", + adsfdm1_parent, ARRAY_SIZE(adsfdm1_parent), + STM32F4_RCC_DCKCFGR, 26, 1, + STM32F4_RCC_APB2ENR, 29, + CLK_SET_RATE_PARENT + }, +}; + static const struct stm32f4_clk_data stm32f429_clk_data = { .end_primary = END_PRIMARY_CLK, .gates_data = stm32f429_gates, @@ -1343,6 +1604,16 @@ static const struct stm32f4_clk_data stm32f746_clk_data = { .aux_clk_num = ARRAY_SIZE(stm32f746_aux_clk), }; +static const struct stm32f4_clk_data stm32f769_clk_data = { + .end_primary = END_PRIMARY_CLK_F7, + .gates_data = stm32f769_gates, + .gates_map = stm32f769_gate_map, + .gates_num = ARRAY_SIZE(stm32f769_gates), + .pll_data = stm32f469_pll, + .aux_clk = stm32f769_aux_clk, + .aux_clk_num = ARRAY_SIZE(stm32f769_aux_clk), +}; + static const struct of_device_id stm32f4_of_match[] = { { .compatible = "st,stm32f42xx-rcc", @@ -1356,6 +1627,10 @@ static const struct of_device_id stm32f4_of_match[] = { .compatible = "st,stm32f746-rcc", .data = &stm32f746_clk_data }, + { + .compatible = "st,stm32f769-rcc", + .data = &stm32f769_clk_data + }, {} }; @@ -1427,9 +1702,8 @@ static void __init stm32f4_rcc_init(struct device_node *np) int n; const struct of_device_id *match; const struct stm32f4_clk_data *data; - unsigned long pllcfgr; - const char *pllsrc; unsigned long pllm; + struct clk_hw *pll_src_hw; base = of_iomap(np, 0); if (!base) { @@ -1460,21 +1734,33 @@ static void __init stm32f4_rcc_init(struct device_node *np) hse_clk = of_clk_get_parent_name(np, 0); dsi_parent[0] = hse_clk; + pllsrc_parent[1] = hse_clk; i2s_in_clk = of_clk_get_parent_name(np, 1); i2s_parents[1] = i2s_in_clk; sai_parents[2] = i2s_in_clk; + if (of_device_is_compatible(np, "st,stm32f769-rcc")) { + clk_hw_register_gate(NULL, "dfsdm1_apb", "apb2_div", 0, + base + STM32F4_RCC_APB2ENR, 29, + CLK_IGNORE_UNUSED, &stm32f4_clk_lock); + dsi_parent[0] = pll_src; + sai_parents[3] = pll_src; + } + clks[CLK_HSI] = clk_hw_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0, 16000000, 160000); - pllcfgr = readl(base + STM32F4_RCC_PLLCFGR); - pllsrc = pllcfgr & BIT(22) ? hse_clk : "hsi"; - pllm = pllcfgr & 0x3f; + pll_src_hw = clk_hw_register_mux(NULL, pll_src, pllsrc_parent, + ARRAY_SIZE(pllsrc_parent), 0, + base + STM32F4_RCC_PLLCFGR, 22, 1, 0, + &stm32f4_clk_lock); + + pllm = readl(base + STM32F4_RCC_PLLCFGR) & 0x3f; - clk_hw_register_fixed_factor(NULL, "vco_in", pllsrc, - 0, 1, pllm); + clk_hw_register_fixed_factor(NULL, "vco_in", pll_src, + 0, 1, pllm); stm32f4_rcc_register_pll("vco_in", &data->pll_data[0], &stm32f4_clk_lock); @@ -1612,12 +1898,16 @@ static void __init stm32f4_rcc_init(struct device_node *np) clks[aux_clk->idx] = hw; } - if (of_device_is_compatible(np, "st,stm32f746-rcc")) + if (of_device_is_compatible(np, "st,stm32f746-rcc")) { clk_hw_register_fixed_factor(NULL, "hsi_div488", "hsi", 0, 1, 488); + clks[CLK_PLL_SRC] = pll_src_hw; + } + of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL); + return; fail: kfree(clks); @@ -1626,3 +1916,4 @@ fail: CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); CLK_OF_DECLARE_DRIVER(stm32f746_rcc, "st,stm32f746-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE_DRIVER(stm32f769_rcc, "st,stm32f769-rcc", stm32f4_rcc_init); diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index a0ae8dc16909..a875649df8b8 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1402,6 +1402,7 @@ enum { G_CRYP1, G_HASH1, G_BKPSRAM, + G_DDRPERFM, G_LAST }; @@ -1488,6 +1489,7 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), + K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0), K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), @@ -1899,6 +1901,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), + PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM), /* Kernel clocks */ KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 531b030d4d4e..d975465fe2a8 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -262,7 +262,7 @@ static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw, else __acquire(fd->lock); - val = clk_readl(fd->reg); + val = readl(fd->reg); if (fd->lock) spin_unlock_irqrestore(fd->lock, flags); @@ -333,10 +333,10 @@ static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate, else __acquire(fd->lock); - val = clk_readl(fd->reg); + val = readl(fd->reg); val &= ~fd->mask; val |= (scale << fd->shift); - clk_writel(val, fd->reg); + writel(val, fd->reg); if (fd->lock) spin_unlock_irqrestore(fd->lock, flags); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 96053a96fe2f..aa51756fd4d6 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -39,15 +39,23 @@ static LIST_HEAD(clk_notifier_list); /*** private data structures ***/ +struct clk_parent_map { + const struct clk_hw *hw; + struct clk_core *core; + const char *fw_name; + const char *name; + int index; +}; + struct clk_core { const char *name; const struct clk_ops *ops; struct clk_hw *hw; struct module *owner; struct device *dev; + struct device_node *of_node; struct clk_core *parent; - const char **parent_names; - struct clk_core **parents; + struct clk_parent_map *parents; u8 num_parents; u8 new_parent_index; unsigned long rate; @@ -316,17 +324,102 @@ static struct clk_core *clk_core_lookup(const char *name) return NULL; } +/** + * clk_core_get - Find the clk_core parent of a clk + * @core: clk to find parent of + * @p_index: parent index to search for + * + * This is the preferred method for clk providers to find the parent of a + * clk when that parent is external to the clk controller. The parent_names + * array is indexed and treated as a local name matching a string in the device + * node's 'clock-names' property or as the 'con_id' matching the device's + * dev_name() in a clk_lookup. This allows clk providers to use their own + * namespace instead of looking for a globally unique parent string. + * + * For example the following DT snippet would allow a clock registered by the + * clock-controller@c001 that has a clk_init_data::parent_data array + * with 'xtal' in the 'name' member to find the clock provided by the + * clock-controller@f00abcd without needing to get the globally unique name of + * the xtal clk. + * + * parent: clock-controller@f00abcd { + * reg = <0xf00abcd 0xabcd>; + * #clock-cells = <0>; + * }; + * + * clock-controller@c001 { + * reg = <0xc001 0xf00d>; + * clocks = <&parent>; + * clock-names = "xtal"; + * #clock-cells = <1>; + * }; + * + * Returns: -ENOENT when the provider can't be found or the clk doesn't + * exist in the provider. -EINVAL when the name can't be found. NULL when the + * provider knows about the clk but it isn't provided on this system. + * A valid clk_core pointer when the clk can be found in the provider. + */ +static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index) +{ + const char *name = core->parents[p_index].fw_name; + int index = core->parents[p_index].index; + struct clk_hw *hw = ERR_PTR(-ENOENT); + struct device *dev = core->dev; + const char *dev_id = dev ? dev_name(dev) : NULL; + struct device_node *np = core->of_node; + + if (np && index >= 0) + hw = of_clk_get_hw(np, index, name); + + /* + * If the DT search above couldn't find the provider or the provider + * didn't know about this clk, fallback to looking up via clkdev based + * clk_lookups + */ + if (PTR_ERR(hw) == -ENOENT && name) + hw = clk_find_hw(dev_id, name); + + if (IS_ERR(hw)) + return ERR_CAST(hw); + + return hw->core; +} + +static void clk_core_fill_parent_index(struct clk_core *core, u8 index) +{ + struct clk_parent_map *entry = &core->parents[index]; + struct clk_core *parent = ERR_PTR(-ENOENT); + + if (entry->hw) { + parent = entry->hw->core; + /* + * We have a direct reference but it isn't registered yet? + * Orphan it and let clk_reparent() update the orphan status + * when the parent is registered. + */ + if (!parent) + parent = ERR_PTR(-EPROBE_DEFER); + } else { + parent = clk_core_get(core, index); + if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT) + parent = clk_core_lookup(entry->name); + } + + /* Only cache it if it's not an error */ + if (!IS_ERR(parent)) + entry->core = parent; +} + static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core, u8 index) { - if (!core || index >= core->num_parents) + if (!core || index >= core->num_parents || !core->parents) return NULL; - if (!core->parents[index]) - core->parents[index] = - clk_core_lookup(core->parent_names[index]); + if (!core->parents[index].core) + clk_core_fill_parent_index(core, index); - return core->parents[index]; + return core->parents[index].core; } struct clk_hw * @@ -347,23 +440,18 @@ unsigned int __clk_get_enable_count(struct clk *clk) static unsigned long clk_core_get_rate_nolock(struct clk_core *core) { - unsigned long ret; - - if (!core) { - ret = 0; - goto out; - } - - ret = core->rate; - - if (!core->num_parents) - goto out; + if (!core) + return 0; - if (!core->parent) - ret = 0; + if (!core->num_parents || core->parent) + return core->rate; -out: - return ret; + /* + * Clk must have a parent because num_parents > 0 but the parent isn't + * known yet. Best to return 0 as the rate of this clk until we can + * properly recalc the rate based on the parent's rate. + */ + return 0; } unsigned long clk_hw_get_rate(const struct clk_hw *hw) @@ -524,9 +612,15 @@ void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, EXPORT_SYMBOL_GPL(clk_hw_set_rate_range); /* + * __clk_mux_determine_rate - clk_ops::determine_rate implementation for a mux type clk + * @hw: mux type clk to determine rate on + * @req: rate request, also used to return preferred parent and frequencies + * * Helper for finding best parent to provide a given frequency. This can be used * directly as a determine_rate callback (e.g. for a mux), or from a more * complex clock that may combine a mux with other operations. + * + * Returns: 0 on success, -EERROR value on error */ int __clk_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) @@ -1519,20 +1613,37 @@ static int clk_fetch_parent_index(struct clk_core *core, return -EINVAL; for (i = 0; i < core->num_parents; i++) { - if (core->parents[i] == parent) + /* Found it first try! */ + if (core->parents[i].core == parent) return i; - if (core->parents[i]) + /* Something else is here, so keep looking */ + if (core->parents[i].core) continue; - /* Fallback to comparing globally unique names */ - if (!strcmp(parent->name, core->parent_names[i])) { - core->parents[i] = parent; - return i; + /* Maybe core hasn't been cached but the hw is all we know? */ + if (core->parents[i].hw) { + if (core->parents[i].hw == parent->hw) + break; + + /* Didn't match, but we're expecting a clk_hw */ + continue; } + + /* Maybe it hasn't been cached (clk_set_parent() path) */ + if (parent == clk_core_get(core, i)) + break; + + /* Fallback to comparing globally unique names */ + if (!strcmp(parent->name, core->parents[i].name)) + break; } - return -EINVAL; + if (i == core->num_parents) + return -EINVAL; + + core->parents[i].core = parent; + return i; } /* @@ -2293,6 +2404,7 @@ void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent) bool clk_has_parent(struct clk *clk, struct clk *parent) { struct clk_core *core, *parent_core; + int i; /* NULL clocks should be nops, so return success if either is NULL. */ if (!clk || !parent) @@ -2305,8 +2417,11 @@ bool clk_has_parent(struct clk *clk, struct clk *parent) if (core->parent == parent_core) return true; - return match_string(core->parent_names, core->num_parents, - parent_core->name) >= 0; + for (i = 0; i < core->num_parents; i++) + if (!strcmp(core->parents[i].name, parent_core->name)) + return true; + + return false; } EXPORT_SYMBOL_GPL(clk_has_parent); @@ -2850,7 +2965,6 @@ static const struct { ENTRY(CLK_SET_PARENT_GATE), ENTRY(CLK_SET_RATE_PARENT), ENTRY(CLK_IGNORE_UNUSED), - ENTRY(CLK_IS_BASIC), ENTRY(CLK_GET_RATE_NOCACHE), ENTRY(CLK_SET_RATE_NO_REPARENT), ENTRY(CLK_GET_ACCURACY_NOCACHE), @@ -2889,9 +3003,9 @@ static int possible_parents_show(struct seq_file *s, void *data) int i; for (i = 0; i < core->num_parents - 1; i++) - seq_printf(s, "%s ", core->parent_names[i]); + seq_printf(s, "%s ", core->parents[i].name); - seq_printf(s, "%s\n", core->parent_names[i]); + seq_printf(s, "%s\n", core->parents[i].name); return 0; } @@ -3025,7 +3139,7 @@ static inline void clk_debug_unregister(struct clk_core *core) */ static int __clk_core_init(struct clk_core *core) { - int i, ret; + int ret; struct clk_core *orphan; struct hlist_node *tmp2; unsigned long rate; @@ -3079,12 +3193,6 @@ static int __clk_core_init(struct clk_core *core) goto out; } - /* throw a WARN if any entries in parent_names are NULL */ - for (i = 0; i < core->num_parents; i++) - WARN(!core->parent_names[i], - "%s: invalid NULL in %s's .parent_names\n", - __func__, core->name); - core->parent = __clk_init_parent(core); /* @@ -3313,20 +3421,104 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; } -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjunction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw) +static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist) +{ + const char *dst; + + if (!src) { + if (must_exist) + return -EINVAL; + return 0; + } + + *dst_p = dst = kstrdup_const(src, GFP_KERNEL); + if (!dst) + return -ENOMEM; + + return 0; +} + +static int clk_core_populate_parent_map(struct clk_core *core) +{ + const struct clk_init_data *init = core->hw->init; + u8 num_parents = init->num_parents; + const char * const *parent_names = init->parent_names; + const struct clk_hw **parent_hws = init->parent_hws; + const struct clk_parent_data *parent_data = init->parent_data; + int i, ret = 0; + struct clk_parent_map *parents, *parent; + + if (!num_parents) + return 0; + + /* + * Avoid unnecessary string look-ups of clk_core's possible parents by + * having a cache of names/clk_hw pointers to clk_core pointers. + */ + parents = kcalloc(num_parents, sizeof(*parents), GFP_KERNEL); + core->parents = parents; + if (!parents) + return -ENOMEM; + + /* Copy everything over because it might be __initdata */ + for (i = 0, parent = parents; i < num_parents; i++, parent++) { + parent->index = -1; + if (parent_names) { + /* throw a WARN if any entries are NULL */ + WARN(!parent_names[i], + "%s: invalid NULL in %s's .parent_names\n", + __func__, core->name); + ret = clk_cpy_name(&parent->name, parent_names[i], + true); + } else if (parent_data) { + parent->hw = parent_data[i].hw; + parent->index = parent_data[i].index; + ret = clk_cpy_name(&parent->fw_name, + parent_data[i].fw_name, false); + if (!ret) + ret = clk_cpy_name(&parent->name, + parent_data[i].name, + false); + } else if (parent_hws) { + parent->hw = parent_hws[i]; + } else { + ret = -EINVAL; + WARN(1, "Must specify parents if num_parents > 0\n"); + } + + if (ret) { + do { + kfree_const(parents[i].name); + kfree_const(parents[i].fw_name); + } while (--i >= 0); + kfree(parents); + + return ret; + } + } + + return 0; +} + +static void clk_core_free_parent_map(struct clk_core *core) +{ + int i = core->num_parents; + + if (!core->num_parents) + return; + + while (--i >= 0) { + kfree_const(core->parents[i].name); + kfree_const(core->parents[i].fw_name); + } + + kfree(core->parents); +} + +static struct clk * +__clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) { - int i, ret; + int ret; struct clk_core *core; core = kzalloc(sizeof(*core), GFP_KERNEL); @@ -3350,6 +3542,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) if (dev && pm_runtime_enabled(dev)) core->rpm_enabled = true; core->dev = dev; + core->of_node = np; if (dev && dev->driver) core->owner = dev->driver->owner; core->hw = hw; @@ -3359,33 +3552,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) core->max_rate = ULONG_MAX; hw->core = core; - /* allocate local copy in case parent_names is __initdata */ - core->parent_names = kcalloc(core->num_parents, sizeof(char *), - GFP_KERNEL); - - if (!core->parent_names) { - ret = -ENOMEM; - goto fail_parent_names; - } - - - /* copy each string name in case parent_names is __initdata */ - for (i = 0; i < core->num_parents; i++) { - core->parent_names[i] = kstrdup_const(hw->init->parent_names[i], - GFP_KERNEL); - if (!core->parent_names[i]) { - ret = -ENOMEM; - goto fail_parent_names_copy; - } - } - - /* avoid unnecessary string look-ups of clk_core's possible parents. */ - core->parents = kcalloc(core->num_parents, sizeof(*core->parents), - GFP_KERNEL); - if (!core->parents) { - ret = -ENOMEM; + ret = clk_core_populate_parent_map(core); + if (ret) goto fail_parents; - }; INIT_HLIST_HEAD(&core->clks); @@ -3396,7 +3565,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) hw->clk = alloc_clk(core, NULL, NULL); if (IS_ERR(hw->clk)) { ret = PTR_ERR(hw->clk); - goto fail_parents; + goto fail_create_clk; } clk_core_link_consumer(hw->core, hw->clk); @@ -3412,13 +3581,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) free_clk(hw->clk); hw->clk = NULL; +fail_create_clk: + clk_core_free_parent_map(core); fail_parents: - kfree(core->parents); -fail_parent_names_copy: - while (--i >= 0) - kfree_const(core->parent_names[i]); - kfree(core->parent_names); -fail_parent_names: fail_ops: kfree_const(core->name); fail_name: @@ -3426,6 +3591,24 @@ fail_name: fail_out: return ERR_PTR(ret); } + +/** + * clk_register - allocate a new clock, register it and return an opaque cookie + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * clk_register is the *deprecated* interface for populating the clock tree with + * new clock nodes. Use clk_hw_register() instead. + * + * Returns: a pointer to the newly allocated struct clk which + * cannot be dereferenced by driver code but may be used in conjunction with the + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. + */ +struct clk *clk_register(struct device *dev, struct clk_hw *hw) +{ + return __clk_register(dev, dev_of_node(dev), hw); +} EXPORT_SYMBOL_GPL(clk_register); /** @@ -3440,23 +3623,35 @@ EXPORT_SYMBOL_GPL(clk_register); */ int clk_hw_register(struct device *dev, struct clk_hw *hw) { - return PTR_ERR_OR_ZERO(clk_register(dev, hw)); + return PTR_ERR_OR_ZERO(__clk_register(dev, dev_of_node(dev), hw)); } EXPORT_SYMBOL_GPL(clk_hw_register); +/* + * of_clk_hw_register - register a clk_hw and return an error code + * @node: device_node of device that is registering this clock + * @hw: link to hardware-specific clock data + * + * of_clk_hw_register() is the primary interface for populating the clock tree + * with new clock nodes when a struct device is not available, but a struct + * device_node is. It returns an integer equal to zero indicating success or + * less than zero indicating failure. Drivers must test for an error code after + * calling of_clk_hw_register(). + */ +int of_clk_hw_register(struct device_node *node, struct clk_hw *hw) +{ + return PTR_ERR_OR_ZERO(__clk_register(NULL, node, hw)); +} +EXPORT_SYMBOL_GPL(of_clk_hw_register); + /* Free memory allocated for a clock. */ static void __clk_release(struct kref *ref) { struct clk_core *core = container_of(ref, struct clk_core, ref); - int i = core->num_parents; lockdep_assert_held(&prepare_lock); - kfree(core->parents); - while (--i >= 0) - kfree_const(core->parent_names[i]); - - kfree(core->parent_names); + clk_core_free_parent_map(core); kfree_const(core->name); kfree(core); } @@ -3575,9 +3770,10 @@ static void devm_clk_hw_release(struct device *dev, void *res) * @dev: device that is registering this clock * @hw: link to hardware-specific clock data * - * Managed clk_register(). Clocks returned from this function are - * automatically clk_unregister()ed on driver detach. See clk_register() for - * more information. + * Managed clk_register(). This function is *deprecated*, use devm_clk_hw_register() instead. + * + * Clocks returned from this function are automatically clk_unregister()ed on + * driver detach. See clk_register() for more information. */ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw) { @@ -3895,6 +4091,8 @@ EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get); * @np: Device node pointer associated with clock provider * @clk_src_get: callback for decoding clock * @data: context pointer for @clk_src_get callback. + * + * This function is *deprecated*. Use of_clk_add_hw_provider() instead. */ int of_clk_add_provider(struct device_node *np, struct clk *(*clk_src_get)(struct of_phandle_args *clkspec, diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 553f531cc232..d8400d623b34 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -19,6 +19,8 @@ static inline struct clk_hw *of_clk_get_hw(struct device_node *np, } #endif +struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id); + #ifdef CONFIG_COMMON_CLK struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, const char *con_id); diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 6e787cc9e5b9..2afc8df8acff 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -72,25 +72,26 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) return cl; } -static struct clk *__clk_get_sys(struct device *dev, const char *dev_id, - const char *con_id) +struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id) { struct clk_lookup *cl; - struct clk *clk = NULL; + struct clk_hw *hw = ERR_PTR(-ENOENT); mutex_lock(&clocks_mutex); - cl = clk_find(dev_id, con_id); - if (!cl) - goto out; - - clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id); - if (IS_ERR(clk)) - cl = NULL; -out: + if (cl) + hw = cl->clk_hw; mutex_unlock(&clocks_mutex); - return cl ? clk : ERR_PTR(-ENOENT); + return hw; +} + +static struct clk *__clk_get_sys(struct device *dev, const char *dev_id, + const char *con_id) +{ + struct clk_hw *hw = clk_find_hw(dev_id, con_id); + + return clk_hw_create_clk(dev, hw, dev_id, con_id); } struct clk *clk_get_sys(const char *dev_id, const char *con_id) diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index d1bbee19ed0f..bdc52364b421 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -160,10 +160,8 @@ static int __init da8xx_cfgchip_register_div4p5(struct device *dev, struct da8xx_cfgchip_gate_clk *gate; gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_div4p5ena_info, regmap); - if (IS_ERR(gate)) - return PTR_ERR(gate); - return 0; + return PTR_ERR_OR_ZERO(gate); } static int __init diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index 7cc354dd29e2..c2a453caa131 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Clock driver for TI Davinci PSC controllers * diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index cc5614567a70..69070f834391 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Clock driver for TI Davinci PSC controllers * diff --git a/drivers/clk/hisilicon/clk-hi3660.c b/drivers/clk/hisilicon/clk-hi3660.c index f40419959656..794eeff0d5d2 100644 --- a/drivers/clk/hisilicon/clk-hi3660.c +++ b/drivers/clk/hisilicon/clk-hi3660.c @@ -163,8 +163,12 @@ static const struct hisi_gate_clock hi3660_crgctrl_gate_sep_clks[] = { "clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 17, 0, }, { HI3660_CLK_GATE_ISP_SNCLK2, "clk_gate_isp_snclk2", "clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 18, 0, }, + /* + * clk_gate_ufs_subsys is a system bus clock, mark it as critical + * clock and keep it on for system suspend and resume. + */ { HI3660_CLK_GATE_UFS_SUBSYS, "clk_gate_ufs_subsys", "clk_div_sysbus", - CLK_SET_RATE_PARENT, 0x50, 21, 0, }, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0x50, 21, 0, }, { HI3660_PCLK_GATE_DSI0, "pclk_gate_dsi0", "clk_div_cfgbus", CLK_SET_RATE_PARENT, 0x50, 28, 0, }, { HI3660_PCLK_GATE_DSI1, "pclk_gate_dsi1", "clk_div_cfgbus", diff --git a/drivers/clk/hisilicon/clk-hisi-phase.c b/drivers/clk/hisilicon/clk-hisi-phase.c index 5fdc267bb2da..ba6afad66a2b 100644 --- a/drivers/clk/hisilicon/clk-hisi-phase.c +++ b/drivers/clk/hisilicon/clk-hisi-phase.c @@ -75,10 +75,10 @@ static int hisi_clk_set_phase(struct clk_hw *hw, int degrees) spin_lock_irqsave(phase->lock, flags); - val = clk_readl(phase->reg); + val = readl(phase->reg); val &= ~phase->mask; val |= regval << phase->shift; - clk_writel(val, phase->reg); + writel(val, phase->reg); spin_unlock_irqrestore(phase->lock, flags); diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 0d5180fbe988..05641c64b317 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_SOC_IMX25) += clk-imx25.o obj-$(CONFIG_SOC_IMX27) += clk-imx27.o obj-$(CONFIG_SOC_IMX31) += clk-imx31.o obj-$(CONFIG_SOC_IMX35) += clk-imx35.o -obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o +obj-$(CONFIG_SOC_IMX5) += clk-imx5.o obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o diff --git a/drivers/clk/imx/clk-divider-gate.c b/drivers/clk/imx/clk-divider-gate.c index df1f8429fe16..2a8352a316c7 100644 --- a/drivers/clk/imx/clk-divider-gate.c +++ b/drivers/clk/imx/clk-divider-gate.c @@ -29,7 +29,7 @@ static unsigned long clk_divider_gate_recalc_rate_ro(struct clk_hw *hw, struct clk_divider *div = to_clk_divider(hw); unsigned int val; - val = clk_readl(div->reg) >> div->shift; + val = readl(div->reg) >> div->shift; val &= clk_div_mask(div->width); if (!val) return 0; @@ -51,7 +51,7 @@ static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, if (!clk_hw_is_enabled(hw)) { val = div_gate->cached_val; } else { - val = clk_readl(div->reg) >> div->shift; + val = readl(div->reg) >> div->shift; val &= clk_div_mask(div->width); } @@ -87,10 +87,10 @@ static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, spin_lock_irqsave(div->lock, flags); if (clk_hw_is_enabled(hw)) { - val = clk_readl(div->reg); + val = readl(div->reg); val &= ~(clk_div_mask(div->width) << div->shift); val |= (u32)value << div->shift; - clk_writel(val, div->reg); + writel(val, div->reg); } else { div_gate->cached_val = value; } @@ -114,9 +114,9 @@ static int clk_divider_enable(struct clk_hw *hw) spin_lock_irqsave(div->lock, flags); /* restore div val */ - val = clk_readl(div->reg); + val = readl(div->reg); val |= div_gate->cached_val << div->shift; - clk_writel(val, div->reg); + writel(val, div->reg); spin_unlock_irqrestore(div->lock, flags); @@ -133,10 +133,10 @@ static void clk_divider_disable(struct clk_hw *hw) spin_lock_irqsave(div->lock, flags); /* store the current div val */ - val = clk_readl(div->reg) >> div->shift; + val = readl(div->reg) >> div->shift; val &= clk_div_mask(div->width); div_gate->cached_val = val; - clk_writel(0, div->reg); + writel(0, div->reg); spin_unlock_irqrestore(div->lock, flags); } @@ -146,7 +146,7 @@ static int clk_divider_is_enabled(struct clk_hw *hw) struct clk_divider *div = to_clk_divider(hw); u32 val; - val = clk_readl(div->reg) >> div->shift; + val = readl(div->reg) >> div->shift; val &= clk_div_mask(div->width); return val ? 1 : 0; @@ -206,7 +206,7 @@ struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name, div_gate->divider.hw.init = &init; div_gate->divider.flags = CLK_DIVIDER_ONE_BASED | clk_divider_flags; /* cache gate status */ - val = clk_readl(reg) >> shift; + val = readl(reg) >> shift; val &= clk_div_mask(width); div_gate->cached_val = val; diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx5.c index e91c826bce70..c85ebd74a8a5 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx5.c @@ -164,10 +164,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_CKIH1] = imx_obtain_fixed_clock("ckih1", 0); clk[IMX5_CLK_CKIH2] = imx_obtain_fixed_clock("ckih2", 0); - clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2, - periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); - clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1, - main_bus_sel, ARRAY_SIZE(main_bus_sel)); clk[IMX5_CLK_PER_LP_APM] = imx_clk_mux("per_lp_apm", MXC_CCM_CBCMR, 1, 1, per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel)); clk[IMX5_CLK_PER_PRED1] = imx_clk_divider("per_pred1", "per_lp_apm", MXC_CCM_CBCDR, 6, 2); @@ -191,16 +187,10 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_UART_PRED] = imx_clk_divider("uart_pred", "uart_sel", MXC_CCM_CSCDR1, 3, 3); clk[IMX5_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_pred", MXC_CCM_CSCDR1, 0, 3); - clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2, - standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2, - standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); clk[IMX5_CLK_ESDHC_A_PRED] = imx_clk_divider("esdhc_a_pred", "esdhc_a_sel", MXC_CCM_CSCDR1, 16, 3); clk[IMX5_CLK_ESDHC_A_PODF] = imx_clk_divider("esdhc_a_podf", "esdhc_a_pred", MXC_CCM_CSCDR1, 11, 3); clk[IMX5_CLK_ESDHC_B_PRED] = imx_clk_divider("esdhc_b_pred", "esdhc_b_sel", MXC_CCM_CSCDR1, 22, 3); clk[IMX5_CLK_ESDHC_B_PODF] = imx_clk_divider("esdhc_b_podf", "esdhc_b_pred", MXC_CCM_CSCDR1, 19, 3); - clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); - clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); clk[IMX5_CLK_EMI_SEL] = imx_clk_mux("emi_sel", MXC_CCM_CBCDR, 26, 1, emi_slow_sel, ARRAY_SIZE(emi_slow_sel)); @@ -311,10 +301,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk_register_clkdev(clk[IMX5_CLK_CPU_PODF], NULL, "cpu0"); clk_register_clkdev(clk[IMX5_CLK_GPC_DVFS], "gpc_dvfs", NULL); - /* Set SDHC parents to be PLL2 */ - clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]); - clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]); - /* move usb phy clk to 24MHz */ clk_set_parent(clk[IMX5_CLK_USB_PHY_SEL], clk[IMX5_CLK_OSC]); } @@ -342,8 +328,21 @@ static void __init mx50_clocks_init(struct device_node *np) mx5_clocks_common_init(ccm_base); + /* + * This clock is called periph_clk in the i.MX50 Reference Manual, but + * it comes closest in scope to the main_bus_clk of i.MX51 and i.MX53 + */ + clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 10, 1, lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); + clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 21, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 20, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6); clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10); @@ -372,6 +371,10 @@ static void __init mx50_clocks_init(struct device_node *np) clk_data.clk_num = ARRAY_SIZE(clk); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + /* Set SDHC parents to be PLL2 */ + clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]); + clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]); + /* set SDHC root clock to 200MHZ*/ clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 200000000); clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 200000000); @@ -410,6 +413,10 @@ static void __init mx51_clocks_init(struct device_node *np) mx5_clocks_common_init(ccm_base); + clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2, + periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); + clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1, + main_bus_sel, ARRAY_SIZE(main_bus_sel)); clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1, lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3, @@ -422,6 +429,12 @@ static void __init mx51_clocks_init(struct device_node *np) mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel)); clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30); clk[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3); + clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 6); clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 10); @@ -452,6 +465,10 @@ static void __init mx51_clocks_init(struct device_node *np) /* set the usboh3 parent to pll2_sw */ clk_set_parent(clk[IMX5_CLK_USBOH3_SEL], clk[IMX5_CLK_PLL2_SW]); + /* Set SDHC parents to be PLL2 */ + clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]); + clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]); + /* set SDHC root clock to 166.25MHZ*/ clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 166250000); clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 166250000); @@ -506,6 +523,10 @@ static void __init mx53_clocks_init(struct device_node *np) mx5_clocks_common_init(ccm_base); + clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2, + periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); + clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1, + main_bus_sel, ARRAY_SIZE(main_bus_sel)); clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 10, 1, lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); clk[IMX5_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); @@ -527,6 +548,12 @@ static void __init mx53_clocks_init(struct device_node *np) mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT); clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30); clk[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3); + clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6); clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10); @@ -589,6 +616,10 @@ static void __init mx53_clocks_init(struct device_node *np) clk_data.clk_num = ARRAY_SIZE(clk); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + /* Set SDHC parents to be PLL2 */ + clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]); + clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]); + /* set SDHC root clock to 200MHZ*/ clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 200000000); clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 200000000); diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c index 3bd2044cf25c..7eea448cb9a9 100644 --- a/drivers/clk/imx/clk-imx6sll.c +++ b/drivers/clk/imx/clk-imx6sll.c @@ -76,6 +76,20 @@ static u32 share_count_ssi1; static u32 share_count_ssi2; static u32 share_count_ssi3; +static struct clk ** const uart_clks[] __initconst = { + &clks[IMX6SLL_CLK_UART1_IPG], + &clks[IMX6SLL_CLK_UART1_SERIAL], + &clks[IMX6SLL_CLK_UART2_IPG], + &clks[IMX6SLL_CLK_UART2_SERIAL], + &clks[IMX6SLL_CLK_UART3_IPG], + &clks[IMX6SLL_CLK_UART3_SERIAL], + &clks[IMX6SLL_CLK_UART4_IPG], + &clks[IMX6SLL_CLK_UART4_SERIAL], + &clks[IMX6SLL_CLK_UART5_IPG], + &clks[IMX6SLL_CLK_UART5_SERIAL], + NULL +}; + static void __init imx6sll_clocks_init(struct device_node *ccm_node) { struct device_node *np; @@ -268,7 +282,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_GPT_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20); clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); - clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); + clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24); clks[IMX6SLL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26); clks[IMX6SLL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30); @@ -334,6 +348,8 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clk_data.clk_num = ARRAY_SIZE(clks); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + imx_register_uart_clocks(uart_clks); + /* Lower the AHB clock rate before changing the clock source. */ clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000); diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index cfbd8d4edb85..5b8a0c729f90 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -417,8 +417,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f); clks[IMX7D_PLL_SYS_MAIN] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1); clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0); - clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_audio_main", "osc", base + 0xf0, 0x7f); - clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_video_main", "osc", base + 0x130, 0x7f); + clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f); + clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f); clks[IMX7D_PLL_ARM_MAIN_BYPASS] = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT); clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT); diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c index ce306631e844..66682100f14c 100644 --- a/drivers/clk/imx/clk-imx7ulp.c +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -151,7 +151,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np) clks[IMX7ULP_CLK_DMA1] = imx_clk_hw_gate("dma1", "nic1_clk", base + 0x20, 30); clks[IMX7ULP_CLK_RGPIO2P1] = imx_clk_hw_gate("rgpio2p1", "nic1_bus_clk", base + 0x3c, 30); clks[IMX7ULP_CLK_DMA_MUX1] = imx_clk_hw_gate("dma_mux1", "nic1_bus_clk", base + 0x84, 30); - clks[IMX7ULP_CLK_SNVS] = imx_clk_hw_gate("snvs", "nic1_bus_clk", base + 0x8c, 30); clks[IMX7ULP_CLK_CAAM] = imx_clk_hw_gate("caam", "nic1_clk", base + 0x90, 30); clks[IMX7ULP_CLK_LPTPM4] = imx7ulp_clk_composite("lptpm4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94); clks[IMX7ULP_CLK_LPTPM5] = imx7ulp_clk_composite("lptpm5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98); diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index a9b3888aef0c..daf1841b2adb 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -458,6 +458,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) clks[IMX8MQ_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mq_dsi_dbi_sels, base + 0xbc00); clks[IMX8MQ_CLK_DSI_ESC] = imx8m_clk_composite("dsi_esc", imx8mq_dsi_esc_sels, base + 0xbc80); clks[IMX8MQ_CLK_DSI_AHB] = imx8m_clk_composite("dsi_ahb", imx8mq_dsi_ahb_sels, base + 0x9200); + clks[IMX8MQ_CLK_DSI_IPG_DIV] = imx_clk_divider2("dsi_ipg_div", "dsi_ahb", base + 0x9280, 0, 6); clks[IMX8MQ_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mq_csi1_core_sels, base + 0xbd00); clks[IMX8MQ_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mq_csi1_phy_sels, base + 0xbd80); clks[IMX8MQ_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mq_csi1_esc_sels, base + 0xbe00); diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c index 7e9134b205ab..fb567dcc2118 100644 --- a/drivers/clk/imx/clk-pfdv2.c +++ b/drivers/clk/imx/clk-pfdv2.c @@ -43,7 +43,7 @@ static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) { u32 val; - return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + return readl_poll_timeout(pfd->reg, val, val & (1 << pfd->vld_bit), 0, LOCK_TIMEOUT_US); } @@ -55,7 +55,7 @@ static int clk_pfdv2_enable(struct clk_hw *hw) spin_lock_irqsave(&pfd_lock, flags); val = readl_relaxed(pfd->reg); - val &= ~pfd->gate_bit; + val &= ~(1 << pfd->gate_bit); writel_relaxed(val, pfd->reg); spin_unlock_irqrestore(&pfd_lock, flags); @@ -70,7 +70,7 @@ static void clk_pfdv2_disable(struct clk_hw *hw) spin_lock_irqsave(&pfd_lock, flags); val = readl_relaxed(pfd->reg); - val |= pfd->gate_bit; + val |= (1 << pfd->gate_bit); writel_relaxed(val, pfd->reg); spin_unlock_irqrestore(&pfd_lock, flags); } @@ -123,7 +123,7 @@ static int clk_pfdv2_is_enabled(struct clk_hw *hw) { struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); - if (readl_relaxed(pfd->reg) & pfd->gate_bit) + if (readl_relaxed(pfd->reg) & (1 << pfd->gate_bit)) return 0; return 1; @@ -180,7 +180,7 @@ struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name, return ERR_PTR(-ENOMEM); pfd->reg = reg; - pfd->gate_bit = 1 << ((idx + 1) * 8 - 1); + pfd->gate_bit = (idx + 1) * 8 - 1; pfd->vld_bit = pfd->gate_bit - 1; pfd->frac_off = idx * 8; diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 113d71042199..b7213023b238 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -74,10 +74,9 @@ 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; + u32 mdiv, pdiv, sdiv, 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; @@ -93,11 +92,10 @@ 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; + u32 mdiv, pdiv, sdiv, 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; diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index 9af62ee8f347..4110e713d259 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -20,6 +20,8 @@ #define PLL_NUM_OFFSET 0x10 #define PLL_DENOM_OFFSET 0x20 +#define PLL_IMX7_NUM_OFFSET 0x20 +#define PLL_IMX7_DENOM_OFFSET 0x30 #define PLL_VF610_NUM_OFFSET 0x20 #define PLL_VF610_DENOM_OFFSET 0x30 @@ -49,6 +51,8 @@ struct clk_pllv3 { u32 div_mask; u32 div_shift; unsigned long ref_clock; + u32 num_offset; + u32 denom_offset; }; #define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw) @@ -219,8 +223,8 @@ static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_pllv3 *pll = to_clk_pllv3(hw); - u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET); - u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET); + u32 mfn = readl_relaxed(pll->base + pll->num_offset); + u32 mfd = readl_relaxed(pll->base + pll->denom_offset); u32 div = readl_relaxed(pll->base) & pll->div_mask; u64 temp64 = (u64)parent_rate; @@ -289,8 +293,8 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, val &= ~pll->div_mask; val |= div; writel_relaxed(val, pll->base); - writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); - writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); + writel_relaxed(mfn, pll->base + pll->num_offset); + writel_relaxed(mfd, pll->base + pll->denom_offset); return clk_pllv3_wait_lock(pll); } @@ -352,8 +356,8 @@ static unsigned long clk_pllv3_vf610_recalc_rate(struct clk_hw *hw, struct clk_pllv3 *pll = to_clk_pllv3(hw); struct clk_pllv3_vf610_mf mf; - mf.mfn = readl_relaxed(pll->base + PLL_VF610_NUM_OFFSET); - mf.mfd = readl_relaxed(pll->base + PLL_VF610_DENOM_OFFSET); + mf.mfn = readl_relaxed(pll->base + pll->num_offset); + mf.mfd = readl_relaxed(pll->base + pll->denom_offset); mf.mfi = (readl_relaxed(pll->base) & pll->div_mask) ? 22 : 20; return clk_pllv3_vf610_mf_to_rate(parent_rate, mf); @@ -382,8 +386,8 @@ static int clk_pllv3_vf610_set_rate(struct clk_hw *hw, unsigned long rate, val |= pll->div_mask; /* set bit for mfi=22 */ writel_relaxed(val, pll->base); - writel_relaxed(mf.mfn, pll->base + PLL_VF610_NUM_OFFSET); - writel_relaxed(mf.mfd, pll->base + PLL_VF610_DENOM_OFFSET); + writel_relaxed(mf.mfn, pll->base + pll->num_offset); + writel_relaxed(mf.mfd, pll->base + pll->denom_offset); return clk_pllv3_wait_lock(pll); } @@ -426,6 +430,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, return ERR_PTR(-ENOMEM); pll->power_bit = BM_PLL_POWER; + pll->num_offset = PLL_NUM_OFFSET; + pll->denom_offset = PLL_DENOM_OFFSET; switch (type) { case IMX_PLLV3_SYS: @@ -433,13 +439,20 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, break; case IMX_PLLV3_SYS_VF610: ops = &clk_pllv3_vf610_ops; + pll->num_offset = PLL_VF610_NUM_OFFSET; + pll->denom_offset = PLL_VF610_DENOM_OFFSET; break; case IMX_PLLV3_USB_VF610: pll->div_shift = 1; + /* fall through */ case IMX_PLLV3_USB: ops = &clk_pllv3_ops; pll->powerup_set = true; break; + case IMX_PLLV3_AV_IMX7: + pll->num_offset = PLL_IMX7_NUM_OFFSET; + pll->denom_offset = PLL_IMX7_DENOM_OFFSET; + /* fall through */ case IMX_PLLV3_AV: ops = &clk_pllv3_av_ops; break; @@ -454,6 +467,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, break; case IMX_PLLV3_DDR_IMX7: pll->power_bit = IMX7_DDR_PLL_POWER; + pll->num_offset = PLL_IMX7_NUM_OFFSET; + pll->denom_offset = PLL_IMX7_DENOM_OFFSET; ops = &clk_pllv3_av_ops; break; default: diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c index d38bc9f87c1d..d7e62c3620d3 100644 --- a/drivers/clk/imx/clk-pllv4.c +++ b/drivers/clk/imx/clk-pllv4.c @@ -30,6 +30,9 @@ /* PLL Denominator Register (xPLLDENOM) */ #define PLL_DENOM_OFFSET 0x14 +#define MAX_MFD 0x3fffffff +#define DEFAULT_MFD 1000000 + struct clk_pllv4 { struct clk_hw hw; void __iomem *base; @@ -64,13 +67,20 @@ static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_pllv4 *pll = to_clk_pllv4(hw); - u32 div; + u32 mult, mfn, mfd; + u64 temp64; + + mult = readl_relaxed(pll->base + PLL_CFG_OFFSET); + mult &= BM_PLL_MULT; + mult >>= BP_PLL_MULT; - div = readl_relaxed(pll->base + PLL_CFG_OFFSET); - div &= BM_PLL_MULT; - div >>= BP_PLL_MULT; + mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET); + mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET); + temp64 = parent_rate; + temp64 *= mfn; + do_div(temp64, mfd); - return parent_rate * div; + return (parent_rate * mult) + (u32)temp64; } static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, @@ -78,14 +88,46 @@ static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, { unsigned long parent_rate = *prate; unsigned long round_rate, i; + u32 mfn, mfd = DEFAULT_MFD; + bool found = false; + u64 temp64; for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { round_rate = parent_rate * pllv4_mult_table[i]; - if (rate >= round_rate) - return round_rate; + if (rate >= round_rate) { + found = true; + break; + } + } + + if (!found) { + pr_warn("%s: unable to round rate %lu, parent rate %lu\n", + clk_hw_get_name(hw), rate, parent_rate); + return 0; } - return round_rate; + if (parent_rate <= MAX_MFD) + mfd = parent_rate; + + temp64 = (u64)(rate - round_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + /* + * NOTE: The value of numerator must always be configured to be + * less than the value of the denominator. If we can't get a proper + * pair of mfn/mfd, we simply return the round_rate without using + * the frac part. + */ + if (mfn >= mfd) + return round_rate; + + temp64 = (u64)parent_rate; + temp64 *= mfn; + do_div(temp64, mfd); + + return round_rate + (u32)temp64; } static bool clk_pllv4_is_valid_mult(unsigned int mult) @@ -105,18 +147,30 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_pllv4 *pll = to_clk_pllv4(hw); - u32 val, mult; + u32 val, mult, mfn, mfd = DEFAULT_MFD; + u64 temp64; mult = rate / parent_rate; if (!clk_pllv4_is_valid_mult(mult)) return -EINVAL; + if (parent_rate <= MAX_MFD) + mfd = parent_rate; + + temp64 = (u64)(rate - mult * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); val &= ~BM_PLL_MULT; val |= mult << BP_PLL_MULT; writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); + writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); + return 0; } diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c index 9dfd03a95557..991bbe63f156 100644 --- a/drivers/clk/imx/clk-sccg-pll.c +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -348,7 +348,7 @@ static unsigned long clk_sccg_pll_recalc_rate(struct clk_hw *hw, temp64 = parent_rate; - val = clk_readl(pll->base + PLL_CFG0); + val = readl(pll->base + PLL_CFG0); if (val & SSCG_PLL_BYPASS2_MASK) { temp64 = parent_rate; } else if (val & SSCG_PLL_BYPASS1_MASK) { @@ -371,10 +371,10 @@ static int clk_sccg_pll_set_rate(struct clk_hw *hw, unsigned long rate, u32 val; /* set bypass here too since the parent might be the same */ - val = clk_readl(pll->base + PLL_CFG0); + val = 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); + writel(val, pll->base + PLL_CFG0); val = readl_relaxed(pll->base + PLL_CFG2); val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK); @@ -395,7 +395,7 @@ static u8 clk_sccg_pll_get_parent(struct clk_hw *hw) u32 val; u8 ret = pll->parent; - val = clk_readl(pll->base + PLL_CFG0); + val = readl(pll->base + PLL_CFG0); if (val & SSCG_PLL_BYPASS2_MASK) ret = pll->bypass2; else if (val & SSCG_PLL_BYPASS1_MASK) @@ -408,10 +408,10 @@ 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; - val = clk_readl(pll->base + PLL_CFG0); + val = 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); + writel(val, pll->base + PLL_CFG0); return clk_sccg_pll_wait_lock(pll); } diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 5748ec8673e4..8639a8f2153e 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -77,6 +77,7 @@ enum imx_pllv3_type { IMX_PLLV3_ENET_IMX7, IMX_PLLV3_SYS_VF610, IMX_PLLV3_DDR_IMX7, + IMX_PLLV3_AV_IMX7, }; struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, @@ -138,11 +139,6 @@ static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); } -static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) -{ - return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); -} - static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c index 584ff4ff81c7..8901ea0295b7 100644 --- a/drivers/clk/ingenic/jz4725b-cgu.c +++ b/drivers/clk/ingenic/jz4725b-cgu.c @@ -205,6 +205,12 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = { .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 }, .mux = { CGU_REG_OPCR, 2, 1}, }, + + [JZ4725B_CLK_UDC_PHY] = { + "udc_phy", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, + .gate = { CGU_REG_OPCR, 6, true }, + }, }; static void __init jz4725b_cgu_init(struct device_node *np) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 53edade25a1d..4d8a9aef95f6 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -216,4 +216,87 @@ config COMMON_CLK_MT8173 default ARCH_MEDIATEK ---help--- This driver supports MediaTek MT8173 clocks. + +config COMMON_CLK_MT8183 + bool "Clock driver for MediaTek MT8183" + depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK && ARM64 + help + This driver supports MediaTek MT8183 basic clocks. + +config COMMON_CLK_MT8183_AUDIOSYS + bool "Clock driver for MediaTek MT8183 audiosys" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 audiosys clocks. + +config COMMON_CLK_MT8183_CAMSYS + bool "Clock driver for MediaTek MT8183 camsys" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 camsys clocks. + +config COMMON_CLK_MT8183_IMGSYS + bool "Clock driver for MediaTek MT8183 imgsys" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 imgsys clocks. + +config COMMON_CLK_MT8183_IPU_CORE0 + bool "Clock driver for MediaTek MT8183 ipu_core0" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 ipu_core0 clocks. + +config COMMON_CLK_MT8183_IPU_CORE1 + bool "Clock driver for MediaTek MT8183 ipu_core1" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 ipu_core1 clocks. + +config COMMON_CLK_MT8183_IPU_ADL + bool "Clock driver for MediaTek MT8183 ipu_adl" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 ipu_adl clocks. + +config COMMON_CLK_MT8183_IPU_CONN + bool "Clock driver for MediaTek MT8183 ipu_conn" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 ipu_conn clocks. + +config COMMON_CLK_MT8183_MFGCFG + bool "Clock driver for MediaTek MT8183 mfgcfg" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 mfgcfg clocks. + +config COMMON_CLK_MT8183_MMSYS + bool "Clock driver for MediaTek MT8183 mmsys" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 mmsys clocks. + +config COMMON_CLK_MT8183_VDECSYS + bool "Clock driver for MediaTek MT8183 vdecsys" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 vdecsys clocks. + +config COMMON_CLK_MT8183_VENCSYS + bool "Clock driver for MediaTek MT8183 vencsys" + depends on COMMON_CLK_MT8183 + help + This driver supports MediaTek MT8183 vencsys clocks. + +config COMMON_CLK_MT8516 + bool "Clock driver for MediaTek MT8516" + depends on ARCH_MEDIATEK || COMPILE_TEST + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + help + This driver supports MediaTek MT8516 clocks. + endmenu diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index ee4410ff43ab..f74937b35f68 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o +obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o clk-mux.o + obj-$(CONFIG_COMMON_CLK_MT6797) += clk-mt6797.o obj-$(CONFIG_COMMON_CLK_MT6797_IMGSYS) += clk-mt6797-img.o obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o @@ -31,3 +32,16 @@ obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o +obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183.o +obj-$(CONFIG_COMMON_CLK_MT8183_AUDIOSYS) += clk-mt8183-audio.o +obj-$(CONFIG_COMMON_CLK_MT8183_CAMSYS) += clk-mt8183-cam.o +obj-$(CONFIG_COMMON_CLK_MT8183_IMGSYS) += clk-mt8183-img.o +obj-$(CONFIG_COMMON_CLK_MT8183_IPU_CORE0) += clk-mt8183-ipu0.o +obj-$(CONFIG_COMMON_CLK_MT8183_IPU_CORE1) += clk-mt8183-ipu1.o +obj-$(CONFIG_COMMON_CLK_MT8183_IPU_ADL) += clk-mt8183-ipu_adl.o +obj-$(CONFIG_COMMON_CLK_MT8183_IPU_CONN) += clk-mt8183-ipu_conn.o +obj-$(CONFIG_COMMON_CLK_MT8183_MFGCFG) += clk-mt8183-mfgcfg.o +obj-$(CONFIG_COMMON_CLK_MT8183_MMSYS) += clk-mt8183-mm.o +obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o +obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o +obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 9f766dfe1d57..ab240163f9f8 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -50,4 +50,18 @@ struct clk *mtk_clk_register_gate( const struct clk_ops *ops, unsigned long flags); +#define GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, \ + _ops, _flags) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = _regs, \ + .shift = _shift, \ + .ops = _ops, \ + .flags = _flags, \ + } + +#define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops) \ + GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0) + #endif /* __DRV_CLK_GATE_H */ diff --git a/drivers/clk/mediatek/clk-mt8183-audio.c b/drivers/clk/mediatek/clk-mt8183-audio.c new file mode 100644 index 000000000000..c87450180b7b --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-audio.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs audio0_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x0, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs audio1_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x4, + .sta_ofs = 0x4, +}; + +#define GATE_AUDIO0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio0_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr) + +#define GATE_AUDIO1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio1_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr) + +static const struct mtk_gate audio_clks[] = { + /* AUDIO0 */ + GATE_AUDIO0(CLK_AUDIO_AFE, "aud_afe", "audio_sel", + 2), + GATE_AUDIO0(CLK_AUDIO_22M, "aud_22m", "aud_eng1_sel", + 8), + GATE_AUDIO0(CLK_AUDIO_24M, "aud_24m", "aud_eng2_sel", + 9), + GATE_AUDIO0(CLK_AUDIO_APLL2_TUNER, "aud_apll2_tuner", "aud_eng2_sel", + 18), + GATE_AUDIO0(CLK_AUDIO_APLL_TUNER, "aud_apll_tuner", "aud_eng1_sel", + 19), + GATE_AUDIO0(CLK_AUDIO_TDM, "aud_tdm", "apll12_divb", + 20), + GATE_AUDIO0(CLK_AUDIO_ADC, "aud_adc", "audio_sel", + 24), + GATE_AUDIO0(CLK_AUDIO_DAC, "aud_dac", "audio_sel", + 25), + GATE_AUDIO0(CLK_AUDIO_DAC_PREDIS, "aud_dac_predis", "audio_sel", + 26), + GATE_AUDIO0(CLK_AUDIO_TML, "aud_tml", "audio_sel", + 27), + /* AUDIO1 */ + GATE_AUDIO1(CLK_AUDIO_I2S1, "aud_i2s1", "audio_sel", + 4), + GATE_AUDIO1(CLK_AUDIO_I2S2, "aud_i2s2", "audio_sel", + 5), + GATE_AUDIO1(CLK_AUDIO_I2S3, "aud_i2s3", "audio_sel", + 6), + GATE_AUDIO1(CLK_AUDIO_I2S4, "aud_i2s4", "audio_sel", + 7), + GATE_AUDIO1(CLK_AUDIO_PDN_ADDA6_ADC, "aud_pdn_adda6_adc", "audio_sel", + 20), +}; + +static int clk_mt8183_audio_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_AUDIO_NR_CLK); + + mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + return r; + + r = devm_of_platform_populate(&pdev->dev); + if (r) + of_clk_del_provider(node); + + return r; +} + +static const struct of_device_id of_match_clk_mt8183_audio[] = { + { .compatible = "mediatek,mt8183-audiosys", }, + {} +}; + +static struct platform_driver clk_mt8183_audio_drv = { + .probe = clk_mt8183_audio_probe, + .driver = { + .name = "clk-mt8183-audio", + .of_match_table = of_match_clk_mt8183_audio, + }, +}; + +builtin_platform_driver(clk_mt8183_audio_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-cam.c b/drivers/clk/mediatek/clk-mt8183-cam.c new file mode 100644 index 000000000000..8643802c4471 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-cam.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs cam_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_CAM(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &cam_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate cam_clks[] = { + GATE_CAM(CLK_CAM_LARB6, "cam_larb6", "cam_sel", 0), + GATE_CAM(CLK_CAM_DFP_VAD, "cam_dfp_vad", "cam_sel", 1), + GATE_CAM(CLK_CAM_LARB3, "cam_larb3", "cam_sel", 2), + GATE_CAM(CLK_CAM_CAM, "cam_cam", "cam_sel", 6), + GATE_CAM(CLK_CAM_CAMTG, "cam_camtg", "cam_sel", 7), + GATE_CAM(CLK_CAM_SENINF, "cam_seninf", "cam_sel", 8), + GATE_CAM(CLK_CAM_CAMSV0, "cam_camsv0", "cam_sel", 9), + GATE_CAM(CLK_CAM_CAMSV1, "cam_camsv1", "cam_sel", 10), + GATE_CAM(CLK_CAM_CAMSV2, "cam_camsv2", "cam_sel", 11), + GATE_CAM(CLK_CAM_CCU, "cam_ccu", "cam_sel", 12), +}; + +static int clk_mt8183_cam_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_CAM_NR_CLK); + + mtk_clk_register_gates(node, cam_clks, ARRAY_SIZE(cam_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_cam[] = { + { .compatible = "mediatek,mt8183-camsys", }, + {} +}; + +static struct platform_driver clk_mt8183_cam_drv = { + .probe = clk_mt8183_cam_probe, + .driver = { + .name = "clk-mt8183-cam", + .of_match_table = of_match_clk_mt8183_cam, + }, +}; + +builtin_platform_driver(clk_mt8183_cam_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-img.c b/drivers/clk/mediatek/clk-mt8183-img.c new file mode 100644 index 000000000000..470d676a4a10 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-img.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs img_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_IMG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate img_clks[] = { + GATE_IMG(CLK_IMG_LARB5, "img_larb5", "img_sel", 0), + GATE_IMG(CLK_IMG_LARB2, "img_larb2", "img_sel", 1), + GATE_IMG(CLK_IMG_DIP, "img_dip", "img_sel", 2), + GATE_IMG(CLK_IMG_FDVT, "img_fdvt", "img_sel", 3), + GATE_IMG(CLK_IMG_DPE, "img_dpe", "img_sel", 4), + GATE_IMG(CLK_IMG_RSC, "img_rsc", "img_sel", 5), + GATE_IMG(CLK_IMG_MFB, "img_mfb", "img_sel", 6), + GATE_IMG(CLK_IMG_WPE_A, "img_wpe_a", "img_sel", 7), + GATE_IMG(CLK_IMG_WPE_B, "img_wpe_b", "img_sel", 8), + GATE_IMG(CLK_IMG_OWE, "img_owe", "img_sel", 9), +}; + +static int clk_mt8183_img_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IMG_NR_CLK); + + mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_img[] = { + { .compatible = "mediatek,mt8183-imgsys", }, + {} +}; + +static struct platform_driver clk_mt8183_img_drv = { + .probe = clk_mt8183_img_probe, + .driver = { + .name = "clk-mt8183-img", + .of_match_table = of_match_clk_mt8183_img, + }, +}; + +builtin_platform_driver(clk_mt8183_img_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu0.c b/drivers/clk/mediatek/clk-mt8183-ipu0.c new file mode 100644 index 000000000000..c5cb76fc9e5e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-ipu0.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs ipu_core0_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_IPU_CORE0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_core0_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate ipu_core0_clks[] = { + GATE_IPU_CORE0(CLK_IPU_CORE0_JTAG, "ipu_core0_jtag", "dsp_sel", 0), + GATE_IPU_CORE0(CLK_IPU_CORE0_AXI, "ipu_core0_axi", "dsp_sel", 1), + GATE_IPU_CORE0(CLK_IPU_CORE0_IPU, "ipu_core0_ipu", "dsp_sel", 2), +}; + +static int clk_mt8183_ipu_core0_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IPU_CORE0_NR_CLK); + + mtk_clk_register_gates(node, ipu_core0_clks, ARRAY_SIZE(ipu_core0_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_ipu_core0[] = { + { .compatible = "mediatek,mt8183-ipu_core0", }, + {} +}; + +static struct platform_driver clk_mt8183_ipu_core0_drv = { + .probe = clk_mt8183_ipu_core0_probe, + .driver = { + .name = "clk-mt8183-ipu_core0", + .of_match_table = of_match_clk_mt8183_ipu_core0, + }, +}; + +builtin_platform_driver(clk_mt8183_ipu_core0_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu1.c b/drivers/clk/mediatek/clk-mt8183-ipu1.c new file mode 100644 index 000000000000..8fd5fe002890 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-ipu1.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs ipu_core1_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_IPU_CORE1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_core1_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate ipu_core1_clks[] = { + GATE_IPU_CORE1(CLK_IPU_CORE1_JTAG, "ipu_core1_jtag", "dsp_sel", 0), + GATE_IPU_CORE1(CLK_IPU_CORE1_AXI, "ipu_core1_axi", "dsp_sel", 1), + GATE_IPU_CORE1(CLK_IPU_CORE1_IPU, "ipu_core1_ipu", "dsp_sel", 2), +}; + +static int clk_mt8183_ipu_core1_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IPU_CORE1_NR_CLK); + + mtk_clk_register_gates(node, ipu_core1_clks, ARRAY_SIZE(ipu_core1_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_ipu_core1[] = { + { .compatible = "mediatek,mt8183-ipu_core1", }, + {} +}; + +static struct platform_driver clk_mt8183_ipu_core1_drv = { + .probe = clk_mt8183_ipu_core1_probe, + .driver = { + .name = "clk-mt8183-ipu_core1", + .of_match_table = of_match_clk_mt8183_ipu_core1, + }, +}; + +builtin_platform_driver(clk_mt8183_ipu_core1_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu_adl.c b/drivers/clk/mediatek/clk-mt8183-ipu_adl.c new file mode 100644 index 000000000000..3f37d0ef1df1 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-ipu_adl.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs ipu_adl_cg_regs = { + .set_ofs = 0x204, + .clr_ofs = 0x204, + .sta_ofs = 0x204, +}; + +#define GATE_IPU_ADL_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_adl_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate ipu_adl_clks[] = { + GATE_IPU_ADL_I(CLK_IPU_ADL_CABGEN, "ipu_adl_cabgen", "dsp_sel", 24), +}; + +static int clk_mt8183_ipu_adl_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IPU_ADL_NR_CLK); + + mtk_clk_register_gates(node, ipu_adl_clks, ARRAY_SIZE(ipu_adl_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_ipu_adl[] = { + { .compatible = "mediatek,mt8183-ipu_adl", }, + {} +}; + +static struct platform_driver clk_mt8183_ipu_adl_drv = { + .probe = clk_mt8183_ipu_adl_probe, + .driver = { + .name = "clk-mt8183-ipu_adl", + .of_match_table = of_match_clk_mt8183_ipu_adl, + }, +}; + +builtin_platform_driver(clk_mt8183_ipu_adl_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu_conn.c b/drivers/clk/mediatek/clk-mt8183-ipu_conn.c new file mode 100644 index 000000000000..7e0eef79c461 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-ipu_conn.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs ipu_conn_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs ipu_conn_apb_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x10, + .sta_ofs = 0x10, +}; + +static const struct mtk_gate_regs ipu_conn_axi_cg_regs = { + .set_ofs = 0x18, + .clr_ofs = 0x18, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs ipu_conn_axi1_cg_regs = { + .set_ofs = 0x1c, + .clr_ofs = 0x1c, + .sta_ofs = 0x1c, +}; + +static const struct mtk_gate_regs ipu_conn_axi2_cg_regs = { + .set_ofs = 0x20, + .clr_ofs = 0x20, + .sta_ofs = 0x20, +}; + +#define GATE_IPU_CONN(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_conn_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +#define GATE_IPU_CONN_APB(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_conn_apb_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr) + +#define GATE_IPU_CONN_AXI_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_conn_axi_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr_inv) + +#define GATE_IPU_CONN_AXI1_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_conn_axi1_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr_inv) + +#define GATE_IPU_CONN_AXI2_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipu_conn_axi2_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate ipu_conn_clks[] = { + GATE_IPU_CONN(CLK_IPU_CONN_IPU, + "ipu_conn_ipu", "dsp_sel", 0), + GATE_IPU_CONN(CLK_IPU_CONN_AHB, + "ipu_conn_ahb", "dsp_sel", 1), + GATE_IPU_CONN(CLK_IPU_CONN_AXI, + "ipu_conn_axi", "dsp_sel", 2), + GATE_IPU_CONN(CLK_IPU_CONN_ISP, + "ipu_conn_isp", "dsp_sel", 3), + GATE_IPU_CONN(CLK_IPU_CONN_CAM_ADL, + "ipu_conn_cam_adl", "dsp_sel", 4), + GATE_IPU_CONN(CLK_IPU_CONN_IMG_ADL, + "ipu_conn_img_adl", "dsp_sel", 5), + GATE_IPU_CONN_APB(CLK_IPU_CONN_DAP_RX, + "ipu_conn_dap_rx", "dsp1_sel", 0), + GATE_IPU_CONN_APB(CLK_IPU_CONN_APB2AXI, + "ipu_conn_apb2axi", "dsp1_sel", 3), + GATE_IPU_CONN_APB(CLK_IPU_CONN_APB2AHB, + "ipu_conn_apb2ahb", "dsp1_sel", 20), + GATE_IPU_CONN_AXI_I(CLK_IPU_CONN_IPU_CAB1TO2, + "ipu_conn_ipu_cab1to2", "dsp1_sel", 6), + GATE_IPU_CONN_AXI_I(CLK_IPU_CONN_IPU1_CAB1TO2, + "ipu_conn_ipu1_cab1to2", "dsp1_sel", 13), + GATE_IPU_CONN_AXI_I(CLK_IPU_CONN_IPU2_CAB1TO2, + "ipu_conn_ipu2_cab1to2", "dsp1_sel", 20), + GATE_IPU_CONN_AXI1_I(CLK_IPU_CONN_CAB3TO3, + "ipu_conn_cab3to3", "dsp1_sel", 0), + GATE_IPU_CONN_AXI2_I(CLK_IPU_CONN_CAB2TO1, + "ipu_conn_cab2to1", "dsp1_sel", 14), + GATE_IPU_CONN_AXI2_I(CLK_IPU_CONN_CAB3TO1_SLICE, + "ipu_conn_cab3to1_slice", "dsp1_sel", 17), +}; + +static int clk_mt8183_ipu_conn_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IPU_CONN_NR_CLK); + + mtk_clk_register_gates(node, ipu_conn_clks, ARRAY_SIZE(ipu_conn_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_ipu_conn[] = { + { .compatible = "mediatek,mt8183-ipu_conn", }, + {} +}; + +static struct platform_driver clk_mt8183_ipu_conn_drv = { + .probe = clk_mt8183_ipu_conn_probe, + .driver = { + .name = "clk-mt8183-ipu_conn", + .of_match_table = of_match_clk_mt8183_ipu_conn, + }, +}; + +builtin_platform_driver(clk_mt8183_ipu_conn_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-mfgcfg.c b/drivers/clk/mediatek/clk-mt8183-mfgcfg.c new file mode 100644 index 000000000000..99a6b020833e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-mfgcfg.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs mfg_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_MFG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mfg_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate mfg_clks[] = { + GATE_MFG(CLK_MFG_BG3D, "mfg_bg3d", "mfg_sel", 0) +}; + +static int clk_mt8183_mfg_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_MFG_NR_CLK); + + mtk_clk_register_gates(node, mfg_clks, ARRAY_SIZE(mfg_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_mfg[] = { + { .compatible = "mediatek,mt8183-mfgcfg", }, + {} +}; + +static struct platform_driver clk_mt8183_mfg_drv = { + .probe = clk_mt8183_mfg_probe, + .driver = { + .name = "clk-mt8183-mfg", + .of_match_table = of_match_clk_mt8183_mfg, + }, +}; + +builtin_platform_driver(clk_mt8183_mfg_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-mm.c b/drivers/clk/mediatek/clk-mt8183-mm.c new file mode 100644 index 000000000000..720c696b506d --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-mm.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs mm0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs mm1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +#define GATE_MM0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm0_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +#define GATE_MM1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm1_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate mm_clks[] = { + /* MM0 */ + GATE_MM0(CLK_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 0), + GATE_MM0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1), + GATE_MM0(CLK_MM_SMI_LARB1, "mm_smi_larb1", "mm_sel", 2), + GATE_MM0(CLK_MM_GALS_COMM0, "mm_gals_comm0", "mm_sel", 3), + GATE_MM0(CLK_MM_GALS_COMM1, "mm_gals_comm1", "mm_sel", 4), + GATE_MM0(CLK_MM_GALS_CCU2MM, "mm_gals_ccu2mm", "mm_sel", 5), + GATE_MM0(CLK_MM_GALS_IPU12MM, "mm_gals_ipu12mm", "mm_sel", 6), + GATE_MM0(CLK_MM_GALS_IMG2MM, "mm_gals_img2mm", "mm_sel", 7), + GATE_MM0(CLK_MM_GALS_CAM2MM, "mm_gals_cam2mm", "mm_sel", 8), + GATE_MM0(CLK_MM_GALS_IPU2MM, "mm_gals_ipu2mm", "mm_sel", 9), + GATE_MM0(CLK_MM_MDP_DL_TXCK, "mm_mdp_dl_txck", "mm_sel", 10), + GATE_MM0(CLK_MM_IPU_DL_TXCK, "mm_ipu_dl_txck", "mm_sel", 11), + GATE_MM0(CLK_MM_MDP_RDMA0, "mm_mdp_rdma0", "mm_sel", 12), + GATE_MM0(CLK_MM_MDP_RDMA1, "mm_mdp_rdma1", "mm_sel", 13), + GATE_MM0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 14), + GATE_MM0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 15), + GATE_MM0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 16), + GATE_MM0(CLK_MM_MDP_WROT0, "mm_mdp_wrot0", "mm_sel", 17), + GATE_MM0(CLK_MM_MDP_WDMA0, "mm_mdp_wdma0", "mm_sel", 18), + GATE_MM0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 19), + GATE_MM0(CLK_MM_DISP_OVL0, "mm_disp_ovl0", "mm_sel", 20), + GATE_MM0(CLK_MM_DISP_OVL0_2L, "mm_disp_ovl0_2l", "mm_sel", 21), + GATE_MM0(CLK_MM_DISP_OVL1_2L, "mm_disp_ovl1_2l", "mm_sel", 22), + GATE_MM0(CLK_MM_DISP_RDMA0, "mm_disp_rdma0", "mm_sel", 23), + GATE_MM0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 24), + GATE_MM0(CLK_MM_DISP_WDMA0, "mm_disp_wdma0", "mm_sel", 25), + GATE_MM0(CLK_MM_DISP_COLOR0, "mm_disp_color0", "mm_sel", 26), + GATE_MM0(CLK_MM_DISP_CCORR0, "mm_disp_ccorr0", "mm_sel", 27), + GATE_MM0(CLK_MM_DISP_AAL0, "mm_disp_aal0", "mm_sel", 28), + GATE_MM0(CLK_MM_DISP_GAMMA0, "mm_disp_gamma0", "mm_sel", 29), + GATE_MM0(CLK_MM_DISP_DITHER0, "mm_disp_dither0", "mm_sel", 30), + GATE_MM0(CLK_MM_DISP_SPLIT, "mm_disp_split", "mm_sel", 31), + /* MM1 */ + GATE_MM1(CLK_MM_DSI0_MM, "mm_dsi0_mm", "mm_sel", 0), + GATE_MM1(CLK_MM_DSI0_IF, "mm_dsi0_if", "mm_sel", 1), + GATE_MM1(CLK_MM_DPI_MM, "mm_dpi_mm", "mm_sel", 2), + GATE_MM1(CLK_MM_DPI_IF, "mm_dpi_if", "dpi0_sel", 3), + GATE_MM1(CLK_MM_FAKE_ENG2, "mm_fake_eng2", "mm_sel", 4), + GATE_MM1(CLK_MM_MDP_DL_RX, "mm_mdp_dl_rx", "mm_sel", 5), + GATE_MM1(CLK_MM_IPU_DL_RX, "mm_ipu_dl_rx", "mm_sel", 6), + GATE_MM1(CLK_MM_26M, "mm_26m", "f_f26m_ck", 7), + GATE_MM1(CLK_MM_MMSYS_R2Y, "mm_mmsys_r2y", "mm_sel", 8), + GATE_MM1(CLK_MM_DISP_RSZ, "mm_disp_rsz", "mm_sel", 9), + GATE_MM1(CLK_MM_MDP_AAL, "mm_mdp_aal", "mm_sel", 10), + GATE_MM1(CLK_MM_MDP_CCORR, "mm_mdp_ccorr", "mm_sel", 11), + GATE_MM1(CLK_MM_DBI_MM, "mm_dbi_mm", "mm_sel", 12), + GATE_MM1(CLK_MM_DBI_IF, "mm_dbi_if", "dpi0_sel", 13), +}; + +static int clk_mt8183_mm_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); + + mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_mm[] = { + { .compatible = "mediatek,mt8183-mmsys", }, + {} +}; + +static struct platform_driver clk_mt8183_mm_drv = { + .probe = clk_mt8183_mm_probe, + .driver = { + .name = "clk-mt8183-mm", + .of_match_table = of_match_clk_mt8183_mm, + }, +}; + +builtin_platform_driver(clk_mt8183_mm_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-vdec.c b/drivers/clk/mediatek/clk-mt8183-vdec.c new file mode 100644 index 000000000000..6250fd1e0edc --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-vdec.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs vdec0_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x4, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs vdec1_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x8, +}; + +#define GATE_VDEC0_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec0_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr_inv) + +#define GATE_VDEC1_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec1_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr_inv) + +static const struct mtk_gate vdec_clks[] = { + /* VDEC0 */ + GATE_VDEC0_I(CLK_VDEC_VDEC, "vdec_vdec", "mm_sel", 0), + /* VDEC1 */ + GATE_VDEC1_I(CLK_VDEC_LARB1, "vdec_larb1", "mm_sel", 0), +}; + +static int clk_mt8183_vdec_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_VDEC_NR_CLK); + + mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_vdec[] = { + { .compatible = "mediatek,mt8183-vdecsys", }, + {} +}; + +static struct platform_driver clk_mt8183_vdec_drv = { + .probe = clk_mt8183_vdec_probe, + .driver = { + .name = "clk-mt8183-vdec", + .of_match_table = of_match_clk_mt8183_vdec, + }, +}; + +builtin_platform_driver(clk_mt8183_vdec_drv); diff --git a/drivers/clk/mediatek/clk-mt8183-venc.c b/drivers/clk/mediatek/clk-mt8183-venc.c new file mode 100644 index 000000000000..6678ef03fab2 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-venc.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static const struct mtk_gate_regs venc_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_VENC_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &venc_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr_inv) + +static const struct mtk_gate venc_clks[] = { + GATE_VENC_I(CLK_VENC_LARB, "venc_larb", + "mm_sel", 0), + GATE_VENC_I(CLK_VENC_VENC, "venc_venc", + "mm_sel", 4), + GATE_VENC_I(CLK_VENC_JPGENC, "venc_jpgenc", + "mm_sel", 8), +}; + +static int clk_mt8183_venc_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_VENC_NR_CLK); + + mtk_clk_register_gates(node, venc_clks, ARRAY_SIZE(venc_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183_venc[] = { + { .compatible = "mediatek,mt8183-vencsys", }, + {} +}; + +static struct platform_driver clk_mt8183_venc_drv = { + .probe = clk_mt8183_venc_probe, + .driver = { + .name = "clk-mt8183-venc", + .of_match_table = of_match_clk_mt8183_venc, + }, +}; + +builtin_platform_driver(clk_mt8183_venc_drv); diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c new file mode 100644 index 000000000000..9d8651033ae9 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183.c @@ -0,0 +1,1284 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: Weiyi Lu <weiyi.lu@mediatek.com> + +#include <linux/delay.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "clk-mtk.h" +#include "clk-mux.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8183-clk.h> + +static DEFINE_SPINLOCK(mt8183_clk_lock); + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_CLK26M, "f_f26m_ck", "clk26m", 26000000), + FIXED_CLK(CLK_TOP_ULPOSC, "osc", NULL, 250000), + FIXED_CLK(CLK_TOP_UNIVP_192M, "univpll_192m", "univpll", 192000000), +}; + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_CLK13M, "clk13m", "clk26m", 1, + 2), + FACTOR(CLK_TOP_F26M_CK_D2, "csw_f26m_ck_d2", "clk26m", 1, + 2), + FACTOR(CLK_TOP_SYSPLL_CK, "syspll_ck", "mainpll", 1, + 1), + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "syspll_ck", 1, + 2), + FACTOR(CLK_TOP_SYSPLL_D2_D2, "syspll_d2_d2", "syspll_d2", 1, + 2), + FACTOR(CLK_TOP_SYSPLL_D2_D4, "syspll_d2_d4", "syspll_d2", 1, + 4), + FACTOR(CLK_TOP_SYSPLL_D2_D8, "syspll_d2_d8", "syspll_d2", 1, + 8), + FACTOR(CLK_TOP_SYSPLL_D2_D16, "syspll_d2_d16", "syspll_d2", 1, + 16), + FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, + 3), + FACTOR(CLK_TOP_SYSPLL_D3_D2, "syspll_d3_d2", "syspll_d3", 1, + 2), + FACTOR(CLK_TOP_SYSPLL_D3_D4, "syspll_d3_d4", "syspll_d3", 1, + 4), + FACTOR(CLK_TOP_SYSPLL_D3_D8, "syspll_d3_d8", "syspll_d3", 1, + 8), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, + 5), + FACTOR(CLK_TOP_SYSPLL_D5_D2, "syspll_d5_d2", "syspll_d5", 1, + 2), + FACTOR(CLK_TOP_SYSPLL_D5_D4, "syspll_d5_d4", "syspll_d5", 1, + 4), + FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, + 7), + FACTOR(CLK_TOP_SYSPLL_D7_D2, "syspll_d7_d2", "syspll_d7", 1, + 2), + FACTOR(CLK_TOP_SYSPLL_D7_D4, "syspll_d7_d4", "syspll_d7", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL_CK, "univpll_ck", "univpll", 1, + 1), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll_ck", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL_D2_D2, "univpll_d2_d2", "univpll_d2", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL_D2_D4, "univpll_d2_d4", "univpll_d2", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL_D2_D8, "univpll_d2_d8", "univpll_d2", 1, + 8), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, + 3), + FACTOR(CLK_TOP_UNIVPLL_D3_D2, "univpll_d3_d2", "univpll_d3", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL_D3_D4, "univpll_d3_d4", "univpll_d3", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL_D3_D8, "univpll_d3_d8", "univpll_d3", 1, + 8), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, + 5), + FACTOR(CLK_TOP_UNIVPLL_D5_D2, "univpll_d5_d2", "univpll_d5", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL_D5_D4, "univpll_d5_d4", "univpll_d5", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL_D5_D8, "univpll_d5_d8", "univpll_d5", 1, + 8), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, + 7), + FACTOR(CLK_TOP_UNIVP_192M_CK, "univ_192m_ck", "univpll_192m", 1, + 1), + FACTOR(CLK_TOP_UNIVP_192M_D2, "univ_192m_d2", "univ_192m_ck", 1, + 2), + FACTOR(CLK_TOP_UNIVP_192M_D4, "univ_192m_d4", "univ_192m_ck", 1, + 4), + FACTOR(CLK_TOP_UNIVP_192M_D8, "univ_192m_d8", "univ_192m_ck", 1, + 8), + FACTOR(CLK_TOP_UNIVP_192M_D16, "univ_192m_d16", "univ_192m_ck", 1, + 16), + FACTOR(CLK_TOP_UNIVP_192M_D32, "univ_192m_d32", "univ_192m_ck", 1, + 32), + FACTOR(CLK_TOP_APLL1_CK, "apll1_ck", "apll1", 1, + 1), + FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1", 1, + 2), + FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1", 1, + 4), + FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "apll1", 1, + 8), + FACTOR(CLK_TOP_APLL2_CK, "apll2_ck", "apll2", 1, + 1), + FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, + 2), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, + 4), + FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "apll2", 1, + 8), + FACTOR(CLK_TOP_TVDPLL_CK, "tvdpll_ck", "tvdpll", 1, + 1), + FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_ck", 1, + 2), + FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, + 4), + FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll", 1, + 8), + FACTOR(CLK_TOP_TVDPLL_D16, "tvdpll_d16", "tvdpll", 1, + 16), + FACTOR(CLK_TOP_MMPLL_CK, "mmpll_ck", "mmpll", 1, + 1), + FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, + 4), + FACTOR(CLK_TOP_MMPLL_D4_D2, "mmpll_d4_d2", "mmpll_d4", 1, + 2), + FACTOR(CLK_TOP_MMPLL_D4_D4, "mmpll_d4_d4", "mmpll_d4", 1, + 4), + FACTOR(CLK_TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, + 5), + FACTOR(CLK_TOP_MMPLL_D5_D2, "mmpll_d5_d2", "mmpll_d5", 1, + 2), + FACTOR(CLK_TOP_MMPLL_D5_D4, "mmpll_d5_d4", "mmpll_d5", 1, + 4), + FACTOR(CLK_TOP_MMPLL_D6, "mmpll_d6", "mmpll", 1, + 6), + FACTOR(CLK_TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, + 7), + FACTOR(CLK_TOP_MFGPLL_CK, "mfgpll_ck", "mfgpll", 1, + 1), + FACTOR(CLK_TOP_MSDCPLL_CK, "msdcpll_ck", "msdcpll", 1, + 1), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, + 2), + FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, + 4), + FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, + 8), + FACTOR(CLK_TOP_MSDCPLL_D16, "msdcpll_d16", "msdcpll", 1, + 16), + FACTOR(CLK_TOP_AD_OSC_CK, "ad_osc_ck", "osc", 1, + 1), + FACTOR(CLK_TOP_OSC_D2, "osc_d2", "osc", 1, + 2), + FACTOR(CLK_TOP_OSC_D4, "osc_d4", "osc", 1, + 4), + FACTOR(CLK_TOP_OSC_D8, "osc_d8", "osc", 1, + 8), + FACTOR(CLK_TOP_OSC_D16, "osc_d16", "osc", 1, + 16), + FACTOR(CLK_TOP_UNIVPLL, "univpll", "univ2pll", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL_D3_D16, "univpll_d3_d16", "univpll_d3", 1, + 16), +}; + +static const char * const axi_parents[] = { + "clk26m", + "syspll_d2_d4", + "syspll_d7", + "osc_d4" +}; + +static const char * const mm_parents[] = { + "clk26m", + "mmpll_d7", + "syspll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "syspll_d3_d2" +}; + +static const char * const img_parents[] = { + "clk26m", + "mmpll_d6", + "univpll_d3", + "syspll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "univpll_d3_d2", + "syspll_d3_d2" +}; + +static const char * const cam_parents[] = { + "clk26m", + "syspll_d2", + "mmpll_d6", + "syspll_d3", + "mmpll_d7", + "univpll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "syspll_d3_d2", + "univpll_d3_d2" +}; + +static const char * const dsp_parents[] = { + "clk26m", + "mmpll_d6", + "mmpll_d7", + "univpll_d3", + "syspll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "univpll_d3_d2", + "syspll_d3_d2" +}; + +static const char * const dsp1_parents[] = { + "clk26m", + "mmpll_d6", + "mmpll_d7", + "univpll_d3", + "syspll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "univpll_d3_d2", + "syspll_d3_d2" +}; + +static const char * const dsp2_parents[] = { + "clk26m", + "mmpll_d6", + "mmpll_d7", + "univpll_d3", + "syspll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "univpll_d3_d2", + "syspll_d3_d2" +}; + +static const char * const ipu_if_parents[] = { + "clk26m", + "mmpll_d6", + "mmpll_d7", + "univpll_d3", + "syspll_d3", + "univpll_d2_d2", + "syspll_d2_d2", + "univpll_d3_d2", + "syspll_d3_d2" +}; + +static const char * const mfg_parents[] = { + "clk26m", + "mfgpll_ck", + "univpll_d3", + "syspll_d3" +}; + +static const char * const f52m_mfg_parents[] = { + "clk26m", + "univpll_d3_d2", + "univpll_d3_d4", + "univpll_d3_d8" +}; + +static const char * const camtg_parents[] = { + "clk26m", + "univ_192m_d8", + "univpll_d3_d8", + "univ_192m_d4", + "univpll_d3_d16", + "csw_f26m_ck_d2", + "univ_192m_d16", + "univ_192m_d32" +}; + +static const char * const camtg2_parents[] = { + "clk26m", + "univ_192m_d8", + "univpll_d3_d8", + "univ_192m_d4", + "univpll_d3_d16", + "csw_f26m_ck_d2", + "univ_192m_d16", + "univ_192m_d32" +}; + +static const char * const camtg3_parents[] = { + "clk26m", + "univ_192m_d8", + "univpll_d3_d8", + "univ_192m_d4", + "univpll_d3_d16", + "csw_f26m_ck_d2", + "univ_192m_d16", + "univ_192m_d32" +}; + +static const char * const camtg4_parents[] = { + "clk26m", + "univ_192m_d8", + "univpll_d3_d8", + "univ_192m_d4", + "univpll_d3_d16", + "csw_f26m_ck_d2", + "univ_192m_d16", + "univ_192m_d32" +}; + +static const char * const uart_parents[] = { + "clk26m", + "univpll_d3_d8" +}; + +static const char * const spi_parents[] = { + "clk26m", + "syspll_d5_d2", + "syspll_d3_d4", + "msdcpll_d4" +}; + +static const char * const msdc50_hclk_parents[] = { + "clk26m", + "syspll_d2_d2", + "syspll_d3_d2" +}; + +static const char * const msdc50_0_parents[] = { + "clk26m", + "msdcpll_ck", + "msdcpll_d2", + "univpll_d2_d4", + "syspll_d3_d2", + "univpll_d2_d2" +}; + +static const char * const msdc30_1_parents[] = { + "clk26m", + "univpll_d3_d2", + "syspll_d3_d2", + "syspll_d7", + "msdcpll_d2" +}; + +static const char * const msdc30_2_parents[] = { + "clk26m", + "univpll_d3_d2", + "syspll_d3_d2", + "syspll_d7", + "msdcpll_d2" +}; + +static const char * const audio_parents[] = { + "clk26m", + "syspll_d5_d4", + "syspll_d7_d4", + "syspll_d2_d16" +}; + +static const char * const aud_intbus_parents[] = { + "clk26m", + "syspll_d2_d4", + "syspll_d7_d2" +}; + +static const char * const pmicspi_parents[] = { + "clk26m", + "syspll_d2_d8", + "osc_d8" +}; + +static const char * const fpwrap_ulposc_parents[] = { + "clk26m", + "osc_d16", + "osc_d4", + "osc_d8" +}; + +static const char * const atb_parents[] = { + "clk26m", + "syspll_d2_d2", + "syspll_d5" +}; + +static const char * const sspm_parents[] = { + "clk26m", + "univpll_d2_d4", + "syspll_d2_d2", + "univpll_d2_d2", + "syspll_d3" +}; + +static const char * const dpi0_parents[] = { + "clk26m", + "tvdpll_d2", + "tvdpll_d4", + "tvdpll_d8", + "tvdpll_d16", + "univpll_d5_d2", + "univpll_d3_d4", + "syspll_d3_d4", + "univpll_d3_d8" +}; + +static const char * const scam_parents[] = { + "clk26m", + "syspll_d5_d2" +}; + +static const char * const disppwm_parents[] = { + "clk26m", + "univpll_d3_d4", + "osc_d2", + "osc_d4", + "osc_d16" +}; + +static const char * const usb_top_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d3_d4", + "univpll_d5_d2" +}; + + +static const char * const ssusb_top_xhci_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d3_d4", + "univpll_d5_d2" +}; + +static const char * const spm_parents[] = { + "clk26m", + "syspll_d2_d8" +}; + +static const char * const i2c_parents[] = { + "clk26m", + "syspll_d2_d8", + "univpll_d5_d2" +}; + +static const char * const scp_parents[] = { + "clk26m", + "univpll_d2_d8", + "syspll_d5", + "syspll_d2_d2", + "univpll_d2_d2", + "syspll_d3", + "univpll_d3" +}; + +static const char * const seninf_parents[] = { + "clk26m", + "univpll_d2_d2", + "univpll_d3_d2", + "univpll_d2_d4" +}; + +static const char * const dxcc_parents[] = { + "clk26m", + "syspll_d2_d2", + "syspll_d2_d4", + "syspll_d2_d8" +}; + +static const char * const aud_engen1_parents[] = { + "clk26m", + "apll1_d2", + "apll1_d4", + "apll1_d8" +}; + +static const char * const aud_engen2_parents[] = { + "clk26m", + "apll2_d2", + "apll2_d4", + "apll2_d8" +}; + +static const char * const faes_ufsfde_parents[] = { + "clk26m", + "syspll_d2", + "syspll_d2_d2", + "syspll_d3", + "syspll_d2_d4", + "univpll_d3" +}; + +static const char * const fufs_parents[] = { + "clk26m", + "syspll_d2_d4", + "syspll_d2_d8", + "syspll_d2_d16" +}; + +static const char * const aud_1_parents[] = { + "clk26m", + "apll1_ck" +}; + +static const char * const aud_2_parents[] = { + "clk26m", + "apll2_ck" +}; + +/* + * CRITICAL CLOCK: + * axi_sel is the main bus clock of whole SOC. + * spm_sel is the clock of the always-on co-processor. + */ +static const struct mtk_mux top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MUX_AXI, "axi_sel", + axi_parents, 0x40, + 0x44, 0x48, 0, 2, 7, 0x004, 0, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MM, "mm_sel", + mm_parents, 0x40, + 0x44, 0x48, 8, 3, 15, 0x004, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_IMG, "img_sel", + img_parents, 0x40, + 0x44, 0x48, 16, 3, 23, 0x004, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAM, "cam_sel", + cam_parents, 0x40, + 0x44, 0x48, 24, 4, 31, 0x004, 3), + /* CLK_CFG_1 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DSP, "dsp_sel", + dsp_parents, 0x50, + 0x54, 0x58, 0, 4, 7, 0x004, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DSP1, "dsp1_sel", + dsp1_parents, 0x50, + 0x54, 0x58, 8, 4, 15, 0x004, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DSP2, "dsp2_sel", + dsp2_parents, 0x50, + 0x54, 0x58, 16, 4, 23, 0x004, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_IPU_IF, "ipu_if_sel", + ipu_if_parents, 0x50, + 0x54, 0x58, 24, 4, 31, 0x004, 7), + /* CLK_CFG_2 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MFG, "mfg_sel", + mfg_parents, 0x60, + 0x64, 0x68, 0, 2, 7, 0x004, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_F52M_MFG, "f52m_mfg_sel", + f52m_mfg_parents, 0x60, + 0x64, 0x68, 8, 2, 15, 0x004, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG, "camtg_sel", + camtg_parents, 0x60, + 0x64, 0x68, 16, 3, 23, 0x004, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG2, "camtg2_sel", + camtg2_parents, 0x60, + 0x64, 0x68, 24, 3, 31, 0x004, 11), + /* CLK_CFG_3 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG3, "camtg3_sel", + camtg3_parents, 0x70, + 0x74, 0x78, 0, 3, 7, 0x004, 12), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG4, "camtg4_sel", + camtg4_parents, 0x70, + 0x74, 0x78, 8, 3, 15, 0x004, 13), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_UART, "uart_sel", + uart_parents, 0x70, + 0x74, 0x78, 16, 1, 23, 0x004, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SPI, "spi_sel", + spi_parents, 0x70, + 0x74, 0x78, 24, 2, 31, 0x004, 15), + /* CLK_CFG_4 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC50_0_HCLK, "msdc50_hclk_sel", + msdc50_hclk_parents, 0x80, + 0x84, 0x88, 0, 2, 7, 0x004, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC50_0, "msdc50_0_sel", + msdc50_0_parents, 0x80, + 0x84, 0x88, 8, 3, 15, 0x004, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC30_1, "msdc30_1_sel", + msdc30_1_parents, 0x80, + 0x84, 0x88, 16, 3, 23, 0x004, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC30_2, "msdc30_2_sel", + msdc30_2_parents, 0x80, + 0x84, 0x88, 24, 3, 31, 0x004, 19), + /* CLK_CFG_5 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUDIO, "audio_sel", + audio_parents, 0x90, + 0x94, 0x98, 0, 2, 7, 0x004, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_INTBUS, "aud_intbus_sel", + aud_intbus_parents, 0x90, + 0x94, 0x98, 8, 2, 15, 0x004, 21), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_PMICSPI, "pmicspi_sel", + pmicspi_parents, 0x90, + 0x94, 0x98, 16, 2, 23, 0x004, 22), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_FPWRAP_ULPOSC, "fpwrap_ulposc_sel", + fpwrap_ulposc_parents, 0x90, + 0x94, 0x98, 24, 2, 31, 0x004, 23), + /* CLK_CFG_6 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_ATB, "atb_sel", + atb_parents, 0xa0, + 0xa4, 0xa8, 0, 2, 7, 0x004, 24), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SSPM, "sspm_sel", + sspm_parents, 0xa0, + 0xa4, 0xa8, 8, 3, 15, 0x004, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DPI0, "dpi0_sel", + dpi0_parents, 0xa0, + 0xa4, 0xa8, 16, 4, 23, 0x004, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SCAM, "scam_sel", + scam_parents, 0xa0, + 0xa4, 0xa8, 24, 1, 31, 0x004, 27), + /* CLK_CFG_7 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DISP_PWM, "disppwm_sel", + disppwm_parents, 0xb0, + 0xb4, 0xb8, 0, 3, 7, 0x004, 28), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_USB_TOP, "usb_top_sel", + usb_top_parents, 0xb0, + 0xb4, 0xb8, 8, 2, 15, 0x004, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SSUSB_TOP_XHCI, "ssusb_top_xhci_sel", + ssusb_top_xhci_parents, 0xb0, + 0xb4, 0xb8, 16, 2, 23, 0x004, 30), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MUX_SPM, "spm_sel", + spm_parents, 0xb0, + 0xb4, 0xb8, 24, 1, 31, 0x008, 0, CLK_IS_CRITICAL), + /* CLK_CFG_8 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_I2C, "i2c_sel", + i2c_parents, 0xc0, + 0xc4, 0xc8, 0, 2, 7, 0x008, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SCP, "scp_sel", + scp_parents, 0xc0, + 0xc4, 0xc8, 8, 3, 15, 0x008, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SENINF, "seninf_sel", + seninf_parents, 0xc0, + 0xc4, 0xc8, 16, 2, 23, 0x008, 3), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DXCC, "dxcc_sel", + dxcc_parents, 0xc0, + 0xc4, 0xc8, 24, 2, 31, 0x008, 4), + /* CLK_CFG_9 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_ENG1, "aud_eng1_sel", + aud_engen1_parents, 0xd0, + 0xd4, 0xd8, 0, 2, 7, 0x008, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_ENG2, "aud_eng2_sel", + aud_engen2_parents, 0xd0, + 0xd4, 0xd8, 8, 2, 15, 0x008, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_FAES_UFSFDE, "faes_ufsfde_sel", + faes_ufsfde_parents, 0xd0, + 0xd4, 0xd8, 16, 3, 23, 0x008, 7), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_FUFS, "fufs_sel", + fufs_parents, 0xd0, + 0xd4, 0xd8, 24, 2, 31, 0x008, 8), + /* CLK_CFG_10 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_1, "aud_1_sel", + aud_1_parents, 0xe0, + 0xe4, 0xe8, 0, 1, 7, 0x008, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_2, "aud_2_sel", + aud_2_parents, 0xe0, + 0xe4, 0xe8, 8, 1, 15, 0x008, 10), +}; + +static const char * const apll_i2s0_parents[] = { + "aud_1_sel", + "aud_2_sel" +}; + +static const char * const apll_i2s1_parents[] = { + "aud_1_sel", + "aud_2_sel" +}; + +static const char * const apll_i2s2_parents[] = { + "aud_1_sel", + "aud_2_sel" +}; + +static const char * const apll_i2s3_parents[] = { + "aud_1_sel", + "aud_2_sel" +}; + +static const char * const apll_i2s4_parents[] = { + "aud_1_sel", + "aud_2_sel" +}; + +static const char * const apll_i2s5_parents[] = { + "aud_1_sel", + "aud_2_sel" +}; + +static struct mtk_composite top_aud_muxes[] = { + MUX(CLK_TOP_MUX_APLL_I2S0, "apll_i2s0_sel", apll_i2s0_parents, + 0x320, 8, 1), + MUX(CLK_TOP_MUX_APLL_I2S1, "apll_i2s1_sel", apll_i2s1_parents, + 0x320, 9, 1), + MUX(CLK_TOP_MUX_APLL_I2S2, "apll_i2s2_sel", apll_i2s2_parents, + 0x320, 10, 1), + MUX(CLK_TOP_MUX_APLL_I2S3, "apll_i2s3_sel", apll_i2s3_parents, + 0x320, 11, 1), + MUX(CLK_TOP_MUX_APLL_I2S4, "apll_i2s4_sel", apll_i2s4_parents, + 0x320, 12, 1), + MUX(CLK_TOP_MUX_APLL_I2S5, "apll_i2s5_sel", apll_i2s5_parents, + 0x328, 20, 1), +}; + +static const char * const mcu_mp0_parents[] = { + "clk26m", + "armpll_ll", + "armpll_div_pll1", + "armpll_div_pll2" +}; + +static const char * const mcu_mp2_parents[] = { + "clk26m", + "armpll_l", + "armpll_div_pll1", + "armpll_div_pll2" +}; + +static const char * const mcu_bus_parents[] = { + "clk26m", + "ccipll", + "armpll_div_pll1", + "armpll_div_pll2" +}; + +static struct mtk_composite mcu_muxes[] = { + /* mp0_pll_divider_cfg */ + MUX(CLK_MCU_MP0_SEL, "mcu_mp0_sel", mcu_mp0_parents, 0x7A0, 9, 2), + /* mp2_pll_divider_cfg */ + MUX(CLK_MCU_MP2_SEL, "mcu_mp2_sel", mcu_mp2_parents, 0x7A8, 9, 2), + /* bus_pll_divider_cfg */ + MUX(CLK_MCU_BUS_SEL, "mcu_bus_sel", mcu_bus_parents, 0x7C0, 9, 2), +}; + +static struct mtk_composite top_aud_divs[] = { + DIV_GATE(CLK_TOP_APLL12_DIV0, "apll12_div0", "apll_i2s0_sel", + 0x320, 2, 0x324, 8, 0), + DIV_GATE(CLK_TOP_APLL12_DIV1, "apll12_div1", "apll_i2s1_sel", + 0x320, 3, 0x324, 8, 8), + DIV_GATE(CLK_TOP_APLL12_DIV2, "apll12_div2", "apll_i2s2_sel", + 0x320, 4, 0x324, 8, 16), + DIV_GATE(CLK_TOP_APLL12_DIV3, "apll12_div3", "apll_i2s3_sel", + 0x320, 5, 0x324, 8, 24), + DIV_GATE(CLK_TOP_APLL12_DIV4, "apll12_div4", "apll_i2s4_sel", + 0x320, 6, 0x328, 8, 0), + DIV_GATE(CLK_TOP_APLL12_DIVB, "apll12_divb", "apll12_div4", + 0x320, 7, 0x328, 8, 8), +}; + +static const struct mtk_gate_regs top_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x104, + .sta_ofs = 0x104, +}; + +#define GATE_TOP(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate top_clks[] = { + /* TOP */ + GATE_TOP(CLK_TOP_ARMPLL_DIV_PLL1, "armpll_div_pll1", "mainpll", 4), + GATE_TOP(CLK_TOP_ARMPLL_DIV_PLL2, "armpll_div_pll2", "univpll", 5), +}; + +static const struct mtk_gate_regs infra0_cg_regs = { + .set_ofs = 0x80, + .clr_ofs = 0x84, + .sta_ofs = 0x90, +}; + +static const struct mtk_gate_regs infra1_cg_regs = { + .set_ofs = 0x88, + .clr_ofs = 0x8c, + .sta_ofs = 0x94, +}; + +static const struct mtk_gate_regs infra2_cg_regs = { + .set_ofs = 0xa4, + .clr_ofs = 0xa8, + .sta_ofs = 0xac, +}; + +static const struct mtk_gate_regs infra3_cg_regs = { + .set_ofs = 0xc0, + .clr_ofs = 0xc4, + .sta_ofs = 0xc8, +}; + +#define GATE_INFRA0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra0_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +#define GATE_INFRA1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra1_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +#define GATE_INFRA2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra2_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +#define GATE_INFRA3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra3_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate infra_clks[] = { + /* INFRA0 */ + GATE_INFRA0(CLK_INFRA_PMIC_TMR, "infra_pmic_tmr", + "axi_sel", 0), + GATE_INFRA0(CLK_INFRA_PMIC_AP, "infra_pmic_ap", + "axi_sel", 1), + GATE_INFRA0(CLK_INFRA_PMIC_MD, "infra_pmic_md", + "axi_sel", 2), + GATE_INFRA0(CLK_INFRA_PMIC_CONN, "infra_pmic_conn", + "axi_sel", 3), + GATE_INFRA0(CLK_INFRA_SCPSYS, "infra_scp", + "scp_sel", 4), + GATE_INFRA0(CLK_INFRA_SEJ, "infra_sej", + "f_f26m_ck", 5), + GATE_INFRA0(CLK_INFRA_APXGPT, "infra_apxgpt", + "axi_sel", 6), + GATE_INFRA0(CLK_INFRA_ICUSB, "infra_icusb", + "axi_sel", 8), + GATE_INFRA0(CLK_INFRA_GCE, "infra_gce", + "axi_sel", 9), + GATE_INFRA0(CLK_INFRA_THERM, "infra_therm", + "axi_sel", 10), + GATE_INFRA0(CLK_INFRA_I2C0, "infra_i2c0", + "i2c_sel", 11), + GATE_INFRA0(CLK_INFRA_I2C1, "infra_i2c1", + "i2c_sel", 12), + GATE_INFRA0(CLK_INFRA_I2C2, "infra_i2c2", + "i2c_sel", 13), + GATE_INFRA0(CLK_INFRA_I2C3, "infra_i2c3", + "i2c_sel", 14), + GATE_INFRA0(CLK_INFRA_PWM_HCLK, "infra_pwm_hclk", + "axi_sel", 15), + GATE_INFRA0(CLK_INFRA_PWM1, "infra_pwm1", + "i2c_sel", 16), + GATE_INFRA0(CLK_INFRA_PWM2, "infra_pwm2", + "i2c_sel", 17), + GATE_INFRA0(CLK_INFRA_PWM3, "infra_pwm3", + "i2c_sel", 18), + GATE_INFRA0(CLK_INFRA_PWM4, "infra_pwm4", + "i2c_sel", 19), + GATE_INFRA0(CLK_INFRA_PWM, "infra_pwm", + "i2c_sel", 21), + GATE_INFRA0(CLK_INFRA_UART0, "infra_uart0", + "uart_sel", 22), + GATE_INFRA0(CLK_INFRA_UART1, "infra_uart1", + "uart_sel", 23), + GATE_INFRA0(CLK_INFRA_UART2, "infra_uart2", + "uart_sel", 24), + GATE_INFRA0(CLK_INFRA_UART3, "infra_uart3", + "uart_sel", 25), + GATE_INFRA0(CLK_INFRA_GCE_26M, "infra_gce_26m", + "axi_sel", 27), + GATE_INFRA0(CLK_INFRA_CQ_DMA_FPC, "infra_cqdma_fpc", + "axi_sel", 28), + GATE_INFRA0(CLK_INFRA_BTIF, "infra_btif", + "axi_sel", 31), + /* INFRA1 */ + GATE_INFRA1(CLK_INFRA_SPI0, "infra_spi0", + "spi_sel", 1), + GATE_INFRA1(CLK_INFRA_MSDC0, "infra_msdc0", + "msdc50_hclk_sel", 2), + GATE_INFRA1(CLK_INFRA_MSDC1, "infra_msdc1", + "axi_sel", 4), + GATE_INFRA1(CLK_INFRA_MSDC2, "infra_msdc2", + "axi_sel", 5), + GATE_INFRA1(CLK_INFRA_MSDC0_SCK, "infra_msdc0_sck", + "msdc50_0_sel", 6), + GATE_INFRA1(CLK_INFRA_DVFSRC, "infra_dvfsrc", + "f_f26m_ck", 7), + GATE_INFRA1(CLK_INFRA_GCPU, "infra_gcpu", + "axi_sel", 8), + GATE_INFRA1(CLK_INFRA_TRNG, "infra_trng", + "axi_sel", 9), + GATE_INFRA1(CLK_INFRA_AUXADC, "infra_auxadc", + "f_f26m_ck", 10), + GATE_INFRA1(CLK_INFRA_CPUM, "infra_cpum", + "axi_sel", 11), + GATE_INFRA1(CLK_INFRA_CCIF1_AP, "infra_ccif1_ap", + "axi_sel", 12), + GATE_INFRA1(CLK_INFRA_CCIF1_MD, "infra_ccif1_md", + "axi_sel", 13), + GATE_INFRA1(CLK_INFRA_AUXADC_MD, "infra_auxadc_md", + "f_f26m_ck", 14), + GATE_INFRA1(CLK_INFRA_MSDC1_SCK, "infra_msdc1_sck", + "msdc30_1_sel", 16), + GATE_INFRA1(CLK_INFRA_MSDC2_SCK, "infra_msdc2_sck", + "msdc30_2_sel", 17), + GATE_INFRA1(CLK_INFRA_AP_DMA, "infra_apdma", + "axi_sel", 18), + GATE_INFRA1(CLK_INFRA_XIU, "infra_xiu", + "axi_sel", 19), + GATE_INFRA1(CLK_INFRA_DEVICE_APC, "infra_device_apc", + "axi_sel", 20), + GATE_INFRA1(CLK_INFRA_CCIF_AP, "infra_ccif_ap", + "axi_sel", 23), + GATE_INFRA1(CLK_INFRA_DEBUGSYS, "infra_debugsys", + "axi_sel", 24), + GATE_INFRA1(CLK_INFRA_AUDIO, "infra_audio", + "axi_sel", 25), + GATE_INFRA1(CLK_INFRA_CCIF_MD, "infra_ccif_md", + "axi_sel", 26), + GATE_INFRA1(CLK_INFRA_DXCC_SEC_CORE, "infra_dxcc_sec_core", + "dxcc_sel", 27), + GATE_INFRA1(CLK_INFRA_DXCC_AO, "infra_dxcc_ao", + "dxcc_sel", 28), + GATE_INFRA1(CLK_INFRA_DEVMPU_BCLK, "infra_devmpu_bclk", + "axi_sel", 30), + GATE_INFRA1(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", + "f_f26m_ck", 31), + /* INFRA2 */ + GATE_INFRA2(CLK_INFRA_IRTX, "infra_irtx", + "f_f26m_ck", 0), + GATE_INFRA2(CLK_INFRA_USB, "infra_usb", + "usb_top_sel", 1), + GATE_INFRA2(CLK_INFRA_DISP_PWM, "infra_disppwm", + "axi_sel", 2), + GATE_INFRA2(CLK_INFRA_CLDMA_BCLK, "infra_cldma_bclk", + "axi_sel", 3), + GATE_INFRA2(CLK_INFRA_AUDIO_26M_BCLK, "infra_audio_26m_bclk", + "f_f26m_ck", 4), + GATE_INFRA2(CLK_INFRA_SPI1, "infra_spi1", + "spi_sel", 6), + GATE_INFRA2(CLK_INFRA_I2C4, "infra_i2c4", + "i2c_sel", 7), + GATE_INFRA2(CLK_INFRA_MODEM_TEMP_SHARE, "infra_md_tmp_share", + "f_f26m_ck", 8), + GATE_INFRA2(CLK_INFRA_SPI2, "infra_spi2", + "spi_sel", 9), + GATE_INFRA2(CLK_INFRA_SPI3, "infra_spi3", + "spi_sel", 10), + GATE_INFRA2(CLK_INFRA_UNIPRO_SCK, "infra_unipro_sck", + "ssusb_top_xhci_sel", 11), + GATE_INFRA2(CLK_INFRA_UNIPRO_TICK, "infra_unipro_tick", + "fufs_sel", 12), + GATE_INFRA2(CLK_INFRA_UFS_MP_SAP_BCLK, "infra_ufs_mp_sap_bck", + "fufs_sel", 13), + GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk", + "axi_sel", 14), + GATE_INFRA2(CLK_INFRA_SSPM, "infra_sspm", + "sspm_sel", 15), + GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist", + "axi_sel", 16), + GATE_INFRA2(CLK_INFRA_SSPM_BUS_HCLK, "infra_sspm_bus_hclk", + "axi_sel", 17), + GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5", + "i2c_sel", 18), + GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter", + "i2c_sel", 19), + GATE_INFRA2(CLK_INFRA_I2C5_IMM, "infra_i2c5_imm", + "i2c_sel", 20), + GATE_INFRA2(CLK_INFRA_I2C1_ARBITER, "infra_i2c1_arbiter", + "i2c_sel", 21), + GATE_INFRA2(CLK_INFRA_I2C1_IMM, "infra_i2c1_imm", + "i2c_sel", 22), + GATE_INFRA2(CLK_INFRA_I2C2_ARBITER, "infra_i2c2_arbiter", + "i2c_sel", 23), + GATE_INFRA2(CLK_INFRA_I2C2_IMM, "infra_i2c2_imm", + "i2c_sel", 24), + GATE_INFRA2(CLK_INFRA_SPI4, "infra_spi4", + "spi_sel", 25), + GATE_INFRA2(CLK_INFRA_SPI5, "infra_spi5", + "spi_sel", 26), + GATE_INFRA2(CLK_INFRA_CQ_DMA, "infra_cqdma", + "axi_sel", 27), + GATE_INFRA2(CLK_INFRA_UFS, "infra_ufs", + "fufs_sel", 28), + GATE_INFRA2(CLK_INFRA_AES_UFSFDE, "infra_aes_ufsfde", + "faes_ufsfde_sel", 29), + GATE_INFRA2(CLK_INFRA_UFS_TICK, "infra_ufs_tick", + "fufs_sel", 30), + /* INFRA3 */ + GATE_INFRA3(CLK_INFRA_MSDC0_SELF, "infra_msdc0_self", + "msdc50_0_sel", 0), + GATE_INFRA3(CLK_INFRA_MSDC1_SELF, "infra_msdc1_self", + "msdc50_0_sel", 1), + GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self", + "msdc50_0_sel", 2), + GATE_INFRA3(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self", + "f_f26m_ck", 3), + GATE_INFRA3(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self", + "f_f26m_ck", 4), + GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi", + "axi_sel", 5), + GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6", + "i2c_sel", 6), + GATE_INFRA3(CLK_INFRA_AP_MSDC0, "infra_ap_msdc0", + "msdc50_hclk_sel", 7), + GATE_INFRA3(CLK_INFRA_MD_MSDC0, "infra_md_msdc0", + "msdc50_hclk_sel", 8), + GATE_INFRA3(CLK_INFRA_CCIF2_AP, "infra_ccif2_ap", + "axi_sel", 16), + GATE_INFRA3(CLK_INFRA_CCIF2_MD, "infra_ccif2_md", + "axi_sel", 17), + GATE_INFRA3(CLK_INFRA_CCIF3_AP, "infra_ccif3_ap", + "axi_sel", 18), + GATE_INFRA3(CLK_INFRA_CCIF3_MD, "infra_ccif3_md", + "axi_sel", 19), + GATE_INFRA3(CLK_INFRA_SEJ_F13M, "infra_sej_f13m", + "f_f26m_ck", 20), + GATE_INFRA3(CLK_INFRA_AES_BCLK, "infra_aes_bclk", + "axi_sel", 21), + GATE_INFRA3(CLK_INFRA_I2C7, "infra_i2c7", + "i2c_sel", 22), + GATE_INFRA3(CLK_INFRA_I2C8, "infra_i2c8", + "i2c_sel", 23), + GATE_INFRA3(CLK_INFRA_FBIST2FPC, "infra_fbist2fpc", + "msdc50_0_sel", 24), +}; + +static const struct mtk_gate_regs apmixed_cg_regs = { + .set_ofs = 0x20, + .clr_ofs = 0x20, + .sta_ofs = 0x20, +}; + +#define GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &apmixed_cg_regs, \ + _shift, &mtk_clk_gate_ops_no_setclr_inv, _flags) + +#define GATE_APMIXED(_id, _name, _parent, _shift) \ + GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, 0) + +/* + * CRITICAL CLOCK: + * apmixed_appll26m is the toppest clock gate of all PLLs. + */ +static const struct mtk_gate apmixed_clks[] = { + /* AUDIO0 */ + GATE_APMIXED(CLK_APMIXED_SSUSB_26M, "apmixed_ssusb26m", + "f_f26m_ck", 4), + GATE_APMIXED_FLAGS(CLK_APMIXED_APPLL_26M, "apmixed_appll26m", + "f_f26m_ck", 5, CLK_IS_CRITICAL), + GATE_APMIXED(CLK_APMIXED_MIPIC0_26M, "apmixed_mipic026m", + "f_f26m_ck", 6), + GATE_APMIXED(CLK_APMIXED_MDPLLGP_26M, "apmixed_mdpll26m", + "f_f26m_ck", 7), + GATE_APMIXED(CLK_APMIXED_MMSYS_26M, "apmixed_mmsys26m", + "f_f26m_ck", 8), + GATE_APMIXED(CLK_APMIXED_UFS_26M, "apmixed_ufs26m", + "f_f26m_ck", 9), + GATE_APMIXED(CLK_APMIXED_MIPIC1_26M, "apmixed_mipic126m", + "f_f26m_ck", 11), + GATE_APMIXED(CLK_APMIXED_MEMPLL_26M, "apmixed_mempll26m", + "f_f26m_ck", 13), + GATE_APMIXED(CLK_APMIXED_CLKSQ_LVPLL_26M, "apmixed_lvpll26m", + "f_f26m_ck", 14), + GATE_APMIXED(CLK_APMIXED_MIPID0_26M, "apmixed_mipid026m", + "f_f26m_ck", 16), + GATE_APMIXED(CLK_APMIXED_MIPID1_26M, "apmixed_mipid126m", + "f_f26m_ck", 17), +}; + +#define MT8183_PLL_FMAX (3800UL * MHZ) +#define MT8183_PLL_FMIN (1500UL * MHZ) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg, _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8183_PLL_FMAX, \ + .fmin = MT8183_PLL_FMIN, \ + .pcwbits = _pcwbits, \ + .pcwibits = _pcwibits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg, NULL) + +static const struct mtk_pll_div_table armpll_div_table[] = { + { .div = 0, .freq = MT8183_PLL_FMAX }, + { .div = 1, .freq = 1500 * MHZ }, + { .div = 2, .freq = 750 * MHZ }, + { .div = 3, .freq = 375 * MHZ }, + { .div = 4, .freq = 187500000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_div_table mfgpll_div_table[] = { + { .div = 0, .freq = MT8183_PLL_FMAX }, + { .div = 1, .freq = 1600 * MHZ }, + { .div = 2, .freq = 800 * MHZ }, + { .div = 3, .freq = 400 * MHZ }, + { .div = 4, .freq = 200 * MHZ }, + { } /* sentinel */ +}; + +static const struct mtk_pll_data plls[] = { + PLL_B(CLK_APMIXED_ARMPLL_LL, "armpll_ll", 0x0200, 0x020C, 0x00000001, + HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0204, 24, 0x0, 0x0, 0, + 0x0204, 0, 0, armpll_div_table), + PLL_B(CLK_APMIXED_ARMPLL_L, "armpll_l", 0x0210, 0x021C, 0x00000001, + HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0214, 24, 0x0, 0x0, 0, + 0x0214, 0, 0, armpll_div_table), + PLL(CLK_APMIXED_CCIPLL, "ccipll", 0x0290, 0x029C, 0x00000001, + HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0294, 24, 0x0, 0x0, 0, + 0x0294, 0, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0220, 0x022C, 0x00000001, + HAVE_RST_BAR, BIT(24), 22, 8, 0x0224, 24, 0x0, 0x0, 0, + 0x0224, 0, 0), + PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0230, 0x023C, 0x00000001, + HAVE_RST_BAR, BIT(24), 22, 8, 0x0234, 24, 0x0, 0x0, 0, + 0x0234, 0, 0), + PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0240, 0x024C, 0x00000001, + 0, 0, 22, 8, 0x0244, 24, 0x0, 0x0, 0, 0x0244, 0, 0, + mfgpll_div_table), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0250, 0x025C, 0x00000001, + 0, 0, 22, 8, 0x0254, 24, 0x0, 0x0, 0, 0x0254, 0, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0260, 0x026C, 0x00000001, + 0, 0, 22, 8, 0x0264, 24, 0x0, 0x0, 0, 0x0264, 0, 0), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0270, 0x027C, 0x00000001, + HAVE_RST_BAR, BIT(23), 22, 8, 0x0274, 24, 0x0, 0x0, 0, + 0x0274, 0, 0), + PLL(CLK_APMIXED_APLL1, "apll1", 0x02A0, 0x02B0, 0x00000001, + 0, 0, 32, 8, 0x02A0, 1, 0x02A8, 0x0014, 0, 0x02A4, 0, 0x02A0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x02b4, 0x02c4, 0x00000001, + 0, 0, 32, 8, 0x02B4, 1, 0x02BC, 0x0014, 1, 0x02B8, 0, 0x02B4), +}; + +static int clk_mt8183_apmixed_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + + mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static int clk_mt8183_top_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + void __iomem *base; + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); + + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); + + mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), + node, &mt8183_clk_lock, clk_data); + + mtk_clk_register_composites(top_aud_muxes, ARRAY_SIZE(top_aud_muxes), + base, &mt8183_clk_lock, clk_data); + + mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), + base, &mt8183_clk_lock, clk_data); + + mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static int clk_mt8183_infra_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); + + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static int clk_mt8183_mcu_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + void __iomem *base; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK); + + mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base, + &mt8183_clk_lock, clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt8183[] = { + { + .compatible = "mediatek,mt8183-apmixedsys", + .data = clk_mt8183_apmixed_probe, + }, { + .compatible = "mediatek,mt8183-topckgen", + .data = clk_mt8183_top_probe, + }, { + .compatible = "mediatek,mt8183-infracfg", + .data = clk_mt8183_infra_probe, + }, { + .compatible = "mediatek,mt8183-mcucfg", + .data = clk_mt8183_mcu_probe, + }, { + /* sentinel */ + } +}; + +static int clk_mt8183_probe(struct platform_device *pdev) +{ + int (*clk_probe)(struct platform_device *pdev); + int r; + + clk_probe = of_device_get_match_data(&pdev->dev); + if (!clk_probe) + return -EINVAL; + + r = clk_probe(pdev); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt8183_drv = { + .probe = clk_mt8183_probe, + .driver = { + .name = "clk-mt8183", + .of_match_table = of_match_clk_mt8183, + }, +}; + +static int __init clk_mt8183_init(void) +{ + return platform_driver_register(&clk_mt8183_drv); +} + +arch_initcall(clk_mt8183_init); diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c new file mode 100644 index 000000000000..26fe43cc9ea2 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8516.c @@ -0,0 +1,815 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: James Liao <jamesjj.liao@mediatek.com> + * Fabien Parent <fparent@baylibre.com> + */ + +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/mfd/syscon.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt8516-clk.h> + +static DEFINE_SPINLOCK(mt8516_clk_lock); + +static const struct mtk_fixed_clk fixed_clks[] __initconst = { + FIXED_CLK(CLK_TOP_CLK_NULL, "clk_null", NULL, 0), + FIXED_CLK(CLK_TOP_I2S_INFRA_BCK, "i2s_infra_bck", "clk_null", 26000000), + FIXED_CLK(CLK_TOP_MEMPLL, "mempll", "clk26m", 800000000), +}; + +static const struct mtk_fixed_factor top_divs[] __initconst = { + FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "mempll", 1, 1), + FACTOR(CLK_TOP_MAINPLL_D2, "mainpll_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D8, "mainpll_d8", "mainpll", 1, 8), + FACTOR(CLK_TOP_MAINPLL_D16, "mainpll_d16", "mainpll", 1, 16), + FACTOR(CLK_TOP_MAINPLL_D11, "mainpll_d11", "mainpll", 1, 11), + FACTOR(CLK_TOP_MAINPLL_D22, "mainpll_d22", "mainpll", 1, 22), + FACTOR(CLK_TOP_MAINPLL_D3, "mainpll_d3", "mainpll", 1, 3), + FACTOR(CLK_TOP_MAINPLL_D6, "mainpll_d6", "mainpll", 1, 6), + FACTOR(CLK_TOP_MAINPLL_D12, "mainpll_d12", "mainpll", 1, 12), + FACTOR(CLK_TOP_MAINPLL_D5, "mainpll_d5", "mainpll", 1, 5), + FACTOR(CLK_TOP_MAINPLL_D10, "mainpll_d10", "mainpll", 1, 10), + FACTOR(CLK_TOP_MAINPLL_D20, "mainpll_d20", "mainpll", 1, 20), + FACTOR(CLK_TOP_MAINPLL_D40, "mainpll_d40", "mainpll", 1, 40), + FACTOR(CLK_TOP_MAINPLL_D7, "mainpll_d7", "mainpll", 1, 7), + FACTOR(CLK_TOP_MAINPLL_D14, "mainpll_d14", "mainpll", 1, 14), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D4, "univpll_d4", "univpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D8, "univpll_d8", "univpll", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D16, "univpll_d16", "univpll", 1, 16), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3), + FACTOR(CLK_TOP_UNIVPLL_D6, "univpll_d6", "univpll", 1, 6), + FACTOR(CLK_TOP_UNIVPLL_D12, "univpll_d12", "univpll", 1, 12), + FACTOR(CLK_TOP_UNIVPLL_D24, "univpll_d24", "univpll", 1, 24), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIVPLL_D20, "univpll_d20", "univpll", 1, 20), + FACTOR(CLK_TOP_MMPLL380M, "mmpll380m", "mmpll", 1, 1), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), + FACTOR(CLK_TOP_MMPLL_200M, "mmpll_200m", "mmpll", 1, 3), + FACTOR(CLK_TOP_USB_PHY48M, "usb_phy48m_ck", "univpll", 1, 26), + FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1), + FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1_ck", 1, 2), + FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "rg_apll1_d2_en", 1, 2), + FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "rg_apll1_d4_en", 1, 2), + FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1), + FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2_ck", 1, 2), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "rg_apll2_d2_en", 1, 2), + FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "rg_apll2_d4_en", 1, 2), + FACTOR(CLK_TOP_CLK26M, "clk26m_ck", "clk26m", 1, 1), + FACTOR(CLK_TOP_CLK26M_D2, "clk26m_d2", "clk26m", 1, 2), + FACTOR(CLK_TOP_AHB_INFRA_D2, "ahb_infra_d2", "ahb_infra_sel", 1, 2), + FACTOR(CLK_TOP_NFI1X, "nfi1x_ck", "nfi2x_pad_sel", 1, 2), + FACTOR(CLK_TOP_ETH_D2, "eth_d2_ck", "eth_sel", 1, 2), +}; + +static const char * const uart0_parents[] __initconst = { + "clk26m_ck", + "univpll_d24" +}; + +static const char * const ahb_infra_parents[] __initconst = { + "clk_null", + "clk26m_ck", + "mainpll_d11", + "clk_null", + "mainpll_d12", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "mainpll_d10" +}; + +static const char * const msdc0_parents[] __initconst = { + "clk26m_ck", + "univpll_d6", + "mainpll_d8", + "univpll_d8", + "mainpll_d16", + "mmpll_200m", + "mainpll_d12", + "mmpll_d2" +}; + +static const char * const uart1_parents[] __initconst = { + "clk26m_ck", + "univpll_d24" +}; + +static const char * const msdc1_parents[] __initconst = { + "clk26m_ck", + "univpll_d6", + "mainpll_d8", + "univpll_d8", + "mainpll_d16", + "mmpll_200m", + "mainpll_d12", + "mmpll_d2" +}; + +static const char * const pmicspi_parents[] __initconst = { + "univpll_d20", + "usb_phy48m_ck", + "univpll_d16", + "clk26m_ck" +}; + +static const char * const qaxi_aud26m_parents[] __initconst = { + "clk26m_ck", + "ahb_infra_sel" +}; + +static const char * const aud_intbus_parents[] __initconst = { + "clk_null", + "clk26m_ck", + "mainpll_d22", + "clk_null", + "mainpll_d11" +}; + +static const char * const nfi2x_pad_parents[] __initconst = { + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk26m_ck", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "mainpll_d12", + "mainpll_d8", + "clk_null", + "mainpll_d6", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "mainpll_d4", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "mainpll_d10", + "mainpll_d7", + "clk_null", + "mainpll_d5" +}; + +static const char * const nfi1x_pad_parents[] __initconst = { + "ahb_infra_sel", + "nfi1x_ck" +}; + +static const char * const ddrphycfg_parents[] __initconst = { + "clk26m_ck", + "mainpll_d16" +}; + +static const char * const usb_78m_parents[] __initconst = { + "clk_null", + "clk26m_ck", + "univpll_d16", + "clk_null", + "mainpll_d20" +}; + +static const char * const spinor_parents[] __initconst = { + "clk26m_d2", + "clk26m_ck", + "mainpll_d40", + "univpll_d24", + "univpll_d20", + "mainpll_d20", + "mainpll_d16", + "univpll_d12" +}; + +static const char * const msdc2_parents[] __initconst = { + "clk26m_ck", + "univpll_d6", + "mainpll_d8", + "univpll_d8", + "mainpll_d16", + "mmpll_200m", + "mainpll_d12", + "mmpll_d2" +}; + +static const char * const eth_parents[] __initconst = { + "clk26m_ck", + "mainpll_d40", + "univpll_d24", + "univpll_d20", + "mainpll_d20" +}; + +static const char * const aud1_parents[] __initconst = { + "clk26m_ck", + "apll1_ck" +}; + +static const char * const aud2_parents[] __initconst = { + "clk26m_ck", + "apll2_ck" +}; + +static const char * const aud_engen1_parents[] __initconst = { + "clk26m_ck", + "rg_apll1_d2_en", + "rg_apll1_d4_en", + "rg_apll1_d8_en" +}; + +static const char * const aud_engen2_parents[] __initconst = { + "clk26m_ck", + "rg_apll2_d2_en", + "rg_apll2_d4_en", + "rg_apll2_d8_en" +}; + +static const char * const i2c_parents[] __initconst = { + "clk26m_ck", + "univpll_d20", + "univpll_d16", + "univpll_d12" +}; + +static const char * const aud_i2s0_m_parents[] __initconst = { + "rg_aud1", + "rg_aud2" +}; + +static const char * const pwm_parents[] __initconst = { + "clk26m_ck", + "univpll_d12" +}; + +static const char * const spi_parents[] __initconst = { + "clk26m_ck", + "univpll_d12", + "univpll_d8", + "univpll_d6" +}; + +static const char * const aud_spdifin_parents[] __initconst = { + "clk26m_ck", + "univpll_d2" +}; + +static const char * const uart2_parents[] __initconst = { + "clk26m_ck", + "univpll_d24" +}; + +static const char * const bsi_parents[] __initconst = { + "clk26m_ck", + "mainpll_d10", + "mainpll_d12", + "mainpll_d20" +}; + +static const char * const dbg_atclk_parents[] __initconst = { + "clk_null", + "clk26m_ck", + "mainpll_d5", + "clk_null", + "univpll_d5" +}; + +static const char * const csw_nfiecc_parents[] __initconst = { + "clk_null", + "mainpll_d7", + "mainpll_d6", + "clk_null", + "mainpll_d5" +}; + +static const char * const nfiecc_parents[] __initconst = { + "clk_null", + "nfi2x_pad_sel", + "mainpll_d4", + "clk_null", + "csw_nfiecc_sel" +}; + +static struct mtk_composite top_muxes[] __initdata = { + /* CLK_MUX_SEL0 */ + MUX(CLK_TOP_UART0_SEL, "uart0_sel", uart0_parents, + 0x000, 0, 1), + MUX(CLK_TOP_AHB_INFRA_SEL, "ahb_infra_sel", ahb_infra_parents, + 0x000, 4, 4), + MUX(CLK_TOP_MSDC0_SEL, "msdc0_sel", msdc0_parents, + 0x000, 11, 3), + MUX(CLK_TOP_UART1_SEL, "uart1_sel", uart1_parents, + 0x000, 19, 1), + MUX(CLK_TOP_MSDC1_SEL, "msdc1_sel", msdc1_parents, + 0x000, 20, 3), + MUX(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, + 0x000, 24, 2), + MUX(CLK_TOP_QAXI_AUD26M_SEL, "qaxi_aud26m_sel", qaxi_aud26m_parents, + 0x000, 26, 1), + MUX(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, + 0x000, 27, 3), + /* CLK_MUX_SEL1 */ + MUX(CLK_TOP_NFI2X_PAD_SEL, "nfi2x_pad_sel", nfi2x_pad_parents, + 0x004, 0, 7), + MUX(CLK_TOP_NFI1X_PAD_SEL, "nfi1x_pad_sel", nfi1x_pad_parents, + 0x004, 7, 1), + MUX(CLK_TOP_USB_78M_SEL, "usb_78m_sel", usb_78m_parents, + 0x004, 20, 3), + /* CLK_MUX_SEL8 */ + MUX(CLK_TOP_SPINOR_SEL, "spinor_sel", spinor_parents, + 0x040, 0, 3), + MUX(CLK_TOP_MSDC2_SEL, "msdc2_sel", msdc2_parents, + 0x040, 3, 3), + MUX(CLK_TOP_ETH_SEL, "eth_sel", eth_parents, + 0x040, 6, 3), + MUX(CLK_TOP_AUD1_SEL, "aud1_sel", aud1_parents, + 0x040, 22, 1), + MUX(CLK_TOP_AUD2_SEL, "aud2_sel", aud2_parents, + 0x040, 23, 1), + MUX(CLK_TOP_AUD_ENGEN1_SEL, "aud_engen1_sel", aud_engen1_parents, + 0x040, 24, 2), + MUX(CLK_TOP_AUD_ENGEN2_SEL, "aud_engen2_sel", aud_engen2_parents, + 0x040, 26, 2), + MUX(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, + 0x040, 28, 2), + /* CLK_SEL_9 */ + MUX(CLK_TOP_AUD_I2S0_M_SEL, "aud_i2s0_m_sel", aud_i2s0_m_parents, + 0x044, 12, 1), + MUX(CLK_TOP_AUD_I2S1_M_SEL, "aud_i2s1_m_sel", aud_i2s0_m_parents, + 0x044, 13, 1), + MUX(CLK_TOP_AUD_I2S2_M_SEL, "aud_i2s2_m_sel", aud_i2s0_m_parents, + 0x044, 14, 1), + MUX(CLK_TOP_AUD_I2S3_M_SEL, "aud_i2s3_m_sel", aud_i2s0_m_parents, + 0x044, 15, 1), + MUX(CLK_TOP_AUD_I2S4_M_SEL, "aud_i2s4_m_sel", aud_i2s0_m_parents, + 0x044, 16, 1), + MUX(CLK_TOP_AUD_I2S5_M_SEL, "aud_i2s5_m_sel", aud_i2s0_m_parents, + 0x044, 17, 1), + MUX(CLK_TOP_AUD_SPDIF_B_SEL, "aud_spdif_b_sel", aud_i2s0_m_parents, + 0x044, 18, 1), + /* CLK_MUX_SEL13 */ + MUX(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, + 0x07c, 0, 1), + MUX(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, + 0x07c, 1, 2), + MUX(CLK_TOP_AUD_SPDIFIN_SEL, "aud_spdifin_sel", aud_spdifin_parents, + 0x07c, 3, 1), + MUX(CLK_TOP_UART2_SEL, "uart2_sel", uart2_parents, + 0x07c, 4, 1), + MUX(CLK_TOP_BSI_SEL, "bsi_sel", bsi_parents, + 0x07c, 5, 2), + MUX(CLK_TOP_DBG_ATCLK_SEL, "dbg_atclk_sel", dbg_atclk_parents, + 0x07c, 7, 3), + MUX(CLK_TOP_CSW_NFIECC_SEL, "csw_nfiecc_sel", csw_nfiecc_parents, + 0x07c, 10, 3), + MUX(CLK_TOP_NFIECC_SEL, "nfiecc_sel", nfiecc_parents, + 0x07c, 13, 3), +}; + +static const char * const ifr_mux1_parents[] __initconst = { + "clk26m_ck", + "armpll", + "univpll", + "mainpll_d2" +}; + +static const char * const ifr_eth_25m_parents[] __initconst = { + "eth_d2_ck", + "rg_eth" +}; + +static const char * const ifr_i2c0_parents[] __initconst = { + "ahb_infra_d2", + "rg_i2c" +}; + +static const struct mtk_composite ifr_muxes[] __initconst = { + MUX(CLK_IFR_MUX1_SEL, "ifr_mux1_sel", ifr_mux1_parents, 0x000, + 2, 2), + MUX(CLK_IFR_ETH_25M_SEL, "ifr_eth_25m_sel", ifr_eth_25m_parents, 0x080, + 0, 1), + MUX(CLK_IFR_I2C0_SEL, "ifr_i2c0_sel", ifr_i2c0_parents, 0x080, + 1, 1), + MUX(CLK_IFR_I2C1_SEL, "ifr_i2c1_sel", ifr_i2c0_parents, 0x080, + 2, 1), + MUX(CLK_IFR_I2C2_SEL, "ifr_i2c2_sel", ifr_i2c0_parents, 0x080, + 3, 1), +}; + +#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .div_reg = _reg, \ + .div_shift = _shift, \ + .div_width = _width, \ +} + +static const struct mtk_clk_divider top_adj_divs[] = { + DIV_ADJ(CLK_TOP_APLL12_CK_DIV0, "apll12_ck_div0", "aud_i2s0_m_sel", + 0x0048, 0, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV1, "apll12_ck_div1", "aud_i2s1_m_sel", + 0x0048, 8, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV2, "apll12_ck_div2", "aud_i2s2_m_sel", + 0x0048, 16, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV3, "apll12_ck_div3", "aud_i2s3_m_sel", + 0x0048, 24, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV4, "apll12_ck_div4", "aud_i2s4_m_sel", + 0x004c, 0, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV4B, "apll12_ck_div4b", "apll12_div4", + 0x004c, 8, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV5, "apll12_ck_div5", "aud_i2s5_m_sel", + 0x004c, 16, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV5B, "apll12_ck_div5b", "apll12_div5", + 0x004c, 24, 8), + DIV_ADJ(CLK_TOP_APLL12_CK_DIV6, "apll12_ck_div6", "aud_spdif_b_sel", + 0x0078, 0, 8), +}; + +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x54, + .clr_ofs = 0x84, + .sta_ofs = 0x24, +}; + +static const struct mtk_gate_regs top2_cg_regs = { + .set_ofs = 0x6c, + .clr_ofs = 0x9c, + .sta_ofs = 0x3c, +}; + +static const struct mtk_gate_regs top3_cg_regs = { + .set_ofs = 0xa0, + .clr_ofs = 0xb0, + .sta_ofs = 0x70, +}; + +static const struct mtk_gate_regs top4_cg_regs = { + .set_ofs = 0xa4, + .clr_ofs = 0xb4, + .sta_ofs = 0x74, +}; + +static const struct mtk_gate_regs top5_cg_regs = { + .set_ofs = 0x44, + .clr_ofs = 0x44, + .sta_ofs = 0x44, +}; + +#define GATE_TOP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_TOP2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_TOP2_I(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_TOP3(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top3_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_TOP4_I(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top4_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_TOP5(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top5_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate top_clks[] __initconst = { + /* TOP1 */ + GATE_TOP1(CLK_TOP_THEM, "them", "ahb_infra_sel", 1), + GATE_TOP1(CLK_TOP_APDMA, "apdma", "ahb_infra_sel", 2), + GATE_TOP1(CLK_TOP_I2C0, "i2c0", "ifr_i2c0_sel", 3), + GATE_TOP1(CLK_TOP_I2C1, "i2c1", "ifr_i2c1_sel", 4), + GATE_TOP1(CLK_TOP_AUXADC1, "auxadc1", "ahb_infra_sel", 5), + GATE_TOP1(CLK_TOP_NFI, "nfi", "nfi1x_pad_sel", 6), + GATE_TOP1(CLK_TOP_NFIECC, "nfiecc", "rg_nfiecc", 7), + GATE_TOP1(CLK_TOP_DEBUGSYS, "debugsys", "rg_dbg_atclk", 8), + GATE_TOP1(CLK_TOP_PWM, "pwm", "ahb_infra_sel", 9), + GATE_TOP1(CLK_TOP_UART0, "uart0", "uart0_sel", 10), + GATE_TOP1(CLK_TOP_UART1, "uart1", "uart1_sel", 11), + GATE_TOP1(CLK_TOP_BTIF, "btif", "ahb_infra_sel", 12), + GATE_TOP1(CLK_TOP_USB, "usb", "usb_78m", 13), + GATE_TOP1(CLK_TOP_FLASHIF_26M, "flashif_26m", "clk26m_ck", 14), + GATE_TOP1(CLK_TOP_AUXADC2, "auxadc2", "ahb_infra_sel", 15), + GATE_TOP1(CLK_TOP_I2C2, "i2c2", "ifr_i2c2_sel", 16), + GATE_TOP1(CLK_TOP_MSDC0, "msdc0", "msdc0_sel", 17), + GATE_TOP1(CLK_TOP_MSDC1, "msdc1", "msdc1_sel", 18), + GATE_TOP1(CLK_TOP_NFI2X, "nfi2x", "nfi2x_pad_sel", 19), + GATE_TOP1(CLK_TOP_PMICWRAP_AP, "pwrap_ap", "clk26m_ck", 20), + GATE_TOP1(CLK_TOP_SEJ, "sej", "ahb_infra_sel", 21), + GATE_TOP1(CLK_TOP_MEMSLP_DLYER, "memslp_dlyer", "clk26m_ck", 22), + GATE_TOP1(CLK_TOP_SPI, "spi", "spi_sel", 23), + GATE_TOP1(CLK_TOP_APXGPT, "apxgpt", "clk26m_ck", 24), + GATE_TOP1(CLK_TOP_AUDIO, "audio", "clk26m_ck", 25), + GATE_TOP1(CLK_TOP_PMICWRAP_MD, "pwrap_md", "clk26m_ck", 27), + GATE_TOP1(CLK_TOP_PMICWRAP_CONN, "pwrap_conn", "clk26m_ck", 28), + GATE_TOP1(CLK_TOP_PMICWRAP_26M, "pwrap_26m", "clk26m_ck", 29), + GATE_TOP1(CLK_TOP_AUX_ADC, "aux_adc", "clk26m_ck", 30), + GATE_TOP1(CLK_TOP_AUX_TP, "aux_tp", "clk26m_ck", 31), + /* TOP2 */ + GATE_TOP2(CLK_TOP_MSDC2, "msdc2", "ahb_infra_sel", 0), + GATE_TOP2(CLK_TOP_RBIST, "rbist", "univpll_d12", 1), + GATE_TOP2(CLK_TOP_NFI_BUS, "nfi_bus", "ahb_infra_sel", 2), + GATE_TOP2(CLK_TOP_GCE, "gce", "ahb_infra_sel", 4), + GATE_TOP2(CLK_TOP_TRNG, "trng", "ahb_infra_sel", 5), + GATE_TOP2(CLK_TOP_SEJ_13M, "sej_13m", "clk26m_ck", 6), + GATE_TOP2(CLK_TOP_AES, "aes", "ahb_infra_sel", 7), + GATE_TOP2(CLK_TOP_PWM_B, "pwm_b", "rg_pwm_infra", 8), + GATE_TOP2(CLK_TOP_PWM1_FB, "pwm1_fb", "rg_pwm_infra", 9), + GATE_TOP2(CLK_TOP_PWM2_FB, "pwm2_fb", "rg_pwm_infra", 10), + GATE_TOP2(CLK_TOP_PWM3_FB, "pwm3_fb", "rg_pwm_infra", 11), + GATE_TOP2(CLK_TOP_PWM4_FB, "pwm4_fb", "rg_pwm_infra", 12), + GATE_TOP2(CLK_TOP_PWM5_FB, "pwm5_fb", "rg_pwm_infra", 13), + GATE_TOP2(CLK_TOP_USB_1P, "usb_1p", "usb_78m", 14), + GATE_TOP2(CLK_TOP_FLASHIF_FREERUN, "flashif_freerun", "ahb_infra_sel", + 15), + GATE_TOP2(CLK_TOP_66M_ETH, "eth_66m", "ahb_infra_d2", 19), + GATE_TOP2(CLK_TOP_133M_ETH, "eth_133m", "ahb_infra_sel", 20), + GATE_TOP2(CLK_TOP_FETH_25M, "feth_25m", "ifr_eth_25m_sel", 21), + GATE_TOP2(CLK_TOP_FETH_50M, "feth_50m", "rg_eth", 22), + GATE_TOP2(CLK_TOP_FLASHIF_AXI, "flashif_axi", "ahb_infra_sel", 23), + GATE_TOP2(CLK_TOP_USBIF, "usbif", "ahb_infra_sel", 24), + GATE_TOP2(CLK_TOP_UART2, "uart2", "rg_uart2", 25), + GATE_TOP2(CLK_TOP_BSI, "bsi", "ahb_infra_sel", 26), + GATE_TOP2_I(CLK_TOP_MSDC0_INFRA, "msdc0_infra", "msdc0", 28), + GATE_TOP2_I(CLK_TOP_MSDC1_INFRA, "msdc1_infra", "msdc1", 29), + GATE_TOP2_I(CLK_TOP_MSDC2_INFRA, "msdc2_infra", "rg_msdc2", 30), + GATE_TOP2(CLK_TOP_USB_78M, "usb_78m", "usb_78m_sel", 31), + /* TOP3 */ + GATE_TOP3(CLK_TOP_RG_SPINOR, "rg_spinor", "spinor_sel", 0), + GATE_TOP3(CLK_TOP_RG_MSDC2, "rg_msdc2", "msdc2_sel", 1), + GATE_TOP3(CLK_TOP_RG_ETH, "rg_eth", "eth_sel", 2), + GATE_TOP3(CLK_TOP_RG_AUD1, "rg_aud1", "aud1_sel", 8), + GATE_TOP3(CLK_TOP_RG_AUD2, "rg_aud2", "aud2_sel", 9), + GATE_TOP3(CLK_TOP_RG_AUD_ENGEN1, "rg_aud_engen1", "aud_engen1_sel", 10), + GATE_TOP3(CLK_TOP_RG_AUD_ENGEN2, "rg_aud_engen2", "aud_engen2_sel", 11), + GATE_TOP3(CLK_TOP_RG_I2C, "rg_i2c", "i2c_sel", 12), + GATE_TOP3(CLK_TOP_RG_PWM_INFRA, "rg_pwm_infra", "pwm_sel", 13), + GATE_TOP3(CLK_TOP_RG_AUD_SPDIF_IN, "rg_aud_spdif_in", "aud_spdifin_sel", + 14), + GATE_TOP3(CLK_TOP_RG_UART2, "rg_uart2", "uart2_sel", 15), + GATE_TOP3(CLK_TOP_RG_BSI, "rg_bsi", "bsi_sel", 16), + GATE_TOP3(CLK_TOP_RG_DBG_ATCLK, "rg_dbg_atclk", "dbg_atclk_sel", 17), + GATE_TOP3(CLK_TOP_RG_NFIECC, "rg_nfiecc", "nfiecc_sel", 18), + /* TOP4 */ + GATE_TOP4_I(CLK_TOP_RG_APLL1_D2_EN, "rg_apll1_d2_en", "apll1_d2", 8), + GATE_TOP4_I(CLK_TOP_RG_APLL1_D4_EN, "rg_apll1_d4_en", "apll1_d4", 9), + GATE_TOP4_I(CLK_TOP_RG_APLL1_D8_EN, "rg_apll1_d8_en", "apll1_d8", 10), + GATE_TOP4_I(CLK_TOP_RG_APLL2_D2_EN, "rg_apll2_d2_en", "apll2_d2", 11), + GATE_TOP4_I(CLK_TOP_RG_APLL2_D4_EN, "rg_apll2_d4_en", "apll2_d4", 12), + GATE_TOP4_I(CLK_TOP_RG_APLL2_D8_EN, "rg_apll2_d8_en", "apll2_d8", 13), + /* TOP5 */ + GATE_TOP5(CLK_TOP_APLL12_DIV0, "apll12_div0", "apll12_ck_div0", 0), + GATE_TOP5(CLK_TOP_APLL12_DIV1, "apll12_div1", "apll12_ck_div1", 1), + GATE_TOP5(CLK_TOP_APLL12_DIV2, "apll12_div2", "apll12_ck_div2", 2), + GATE_TOP5(CLK_TOP_APLL12_DIV3, "apll12_div3", "apll12_ck_div3", 3), + GATE_TOP5(CLK_TOP_APLL12_DIV4, "apll12_div4", "apll12_ck_div4", 4), + GATE_TOP5(CLK_TOP_APLL12_DIV4B, "apll12_div4b", "apll12_ck_div4b", 5), + GATE_TOP5(CLK_TOP_APLL12_DIV5, "apll12_div5", "apll12_ck_div5", 6), + GATE_TOP5(CLK_TOP_APLL12_DIV5B, "apll12_div5b", "apll12_ck_div5b", 7), + GATE_TOP5(CLK_TOP_APLL12_DIV6, "apll12_div6", "apll12_ck_div6", 8), +}; + +static void __init mtk_topckgen_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return; + } + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + + mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), + clk_data); + mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), clk_data); + + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); + mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, + &mt8516_clk_lock, clk_data); + mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), + base, &mt8516_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8516-topckgen", mtk_topckgen_init); + +static void __init mtk_infracfg_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return; + } + + clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK); + + mtk_clk_register_composites(ifr_muxes, ARRAY_SIZE(ifr_muxes), base, + &mt8516_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt8516-infracfg", mtk_infracfg_init); + +#define MT8516_PLL_FMAX (1502UL * MHZ) + +#define CON0_MT8516_RST_BAR BIT(27) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT8516_RST_BAR, \ + .fmax = MT8516_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL) + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT8516_PLL_FMAX }, + { .div = 1, .freq = 1000000000 }, + { .div = 2, .freq = 604500000 }, + { .div = 3, .freq = 253500000 }, + { .div = 4, .freq = 126750000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0100, 0x0110, 0x00000001, 0, + 21, 0x0104, 24, 0, 0x0104, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0120, 0x0130, 0x00000001, + HAVE_RST_BAR, 21, 0x0124, 24, 0, 0x0124, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0140, 0x0150, 0x30000001, + HAVE_RST_BAR, 7, 0x0144, 24, 0, 0x0144, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0160, 0x0170, 0x00000001, 0, + 21, 0x0164, 24, 0, 0x0164, 0, mmpll_div_table), + PLL(CLK_APMIXED_APLL1, "apll1", 0x0180, 0x0190, 0x00000001, 0, + 31, 0x0180, 1, 0x0194, 0x0184, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x01A0, 0x01B0, 0x00000001, 0, + 31, 0x01A0, 1, 0x01B4, 0x01A4, 0), +}; + +static void __init mtk_apmixedsys_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + void __iomem *base; + int r; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return; + } + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + +} +CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8516-apmixedsys", + mtk_apmixedsys_init); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index fb27b5bf30d9..33ab1731482f 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -227,10 +227,13 @@ struct mtk_pll_data { unsigned int flags; const struct clk_ops *ops; u32 rst_bar_mask; + unsigned long fmin; unsigned long fmax; int pcwbits; + int pcwibits; uint32_t pcw_reg; int pcw_shift; + uint32_t pcw_chg_reg; const struct mtk_pll_div_table *div_table; const char *parent_name; }; diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c new file mode 100644 index 000000000000..76f9cd039195 --- /dev/null +++ b/drivers/clk/mediatek/clk-mux.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Owen Chen <owen.chen@mediatek.com> + */ + +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/mfd/syscon.h> + +#include "clk-mtk.h" +#include "clk-mux.h" + +static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw) +{ + return container_of(hw, struct mtk_clk_mux, hw); +} + +static int mtk_clk_mux_enable(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 mask = BIT(mux->data->gate_shift); + + return regmap_update_bits(mux->regmap, mux->data->mux_ofs, + mask, ~mask); +} + +static void mtk_clk_mux_disable(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 mask = BIT(mux->data->gate_shift); + + regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, mask); +} + +static int mtk_clk_mux_enable_setclr(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + + return regmap_write(mux->regmap, mux->data->clr_ofs, + BIT(mux->data->gate_shift)); +} + +static void mtk_clk_mux_disable_setclr(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + + regmap_write(mux->regmap, mux->data->set_ofs, + BIT(mux->data->gate_shift)); +} + +static int mtk_clk_mux_is_enabled(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 val; + + regmap_read(mux->regmap, mux->data->mux_ofs, &val); + + return (val & BIT(mux->data->gate_shift)) == 0; +} + +static u8 mtk_clk_mux_get_parent(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 mask = GENMASK(mux->data->mux_width - 1, 0); + u32 val; + + regmap_read(mux->regmap, mux->data->mux_ofs, &val); + val = (val >> mux->data->mux_shift) & mask; + + return val; +} + +static int mtk_clk_mux_set_parent_lock(struct clk_hw *hw, u8 index) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 mask = GENMASK(mux->data->mux_width - 1, 0); + unsigned long flags = 0; + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); + + regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, + index << mux->data->mux_shift); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); + + return 0; +} + +static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 mask = GENMASK(mux->data->mux_width - 1, 0); + u32 val, orig; + unsigned long flags = 0; + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); + + regmap_read(mux->regmap, mux->data->mux_ofs, &orig); + val = (orig & ~(mask << mux->data->mux_shift)) + | (index << mux->data->mux_shift); + + if (val != orig) { + regmap_write(mux->regmap, mux->data->clr_ofs, + mask << mux->data->mux_shift); + regmap_write(mux->regmap, mux->data->set_ofs, + index << mux->data->mux_shift); + + if (mux->data->upd_shift >= 0) + regmap_write(mux->regmap, mux->data->upd_ofs, + BIT(mux->data->upd_shift)); + } + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); + + return 0; +} + +const struct clk_ops mtk_mux_ops = { + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_lock, +}; + +const struct clk_ops mtk_mux_clr_set_upd_ops = { + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_setclr_lock, +}; + +const struct clk_ops mtk_mux_gate_ops = { + .enable = mtk_clk_mux_enable, + .disable = mtk_clk_mux_disable, + .is_enabled = mtk_clk_mux_is_enabled, + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_lock, +}; + +const struct clk_ops mtk_mux_gate_clr_set_upd_ops = { + .enable = mtk_clk_mux_enable_setclr, + .disable = mtk_clk_mux_disable_setclr, + .is_enabled = mtk_clk_mux_is_enabled, + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_setclr_lock, +}; + +struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, + struct regmap *regmap, + spinlock_t *lock) +{ + struct mtk_clk_mux *clk_mux; + struct clk_init_data init; + struct clk *clk; + + clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL); + if (!clk_mux) + return ERR_PTR(-ENOMEM); + + init.name = mux->name; + init.flags = mux->flags | CLK_SET_RATE_PARENT; + init.parent_names = mux->parent_names; + init.num_parents = mux->num_parents; + init.ops = mux->ops; + + clk_mux->regmap = regmap; + clk_mux->data = mux; + clk_mux->lock = lock; + clk_mux->hw.init = &init; + + clk = clk_register(NULL, &clk_mux->hw); + if (IS_ERR(clk)) { + kfree(clk_mux); + return clk; + } + + return clk; +} + +int mtk_clk_register_muxes(const struct mtk_mux *muxes, + int num, struct device_node *node, + spinlock_t *lock, + struct clk_onecell_data *clk_data) +{ + struct regmap *regmap; + struct clk *clk; + int i; + + regmap = syscon_node_to_regmap(node); + if (IS_ERR(regmap)) { + pr_err("Cannot find regmap for %pOF: %ld\n", node, + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + for (i = 0; i < num; i++) { + const struct mtk_mux *mux = &muxes[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) { + clk = mtk_clk_register_mux(mux, regmap, lock); + + if (IS_ERR(clk)) { + pr_err("Failed to register clk %s: %ld\n", + mux->name, PTR_ERR(clk)); + continue; + } + + clk_data->clks[mux->id] = clk; + } + } + + return 0; +} diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h new file mode 100644 index 000000000000..f5625f4d9e6c --- /dev/null +++ b/drivers/clk/mediatek/clk-mux.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Owen Chen <owen.chen@mediatek.com> + */ + +#ifndef __DRV_CLK_MTK_MUX_H +#define __DRV_CLK_MTK_MUX_H + +#include <linux/clk-provider.h> + +struct mtk_clk_mux { + struct clk_hw hw; + struct regmap *regmap; + const struct mtk_mux *data; + spinlock_t *lock; +}; + +struct mtk_mux { + int id; + const char *name; + const char * const *parent_names; + unsigned int flags; + + u32 mux_ofs; + u32 set_ofs; + u32 clr_ofs; + u32 upd_ofs; + + u8 mux_shift; + u8 mux_width; + u8 gate_shift; + s8 upd_shift; + + const struct clk_ops *ops; + + signed char num_parents; +}; + +extern const struct clk_ops mtk_mux_ops; +extern const struct clk_ops mtk_mux_clr_set_upd_ops; +extern const struct clk_ops mtk_mux_gate_ops; +extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; + +#define GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd, _flags, _ops) { \ + .id = _id, \ + .name = _name, \ + .mux_ofs = _mux_ofs, \ + .set_ofs = _mux_set_ofs, \ + .clr_ofs = _mux_clr_ofs, \ + .upd_ofs = _upd_ofs, \ + .mux_shift = _shift, \ + .mux_width = _width, \ + .gate_shift = _gate, \ + .upd_shift = _upd, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .flags = _flags, \ + .ops = &_ops, \ + } + +#define MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd, _flags) \ + GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd, _flags, \ + mtk_mux_gate_clr_set_upd_ops) + +#define MUX_GATE_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd) \ + MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \ + _width, _gate, _upd_ofs, _upd, \ + CLK_SET_RATE_PARENT) + +struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, + struct regmap *regmap, + spinlock_t *lock); + +int mtk_clk_register_muxes(const struct mtk_mux *muxes, + int num, struct device_node *node, + spinlock_t *lock, + struct clk_onecell_data *clk_data); + +#endif /* __DRV_CLK_MTK_MUX_H */ diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index f54e4015b0b1..8d556fc99fed 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -27,11 +27,13 @@ #define CON0_BASE_EN BIT(0) #define CON0_PWR_ON BIT(0) #define CON0_ISO_EN BIT(1) -#define CON0_PCW_CHG BIT(31) +#define PCW_CHG_MASK BIT(31) #define AUDPLL_TUNER_EN BIT(31) #define POSTDIV_MASK 0x7 + +/* default 7 bits integer, can be overridden with pcwibits. */ #define INTEGER_BITS 7 /* @@ -49,6 +51,7 @@ struct mtk_clk_pll { void __iomem *tuner_addr; void __iomem *tuner_en_addr; void __iomem *pcw_addr; + void __iomem *pcw_chg_addr; const struct mtk_pll_data *data; }; @@ -68,12 +71,15 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, u32 pcw, int postdiv) { int pcwbits = pll->data->pcwbits; - int pcwfbits; + int pcwfbits = 0; + int ibits; u64 vco; u8 c = 0; /* The fractional part of the PLL divider. */ - pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0; + ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS; + if (pcwbits > ibits) + pcwfbits = pcwbits - ibits; vco = (u64)fin * pcw; @@ -88,13 +94,39 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, return ((unsigned long)vco + postdiv - 1) / postdiv; } +static void __mtk_pll_tuner_enable(struct mtk_clk_pll *pll) +{ + u32 r; + + if (pll->tuner_en_addr) { + r = readl(pll->tuner_en_addr) | BIT(pll->data->tuner_en_bit); + writel(r, pll->tuner_en_addr); + } else if (pll->tuner_addr) { + r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN; + writel(r, pll->tuner_addr); + } +} + +static void __mtk_pll_tuner_disable(struct mtk_clk_pll *pll) +{ + u32 r; + + if (pll->tuner_en_addr) { + r = readl(pll->tuner_en_addr) & ~BIT(pll->data->tuner_en_bit); + writel(r, pll->tuner_en_addr); + } else if (pll->tuner_addr) { + r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN; + writel(r, pll->tuner_addr); + } +} + static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, int postdiv) { - u32 con1, val; - int pll_en; + u32 chg, val; - pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN; + /* disable tuner */ + __mtk_pll_tuner_disable(pll); /* set postdiv */ val = readl(pll->pd_addr); @@ -112,18 +144,15 @@ static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, pll->data->pcw_shift); val |= pcw << pll->data->pcw_shift; writel(val, pll->pcw_addr); - - con1 = readl(pll->base_addr + REG_CON1); - - if (pll_en) - con1 |= CON0_PCW_CHG; - - writel(con1, pll->base_addr + REG_CON1); + chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; + writel(chg, pll->pcw_chg_addr); if (pll->tuner_addr) - writel(con1 + 1, pll->tuner_addr); + writel(val + 1, pll->tuner_addr); + + /* restore tuner_en */ + __mtk_pll_tuner_enable(pll); - if (pll_en) - udelay(20); + udelay(20); } /* @@ -138,9 +167,10 @@ static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, u32 freq, u32 fin) { - unsigned long fmin = 1000 * MHZ; + unsigned long fmin = pll->data->fmin ? pll->data->fmin : (1000 * MHZ); const struct mtk_pll_div_table *div_table = pll->data->div_table; u64 _pcw; + int ibits; u32 val; if (freq > pll->data->fmax) @@ -164,7 +194,8 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, } /* _pcw = freq * postdiv / fin * 2^pcwfbits */ - _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS); + ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS; + _pcw = ((u64)freq << val) << (pll->data->pcwbits - ibits); do_div(_pcw, fin); *pcw = (u32)_pcw; @@ -228,13 +259,7 @@ static int mtk_pll_prepare(struct clk_hw *hw) r |= pll->data->en_mask; writel(r, pll->base_addr + REG_CON0); - if (pll->tuner_en_addr) { - r = readl(pll->tuner_en_addr) | BIT(pll->data->tuner_en_bit); - writel(r, pll->tuner_en_addr); - } else if (pll->tuner_addr) { - r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN; - writel(r, pll->tuner_addr); - } + __mtk_pll_tuner_enable(pll); udelay(20); @@ -258,13 +283,7 @@ static void mtk_pll_unprepare(struct clk_hw *hw) writel(r, pll->base_addr + REG_CON0); } - if (pll->tuner_en_addr) { - r = readl(pll->tuner_en_addr) & ~BIT(pll->data->tuner_en_bit); - writel(r, pll->tuner_en_addr); - } else if (pll->tuner_addr) { - r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN; - writel(r, pll->tuner_addr); - } + __mtk_pll_tuner_disable(pll); r = readl(pll->base_addr + REG_CON0); r &= ~CON0_BASE_EN; @@ -302,6 +321,10 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, pll->pwr_addr = base + data->pwr_reg; pll->pd_addr = base + data->pd_reg; pll->pcw_addr = base + data->pcw_reg; + if (data->pcw_chg_reg) + pll->pcw_chg_addr = base + data->pcw_chg_reg; + else + pll->pcw_chg_addr = pll->base_addr + REG_CON1; if (data->tuner_reg) pll->tuner_addr = base + data->tuner_reg; if (data->tuner_en_reg) diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 7ab200b6c3bf..8028ff6f6610 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -20,18 +20,18 @@ #include "clk-phase.h" #include "sclk-div.h" -#define AXG_MST_IN_COUNT 8 -#define AXG_SLV_SCLK_COUNT 10 -#define AXG_SLV_LRCLK_COUNT 10 +#define AUD_MST_IN_COUNT 8 +#define AUD_SLV_SCLK_COUNT 10 +#define AUD_SLV_LRCLK_COUNT 10 -#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ -struct clk_regmap axg_##_name = { \ +#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ +struct clk_regmap aud_##_name = { \ .data = &(struct clk_regmap_gate_data){ \ .offset = (_reg), \ .bit_idx = (_bit), \ }, \ .hw.init = &(struct clk_init_data) { \ - .name = "axg_"#_name, \ + .name = "aud_"#_name, \ .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ _pname }, \ .num_parents = 1, \ @@ -39,8 +39,8 @@ struct clk_regmap axg_##_name = { \ }, \ } -#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ -struct clk_regmap axg_##_name = { \ +#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ +struct clk_regmap aud_##_name = { \ .data = &(struct clk_regmap_mux_data){ \ .offset = (_reg), \ .mask = (_mask), \ @@ -48,7 +48,7 @@ struct clk_regmap axg_##_name = { \ .flags = (_dflags), \ }, \ .hw.init = &(struct clk_init_data){ \ - .name = "axg_"#_name, \ + .name = "aud_"#_name, \ .ops = &clk_regmap_mux_ops, \ .parent_names = (_pnames), \ .num_parents = ARRAY_SIZE(_pnames), \ @@ -56,8 +56,8 @@ struct clk_regmap axg_##_name = { \ }, \ } -#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ -struct clk_regmap axg_##_name = { \ +#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ +struct clk_regmap aud_##_name = { \ .data = &(struct clk_regmap_div_data){ \ .offset = (_reg), \ .shift = (_shift), \ @@ -65,7 +65,7 @@ struct clk_regmap axg_##_name = { \ .flags = (_dflags), \ }, \ .hw.init = &(struct clk_init_data){ \ - .name = "axg_"#_name, \ + .name = "aud_"#_name, \ .ops = &clk_regmap_divider_ops, \ .parent_names = (const char *[]) { _pname }, \ .num_parents = 1, \ @@ -73,109 +73,113 @@ struct clk_regmap axg_##_name = { \ }, \ } -#define AXG_PCLK_GATE(_name, _bit) \ - AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0) +#define AUD_PCLK_GATE(_name, _bit) \ + AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "audio_pclk", 0) /* Audio peripheral clocks */ -static AXG_PCLK_GATE(ddr_arb, 0); -static AXG_PCLK_GATE(pdm, 1); -static AXG_PCLK_GATE(tdmin_a, 2); -static AXG_PCLK_GATE(tdmin_b, 3); -static AXG_PCLK_GATE(tdmin_c, 4); -static AXG_PCLK_GATE(tdmin_lb, 5); -static AXG_PCLK_GATE(tdmout_a, 6); -static AXG_PCLK_GATE(tdmout_b, 7); -static AXG_PCLK_GATE(tdmout_c, 8); -static AXG_PCLK_GATE(frddr_a, 9); -static AXG_PCLK_GATE(frddr_b, 10); -static AXG_PCLK_GATE(frddr_c, 11); -static AXG_PCLK_GATE(toddr_a, 12); -static AXG_PCLK_GATE(toddr_b, 13); -static AXG_PCLK_GATE(toddr_c, 14); -static AXG_PCLK_GATE(loopback, 15); -static AXG_PCLK_GATE(spdifin, 16); -static AXG_PCLK_GATE(spdifout, 17); -static AXG_PCLK_GATE(resample, 18); -static AXG_PCLK_GATE(power_detect, 19); +static AUD_PCLK_GATE(ddr_arb, 0); +static AUD_PCLK_GATE(pdm, 1); +static AUD_PCLK_GATE(tdmin_a, 2); +static AUD_PCLK_GATE(tdmin_b, 3); +static AUD_PCLK_GATE(tdmin_c, 4); +static AUD_PCLK_GATE(tdmin_lb, 5); +static AUD_PCLK_GATE(tdmout_a, 6); +static AUD_PCLK_GATE(tdmout_b, 7); +static AUD_PCLK_GATE(tdmout_c, 8); +static AUD_PCLK_GATE(frddr_a, 9); +static AUD_PCLK_GATE(frddr_b, 10); +static AUD_PCLK_GATE(frddr_c, 11); +static AUD_PCLK_GATE(toddr_a, 12); +static AUD_PCLK_GATE(toddr_b, 13); +static AUD_PCLK_GATE(toddr_c, 14); +static AUD_PCLK_GATE(loopback, 15); +static AUD_PCLK_GATE(spdifin, 16); +static AUD_PCLK_GATE(spdifout, 17); +static AUD_PCLK_GATE(resample, 18); +static AUD_PCLK_GATE(power_detect, 19); +static AUD_PCLK_GATE(spdifout_b, 21); /* Audio Master Clocks */ static const char * const mst_mux_parent_names[] = { - "axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3", - "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", + "aud_mst_in0", "aud_mst_in1", "aud_mst_in2", "aud_mst_in3", + "aud_mst_in4", "aud_mst_in5", "aud_mst_in6", "aud_mst_in7", }; -#define AXG_MST_MUX(_name, _reg, _flag) \ - AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ - mst_mux_parent_names, CLK_SET_RATE_PARENT) - -#define AXG_MST_MCLK_MUX(_name, _reg) \ - AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) - -#define AXG_MST_SYS_MUX(_name, _reg) \ - AXG_MST_MUX(_name, _reg, 0) - -static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); -static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); -static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); -static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); -static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); -static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); -static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); -static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); - -#define AXG_MST_DIV(_name, _reg, _flag) \ - AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ - "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ - -#define AXG_MST_MCLK_DIV(_name, _reg) \ - AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) - -#define AXG_MST_SYS_DIV(_name, _reg) \ - AXG_MST_DIV(_name, _reg, 0) - -static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); -static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); -static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); -static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); -static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); -static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); -static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); -static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); - -#define AXG_MST_MCLK_GATE(_name, _reg) \ - AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ - CLK_SET_RATE_PARENT) - -static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); -static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); -static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); -static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); -static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); -static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); -static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); -static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +#define AUD_MST_MUX(_name, _reg, _flag) \ + AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ + mst_mux_parent_names, CLK_SET_RATE_PARENT) + +#define AUD_MST_MCLK_MUX(_name, _reg) \ + AUD_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) + +#define AUD_MST_SYS_MUX(_name, _reg) \ + AUD_MST_MUX(_name, _reg, 0) + +static AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static AUD_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static AUD_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); +static AUD_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static AUD_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static AUD_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AUD_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AUD_MST_MCLK_MUX(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + +#define AUD_MST_DIV(_name, _reg, _flag) \ + AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ + "aud_"#_name"_sel", CLK_SET_RATE_PARENT) \ + +#define AUD_MST_MCLK_DIV(_name, _reg) \ + AUD_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) + +#define AUD_MST_SYS_DIV(_name, _reg) \ + AUD_MST_DIV(_name, _reg, 0) + +static AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static AUD_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static AUD_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); +static AUD_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static AUD_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static AUD_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AUD_MST_MCLK_DIV(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + +#define AUD_MST_MCLK_GATE(_name, _reg) \ + AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ + CLK_SET_RATE_PARENT) + +static AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static AUD_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static AUD_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); +static AUD_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AUD_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static AUD_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AUD_MST_MCLK_GATE(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); /* Sample Clocks */ -#define AXG_MST_SCLK_PRE_EN(_name, _reg) \ - AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ - "axg_mst_"#_name"_mclk", 0) - -static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); -static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); -static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); -static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); -static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); -static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); - -#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ +#define AUD_MST_SCLK_PRE_EN(_name, _reg) \ + AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ + "aud_mst_"#_name"_mclk", 0) + +static AUD_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); +static AUD_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); +static AUD_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); +static AUD_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); +static AUD_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); +static AUD_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ _hi_shift, _hi_width, _pname, _iflags) \ -struct clk_regmap axg_##_name = { \ +struct clk_regmap aud_##_name = { \ .data = &(struct meson_sclk_div_data) { \ .div = { \ .reg_off = (_reg), \ @@ -189,7 +193,7 @@ struct clk_regmap axg_##_name = { \ }, \ }, \ .hw.init = &(struct clk_init_data) { \ - .name = "axg_"#_name, \ + .name = "aud_"#_name, \ .ops = &meson_sclk_div_ops, \ .parent_names = (const char *[]) { _pname }, \ .num_parents = 1, \ @@ -197,32 +201,32 @@ struct clk_regmap axg_##_name = { \ }, \ } -#define AXG_MST_SCLK_DIV(_name, _reg) \ - AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ - "axg_mst_"#_name"_sclk_pre_en", \ - CLK_SET_RATE_PARENT) - -static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); -static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); -static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); -static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); -static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); -static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); - -#define AXG_MST_SCLK_POST_EN(_name, _reg) \ - AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ - "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) - -static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); -static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); -static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); -static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); -static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); -static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); - -#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ +#define AUD_MST_SCLK_DIV(_name, _reg) \ + AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ + "aud_mst_"#_name"_sclk_pre_en", \ + CLK_SET_RATE_PARENT) + +static AUD_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +static AUD_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +static AUD_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +static AUD_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +static AUD_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +static AUD_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AUD_MST_SCLK_POST_EN(_name, _reg) \ + AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ + "aud_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) + +static AUD_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); +static AUD_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); +static AUD_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); +static AUD_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); +static AUD_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); +static AUD_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ _pname, _iflags) \ -struct clk_regmap axg_##_name = { \ +struct clk_regmap aud_##_name = { \ .data = &(struct meson_clk_triphase_data) { \ .ph0 = { \ .reg_off = (_reg), \ @@ -241,7 +245,7 @@ struct clk_regmap axg_##_name = { \ }, \ }, \ .hw.init = &(struct clk_init_data) { \ - .name = "axg_"#_name, \ + .name = "aud_"#_name, \ .ops = &meson_clk_triphase_ops, \ .parent_names = (const char *[]) { _pname }, \ .num_parents = 1, \ @@ -249,87 +253,87 @@ struct clk_regmap axg_##_name = { \ }, \ } -#define AXG_MST_SCLK(_name, _reg) \ - AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ - "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) - -static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); -static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); -static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); -static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); -static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); -static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); - -#define AXG_MST_LRCLK_DIV(_name, _reg) \ - AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ - "axg_mst_"#_name"_sclk_post_en", 0) \ - -static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); -static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); -static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); -static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); -static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); -static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); - -#define AXG_MST_LRCLK(_name, _reg) \ - AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ - "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) - -static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); -static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); -static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); -static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); -static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); -static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); +#define AUD_MST_SCLK(_name, _reg) \ + AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ + "aud_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) + +static AUD_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); +static AUD_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); +static AUD_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); +static AUD_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); +static AUD_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); +static AUD_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); + +#define AUD_MST_LRCLK_DIV(_name, _reg) \ + AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ + "aud_mst_"#_name"_sclk_post_en", 0) \ + +static AUD_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +static AUD_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +static AUD_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +static AUD_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +static AUD_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +static AUD_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AUD_MST_LRCLK(_name, _reg) \ + AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ + "aud_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) + +static AUD_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); +static AUD_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); +static AUD_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); +static AUD_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); +static AUD_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); +static AUD_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); static const char * const tdm_sclk_parent_names[] = { - "axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk", - "axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk", - "axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2", - "axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5", - "axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8", - "axg_slv_sclk9" + "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", + "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", + "aud_slv_sclk0", "aud_slv_sclk1", "aud_slv_sclk2", + "aud_slv_sclk3", "aud_slv_sclk4", "aud_slv_sclk5", + "aud_slv_sclk6", "aud_slv_sclk7", "aud_slv_sclk8", + "aud_slv_sclk9" }; -#define AXG_TDM_SCLK_MUX(_name, _reg) \ - AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ +#define AUD_TDM_SCLK_MUX(_name, _reg) \ + AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ CLK_MUX_ROUND_CLOSEST, \ tdm_sclk_parent_names, 0) -static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); -static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); -static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); -static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - -#define AXG_TDM_SCLK_PRE_EN(_name, _reg) \ - AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ - "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) - -static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); -static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); -static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); -static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - -#define AXG_TDM_SCLK_POST_EN(_name, _reg) \ - AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ - "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) - -static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); -static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); -static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); -static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - -#define AXG_TDM_SCLK(_name, _reg) \ - struct clk_regmap axg_tdm##_name##_sclk = { \ +static AUD_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AUD_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AUD_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AUD_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AUD_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AUD_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AUD_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \ + AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ + "aud_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) + +static AUD_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AUD_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AUD_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AUD_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AUD_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AUD_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AUD_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +#define AUD_TDM_SCLK_POST_EN(_name, _reg) \ + AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ + "aud_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) + +static AUD_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AUD_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AUD_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AUD_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AUD_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AUD_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AUD_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +#define AUD_TDM_SCLK(_name, _reg) \ + struct clk_regmap aud_tdm##_name##_sclk = { \ .data = &(struct meson_clk_phase_data) { \ .ph = { \ .reg_off = (_reg), \ @@ -338,44 +342,83 @@ static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); }, \ }, \ .hw.init = &(struct clk_init_data) { \ - .name = "axg_tdm"#_name"_sclk", \ + .name = "aud_tdm"#_name"_sclk", \ .ops = &meson_clk_phase_ops, \ .parent_names = (const char *[]) \ - { "axg_tdm"#_name"_sclk_post_en" }, \ + { "aud_tdm"#_name"_sclk_post_en" }, \ .num_parents = 1, \ .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ }, \ } -static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); -static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); -static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); -static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); +static AUD_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AUD_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AUD_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AUD_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); static const char * const tdm_lrclk_parent_names[] = { - "axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk", - "axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk", - "axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2", - "axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5", - "axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8", - "axg_slv_lrclk9" + "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", + "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", + "aud_slv_lrclk0", "aud_slv_lrclk1", "aud_slv_lrclk2", + "aud_slv_lrclk3", "aud_slv_lrclk4", "aud_slv_lrclk5", + "aud_slv_lrclk6", "aud_slv_lrclk7", "aud_slv_lrclk8", + "aud_slv_lrclk9" }; -#define AXG_TDM_LRLCK(_name, _reg) \ - AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ - CLK_MUX_ROUND_CLOSEST, \ - tdm_lrclk_parent_names, 0) +#define AUD_TDM_LRLCK(_name, _reg) \ + AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ + CLK_MUX_ROUND_CLOSEST, \ + tdm_lrclk_parent_names, 0) + +static AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AUD_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AUD_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AUD_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AUD_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AUD_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +/* G12a Pad control */ +#define AUD_TDM_PAD_CTRL(_name, _reg, _shift, _parents) \ + AUD_MUX(tdm_##_name, _reg, 0x7, _shift, 0, _parents, \ + CLK_SET_RATE_NO_REPARENT) + +static const char * const mclk_pad_ctrl_parent_names[] = { + "aud_mst_a_mclk", "aud_mst_b_mclk", "aud_mst_c_mclk", + "aud_mst_d_mclk", "aud_mst_e_mclk", "aud_mst_f_mclk", +}; + +static AUD_TDM_PAD_CTRL(mclk_pad_0, AUDIO_MST_PAD_CTRL0, 0, + mclk_pad_ctrl_parent_names); +static AUD_TDM_PAD_CTRL(mclk_pad_1, AUDIO_MST_PAD_CTRL0, 4, + mclk_pad_ctrl_parent_names); + +static const char * const lrclk_pad_ctrl_parent_names[] = { + "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", + "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", +}; -static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); -static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); -static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); -static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); +static AUD_TDM_PAD_CTRL(lrclk_pad_0, AUDIO_MST_PAD_CTRL1, 16, + lrclk_pad_ctrl_parent_names); +static AUD_TDM_PAD_CTRL(lrclk_pad_1, AUDIO_MST_PAD_CTRL1, 20, + lrclk_pad_ctrl_parent_names); +static AUD_TDM_PAD_CTRL(lrclk_pad_2, AUDIO_MST_PAD_CTRL1, 24, + lrclk_pad_ctrl_parent_names); + +static const char * const sclk_pad_ctrl_parent_names[] = { + "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", + "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", +}; + +static AUD_TDM_PAD_CTRL(sclk_pad_0, AUDIO_MST_PAD_CTRL1, 0, + sclk_pad_ctrl_parent_names); +static AUD_TDM_PAD_CTRL(sclk_pad_1, AUDIO_MST_PAD_CTRL1, 4, + sclk_pad_ctrl_parent_names); +static AUD_TDM_PAD_CTRL(sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, + sclk_pad_ctrl_parent_names); /* * Array of all clocks provided by this provider @@ -383,255 +426,416 @@ static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); */ static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { .hws = { - [AUD_CLKID_DDR_ARB] = &axg_ddr_arb.hw, - [AUD_CLKID_PDM] = &axg_pdm.hw, - [AUD_CLKID_TDMIN_A] = &axg_tdmin_a.hw, - [AUD_CLKID_TDMIN_B] = &axg_tdmin_b.hw, - [AUD_CLKID_TDMIN_C] = &axg_tdmin_c.hw, - [AUD_CLKID_TDMIN_LB] = &axg_tdmin_lb.hw, - [AUD_CLKID_TDMOUT_A] = &axg_tdmout_a.hw, - [AUD_CLKID_TDMOUT_B] = &axg_tdmout_b.hw, - [AUD_CLKID_TDMOUT_C] = &axg_tdmout_c.hw, - [AUD_CLKID_FRDDR_A] = &axg_frddr_a.hw, - [AUD_CLKID_FRDDR_B] = &axg_frddr_b.hw, - [AUD_CLKID_FRDDR_C] = &axg_frddr_c.hw, - [AUD_CLKID_TODDR_A] = &axg_toddr_a.hw, - [AUD_CLKID_TODDR_B] = &axg_toddr_b.hw, - [AUD_CLKID_TODDR_C] = &axg_toddr_c.hw, - [AUD_CLKID_LOOPBACK] = &axg_loopback.hw, - [AUD_CLKID_SPDIFIN] = &axg_spdifin.hw, - [AUD_CLKID_SPDIFOUT] = &axg_spdifout.hw, - [AUD_CLKID_RESAMPLE] = &axg_resample.hw, - [AUD_CLKID_POWER_DETECT] = &axg_power_detect.hw, - [AUD_CLKID_MST_A_MCLK_SEL] = &axg_mst_a_mclk_sel.hw, - [AUD_CLKID_MST_B_MCLK_SEL] = &axg_mst_b_mclk_sel.hw, - [AUD_CLKID_MST_C_MCLK_SEL] = &axg_mst_c_mclk_sel.hw, - [AUD_CLKID_MST_D_MCLK_SEL] = &axg_mst_d_mclk_sel.hw, - [AUD_CLKID_MST_E_MCLK_SEL] = &axg_mst_e_mclk_sel.hw, - [AUD_CLKID_MST_F_MCLK_SEL] = &axg_mst_f_mclk_sel.hw, - [AUD_CLKID_MST_A_MCLK_DIV] = &axg_mst_a_mclk_div.hw, - [AUD_CLKID_MST_B_MCLK_DIV] = &axg_mst_b_mclk_div.hw, - [AUD_CLKID_MST_C_MCLK_DIV] = &axg_mst_c_mclk_div.hw, - [AUD_CLKID_MST_D_MCLK_DIV] = &axg_mst_d_mclk_div.hw, - [AUD_CLKID_MST_E_MCLK_DIV] = &axg_mst_e_mclk_div.hw, - [AUD_CLKID_MST_F_MCLK_DIV] = &axg_mst_f_mclk_div.hw, - [AUD_CLKID_MST_A_MCLK] = &axg_mst_a_mclk.hw, - [AUD_CLKID_MST_B_MCLK] = &axg_mst_b_mclk.hw, - [AUD_CLKID_MST_C_MCLK] = &axg_mst_c_mclk.hw, - [AUD_CLKID_MST_D_MCLK] = &axg_mst_d_mclk.hw, - [AUD_CLKID_MST_E_MCLK] = &axg_mst_e_mclk.hw, - [AUD_CLKID_MST_F_MCLK] = &axg_mst_f_mclk.hw, - [AUD_CLKID_SPDIFOUT_CLK_SEL] = &axg_spdifout_clk_sel.hw, - [AUD_CLKID_SPDIFOUT_CLK_DIV] = &axg_spdifout_clk_div.hw, - [AUD_CLKID_SPDIFOUT_CLK] = &axg_spdifout_clk.hw, - [AUD_CLKID_SPDIFIN_CLK_SEL] = &axg_spdifin_clk_sel.hw, - [AUD_CLKID_SPDIFIN_CLK_DIV] = &axg_spdifin_clk_div.hw, - [AUD_CLKID_SPDIFIN_CLK] = &axg_spdifin_clk.hw, - [AUD_CLKID_PDM_DCLK_SEL] = &axg_pdm_dclk_sel.hw, - [AUD_CLKID_PDM_DCLK_DIV] = &axg_pdm_dclk_div.hw, - [AUD_CLKID_PDM_DCLK] = &axg_pdm_dclk.hw, - [AUD_CLKID_PDM_SYSCLK_SEL] = &axg_pdm_sysclk_sel.hw, - [AUD_CLKID_PDM_SYSCLK_DIV] = &axg_pdm_sysclk_div.hw, - [AUD_CLKID_PDM_SYSCLK] = &axg_pdm_sysclk.hw, - [AUD_CLKID_MST_A_SCLK_PRE_EN] = &axg_mst_a_sclk_pre_en.hw, - [AUD_CLKID_MST_B_SCLK_PRE_EN] = &axg_mst_b_sclk_pre_en.hw, - [AUD_CLKID_MST_C_SCLK_PRE_EN] = &axg_mst_c_sclk_pre_en.hw, - [AUD_CLKID_MST_D_SCLK_PRE_EN] = &axg_mst_d_sclk_pre_en.hw, - [AUD_CLKID_MST_E_SCLK_PRE_EN] = &axg_mst_e_sclk_pre_en.hw, - [AUD_CLKID_MST_F_SCLK_PRE_EN] = &axg_mst_f_sclk_pre_en.hw, - [AUD_CLKID_MST_A_SCLK_DIV] = &axg_mst_a_sclk_div.hw, - [AUD_CLKID_MST_B_SCLK_DIV] = &axg_mst_b_sclk_div.hw, - [AUD_CLKID_MST_C_SCLK_DIV] = &axg_mst_c_sclk_div.hw, - [AUD_CLKID_MST_D_SCLK_DIV] = &axg_mst_d_sclk_div.hw, - [AUD_CLKID_MST_E_SCLK_DIV] = &axg_mst_e_sclk_div.hw, - [AUD_CLKID_MST_F_SCLK_DIV] = &axg_mst_f_sclk_div.hw, - [AUD_CLKID_MST_A_SCLK_POST_EN] = &axg_mst_a_sclk_post_en.hw, - [AUD_CLKID_MST_B_SCLK_POST_EN] = &axg_mst_b_sclk_post_en.hw, - [AUD_CLKID_MST_C_SCLK_POST_EN] = &axg_mst_c_sclk_post_en.hw, - [AUD_CLKID_MST_D_SCLK_POST_EN] = &axg_mst_d_sclk_post_en.hw, - [AUD_CLKID_MST_E_SCLK_POST_EN] = &axg_mst_e_sclk_post_en.hw, - [AUD_CLKID_MST_F_SCLK_POST_EN] = &axg_mst_f_sclk_post_en.hw, - [AUD_CLKID_MST_A_SCLK] = &axg_mst_a_sclk.hw, - [AUD_CLKID_MST_B_SCLK] = &axg_mst_b_sclk.hw, - [AUD_CLKID_MST_C_SCLK] = &axg_mst_c_sclk.hw, - [AUD_CLKID_MST_D_SCLK] = &axg_mst_d_sclk.hw, - [AUD_CLKID_MST_E_SCLK] = &axg_mst_e_sclk.hw, - [AUD_CLKID_MST_F_SCLK] = &axg_mst_f_sclk.hw, - [AUD_CLKID_MST_A_LRCLK_DIV] = &axg_mst_a_lrclk_div.hw, - [AUD_CLKID_MST_B_LRCLK_DIV] = &axg_mst_b_lrclk_div.hw, - [AUD_CLKID_MST_C_LRCLK_DIV] = &axg_mst_c_lrclk_div.hw, - [AUD_CLKID_MST_D_LRCLK_DIV] = &axg_mst_d_lrclk_div.hw, - [AUD_CLKID_MST_E_LRCLK_DIV] = &axg_mst_e_lrclk_div.hw, - [AUD_CLKID_MST_F_LRCLK_DIV] = &axg_mst_f_lrclk_div.hw, - [AUD_CLKID_MST_A_LRCLK] = &axg_mst_a_lrclk.hw, - [AUD_CLKID_MST_B_LRCLK] = &axg_mst_b_lrclk.hw, - [AUD_CLKID_MST_C_LRCLK] = &axg_mst_c_lrclk.hw, - [AUD_CLKID_MST_D_LRCLK] = &axg_mst_d_lrclk.hw, - [AUD_CLKID_MST_E_LRCLK] = &axg_mst_e_lrclk.hw, - [AUD_CLKID_MST_F_LRCLK] = &axg_mst_f_lrclk.hw, - [AUD_CLKID_TDMIN_A_SCLK_SEL] = &axg_tdmin_a_sclk_sel.hw, - [AUD_CLKID_TDMIN_B_SCLK_SEL] = &axg_tdmin_b_sclk_sel.hw, - [AUD_CLKID_TDMIN_C_SCLK_SEL] = &axg_tdmin_c_sclk_sel.hw, - [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &axg_tdmin_lb_sclk_sel.hw, - [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &axg_tdmout_a_sclk_sel.hw, - [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &axg_tdmout_b_sclk_sel.hw, - [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &axg_tdmout_c_sclk_sel.hw, - [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &axg_tdmin_a_sclk_pre_en.hw, - [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &axg_tdmin_b_sclk_pre_en.hw, - [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &axg_tdmin_c_sclk_pre_en.hw, - [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw, - [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw, - [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw, - [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw, - [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw, - [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw, - [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw, - [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw, - [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw, - [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw, - [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw, - [AUD_CLKID_TDMIN_A_SCLK] = &axg_tdmin_a_sclk.hw, - [AUD_CLKID_TDMIN_B_SCLK] = &axg_tdmin_b_sclk.hw, - [AUD_CLKID_TDMIN_C_SCLK] = &axg_tdmin_c_sclk.hw, - [AUD_CLKID_TDMIN_LB_SCLK] = &axg_tdmin_lb_sclk.hw, - [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, - [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, - [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, - [AUD_CLKID_TDMIN_A_LRCLK] = &axg_tdmin_a_lrclk.hw, - [AUD_CLKID_TDMIN_B_LRCLK] = &axg_tdmin_b_lrclk.hw, - [AUD_CLKID_TDMIN_C_LRCLK] = &axg_tdmin_c_lrclk.hw, - [AUD_CLKID_TDMIN_LB_LRCLK] = &axg_tdmin_lb_lrclk.hw, - [AUD_CLKID_TDMOUT_A_LRCLK] = &axg_tdmout_a_lrclk.hw, - [AUD_CLKID_TDMOUT_B_LRCLK] = &axg_tdmout_b_lrclk.hw, - [AUD_CLKID_TDMOUT_C_LRCLK] = &axg_tdmout_c_lrclk.hw, + [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw, + [AUD_CLKID_PDM] = &aud_pdm.hw, + [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw, + [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw, + [AUD_CLKID_TDMIN_C] = &aud_tdmin_c.hw, + [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw, + [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw, + [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw, + [AUD_CLKID_TDMOUT_C] = &aud_tdmout_c.hw, + [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw, + [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw, + [AUD_CLKID_FRDDR_C] = &aud_frddr_c.hw, + [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw, + [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw, + [AUD_CLKID_TODDR_C] = &aud_toddr_c.hw, + [AUD_CLKID_LOOPBACK] = &aud_loopback.hw, + [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw, + [AUD_CLKID_SPDIFOUT] = &aud_spdifout.hw, + [AUD_CLKID_RESAMPLE] = &aud_resample.hw, + [AUD_CLKID_POWER_DETECT] = &aud_power_detect.hw, + [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw, + [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw, + [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw, + [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw, + [AUD_CLKID_MST_E_MCLK_SEL] = &aud_mst_e_mclk_sel.hw, + [AUD_CLKID_MST_F_MCLK_SEL] = &aud_mst_f_mclk_sel.hw, + [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw, + [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw, + [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw, + [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw, + [AUD_CLKID_MST_E_MCLK_DIV] = &aud_mst_e_mclk_div.hw, + [AUD_CLKID_MST_F_MCLK_DIV] = &aud_mst_f_mclk_div.hw, + [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw, + [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw, + [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw, + [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw, + [AUD_CLKID_MST_E_MCLK] = &aud_mst_e_mclk.hw, + [AUD_CLKID_MST_F_MCLK] = &aud_mst_f_mclk.hw, + [AUD_CLKID_SPDIFOUT_CLK_SEL] = &aud_spdifout_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_CLK_DIV] = &aud_spdifout_clk_div.hw, + [AUD_CLKID_SPDIFOUT_CLK] = &aud_spdifout_clk.hw, + [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw, + [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw, + [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw, + [AUD_CLKID_PDM_DCLK_SEL] = &aud_pdm_dclk_sel.hw, + [AUD_CLKID_PDM_DCLK_DIV] = &aud_pdm_dclk_div.hw, + [AUD_CLKID_PDM_DCLK] = &aud_pdm_dclk.hw, + [AUD_CLKID_PDM_SYSCLK_SEL] = &aud_pdm_sysclk_sel.hw, + [AUD_CLKID_PDM_SYSCLK_DIV] = &aud_pdm_sysclk_div.hw, + [AUD_CLKID_PDM_SYSCLK] = &aud_pdm_sysclk.hw, + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw, + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw, + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw, + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw, + [AUD_CLKID_MST_E_SCLK_PRE_EN] = &aud_mst_e_sclk_pre_en.hw, + [AUD_CLKID_MST_F_SCLK_PRE_EN] = &aud_mst_f_sclk_pre_en.hw, + [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw, + [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw, + [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw, + [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw, + [AUD_CLKID_MST_E_SCLK_DIV] = &aud_mst_e_sclk_div.hw, + [AUD_CLKID_MST_F_SCLK_DIV] = &aud_mst_f_sclk_div.hw, + [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw, + [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw, + [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw, + [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw, + [AUD_CLKID_MST_E_SCLK_POST_EN] = &aud_mst_e_sclk_post_en.hw, + [AUD_CLKID_MST_F_SCLK_POST_EN] = &aud_mst_f_sclk_post_en.hw, + [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw, + [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw, + [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw, + [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw, + [AUD_CLKID_MST_E_SCLK] = &aud_mst_e_sclk.hw, + [AUD_CLKID_MST_F_SCLK] = &aud_mst_f_sclk.hw, + [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw, + [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw, + [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw, + [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw, + [AUD_CLKID_MST_E_LRCLK_DIV] = &aud_mst_e_lrclk_div.hw, + [AUD_CLKID_MST_F_LRCLK_DIV] = &aud_mst_f_lrclk_div.hw, + [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw, + [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw, + [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw, + [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw, + [AUD_CLKID_MST_E_LRCLK] = &aud_mst_e_lrclk.hw, + [AUD_CLKID_MST_F_LRCLK] = &aud_mst_f_lrclk.hw, + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw, + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw, + [AUD_CLKID_TDMIN_C_SCLK_SEL] = &aud_tdmin_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw, + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw, + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw, + [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &aud_tdmout_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &aud_tdmin_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &aud_tdmout_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &aud_tdmin_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &aud_tdmout_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw, + [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw, + [AUD_CLKID_TDMIN_C_SCLK] = &aud_tdmin_c_sclk.hw, + [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &aud_tdmout_c_sclk.hw, + [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw, + [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw, + [AUD_CLKID_TDMIN_C_LRCLK] = &aud_tdmin_c_lrclk.hw, + [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw, + [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw, + [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw, + [AUD_CLKID_TDMOUT_C_LRCLK] = &aud_tdmout_c_lrclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, }; -/* Convenience table to populate regmap in .probe() */ -static struct clk_regmap *const axg_audio_clk_regmaps[] = { - &axg_ddr_arb, - &axg_pdm, - &axg_tdmin_a, - &axg_tdmin_b, - &axg_tdmin_c, - &axg_tdmin_lb, - &axg_tdmout_a, - &axg_tdmout_b, - &axg_tdmout_c, - &axg_frddr_a, - &axg_frddr_b, - &axg_frddr_c, - &axg_toddr_a, - &axg_toddr_b, - &axg_toddr_c, - &axg_loopback, - &axg_spdifin, - &axg_spdifout, - &axg_resample, - &axg_power_detect, - &axg_mst_a_mclk_sel, - &axg_mst_b_mclk_sel, - &axg_mst_c_mclk_sel, - &axg_mst_d_mclk_sel, - &axg_mst_e_mclk_sel, - &axg_mst_f_mclk_sel, - &axg_mst_a_mclk_div, - &axg_mst_b_mclk_div, - &axg_mst_c_mclk_div, - &axg_mst_d_mclk_div, - &axg_mst_e_mclk_div, - &axg_mst_f_mclk_div, - &axg_mst_a_mclk, - &axg_mst_b_mclk, - &axg_mst_c_mclk, - &axg_mst_d_mclk, - &axg_mst_e_mclk, - &axg_mst_f_mclk, - &axg_spdifout_clk_sel, - &axg_spdifout_clk_div, - &axg_spdifout_clk, - &axg_spdifin_clk_sel, - &axg_spdifin_clk_div, - &axg_spdifin_clk, - &axg_pdm_dclk_sel, - &axg_pdm_dclk_div, - &axg_pdm_dclk, - &axg_pdm_sysclk_sel, - &axg_pdm_sysclk_div, - &axg_pdm_sysclk, - &axg_mst_a_sclk_pre_en, - &axg_mst_b_sclk_pre_en, - &axg_mst_c_sclk_pre_en, - &axg_mst_d_sclk_pre_en, - &axg_mst_e_sclk_pre_en, - &axg_mst_f_sclk_pre_en, - &axg_mst_a_sclk_div, - &axg_mst_b_sclk_div, - &axg_mst_c_sclk_div, - &axg_mst_d_sclk_div, - &axg_mst_e_sclk_div, - &axg_mst_f_sclk_div, - &axg_mst_a_sclk_post_en, - &axg_mst_b_sclk_post_en, - &axg_mst_c_sclk_post_en, - &axg_mst_d_sclk_post_en, - &axg_mst_e_sclk_post_en, - &axg_mst_f_sclk_post_en, - &axg_mst_a_sclk, - &axg_mst_b_sclk, - &axg_mst_c_sclk, - &axg_mst_d_sclk, - &axg_mst_e_sclk, - &axg_mst_f_sclk, - &axg_mst_a_lrclk_div, - &axg_mst_b_lrclk_div, - &axg_mst_c_lrclk_div, - &axg_mst_d_lrclk_div, - &axg_mst_e_lrclk_div, - &axg_mst_f_lrclk_div, - &axg_mst_a_lrclk, - &axg_mst_b_lrclk, - &axg_mst_c_lrclk, - &axg_mst_d_lrclk, - &axg_mst_e_lrclk, - &axg_mst_f_lrclk, - &axg_tdmin_a_sclk_sel, - &axg_tdmin_b_sclk_sel, - &axg_tdmin_c_sclk_sel, - &axg_tdmin_lb_sclk_sel, - &axg_tdmout_a_sclk_sel, - &axg_tdmout_b_sclk_sel, - &axg_tdmout_c_sclk_sel, - &axg_tdmin_a_sclk_pre_en, - &axg_tdmin_b_sclk_pre_en, - &axg_tdmin_c_sclk_pre_en, - &axg_tdmin_lb_sclk_pre_en, - &axg_tdmout_a_sclk_pre_en, - &axg_tdmout_b_sclk_pre_en, - &axg_tdmout_c_sclk_pre_en, - &axg_tdmin_a_sclk_post_en, - &axg_tdmin_b_sclk_post_en, - &axg_tdmin_c_sclk_post_en, - &axg_tdmin_lb_sclk_post_en, - &axg_tdmout_a_sclk_post_en, - &axg_tdmout_b_sclk_post_en, - &axg_tdmout_c_sclk_post_en, - &axg_tdmin_a_sclk, - &axg_tdmin_b_sclk, - &axg_tdmin_c_sclk, - &axg_tdmin_lb_sclk, - &axg_tdmout_a_sclk, - &axg_tdmout_b_sclk, - &axg_tdmout_c_sclk, - &axg_tdmin_a_lrclk, - &axg_tdmin_b_lrclk, - &axg_tdmin_c_lrclk, - &axg_tdmin_lb_lrclk, - &axg_tdmout_a_lrclk, - &axg_tdmout_b_lrclk, - &axg_tdmout_c_lrclk, +/* + * Array of all G12A clocks provided by this provider + * The input clocks of the controller will be populated at runtime + */ +static struct clk_hw_onecell_data g12a_audio_hw_onecell_data = { + .hws = { + [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw, + [AUD_CLKID_PDM] = &aud_pdm.hw, + [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw, + [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw, + [AUD_CLKID_TDMIN_C] = &aud_tdmin_c.hw, + [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw, + [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw, + [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw, + [AUD_CLKID_TDMOUT_C] = &aud_tdmout_c.hw, + [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw, + [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw, + [AUD_CLKID_FRDDR_C] = &aud_frddr_c.hw, + [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw, + [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw, + [AUD_CLKID_TODDR_C] = &aud_toddr_c.hw, + [AUD_CLKID_LOOPBACK] = &aud_loopback.hw, + [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw, + [AUD_CLKID_SPDIFOUT] = &aud_spdifout.hw, + [AUD_CLKID_RESAMPLE] = &aud_resample.hw, + [AUD_CLKID_POWER_DETECT] = &aud_power_detect.hw, + [AUD_CLKID_SPDIFOUT_B] = &aud_spdifout_b.hw, + [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw, + [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw, + [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw, + [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw, + [AUD_CLKID_MST_E_MCLK_SEL] = &aud_mst_e_mclk_sel.hw, + [AUD_CLKID_MST_F_MCLK_SEL] = &aud_mst_f_mclk_sel.hw, + [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw, + [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw, + [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw, + [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw, + [AUD_CLKID_MST_E_MCLK_DIV] = &aud_mst_e_mclk_div.hw, + [AUD_CLKID_MST_F_MCLK_DIV] = &aud_mst_f_mclk_div.hw, + [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw, + [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw, + [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw, + [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw, + [AUD_CLKID_MST_E_MCLK] = &aud_mst_e_mclk.hw, + [AUD_CLKID_MST_F_MCLK] = &aud_mst_f_mclk.hw, + [AUD_CLKID_SPDIFOUT_CLK_SEL] = &aud_spdifout_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_CLK_DIV] = &aud_spdifout_clk_div.hw, + [AUD_CLKID_SPDIFOUT_CLK] = &aud_spdifout_clk.hw, + [AUD_CLKID_SPDIFOUT_B_CLK_SEL] = &aud_spdifout_b_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_B_CLK_DIV] = &aud_spdifout_b_clk_div.hw, + [AUD_CLKID_SPDIFOUT_B_CLK] = &aud_spdifout_b_clk.hw, + [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw, + [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw, + [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw, + [AUD_CLKID_PDM_DCLK_SEL] = &aud_pdm_dclk_sel.hw, + [AUD_CLKID_PDM_DCLK_DIV] = &aud_pdm_dclk_div.hw, + [AUD_CLKID_PDM_DCLK] = &aud_pdm_dclk.hw, + [AUD_CLKID_PDM_SYSCLK_SEL] = &aud_pdm_sysclk_sel.hw, + [AUD_CLKID_PDM_SYSCLK_DIV] = &aud_pdm_sysclk_div.hw, + [AUD_CLKID_PDM_SYSCLK] = &aud_pdm_sysclk.hw, + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw, + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw, + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw, + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw, + [AUD_CLKID_MST_E_SCLK_PRE_EN] = &aud_mst_e_sclk_pre_en.hw, + [AUD_CLKID_MST_F_SCLK_PRE_EN] = &aud_mst_f_sclk_pre_en.hw, + [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw, + [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw, + [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw, + [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw, + [AUD_CLKID_MST_E_SCLK_DIV] = &aud_mst_e_sclk_div.hw, + [AUD_CLKID_MST_F_SCLK_DIV] = &aud_mst_f_sclk_div.hw, + [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw, + [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw, + [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw, + [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw, + [AUD_CLKID_MST_E_SCLK_POST_EN] = &aud_mst_e_sclk_post_en.hw, + [AUD_CLKID_MST_F_SCLK_POST_EN] = &aud_mst_f_sclk_post_en.hw, + [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw, + [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw, + [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw, + [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw, + [AUD_CLKID_MST_E_SCLK] = &aud_mst_e_sclk.hw, + [AUD_CLKID_MST_F_SCLK] = &aud_mst_f_sclk.hw, + [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw, + [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw, + [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw, + [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw, + [AUD_CLKID_MST_E_LRCLK_DIV] = &aud_mst_e_lrclk_div.hw, + [AUD_CLKID_MST_F_LRCLK_DIV] = &aud_mst_f_lrclk_div.hw, + [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw, + [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw, + [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw, + [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw, + [AUD_CLKID_MST_E_LRCLK] = &aud_mst_e_lrclk.hw, + [AUD_CLKID_MST_F_LRCLK] = &aud_mst_f_lrclk.hw, + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw, + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw, + [AUD_CLKID_TDMIN_C_SCLK_SEL] = &aud_tdmin_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw, + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw, + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw, + [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &aud_tdmout_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &aud_tdmin_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &aud_tdmout_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &aud_tdmin_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &aud_tdmout_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw, + [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw, + [AUD_CLKID_TDMIN_C_SCLK] = &aud_tdmin_c_sclk.hw, + [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &aud_tdmout_c_sclk.hw, + [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw, + [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw, + [AUD_CLKID_TDMIN_C_LRCLK] = &aud_tdmin_c_lrclk.hw, + [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw, + [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw, + [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw, + [AUD_CLKID_TDMOUT_C_LRCLK] = &aud_tdmout_c_lrclk.hw, + [AUD_CLKID_TDM_MCLK_PAD0] = &aud_tdm_mclk_pad_0.hw, + [AUD_CLKID_TDM_MCLK_PAD1] = &aud_tdm_mclk_pad_1.hw, + [AUD_CLKID_TDM_LRCLK_PAD0] = &aud_tdm_lrclk_pad_0.hw, + [AUD_CLKID_TDM_LRCLK_PAD1] = &aud_tdm_lrclk_pad_1.hw, + [AUD_CLKID_TDM_LRCLK_PAD2] = &aud_tdm_lrclk_pad_2.hw, + [AUD_CLKID_TDM_SCLK_PAD0] = &aud_tdm_sclk_pad_0.hw, + [AUD_CLKID_TDM_SCLK_PAD1] = &aud_tdm_sclk_pad_1.hw, + [AUD_CLKID_TDM_SCLK_PAD2] = &aud_tdm_sclk_pad_2.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +}; + +/* Convenience table to populate regmap in .probe() + * Note that this table is shared between both AXG and G12A, + * with spdifout_b clocks being exclusive to G12A. Since those + * clocks are not declared within the AXG onecell table, we do not + * feel the need to have separate AXG/G12A regmap tables. + */ +static struct clk_regmap *const aud_clk_regmaps[] = { + &aud_ddr_arb, + &aud_pdm, + &aud_tdmin_a, + &aud_tdmin_b, + &aud_tdmin_c, + &aud_tdmin_lb, + &aud_tdmout_a, + &aud_tdmout_b, + &aud_tdmout_c, + &aud_frddr_a, + &aud_frddr_b, + &aud_frddr_c, + &aud_toddr_a, + &aud_toddr_b, + &aud_toddr_c, + &aud_loopback, + &aud_spdifin, + &aud_spdifout, + &aud_resample, + &aud_power_detect, + &aud_spdifout_b, + &aud_mst_a_mclk_sel, + &aud_mst_b_mclk_sel, + &aud_mst_c_mclk_sel, + &aud_mst_d_mclk_sel, + &aud_mst_e_mclk_sel, + &aud_mst_f_mclk_sel, + &aud_mst_a_mclk_div, + &aud_mst_b_mclk_div, + &aud_mst_c_mclk_div, + &aud_mst_d_mclk_div, + &aud_mst_e_mclk_div, + &aud_mst_f_mclk_div, + &aud_mst_a_mclk, + &aud_mst_b_mclk, + &aud_mst_c_mclk, + &aud_mst_d_mclk, + &aud_mst_e_mclk, + &aud_mst_f_mclk, + &aud_spdifout_clk_sel, + &aud_spdifout_clk_div, + &aud_spdifout_clk, + &aud_spdifin_clk_sel, + &aud_spdifin_clk_div, + &aud_spdifin_clk, + &aud_pdm_dclk_sel, + &aud_pdm_dclk_div, + &aud_pdm_dclk, + &aud_pdm_sysclk_sel, + &aud_pdm_sysclk_div, + &aud_pdm_sysclk, + &aud_mst_a_sclk_pre_en, + &aud_mst_b_sclk_pre_en, + &aud_mst_c_sclk_pre_en, + &aud_mst_d_sclk_pre_en, + &aud_mst_e_sclk_pre_en, + &aud_mst_f_sclk_pre_en, + &aud_mst_a_sclk_div, + &aud_mst_b_sclk_div, + &aud_mst_c_sclk_div, + &aud_mst_d_sclk_div, + &aud_mst_e_sclk_div, + &aud_mst_f_sclk_div, + &aud_mst_a_sclk_post_en, + &aud_mst_b_sclk_post_en, + &aud_mst_c_sclk_post_en, + &aud_mst_d_sclk_post_en, + &aud_mst_e_sclk_post_en, + &aud_mst_f_sclk_post_en, + &aud_mst_a_sclk, + &aud_mst_b_sclk, + &aud_mst_c_sclk, + &aud_mst_d_sclk, + &aud_mst_e_sclk, + &aud_mst_f_sclk, + &aud_mst_a_lrclk_div, + &aud_mst_b_lrclk_div, + &aud_mst_c_lrclk_div, + &aud_mst_d_lrclk_div, + &aud_mst_e_lrclk_div, + &aud_mst_f_lrclk_div, + &aud_mst_a_lrclk, + &aud_mst_b_lrclk, + &aud_mst_c_lrclk, + &aud_mst_d_lrclk, + &aud_mst_e_lrclk, + &aud_mst_f_lrclk, + &aud_tdmin_a_sclk_sel, + &aud_tdmin_b_sclk_sel, + &aud_tdmin_c_sclk_sel, + &aud_tdmin_lb_sclk_sel, + &aud_tdmout_a_sclk_sel, + &aud_tdmout_b_sclk_sel, + &aud_tdmout_c_sclk_sel, + &aud_tdmin_a_sclk_pre_en, + &aud_tdmin_b_sclk_pre_en, + &aud_tdmin_c_sclk_pre_en, + &aud_tdmin_lb_sclk_pre_en, + &aud_tdmout_a_sclk_pre_en, + &aud_tdmout_b_sclk_pre_en, + &aud_tdmout_c_sclk_pre_en, + &aud_tdmin_a_sclk_post_en, + &aud_tdmin_b_sclk_post_en, + &aud_tdmin_c_sclk_post_en, + &aud_tdmin_lb_sclk_post_en, + &aud_tdmout_a_sclk_post_en, + &aud_tdmout_b_sclk_post_en, + &aud_tdmout_c_sclk_post_en, + &aud_tdmin_a_sclk, + &aud_tdmin_b_sclk, + &aud_tdmin_c_sclk, + &aud_tdmin_lb_sclk, + &aud_tdmout_a_sclk, + &aud_tdmout_b_sclk, + &aud_tdmout_c_sclk, + &aud_tdmin_a_lrclk, + &aud_tdmin_b_lrclk, + &aud_tdmin_c_lrclk, + &aud_tdmin_lb_lrclk, + &aud_tdmout_a_lrclk, + &aud_tdmout_b_lrclk, + &aud_tdmout_c_lrclk, + &aud_spdifout_b_clk_sel, + &aud_spdifout_b_clk_div, + &aud_spdifout_b_clk, + &aud_tdm_mclk_pad_0, + &aud_tdm_mclk_pad_1, + &aud_tdm_lrclk_pad_0, + &aud_tdm_lrclk_pad_1, + &aud_tdm_lrclk_pad_2, + &aud_tdm_sclk_pad_0, + &aud_tdm_sclk_pad_1, + &aud_tdm_sclk_pad_2, }; static int devm_clk_get_enable(struct device *dev, char *id) @@ -665,14 +869,13 @@ static int devm_clk_get_enable(struct device *dev, char *id) } static int axg_register_clk_hw_input(struct device *dev, - const char *name, - unsigned int clkid) + const char *name) { char *clk_name; struct clk_hw *hw; int err = 0; - clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); + clk_name = kasprintf(GFP_KERNEL, "aud_%s", name); if (!clk_name) return -ENOMEM; @@ -686,8 +889,6 @@ static int axg_register_clk_hw_input(struct device *dev, if (err != -EPROBE_DEFER) dev_err(dev, "failed to get %s clock", name); } - } else { - axg_audio_hw_onecell_data.hws[clkid] = hw; } kfree(clk_name); @@ -696,8 +897,7 @@ static int axg_register_clk_hw_input(struct device *dev, static int axg_register_clk_hw_inputs(struct device *dev, const char *basename, - unsigned int count, - unsigned int clkid) + unsigned int count) { char *name; int i, ret; @@ -707,7 +907,7 @@ static int axg_register_clk_hw_inputs(struct device *dev, if (!name) return -ENOMEM; - ret = axg_register_clk_hw_input(dev, name, clkid + i); + ret = axg_register_clk_hw_input(dev, name); kfree(name); if (ret) return ret; @@ -723,15 +923,24 @@ static const struct regmap_config axg_audio_regmap_cfg = { .max_register = AUDIO_CLK_PDMIN_CTRL1, }; +struct audioclk_data { + struct clk_hw_onecell_data *hw_onecell_data; +}; + static int axg_audio_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct audioclk_data *data; struct regmap *map; struct resource *res; void __iomem *regs; struct clk_hw *hw; int ret, i; + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) @@ -755,40 +964,35 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) } /* Register the peripheral input clock */ - hw = meson_clk_hw_register_input(dev, "pclk", "axg_audio_pclk", 0); + hw = meson_clk_hw_register_input(dev, "pclk", "audio_pclk", 0); if (IS_ERR(hw)) return PTR_ERR(hw); - axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw; - /* Register optional input master clocks */ ret = axg_register_clk_hw_inputs(dev, "mst_in", - AXG_MST_IN_COUNT, - AUD_CLKID_MST0); + AUD_MST_IN_COUNT); if (ret) return ret; /* Register optional input slave sclks */ ret = axg_register_clk_hw_inputs(dev, "slv_sclk", - AXG_SLV_SCLK_COUNT, - AUD_CLKID_SLV_SCLK0); + AUD_SLV_SCLK_COUNT); if (ret) return ret; /* Register optional input slave lrclks */ ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", - AXG_SLV_LRCLK_COUNT, - AUD_CLKID_SLV_LRCLK0); + AUD_SLV_LRCLK_COUNT); if (ret) return ret; /* Populate regmap for the regmap backed clocks */ - for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++) - axg_audio_clk_regmaps[i]->map = map; + for (i = 0; i < ARRAY_SIZE(aud_clk_regmaps); i++) + aud_clk_regmaps[i]->map = map; /* Take care to skip the registered input clocks */ - for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { - hw = axg_audio_hw_onecell_data.hws[i]; + for (i = AUD_CLKID_DDR_ARB; i < data->hw_onecell_data->num; i++) { + hw = data->hw_onecell_data->hws[i]; /* array might be sparse */ if (!hw) continue; @@ -802,12 +1006,25 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) } return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - &axg_audio_hw_onecell_data); + data->hw_onecell_data); } +static const struct audioclk_data axg_audioclk_data = { + .hw_onecell_data = &axg_audio_hw_onecell_data, +}; + +static const struct audioclk_data g12a_audioclk_data = { + .hw_onecell_data = &g12a_audio_hw_onecell_data, +}; + static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,axg-audio-clkc" }, - {} + { + .compatible = "amlogic,axg-audio-clkc", + .data = &axg_audioclk_data + }, { + .compatible = "amlogic,g12a-audio-clkc", + .data = &g12a_audioclk_data + }, {} }; MODULE_DEVICE_TABLE(of, clkc_match_table); @@ -820,6 +1037,6 @@ static struct platform_driver axg_audio_driver = { }; module_platform_driver(axg_audio_driver); -MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver"); +MODULE_DESCRIPTION("Amlogic AXG/G12A Audio Clock driver"); MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h index 7191b39c9d65..5d972d55d6c7 100644 --- a/drivers/clk/meson/axg-audio.h +++ b/drivers/clk/meson/axg-audio.h @@ -20,6 +20,8 @@ #define AUDIO_MCLK_D_CTRL 0x010 #define AUDIO_MCLK_E_CTRL 0x014 #define AUDIO_MCLK_F_CTRL 0x018 +#define AUDIO_MST_PAD_CTRL0 0x01c +#define AUDIO_MST_PAD_CTRL1 0x020 #define AUDIO_MST_A_SCLK_CTRL0 0x040 #define AUDIO_MST_A_SCLK_CTRL1 0x044 #define AUDIO_MST_B_SCLK_CTRL0 0x048 @@ -45,21 +47,13 @@ #define AUDIO_CLK_LOCKER_CTRL 0x0A8 #define AUDIO_CLK_PDMIN_CTRL0 0x0AC #define AUDIO_CLK_PDMIN_CTRL1 0x0B0 +#define AUDIO_CLK_SPDIFOUT_B_CTRL 0x0B4 /* * CLKID index values * These indices are entirely contrived and do not map onto the hardware. */ -#define AUD_CLKID_PCLK 0 -#define AUD_CLKID_MST0 1 -#define AUD_CLKID_MST1 2 -#define AUD_CLKID_MST2 3 -#define AUD_CLKID_MST3 4 -#define AUD_CLKID_MST4 5 -#define AUD_CLKID_MST5 6 -#define AUD_CLKID_MST6 7 -#define AUD_CLKID_MST7 8 #define AUD_CLKID_MST_A_MCLK_SEL 59 #define AUD_CLKID_MST_B_MCLK_SEL 60 #define AUD_CLKID_MST_C_MCLK_SEL 61 @@ -118,10 +112,12 @@ #define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 148 #define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 149 #define AUD_CLKID_TDMOUT_C_SCLK_POST_EN 150 +#define AUD_CLKID_SPDIFOUT_B_CLK_SEL 153 +#define AUD_CLKID_SPDIFOUT_B_CLK_DIV 154 /* include the CLKIDs which are part of the DT bindings */ #include <dt-bindings/clock/axg-audio-clkc.h> -#define NR_CLKS 151 +#define NR_CLKS 163 #endif /*__AXG_AUDIO_CLKC_H */ diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 7a14ac9b2fec..ddb1e5634739 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -303,6 +303,16 @@ static int meson_clk_pll_is_enabled(struct clk_hw *hw) return 1; } +static int meson_clk_pcie_pll_enable(struct clk_hw *hw) +{ + meson_clk_pll_init(hw); + + if (meson_clk_pll_wait_lock(hw)) + return -EIO; + + return 0; +} + static int meson_clk_pll_enable(struct clk_hw *hw) { struct clk_regmap *clk = to_clk_regmap(hw); @@ -387,6 +397,22 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +/* + * The Meson G12A PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + * To simplify, re-use the _init() op to enable the PLL and keep + * the other ops except set_rate since the rate is fixed. + */ +const struct clk_ops meson_clk_pcie_pll_ops = { + .recalc_rate = meson_clk_pll_recalc_rate, + .round_rate = meson_clk_pll_round_rate, + .is_enabled = meson_clk_pll_is_enabled, + .enable = meson_clk_pcie_pll_enable, + .disable = meson_clk_pll_disable +}; +EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops); + const struct clk_ops meson_clk_pll_ops = { .init = meson_clk_pll_init, .recalc_rate = meson_clk_pll_recalc_rate, diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h index 55af2e285b1b..367efd0f6410 100644 --- a/drivers/clk/meson/clk-pll.h +++ b/drivers/clk/meson/clk-pll.h @@ -45,5 +45,6 @@ struct meson_clk_pll_data { extern const struct clk_ops meson_clk_pll_ro_ops; extern const struct clk_ops meson_clk_pll_ops; +extern const struct clk_ops meson_clk_pcie_pll_ops; #endif /* __MESON_CLK_PLL_H */ diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h index 04b0d5506641..a67c8a7cd7c4 100644 --- a/drivers/clk/meson/g12a-aoclk.h +++ b/drivers/clk/meson/g12a-aoclk.h @@ -16,9 +16,7 @@ * to expose, such as the internal muxes and dividers of composite clocks, * will remain defined here. */ -#define CLKID_AO_SAR_ADC_SEL 16 #define CLKID_AO_SAR_ADC_DIV 17 -#define CLKID_AO_CTS_OSCIN 19 #define CLKID_AO_32K_PRE 20 #define CLKID_AO_32K_DIV 21 #define CLKID_AO_32K_SEL 22 diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index f7b11e1eeebe..739f64fdf1e3 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -150,6 +150,318 @@ static struct clk_regmap g12a_sys_pll = { }, }; +static struct clk_regmap g12a_sys_pll_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "sys_pll_div16_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "sys_pll" }, + .num_parents = 1, + /* + * This clock is used to debug the sys_pll range + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_fixed_factor g12a_sys_pll_div16 = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_div16", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "sys_pll_div16_en" }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "premux0" */ +static struct clk_regmap g12a_cpu_clk_premux0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal", + "fclk_div2", + "fclk_div3" }, + .num_parents = 3, + }, +}; + +/* Datasheet names this field as "mux0_divn_tcnt" */ +static struct clk_regmap g12a_cpu_clk_mux0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .shift = 4, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_dyn0_sel" }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux0" */ +static struct clk_regmap g12a_cpu_clk_postmux0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_dyn0_sel", + "cpu_clk_dyn0_div" }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "premux1" */ +static struct clk_regmap g12a_cpu_clk_premux1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal", + "fclk_div2", + "fclk_div3" }, + .num_parents = 3, + }, +}; + +/* Datasheet names this field as "Mux1_divn_tcnt" */ +static struct clk_regmap g12a_cpu_clk_mux1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .shift = 20, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_dyn1_sel" }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux1" */ +static struct clk_regmap g12a_cpu_clk_postmux1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_dyn1_sel", + "cpu_clk_dyn1_div" }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "Final_dyn_mux_sel" */ +static struct clk_regmap g12a_cpu_clk_dyn = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_dyn0", + "cpu_clk_dyn1" }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "Final_mux_sel" */ +static struct clk_regmap g12a_cpu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_dyn", + "sys_pll" }, + .num_parents = 2, + }, +}; + +static struct clk_regmap g12a_cpu_clk_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_div16_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cpu_clk" }, + .num_parents = 1, + /* + * This clock is used to debug the cpu_clk range + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_fixed_factor g12a_cpu_clk_div16 = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div16", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "cpu_clk_div16_en" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_apb_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 3, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_apb_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_clk" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_apb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_apb", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_apb_div" }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12a_cpu_clk_atb_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 6, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_atb_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_clk" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_atb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 17, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_atb", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_atb_div" }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12a_cpu_clk_axi_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 9, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_axi_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_clk" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_axi = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 18, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_axi", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_axi_div" }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12a_cpu_clk_trace_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 20, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_trace_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_clk" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_trace = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_trace", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cpu_clk_trace_div" }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + static const struct pll_mult_range g12a_gp0_pll_mult_range = { .min = 55, .max = 255, @@ -302,6 +614,118 @@ static struct clk_regmap g12a_hifi_pll = { }, }; +/* + * The Meson G12A PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + */ +static const struct reg_sequence g12a_pcie_pll_init_regs[] = { + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x20090496 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x30090496 }, + { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001100 }, + { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x10058e00 }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x000100c0 }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000048 }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000068, .delay_us = 20 }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x008100c0, .delay_us = 10 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x34090496 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x14090496, .delay_us = 10 }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001000 }, +}; + +/* Keep a single entry table for recalc/round_rate() ops */ +static const struct pll_params_table g12a_pcie_pll_table[] = { + PLL_PARAMS(150, 1), + {0, 0}, +}; + +static struct clk_regmap g12a_pcie_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_PCIE_PLL_CNTL1, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .table = g12a_pcie_pll_table, + .init_regs = g12a_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_pcie_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pcie_pll_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pcie_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL0, + .shift = 16, + .width = 5, + .flags = CLK_DIVIDER_ROUND_CLOSEST | + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_dco_div2" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_pcie_pll = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_pll", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pcie_pll_od" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap g12a_hdmi_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { @@ -1071,6 +1495,151 @@ static struct clk_regmap g12a_vpu = { }, }; +/* VDEC clocks */ + +static const char * const g12a_vdec_parent_names[] = { + "fclk_div2p5", "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", + "hifi_pll", "gp0_pll", +}; + +static struct clk_regmap g12a_vdec_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vdec_parent_names, + .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevcf_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevcf_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vdec_parent_names, + .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevcf_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevcf_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_hevcf_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevcf = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevcf", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_hevcf_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vdec_parent_names, + .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_hevc_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevc = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_hevc_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* VAPB Clock */ static const char * const g12a_vapb_parent_names[] = { @@ -2167,6 +2736,39 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { [CLKID_MALI] = &g12a_mali.hw, [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, + [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, + [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, + [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, + [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, + [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, + [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, + [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, + [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, + [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, + [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, + [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, + [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, + [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, + [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, + [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, + [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, + [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, + [CLKID_VDEC_1] = &g12a_vdec_1.hw, + [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, + [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, + [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, + [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -2335,6 +2937,35 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12a_mali_1, &g12a_mali, &g12a_mpll_50m, + &g12a_sys_pll_div16_en, + &g12a_cpu_clk_premux0, + &g12a_cpu_clk_mux0_div, + &g12a_cpu_clk_postmux0, + &g12a_cpu_clk_premux1, + &g12a_cpu_clk_mux1_div, + &g12a_cpu_clk_postmux1, + &g12a_cpu_clk_dyn, + &g12a_cpu_clk, + &g12a_cpu_clk_div16_en, + &g12a_cpu_clk_apb_div, + &g12a_cpu_clk_apb, + &g12a_cpu_clk_atb_div, + &g12a_cpu_clk_atb, + &g12a_cpu_clk_axi_div, + &g12a_cpu_clk_axi, + &g12a_cpu_clk_trace_div, + &g12a_cpu_clk_trace, + &g12a_pcie_pll_od, + &g12a_pcie_pll_dco, + &g12a_vdec_1_sel, + &g12a_vdec_1_div, + &g12a_vdec_1, + &g12a_vdec_hevc_sel, + &g12a_vdec_hevc_div, + &g12a_vdec_hevc, + &g12a_vdec_hevcf_sel, + &g12a_vdec_hevcf_div, + &g12a_vdec_hevcf, }; static const struct meson_eeclkc_data g12a_clkc_data = { diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index f399dfe1401c..39c41af70804 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -50,6 +50,7 @@ #define HHI_GCLK_MPEG2 0x148 #define HHI_GCLK_OTHER 0x150 #define HHI_GCLK_OTHER2 0x154 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c #define HHI_VID_CLK_DIV 0x164 #define HHI_MPEG_CLK_CNTL 0x174 #define HHI_AUD_CLK_CNTL 0x178 @@ -166,8 +167,36 @@ #define CLKID_MALI_0_DIV 170 #define CLKID_MALI_1_DIV 173 #define CLKID_MPLL_5OM_DIV 176 +#define CLKID_SYS_PLL_DIV16_EN 178 +#define CLKID_SYS_PLL_DIV16 179 +#define CLKID_CPU_CLK_DYN0_SEL 180 +#define CLKID_CPU_CLK_DYN0_DIV 181 +#define CLKID_CPU_CLK_DYN0 182 +#define CLKID_CPU_CLK_DYN1_SEL 183 +#define CLKID_CPU_CLK_DYN1_DIV 184 +#define CLKID_CPU_CLK_DYN1 185 +#define CLKID_CPU_CLK_DYN 186 +#define CLKID_CPU_CLK_DIV16_EN 188 +#define CLKID_CPU_CLK_DIV16 189 +#define CLKID_CPU_CLK_APB_DIV 190 +#define CLKID_CPU_CLK_APB 191 +#define CLKID_CPU_CLK_ATB_DIV 192 +#define CLKID_CPU_CLK_ATB 193 +#define CLKID_CPU_CLK_AXI_DIV 194 +#define CLKID_CPU_CLK_AXI 195 +#define CLKID_CPU_CLK_TRACE_DIV 196 +#define CLKID_CPU_CLK_TRACE 197 +#define CLKID_PCIE_PLL_DCO 198 +#define CLKID_PCIE_PLL_DCO_DIV2 199 +#define CLKID_PCIE_PLL_OD 200 +#define CLKID_VDEC_1_SEL 202 +#define CLKID_VDEC_1_DIV 203 +#define CLKID_VDEC_HEVC_SEL 205 +#define CLKID_VDEC_HEVC_DIV 206 +#define CLKID_VDEC_HEVCF_SEL 208 +#define CLKID_VDEC_HEVCF_DIV 209 -#define NR_CLKS 178 +#define NR_CLKS 211 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/g12a-clkc.h> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 576ad42252d0..37cf0f01bb5d 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1703,6 +1703,456 @@ static struct clk_regmap meson8b_mali = { }, }; +static const struct pll_params_table meson8m2_gp_pll_params_table[] = { + PLL_PARAMS(182, 3), + { /* sentinel */ }, +}; + +static struct clk_regmap meson8m2_gp_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = meson8m2_gp_pll_params_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8m2_gp_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const char * const mmeson8b_vpu_0_1_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +}; + +static const char * const mmeson8m2_vpu_0_1_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "gp_pll" +}; + +static struct clk_regmap meson8b_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = mmeson8b_vpu_0_1_parent_names, + .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8m2_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = mmeson8m2_vpu_0_1_parent_names, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vpu_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vpu_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = mmeson8b_vpu_0_1_parent_names, + .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8m2_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = mmeson8m2_vpu_0_1_parent_names, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vpu_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vpu_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static const char * const meson8b_vdec_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "mpll2", "mpll1" +}; + +static struct clk_regmap meson8b_vdec_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_vdec_parent_names, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_1_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC3_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_2_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC3_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1_2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_1_2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC3_CLK_CNTL, + .mask = 0x1, + .shift = 15, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "vdec_1_1", "vdec_1_2" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hcodec_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x3, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hcodec_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_vdec_parent_names, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hcodec_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hcodec_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_hcodec_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hcodec = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hcodec", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_hcodec_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_2_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_vdec_parent_names, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_2_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_2_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x3, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_vdec_parent_names, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vdec_hevc_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc_en", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vdec_hevc_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc", + .ops = &clk_regmap_mux_ops, + /* TODO: The second parent is currently unknown */ + .parent_names = (const char *[]){ "vdec_hevc_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); @@ -1966,6 +2416,22 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = { [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, [CLKID_MALI] = &meson8b_mali_0.hw, + [CLKID_VPU_0_SEL] = &meson8b_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &meson8b_vpu_0_div.hw, + [CLKID_VPU] = &meson8b_vpu_0.hw, + [CLKID_VDEC_1_SEL] = &meson8b_vdec_1_sel.hw, + [CLKID_VDEC_1_1_DIV] = &meson8b_vdec_1_1_div.hw, + [CLKID_VDEC_1] = &meson8b_vdec_1_1.hw, + [CLKID_VDEC_HCODEC_SEL] = &meson8b_vdec_hcodec_sel.hw, + [CLKID_VDEC_HCODEC_DIV] = &meson8b_vdec_hcodec_div.hw, + [CLKID_VDEC_HCODEC] = &meson8b_vdec_hcodec.hw, + [CLKID_VDEC_2_SEL] = &meson8b_vdec_2_sel.hw, + [CLKID_VDEC_2_DIV] = &meson8b_vdec_2_div.hw, + [CLKID_VDEC_2] = &meson8b_vdec_2.hw, + [CLKID_VDEC_HEVC_SEL] = &meson8b_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw, + [CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -2152,6 +2618,240 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MALI_1_DIV] = &meson8b_mali_1_div.hw, [CLKID_MALI_1] = &meson8b_mali_1.hw, [CLKID_MALI] = &meson8b_mali.hw, + [CLKID_VPU_0_SEL] = &meson8b_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &meson8b_vpu_0_div.hw, + [CLKID_VPU_0] = &meson8b_vpu_0.hw, + [CLKID_VPU_1_SEL] = &meson8b_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &meson8b_vpu_1_div.hw, + [CLKID_VPU_1] = &meson8b_vpu_1.hw, + [CLKID_VPU] = &meson8b_vpu.hw, + [CLKID_VDEC_1_SEL] = &meson8b_vdec_1_sel.hw, + [CLKID_VDEC_1_1_DIV] = &meson8b_vdec_1_1_div.hw, + [CLKID_VDEC_1_1] = &meson8b_vdec_1_1.hw, + [CLKID_VDEC_1_2_DIV] = &meson8b_vdec_1_2_div.hw, + [CLKID_VDEC_1_2] = &meson8b_vdec_1_2.hw, + [CLKID_VDEC_1] = &meson8b_vdec_1.hw, + [CLKID_VDEC_HCODEC_SEL] = &meson8b_vdec_hcodec_sel.hw, + [CLKID_VDEC_HCODEC_DIV] = &meson8b_vdec_hcodec_div.hw, + [CLKID_VDEC_HCODEC] = &meson8b_vdec_hcodec.hw, + [CLKID_VDEC_2_SEL] = &meson8b_vdec_2_sel.hw, + [CLKID_VDEC_2_DIV] = &meson8b_vdec_2_div.hw, + [CLKID_VDEC_2] = &meson8b_vdec_2.hw, + [CLKID_VDEC_HEVC_SEL] = &meson8b_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw, + [CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw, + [CLK_NR_CLKS] = NULL, + }, + .num = CLK_NR_CLKS, +}; + +static struct clk_hw_onecell_data meson8m2_hw_onecell_data = { + .hws = { + [CLKID_XTAL] = &meson8b_xtal.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_IN_DIV2] = &meson8b_cpu_in_div2.hw, + [CLKID_CPU_IN_DIV3] = &meson8b_cpu_in_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, + [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, + [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, + [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, + [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, + [CLKID_CPU_CLK_DIV4] = &meson8b_cpu_clk_div4.hw, + [CLKID_CPU_CLK_DIV5] = &meson8b_cpu_clk_div5.hw, + [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, + [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, + [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, + [CLKID_APB_SEL] = &meson8b_apb_clk_sel.hw, + [CLKID_APB] = &meson8b_apb_clk_gate.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, + [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, + [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, + [CLKID_AXI] = &meson8b_axi_clk_gate.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI_0] = &meson8b_mali_0.hw, + [CLKID_MALI_1_SEL] = &meson8b_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &meson8b_mali_1_div.hw, + [CLKID_MALI_1] = &meson8b_mali_1.hw, + [CLKID_MALI] = &meson8b_mali.hw, + [CLKID_GP_PLL_DCO] = &meson8m2_gp_pll_dco.hw, + [CLKID_GP_PLL] = &meson8m2_gp_pll.hw, + [CLKID_VPU_0_SEL] = &meson8m2_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &meson8b_vpu_0_div.hw, + [CLKID_VPU_0] = &meson8b_vpu_0.hw, + [CLKID_VPU_1_SEL] = &meson8m2_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &meson8b_vpu_1_div.hw, + [CLKID_VPU_1] = &meson8b_vpu_1.hw, + [CLKID_VPU] = &meson8b_vpu.hw, + [CLKID_VDEC_1_SEL] = &meson8b_vdec_1_sel.hw, + [CLKID_VDEC_1_1_DIV] = &meson8b_vdec_1_1_div.hw, + [CLKID_VDEC_1_1] = &meson8b_vdec_1_1.hw, + [CLKID_VDEC_1_2_DIV] = &meson8b_vdec_1_2_div.hw, + [CLKID_VDEC_1_2] = &meson8b_vdec_1_2.hw, + [CLKID_VDEC_1] = &meson8b_vdec_1.hw, + [CLKID_VDEC_HCODEC_SEL] = &meson8b_vdec_hcodec_sel.hw, + [CLKID_VDEC_HCODEC_DIV] = &meson8b_vdec_hcodec_div.hw, + [CLKID_VDEC_HCODEC] = &meson8b_vdec_hcodec.hw, + [CLKID_VDEC_2_SEL] = &meson8b_vdec_2_sel.hw, + [CLKID_VDEC_2_DIV] = &meson8b_vdec_2_div.hw, + [CLKID_VDEC_2] = &meson8b_vdec_2.hw, + [CLKID_VDEC_HEVC_SEL] = &meson8b_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw, + [CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -2314,6 +3014,33 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_mali_1_div, &meson8b_mali_1, &meson8b_mali, + &meson8m2_gp_pll_dco, + &meson8m2_gp_pll, + &meson8b_vpu_0_sel, + &meson8m2_vpu_0_sel, + &meson8b_vpu_0_div, + &meson8b_vpu_0, + &meson8b_vpu_1_sel, + &meson8m2_vpu_1_sel, + &meson8b_vpu_1_div, + &meson8b_vpu_1, + &meson8b_vpu, + &meson8b_vdec_1_sel, + &meson8b_vdec_1_1_div, + &meson8b_vdec_1_1, + &meson8b_vdec_1_2_div, + &meson8b_vdec_1_2, + &meson8b_vdec_1, + &meson8b_vdec_hcodec_sel, + &meson8b_vdec_hcodec_div, + &meson8b_vdec_hcodec, + &meson8b_vdec_2_sel, + &meson8b_vdec_2_div, + &meson8b_vdec_2, + &meson8b_vdec_hevc_sel, + &meson8b_vdec_hevc_div, + &meson8b_vdec_hevc_en, + &meson8b_vdec_hevc, }; static const struct meson8b_clk_reset_line { @@ -2558,9 +3285,14 @@ static void __init meson8b_clkc_init(struct device_node *np) return meson8b_clkc_init_common(np, &meson8b_hw_onecell_data); } +static void __init meson8m2_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8m2_hw_onecell_data); +} + CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", meson8_clkc_init); CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", - meson8b_clkc_init); + meson8m2_clkc_init); diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index b8c58faeae52..ed37196187e6 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -19,6 +19,7 @@ * * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf */ +#define HHI_GP_PLL_CNTL 0x40 /* 0x10 offset in data sheet */ #define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ #define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ #define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ @@ -34,7 +35,11 @@ #define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ #define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in data sheet */ +#define HHI_VPU_CLK_CNTL 0x1bc /* 0x6f offset in data sheet */ #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ +#define HHI_VDEC_CLK_CNTL 0x1e0 /* 0x78 offset in data sheet */ +#define HHI_VDEC2_CLK_CNTL 0x1e4 /* 0x79 offset in data sheet */ +#define HHI_VDEC3_CLK_CNTL 0x1e8 /* 0x7a offset in data sheet */ #define HHI_NAND_CLK_CNTL 0x25c /* 0x97 offset in data sheet */ #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ @@ -146,8 +151,28 @@ #define CLKID_MALI_1_SEL 178 #define CLKID_MALI_1_DIV 179 #define CLKID_MALI_1 180 +#define CLKID_GP_PLL_DCO 181 +#define CLKID_GP_PLL 182 +#define CLKID_VPU_0_SEL 183 +#define CLKID_VPU_0_DIV 184 +#define CLKID_VPU_0 185 +#define CLKID_VPU_1_SEL 186 +#define CLKID_VPU_1_DIV 187 +#define CLKID_VPU_1 189 +#define CLKID_VDEC_1_SEL 191 +#define CLKID_VDEC_1_1_DIV 192 +#define CLKID_VDEC_1_1 193 +#define CLKID_VDEC_1_2_DIV 194 +#define CLKID_VDEC_1_2 195 +#define CLKID_VDEC_HCODEC_SEL 197 +#define CLKID_VDEC_HCODEC_DIV 198 +#define CLKID_VDEC_2_SEL 200 +#define CLKID_VDEC_2_DIV 201 +#define CLKID_VDEC_HEVC_SEL 203 +#define CLKID_VDEC_HEVC_DIV 204 +#define CLKID_VDEC_HEVC_EN 205 -#define CLK_NR_CLKS 181 +#define CLK_NR_CLKS 207 /* * include the CLKID and RESETID that have diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c index 7355595c42e2..1755916ddef2 100644 --- a/drivers/clk/mmp/clk-gate.c +++ b/drivers/clk/mmp/clk-gate.c @@ -108,7 +108,7 @@ struct clk *mmp_clk_register_gate(struct device *dev, const char *name, init.name = name; init.ops = &mmp_clk_gate_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = (parent_name ? &parent_name : NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 6ab3c2e627c7..785dbede4835 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -240,7 +240,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np, int n; if (ctrl) { - pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n"); + pr_err("mvebu-clk-gating: cannot instantiate more than one gateable clock device\n"); return; } diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index 9235a331b588..b6de283f45e3 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -21,7 +21,7 @@ * - Equal to SDIO clock * - 2/5 PLL0 * - * CP110 has 32 gatable clocks, for the various peripherals in the IP. + * CP110 has 32 gateable clocks, for the various peripherals in the IP. */ #define pr_fmt(fmt) "cp110-system-controller: " fmt @@ -57,7 +57,7 @@ enum { #define CP110_CORE_NAND 4 #define CP110_CORE_SDIO 5 -/* A number of gatable clocks need special handling */ +/* A number of gateable clocks need special handling */ #define CP110_GATE_AUDIO 0 #define CP110_GATE_COMM_UNIT 1 #define CP110_GATE_NAND 2 diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c index 27781b49eb82..5969f620607a 100644 --- a/drivers/clk/nxp/clk-lpc18xx-ccu.c +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -142,7 +142,7 @@ static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable) * Divider field is write only, so divider stat field must * be read so divider field can be set accordingly. */ - val = clk_readl(gate->reg); + val = readl(gate->reg); if (val & LPC18XX_CCU_DIVSTAT) val |= LPC18XX_CCU_DIV; @@ -155,12 +155,12 @@ static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable) * and the next write should clear the RUN bit. */ val |= LPC18XX_CCU_AUTO; - clk_writel(val, gate->reg); + writel(val, gate->reg); val &= ~LPC18XX_CCU_RUN; } - clk_writel(val, gate->reg); + writel(val, gate->reg); return 0; } diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c index 2531174b399e..f5bc8bd192b7 100644 --- a/drivers/clk/nxp/clk-lpc18xx-cgu.c +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -352,9 +352,9 @@ static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw, struct lpc18xx_pll *pll = to_lpc_pll(hw); u32 ctrl, mdiv, msel, npdiv; - ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); - mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV); - npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); + ctrl = readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + mdiv = readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV); + npdiv = readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); if (ctrl & LPC18XX_PLL0_CTRL_BYPASS) return parent_rate; @@ -415,25 +415,25 @@ static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT; /* Power down PLL, disable clk output and dividers */ - ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + ctrl = readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); ctrl |= LPC18XX_PLL0_CTRL_PD; ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI | LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN); - clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); /* Configure new PLL settings */ - clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV); - clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); + writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV); + writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); /* Power up PLL and wait for lock */ ctrl &= ~LPC18XX_PLL0_CTRL_PD; - clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); do { udelay(10); - stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT); + stat = readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT); if (stat & LPC18XX_PLL0_STAT_LOCK) { ctrl |= LPC18XX_PLL0_CTRL_CLKEN; - clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); return 0; } @@ -458,8 +458,8 @@ static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw, bool direct, fbsel; u32 stat, ctrl; - stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT); - ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL); + stat = readl(pll->reg + LPC18XX_CGU_PLL1_STAT); + ctrl = readl(pll->reg + LPC18XX_CGU_PLL1_CTRL); direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false; fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false; diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 5eeecee17b69..7524d19fe60b 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -1085,13 +1085,12 @@ struct clk_hw_proto { }; }; -#define LPC32XX_DEFINE_FIXED(_idx, _rate, _flags) \ +#define LPC32XX_DEFINE_FIXED(_idx, _rate) \ [CLK_PREFIX(_idx)] = { \ .type = CLK_FIXED, \ { \ .f = { \ .fixed_rate = (_rate), \ - .flags = (_flags), \ }, \ }, \ } @@ -1225,7 +1224,7 @@ struct clk_hw_proto { } static struct clk_hw_proto clk_hw_proto[LPC32XX_CLK_HW_MAX] = { - LPC32XX_DEFINE_FIXED(RTC, 32768, 0), + LPC32XX_DEFINE_FIXED(RTC, 32768), LPC32XX_DEFINE_PLL(PLL397X, pll_397x, HCLKPLL_CTRL, BIT(1)), LPC32XX_DEFINE_PLL(HCLK_PLL, hclk_pll, HCLKPLL_CTRL, PLL_CTRL_ENABLE), LPC32XX_DEFINE_PLL(USB_PLL, usb_pll, USB_CTRL, PLL_CTRL_ENABLE), @@ -1468,7 +1467,7 @@ static struct clk * __init lpc32xx_clk_register(u32 id) struct clk_fixed_rate *fixed = &clk_hw->f; clk = clk_register_fixed_rate(NULL, lpc32xx_clk->name, - parents[0], fixed->flags, fixed->fixed_rate); + parents[0], 0, fixed->fixed_rate); break; } default: diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 1c04575c118f..18bdf34d5e64 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -243,6 +243,12 @@ config SDM_GCC_660 Say Y if you want to use peripheral devices such as UART, SPI, i2C, USB, UFS, SDDC, PCIe, etc. +config QCS_TURING_404 + tristate "QCS404 Turing Clock Controller" + help + Support for the Turing Clock Controller on QCS404, provides clocks + and resets for the Turing subsystem. + config SDM_GCC_845 tristate "SDM845 Global Clock Controller" select QCOM_GDSC diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index ee8d0698e370..f0768fb1f037 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o +obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 99446bf630aa..f869fc6aaed6 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -146,6 +146,12 @@ const struct clk_ops clk_branch2_ops = { }; EXPORT_SYMBOL_GPL(clk_branch2_ops); +const struct clk_ops clk_branch2_aon_ops = { + .enable = clk_branch2_enable, + .is_enabled = clk_is_enabled_regmap, +}; +EXPORT_SYMBOL_GPL(clk_branch2_aon_ops); + const struct clk_ops clk_branch_simple_ops = { .enable = clk_enable_regmap, .disable = clk_disable_regmap, diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index b3561e0a3984..17a58119165e 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -40,6 +40,7 @@ struct clk_branch { extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch_simple_ops; +extern const struct clk_ops clk_branch2_aon_ops; #define to_clk_branch(_hw) \ container_of(to_clk_regmap(_hw), struct clk_branch, clkr) diff --git a/drivers/clk/qcom/clk-regmap-mux-div.h b/drivers/clk/qcom/clk-regmap-mux-div.h index 6cd6261be7ac..4df6c8d24c24 100644 --- a/drivers/clk/qcom/clk-regmap-mux-div.h +++ b/drivers/clk/qcom/clk-regmap-mux-div.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2017, Linaro Limited * Author: Georgi Djakov <georgi.djakov@linaro.org> diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index c240fba794c7..033688264c7b 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -2161,7 +2161,7 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = { static struct clk_branch gcc_pcie_0_pipe_clk = { .halt_reg = 0x6b018, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x6b018, .enable_mask = BIT(0), diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index 5a62f64ada93..a54807eb3b28 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -260,6 +260,20 @@ static const char * const gcc_parent_names_15[] = { "core_bi_pll_test_se", }; +static const struct parent_map gcc_parent_map_16[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_16[] = { + "cxo", + "gpll0_out_main", + "gpll0_out_aux", + "core_bi_pll_test_se", +}; + static struct clk_fixed_factor cxo = { .mult = 1, .div = 1, @@ -1194,6 +1208,28 @@ static struct clk_rcg2 vsync_clk_src = { }, }; +static const struct freq_tbl ftbl_cdsp_bimc_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 cdsp_bimc_clk_src = { + .cmd_rcgr = 0x5e010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_16, + .freq_tbl = ftbl_cdsp_bimc_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "cdsp_bimc_clk_src", + .parent_names = gcc_parent_names_16, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + static struct clk_branch gcc_apss_ahb_clk = { .halt_reg = 0x4601c, .halt_check = BRANCH_HALT_VOTED, @@ -1255,6 +1291,24 @@ static struct clk_branch gcc_bimc_gpu_clk = { }, }; +static struct clk_branch gcc_bimc_cdsp_clk = { + .halt_reg = 0x31030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_bimc_cdsp_clk", + .parent_names = (const char *[]) { + "cdsp_bimc_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_bimc_mdss_clk = { .halt_reg = 0x31038, .halt_check = BRANCH_HALT, @@ -1792,6 +1846,24 @@ static struct clk_branch gcc_gfx_tbu_clk = { }, }; +static struct clk_branch gcc_cdsp_tbu_clk = { + .halt_reg = 0x1203c, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x13020, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data) { + .name = "gcc_cdsp_tbu_clk", + .parent_names = (const char *[]) { + "cdsp_bimc_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_gp1_clk = { .halt_reg = 0x8000, .halt_check = BRANCH_HALT, @@ -2304,6 +2376,19 @@ static struct clk_branch gcc_sdcc1_ice_core_clk = { }, }; +static struct clk_branch gcc_cdsp_cfg_ahb_clk = { + .halt_reg = 0x5e004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5e004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_cdsp_cfg_ahb_cbcr", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_sdcc2_ahb_clk = { .halt_reg = 0x4301c, .halt_check = BRANCH_HALT, @@ -2548,6 +2633,7 @@ static struct clk_regmap *gcc_qcs404_clocks[] = { [GCC_ESC0_CLK_SRC] = &esc0_clk_src.clkr, [GCC_APSS_AHB_CLK] = &gcc_apss_ahb_clk.clkr, [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr, + [GCC_BIMC_CDSP_CLK] = &gcc_bimc_cdsp_clk.clkr, [GCC_BIMC_MDSS_CLK] = &gcc_bimc_mdss_clk.clkr, [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, [GCC_BLSP1_QUP0_I2C_APPS_CLK] = &gcc_blsp1_qup0_i2c_apps_clk.clkr, @@ -2605,6 +2691,7 @@ static struct clk_regmap *gcc_qcs404_clocks[] = { [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_CDSP_CFG_AHB_CLK] = &gcc_cdsp_cfg_ahb_clk.clkr, [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, [GCC_SYS_NOC_USB3_CLK] = &gcc_sys_noc_usb3_clk.clkr, @@ -2645,6 +2732,7 @@ static struct clk_regmap *gcc_qcs404_clocks[] = { [GCC_USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr, [GCC_USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, [GCC_VSYNC_CLK_SRC] = &vsync_clk_src.clkr, + [GCC_CDSP_BIMC_CLK_SRC] = &cdsp_bimc_clk_src.clkr, [GCC_USB_HS_INACTIVITY_TIMERS_CLK] = &gcc_usb_hs_inactivity_timers_clk.clkr, [GCC_BIMC_GPU_CLK] = &gcc_bimc_gpu_clk.clkr, @@ -2653,6 +2741,7 @@ static struct clk_regmap *gcc_qcs404_clocks[] = { [GCC_GFX_TBU_CLK] = &gcc_gfx_tbu_clk.clkr, [GCC_SMMU_CFG_CLK] = &gcc_smmu_cfg_clk.clkr, [GCC_APSS_TCU_CLK] = &gcc_apss_tcu_clk.clkr, + [GCC_CDSP_TBU_CLK] = &gcc_cdsp_tbu_clk.clkr, [GCC_CRYPTO_AHB_CLK] = &gcc_crypto_ahb_clk.clkr, [GCC_CRYPTO_AXI_CLK] = &gcc_crypto_axi_clk.clkr, [GCC_CRYPTO_CLK] = &gcc_crypto_clk.clkr, @@ -2664,6 +2753,7 @@ static struct clk_regmap *gcc_qcs404_clocks[] = { static const struct qcom_reset_map gcc_qcs404_resets[] = { [GCC_GENI_IR_BCR] = { 0x0F000 }, + [GCC_CDSP_RESTART] = { 0x18000 }, [GCC_USB_HS_BCR] = { 0x41000 }, [GCC_USB2_HS_PHY_ONLY_BCR] = { 0x41034 }, [GCC_QUSB2_PHY_BCR] = { 0x4103c }, diff --git a/drivers/clk/qcom/turingcc-qcs404.c b/drivers/clk/qcom/turingcc-qcs404.c new file mode 100644 index 000000000000..aa859e6ec9bd --- /dev/null +++ b/drivers/clk/qcom/turingcc-qcs404.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Linaro Ltd. + */ + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,turingcc-qcs404.h> + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" +#include "reset.h" + +static struct clk_branch turing_wrapper_aon_cbcr = { + .halt_reg = 0x5098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "turing_wrapper_aon_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch turing_q6ss_ahbm_aon_cbcr = { + .halt_reg = 0x9000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "turing_q6ss_ahbm_aon_cbcr", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch turing_q6ss_q6_axim_clk = { + .halt_reg = 0xb000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "turing_q6ss_q6_axim_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch turing_q6ss_ahbs_aon_cbcr = { + .halt_reg = 0x10000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "turing_q6ss_ahbs_aon_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch turing_wrapper_qos_ahbs_aon_cbcr = { + .halt_reg = 0x11014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "turing_wrapper_qos_ahbs_aon_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_regmap *turingcc_clocks[] = { + [TURING_WRAPPER_AON_CLK] = &turing_wrapper_aon_cbcr.clkr, + [TURING_Q6SS_AHBM_AON_CLK] = &turing_q6ss_ahbm_aon_cbcr.clkr, + [TURING_Q6SS_Q6_AXIM_CLK] = &turing_q6ss_q6_axim_clk.clkr, + [TURING_Q6SS_AHBS_AON_CLK] = &turing_q6ss_ahbs_aon_cbcr.clkr, + [TURING_WRAPPER_QOS_AHBS_AON_CLK] = &turing_wrapper_qos_ahbs_aon_cbcr.clkr, +}; + +static const struct regmap_config turingcc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x30000, + .fast_io = true, +}; + +static const struct qcom_cc_desc turingcc_desc = { + .config = &turingcc_regmap_config, + .clks = turingcc_clocks, + .num_clks = ARRAY_SIZE(turingcc_clocks), +}; + +static int turingcc_probe(struct platform_device *pdev) +{ + int ret; + + pm_runtime_enable(&pdev->dev); + ret = pm_clk_create(&pdev->dev); + if (ret) + goto disable_pm_runtime; + + ret = pm_clk_add(&pdev->dev, NULL); + if (ret < 0) { + dev_err(&pdev->dev, "failed to acquire iface clock\n"); + goto destroy_pm_clk; + } + + ret = qcom_cc_probe(pdev, &turingcc_desc); + if (ret < 0) + goto destroy_pm_clk; + + return 0; + +destroy_pm_clk: + pm_clk_destroy(&pdev->dev); + +disable_pm_runtime: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int turingcc_remove(struct platform_device *pdev) +{ + pm_clk_destroy(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops turingcc_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + +static const struct of_device_id turingcc_match_table[] = { + { .compatible = "qcom,qcs404-turingcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, turingcc_match_table); + +static struct platform_driver turingcc_driver = { + .probe = turingcc_probe, + .remove = turingcc_remove, + .driver = { + .name = "qcs404-turingcc", + .of_match_table = turingcc_match_table, + .pm = &turingcc_pm_ops, + }, +}; + +module_platform_driver(turingcc_driver); + +MODULE_DESCRIPTION("Qualcomm QCS404 Turing Clock Controller"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/renesas/r7s9210-cpg-mssr.c b/drivers/clk/renesas/r7s9210-cpg-mssr.c index 57c49fe88295..cf65d4e0e116 100644 --- a/drivers/clk/renesas/r7s9210-cpg-mssr.c +++ b/drivers/clk/renesas/r7s9210-cpg-mssr.c @@ -11,6 +11,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/io.h> #include <dt-bindings/clock/r7s9210-cpg-mssr.h> #include "renesas-cpg-mssr.h" @@ -119,7 +120,7 @@ static void __init r7s9210_update_clk_table(struct clk *extal_clk, if (clk_get_rate(extal_clk) > 12000000) cpg_mode = 1; - frqcr = clk_readl(base + CPG_FRQCR) & 0xFFF; + frqcr = readl(base + CPG_FRQCR) & 0xFFF; if (frqcr == 0x012) index = 0; else if (frqcr == 0x112) diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c index 4d92b27a6153..76ed7d1bae36 100644 --- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c @@ -71,8 +71,8 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = { DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), /* Core Clock Outputs */ - DEF_BASE("z", R8A774A1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), - DEF_BASE("z2", R8A774A1_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2), + DEF_GEN3_Z("z", R8A774A1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("z2", R8A774A1_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), DEF_FIXED("ztr", R8A774A1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A774A1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A774A1_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -123,8 +123,8 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { DEF_MOD("msiof2", 209, R8A774A1_CLK_MSO), DEF_MOD("msiof1", 210, R8A774A1_CLK_MSO), DEF_MOD("msiof0", 211, R8A774A1_CLK_MSO), - DEF_MOD("sys-dmac2", 217, R8A774A1_CLK_S0D3), - DEF_MOD("sys-dmac1", 218, R8A774A1_CLK_S0D3), + DEF_MOD("sys-dmac2", 217, R8A774A1_CLK_S3D1), + DEF_MOD("sys-dmac1", 218, R8A774A1_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A774A1_CLK_S0D3), DEF_MOD("cmt3", 300, R8A774A1_CLK_R), DEF_MOD("cmt2", 301, R8A774A1_CLK_R), @@ -143,8 +143,8 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { DEF_MOD("rwdt", 402, R8A774A1_CLK_R), DEF_MOD("intc-ex", 407, R8A774A1_CLK_CP), DEF_MOD("intc-ap", 408, R8A774A1_CLK_S0D3), - DEF_MOD("audmac1", 501, R8A774A1_CLK_S0D3), - DEF_MOD("audmac0", 502, R8A774A1_CLK_S0D3), + DEF_MOD("audmac1", 501, R8A774A1_CLK_S1D2), + DEF_MOD("audmac0", 502, R8A774A1_CLK_S1D2), DEF_MOD("hscif4", 516, R8A774A1_CLK_S3D1), DEF_MOD("hscif3", 517, R8A774A1_CLK_S3D1), DEF_MOD("hscif2", 518, R8A774A1_CLK_S3D1), @@ -165,9 +165,9 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { DEF_MOD("vspd0", 623, R8A774A1_CLK_S0D2), DEF_MOD("vspb", 626, R8A774A1_CLK_S0D1), DEF_MOD("vspi0", 631, R8A774A1_CLK_S0D1), - DEF_MOD("ehci1", 702, R8A774A1_CLK_S3D4), - DEF_MOD("ehci0", 703, R8A774A1_CLK_S3D4), - DEF_MOD("hsusb", 704, R8A774A1_CLK_S3D4), + DEF_MOD("ehci1", 702, R8A774A1_CLK_S3D2), + DEF_MOD("ehci0", 703, R8A774A1_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A774A1_CLK_S3D2), DEF_MOD("csi20", 714, R8A774A1_CLK_CSI0), DEF_MOD("csi40", 716, R8A774A1_CLK_CSI0), DEF_MOD("du2", 722, R8A774A1_CLK_S2D1), diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index 34e274f2a273..f91e7a484753 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -81,6 +81,7 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_FIXED("za2", R8A774C0_CLK_ZA2, CLK_PLL0D24, 1, 1), DEF_FIXED("za8", R8A774C0_CLK_ZA8, CLK_PLL0D8, 1, 1), + DEF_GEN3_Z("z2", R8A774C0_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL0, 4, 8), DEF_FIXED("ztr", R8A774C0_CLK_ZTR, CLK_PLL1, 6, 1), DEF_FIXED("zt", R8A774C0_CLK_ZT, CLK_PLL1, 4, 1), DEF_FIXED("zx", R8A774C0_CLK_ZX, CLK_PLL1, 3, 1), @@ -157,7 +158,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { DEF_MOD("intc-ex", 407, R8A774C0_CLK_CP), DEF_MOD("intc-ap", 408, R8A774C0_CLK_S0D3), - DEF_MOD("audmac0", 502, R8A774C0_CLK_S3D4), + DEF_MOD("audmac0", 502, R8A774C0_CLK_S1D2), DEF_MOD("hscif4", 516, R8A774C0_CLK_S3D1C), DEF_MOD("hscif3", 517, R8A774C0_CLK_S3D1C), DEF_MOD("hscif2", 518, R8A774C0_CLK_S3D1C), @@ -177,8 +178,8 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { DEF_MOD("vspb", 626, R8A774C0_CLK_S0D1), DEF_MOD("vspi0", 631, R8A774C0_CLK_S0D1), - DEF_MOD("ehci0", 703, R8A774C0_CLK_S3D4), - DEF_MOD("hsusb", 704, R8A774C0_CLK_S3D4), + DEF_MOD("ehci0", 703, R8A774C0_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A774C0_CLK_S3D2), DEF_MOD("csi40", 716, R8A774C0_CLK_CSI0), DEF_MOD("du1", 723, R8A774C0_CLK_S1D1), DEF_MOD("du0", 724, R8A774C0_CLK_S1D1), diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 86842c9fd314..9e9a6f2c31e8 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -3,6 +3,7 @@ * r8a7795 Clock Pulse Generator / Module Standby and Software Reset * * Copyright (C) 2015 Glider bvba + * Copyright (C) 2018-2019 Renesas Electronics Corp. * * Based on clk-rcar-gen3.c * @@ -73,8 +74,8 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), /* Core Clock Outputs */ - DEF_BASE("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), - DEF_BASE("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2), + DEF_GEN3_Z("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -129,8 +130,8 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("msiof2", 209, R8A7795_CLK_MSO), DEF_MOD("msiof1", 210, R8A7795_CLK_MSO), DEF_MOD("msiof0", 211, R8A7795_CLK_MSO), - DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S0D3), - DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S0D3), + DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1), + DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S0D3), DEF_MOD("sceg-pub", 229, R8A7795_CLK_CR), DEF_MOD("cmt3", 300, R8A7795_CLK_R), @@ -153,16 +154,16 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("rwdt", 402, R8A7795_CLK_R), DEF_MOD("intc-ex", 407, R8A7795_CLK_CP), DEF_MOD("intc-ap", 408, R8A7795_CLK_S0D3), - DEF_MOD("audmac1", 501, R8A7795_CLK_S0D3), - DEF_MOD("audmac0", 502, R8A7795_CLK_S0D3), - DEF_MOD("drif7", 508, R8A7795_CLK_S3D2), - DEF_MOD("drif6", 509, R8A7795_CLK_S3D2), - DEF_MOD("drif5", 510, R8A7795_CLK_S3D2), - DEF_MOD("drif4", 511, R8A7795_CLK_S3D2), - DEF_MOD("drif3", 512, R8A7795_CLK_S3D2), - DEF_MOD("drif2", 513, R8A7795_CLK_S3D2), - DEF_MOD("drif1", 514, R8A7795_CLK_S3D2), - DEF_MOD("drif0", 515, R8A7795_CLK_S3D2), + DEF_MOD("audmac1", 501, R8A7795_CLK_S1D2), + DEF_MOD("audmac0", 502, R8A7795_CLK_S1D2), + DEF_MOD("drif31", 508, R8A7795_CLK_S3D2), + DEF_MOD("drif30", 509, R8A7795_CLK_S3D2), + DEF_MOD("drif21", 510, R8A7795_CLK_S3D2), + DEF_MOD("drif20", 511, R8A7795_CLK_S3D2), + DEF_MOD("drif11", 512, R8A7795_CLK_S3D2), + DEF_MOD("drif10", 513, R8A7795_CLK_S3D2), + DEF_MOD("drif01", 514, R8A7795_CLK_S3D2), + DEF_MOD("drif00", 515, R8A7795_CLK_S3D2), DEF_MOD("hscif4", 516, R8A7795_CLK_S3D1), DEF_MOD("hscif3", 517, R8A7795_CLK_S3D1), DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1), @@ -194,12 +195,12 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1), /* ES1.x */ DEF_MOD("vspi1", 630, R8A7795_CLK_S0D1), DEF_MOD("vspi0", 631, R8A7795_CLK_S0D1), - DEF_MOD("ehci3", 700, R8A7795_CLK_S3D4), - DEF_MOD("ehci2", 701, R8A7795_CLK_S3D4), - DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4), - DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4), - DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4), - DEF_MOD("hsusb3", 705, R8A7795_CLK_S3D4), + DEF_MOD("ehci3", 700, R8A7795_CLK_S3D2), + DEF_MOD("ehci2", 701, R8A7795_CLK_S3D2), + DEF_MOD("ehci1", 702, R8A7795_CLK_S3D2), + DEF_MOD("ehci0", 703, R8A7795_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A7795_CLK_S3D2), + DEF_MOD("hsusb3", 705, R8A7795_CLK_S3D2), DEF_MOD("csi21", 713, R8A7795_CLK_CSI0), /* ES1.x */ DEF_MOD("csi20", 714, R8A7795_CLK_CSI0), DEF_MOD("csi41", 715, R8A7795_CLK_CSI0), diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 12c455859f2c..d8e9af5d9ae9 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -3,6 +3,7 @@ * r8a7796 Clock Pulse Generator / Module Standby and Software Reset * * Copyright (C) 2016 Glider bvba + * Copyright (C) 2018 Renesas Electronics Corp. * * Based on r8a7795-cpg-mssr.c * @@ -73,8 +74,8 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), /* Core Clock Outputs */ - DEF_BASE("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), - DEF_BASE("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2), + DEF_GEN3_Z("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7796_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7796_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -126,8 +127,8 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("msiof2", 209, R8A7796_CLK_MSO), DEF_MOD("msiof1", 210, R8A7796_CLK_MSO), DEF_MOD("msiof0", 211, R8A7796_CLK_MSO), - DEF_MOD("sys-dmac2", 217, R8A7796_CLK_S0D3), - DEF_MOD("sys-dmac1", 218, R8A7796_CLK_S0D3), + DEF_MOD("sys-dmac2", 217, R8A7796_CLK_S3D1), + DEF_MOD("sys-dmac1", 218, R8A7796_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A7796_CLK_S0D3), DEF_MOD("cmt3", 300, R8A7796_CLK_R), DEF_MOD("cmt2", 301, R8A7796_CLK_R), @@ -146,16 +147,16 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("rwdt", 402, R8A7796_CLK_R), DEF_MOD("intc-ex", 407, R8A7796_CLK_CP), DEF_MOD("intc-ap", 408, R8A7796_CLK_S0D3), - DEF_MOD("audmac1", 501, R8A7796_CLK_S0D3), - DEF_MOD("audmac0", 502, R8A7796_CLK_S0D3), - DEF_MOD("drif7", 508, R8A7796_CLK_S3D2), - DEF_MOD("drif6", 509, R8A7796_CLK_S3D2), - DEF_MOD("drif5", 510, R8A7796_CLK_S3D2), - DEF_MOD("drif4", 511, R8A7796_CLK_S3D2), - DEF_MOD("drif3", 512, R8A7796_CLK_S3D2), - DEF_MOD("drif2", 513, R8A7796_CLK_S3D2), - DEF_MOD("drif1", 514, R8A7796_CLK_S3D2), - DEF_MOD("drif0", 515, R8A7796_CLK_S3D2), + DEF_MOD("audmac1", 501, R8A7796_CLK_S1D2), + DEF_MOD("audmac0", 502, R8A7796_CLK_S1D2), + DEF_MOD("drif31", 508, R8A7796_CLK_S3D2), + DEF_MOD("drif30", 509, R8A7796_CLK_S3D2), + DEF_MOD("drif21", 510, R8A7796_CLK_S3D2), + DEF_MOD("drif20", 511, R8A7796_CLK_S3D2), + DEF_MOD("drif11", 512, R8A7796_CLK_S3D2), + DEF_MOD("drif10", 513, R8A7796_CLK_S3D2), + DEF_MOD("drif01", 514, R8A7796_CLK_S3D2), + DEF_MOD("drif00", 515, R8A7796_CLK_S3D2), DEF_MOD("hscif4", 516, R8A7796_CLK_S3D1), DEF_MOD("hscif3", 517, R8A7796_CLK_S3D1), DEF_MOD("hscif2", 518, R8A7796_CLK_S3D1), @@ -176,9 +177,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("vspd0", 623, R8A7796_CLK_S0D2), DEF_MOD("vspb", 626, R8A7796_CLK_S0D1), DEF_MOD("vspi0", 631, R8A7796_CLK_S0D1), - DEF_MOD("ehci1", 702, R8A7796_CLK_S3D4), - DEF_MOD("ehci0", 703, R8A7796_CLK_S3D4), - DEF_MOD("hsusb", 704, R8A7796_CLK_S3D4), + DEF_MOD("ehci1", 702, R8A7796_CLK_S3D2), + DEF_MOD("ehci0", 703, R8A7796_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A7796_CLK_S3D2), DEF_MOD("csi20", 714, R8A7796_CLK_CSI0), DEF_MOD("csi40", 716, R8A7796_CLK_CSI0), DEF_MOD("du2", 722, R8A7796_CLK_S2D1), diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c index eb1cca58a1e1..8f87e314d949 100644 --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -3,6 +3,7 @@ * r8a77965 Clock Pulse Generator / Module Standby and Software Reset * * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org> + * Copyright (C) 2019 Renesas Electronics Corp. * * Based on r8a7795-cpg-mssr.c * @@ -71,7 +72,7 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), /* Core Clock Outputs */ - DEF_BASE("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), + DEF_GEN3_Z("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), DEF_FIXED("ztr", R8A77965_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A77965_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A77965_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -123,8 +124,8 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("msiof2", 209, R8A77965_CLK_MSO), DEF_MOD("msiof1", 210, R8A77965_CLK_MSO), DEF_MOD("msiof0", 211, R8A77965_CLK_MSO), - DEF_MOD("sys-dmac2", 217, R8A77965_CLK_S0D3), - DEF_MOD("sys-dmac1", 218, R8A77965_CLK_S0D3), + DEF_MOD("sys-dmac2", 217, R8A77965_CLK_S3D1), + DEF_MOD("sys-dmac1", 218, R8A77965_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A77965_CLK_S0D3), DEF_MOD("cmt3", 300, R8A77965_CLK_R), @@ -146,16 +147,16 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("intc-ex", 407, R8A77965_CLK_CP), DEF_MOD("intc-ap", 408, R8A77965_CLK_S0D3), - DEF_MOD("audmac1", 501, R8A77965_CLK_S0D3), - DEF_MOD("audmac0", 502, R8A77965_CLK_S0D3), - DEF_MOD("drif7", 508, R8A77965_CLK_S3D2), - DEF_MOD("drif6", 509, R8A77965_CLK_S3D2), - DEF_MOD("drif5", 510, R8A77965_CLK_S3D2), - DEF_MOD("drif4", 511, R8A77965_CLK_S3D2), - DEF_MOD("drif3", 512, R8A77965_CLK_S3D2), - DEF_MOD("drif2", 513, R8A77965_CLK_S3D2), - DEF_MOD("drif1", 514, R8A77965_CLK_S3D2), - DEF_MOD("drif0", 515, R8A77965_CLK_S3D2), + DEF_MOD("audmac1", 501, R8A77965_CLK_S1D2), + DEF_MOD("audmac0", 502, R8A77965_CLK_S1D2), + DEF_MOD("drif31", 508, R8A77965_CLK_S3D2), + DEF_MOD("drif30", 509, R8A77965_CLK_S3D2), + DEF_MOD("drif21", 510, R8A77965_CLK_S3D2), + DEF_MOD("drif20", 511, R8A77965_CLK_S3D2), + DEF_MOD("drif11", 512, R8A77965_CLK_S3D2), + DEF_MOD("drif10", 513, R8A77965_CLK_S3D2), + DEF_MOD("drif01", 514, R8A77965_CLK_S3D2), + DEF_MOD("drif00", 515, R8A77965_CLK_S3D2), DEF_MOD("hscif4", 516, R8A77965_CLK_S3D1), DEF_MOD("hscif3", 517, R8A77965_CLK_S3D1), DEF_MOD("hscif2", 518, R8A77965_CLK_S3D1), @@ -175,9 +176,9 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("vspb", 626, R8A77965_CLK_S0D1), DEF_MOD("vspi0", 631, R8A77965_CLK_S0D1), - DEF_MOD("ehci1", 702, R8A77965_CLK_S3D4), - DEF_MOD("ehci0", 703, R8A77965_CLK_S3D4), - DEF_MOD("hsusb", 704, R8A77965_CLK_S3D4), + DEF_MOD("ehci1", 702, R8A77965_CLK_S3D2), + DEF_MOD("ehci0", 703, R8A77965_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A77965_CLK_S3D2), DEF_MOD("csi20", 714, R8A77965_CLK_CSI0), DEF_MOD("csi40", 716, R8A77965_CLK_CSI0), DEF_MOD("du3", 721, R8A77965_CLK_S2D1), diff --git a/drivers/clk/renesas/r8a77980-cpg-mssr.c b/drivers/clk/renesas/r8a77980-cpg-mssr.c index f9e07fcc0d96..7227f675e61f 100644 --- a/drivers/clk/renesas/r8a77980-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77980-cpg-mssr.c @@ -171,7 +171,7 @@ static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = { DEF_MOD("gpio1", 911, R8A77980_CLK_CP), DEF_MOD("gpio0", 912, R8A77980_CLK_CP), DEF_MOD("can-fd", 914, R8A77980_CLK_S3D2), - DEF_MOD("rpc-if", 917, R8A77980_CLK_RPC), + DEF_MOD("rpc-if", 917, R8A77980_CLK_RPCD2), DEF_MOD("i2c4", 927, R8A77980_CLK_S0D6), DEF_MOD("i2c3", 928, R8A77980_CLK_S0D6), DEF_MOD("i2c2", 929, R8A77980_CLK_S3D2), diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c index 9a278c75c918..9570404baa58 100644 --- a/drivers/clk/renesas/r8a77990-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c @@ -2,7 +2,7 @@ /* * r8a77990 Clock Pulse Generator / Module Standby and Software Reset * - * Copyright (C) 2018 Renesas Electronics Corp. + * Copyright (C) 2018-2019 Renesas Electronics Corp. * * Based on r8a7795-cpg-mssr.c * @@ -81,6 +81,7 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_FIXED("za2", R8A77990_CLK_ZA2, CLK_PLL0D24, 1, 1), DEF_FIXED("za8", R8A77990_CLK_ZA8, CLK_PLL0D8, 1, 1), + DEF_GEN3_Z("z2", R8A77990_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL0, 4, 8), DEF_FIXED("ztr", R8A77990_CLK_ZTR, CLK_PLL1, 6, 1), DEF_FIXED("zt", R8A77990_CLK_ZT, CLK_PLL1, 4, 1), DEF_FIXED("zx", R8A77990_CLK_ZX, CLK_PLL1, 3, 1), @@ -152,15 +153,15 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = { DEF_MOD("intc-ex", 407, R8A77990_CLK_CP), DEF_MOD("intc-ap", 408, R8A77990_CLK_S0D3), - DEF_MOD("audmac0", 502, R8A77990_CLK_S3D4), - DEF_MOD("drif7", 508, R8A77990_CLK_S3D2), - DEF_MOD("drif6", 509, R8A77990_CLK_S3D2), - DEF_MOD("drif5", 510, R8A77990_CLK_S3D2), - DEF_MOD("drif4", 511, R8A77990_CLK_S3D2), - DEF_MOD("drif3", 512, R8A77990_CLK_S3D2), - DEF_MOD("drif2", 513, R8A77990_CLK_S3D2), - DEF_MOD("drif1", 514, R8A77990_CLK_S3D2), - DEF_MOD("drif0", 515, R8A77990_CLK_S3D2), + DEF_MOD("audmac0", 502, R8A77990_CLK_S1D2), + DEF_MOD("drif31", 508, R8A77990_CLK_S3D2), + DEF_MOD("drif30", 509, R8A77990_CLK_S3D2), + DEF_MOD("drif21", 510, R8A77990_CLK_S3D2), + DEF_MOD("drif20", 511, R8A77990_CLK_S3D2), + DEF_MOD("drif11", 512, R8A77990_CLK_S3D2), + DEF_MOD("drif10", 513, R8A77990_CLK_S3D2), + DEF_MOD("drif01", 514, R8A77990_CLK_S3D2), + DEF_MOD("drif00", 515, R8A77990_CLK_S3D2), DEF_MOD("hscif4", 516, R8A77990_CLK_S3D1C), DEF_MOD("hscif3", 517, R8A77990_CLK_S3D1C), DEF_MOD("hscif2", 518, R8A77990_CLK_S3D1C), @@ -180,8 +181,8 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = { DEF_MOD("vspb", 626, R8A77990_CLK_S0D1), DEF_MOD("vspi0", 631, R8A77990_CLK_S0D1), - DEF_MOD("ehci0", 703, R8A77990_CLK_S3D4), - DEF_MOD("hsusb", 704, R8A77990_CLK_S3D4), + DEF_MOD("ehci0", 703, R8A77990_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A77990_CLK_S3D2), DEF_MOD("csi40", 716, R8A77990_CLK_CSI0), DEF_MOD("du1", 723, R8A77990_CLK_S1D1), DEF_MOD("du0", 724, R8A77990_CLK_S1D1), diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index eee3874865a9..68707277b17b 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -133,7 +133,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { DEF_MOD("rwdt", 402, R8A77995_CLK_R), DEF_MOD("intc-ex", 407, R8A77995_CLK_CP), DEF_MOD("intc-ap", 408, R8A77995_CLK_S1D2), - DEF_MOD("audmac0", 502, R8A77995_CLK_S3D1), + DEF_MOD("audmac0", 502, R8A77995_CLK_S1D2), DEF_MOD("hscif3", 517, R8A77995_CLK_S3D1C), DEF_MOD("hscif0", 520, R8A77995_CLK_S3D1C), DEF_MOD("thermal", 522, R8A77995_CLK_CP), diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index 658cb11b6f55..97c72477cd54 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -170,6 +170,7 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = { D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0), D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0), D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0), + D_GATE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0), D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0), D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0), D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0), diff --git a/drivers/clk/renesas/rcar-gen2-cpg.h b/drivers/clk/renesas/rcar-gen2-cpg.h index bff9551c7a38..db2f57ef2f99 100644 --- a/drivers/clk/renesas/rcar-gen2-cpg.h +++ b/drivers/clk/renesas/rcar-gen2-cpg.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +/* SPDX-License-Identifier: GPL-2.0 */ +/* * R-Car Gen2 Clock Pulse Generator * * Copyright (C) 2016 Cogent Embedded Inc. diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 9a8071a8114d..d25c8ba00a65 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -3,6 +3,7 @@ * R-Car Gen3 Clock Pulse Generator * * Copyright (C) 2015-2018 Glider bvba + * Copyright (C) 2019 Renesas Electronics Corp. * * Based on clk-rcar-gen3.c * @@ -88,14 +89,13 @@ static void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, #define CPG_FRQCRB 0x00000004 #define CPG_FRQCRB_KICK BIT(31) #define CPG_FRQCRC 0x000000e0 -#define CPG_FRQCRC_ZFC_MASK GENMASK(12, 8) -#define CPG_FRQCRC_Z2FC_MASK GENMASK(4, 0) struct cpg_z_clk { struct clk_hw hw; void __iomem *reg; void __iomem *kick_reg; unsigned long mask; + unsigned int fixed_div; }; #define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) @@ -110,17 +110,18 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, val = readl(zclk->reg) & zclk->mask; mult = 32 - (val >> __ffs(zclk->mask)); - /* Factor of 2 is for fixed divider */ - return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * 2); + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, + 32 * zclk->fixed_div); } static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - /* Factor of 2 is for fixed divider */ - unsigned long prate = *parent_rate / 2; + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned long prate; unsigned int mult; + prate = *parent_rate / zclk->fixed_div; mult = div_u64(rate * 32ULL, prate); mult = clamp(mult, 1U, 32U); @@ -134,8 +135,8 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned int mult; unsigned int i; - /* Factor of 2 is for fixed divider */ - mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL * 2, parent_rate); + mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div, + parent_rate); mult = clamp(mult, 1U, 32U); if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) @@ -178,7 +179,8 @@ static const struct clk_ops cpg_z_clk_ops = { static struct clk * __init cpg_z_clk_register(const char *name, const char *parent_name, void __iomem *reg, - unsigned long mask) + unsigned int div, + unsigned int offset) { struct clk_init_data init; struct cpg_z_clk *zclk; @@ -197,7 +199,8 @@ static struct clk * __init cpg_z_clk_register(const char *name, zclk->reg = reg + CPG_FRQCRC; zclk->kick_reg = reg + CPG_FRQCRB; zclk->hw.init = &init; - zclk->mask = mask; + zclk->mask = GENMASK(offset + 4, offset); + zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */ clk = clk_register(NULL, &zclk->hw); if (IS_ERR(clk)) @@ -234,8 +237,6 @@ struct sd_clock { const struct sd_div_table *div_table; struct cpg_simple_notifier csn; unsigned int div_num; - unsigned int div_min; - unsigned int div_max; unsigned int cur_div_idx; }; @@ -312,14 +313,20 @@ static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock, unsigned long rate, unsigned long parent_rate) { - unsigned int div; - - if (!rate) - rate = 1; - - div = DIV_ROUND_CLOSEST(parent_rate, rate); + unsigned long calc_rate, diff, diff_min = ULONG_MAX; + unsigned int i, best_div = 0; + + for (i = 0; i < clock->div_num; i++) { + calc_rate = DIV_ROUND_CLOSEST(parent_rate, + clock->div_table[i].div); + diff = calc_rate > rate ? calc_rate - rate : rate - calc_rate; + if (diff < diff_min) { + best_div = clock->div_table[i].div; + diff_min = diff; + } + } - return clamp_t(unsigned int, div, clock->div_min, clock->div_max); + return best_div; } static long cpg_sd_clock_round_rate(struct clk_hw *hw, unsigned long rate, @@ -369,27 +376,26 @@ static u32 cpg_quirks __initdata; #define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */ #define SD_SKIP_FIRST BIT(2) /* Skip first clock in SD table */ -static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, - void __iomem *base, const char *parent_name, +static struct clk * __init cpg_sd_clk_register(const char *name, + void __iomem *base, unsigned int offset, const char *parent_name, struct raw_notifier_head *notifiers) { struct clk_init_data init; struct sd_clock *clock; struct clk *clk; - unsigned int i; u32 val; clock = kzalloc(sizeof(*clock), GFP_KERNEL); if (!clock) return ERR_PTR(-ENOMEM); - init.name = core->name; + init.name = name; init.ops = &cpg_sd_clock_ops; init.flags = CLK_SET_RATE_PARENT; init.parent_names = &parent_name; init.num_parents = 1; - clock->csn.reg = base + core->offset; + clock->csn.reg = base + offset; clock->hw.init = &init; clock->div_table = cpg_sd_div_table; clock->div_num = ARRAY_SIZE(cpg_sd_div_table); @@ -403,13 +409,6 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK); writel(val, clock->csn.reg); - clock->div_max = clock->div_table[0].div; - clock->div_min = clock->div_max; - for (i = 1; i < clock->div_num; i++) { - clock->div_max = max(clock->div_max, clock->div_table[i].div); - clock->div_min = min(clock->div_min, clock->div_table[i].div); - } - clk = clk_register(NULL, &clock->hw); if (IS_ERR(clk)) goto free_clock; @@ -606,8 +605,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, break; case CLK_TYPE_GEN3_SD: - return cpg_sd_clk_register(core, base, __clk_get_name(parent), - notifiers); + return cpg_sd_clk_register(core->name, base, core->offset, + __clk_get_name(parent), notifiers); case CLK_TYPE_GEN3_R: if (cpg_quirks & RCKCR_CKSEL) { @@ -658,11 +657,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, case CLK_TYPE_GEN3_Z: return cpg_z_clk_register(core->name, __clk_get_name(parent), - base, CPG_FRQCRC_ZFC_MASK); - - case CLK_TYPE_GEN3_Z2: - return cpg_z_clk_register(core->name, __clk_get_name(parent), - base, CPG_FRQCRC_Z2FC_MASK); + base, core->div, core->offset); case CLK_TYPE_GEN3_OSC: /* diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index eac1b057455a..c4ac80cac6a0 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -1,8 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +/* SPDX-License-Identifier: GPL-2.0 */ +/* * R-Car Gen3 Clock Pulse Generator * * Copyright (C) 2015-2018 Glider bvba + * Copyright (C) 2018 Renesas Electronics Corp. * */ @@ -20,7 +21,6 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_R, CLK_TYPE_GEN3_MDSEL, /* Select parent/divider using mode pin */ CLK_TYPE_GEN3_Z, - CLK_TYPE_GEN3_Z2, CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */ CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */ CLK_TYPE_GEN3_RPCSRC, @@ -51,6 +51,9 @@ enum rcar_gen3_clk_types { DEF_BASE(_name, _id, CLK_TYPE_GEN3_RCKSEL, \ (_parent0) << 16 | (_parent1), .div = (_div0) << 16 | (_div1)) +#define DEF_GEN3_Z(_name, _id, _type, _parent, _div, _offset) \ + DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset) + struct rcar_gen3_cpg_pll_config { u8 extal_div; u8 pll1_mult; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index c4ec9df146fd..4ddcdf3bfb95 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +/* SPDX-License-Identifier: GPL-2.0 */ +/* * Renesas Clock Pulse Generator / Module Standby and Software Reset * * Copyright (C) 2015 Glider bvba diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c index ebce5260068b..09ede6920593 100644 --- a/drivers/clk/rockchip/clk-ddr.c +++ b/drivers/clk/rockchip/clk-ddr.c @@ -82,7 +82,7 @@ static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); u32 val; - val = clk_readl(ddrclk->reg_base + + val = readl(ddrclk->reg_base + ddrclk->mux_offset) >> ddrclk->mux_shift; val &= GENMASK(ddrclk->mux_width - 1, 0); diff --git a/drivers/clk/rockchip/clk-half-divider.c b/drivers/clk/rockchip/clk-half-divider.c index b8da6e799423..784b81e1ea7c 100644 --- a/drivers/clk/rockchip/clk-half-divider.c +++ b/drivers/clk/rockchip/clk-half-divider.c @@ -24,7 +24,7 @@ static unsigned long clk_half_divider_recalc_rate(struct clk_hw *hw, struct clk_divider *divider = to_clk_divider(hw); unsigned int val; - val = clk_readl(divider->reg) >> divider->shift; + val = readl(divider->reg) >> divider->shift; val &= div_mask(divider->width); val = val * 2 + 3; @@ -124,11 +124,11 @@ static int clk_half_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { val = div_mask(divider->width) << (divider->shift + 16); } else { - val = clk_readl(divider->reg); + val = readl(divider->reg); val &= ~(div_mask(divider->width) << divider->shift); } val |= value << divider->shift; - clk_writel(val, divider->reg); + writel(val, divider->reg); if (divider->lock) spin_unlock_irqrestore(divider->lock, flags); diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 5a67b7869960..24baeb56a1b3 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -200,8 +200,8 @@ PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu" }; PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; -PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usbphy480m_src" }; -PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "usbphy480m_src", "npll" }; +PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "unstable:usbphy480m_src" }; +PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "unstable:usbphy480m_src", "npll" }; PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "xin24m" }; PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; @@ -219,7 +219,7 @@ PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" }; -PNAME(mux_aclk_vcodec_pre_p) = { "aclk_vepu", "aclk_vdpu" }; +PNAME(mux_aclk_vcodec_pre_p) = { "aclk_vdpu", "aclk_vepu" }; PNAME(mux_usbphy480m_p) = { "sclk_otgphy1_480m", "sclk_otgphy2_480m", "sclk_otgphy0_480m" }; PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy480m_src" }; @@ -313,13 +313,13 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(0), 4, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 6, GFLAGS), - COMPOSITE_NOMUX(0, "atclk", "armclk", CLK_IGNORE_UNUSED, + COMPOSITE_NOMUX(0, "atclk", "armclk", 0, RK3288_CLKSEL_CON(37), 4, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 7, GFLAGS), COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(37), 9, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 8, GFLAGS), - GATE(0, "pclk_dbg", "pclk_dbg_pre", CLK_IGNORE_UNUSED, + GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, RK3288_CLKGATE_CON(12), 9, GFLAGS), GATE(0, "cs_dbg", "pclk_dbg_pre", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(12), 10, GFLAGS), @@ -420,7 +420,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb480m_p, 0, RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(3), 11, GFLAGS), - MUXGRF(0, "aclk_vcodec_pre", mux_aclk_vcodec_pre_p, 0, + MUXGRF(0, "aclk_vcodec_pre", mux_aclk_vcodec_pre_p, CLK_SET_RATE_PARENT, RK3288_GRF_SOC_CON(0), 7, 1, MFLAGS), GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0, RK3288_CLKGATE_CON(9), 0, GFLAGS), @@ -647,7 +647,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out", RK3288_CLKSEL_CON(22), 7, IFLAGS), - GATE(0, "jtag", "ext_jtag", CLK_IGNORE_UNUSED, + GATE(0, "jtag", "ext_jtag", 0, RK3288_CLKGATE_CON(4), 14, GFLAGS), COMPOSITE_NODIV(SCLK_USBPHY480M_SRC, "usbphy480m_src", mux_usbphy480m_p, 0, @@ -656,7 +656,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0, RK3288_CLKSEL_CON(29), 0, 2, MFLAGS, RK3288_CLKGATE_CON(3), 6, GFLAGS), - GATE(0, "hsicphy12m_xin12m", "xin12m", CLK_IGNORE_UNUSED, + GATE(0, "hsicphy12m_xin12m", "xin12m", 0, RK3288_CLKGATE_CON(13), 9, GFLAGS), DIV(0, "hsicphy12m_usbphy", "sclk_hsicphy480m", 0, RK3288_CLKSEL_CON(11), 8, 6, DFLAGS), @@ -697,7 +697,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS), GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS), GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS), - GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS), + GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 11, GFLAGS), /* ddrctrl [DDR Controller PHY clock] gates */ GATE(0, "nclk_ddrupctl0", "ddrphy", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 4, GFLAGS), @@ -837,12 +837,9 @@ static const char *const rk3288_critical_clocks[] __initconst = { "pclk_alive_niu", "pclk_pd_pmu", "pclk_pmu_niu", - "pclk_core_niu", - "pclk_ddrupctl0", - "pclk_publ0", - "pclk_ddrupctl1", - "pclk_publ1", "pmu_hclk_otg0", + /* pwm-regulators on some boards, so handoff-critical later */ + "pclk_rkpwm", }; static void __iomem *rk3288_cru_base; @@ -859,6 +856,9 @@ static const int rk3288_saved_cru_reg_ids[] = { RK3288_CLKSEL_CON(10), RK3288_CLKSEL_CON(33), RK3288_CLKSEL_CON(37), + + /* We turn aclk_dmac1 on for suspend; this will restore it */ + RK3288_CLKGATE_CON(10), }; static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)]; @@ -875,6 +875,14 @@ static int rk3288_clk_suspend(void) } /* + * Going into deep sleep (specifically setting PMU_CLR_DMA in + * RK3288_PMU_PWRMODE_CON1) appears to fail unless + * "aclk_dmac1" is on. + */ + writel_relaxed(1 << (12 + 16), + rk3288_cru_base + RK3288_CLKGATE_CON(10)); + + /* * Switch PLLs other than DPLL (for SDRAM) to slow mode to * avoid crashes on resume. The Mask ROM on the system will * put APLL, CPLL, and GPLL into slow mode at resume time diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index 65ab5c2f48b0..f12142d9cea2 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -458,7 +458,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKSEL_CON(35), 15, 1, MFLAGS, 8, 7, DFLAGS, RK3328_CLKGATE_CON(2), 12, GFLAGS), COMPOSITE(SCLK_CRYPTO, "clk_crypto", mux_2plls_p, 0, - RK3328_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 5, DFLAGS, RK3328_CLKGATE_CON(2), 4, GFLAGS), COMPOSITE_NOMUX(SCLK_TSADC, "clk_tsadc", "clk_24m", 0, RK3328_CLKSEL_CON(22), 0, 10, DFLAGS, @@ -550,15 +550,15 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", 0, RK3328_CLKGATE_CON(25), 1, GFLAGS), GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0, - RK3328_CLKGATE_CON(25), 0, GFLAGS), + RK3328_CLKGATE_CON(25), 2, GFLAGS), GATE(PCLK_H265, "pclk_h265", "hclk_rkvenc", 0, - RK3328_CLKGATE_CON(25), 1, GFLAGS), + RK3328_CLKGATE_CON(25), 3, GFLAGS), GATE(ACLK_H264, "aclk_h264", "aclk_rkvenc", 0, - RK3328_CLKGATE_CON(25), 0, GFLAGS), + RK3328_CLKGATE_CON(25), 4, GFLAGS), GATE(HCLK_H264, "hclk_h264", "hclk_rkvenc", 0, - RK3328_CLKGATE_CON(25), 1, GFLAGS), + RK3328_CLKGATE_CON(25), 5, GFLAGS), GATE(ACLK_AXISRAM, "aclk_axisram", "aclk_rkvenc", CLK_IGNORE_UNUSED, - RK3328_CLKGATE_CON(25), 0, GFLAGS), + RK3328_CLKGATE_CON(25), 6, GFLAGS), COMPOSITE(SCLK_VENC_CORE, "sclk_venc_core", mux_4plls_p, 0, RK3328_CLKSEL_CON(51), 14, 2, MFLAGS, 8, 5, DFLAGS, @@ -663,7 +663,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { /* PD_GMAC */ COMPOSITE(ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_p, 0, - RK3328_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKSEL_CON(25), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3328_CLKGATE_CON(3), 2, GFLAGS), COMPOSITE_NOMUX(PCLK_GMAC, "pclk_gmac", "aclk_gmac", 0, RK3328_CLKSEL_CON(25), 8, 3, DFLAGS, @@ -733,7 +733,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { /* PD_PERI */ GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 11, GFLAGS), - GATE(ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0, RK3328_CLKGATE_CON(19), 4, GFLAGS), + GATE(ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0, RK3328_CLKGATE_CON(19), 14, GFLAGS), GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 0, GFLAGS), GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 1, GFLAGS), @@ -913,7 +913,7 @@ static void __init rk3328_clk_init(struct device_node *np) &rk3328_cpuclk_data, rk3328_cpuclk_rates, ARRAY_SIZE(rk3328_cpuclk_rates)); - rockchip_register_softrst(np, 11, reg_base + RK3328_SOFTRST_CON(0), + rockchip_register_softrst(np, 12, reg_base + RK3328_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); rockchip_register_restart_notifier(ctx, RK3328_GLB_SRST_FST, NULL); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index c3ad92965823..0ea8e8080d1a 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -46,7 +46,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *base, int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, - u8 div_shift, u8 div_width, u8 div_flags, + int div_offset, u8 div_shift, u8 div_width, u8 div_flags, struct clk_div_table *div_table, int gate_offset, u8 gate_shift, u8 gate_flags, unsigned long flags, spinlock_t *lock) @@ -95,7 +95,10 @@ static struct clk *rockchip_clk_register_branch(const char *name, } div->flags = div_flags; - div->reg = base + muxdiv_offset; + if (div_offset) + div->reg = base + div_offset; + else + div->reg = base + muxdiv_offset; div->shift = div_shift; div->width = div_width; div->lock = lock; @@ -516,7 +519,7 @@ void __init rockchip_clk_register_branches( ctx->reg_base, list->muxdiv_offset, list->mux_shift, list->mux_width, list->mux_flags, - list->div_shift, list->div_width, + list->div_offset, list->div_shift, list->div_width, list->div_flags, list->div_table, list->gate_offset, list->gate_shift, list->gate_flags, flags, &ctx->lock); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 6b53fff4cc96..1b5270755431 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -407,6 +407,7 @@ struct rockchip_clk_branch { u8 mux_shift; u8 mux_width; u8 mux_flags; + int div_offset; u8 div_shift; u8 div_width; u8 div_flags; @@ -438,6 +439,28 @@ struct rockchip_clk_branch { .gate_flags = gf, \ } +#define COMPOSITE_DIV_OFFSET(_id, cname, pnames, f, mo, ms, mw, \ + mf, do, ds, dw, df, go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_offset = do, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + #define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df, \ go, gs, gf) \ { \ diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index 0a0b09591e6f..b2da2c8fa0c7 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -209,6 +209,7 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { GATE(CLK_USI1, "usi1", "aclk66", GATE_IP_PERIC, 11, 0, 0), GATE(CLK_USI2, "usi2", "aclk66", GATE_IP_PERIC, 12, 0, 0), GATE(CLK_USI3, "usi3", "aclk66", GATE_IP_PERIC, 13, 0, 0), + GATE(CLK_TSADC, "tsadc", "aclk66", GATE_IP_PERIC, 15, 0, 0), GATE(CLK_PWM, "pwm", "aclk66", GATE_IP_PERIC, 24, 0, 0), GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0", diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig new file mode 100644 index 000000000000..8db4a3eb4782 --- /dev/null +++ b/drivers/clk/sifive/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +menuconfig CLK_SIFIVE + bool "SiFive SoC driver support" + help + SoC drivers for SiFive Linux-capable SoCs. + +if CLK_SIFIVE + +config CLK_SIFIVE_FU540_PRCI + bool "PRCI driver for SiFive FU540 SoCs" + select CLK_ANALOGBITS_WRPLL_CLN28HPC + help + Supports the Power Reset Clock interface (PRCI) IP block found in + FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC, + enable this driver. + +endif diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile new file mode 100644 index 000000000000..74d58a4c0756 --- /dev/null +++ b/drivers/clk/sifive/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c new file mode 100644 index 000000000000..0ec8bf7b4b28 --- /dev/null +++ b/drivers/clk/sifive/fu540-prci.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018-2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * The FU540 PRCI implements clock and reset control for the SiFive + * FU540-C000 chip. This driver assumes that it has sole control + * over all PRCI resources. + * + * This driver is based on the PRCI driver written by Wesley Terpstra: + * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60 + * + * References: + * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset" + */ + +#include <dt-bindings/clock/sifive-fu540-prci.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/clk/analogbits-wrpll-cln28hpc.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_clk.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* + * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: + * hfclk and rtcclk + */ +#define EXPECTED_CLK_PARENT_COUNT 2 + +/* + * Register offsets and bitmasks + */ + +/* COREPLLCFG0 */ +#define PRCI_COREPLLCFG0_OFFSET 0x4 +# define PRCI_COREPLLCFG0_DIVR_SHIFT 0 +# define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT) +# define PRCI_COREPLLCFG0_DIVF_SHIFT 6 +# define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT) +# define PRCI_COREPLLCFG0_DIVQ_SHIFT 15 +# define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT) +# define PRCI_COREPLLCFG0_RANGE_SHIFT 18 +# define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT) +# define PRCI_COREPLLCFG0_BYPASS_SHIFT 24 +# define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT) +# define PRCI_COREPLLCFG0_FSE_SHIFT 25 +# define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT) +# define PRCI_COREPLLCFG0_LOCK_SHIFT 31 +# define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) + +/* DDRPLLCFG0 */ +#define PRCI_DDRPLLCFG0_OFFSET 0xc +# define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 +# define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT) +# define PRCI_DDRPLLCFG0_DIVF_SHIFT 6 +# define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT) +# define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15 +# define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT) +# define PRCI_DDRPLLCFG0_RANGE_SHIFT 18 +# define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT) +# define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24 +# define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT) +# define PRCI_DDRPLLCFG0_FSE_SHIFT 25 +# define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT) +# define PRCI_DDRPLLCFG0_LOCK_SHIFT 31 +# define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT) + +/* DDRPLLCFG1 */ +#define PRCI_DDRPLLCFG1_OFFSET 0x10 +# define PRCI_DDRPLLCFG1_CKE_SHIFT 24 +# define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) + +/* GEMGXLPLLCFG0 */ +#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c +# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0 +# define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT) +# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6 +# define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT) +# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15 +# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT) +# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18 +# define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT) +# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24 +# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT) +# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25 +# define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT) +# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31 +# define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT) + +/* GEMGXLPLLCFG1 */ +#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 +# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24 +# define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) + +/* CORECLKSEL */ +#define PRCI_CORECLKSEL_OFFSET 0x24 +# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0 +# define PRCI_CORECLKSEL_CORECLKSEL_MASK (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT) + +/* DEVICESRESETREG */ +#define PRCI_DEVICESRESETREG_OFFSET 0x28 +# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 +# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) +# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 +# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) +# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 +# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) +# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 +# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) +# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 +# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) + +/* CLKMUXSTATUSREG */ +#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c +# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1 +# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) + +/* + * Private structures + */ + +/** + * struct __prci_data - per-device-instance data + * @va: base virtual address of the PRCI IP block + * @hw_clks: encapsulates struct clk_hw records + * + * PRCI per-device instance data + */ +struct __prci_data { + void __iomem *va; + struct clk_hw_onecell_data hw_clks; +}; + +/** + * struct __prci_wrpll_data - WRPLL configuration and integration data + * @c: WRPLL current configuration record + * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) + * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL) + * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address + * + * @enable_bypass and @disable_bypass are used for WRPLL instances + * that contain a separate external glitchless clock mux downstream + * from the PLL. The WRPLL internal bypass mux is not glitchless. + */ +struct __prci_wrpll_data { + struct wrpll_cfg c; + void (*enable_bypass)(struct __prci_data *pd); + void (*disable_bypass)(struct __prci_data *pd); + u8 cfg0_offs; +}; + +/** + * struct __prci_clock - describes a clock device managed by PRCI + * @name: user-readable clock name string - should match the manual + * @parent_name: parent name for this clock + * @ops: struct clk_ops for the Linux clock framework to use for control + * @hw: Linux-private clock data + * @pwd: WRPLL-specific data, associated with this clock (if not NULL) + * @pd: PRCI-specific data associated with this clock (if not NULL) + * + * PRCI clock data. Used by the PRCI driver to register PRCI-provided + * clocks to the Linux clock infrastructure. + */ +struct __prci_clock { + const char *name; + const char *parent_name; + const struct clk_ops *ops; + struct clk_hw hw; + struct __prci_wrpll_data *pwd; + struct __prci_data *pd; +}; + +#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw) + +/* + * Private functions + */ + +/** + * __prci_readl() - read from a PRCI register + * @pd: PRCI context + * @offs: register offset to read from (in bytes, from PRCI base address) + * + * Read the register located at offset @offs from the base virtual + * address of the PRCI register target described by @pd, and return + * the value to the caller. + * + * Context: Any context. + * + * Return: the contents of the register described by @pd and @offs. + */ +static u32 __prci_readl(struct __prci_data *pd, u32 offs) +{ + return readl_relaxed(pd->va + offs); +} + +static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) +{ + writel_relaxed(v, pd->va + offs); +} + +/* WRPLL-related private functions */ + +/** + * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters + * @c: ptr to a struct wrpll_cfg record to write config into + * @r: value read from the PRCI PLL configuration register + * + * Given a value @r read from an FU540 PRCI PLL configuration register, + * split it into fields and populate it into the WRPLL configuration record + * pointed to by @c. + * + * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros + * have the same register layout. + * + * Context: Any context. + */ +static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) +{ + u32 v; + + v = r & PRCI_COREPLLCFG0_DIVR_MASK; + v >>= PRCI_COREPLLCFG0_DIVR_SHIFT; + c->divr = v; + + v = r & PRCI_COREPLLCFG0_DIVF_MASK; + v >>= PRCI_COREPLLCFG0_DIVF_SHIFT; + c->divf = v; + + v = r & PRCI_COREPLLCFG0_DIVQ_MASK; + v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT; + c->divq = v; + + v = r & PRCI_COREPLLCFG0_RANGE_MASK; + v >>= PRCI_COREPLLCFG0_RANGE_SHIFT; + c->range = v; + + c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK | + WRPLL_FLAGS_EXT_FEEDBACK_MASK); + + /* external feedback mode not supported */ + c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; +} + +/** + * __prci_wrpll_pack() - pack PLL configuration parameters into a register value + * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg + * + * Using a set of WRPLL configuration values pointed to by @c, + * assemble a PRCI PLL configuration register value, and return it to + * the caller. + * + * Context: Any context. Caller must ensure that the contents of the + * record pointed to by @c do not change during the execution + * of this function. + * + * Returns: a value suitable for writing into a PRCI PLL configuration + * register + */ +static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) +{ + u32 r = 0; + + r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT; + r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; + r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; + r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; + + /* external feedback mode not supported */ + r |= PRCI_COREPLLCFG0_FSE_MASK; + + return r; +} + +/** + * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * + * Read the current configuration of the PLL identified by @pwd from + * the PRCI identified by @pd, and store it into the local configuration + * cache in @pwd. + * + * Context: Any context. Caller must prevent the records pointed to by + * @pd and @pwd from changing during execution. + */ +static void __prci_wrpll_read_cfg(struct __prci_data *pd, + struct __prci_wrpll_data *pwd) +{ + __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); +} + +/** + * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * @c: WRPLL configuration record to write + * + * Write the WRPLL configuration described by @c into the WRPLL + * configuration register identified by @pwd in the PRCI instance + * described by @c. Make a cached copy of the WRPLL's current + * configuration so it can be used by other code. + * + * Context: Any context. Caller must prevent the records pointed to by + * @pd and @pwd from changing during execution. + */ +static void __prci_wrpll_write_cfg(struct __prci_data *pd, + struct __prci_wrpll_data *pwd, + struct wrpll_cfg *c) +{ + __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); + + memcpy(&pwd->c, c, sizeof(*c)); +} + +/* Core clock mux control */ + +/** + * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the HFCLK input source; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +static void __prci_coreclksel_use_hfclk(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r |= PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +/** + * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the PLL output clock; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +static void __prci_coreclksel_use_corepll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +/* + * Linux clock framework integration + * + * See the Linux clock framework documentation for more information on + * these functions. + */ + +static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + + return wrpll_calc_output_rate(&pwd->c, parent_rate); +} + +static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct wrpll_cfg c; + + memcpy(&c, &pwd->c, sizeof(c)); + + wrpll_configure_for_rate(&c, rate, *parent_rate); + + return wrpll_calc_output_rate(&c, *parent_rate); +} + +static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_wrpll_data *pwd = pc->pwd; + struct __prci_data *pd = pc->pd; + int r; + + r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate); + if (r) + return r; + + if (pwd->enable_bypass) + pwd->enable_bypass(pd); + + __prci_wrpll_write_cfg(pd, pwd, &pwd->c); + + udelay(wrpll_calc_max_lock_us(&pwd->c)); + + if (pwd->disable_bypass) + pwd->disable_bypass(pd); + + return 0; +} + +static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = { + .set_rate = sifive_fu540_prci_wrpll_set_rate, + .round_rate = sifive_fu540_prci_wrpll_round_rate, + .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, +}; + +static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = { + .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, +}; + +/* TLCLKSEL clock integration */ + +static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct __prci_clock *pc = clk_hw_to_prci_clock(hw); + struct __prci_data *pd = pc->pd; + u32 v; + u8 div; + + v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET); + v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK; + div = v ? 1 : 2; + + return div_u64(parent_rate, div); +} + +static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = { + .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate, +}; + +/* + * PRCI integration data for each WRPLL instance + */ + +static struct __prci_wrpll_data __prci_corepll_data = { + .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, + .enable_bypass = __prci_coreclksel_use_hfclk, + .disable_bypass = __prci_coreclksel_use_corepll, +}; + +static struct __prci_wrpll_data __prci_ddrpll_data = { + .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET, +}; + +static struct __prci_wrpll_data __prci_gemgxlpll_data = { + .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, +}; + +/* + * List of clock controls provided by the PRCI + */ + +static struct __prci_clock __prci_init_clocks[] = { + [PRCI_CLK_COREPLL] = { + .name = "corepll", + .parent_name = "hfclk", + .ops = &sifive_fu540_prci_wrpll_clk_ops, + .pwd = &__prci_corepll_data, + }, + [PRCI_CLK_DDRPLL] = { + .name = "ddrpll", + .parent_name = "hfclk", + .ops = &sifive_fu540_prci_wrpll_ro_clk_ops, + .pwd = &__prci_ddrpll_data, + }, + [PRCI_CLK_GEMGXLPLL] = { + .name = "gemgxlpll", + .parent_name = "hfclk", + .ops = &sifive_fu540_prci_wrpll_clk_ops, + .pwd = &__prci_gemgxlpll_data, + }, + [PRCI_CLK_TLCLK] = { + .name = "tlclk", + .parent_name = "corepll", + .ops = &sifive_fu540_prci_tlclksel_clk_ops, + }, +}; + +/** + * __prci_register_clocks() - register clock controls in the PRCI with Linux + * @dev: Linux struct device * + * + * Register the list of clock controls described in __prci_init_plls[] with + * the Linux clock framework. + * + * Return: 0 upon success or a negative error code upon failure. + */ +static int __prci_register_clocks(struct device *dev, struct __prci_data *pd) +{ + struct clk_init_data init = { }; + struct __prci_clock *pic; + int parent_count, i, r; + + parent_count = of_clk_get_parent_count(dev->of_node); + if (parent_count != EXPECTED_CLK_PARENT_COUNT) { + dev_err(dev, "expected only two parent clocks, found %d\n", + parent_count); + return -EINVAL; + } + + /* Register PLLs */ + for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) { + pic = &__prci_init_clocks[i]; + + init.name = pic->name; + init.parent_names = &pic->parent_name; + init.num_parents = 1; + init.ops = pic->ops; + pic->hw.init = &init; + + pic->pd = pd; + + if (pic->pwd) + __prci_wrpll_read_cfg(pd, pic->pwd); + + r = devm_clk_hw_register(dev, &pic->hw); + if (r) { + dev_warn(dev, "Failed to register clock %s: %d\n", + init.name, r); + return r; + } + + r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev)); + if (r) { + dev_warn(dev, "Failed to register clkdev for %s: %d\n", + init.name, r); + return r; + } + + pd->hw_clks.hws[i] = &pic->hw; + } + + pd->hw_clks.num = i; + + r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &pd->hw_clks); + if (r) { + dev_err(dev, "could not add hw_provider: %d\n", r); + return r; + } + + return 0; +} + +/* + * Linux device model integration + * + * See the Linux device model documentation for more information about + * these functions. + */ +static int sifive_fu540_prci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct __prci_data *pd; + int r; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pd->va = devm_ioremap_resource(dev, res); + if (IS_ERR(pd->va)) + return PTR_ERR(pd->va); + + r = __prci_register_clocks(dev, pd); + if (r) { + dev_err(dev, "could not register clocks: %d\n", r); + return r; + } + + dev_dbg(dev, "SiFive FU540 PRCI probed\n"); + + return 0; +} + +static const struct of_device_id sifive_fu540_prci_of_match[] = { + { .compatible = "sifive,fu540-c000-prci", }, + {} +}; +MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match); + +static struct platform_driver sifive_fu540_prci_driver = { + .driver = { + .name = "sifive-fu540-prci", + .of_match_table = sifive_fu540_prci_of_match, + }, + .probe = sifive_fu540_prci_probe, +}; + +static int __init sifive_fu540_prci_init(void) +{ + return platform_driver_register(&sifive_fu540_prci_driver); +} +core_initcall(sifive_fu540_prci_init); diff --git a/drivers/clk/sprd/common.h b/drivers/clk/sprd/common.h index abd9ff5ef448..1d077b39cef6 100644 --- a/drivers/clk/sprd/common.h +++ b/drivers/clk/sprd/common.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ // // Spreadtrum clock infrastructure // diff --git a/drivers/clk/sprd/composite.h b/drivers/clk/sprd/composite.h index 0984e9e252dc..04ab3f587ee2 100644 --- a/drivers/clk/sprd/composite.h +++ b/drivers/clk/sprd/composite.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ // // Spreadtrum composite clock driver // diff --git a/drivers/clk/sprd/div.h b/drivers/clk/sprd/div.h index b3033d24d431..87510e3d0e14 100644 --- a/drivers/clk/sprd/div.h +++ b/drivers/clk/sprd/div.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ // // Spreadtrum divider clock driver // diff --git a/drivers/clk/sprd/gate.h b/drivers/clk/sprd/gate.h index 2e582c68a08b..dc352ea55e1f 100644 --- a/drivers/clk/sprd/gate.h +++ b/drivers/clk/sprd/gate.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ // // Spreadtrum gate clock driver // diff --git a/drivers/clk/sprd/mux.h b/drivers/clk/sprd/mux.h index 548cfa0f145c..892e4191cc7f 100644 --- a/drivers/clk/sprd/mux.h +++ b/drivers/clk/sprd/mux.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ // // Spreadtrum multiplexer clock driver // diff --git a/drivers/clk/sprd/pll.h b/drivers/clk/sprd/pll.h index 514175621099..e95f11e91ffe 100644 --- a/drivers/clk/sprd/pll.h +++ b/drivers/clk/sprd/pll.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ // // Spreadtrum pll clock driver // diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 932836d26e2b..be0deee70182 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -531,7 +531,8 @@ static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram", static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" }; static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, - 0x104, 0, 4, 24, 3, BIT(31), 0); + 0x104, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static const char * const tcon0_parents[] = { "pll-mipi", "pll-video0-2x" }; static const u8 tcon0_table[] = { 0, 2, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index 139e8389615c..3c32d7798f27 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -266,7 +266,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, 0, 4, /* M */ 24, 1, /* mux */ BIT(31), /* gate */ - 0); + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", 0x60c, BIT(0), 0); @@ -311,7 +311,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, 0, 3, /* M */ 24, 1, /* mux */ BIT(31), /* gate */ - 0); + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", 0x69c, BIT(0), 0); @@ -656,6 +656,8 @@ static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { { .index = 1, .div = 36621 }, }; + +#define SUN50I_H6_HDMI_CEC_CLK_REG 0xb10 static struct ccu_mux hdmi_cec_clk = { .enable = BIT(31), @@ -689,7 +691,7 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_lcd0_parents, 0xb60, 24, 3, /* mux */ BIT(31), /* gate */ - 0); + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(bus_tcon_lcd0_clk, "bus-tcon-lcd0", "ahb3", 0xb7c, BIT(0), 0); @@ -704,7 +706,7 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", 8, 2, /* P */ 24, 3, /* mux */ BIT(31), /* gate */ - 0); + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", 0xb9c, BIT(0), 0); @@ -1200,6 +1202,15 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev) val &= ~(GENMASK(21, 16) | BIT(0)); writel(val | (7 << 16), reg + SUN50I_H6_PLL_AUDIO_REG); + /* + * First clock parent (osc32K) is unusable for CEC. But since there + * is no good way to force parent switch (both run with same frequency), + * just set second clock parent here. + */ + val = readl(reg + SUN50I_H6_HDMI_CEC_CLK_REG); + val |= BIT(24); + writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG); + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc); } diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.h b/drivers/clk/sunxi-ng/ccu-sun50i-h6.h index 2ccfe4428260..9406f9a6a8aa 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.h +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright 2016 Icenowy Zheng <icenowy@aosc.io> */ diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.h b/drivers/clk/sunxi-ng/ccu-sun5i.h index 93a275fbd9a9..b66abd4fd0bf 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.h +++ b/drivers/clk/sunxi-ng/ccu-sun5i.h @@ -60,10 +60,6 @@ /* The rest of the module clocks are exported */ -#define CLK_MBUS 99 - -/* And finally the IEP clock */ - #define CLK_NUMBER (CLK_IEP + 1) #endif /* _CCU_SUN5I_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 2d6555d73170..5f714b4d8ee4 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -513,8 +513,9 @@ static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0); static SUNXI_CCU_GATE(mipi_csi_clk, "mipi-csi", "osc24M", 0x130, BIT(31), 0); -static const char * const csi_mclk_parents[] = { "pll-de", "osc24M" }; -static const u8 csi_mclk_table[] = { 3, 5 }; +static const char * const csi_mclk_parents[] = { "pll-video0", "pll-de", + "osc24M" }; +static const u8 csi_mclk_table[] = { 0, 3, 5 }; static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, csi_mclk_table, 0x134, diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index ac12f261f8ca..eada0e291859 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -325,7 +325,8 @@ static SUNXI_CCU_GATE(dram_ohci_clk, "dram-ohci", "dram", static const char * const de_parents[] = { "pll-video", "pll-periph0" }; static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, - 0x104, 0, 4, 24, 2, BIT(31), 0); + 0x104, 0, 4, 24, 2, BIT(31), + CLK_SET_RATE_PARENT); static const char * const tcon_parents[] = { "pll-video" }; static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents, diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c index a09dfbe36402..dc9f0a365664 100644 --- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c +++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c @@ -240,7 +240,7 @@ static SUNXI_CCU_MUX_WITH_GATE(spdif_clk, "spdif", i2s_spdif_parents, /* The BSP header file has a CIR_CFG, but no mod clock uses this definition */ static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", - 0x0cc, BIT(8), 0); + 0x0cc, BIT(1), 0); static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "pll-ddr", 0x100, BIT(0), 0); diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.h b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.h index 39d06fed55b2..b22484f1bb9a 100644 --- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.h +++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0+ - * +/* SPDX-License-Identifier: GPL-2.0+ */ +/* * Copyright 2017 Icenowy Zheng <icenowy@aosc.io> * */ diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig new file mode 100644 index 000000000000..2b6207cc4eda --- /dev/null +++ b/drivers/clk/sunxi/Kconfig @@ -0,0 +1,43 @@ +menuconfig CLK_SUNXI + bool "Legacy clock support for Allwinner SoCs" + depends on ARCH_SUNXI || COMPILE_TEST + default y + +if CLK_SUNXI + +config CLK_SUNXI_CLOCKS + bool "Legacy clock drivers" + default y + help + Legacy clock drivers being used on older (A10, A13, A20, + A23, A31, A80) SoCs. These drivers are kept around for + Device Tree backward compatibility issues, in case one would + still use a Device Tree with one clock provider by + node. Newer Device Trees and newer SoCs use the drivers + controlled by CONFIG_SUNXI_CCU. + +config CLK_SUNXI_PRCM_SUN6I + bool "Legacy A31 PRCM driver" + select MFD_SUN6I_PRCM + default y + help + Legacy clock driver for the A31 PRCM clocks. Those are + usually needed for the PMIC communication, mostly. + +config CLK_SUNXI_PRCM_SUN8I + bool "Legacy sun8i PRCM driver" + select MFD_SUN6I_PRCM + default y + help + Legacy clock driver for the sun8i family PRCM clocks. + Those are usually needed for the PMIC communication, + mostly. + +config CLK_SUNXI_PRCM_SUN9I + bool "Legacy A80 PRCM driver" + default y + help + Legacy clock driver for the A80 PRCM clocks. Those are + usually needed for the PMIC communication, mostly. + +endif diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index be88368b48a1..e10824c76ae9 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -3,27 +3,32 @@ # Makefile for sunxi specific clk # -obj-y += clk-sunxi.o clk-factors.o -obj-y += clk-a10-codec.o -obj-y += clk-a10-hosc.o -obj-y += clk-a10-mod1.o -obj-y += clk-a10-pll2.o -obj-y += clk-a10-ve.o -obj-y += clk-a20-gmac.o -obj-y += clk-mod0.o -obj-y += clk-simple-gates.o -obj-y += clk-sun4i-display.o -obj-y += clk-sun4i-pll3.o -obj-y += clk-sun4i-tcon-ch1.o -obj-y += clk-sun8i-bus-gates.o -obj-y += clk-sun8i-mbus.o -obj-y += clk-sun9i-core.o -obj-y += clk-sun9i-mmc.o -obj-y += clk-usb.o +obj-$(CONFIG_CLK_SUNXI) += clk-factors.o -obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o -obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sunxi.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-a10-codec.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-a10-hosc.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-a10-mod1.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-a10-pll2.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-a10-ve.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-a20-gmac.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-mod0.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-simple-gates.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun4i-display.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun4i-pll3.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun4i-tcon-ch1.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun8i-bus-gates.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun8i-mbus.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun9i-core.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun9i-mmc.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-usb.o -obj-$(CONFIG_MFD_SUN6I_PRCM) += \ - clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ - clk-sun8i-apb0.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun8i-apb0.o +obj-$(CONFIG_CLK_SUNXI_CLOCKS) += clk-sun9i-cpus.o + +obj-$(CONFIG_CLK_SUNXI_PRCM_SUN6I) += clk-sun6i-apb0.o +obj-$(CONFIG_CLK_SUNXI_PRCM_SUN6I) += clk-sun6i-apb0-gates.o +obj-$(CONFIG_CLK_SUNXI_PRCM_SUN6I) += clk-sun6i-ar100.o + +obj-$(CONFIG_CLK_SUNXI_PRCM_SUN8I) += clk-sun8i-apb0.o +obj-$(CONFIG_CLK_SUNXI_PRCM_SUN8I) += clk-sun6i-apb0-gates.o diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 205fe8ff63f0..2a1822a22740 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -175,6 +175,7 @@ struct clk *tegra_clk_register_mc(const char *name, const char *parent_name, void __iomem *reg, spinlock_t *lock) { return clk_register_divider_table(NULL, name, parent_name, - CLK_IS_CRITICAL, reg, 16, 1, 0, + CLK_IS_CRITICAL, + reg, 16, 1, CLK_DIVIDER_READ_ONLY, mc_div_table, lock); } diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 0621a3a82ea6..93ecb538e59b 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -121,18 +121,28 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) struct tegra_clk_emc *tegra; u8 ram_code = tegra_read_ram_code(); struct emc_timing *timing = NULL; - int i; + int i, k, t; tegra = container_of(hw, struct tegra_clk_emc, hw); - for (i = 0; i < tegra->num_timings; i++) { - if (tegra->timings[i].ram_code != ram_code) - continue; + for (k = 0; k < tegra->num_timings; k++) { + if (tegra->timings[k].ram_code == ram_code) + break; + } + + for (t = k; t < tegra->num_timings; t++) { + if (tegra->timings[t].ram_code != ram_code) + break; + } + for (i = k; i < t; i++) { timing = tegra->timings + i; + if (timing->rate < req->rate && i != t - 1) + continue; + if (timing->rate > req->max_rate) { - i = max(i, 1); + i = max(i, k + 1); req->rate = tegra->timings[i - 1].rate; return 0; } @@ -140,10 +150,8 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) if (timing->rate < req->min_rate) continue; - if (timing->rate >= req->rate) { - req->rate = timing->rate; - return 0; - } + req->rate = timing->rate; + return 0; } if (timing) { @@ -214,7 +222,10 @@ static int emc_set_timing(struct tegra_clk_emc *tegra, if (emc_get_parent(&tegra->hw) == timing->parent_index && clk_get_rate(timing->parent) != timing->parent_rate) { - BUG(); + WARN_ONCE(1, "parent %s rate mismatch %lu %lu\n", + __clk_get_name(timing->parent), + clk_get_rate(timing->parent), + timing->parent_rate); return -EINVAL; } @@ -282,7 +293,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, for (i = timing_index+1; i < tegra->num_timings; i++) { timing = tegra->timings + i; if (timing->ram_code != ram_code) - continue; + break; if (emc_parent_clk_sources[timing->parent_index] != emc_parent_clk_sources[ @@ -293,7 +304,7 @@ static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, for (i = timing_index-1; i >= 0; --i) { timing = tegra->timings + i; if (timing->ram_code != ram_code) - continue; + break; if (emc_parent_clk_sources[timing->parent_index] != emc_parent_clk_sources[ @@ -433,19 +444,23 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, struct device_node *node, u32 ram_code) { + struct emc_timing *timings_ptr; struct device_node *child; int child_count = of_get_child_count(node); int i = 0, err; + size_t size; - tegra->timings = kcalloc(child_count, sizeof(struct emc_timing), - GFP_KERNEL); + size = (tegra->num_timings + child_count) * sizeof(struct emc_timing); + + tegra->timings = krealloc(tegra->timings, size, GFP_KERNEL); if (!tegra->timings) return -ENOMEM; - tegra->num_timings = child_count; + timings_ptr = tegra->timings + tegra->num_timings; + tegra->num_timings += child_count; for_each_child_of_node(node, child) { - struct emc_timing *timing = tegra->timings + (i++); + struct emc_timing *timing = timings_ptr + (i++); err = load_one_timing_from_dt(tegra, timing, child); if (err) { @@ -456,7 +471,7 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra, timing->ram_code = ram_code; } - sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing), + sort(timings_ptr, child_count, sizeof(struct emc_timing), cmp_timings, NULL); return 0; @@ -499,10 +514,10 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, * fuses until the apbmisc driver is loaded. */ err = load_timings_from_dt(tegra, node, node_ram_code); - of_node_put(node); - if (err) + if (err) { + of_node_put(node); return ERR_PTR(err); - break; + } } if (tegra->num_timings == 0) @@ -532,7 +547,5 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, /* Allow debugging tools to see the EMC clock */ clk_register_clkdev(clk, "emc", "tegra-clk-debug"); - clk_prepare_enable(clk); - return clk; }; diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index b50b7460014b..6b976b2514f7 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -444,6 +444,9 @@ static int clk_pll_enable(struct clk_hw *hw) unsigned long flags = 0; int ret; + if (clk_pll_is_enabled(hw)) + return 0; + if (pll->lock) spin_lock_irqsave(pll->lock, flags); @@ -663,8 +666,8 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll, pll_override_writel(val, params->pmc_divp_reg, pll); val = pll_override_readl(params->pmc_divnm_reg, pll); - val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) | - ~(divn_mask(pll) << div_nmp->override_divn_shift); + val &= ~((divm_mask(pll) << div_nmp->override_divm_shift) | + (divn_mask(pll) << div_nmp->override_divn_shift)); val |= (cfg->m << div_nmp->override_divm_shift) | (cfg->n << div_nmp->override_divn_shift); pll_override_writel(val, params->pmc_divnm_reg, pll); @@ -940,11 +943,16 @@ static int clk_plle_training(struct tegra_clk_pll *pll) static int clk_plle_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); - unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); struct tegra_clk_pll_freq_table sel; + unsigned long input_rate; u32 val; int err; + if (clk_pll_is_enabled(hw)) + return 0; + + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); + if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; @@ -1355,6 +1363,9 @@ static int clk_pllc_enable(struct clk_hw *hw) int ret; unsigned long flags = 0; + if (clk_pll_is_enabled(hw)) + return 0; + if (pll->lock) spin_lock_irqsave(pll->lock, flags); @@ -1567,7 +1578,12 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) u32 val; int ret; unsigned long flags = 0; - unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); + unsigned long input_rate; + + if (clk_pll_is_enabled(hw)) + return 0; + + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; @@ -1704,6 +1720,9 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw) return -EINVAL; } + if (clk_pll_is_enabled(hw)) + return 0; + input_rate = clk_hw_get_rate(__clk_get_hw(osc)); if (pll->lock) @@ -2379,6 +2398,16 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name, return clk; } +static int clk_plle_tegra210_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + val = pll_readl_base(pll); + + return val & PLLE_BASE_ENABLE ? 1 : 0; +} + static int clk_plle_tegra210_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); @@ -2386,7 +2415,12 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw) u32 val; int ret = 0; unsigned long flags = 0; - unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); + unsigned long input_rate; + + if (clk_plle_tegra210_is_enabled(hw)) + return 0; + + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; @@ -2497,16 +2531,6 @@ out: spin_unlock_irqrestore(pll->lock, flags); } -static int clk_plle_tegra210_is_enabled(struct clk_hw *hw) -{ - struct tegra_clk_pll *pll = to_clk_pll(hw); - u32 val; - - val = pll_readl_base(pll); - - return val & PLLE_BASE_ENABLE ? 1 : 0; -} - static const struct clk_ops tegra_clk_plle_tegra210_ops = { .is_enabled = clk_plle_tegra210_is_enabled, .enable = clk_plle_tegra210_enable, diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c index 84267cfc4433..b5ff76c663f8 100644 --- a/drivers/clk/tegra/clk-super.c +++ b/drivers/clk/tegra/clk-super.c @@ -121,7 +121,7 @@ out: return err; } -const struct clk_ops tegra_clk_super_mux_ops = { +static const struct clk_ops tegra_clk_super_mux_ops = { .get_parent = clk_super_get_parent, .set_parent = clk_super_set_parent, }; diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index df0018f7bf7e..d7bee144f4b7 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -413,7 +413,6 @@ static struct tegra_clk_pll_params pll_m_params = { .base_reg = PLLM_BASE, .misc_reg = PLLM_MISC, .lock_mask = PLL_BASE_LOCK, - .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, .max_p = 5, .pdiv_tohw = pllm_p, @@ -421,7 +420,7 @@ static struct tegra_clk_pll_params pll_m_params = { .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2, .freq_table = pll_m_freq_table, - .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, + .flags = TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { @@ -1466,9 +1465,9 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np) tegra_pmc_clk_init(pmc_base, tegra124_clks); /* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */ - plld_base = clk_readl(clk_base + PLLD_BASE); + plld_base = readl(clk_base + PLLD_BASE); plld_base &= ~BIT(25); - clk_writel(plld_base, clk_base + PLLD_BASE); + writel(plld_base, clk_base + PLLD_BASE); } /** diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 7545af763d7a..ed3c7df75d1e 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -3557,7 +3557,7 @@ static void __init tegra210_clock_init(struct device_node *np) if (!clks) return; - value = clk_readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT; + value = readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT; clk_m_div = (value & CLK_M_DIVISOR_MASK) + 1; if (tegra_osc_clk_init(clk_base, tegra210_clks, tegra210_input_freq, @@ -3574,9 +3574,9 @@ static void __init tegra210_clock_init(struct device_node *np) tegra_pmc_clk_init(pmc_base, tegra210_clks); /* For Tegra210, PLLD is the only source for DSIA & DSIB */ - value = clk_readl(clk_base + PLLD_BASE); + value = readl(clk_base + PLLD_BASE); value &= ~BIT(25); - clk_writel(value, clk_base + PLLD_BASE); + writel(value, clk_base + PLLD_BASE); tegra_clk_apply_init_table = tegra210_clock_apply_init_table; diff --git a/drivers/clk/ti/clk-7xx-compat.c b/drivers/clk/ti/clk-7xx-compat.c index e3cb7f0b03ae..b3cd2296f84b 100644 --- a/drivers/clk/ti/clk-7xx-compat.c +++ b/drivers/clk/ti/clk-7xx-compat.c @@ -362,7 +362,7 @@ static const struct omap_clkctrl_reg_data dra7_l3init_clkctrl_regs[] __initconst { DRA7_MMC2_CLKCTRL, dra7_mmc2_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0010:25" }, { DRA7_USB_OTG_SS2_CLKCTRL, dra7_usb_otg_ss2_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, { DRA7_USB_OTG_SS3_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, - { DRA7_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { DRA7_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_DRA74 | CLKF_SOC_DRA76, "dpll_core_h13x2_ck" }, { DRA7_SATA_CLKCTRL, dra7_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" }, { DRA7_PCIE1_CLKCTRL, dra7_pcie1_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" }, { DRA7_PCIE2_CLKCTRL, dra7_pcie2_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" }, @@ -662,7 +662,7 @@ static const struct omap_clkctrl_reg_data dra7_l4per_clkctrl_regs[] __initconst { DRA7_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, { DRA7_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, { DRA7_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, - { DRA7_RNG_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, + { DRA7_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l3_iclk_div", "l4sec_clkdm" }, { DRA7_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, { DRA7_UART7_CLKCTRL, dra7_uart7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01d0:24", "l4per2_clkdm" }, { DRA7_UART8_CLKCTRL, dra7_uart8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e0:24", "l4per2_clkdm" }, @@ -704,7 +704,7 @@ static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initcons { DRA7_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, { DRA7_GPIO1_CLKCTRL, dra7_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" }, { DRA7_TIMER1_CLKCTRL, dra7_timer1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0020:24" }, - { DRA7_TIMER12_CLKCTRL, NULL, 0, "secure_32k_clk_src_ck" }, + { DRA7_TIMER12_CLKCTRL, NULL, CLKF_SOC_NONSEC, "secure_32k_clk_src_ck" }, { DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, { DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" }, { DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" }, diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index 597fb4a59318..79186b918d87 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -348,7 +348,7 @@ static const struct omap_clkctrl_reg_data dra7_l3init_clkctrl_regs[] __initconst { DRA7_L3INIT_MMC2_CLKCTRL, dra7_mmc2_bit_data, CLKF_SW_SUP, "l3init-clkctrl:0010:25" }, { DRA7_L3INIT_USB_OTG_SS2_CLKCTRL, dra7_usb_otg_ss2_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, { DRA7_L3INIT_USB_OTG_SS3_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, - { DRA7_L3INIT_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { DRA7_L3INIT_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_DRA74 | CLKF_SOC_DRA76, "dpll_core_h13x2_ck" }, { DRA7_L3INIT_SATA_CLKCTRL, dra7_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" }, { DRA7_L3INIT_OCP2SCP1_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" }, { DRA7_L3INIT_OCP2SCP3_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" }, @@ -590,7 +590,7 @@ static const struct omap_clkctrl_reg_data dra7_l4sec_clkctrl_regs[] __initconst { DRA7_L4SEC_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, { DRA7_L4SEC_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, { DRA7_L4SEC_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, - { DRA7_L4SEC_RNG_CLKCTRL, NULL, CLKF_HW_SUP, "" }, + { DRA7_L4SEC_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "" }, { DRA7_L4SEC_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, { 0 }, }; @@ -757,7 +757,7 @@ static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initcons { DRA7_WKUPAON_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, { DRA7_WKUPAON_GPIO1_CLKCTRL, dra7_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" }, { DRA7_WKUPAON_TIMER1_CLKCTRL, dra7_timer1_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0020:24" }, - { DRA7_WKUPAON_TIMER12_CLKCTRL, NULL, 0, "secure_32k_clk_src_ck" }, + { DRA7_WKUPAON_TIMER12_CLKCTRL, NULL, CLKF_SOC_NONSEC, "secure_32k_clk_src_ck" }, { DRA7_WKUPAON_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, { DRA7_WKUPAON_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0060:24" }, { DRA7_WKUPAON_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0068:24" }, diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index 639f515e08f0..96d65a1cf7be 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -446,6 +446,7 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) u32 addr; int ret; char *c; + u16 soc_mask = 0; if (!(ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) && of_node_name_eq(node, "clk")) @@ -469,6 +470,13 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) else data = dra7_clkctrl_data; } + + if (of_machine_is_compatible("ti,dra72")) + soc_mask = CLKF_SOC_DRA72; + if (of_machine_is_compatible("ti,dra74")) + soc_mask = CLKF_SOC_DRA74; + if (of_machine_is_compatible("ti,dra76")) + soc_mask = CLKF_SOC_DRA76; #endif #ifdef CONFIG_SOC_AM33XX if (of_machine_is_compatible("ti,am33xx")) { @@ -501,6 +509,9 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) data = dm816_clkctrl_data; #endif + if (ti_clk_get_features()->flags & TI_CLK_DEVICE_TYPE_GP) + soc_mask |= CLKF_SOC_NONSEC; + while (data->addr) { if (addr == data->addr) break; @@ -562,6 +573,12 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) reg_data = data->regs; while (reg_data->parent) { + if ((reg_data->flags & CLKF_SOC_MASK) && + (reg_data->flags & soc_mask) == 0) { + reg_data++; + continue; + } + hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) return; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 1c0fac59d809..e4b8392ff63c 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -83,6 +83,13 @@ enum { #define CLKF_HW_SUP BIT(6) #define CLKF_NO_IDLEST BIT(7) +#define CLKF_SOC_MASK GENMASK(11, 8) + +#define CLKF_SOC_NONSEC BIT(8) +#define CLKF_SOC_DRA72 BIT(9) +#define CLKF_SOC_DRA74 BIT(10) +#define CLKF_SOC_DRA76 BIT(11) + #define CLK(dev, con, ck) \ { \ .lk = { \ @@ -303,7 +310,6 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)); -bool omap2_clk_is_hw_omap(struct clk_hw *hw); extern struct ti_clk_ll_ops *ti_clk_ll_ops; diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c index 7c0403b733ae..698306f4801f 100644 --- a/drivers/clk/ux500/clk-sysctrl.c +++ b/drivers/clk/ux500/clk-sysctrl.c @@ -42,7 +42,8 @@ static int clk_sysctrl_prepare(struct clk_hw *hw) clk->reg_bits[0]); if (!ret && clk->enable_delay_us) - usleep_range(clk->enable_delay_us, clk->enable_delay_us); + usleep_range(clk->enable_delay_us, clk->enable_delay_us + + (clk->enable_delay_us >> 2)); return ret; } diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index d7b53ac8ad11..4b9d5c14c400 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -158,7 +158,7 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk, clks[fclk] = clk_register_gate(NULL, clk_name, div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg, 0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock); - enable_reg = clk_readl(fclk_gate_reg) & 1; + enable_reg = readl(fclk_gate_reg) & 1; if (enable && !enable_reg) { if (clk_prepare_enable(clks[fclk])) pr_warn("%s: FCLK%u enable failed\n", __func__, @@ -287,7 +287,7 @@ static void __init zynq_clk_setup(struct device_node *np) SLCR_IOPLL_CTRL, 4, 1, 0, &iopll_lock); /* CPU clocks */ - tmp = clk_readl(SLCR_621_TRUE) & 1; + tmp = readl(SLCR_621_TRUE) & 1; clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, CLK_SET_RATE_NO_REPARENT, SLCR_ARM_CLK_CTRL, 4, 2, 0, &armclk_lock); @@ -510,7 +510,7 @@ static void __init zynq_clk_setup(struct device_node *np) &dbgclk_lock); /* leave debug clocks in the state the bootloader set them up to */ - tmp = clk_readl(SLCR_DBG_CLK_CTRL); + tmp = readl(SLCR_DBG_CLK_CTRL); if (tmp & DBG_CLK_CTRL_CLKACT_TRC) if (clk_prepare_enable(clks[dbg_trc])) pr_warn("%s: trace clk enable failed\n", __func__); diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c index 00d72fb5c036..800b70ee19b3 100644 --- a/drivers/clk/zynq/pll.c +++ b/drivers/clk/zynq/pll.c @@ -90,7 +90,7 @@ static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, * makes probably sense to redundantly save fbdiv in the struct * zynq_pll to save the IO access. */ - fbdiv = (clk_readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> + fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; return parent_rate * fbdiv; @@ -112,7 +112,7 @@ static int zynq_pll_is_enabled(struct clk_hw *hw) spin_lock_irqsave(clk->lock, flags); - reg = clk_readl(clk->pll_ctrl); + reg = readl(clk->pll_ctrl); spin_unlock_irqrestore(clk->lock, flags); @@ -138,10 +138,10 @@ static int zynq_pll_enable(struct clk_hw *hw) /* Power up PLL and wait for lock */ spin_lock_irqsave(clk->lock, flags); - reg = clk_readl(clk->pll_ctrl); + reg = readl(clk->pll_ctrl); reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); - clk_writel(reg, clk->pll_ctrl); - while (!(clk_readl(clk->pll_status) & (1 << clk->lockbit))) + writel(reg, clk->pll_ctrl); + while (!(readl(clk->pll_status) & (1 << clk->lockbit))) ; spin_unlock_irqrestore(clk->lock, flags); @@ -168,9 +168,9 @@ static void zynq_pll_disable(struct clk_hw *hw) /* shut down PLL */ spin_lock_irqsave(clk->lock, flags); - reg = clk_readl(clk->pll_ctrl); + reg = readl(clk->pll_ctrl); reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; - clk_writel(reg, clk->pll_ctrl); + writel(reg, clk->pll_ctrl); spin_unlock_irqrestore(clk->lock, flags); } @@ -223,9 +223,9 @@ struct clk *clk_register_zynq_pll(const char *name, const char *parent, spin_lock_irqsave(pll->lock, flags); - reg = clk_readl(pll->pll_ctrl); + reg = readl(pll->pll_ctrl); reg &= ~PLLCTRL_BPQUAL_MASK; - clk_writel(reg, pll->pll_ctrl); + writel(reg, pll->pll_ctrl); spin_unlock_irqrestore(pll->lock, flags); diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c index 4143f560c28d..0af8f74c5fa5 100644 --- a/drivers/clk/zynqmp/clk-mux-zynqmp.c +++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c @@ -138,4 +138,3 @@ struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id, return hw; } -EXPORT_SYMBOL_GPL(zynqmp_clk_register_mux); diff --git a/drivers/clk/zynqmp/clk-zynqmp.h b/drivers/clk/zynqmp/clk-zynqmp.h index 7ab163b67249..fec9a15c8786 100644 --- a/drivers/clk/zynqmp/clk-zynqmp.h +++ b/drivers/clk/zynqmp/clk-zynqmp.h @@ -10,12 +10,6 @@ #include <linux/firmware/xlnx-zynqmp.h> -/* Clock APIs payload parameters */ -#define CLK_GET_NAME_RESP_LEN 16 -#define CLK_GET_TOPOLOGY_RESP_WORDS 3 -#define CLK_GET_PARENTS_RESP_WORDS 3 -#define CLK_GET_ATTR_RESP_WORDS 1 - enum topology_type { TYPE_INVALID, TYPE_MUX, diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c index b0908ec62f73..8febd2431545 100644 --- a/drivers/clk/zynqmp/clkc.c +++ b/drivers/clk/zynqmp/clkc.c @@ -21,24 +21,6 @@ #define MAX_NODES 6 #define MAX_NAME_LEN 50 -#define CLK_TYPE_SHIFT 2 - -#define PM_API_PAYLOAD_LEN 3 - -#define NA_PARENT 0xFFFFFFFF -#define DUMMY_PARENT 0xFFFFFFFE - -#define CLK_TYPE_FIELD_LEN 4 -#define CLK_TOPOLOGY_NODE_OFFSET 16 -#define NODES_PER_RESP 3 - -#define CLK_TYPE_FIELD_MASK 0xF -#define CLK_FLAG_FIELD_MASK GENMASK(21, 8) -#define CLK_TYPE_FLAG_FIELD_MASK GENMASK(31, 24) - -#define CLK_PARENTS_ID_LEN 16 -#define CLK_PARENTS_ID_MASK 0xFFFF - /* Flags for parents */ #define PARENT_CLK_SELF 0 #define PARENT_CLK_NODE1 1 @@ -52,7 +34,10 @@ #define END_OF_PARENTS 1 #define RESERVED_CLK_NAME "" -#define CLK_VALID_MASK 0x1 +#define CLK_GET_NAME_RESP_LEN 16 +#define CLK_GET_TOPOLOGY_RESP_WORDS 3 +#define CLK_GET_PARENTS_RESP_WORDS 3 +#define CLK_GET_ATTR_RESP_WORDS 1 enum clk_type { CLK_TYPE_OUTPUT, @@ -80,6 +65,7 @@ struct clock_parent { * @num_nodes: Number of nodes present in topology * @parent: Parent of clock * @num_parents: Number of parents of clock + * @clk_id: Clock id */ struct zynqmp_clock { char clk_name[MAX_NAME_LEN]; @@ -89,6 +75,36 @@ struct zynqmp_clock { u32 num_nodes; struct clock_parent parent[MAX_PARENT]; u32 num_parents; + u32 clk_id; +}; + +struct name_resp { + char name[CLK_GET_NAME_RESP_LEN]; +}; + +struct topology_resp { +#define CLK_TOPOLOGY_TYPE GENMASK(3, 0) +#define CLK_TOPOLOGY_FLAGS GENMASK(23, 8) +#define CLK_TOPOLOGY_TYPE_FLAGS GENMASK(31, 24) + u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS]; +}; + +struct parents_resp { +#define NA_PARENT 0xFFFFFFFF +#define DUMMY_PARENT 0xFFFFFFFE +#define CLK_PARENTS_ID GENMASK(15, 0) +#define CLK_PARENTS_FLAGS GENMASK(31, 16) + u32 parents[CLK_GET_PARENTS_RESP_WORDS]; +}; + +struct attr_resp { +#define CLK_ATTR_VALID BIT(0) +#define CLK_ATTR_TYPE BIT(2) +#define CLK_ATTR_NODE_INDEX GENMASK(13, 0) +#define CLK_ATTR_NODE_TYPE GENMASK(19, 14) +#define CLK_ATTR_NODE_SUBCLASS GENMASK(25, 20) +#define CLK_ATTR_NODE_CLASS GENMASK(31, 26) + u32 attr[CLK_GET_ATTR_RESP_WORDS]; }; static const char clk_type_postfix[][10] = { @@ -199,14 +215,15 @@ static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks) /** * zynqmp_pm_clock_get_name() - Get the name of clock for given id * @clock_id: ID of the clock to be queried - * @name: Name of given clock + * @response: Name of the clock with the given id * * This function is used to get name of clock specified by given * clock ID. * - * Return: Returns 0, in case of error name would be 0 + * Return: Returns 0 */ -static int zynqmp_pm_clock_get_name(u32 clock_id, char *name) +static int zynqmp_pm_clock_get_name(u32 clock_id, + struct name_resp *response) { struct zynqmp_pm_query_data qdata = {0}; u32 ret_payload[PAYLOAD_ARG_CNT]; @@ -215,7 +232,7 @@ static int zynqmp_pm_clock_get_name(u32 clock_id, char *name) qdata.arg1 = clock_id; eemi_ops->query_data(qdata, ret_payload); - memcpy(name, ret_payload, CLK_GET_NAME_RESP_LEN); + memcpy(response, ret_payload, sizeof(*response)); return 0; } @@ -224,7 +241,7 @@ static int zynqmp_pm_clock_get_name(u32 clock_id, char *name) * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id * @clock_id: ID of the clock to be queried * @index: Node index of clock topology - * @topology: Buffer to store nodes in topology and flags + * @response: Buffer used for the topology response * * This function is used to get topology information for the clock * specified by given clock ID. @@ -237,7 +254,8 @@ static int zynqmp_pm_clock_get_name(u32 clock_id, char *name) * * Return: 0 on success else error+reason */ -static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, u32 *topology) +static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, + struct topology_resp *response) { struct zynqmp_pm_query_data qdata = {0}; u32 ret_payload[PAYLOAD_ARG_CNT]; @@ -248,7 +266,7 @@ static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, u32 *topology) qdata.arg2 = index; ret = eemi_ops->query_data(qdata, ret_payload); - memcpy(topology, &ret_payload[1], CLK_GET_TOPOLOGY_RESP_WORDS * 4); + memcpy(response, &ret_payload[1], sizeof(*response)); return ret; } @@ -297,7 +315,7 @@ struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id, * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id * @clock_id: Clock ID * @index: Parent index - * @parents: 3 parents of the given clock + * @response: Parents of the given clock * * This function is used to get 3 parents for the clock specified by * given clock ID. @@ -310,7 +328,8 @@ struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id, * * Return: 0 on success else error+reason */ -static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents) +static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, + struct parents_resp *response) { struct zynqmp_pm_query_data qdata = {0}; u32 ret_payload[PAYLOAD_ARG_CNT]; @@ -321,7 +340,7 @@ static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents) qdata.arg2 = index; ret = eemi_ops->query_data(qdata, ret_payload); - memcpy(parents, &ret_payload[1], CLK_GET_PARENTS_RESP_WORDS * 4); + memcpy(response, &ret_payload[1], sizeof(*response)); return ret; } @@ -329,13 +348,14 @@ static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents) /** * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id * @clock_id: Clock ID - * @attr: Clock attributes + * @response: Clock attributes response * * This function is used to get clock's attributes(e.g. valid, clock type, etc). * * Return: 0 on success else error+reason */ -static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr) +static int zynqmp_pm_clock_get_attributes(u32 clock_id, + struct attr_resp *response) { struct zynqmp_pm_query_data qdata = {0}; u32 ret_payload[PAYLOAD_ARG_CNT]; @@ -345,7 +365,7 @@ static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr) qdata.arg1 = clock_id; ret = eemi_ops->query_data(qdata, ret_payload); - memcpy(attr, &ret_payload[1], CLK_GET_ATTR_RESP_WORDS * 4); + memcpy(response, &ret_payload[1], sizeof(*response)); return ret; } @@ -354,24 +374,28 @@ static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr) * __zynqmp_clock_get_topology() - Get topology data of clock from firmware * response data * @topology: Clock topology - * @data: Clock topology data received from firmware + * @response: Clock topology data received from firmware * @nnodes: Number of nodes * * Return: 0 on success else error+reason */ static int __zynqmp_clock_get_topology(struct clock_topology *topology, - u32 *data, u32 *nnodes) + struct topology_resp *response, + u32 *nnodes) { int i; + u32 type; - for (i = 0; i < PM_API_PAYLOAD_LEN; i++) { - if (!(data[i] & CLK_TYPE_FIELD_MASK)) + for (i = 0; i < ARRAY_SIZE(response->topology); i++) { + type = FIELD_GET(CLK_TOPOLOGY_TYPE, response->topology[i]); + if (type == TYPE_INVALID) return END_OF_TOPOLOGY_NODE; - topology[*nnodes].type = data[i] & CLK_TYPE_FIELD_MASK; - topology[*nnodes].flag = FIELD_GET(CLK_FLAG_FIELD_MASK, - data[i]); + topology[*nnodes].type = type; + topology[*nnodes].flag = FIELD_GET(CLK_TOPOLOGY_FLAGS, + response->topology[i]); topology[*nnodes].type_flag = - FIELD_GET(CLK_TYPE_FLAG_FIELD_MASK, data[i]); + FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS, + response->topology[i]); (*nnodes)++; } @@ -392,14 +416,16 @@ static int zynqmp_clock_get_topology(u32 clk_id, u32 *num_nodes) { int j, ret; - u32 pm_resp[PM_API_PAYLOAD_LEN] = {0}; + struct topology_resp response = { }; *num_nodes = 0; - for (j = 0; j <= MAX_NODES; j += 3) { - ret = zynqmp_pm_clock_get_topology(clk_id, j, pm_resp); + for (j = 0; j <= MAX_NODES; j += ARRAY_SIZE(response.topology)) { + ret = zynqmp_pm_clock_get_topology(clock[clk_id].clk_id, j, + &response); if (ret) return ret; - ret = __zynqmp_clock_get_topology(topology, pm_resp, num_nodes); + ret = __zynqmp_clock_get_topology(topology, &response, + num_nodes); if (ret == END_OF_TOPOLOGY_NODE) return 0; } @@ -408,31 +434,33 @@ static int zynqmp_clock_get_topology(u32 clk_id, } /** - * __zynqmp_clock_get_topology() - Get parents info of clock from firmware + * __zynqmp_clock_get_parents() - Get parents info of clock from firmware * response data * @parents: Clock parents - * @data: Clock parents data received from firmware + * @response: Clock parents data received from firmware * @nparent: Number of parent * * Return: 0 on success else error+reason */ -static int __zynqmp_clock_get_parents(struct clock_parent *parents, u32 *data, +static int __zynqmp_clock_get_parents(struct clock_parent *parents, + struct parents_resp *response, u32 *nparent) { int i; struct clock_parent *parent; - for (i = 0; i < PM_API_PAYLOAD_LEN; i++) { - if (data[i] == NA_PARENT) + for (i = 0; i < ARRAY_SIZE(response->parents); i++) { + if (response->parents[i] == NA_PARENT) return END_OF_PARENTS; parent = &parents[i]; - parent->id = data[i] & CLK_PARENTS_ID_MASK; - if (data[i] == DUMMY_PARENT) { + parent->id = FIELD_GET(CLK_PARENTS_ID, response->parents[i]); + if (response->parents[i] == DUMMY_PARENT) { strcpy(parent->name, "dummy_name"); parent->flag = 0; } else { - parent->flag = data[i] >> CLK_PARENTS_ID_LEN; + parent->flag = FIELD_GET(CLK_PARENTS_FLAGS, + response->parents[i]); if (zynqmp_get_clock_name(parent->id, parent->name)) continue; } @@ -454,20 +482,21 @@ static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents, u32 *num_parents) { int j = 0, ret; - u32 pm_resp[PM_API_PAYLOAD_LEN] = {0}; + struct parents_resp response = { }; *num_parents = 0; do { /* Get parents from firmware */ - ret = zynqmp_pm_clock_get_parents(clk_id, j, pm_resp); + ret = zynqmp_pm_clock_get_parents(clock[clk_id].clk_id, j, + &response); if (ret) return ret; - ret = __zynqmp_clock_get_parents(&parents[j], pm_resp, + ret = __zynqmp_clock_get_parents(&parents[j], &response, num_parents); if (ret == END_OF_PARENTS) return 0; - j += PM_API_PAYLOAD_LEN; + j += ARRAY_SIZE(response.parents); } while (*num_parents <= MAX_PARENT); return 0; @@ -528,13 +557,14 @@ static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name, const char **parent_names) { int j; - u32 num_nodes; + u32 num_nodes, clk_dev_id; char *clk_out = NULL; struct clock_topology *nodes; struct clk_hw *hw = NULL; nodes = clock[clk_id].node; num_nodes = clock[clk_id].num_nodes; + clk_dev_id = clock[clk_id].clk_id; for (j = 0; j < num_nodes; j++) { /* @@ -551,13 +581,14 @@ static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name, if (!clk_topology[nodes[j].type]) continue; - hw = (*clk_topology[nodes[j].type])(clk_out, clk_id, + hw = (*clk_topology[nodes[j].type])(clk_out, clk_dev_id, parent_names, num_parents, &nodes[j]); if (IS_ERR(hw)) - pr_warn_once("%s() %s register fail with %ld\n", - __func__, clk_name, PTR_ERR(hw)); + pr_warn_once("%s() 0x%x: %s register fail with %ld\n", + __func__, clk_dev_id, clk_name, + PTR_ERR(hw)); parent_names[0] = clk_out; } @@ -621,20 +652,33 @@ static int zynqmp_register_clocks(struct device_node *np) static void zynqmp_get_clock_info(void) { int i, ret; - u32 attr, type = 0; + u32 type = 0; + u32 nodetype, subclass, class; + struct attr_resp attr; + struct name_resp name; for (i = 0; i < clock_max_idx; i++) { - zynqmp_pm_clock_get_name(i, clock[i].clk_name); - if (!strcmp(clock[i].clk_name, RESERVED_CLK_NAME)) - continue; - ret = zynqmp_pm_clock_get_attributes(i, &attr); if (ret) continue; - clock[i].valid = attr & CLK_VALID_MASK; - clock[i].type = attr >> CLK_TYPE_SHIFT ? CLK_TYPE_EXTERNAL : - CLK_TYPE_OUTPUT; + clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]); + clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ? + CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT; + + nodetype = FIELD_GET(CLK_ATTR_NODE_TYPE, attr.attr[0]); + subclass = FIELD_GET(CLK_ATTR_NODE_SUBCLASS, attr.attr[0]); + class = FIELD_GET(CLK_ATTR_NODE_CLASS, attr.attr[0]); + + clock[i].clk_id = FIELD_PREP(CLK_ATTR_NODE_CLASS, class) | + FIELD_PREP(CLK_ATTR_NODE_SUBCLASS, subclass) | + FIELD_PREP(CLK_ATTR_NODE_TYPE, nodetype) | + FIELD_PREP(CLK_ATTR_NODE_INDEX, i); + + zynqmp_pm_clock_get_name(clock[i].clk_id, &name); + if (!strcmp(name.name, RESERVED_CLK_NAME)) + continue; + strncpy(clock[i].clk_name, name.name, MAX_NAME_LEN); } /* Get topology of all clock */ diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c index a371c66e72ef..d8f5b70d2709 100644 --- a/drivers/clk/zynqmp/divider.c +++ b/drivers/clk/zynqmp/divider.c @@ -31,12 +31,14 @@ * struct zynqmp_clk_divider - adjustable divider clock * @hw: handle between common and hardware-specific interfaces * @flags: Hardware specific flags + * @is_frac: The divider is a fractional divider * @clk_id: Id of clock * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2) */ struct zynqmp_clk_divider { struct clk_hw hw; u8 flags; + bool is_frac; u32 clk_id; u32 div_type; }; @@ -76,6 +78,13 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, else value = div >> 16; + if (!value) { + WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), + "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", + clk_name); + return parent_rate; + } + return DIV_ROUND_UP_ULL(parent_rate, value); } @@ -116,8 +125,7 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, bestdiv = zynqmp_divider_get_val(*prate, rate); - if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && - (divider->flags & CLK_FRAC)) + if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac) bestdiv = rate % *prate ? 1 : bestdiv; *prate = rate * bestdiv; @@ -195,11 +203,13 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name, init.name = name; init.ops = &zynqmp_clk_divider_ops; - init.flags = nodes->flag; + /* CLK_FRAC is not defined in the common clk framework */ + init.flags = nodes->flag & ~CLK_FRAC; init.parent_names = parents; init.num_parents = 1; /* struct clk_divider assignments */ + div->is_frac = !!(nodes->flag & CLK_FRAC); div->flags = nodes->type_flag; div->hw.init = &init; div->clk_id = clk_id; @@ -214,4 +224,3 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name, return hw; } -EXPORT_SYMBOL_GPL(zynqmp_clk_register_divider); diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index c1ed641b3e26..4ae5d774443e 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -470,7 +470,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, init.name = name; init.ops = &clk_mux_ops; - init.flags = CLK_IS_BASIC; + init.flags = 0; init.parent_names = meson->data->parent_names; init.num_parents = meson->data->num_parents; diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h index fd9c362099d9..75901c636893 100644 --- a/include/dt-bindings/clock/axg-audio-clkc.h +++ b/include/dt-bindings/clock/axg-audio-clkc.h @@ -7,26 +7,6 @@ #ifndef __AXG_AUDIO_CLKC_BINDINGS_H #define __AXG_AUDIO_CLKC_BINDINGS_H -#define AUD_CLKID_SLV_SCLK0 9 -#define AUD_CLKID_SLV_SCLK1 10 -#define AUD_CLKID_SLV_SCLK2 11 -#define AUD_CLKID_SLV_SCLK3 12 -#define AUD_CLKID_SLV_SCLK4 13 -#define AUD_CLKID_SLV_SCLK5 14 -#define AUD_CLKID_SLV_SCLK6 15 -#define AUD_CLKID_SLV_SCLK7 16 -#define AUD_CLKID_SLV_SCLK8 17 -#define AUD_CLKID_SLV_SCLK9 18 -#define AUD_CLKID_SLV_LRCLK0 19 -#define AUD_CLKID_SLV_LRCLK1 20 -#define AUD_CLKID_SLV_LRCLK2 21 -#define AUD_CLKID_SLV_LRCLK3 22 -#define AUD_CLKID_SLV_LRCLK4 23 -#define AUD_CLKID_SLV_LRCLK5 24 -#define AUD_CLKID_SLV_LRCLK6 25 -#define AUD_CLKID_SLV_LRCLK7 26 -#define AUD_CLKID_SLV_LRCLK8 27 -#define AUD_CLKID_SLV_LRCLK9 28 #define AUD_CLKID_DDR_ARB 29 #define AUD_CLKID_PDM 30 #define AUD_CLKID_TDMIN_A 31 @@ -90,5 +70,15 @@ #define AUD_CLKID_TDMOUT_A_LRCLK 134 #define AUD_CLKID_TDMOUT_B_LRCLK 135 #define AUD_CLKID_TDMOUT_C_LRCLK 136 +#define AUD_CLKID_SPDIFOUT_B 151 +#define AUD_CLKID_SPDIFOUT_B_CLK 152 +#define AUD_CLKID_TDM_MCLK_PAD0 155 +#define AUD_CLKID_TDM_MCLK_PAD1 156 +#define AUD_CLKID_TDM_LRCLK_PAD0 157 +#define AUD_CLKID_TDM_LRCLK_PAD1 158 +#define AUD_CLKID_TDM_LRCLK_PAD2 159 +#define AUD_CLKID_TDM_SCLK_PAD0 160 +#define AUD_CLKID_TDM_SCLK_PAD1 161 +#define AUD_CLKID_TDM_SCLK_PAD2 162 #endif /* __AXG_AUDIO_CLKC_BINDINGS_H */ diff --git a/include/dt-bindings/clock/exynos5410.h b/include/dt-bindings/clock/exynos5410.h index f179eabbcdb7..86c2ad56c5ef 100644 --- a/include/dt-bindings/clock/exynos5410.h +++ b/include/dt-bindings/clock/exynos5410.h @@ -36,6 +36,7 @@ #define CLK_UART0 257 #define CLK_UART1 258 #define CLK_UART2 259 +#define CLK_UART3 260 #define CLK_I2C0 261 #define CLK_I2C1 262 #define CLK_I2C2 263 @@ -44,7 +45,7 @@ #define CLK_USI1 266 #define CLK_USI2 267 #define CLK_USI3 268 -#define CLK_UART3 260 +#define CLK_TSADC 270 #define CLK_PWM 279 #define CLK_MCT 315 #define CLK_WDT 316 diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h index 8db01ffbeb06..e916e49ff288 100644 --- a/include/dt-bindings/clock/g12a-aoclkc.h +++ b/include/dt-bindings/clock/g12a-aoclkc.h @@ -26,7 +26,9 @@ #define CLKID_AO_M4_FCLK 13 #define CLKID_AO_M4_HCLK 14 #define CLKID_AO_CLK81 15 +#define CLKID_AO_SAR_ADC_SEL 16 #define CLKID_AO_SAR_ADC_CLK 18 +#define CLKID_AO_CTS_OSCIN 19 #define CLKID_AO_32K 23 #define CLKID_AO_CEC 27 #define CLKID_AO_CTS_RTC_OSCIN 28 diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h index 83b657038d1e..82c9e0c020b2 100644 --- a/include/dt-bindings/clock/g12a-clkc.h +++ b/include/dt-bindings/clock/g12a-clkc.h @@ -131,5 +131,10 @@ #define CLKID_MALI_1 174 #define CLKID_MALI 175 #define CLKID_MPLL_5OM 177 +#define CLKID_CPU_CLK 187 +#define CLKID_PCIE_PLL 201 +#define CLKID_VDEC_1 204 +#define CLKID_VDEC_HEVC 207 +#define CLKID_VDEC_HEVCF 210 #endif /* __G12A_CLKC_H */ diff --git a/include/dt-bindings/clock/imx7ulp-clock.h b/include/dt-bindings/clock/imx7ulp-clock.h index 21d872e69cb1..6f66f9005c81 100644 --- a/include/dt-bindings/clock/imx7ulp-clock.h +++ b/include/dt-bindings/clock/imx7ulp-clock.h @@ -65,7 +65,6 @@ #define IMX7ULP_CLK_FLEXBUS 2 #define IMX7ULP_CLK_SEMA42_1 3 #define IMX7ULP_CLK_DMA_MUX1 4 -#define IMX7ULP_CLK_SNVS 5 #define IMX7ULP_CLK_CAAM 6 #define IMX7ULP_CLK_LPTPM4 7 #define IMX7ULP_CLK_LPTPM5 8 diff --git a/include/dt-bindings/clock/jz4725b-cgu.h b/include/dt-bindings/clock/jz4725b-cgu.h index 460bbeff6ab8..31f1ab0fe42c 100644 --- a/include/dt-bindings/clock/jz4725b-cgu.h +++ b/include/dt-bindings/clock/jz4725b-cgu.h @@ -31,5 +31,6 @@ #define JZ4725B_CLK_TCU 22 #define JZ4725B_CLK_EXT512 23 #define JZ4725B_CLK_RTC 24 +#define JZ4725B_CLK_UDC_PHY 25 #endif /* __DT_BINDINGS_CLOCK_JZ4725B_CGU_H__ */ diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index 8067077a62ca..47556539f0ee 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -103,10 +103,14 @@ #define CLKID_MPLL1 94 #define CLKID_MPLL2 95 #define CLKID_NAND_CLK 112 -#define CLKID_ABP 124 #define CLKID_APB 124 #define CLKID_PERIPH 126 #define CLKID_AXI 128 #define CLKID_L2_DRAM 130 +#define CLKID_VPU 190 +#define CLKID_VDEC_1 196 +#define CLKID_VDEC_HCODEC 199 +#define CLKID_VDEC_2 202 +#define CLKID_VDEC_HEVC 206 #endif /* __MESON8B_CLKC_H */ diff --git a/include/dt-bindings/clock/mt8183-clk.h b/include/dt-bindings/clock/mt8183-clk.h new file mode 100644 index 000000000000..0046506eb24c --- /dev/null +++ b/include/dt-bindings/clock/mt8183-clk.h @@ -0,0 +1,422 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + */ + +#ifndef _DT_BINDINGS_CLK_MT8183_H +#define _DT_BINDINGS_CLK_MT8183_H + +/* APMIXED */ +#define CLK_APMIXED_ARMPLL_LL 0 +#define CLK_APMIXED_ARMPLL_L 1 +#define CLK_APMIXED_CCIPLL 2 +#define CLK_APMIXED_MAINPLL 3 +#define CLK_APMIXED_UNIV2PLL 4 +#define CLK_APMIXED_MSDCPLL 5 +#define CLK_APMIXED_MMPLL 6 +#define CLK_APMIXED_MFGPLL 7 +#define CLK_APMIXED_TVDPLL 8 +#define CLK_APMIXED_APLL1 9 +#define CLK_APMIXED_APLL2 10 +#define CLK_APMIXED_SSUSB_26M 11 +#define CLK_APMIXED_APPLL_26M 12 +#define CLK_APMIXED_MIPIC0_26M 13 +#define CLK_APMIXED_MDPLLGP_26M 14 +#define CLK_APMIXED_MMSYS_26M 15 +#define CLK_APMIXED_UFS_26M 16 +#define CLK_APMIXED_MIPIC1_26M 17 +#define CLK_APMIXED_MEMPLL_26M 18 +#define CLK_APMIXED_CLKSQ_LVPLL_26M 19 +#define CLK_APMIXED_MIPID0_26M 20 +#define CLK_APMIXED_MIPID1_26M 21 +#define CLK_APMIXED_NR_CLK 22 + +/* TOPCKGEN */ +#define CLK_TOP_MUX_AXI 0 +#define CLK_TOP_MUX_MM 1 +#define CLK_TOP_MUX_CAM 2 +#define CLK_TOP_MUX_MFG 3 +#define CLK_TOP_MUX_CAMTG 4 +#define CLK_TOP_MUX_UART 5 +#define CLK_TOP_MUX_SPI 6 +#define CLK_TOP_MUX_MSDC50_0_HCLK 7 +#define CLK_TOP_MUX_MSDC50_0 8 +#define CLK_TOP_MUX_MSDC30_1 9 +#define CLK_TOP_MUX_MSDC30_2 10 +#define CLK_TOP_MUX_AUDIO 11 +#define CLK_TOP_MUX_AUD_INTBUS 12 +#define CLK_TOP_MUX_FPWRAP_ULPOSC 13 +#define CLK_TOP_MUX_SCP 14 +#define CLK_TOP_MUX_ATB 15 +#define CLK_TOP_MUX_SSPM 16 +#define CLK_TOP_MUX_DPI0 17 +#define CLK_TOP_MUX_SCAM 18 +#define CLK_TOP_MUX_AUD_1 19 +#define CLK_TOP_MUX_AUD_2 20 +#define CLK_TOP_MUX_DISP_PWM 21 +#define CLK_TOP_MUX_SSUSB_TOP_XHCI 22 +#define CLK_TOP_MUX_USB_TOP 23 +#define CLK_TOP_MUX_SPM 24 +#define CLK_TOP_MUX_I2C 25 +#define CLK_TOP_MUX_F52M_MFG 26 +#define CLK_TOP_MUX_SENINF 27 +#define CLK_TOP_MUX_DXCC 28 +#define CLK_TOP_MUX_CAMTG2 29 +#define CLK_TOP_MUX_AUD_ENG1 30 +#define CLK_TOP_MUX_AUD_ENG2 31 +#define CLK_TOP_MUX_FAES_UFSFDE 32 +#define CLK_TOP_MUX_FUFS 33 +#define CLK_TOP_MUX_IMG 34 +#define CLK_TOP_MUX_DSP 35 +#define CLK_TOP_MUX_DSP1 36 +#define CLK_TOP_MUX_DSP2 37 +#define CLK_TOP_MUX_IPU_IF 38 +#define CLK_TOP_MUX_CAMTG3 39 +#define CLK_TOP_MUX_CAMTG4 40 +#define CLK_TOP_MUX_PMICSPI 41 +#define CLK_TOP_SYSPLL_CK 42 +#define CLK_TOP_SYSPLL_D2 43 +#define CLK_TOP_SYSPLL_D3 44 +#define CLK_TOP_SYSPLL_D5 45 +#define CLK_TOP_SYSPLL_D7 46 +#define CLK_TOP_SYSPLL_D2_D2 47 +#define CLK_TOP_SYSPLL_D2_D4 48 +#define CLK_TOP_SYSPLL_D2_D8 49 +#define CLK_TOP_SYSPLL_D2_D16 50 +#define CLK_TOP_SYSPLL_D3_D2 51 +#define CLK_TOP_SYSPLL_D3_D4 52 +#define CLK_TOP_SYSPLL_D3_D8 53 +#define CLK_TOP_SYSPLL_D5_D2 54 +#define CLK_TOP_SYSPLL_D5_D4 55 +#define CLK_TOP_SYSPLL_D7_D2 56 +#define CLK_TOP_SYSPLL_D7_D4 57 +#define CLK_TOP_UNIVPLL_CK 58 +#define CLK_TOP_UNIVPLL_D2 59 +#define CLK_TOP_UNIVPLL_D3 60 +#define CLK_TOP_UNIVPLL_D5 61 +#define CLK_TOP_UNIVPLL_D7 62 +#define CLK_TOP_UNIVPLL_D2_D2 63 +#define CLK_TOP_UNIVPLL_D2_D4 64 +#define CLK_TOP_UNIVPLL_D2_D8 65 +#define CLK_TOP_UNIVPLL_D3_D2 66 +#define CLK_TOP_UNIVPLL_D3_D4 67 +#define CLK_TOP_UNIVPLL_D3_D8 68 +#define CLK_TOP_UNIVPLL_D5_D2 69 +#define CLK_TOP_UNIVPLL_D5_D4 70 +#define CLK_TOP_UNIVPLL_D5_D8 71 +#define CLK_TOP_APLL1_CK 72 +#define CLK_TOP_APLL1_D2 73 +#define CLK_TOP_APLL1_D4 74 +#define CLK_TOP_APLL1_D8 75 +#define CLK_TOP_APLL2_CK 76 +#define CLK_TOP_APLL2_D2 77 +#define CLK_TOP_APLL2_D4 78 +#define CLK_TOP_APLL2_D8 79 +#define CLK_TOP_TVDPLL_CK 80 +#define CLK_TOP_TVDPLL_D2 81 +#define CLK_TOP_TVDPLL_D4 82 +#define CLK_TOP_TVDPLL_D8 83 +#define CLK_TOP_TVDPLL_D16 84 +#define CLK_TOP_MSDCPLL_CK 85 +#define CLK_TOP_MSDCPLL_D2 86 +#define CLK_TOP_MSDCPLL_D4 87 +#define CLK_TOP_MSDCPLL_D8 88 +#define CLK_TOP_MSDCPLL_D16 89 +#define CLK_TOP_AD_OSC_CK 90 +#define CLK_TOP_OSC_D2 91 +#define CLK_TOP_OSC_D4 92 +#define CLK_TOP_OSC_D8 93 +#define CLK_TOP_OSC_D16 94 +#define CLK_TOP_F26M_CK_D2 95 +#define CLK_TOP_MFGPLL_CK 96 +#define CLK_TOP_UNIVP_192M_CK 97 +#define CLK_TOP_UNIVP_192M_D2 98 +#define CLK_TOP_UNIVP_192M_D4 99 +#define CLK_TOP_UNIVP_192M_D8 100 +#define CLK_TOP_UNIVP_192M_D16 101 +#define CLK_TOP_UNIVP_192M_D32 102 +#define CLK_TOP_MMPLL_CK 103 +#define CLK_TOP_MMPLL_D4 104 +#define CLK_TOP_MMPLL_D4_D2 105 +#define CLK_TOP_MMPLL_D4_D4 106 +#define CLK_TOP_MMPLL_D5 107 +#define CLK_TOP_MMPLL_D5_D2 108 +#define CLK_TOP_MMPLL_D5_D4 109 +#define CLK_TOP_MMPLL_D6 110 +#define CLK_TOP_MMPLL_D7 111 +#define CLK_TOP_CLK26M 112 +#define CLK_TOP_CLK13M 113 +#define CLK_TOP_ULPOSC 114 +#define CLK_TOP_UNIVP_192M 115 +#define CLK_TOP_MUX_APLL_I2S0 116 +#define CLK_TOP_MUX_APLL_I2S1 117 +#define CLK_TOP_MUX_APLL_I2S2 118 +#define CLK_TOP_MUX_APLL_I2S3 119 +#define CLK_TOP_MUX_APLL_I2S4 120 +#define CLK_TOP_MUX_APLL_I2S5 121 +#define CLK_TOP_APLL12_DIV0 122 +#define CLK_TOP_APLL12_DIV1 123 +#define CLK_TOP_APLL12_DIV2 124 +#define CLK_TOP_APLL12_DIV3 125 +#define CLK_TOP_APLL12_DIV4 126 +#define CLK_TOP_APLL12_DIVB 127 +#define CLK_TOP_UNIVPLL 128 +#define CLK_TOP_ARMPLL_DIV_PLL1 129 +#define CLK_TOP_ARMPLL_DIV_PLL2 130 +#define CLK_TOP_UNIVPLL_D3_D16 131 +#define CLK_TOP_NR_CLK 132 + +/* CAMSYS */ +#define CLK_CAM_LARB6 0 +#define CLK_CAM_DFP_VAD 1 +#define CLK_CAM_CAM 2 +#define CLK_CAM_CAMTG 3 +#define CLK_CAM_SENINF 4 +#define CLK_CAM_CAMSV0 5 +#define CLK_CAM_CAMSV1 6 +#define CLK_CAM_CAMSV2 7 +#define CLK_CAM_CCU 8 +#define CLK_CAM_LARB3 9 +#define CLK_CAM_NR_CLK 10 + +/* INFRACFG_AO */ +#define CLK_INFRA_PMIC_TMR 0 +#define CLK_INFRA_PMIC_AP 1 +#define CLK_INFRA_PMIC_MD 2 +#define CLK_INFRA_PMIC_CONN 3 +#define CLK_INFRA_SCPSYS 4 +#define CLK_INFRA_SEJ 5 +#define CLK_INFRA_APXGPT 6 +#define CLK_INFRA_ICUSB 7 +#define CLK_INFRA_GCE 8 +#define CLK_INFRA_THERM 9 +#define CLK_INFRA_I2C0 10 +#define CLK_INFRA_I2C1 11 +#define CLK_INFRA_I2C2 12 +#define CLK_INFRA_I2C3 13 +#define CLK_INFRA_PWM_HCLK 14 +#define CLK_INFRA_PWM1 15 +#define CLK_INFRA_PWM2 16 +#define CLK_INFRA_PWM3 17 +#define CLK_INFRA_PWM4 18 +#define CLK_INFRA_PWM 19 +#define CLK_INFRA_UART0 20 +#define CLK_INFRA_UART1 21 +#define CLK_INFRA_UART2 22 +#define CLK_INFRA_UART3 23 +#define CLK_INFRA_GCE_26M 24 +#define CLK_INFRA_CQ_DMA_FPC 25 +#define CLK_INFRA_BTIF 26 +#define CLK_INFRA_SPI0 27 +#define CLK_INFRA_MSDC0 28 +#define CLK_INFRA_MSDC1 29 +#define CLK_INFRA_MSDC2 30 +#define CLK_INFRA_MSDC0_SCK 31 +#define CLK_INFRA_DVFSRC 32 +#define CLK_INFRA_GCPU 33 +#define CLK_INFRA_TRNG 34 +#define CLK_INFRA_AUXADC 35 +#define CLK_INFRA_CPUM 36 +#define CLK_INFRA_CCIF1_AP 37 +#define CLK_INFRA_CCIF1_MD 38 +#define CLK_INFRA_AUXADC_MD 39 +#define CLK_INFRA_MSDC1_SCK 40 +#define CLK_INFRA_MSDC2_SCK 41 +#define CLK_INFRA_AP_DMA 42 +#define CLK_INFRA_XIU 43 +#define CLK_INFRA_DEVICE_APC 44 +#define CLK_INFRA_CCIF_AP 45 +#define CLK_INFRA_DEBUGSYS 46 +#define CLK_INFRA_AUDIO 47 +#define CLK_INFRA_CCIF_MD 48 +#define CLK_INFRA_DXCC_SEC_CORE 49 +#define CLK_INFRA_DXCC_AO 50 +#define CLK_INFRA_DRAMC_F26M 51 +#define CLK_INFRA_IRTX 52 +#define CLK_INFRA_DISP_PWM 53 +#define CLK_INFRA_CLDMA_BCLK 54 +#define CLK_INFRA_AUDIO_26M_BCLK 55 +#define CLK_INFRA_SPI1 56 +#define CLK_INFRA_I2C4 57 +#define CLK_INFRA_MODEM_TEMP_SHARE 58 +#define CLK_INFRA_SPI2 59 +#define CLK_INFRA_SPI3 60 +#define CLK_INFRA_UNIPRO_SCK 61 +#define CLK_INFRA_UNIPRO_TICK 62 +#define CLK_INFRA_UFS_MP_SAP_BCLK 63 +#define CLK_INFRA_MD32_BCLK 64 +#define CLK_INFRA_SSPM 65 +#define CLK_INFRA_UNIPRO_MBIST 66 +#define CLK_INFRA_SSPM_BUS_HCLK 67 +#define CLK_INFRA_I2C5 68 +#define CLK_INFRA_I2C5_ARBITER 69 +#define CLK_INFRA_I2C5_IMM 70 +#define CLK_INFRA_I2C1_ARBITER 71 +#define CLK_INFRA_I2C1_IMM 72 +#define CLK_INFRA_I2C2_ARBITER 73 +#define CLK_INFRA_I2C2_IMM 74 +#define CLK_INFRA_SPI4 75 +#define CLK_INFRA_SPI5 76 +#define CLK_INFRA_CQ_DMA 77 +#define CLK_INFRA_UFS 78 +#define CLK_INFRA_AES_UFSFDE 79 +#define CLK_INFRA_UFS_TICK 80 +#define CLK_INFRA_MSDC0_SELF 81 +#define CLK_INFRA_MSDC1_SELF 82 +#define CLK_INFRA_MSDC2_SELF 83 +#define CLK_INFRA_SSPM_26M_SELF 84 +#define CLK_INFRA_SSPM_32K_SELF 85 +#define CLK_INFRA_UFS_AXI 86 +#define CLK_INFRA_I2C6 87 +#define CLK_INFRA_AP_MSDC0 88 +#define CLK_INFRA_MD_MSDC0 89 +#define CLK_INFRA_USB 90 +#define CLK_INFRA_DEVMPU_BCLK 91 +#define CLK_INFRA_CCIF2_AP 92 +#define CLK_INFRA_CCIF2_MD 93 +#define CLK_INFRA_CCIF3_AP 94 +#define CLK_INFRA_CCIF3_MD 95 +#define CLK_INFRA_SEJ_F13M 96 +#define CLK_INFRA_AES_BCLK 97 +#define CLK_INFRA_I2C7 98 +#define CLK_INFRA_I2C8 99 +#define CLK_INFRA_FBIST2FPC 100 +#define CLK_INFRA_NR_CLK 101 + +/* MFGCFG */ +#define CLK_MFG_BG3D 0 +#define CLK_MFG_NR_CLK 1 + +/* IMG */ +#define CLK_IMG_OWE 0 +#define CLK_IMG_WPE_B 1 +#define CLK_IMG_WPE_A 2 +#define CLK_IMG_MFB 3 +#define CLK_IMG_RSC 4 +#define CLK_IMG_DPE 5 +#define CLK_IMG_FDVT 6 +#define CLK_IMG_DIP 7 +#define CLK_IMG_LARB2 8 +#define CLK_IMG_LARB5 9 +#define CLK_IMG_NR_CLK 10 + +/* MMSYS_CONFIG */ +#define CLK_MM_SMI_COMMON 0 +#define CLK_MM_SMI_LARB0 1 +#define CLK_MM_SMI_LARB1 2 +#define CLK_MM_GALS_COMM0 3 +#define CLK_MM_GALS_COMM1 4 +#define CLK_MM_GALS_CCU2MM 5 +#define CLK_MM_GALS_IPU12MM 6 +#define CLK_MM_GALS_IMG2MM 7 +#define CLK_MM_GALS_CAM2MM 8 +#define CLK_MM_GALS_IPU2MM 9 +#define CLK_MM_MDP_DL_TXCK 10 +#define CLK_MM_IPU_DL_TXCK 11 +#define CLK_MM_MDP_RDMA0 12 +#define CLK_MM_MDP_RDMA1 13 +#define CLK_MM_MDP_RSZ0 14 +#define CLK_MM_MDP_RSZ1 15 +#define CLK_MM_MDP_TDSHP 16 +#define CLK_MM_MDP_WROT0 17 +#define CLK_MM_FAKE_ENG 18 +#define CLK_MM_DISP_OVL0 19 +#define CLK_MM_DISP_OVL0_2L 20 +#define CLK_MM_DISP_OVL1_2L 21 +#define CLK_MM_DISP_RDMA0 22 +#define CLK_MM_DISP_RDMA1 23 +#define CLK_MM_DISP_WDMA0 24 +#define CLK_MM_DISP_COLOR0 25 +#define CLK_MM_DISP_CCORR0 26 +#define CLK_MM_DISP_AAL0 27 +#define CLK_MM_DISP_GAMMA0 28 +#define CLK_MM_DISP_DITHER0 29 +#define CLK_MM_DISP_SPLIT 30 +#define CLK_MM_DSI0_MM 31 +#define CLK_MM_DSI0_IF 32 +#define CLK_MM_DPI_MM 33 +#define CLK_MM_DPI_IF 34 +#define CLK_MM_FAKE_ENG2 35 +#define CLK_MM_MDP_DL_RX 36 +#define CLK_MM_IPU_DL_RX 37 +#define CLK_MM_26M 38 +#define CLK_MM_MMSYS_R2Y 39 +#define CLK_MM_DISP_RSZ 40 +#define CLK_MM_MDP_WDMA0 41 +#define CLK_MM_MDP_AAL 42 +#define CLK_MM_MDP_CCORR 43 +#define CLK_MM_DBI_MM 44 +#define CLK_MM_DBI_IF 45 +#define CLK_MM_NR_CLK 46 + +/* VDEC_GCON */ +#define CLK_VDEC_VDEC 0 +#define CLK_VDEC_LARB1 1 +#define CLK_VDEC_NR_CLK 2 + +/* VENC_GCON */ +#define CLK_VENC_LARB 0 +#define CLK_VENC_VENC 1 +#define CLK_VENC_JPGENC 2 +#define CLK_VENC_NR_CLK 3 + +/* AUDIO */ +#define CLK_AUDIO_TML 0 +#define CLK_AUDIO_DAC_PREDIS 1 +#define CLK_AUDIO_DAC 2 +#define CLK_AUDIO_ADC 3 +#define CLK_AUDIO_APLL_TUNER 4 +#define CLK_AUDIO_APLL2_TUNER 5 +#define CLK_AUDIO_24M 6 +#define CLK_AUDIO_22M 7 +#define CLK_AUDIO_AFE 8 +#define CLK_AUDIO_I2S4 9 +#define CLK_AUDIO_I2S3 10 +#define CLK_AUDIO_I2S2 11 +#define CLK_AUDIO_I2S1 12 +#define CLK_AUDIO_PDN_ADDA6_ADC 13 +#define CLK_AUDIO_TDM 14 +#define CLK_AUDIO_NR_CLK 15 + +/* IPU_CONN */ +#define CLK_IPU_CONN_IPU 0 +#define CLK_IPU_CONN_AHB 1 +#define CLK_IPU_CONN_AXI 2 +#define CLK_IPU_CONN_ISP 3 +#define CLK_IPU_CONN_CAM_ADL 4 +#define CLK_IPU_CONN_IMG_ADL 5 +#define CLK_IPU_CONN_DAP_RX 6 +#define CLK_IPU_CONN_APB2AXI 7 +#define CLK_IPU_CONN_APB2AHB 8 +#define CLK_IPU_CONN_IPU_CAB1TO2 9 +#define CLK_IPU_CONN_IPU1_CAB1TO2 10 +#define CLK_IPU_CONN_IPU2_CAB1TO2 11 +#define CLK_IPU_CONN_CAB3TO3 12 +#define CLK_IPU_CONN_CAB2TO1 13 +#define CLK_IPU_CONN_CAB3TO1_SLICE 14 +#define CLK_IPU_CONN_NR_CLK 15 + +/* IPU_ADL */ +#define CLK_IPU_ADL_CABGEN 0 +#define CLK_IPU_ADL_NR_CLK 1 + +/* IPU_CORE0 */ +#define CLK_IPU_CORE0_JTAG 0 +#define CLK_IPU_CORE0_AXI 1 +#define CLK_IPU_CORE0_IPU 2 +#define CLK_IPU_CORE0_NR_CLK 3 + +/* IPU_CORE1 */ +#define CLK_IPU_CORE1_JTAG 0 +#define CLK_IPU_CORE1_AXI 1 +#define CLK_IPU_CORE1_IPU 2 +#define CLK_IPU_CORE1_NR_CLK 3 + +/* MCUCFG */ +#define CLK_MCU_MP0_SEL 0 +#define CLK_MCU_MP2_SEL 1 +#define CLK_MCU_BUS_SEL 2 +#define CLK_MCU_NR_CLK 3 + +#endif /* _DT_BINDINGS_CLK_MT8183_H */ diff --git a/include/dt-bindings/clock/mt8516-clk.h b/include/dt-bindings/clock/mt8516-clk.h new file mode 100644 index 000000000000..9cfca53cd78d --- /dev/null +++ b/include/dt-bindings/clock/mt8516-clk.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 MediaTek Inc. + * Copyright (c) 2019 BayLibre, SAS. + * Author: James Liao <jamesjj.liao@mediatek.com> + */ + +#ifndef _DT_BINDINGS_CLK_MT8516_H +#define _DT_BINDINGS_CLK_MT8516_H + +/* APMIXEDSYS */ + +#define CLK_APMIXED_ARMPLL 0 +#define CLK_APMIXED_MAINPLL 1 +#define CLK_APMIXED_UNIVPLL 2 +#define CLK_APMIXED_MMPLL 3 +#define CLK_APMIXED_APLL1 4 +#define CLK_APMIXED_APLL2 5 +#define CLK_APMIXED_NR_CLK 6 + +/* INFRACFG */ + +#define CLK_IFR_MUX1_SEL 0 +#define CLK_IFR_ETH_25M_SEL 1 +#define CLK_IFR_I2C0_SEL 2 +#define CLK_IFR_I2C1_SEL 3 +#define CLK_IFR_I2C2_SEL 4 +#define CLK_IFR_NR_CLK 5 + +/* TOPCKGEN */ + +#define CLK_TOP_CLK_NULL 0 +#define CLK_TOP_I2S_INFRA_BCK 1 +#define CLK_TOP_MEMPLL 2 +#define CLK_TOP_DMPLL 3 +#define CLK_TOP_MAINPLL_D2 4 +#define CLK_TOP_MAINPLL_D4 5 +#define CLK_TOP_MAINPLL_D8 6 +#define CLK_TOP_MAINPLL_D16 7 +#define CLK_TOP_MAINPLL_D11 8 +#define CLK_TOP_MAINPLL_D22 9 +#define CLK_TOP_MAINPLL_D3 10 +#define CLK_TOP_MAINPLL_D6 11 +#define CLK_TOP_MAINPLL_D12 12 +#define CLK_TOP_MAINPLL_D5 13 +#define CLK_TOP_MAINPLL_D10 14 +#define CLK_TOP_MAINPLL_D20 15 +#define CLK_TOP_MAINPLL_D40 16 +#define CLK_TOP_MAINPLL_D7 17 +#define CLK_TOP_MAINPLL_D14 18 +#define CLK_TOP_UNIVPLL_D2 19 +#define CLK_TOP_UNIVPLL_D4 20 +#define CLK_TOP_UNIVPLL_D8 21 +#define CLK_TOP_UNIVPLL_D16 22 +#define CLK_TOP_UNIVPLL_D3 23 +#define CLK_TOP_UNIVPLL_D6 24 +#define CLK_TOP_UNIVPLL_D12 25 +#define CLK_TOP_UNIVPLL_D24 26 +#define CLK_TOP_UNIVPLL_D5 27 +#define CLK_TOP_UNIVPLL_D20 28 +#define CLK_TOP_MMPLL380M 29 +#define CLK_TOP_MMPLL_D2 30 +#define CLK_TOP_MMPLL_200M 31 +#define CLK_TOP_USB_PHY48M 32 +#define CLK_TOP_APLL1 33 +#define CLK_TOP_APLL1_D2 34 +#define CLK_TOP_APLL1_D4 35 +#define CLK_TOP_APLL1_D8 36 +#define CLK_TOP_APLL2 37 +#define CLK_TOP_APLL2_D2 38 +#define CLK_TOP_APLL2_D4 39 +#define CLK_TOP_APLL2_D8 40 +#define CLK_TOP_CLK26M 41 +#define CLK_TOP_CLK26M_D2 42 +#define CLK_TOP_AHB_INFRA_D2 43 +#define CLK_TOP_NFI1X 44 +#define CLK_TOP_ETH_D2 45 +#define CLK_TOP_THEM 46 +#define CLK_TOP_APDMA 47 +#define CLK_TOP_I2C0 48 +#define CLK_TOP_I2C1 49 +#define CLK_TOP_AUXADC1 50 +#define CLK_TOP_NFI 51 +#define CLK_TOP_NFIECC 52 +#define CLK_TOP_DEBUGSYS 53 +#define CLK_TOP_PWM 54 +#define CLK_TOP_UART0 55 +#define CLK_TOP_UART1 56 +#define CLK_TOP_BTIF 57 +#define CLK_TOP_USB 58 +#define CLK_TOP_FLASHIF_26M 59 +#define CLK_TOP_AUXADC2 60 +#define CLK_TOP_I2C2 61 +#define CLK_TOP_MSDC0 62 +#define CLK_TOP_MSDC1 63 +#define CLK_TOP_NFI2X 64 +#define CLK_TOP_PMICWRAP_AP 65 +#define CLK_TOP_SEJ 66 +#define CLK_TOP_MEMSLP_DLYER 67 +#define CLK_TOP_SPI 68 +#define CLK_TOP_APXGPT 69 +#define CLK_TOP_AUDIO 70 +#define CLK_TOP_PMICWRAP_MD 71 +#define CLK_TOP_PMICWRAP_CONN 72 +#define CLK_TOP_PMICWRAP_26M 73 +#define CLK_TOP_AUX_ADC 74 +#define CLK_TOP_AUX_TP 75 +#define CLK_TOP_MSDC2 76 +#define CLK_TOP_RBIST 77 +#define CLK_TOP_NFI_BUS 78 +#define CLK_TOP_GCE 79 +#define CLK_TOP_TRNG 80 +#define CLK_TOP_SEJ_13M 81 +#define CLK_TOP_AES 82 +#define CLK_TOP_PWM_B 83 +#define CLK_TOP_PWM1_FB 84 +#define CLK_TOP_PWM2_FB 85 +#define CLK_TOP_PWM3_FB 86 +#define CLK_TOP_PWM4_FB 87 +#define CLK_TOP_PWM5_FB 88 +#define CLK_TOP_USB_1P 89 +#define CLK_TOP_FLASHIF_FREERUN 90 +#define CLK_TOP_66M_ETH 91 +#define CLK_TOP_133M_ETH 92 +#define CLK_TOP_FETH_25M 93 +#define CLK_TOP_FETH_50M 94 +#define CLK_TOP_FLASHIF_AXI 95 +#define CLK_TOP_USBIF 96 +#define CLK_TOP_UART2 97 +#define CLK_TOP_BSI 98 +#define CLK_TOP_RG_SPINOR 99 +#define CLK_TOP_RG_MSDC2 100 +#define CLK_TOP_RG_ETH 101 +#define CLK_TOP_RG_AUD1 102 +#define CLK_TOP_RG_AUD2 103 +#define CLK_TOP_RG_AUD_ENGEN1 104 +#define CLK_TOP_RG_AUD_ENGEN2 105 +#define CLK_TOP_RG_I2C 106 +#define CLK_TOP_RG_PWM_INFRA 107 +#define CLK_TOP_RG_AUD_SPDIF_IN 108 +#define CLK_TOP_RG_UART2 109 +#define CLK_TOP_RG_BSI 110 +#define CLK_TOP_RG_DBG_ATCLK 111 +#define CLK_TOP_RG_NFIECC 112 +#define CLK_TOP_RG_APLL1_D2_EN 113 +#define CLK_TOP_RG_APLL1_D4_EN 114 +#define CLK_TOP_RG_APLL1_D8_EN 115 +#define CLK_TOP_RG_APLL2_D2_EN 116 +#define CLK_TOP_RG_APLL2_D4_EN 117 +#define CLK_TOP_RG_APLL2_D8_EN 118 +#define CLK_TOP_APLL12_DIV0 119 +#define CLK_TOP_APLL12_DIV1 120 +#define CLK_TOP_APLL12_DIV2 121 +#define CLK_TOP_APLL12_DIV3 122 +#define CLK_TOP_APLL12_DIV4 123 +#define CLK_TOP_APLL12_DIV4B 124 +#define CLK_TOP_APLL12_DIV5 125 +#define CLK_TOP_APLL12_DIV5B 126 +#define CLK_TOP_APLL12_DIV6 127 +#define CLK_TOP_UART0_SEL 128 +#define CLK_TOP_EMI_DDRPHY_SEL 129 +#define CLK_TOP_AHB_INFRA_SEL 130 +#define CLK_TOP_MSDC0_SEL 131 +#define CLK_TOP_UART1_SEL 132 +#define CLK_TOP_MSDC1_SEL 133 +#define CLK_TOP_PMICSPI_SEL 134 +#define CLK_TOP_QAXI_AUD26M_SEL 135 +#define CLK_TOP_AUD_INTBUS_SEL 136 +#define CLK_TOP_NFI2X_PAD_SEL 137 +#define CLK_TOP_NFI1X_PAD_SEL 138 +#define CLK_TOP_DDRPHYCFG_SEL 139 +#define CLK_TOP_USB_78M_SEL 140 +#define CLK_TOP_SPINOR_SEL 141 +#define CLK_TOP_MSDC2_SEL 142 +#define CLK_TOP_ETH_SEL 143 +#define CLK_TOP_AUD1_SEL 144 +#define CLK_TOP_AUD2_SEL 145 +#define CLK_TOP_AUD_ENGEN1_SEL 146 +#define CLK_TOP_AUD_ENGEN2_SEL 147 +#define CLK_TOP_I2C_SEL 148 +#define CLK_TOP_AUD_I2S0_M_SEL 149 +#define CLK_TOP_AUD_I2S1_M_SEL 150 +#define CLK_TOP_AUD_I2S2_M_SEL 151 +#define CLK_TOP_AUD_I2S3_M_SEL 152 +#define CLK_TOP_AUD_I2S4_M_SEL 153 +#define CLK_TOP_AUD_I2S5_M_SEL 154 +#define CLK_TOP_AUD_SPDIF_B_SEL 155 +#define CLK_TOP_PWM_SEL 156 +#define CLK_TOP_SPI_SEL 157 +#define CLK_TOP_AUD_SPDIFIN_SEL 158 +#define CLK_TOP_UART2_SEL 159 +#define CLK_TOP_BSI_SEL 160 +#define CLK_TOP_DBG_ATCLK_SEL 161 +#define CLK_TOP_CSW_NFIECC_SEL 162 +#define CLK_TOP_NFIECC_SEL 163 +#define CLK_TOP_APLL12_CK_DIV0 164 +#define CLK_TOP_APLL12_CK_DIV1 165 +#define CLK_TOP_APLL12_CK_DIV2 166 +#define CLK_TOP_APLL12_CK_DIV3 167 +#define CLK_TOP_APLL12_CK_DIV4 168 +#define CLK_TOP_APLL12_CK_DIV4B 169 +#define CLK_TOP_APLL12_CK_DIV5 170 +#define CLK_TOP_APLL12_CK_DIV5B 171 +#define CLK_TOP_APLL12_CK_DIV6 172 +#define CLK_TOP_USB_78M 173 +#define CLK_TOP_MSDC0_INFRA 174 +#define CLK_TOP_MSDC1_INFRA 175 +#define CLK_TOP_MSDC2_INFRA 176 +#define CLK_TOP_NR_CLK 177 + +#endif /* _DT_BINDINGS_CLK_MT8516_H */ diff --git a/include/dt-bindings/clock/qcom,gcc-qcs404.h b/include/dt-bindings/clock/qcom,gcc-qcs404.h index 6ceb55ed72c6..454b3f43f538 100644 --- a/include/dt-bindings/clock/qcom,gcc-qcs404.h +++ b/include/dt-bindings/clock/qcom,gcc-qcs404.h @@ -146,6 +146,10 @@ #define GCC_MDP_TBU_CLK 138 #define GCC_QDSS_DAP_CLK 139 #define GCC_DCC_XO_CLK 140 +#define GCC_CDSP_CFG_AHB_CLK 143 +#define GCC_BIMC_CDSP_CLK 144 +#define GCC_CDSP_TBU_CLK 145 +#define GCC_CDSP_BIMC_CLK_SRC 146 #define GCC_GENI_IR_BCR 0 #define GCC_USB_HS_BCR 1 @@ -161,5 +165,6 @@ #define GCC_PCIE_0_LINK_DOWN_BCR 11 #define GCC_PCIEPHY_0_PHY_BCR 12 #define GCC_EMAC_BCR 13 +#define GCC_CDSP_RESTART 14 #endif diff --git a/include/dt-bindings/clock/qcom,turingcc-qcs404.h b/include/dt-bindings/clock/qcom,turingcc-qcs404.h new file mode 100644 index 000000000000..838faef57c67 --- /dev/null +++ b/include/dt-bindings/clock/qcom,turingcc-qcs404.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019, Linaro Ltd + */ + +#ifndef _DT_BINDINGS_CLK_TURING_QCS404_H +#define _DT_BINDINGS_CLK_TURING_QCS404_H + +#define TURING_Q6SS_Q6_AXIM_CLK 0 +#define TURING_Q6SS_AHBM_AON_CLK 1 +#define TURING_WRAPPER_AON_CLK 2 +#define TURING_Q6SS_AHBS_AON_CLK 3 +#define TURING_WRAPPER_QOS_AHBS_AON_CLK 4 + +#endif diff --git a/include/dt-bindings/clock/stm32fx-clock.h b/include/dt-bindings/clock/stm32fx-clock.h index 58d8b515be55..7d34e297049c 100644 --- a/include/dt-bindings/clock/stm32fx-clock.h +++ b/include/dt-bindings/clock/stm32fx-clock.h @@ -54,7 +54,10 @@ #define CLK_I2C3 28 #define CLK_I2C4 29 #define CLK_LPTIMER 30 - -#define END_PRIMARY_CLK_F7 31 +#define CLK_PLL_SRC 31 +#define CLK_DFSDM1 32 +#define CLK_ADFSDM1 33 +#define CLK_F769_DSI 34 +#define END_PRIMARY_CLK_F7 35 #endif diff --git a/include/dt-bindings/clock/sun5i-ccu.h b/include/dt-bindings/clock/sun5i-ccu.h index 81f34d477aeb..2e6b9ddcc24e 100644 --- a/include/dt-bindings/clock/sun5i-ccu.h +++ b/include/dt-bindings/clock/sun5i-ccu.h @@ -100,7 +100,7 @@ #define CLK_AVS 96 #define CLK_HDMI 97 #define CLK_GPU 98 - +#define CLK_MBUS 99 #define CLK_IEP 100 #endif /* _DT_BINDINGS_CLK_SUN5I_H_ */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b7cf80a71293..491d992d045d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -24,7 +24,7 @@ #define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */ #define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ /* unused */ -#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */ + /* unused */ #define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ @@ -251,19 +251,40 @@ struct clk_ops { }; /** + * struct clk_parent_data - clk parent information + * @hw: parent clk_hw pointer (used for clk providers with internal clks) + * @fw_name: parent name local to provider registering clk + * @name: globally unique parent name (used as a fallback) + * @index: parent index local to provider registering clk (if @fw_name absent) + */ +struct clk_parent_data { + const struct clk_hw *hw; + const char *fw_name; + const char *name; + int index; +}; + +/** * struct clk_init_data - holds init data that's common to all clocks and is * shared between the clock provider and the common clock framework. * * @name: clock name * @ops: operations this clock supports * @parent_names: array of string names for all possible parents + * @parent_data: array of parent data for all possible parents (when some + * parents are external to the clk controller) + * @parent_hws: array of pointers to all possible parents (when all parents + * are internal to the clk controller) * @num_parents: number of possible parents * @flags: framework-level hints and quirks */ struct clk_init_data { const char *name; const struct clk_ops *ops; + /* Only one of the following three should be assigned */ const char * const *parent_names; + const struct clk_parent_data *parent_data; + const struct clk_hw **parent_hws; u8 num_parents; unsigned long flags; }; @@ -307,7 +328,6 @@ struct clk_fixed_rate { struct clk_hw hw; unsigned long fixed_rate; unsigned long fixed_accuracy; - u8 flags; }; #define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw) @@ -349,6 +369,9 @@ void of_fixed_clk_setup(struct device_node *np); * of this register, and mask of gate bits are in higher 16-bit of this * register. While setting the gate bits, higher 16-bit should also be * updated to indicate changing gate bits. + * CLK_GATE_BIG_ENDIAN - by default little endian register accesses are used for + * the gate register. Setting this flag makes the register accesses big + * endian. */ struct clk_gate { struct clk_hw hw; @@ -362,6 +385,7 @@ struct clk_gate { #define CLK_GATE_SET_TO_DISABLE BIT(0) #define CLK_GATE_HIWORD_MASK BIT(1) +#define CLK_GATE_BIG_ENDIAN BIT(2) extern const struct clk_ops clk_gate_ops; struct clk *clk_register_gate(struct device *dev, const char *name, @@ -417,6 +441,9 @@ struct clk_div_table { * CLK_DIVIDER_MAX_AT_ZERO - For dividers which are like CLK_DIVIDER_ONE_BASED * except when the value read from the register is zero, the divisor is * 2^width of the field. + * CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used + * for the divider register. Setting this flag makes the register accesses + * big endian. */ struct clk_divider { struct clk_hw hw; @@ -438,6 +465,7 @@ struct clk_divider { #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) #define CLK_DIVIDER_READ_ONLY BIT(5) #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) +#define CLK_DIVIDER_BIG_ENDIAN BIT(7) extern const struct clk_ops clk_divider_ops; extern const struct clk_ops clk_divider_ro_ops; @@ -499,8 +527,13 @@ void clk_hw_unregister_divider(struct clk_hw *hw); * register, and mask of mux bits are in higher 16-bit of this register. * While setting the mux bits, higher 16-bit should also be updated to * indicate changing mux bits. + * CLK_MUX_READ_ONLY - The mux registers can't be written, only read in the + * .get_parent clk_op. * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired * frequency. + * CLK_MUX_BIG_ENDIAN - By default little endian register accesses are used for + * the mux register. Setting this flag makes the register accesses big + * endian. */ struct clk_mux { struct clk_hw hw; @@ -519,6 +552,7 @@ struct clk_mux { #define CLK_MUX_HIWORD_MASK BIT(2) #define CLK_MUX_READ_ONLY BIT(3) /* mux can't be changed */ #define CLK_MUX_ROUND_CLOSEST BIT(4) +#define CLK_MUX_BIG_ENDIAN BIT(5) extern const struct clk_ops clk_mux_ops; extern const struct clk_ops clk_mux_ro_ops; @@ -602,6 +636,9 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED * is set then the numerator and denominator are both the value read * plus one. + * CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are + * used for the divider register. Setting this flag makes the register + * accesses big endian. */ struct clk_fractional_divider { struct clk_hw hw; @@ -622,6 +659,7 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) #define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0) +#define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1) extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, @@ -654,6 +692,9 @@ void clk_hw_unregister_fractional_divider(struct clk_hw *hw); * leaving the parent rate unmodified. * CLK_MULTIPLIER_ROUND_CLOSEST - Makes the best calculated divider to be * rounded to the closest integer instead of the down one. + * CLK_MULTIPLIER_BIG_ENDIAN - By default little endian register accesses are + * used for the multiplier register. Setting this flag makes the register + * accesses big endian. */ struct clk_multiplier { struct clk_hw hw; @@ -668,6 +709,7 @@ struct clk_multiplier { #define CLK_MULTIPLIER_ZERO_BYPASS BIT(0) #define CLK_MULTIPLIER_ROUND_CLOSEST BIT(1) +#define CLK_MULTIPLIER_BIG_ENDIAN BIT(2) extern const struct clk_ops clk_multiplier_ops; @@ -712,16 +754,19 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, unsigned long flags); void clk_hw_unregister_composite(struct clk_hw *hw); -/*** - * struct clk_gpio_gate - gpio gated clock +/** + * struct clk_gpio - gpio gated clock * * @hw: handle between common and hardware-specific interfaces * @gpiod: gpio descriptor * - * Clock with a gpio control for enabling and disabling the parent clock. - * Implements .enable, .disable and .is_enabled + * Clock with a gpio control for enabling and disabling the parent clock + * or switching between two parents by asserting or deasserting the gpio. + * + * Implements .enable, .disable and .is_enabled or + * .get_parent, .set_parent and .determine_rate depending on which clk_ops + * is used. */ - struct clk_gpio { struct clk_hw hw; struct gpio_desc *gpiod; @@ -738,16 +783,6 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, unsigned long flags); void clk_hw_unregister_gpio_gate(struct clk_hw *hw); -/** - * struct clk_gpio_mux - gpio controlled clock multiplexer - * - * @hw: see struct clk_gpio - * @gpiod: gpio descriptor to select the parent of this clock multiplexer - * - * Clock with a gpio control for selecting the parent clock. - * Implements .get_parent, .set_parent and .determine_rate - */ - extern const struct clk_ops clk_gpio_mux_ops; struct clk *clk_register_gpio_mux(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod, @@ -757,22 +792,12 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name, unsigned long flags); void clk_hw_unregister_gpio_mux(struct clk_hw *hw); -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ struct clk *clk_register(struct device *dev, struct clk_hw *hw); struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw); int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw); int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw); +int __must_check of_clk_hw_register(struct device_node *node, struct clk_hw *hw); void clk_unregister(struct clk *clk); void devm_clk_unregister(struct device *dev, struct clk *clk); @@ -993,37 +1018,6 @@ static inline int of_clk_detect_critical(struct device_node *np, int index, } #endif /* CONFIG_OF */ -/* - * wrap access to peripherals in accessor routines - * for improved portability across platforms - */ - -#if IS_ENABLED(CONFIG_PPC) - -static inline u32 clk_readl(u32 __iomem *reg) -{ - return ioread32be(reg); -} - -static inline void clk_writel(u32 val, u32 __iomem *reg) -{ - iowrite32be(val, reg); -} - -#else /* platform dependent I/O accessors */ - -static inline u32 clk_readl(u32 __iomem *reg) -{ - return readl(reg); -} - -static inline void clk_writel(u32 val, u32 __iomem *reg) -{ - writel(val, reg); -} - -#endif /* platform dependent I/O accessors */ - void clk_gate_restore_context(struct clk_hw *hw); #endif /* CONFIG_COMMON_CLK */ diff --git a/include/linux/clk/analogbits-wrpll-cln28hpc.h b/include/linux/clk/analogbits-wrpll-cln28hpc.h new file mode 100644 index 000000000000..03279097e138 --- /dev/null +++ b/include/linux/clk/analogbits-wrpll-cln28hpc.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018-2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + */ + +#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H +#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H + +#include <linux/types.h> + +/* DIVQ_VALUES: number of valid DIVQ values */ +#define DIVQ_VALUES 6 + +/* + * Bit definitions for struct wrpll_cfg.flags + * + * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be + * programmed to enter bypass + * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset + * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal + * feedback mode + * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external + * feedback mode (not yet supported by this driver) + */ +#define WRPLL_FLAGS_BYPASS_SHIFT 0 +#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT) +#define WRPLL_FLAGS_RESET_SHIFT 1 +#define WRPLL_FLAGS_RESET_MASK BIT(WRPLL_FLAGS_RESET_SHIFT) +#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT 2 +#define WRPLL_FLAGS_INT_FEEDBACK_MASK BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT) +#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT 3 +#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT) + +/** + * struct wrpll_cfg - WRPLL configuration values + * @divr: reference divider value (6 bits), as presented to the PLL signals + * @divf: feedback divider value (9 bits), as presented to the PLL signals + * @divq: output divider value (3 bits), as presented to the PLL signals + * @flags: PLL configuration flags. See above for more information + * @range: PLL loop filter range. See below for more information + * @output_rate_cache: cached output rates, swept across DIVQ + * @parent_rate: PLL refclk rate for which values are valid + * @max_r: maximum possible R divider value, given @parent_rate + * @init_r: initial R divider value to start the search from + * + * @divr, @divq, @divq, @range represent what the PLL expects to see + * on its input signals. Thus @divr and @divf are the actual divisors + * minus one. @divq is a power-of-two divider; for example, 1 = + * divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value. + * + * When initially passing a struct wrpll_cfg record, the + * record should be zero-initialized with the exception of the @flags + * field. The only flag bits that need to be set are either + * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK. + */ +struct wrpll_cfg { + u8 divr; + u8 divq; + u8 range; + u8 flags; + u16 divf; +/* private: */ + u32 output_rate_cache[DIVQ_VALUES]; + unsigned long parent_rate; + u8 max_r; + u8 init_r; +}; + +int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate, + unsigned long parent_rate); + +unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c); + +unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c, + unsigned long parent_rate); + +#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */ diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 931ab05f771d..0c53f26ae3d3 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -74,6 +74,8 @@ #define AT91_PMC_USBDIV_4 (2 << 28) #define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ +#define AT91_PMC_CPU_CKR 0x28 /* CPU Clock Register */ + #define AT91_PMC_MCKR 0x30 /* Master Clock Register */ #define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ #define AT91_PMC_CSS_SLOW (0 << 0) @@ -187,16 +189,8 @@ #define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ #define AT91_PMC_PCR_PID_MASK 0x3f -#define AT91_PMC_PCR_GCKCSS_OFFSET 8 -#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) -#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_DIV_OFFSET 16 -#define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET) -#define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */ -#define AT91_PMC_PCR_GCKDIV_OFFSET 20 -#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) -#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ +#define AT91_PMC_PCR_GCKDIV_MASK GENMASK(27, 20) #define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ #define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 78872efc7be0..1e8ef96555ce 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -243,6 +243,7 @@ struct ti_clk_ll_ops { #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) +bool omap2_clk_is_hw_omap(struct clk_hw *hw); int omap2_clk_disable_autoidle_all(void); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); @@ -293,6 +294,7 @@ struct ti_clk_features { #define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2) #define TI_CLK_ERRATA_I810 BIT(3) #define TI_CLK_CLKCTRL_COMPAT BIT(4) +#define TI_CLK_DEVICE_TYPE_GP BIT(5) void ti_clk_setup_features(struct ti_clk_features *features); const struct ti_clk_features *ti_clk_get_features(void); diff --git a/include/linux/device.h b/include/linux/device.h index 4457e560bc2b..e85264fb6616 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1229,7 +1229,7 @@ static inline void device_lock_assert(struct device *dev) static inline struct device_node *dev_of_node(struct device *dev) { - if (!IS_ENABLED(CONFIG_OF)) + if (!IS_ENABLED(CONFIG_OF) || !dev) return NULL; return dev->of_node; } diff --git a/include/linux/math64.h b/include/linux/math64.h index bb2c84afb80c..65bef21cdddb 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -284,4 +284,17 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) #define DIV64_U64_ROUND_UP(ll, d) \ ({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); }) +/** + * DIV64_U64_ROUND_CLOSEST - unsigned 64bit divide with 64bit divisor rounded to nearest integer + * @dividend: unsigned 64bit dividend + * @divisor: unsigned 64bit divisor + * + * Divide unsigned 64bit dividend by unsigned 64bit divisor + * and round to closest integer. + * + * Return: dividend / divisor rounded to nearest integer + */ +#define DIV64_U64_ROUND_CLOSEST(dividend, divisor) \ + ({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); }) + #endif /* _LINUX_MATH64_H */ |