diff options
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 */ |