diff options
134 files changed, 6947 insertions, 2006 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index c75e5d6b8fa8..a6eb7dcd4dd5 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml \ kernel-api.xml filesystems.xml lsm.xml kgdb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ - 80211.xml sh.xml regulator.xml w1.xml \ + sh.xml regulator.xml w1.xml \ writing_musb_glue_layer.xml iio.xml ifeq ($(DOCBOOKS),) diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt index e56a1df3a9d3..dd906db34b32 100644 --- a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt @@ -16,7 +16,20 @@ Required properties: - #clock-cells: Should be <1>. The permitted clock-specifier values can be found in include/dt-bindings/clock/bcm2835.h - reg: Specifies base physical address and size of the registers -- clocks: The external oscillator clock phandle +- clocks: phandles to the parent clocks used as input to the module, in + the following order: + + - External oscillator + - DSI0 byte clock + - DSI0 DDR2 clock + - DSI0 DDR clock + - DSI1 byte clock + - DSI1 DDR2 clock + - DSI1 DDR clock + + Only external oscillator is required. The DSI clocks may + not be present, in which case their children will be + unusable. Example: diff --git a/Documentation/devicetree/bindings/clock/exynos4415-clock.txt b/Documentation/devicetree/bindings/clock/exynos4415-clock.txt deleted file mode 100644 index 847d98bae8cf..000000000000 --- a/Documentation/devicetree/bindings/clock/exynos4415-clock.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Samsung Exynos4415 Clock Controller - -The Exynos4415 clock controller generates and supplies clock to various -consumer devices within the Exynos4415 SoC. - -Required properties: - -- compatible: should be one of the following: - - "samsung,exynos4415-cmu" - for the main system clocks controller - (CMU_LEFTBUS, CMU_RIGHTBUS, CMU_TOP, CMU_CPU clock domains). - - "samsung,exynos4415-cmu-dmc" - for the Exynos4415 SoC DRAM Memory - Controller (DMC) domain clock controller. - -- reg: physical base address of the controller and length of memory mapped - region. - -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. - -All available clocks are defined as preprocessor macros in -dt-bindings/clock/exynos4415.h header and can be used in device -tree sources. - -Example 1: An example of a clock controller node is listed below. - - cmu: clock-controller@10030000 { - compatible = "samsung,exynos4415-cmu"; - reg = <0x10030000 0x18000>; - #clock-cells = <1>; - }; - - cmu-dmc: clock-controller@105C0000 { - compatible = "samsung,exynos4415-cmu-dmc"; - reg = <0x105C0000 0x3000>; - #clock-cells = <1>; - }; diff --git a/Documentation/devicetree/bindings/clock/hi3660-clock.txt b/Documentation/devicetree/bindings/clock/hi3660-clock.txt new file mode 100644 index 000000000000..cc9b86c35758 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hi3660-clock.txt @@ -0,0 +1,42 @@ +* Hisilicon Hi3660 Clock Controller + +The Hi3660 clock controller generates and supplies clock to various +controllers within the Hi3660 SoC. + +Required Properties: + +- compatible: the compatible should be one of the following strings to + indicate the clock controller functionality. + + - "hisilicon,hi3660-crgctrl" + - "hisilicon,hi3660-pctrl" + - "hisilicon,hi3660-pmuctrl" + - "hisilicon,hi3660-sctrl" + - "hisilicon,hi3660-iomcu" + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in <dt-bindings/clock/hi3660-clock.h>. + +Examples: + crg_ctrl: clock-controller@fff35000 { + compatible = "hisilicon,hi3660-crgctrl", "syscon"; + reg = <0x0 0xfff35000 0x0 0x1000>; + #clock-cells = <1>; + }; + + uart0: serial@fdf02000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xfdf02000 0x0 0x1000>; + interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg_ctrl HI3660_CLK_MUX_UART0>, + <&crg_ctrl HI3660_PCLK>; + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/clock/idt,versaclock5.txt b/Documentation/devicetree/bindings/clock/idt,versaclock5.txt new file mode 100644 index 000000000000..87e9c47a89a3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/idt,versaclock5.txt @@ -0,0 +1,65 @@ +Binding for IDT VersaClock5 programmable i2c clock generator. + +The IDT VersaClock5 are programmable i2c clock generators providing +from 3 to 12 output clocks. + +==I2C device node== + +Required properties: +- compatible: shall be one of "idt,5p49v5923" , "idt,5p49v5933". +- reg: i2c device address, shall be 0x68 or 0x6a. +- #clock-cells: from common clock binding; shall be set to 1. +- clocks: from common clock binding; list of parent clock handles, + - 5p49v5923: (required) either or both of XTAL or CLKIN + reference clock. + - 5p49v5933: (optional) property not present (internal + Xtal used) or CLKIN reference + clock. +- clock-names: from common clock binding; clock input names, can be + - 5p49v5923: (required) either or both of "xin", "clkin". + - 5p49v5933: (optional) property not present or "clkin". + +==Mapping between clock specifier and physical pins== + +When referencing the provided clock in the DT using phandle and +clock specifier, the following mapping applies: + +5P49V5923: + 0 -- OUT0_SEL_I2CB + 1 -- OUT1 + 2 -- OUT2 + +5P49V5933: + 0 -- OUT0_SEL_I2CB + 1 -- OUT1 + 2 -- OUT4 + +==Example== + +/* 25MHz reference crystal */ +ref25: ref25m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; +}; + +i2c-master-node { + + /* IDT 5P49V5923 i2c clock generator */ + vc5: clock-generator@6a { + compatible = "idt,5p49v5923"; + reg = <0x6a>; + #clock-cells = <1>; + + /* Connect XIN input to 25MHz reference */ + clocks = <&ref25m>; + clock-names = "xin"; + }; +}; + +/* Consumer referencing the 5P49V5923 pin OUT1 */ +consumer { + ... + clocks = <&vc5 1>; + ... +} diff --git a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt index 520562a7dc2a..c7b4e3a6b2c6 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt @@ -7,6 +7,7 @@ Required properties: - compatible : must be "marvell,armada-370-corediv-clock", "marvell,armada-375-corediv-clock", "marvell,armada-380-corediv-clock", + "marvell,mv98dx3236-corediv-clock", - reg : must be the register address of Core Divider control register - #clock-cells : from common clock binding; shall be set to 1 diff --git a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt index 99c214660bdc..7f28506eaee7 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt @@ -3,6 +3,7 @@ Device Tree Clock bindings for cpu clock of Marvell EBU platforms Required properties: - compatible : shall be one of the following: "marvell,armada-xp-cpu-clock" - cpu clocks for Armada XP + "marvell,mv98dx3236-cpu-clock" - cpu clocks for 98DX3236 SoC - reg : Address and length of the clock complex register set, followed by address and length of the PMU DFS registers - #clock-cells : should be set to 1. diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt index 87d3714b956a..a7235e9e1c97 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt @@ -11,6 +11,7 @@ Required properties : compatible "qcom,rpmcc" should be also included. "qcom,rpmcc-msm8916", "qcom,rpmcc" + "qcom,rpmcc-msm8974", "qcom,rpmcc" "qcom,rpmcc-apq8064", "qcom,rpmcc" - #clock-cells : shall contain 1 diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt new file mode 100644 index 000000000000..e71c675ba5da --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt @@ -0,0 +1,57 @@ +* Rockchip RK3328 Clock and Reset Unit + +The RK3328 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3328-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "clkin_i2s" - external I2S clock - optional, + - "gmac_clkin" - external GMAC clock - optional + - "phy_50m_out" - output clock of the pll in the mac phy + +Example: Clock controller node: + + cru: clock-controller@ff440000 { + compatible = "rockchip,rk3328-cru"; + reg = <0x0 0xff440000 0x0 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@ff120000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff120000 0x100>; + interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt index 3888dd33fcbd..3bc56fae90ac 100644 --- a/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt @@ -13,6 +13,12 @@ Required Properties: - #clock-cells: should be 1. - #reset-cells: should be 1. +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files". + It is used for GRF muxes, if missing any muxes present in the GRF will not + be available. + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. All available clocks are defined as preprocessor macros in the dt-bindings/clock/rk3399-cru.h headers and can be diff --git a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt index 0532d815dae3..b240121d2ac9 100644 --- a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt +++ b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt @@ -10,6 +10,7 @@ Required properties: - compatible: Should be: "st,stm32f42xx-rcc" "st,stm32f469-rcc" + "st,stm32f746-rcc" - reg: should be register base and length as documented in the datasheet - #reset-cells: 1, see below @@ -17,6 +18,9 @@ Required properties: property, containing a phandle to the clock device node, an index selecting between gated clocks and other clocks and an index specifying the clock to use. +- clocks: External oscillator clock phandle + - high speed external clock signal (HSE) + - external I2S clock (I2S_CKIN) Example: @@ -25,6 +29,7 @@ Example: #clock-cells = <2> compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; reg = <0x40023800 0x400>; + clocks = <&clk_hse>, <&clk_i2s_ckin>; }; Specifying gated clocks @@ -66,6 +71,38 @@ The secondary index is bound with the following magic numbers: 0 SYSTICK 1 FCLK + 2 CLK_LSI (low-power clock source) + 3 CLK_LSE (generated from a 32.768 kHz low-speed external + crystal or ceramic resonator) + 4 CLK_HSE_RTC (HSE division factor for RTC clock) + 5 CLK_RTC (real-time clock) + 6 PLL_VCO_I2S (vco frequency of I2S pll) + 7 PLL_VCO_SAI (vco frequency of SAI pll) + 8 CLK_LCD (LCD-TFT) + 9 CLK_I2S (I2S clocks) + 10 CLK_SAI1 (audio clocks) + 11 CLK_SAI2 + 12 CLK_I2SQ_PDIV (post divisor of pll i2s q divisor) + 13 CLK_SAIQ_PDIV (post divisor of pll sai q divisor) + + 14 CLK_HSI (Internal ocscillator clock) + 15 CLK_SYSCLK (System Clock) + 16 CLK_HDMI_CEC (HDMI-CEC clock) + 17 CLK_SPDIF (SPDIF-Rx clock) + 18 CLK_USART1 (U(s)arts clocks) + 19 CLK_USART2 + 20 CLK_USART3 + 21 CLK_UART4 + 22 CLK_UART5 + 23 CLK_USART6 + 24 CLK_UART7 + 25 CLK_UART8 + 26 CLK_I2C1 (I2S clocks) + 27 CLK_I2C2 + 28 CLK_I2C3 + 29 CLK_I2C4 + 30 CLK_LPTIMER (LPTimer1 clock) +) Example: diff --git a/Documentation/devicetree/bindings/clock/stericsson,abx500.txt b/Documentation/devicetree/bindings/clock/stericsson,abx500.txt new file mode 100644 index 000000000000..dbaa886b223e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/stericsson,abx500.txt @@ -0,0 +1,20 @@ +Clock bindings for ST-Ericsson ABx500 clocks + +Required properties : +- compatible : shall contain the following: + "stericsson,ab8500-clk" +- #clock-cells should be <1> + +The ABx500 clocks need to be placed as a subnode of an AB8500 +device node, see mfd/ab8500.txt + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/ste-ab8500.h header and can be used in device +tree sources. + +Example: + +clock-controller { + compatible = "stericsson,ab8500-clk"; + #clock-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt index 4c7669ad681b..0d01f2d5cc36 100644 --- a/Documentation/devicetree/bindings/clock/ti,cdce925.txt +++ b/Documentation/devicetree/bindings/clock/ti,cdce925.txt @@ -1,15 +1,22 @@ -Binding for TO CDCE925 programmable I2C clock synthesizers. +Binding for TI CDCE913/925/937/949 programmable I2C clock synthesizers. Reference This binding uses the common clock binding[1]. [1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] http://www.ti.com/product/cdce925 +[2] http://www.ti.com/product/cdce913 +[3] http://www.ti.com/product/cdce925 +[4] http://www.ti.com/product/cdce937 +[5] http://www.ti.com/product/cdce949 The driver provides clock sources for each output Y1 through Y5. Required properties: - - compatible: Shall be "ti,cdce925" + - compatible: Shall be one of the following: + - "ti,cdce913": 1-PLL, 3 Outputs + - "ti,cdce925": 2-PLL, 5 Outputs + - "ti,cdce937": 3-PLL, 7 Outputs + - "ti,cdce949": 4-PLL, 9 Outputs - reg: I2C device address. - clocks: Points to a fixed parent clock that provides the input frequency. - #clock-cells: From common clock bindings: Shall be 1. @@ -18,7 +25,7 @@ Optional properties: - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a board, or to compensate for external influences. -For both PLL1 and PLL2 an optional child node can be used to specify spread +For all PLL1, PLL2, ... an optional child node can be used to specify spread spectrum clocking parameters for a board. - spread-spectrum: SSC mode as defined in the data sheet. - spread-spectrum-center: Use "centered" mode instead of "max" mode. When diff --git a/Documentation/devicetree/bindings/clock/zx296718-clk.txt b/Documentation/devicetree/bindings/clock/zx296718-clk.txt index 8c18b7b237bf..4ad703808407 100644 --- a/Documentation/devicetree/bindings/clock/zx296718-clk.txt +++ b/Documentation/devicetree/bindings/clock/zx296718-clk.txt @@ -13,6 +13,9 @@ Required properties: "zte,zx296718-lsp1crm": zx296718 device level clock selection and gating + "zte,zx296718-audiocrm": + zx296718 audio clock selection, divider and gating + - reg: Address and length of the register set The clock consumer should specify the desired clock by having the clock diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt index a445da098bc6..3f76c0c37920 100644 --- a/Documentation/unaligned-memory-access.txt +++ b/Documentation/unaligned-memory-access.txt @@ -151,7 +151,7 @@ bool ether_addr_equal(const u8 *addr1, const u8 *addr2) #else const u16 *a = (const u16 *)addr1; const u16 *b = (const u16 *)addr2; - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; #endif } diff --git a/MAINTAINERS b/MAINTAINERS index cfff2c9e3d94..452df181e261 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6185,6 +6185,11 @@ S: Maintained F: drivers/mfd/lpc_ich.c F: drivers/gpio/gpio-ich.c +IDT VersaClock 5 CLOCK DRIVER +M: Marek Vasut <marek.vasut@gmail.com> +S: Maintained +F: drivers/clk/clk-versaclock5.c + IDE SUBSYSTEM M: "David S. Miller" <davem@davemloft.net> L: linux-ide@vger.kernel.org @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 10 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Roaring Lionus # *DOCUMENTATION* diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h new file mode 100644 index 000000000000..df411f3e083c --- /dev/null +++ b/arch/arm64/include/asm/asm-uaccess.h @@ -0,0 +1,65 @@ +#ifndef __ASM_ASM_UACCESS_H +#define __ASM_ASM_UACCESS_H + +#include <asm/alternative.h> +#include <asm/kernel-pgtable.h> +#include <asm/sysreg.h> +#include <asm/assembler.h> + +/* + * User access enabling/disabling macros. + */ +#ifdef CONFIG_ARM64_SW_TTBR0_PAN + .macro __uaccess_ttbr0_disable, tmp1 + mrs \tmp1, ttbr1_el1 // swapper_pg_dir + add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir + msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1 + isb + .endm + + .macro __uaccess_ttbr0_enable, tmp1 + get_thread_info \tmp1 + ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1 + msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1 + isb + .endm + + .macro uaccess_ttbr0_disable, tmp1 +alternative_if_not ARM64_HAS_PAN + __uaccess_ttbr0_disable \tmp1 +alternative_else_nop_endif + .endm + + .macro uaccess_ttbr0_enable, tmp1, tmp2 +alternative_if_not ARM64_HAS_PAN + save_and_disable_irq \tmp2 // avoid preemption + __uaccess_ttbr0_enable \tmp1 + restore_irq \tmp2 +alternative_else_nop_endif + .endm +#else + .macro uaccess_ttbr0_disable, tmp1 + .endm + + .macro uaccess_ttbr0_enable, tmp1, tmp2 + .endm +#endif + +/* + * These macros are no-ops when UAO is present. + */ + .macro uaccess_disable_not_uao, tmp1 + uaccess_ttbr0_disable \tmp1 +alternative_if ARM64_ALT_PAN_NOT_UAO + SET_PSTATE_PAN(1) +alternative_else_nop_endif + .endm + + .macro uaccess_enable_not_uao, tmp1, tmp2 + uaccess_ttbr0_enable \tmp1, \tmp2 +alternative_if ARM64_ALT_PAN_NOT_UAO + SET_PSTATE_PAN(0) +alternative_else_nop_endif + .endm + +#endif diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index d26750ca6e06..46da3ea638bb 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -22,8 +22,6 @@ #include <asm/kernel-pgtable.h> #include <asm/sysreg.h> -#ifndef __ASSEMBLY__ - /* * User space memory access functions */ @@ -424,66 +422,4 @@ extern long strncpy_from_user(char *dest, const char __user *src, long count); extern __must_check long strlen_user(const char __user *str); extern __must_check long strnlen_user(const char __user *str, long n); -#else /* __ASSEMBLY__ */ - -#include <asm/assembler.h> - -/* - * User access enabling/disabling macros. - */ -#ifdef CONFIG_ARM64_SW_TTBR0_PAN - .macro __uaccess_ttbr0_disable, tmp1 - mrs \tmp1, ttbr1_el1 // swapper_pg_dir - add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir - msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1 - isb - .endm - - .macro __uaccess_ttbr0_enable, tmp1 - get_thread_info \tmp1 - ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1 - msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1 - isb - .endm - - .macro uaccess_ttbr0_disable, tmp1 -alternative_if_not ARM64_HAS_PAN - __uaccess_ttbr0_disable \tmp1 -alternative_else_nop_endif - .endm - - .macro uaccess_ttbr0_enable, tmp1, tmp2 -alternative_if_not ARM64_HAS_PAN - save_and_disable_irq \tmp2 // avoid preemption - __uaccess_ttbr0_enable \tmp1 - restore_irq \tmp2 -alternative_else_nop_endif - .endm -#else - .macro uaccess_ttbr0_disable, tmp1 - .endm - - .macro uaccess_ttbr0_enable, tmp1, tmp2 - .endm -#endif - -/* - * These macros are no-ops when UAO is present. - */ - .macro uaccess_disable_not_uao, tmp1 - uaccess_ttbr0_disable \tmp1 -alternative_if ARM64_ALT_PAN_NOT_UAO - SET_PSTATE_PAN(1) -alternative_else_nop_endif - .endm - - .macro uaccess_enable_not_uao, tmp1, tmp2 - uaccess_ttbr0_enable \tmp1, \tmp2 -alternative_if ARM64_ALT_PAN_NOT_UAO - SET_PSTATE_PAN(0) -alternative_else_nop_endif - .endm - -#endif /* __ASSEMBLY__ */ - #endif /* __ASM_UACCESS_H */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a7504f40d7ee..923841ffe4a9 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -31,7 +31,7 @@ #include <asm/memory.h> #include <asm/ptrace.h> #include <asm/thread_info.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> #include <asm/unistd.h> /* diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index add4a1334085..e88fb99c1561 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -17,7 +17,7 @@ */ #include <linux/linkage.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> .text diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index fd6cd05593f9..4b5d826895ff 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -17,7 +17,7 @@ #include <linux/linkage.h> #include <asm/cache.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> /* * Copy from user space to a kernel buffer (alignment handled by the hardware) diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index d828540ded6f..47184c3a97da 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -19,7 +19,7 @@ #include <linux/linkage.h> #include <asm/cache.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> /* * Copy from user space to user space (alignment handled by the hardware) diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index 3e6ae2663b82..351f0766f7a6 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -17,7 +17,7 @@ #include <linux/linkage.h> #include <asm/cache.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> /* * Copy to user space from a kernel buffer (alignment handled by the hardware) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 17f422a4dc55..83c27b6e6dca 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -23,7 +23,7 @@ #include <asm/assembler.h> #include <asm/cpufeature.h> #include <asm/alternative.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> /* * flush_icache_range(start,end) diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S index 47cf3f9d89ff..947830a459d2 100644 --- a/arch/arm64/xen/hypercall.S +++ b/arch/arm64/xen/hypercall.S @@ -49,7 +49,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <linux/uaccess.h> +#include <asm/asm-uaccess.h> #include <xen/interface/xen.h> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e487493bbd47..7b4f1789f386 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2789,10 +2789,6 @@ config X86_DMA_REMAP bool depends on STA2X11 -config PMC_ATOM - def_bool y - depends on PCI - source "net/Kconfig" source "drivers/Kconfig" diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 68557f52b961..854022772c5b 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -139,6 +139,19 @@ static __always_inline void __clear_bit(long nr, volatile unsigned long *addr) asm volatile("btr %1,%0" : ADDR : "Ir" (nr)); } +static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr) +{ + bool negative; + asm volatile(LOCK_PREFIX "andb %2,%1\n\t" + CC_SET(s) + : CC_OUT(s) (negative), ADDR + : "ir" ((char) ~(1 << nr)) : "memory"); + return negative; +} + +// Let everybody know we have it +#define clear_bit_unlock_is_negative_byte clear_bit_unlock_is_negative_byte + /* * __clear_bit_unlock - Clears a bit in memory * @nr: Bit to clear diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index ffacfdcacb85..a5fd137417a2 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -1182,6 +1182,9 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) const char *name = get_name(bank, NULL); int err = 0; + if (!dev) + return -ENODEV; + if (is_shared_bank(bank)) { nb = node_to_amd_nb(amd_get_nb_id(cpu)); diff --git a/arch/x86/platform/atom/Makefile b/arch/x86/platform/atom/Makefile index 40983f5b0858..57be88fa34bb 100644 --- a/arch/x86/platform/atom/Makefile +++ b/arch/x86/platform/atom/Makefile @@ -1,2 +1 @@ -obj-$(CONFIG_PMC_ATOM) += pmc_atom.o obj-$(CONFIG_PUNIT_ATOM_DEBUG) += punit_atom_debug.o diff --git a/crypto/testmgr.c b/crypto/testmgr.c index f616ad74cce7..44e888b0b041 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1461,16 +1461,25 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, for (i = 0; i < ctcount; i++) { unsigned int dlen = COMP_BUF_SIZE; int ilen = ctemplate[i].inlen; + void *input_vec; + input_vec = kmalloc(ilen, GFP_KERNEL); + if (!input_vec) { + ret = -ENOMEM; + goto out; + } + + memcpy(input_vec, ctemplate[i].input, ilen); memset(output, 0, dlen); init_completion(&result.completion); - sg_init_one(&src, ctemplate[i].input, ilen); + sg_init_one(&src, input_vec, ilen); sg_init_one(&dst, output, dlen); req = acomp_request_alloc(tfm); if (!req) { pr_err("alg: acomp: request alloc failed for %s\n", algo); + kfree(input_vec); ret = -ENOMEM; goto out; } @@ -1483,6 +1492,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, if (ret) { pr_err("alg: acomp: compression failed on test %d for %s: ret=%d\n", i + 1, algo, -ret); + kfree(input_vec); acomp_request_free(req); goto out; } @@ -1491,6 +1501,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, pr_err("alg: acomp: Compression test %d failed for %s: output len = %d\n", i + 1, algo, req->dlen); ret = -EINVAL; + kfree(input_vec); acomp_request_free(req); goto out; } @@ -1500,26 +1511,37 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, i + 1, algo); hexdump(output, req->dlen); ret = -EINVAL; + kfree(input_vec); acomp_request_free(req); goto out; } + kfree(input_vec); acomp_request_free(req); } for (i = 0; i < dtcount; i++) { unsigned int dlen = COMP_BUF_SIZE; int ilen = dtemplate[i].inlen; + void *input_vec; + + input_vec = kmalloc(ilen, GFP_KERNEL); + if (!input_vec) { + ret = -ENOMEM; + goto out; + } + memcpy(input_vec, dtemplate[i].input, ilen); memset(output, 0, dlen); init_completion(&result.completion); - sg_init_one(&src, dtemplate[i].input, ilen); + sg_init_one(&src, input_vec, ilen); sg_init_one(&dst, output, dlen); req = acomp_request_alloc(tfm); if (!req) { pr_err("alg: acomp: request alloc failed for %s\n", algo); + kfree(input_vec); ret = -ENOMEM; goto out; } @@ -1532,6 +1554,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, if (ret) { pr_err("alg: acomp: decompression failed on test %d for %s: ret=%d\n", i + 1, algo, -ret); + kfree(input_vec); acomp_request_free(req); goto out; } @@ -1540,6 +1563,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, pr_err("alg: acomp: Decompression test %d failed for %s: output len = %d\n", i + 1, algo, req->dlen); ret = -EINVAL; + kfree(input_vec); acomp_request_free(req); goto out; } @@ -1549,10 +1573,12 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate, i + 1, algo); hexdump(output, req->dlen); ret = -EINVAL; + kfree(input_vec); acomp_request_free(req); goto out; } + kfree(input_vec); acomp_request_free(req); } diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 8ea836c046f8..90d112a3063a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -18,6 +18,7 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/platform_data/clk-lpss.h> +#include <linux/platform_data/x86/pmc_atom.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/delay.h> @@ -31,7 +32,6 @@ ACPI_MODULE_NAME("acpi_lpss"); #include <asm/cpu_device_id.h> #include <asm/intel-family.h> #include <asm/iosf_mbi.h> -#include <asm/pmc_atom.h> #define LPSS_ADDR(desc) ((unsigned long)&desc) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 56c1998ced3e..9356ab4b7d76 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -95,16 +95,17 @@ config COMMON_CLK_CDCE706 This driver supports TI CDCE706 programmable 3-PLL clock synthesizer. config COMMON_CLK_CDCE925 - tristate "Clock driver for TI CDCE925 devices" + tristate "Clock driver for TI CDCE913/925/937/949 devices" depends on I2C depends on OF select REGMAP_I2C help ---help--- - This driver supports the TI CDCE925 programmable clock synthesizer. - The chip contains two PLLs with spread-spectrum clocking support and - five output dividers. The driver only supports the following setup, - and uses a fixed setting for the output muxes. + This driver supports the TI CDCE913/925/937/949 programmable clock + synthesizer. Each chip has different number of PLLs and outputs. + For example, the CDCE925 contains two PLLs with spread-spectrum + clocking support and five output dividers. The driver only supports + the following setup, and uses a fixed setting for the output muxes. Y1 is derived from the input clock Y2 and Y3 derive from PLL1 Y4 and Y5 derive from PLL2 @@ -198,6 +199,16 @@ config COMMON_CLK_OXNAS ---help--- Support for the OXNAS SoC Family clocks. +config COMMON_CLK_VC5 + tristate "Clock driver for IDT VersaClock5 devices" + depends on I2C + depends on OF + select REGMAP_I2C + help + ---help--- + This driver supports the IDT VersaClock5 programmable clock + generator. + source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/mediatek/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 925081ec14c0..92c12b86c2e8 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_ARCH_U300) += clk-u300.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o +obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o @@ -87,6 +88,8 @@ obj-y += ti/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ +ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_X86) += x86/ +endif obj-$(CONFIG_ARCH_ZX) += zte/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/ diff --git a/drivers/clk/axs10x/i2s_pll_clock.c b/drivers/clk/axs10x/i2s_pll_clock.c index 411310d29581..02d3bcd6216c 100644 --- a/drivers/clk/axs10x/i2s_pll_clock.c +++ b/drivers/clk/axs10x/i2s_pll_clock.c @@ -182,6 +182,7 @@ static int i2s_pll_clk_probe(struct platform_device *pdev) if (IS_ERR(pll_clk->base)) return PTR_ERR(pll_clk->base); + memset(&init, 0, sizeof(init)); clk_name = node->name; init.name = clk_name; init.ops = &i2s_pll_ops; diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 0d14409097e7..025853870619 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -39,6 +39,7 @@ #include <linux/clk.h> #include <linux/clk/bcm2835.h> #include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -98,7 +99,8 @@ #define CM_SMIDIV 0x0b4 /* no definition for 0x0b8 and 0x0bc */ #define CM_TCNTCTL 0x0c0 -#define CM_TCNTDIV 0x0c4 +# define CM_TCNT_SRC1_SHIFT 12 +#define CM_TCNTCNT 0x0c4 #define CM_TECCTL 0x0c8 #define CM_TECDIV 0x0cc #define CM_TD0CTL 0x0d0 @@ -297,11 +299,32 @@ #define LOCK_TIMEOUT_NS 100000000 #define BCM2835_MAX_FB_RATE 1750000000u +/* + * Names of clocks used within the driver that need to be replaced + * with an external parent's name. This array is in the order that + * the clocks node in the DT references external clocks. + */ +static const char *const cprman_parent_names[] = { + "xosc", + "dsi0_byte", + "dsi0_ddr2", + "dsi0_ddr", + "dsi1_byte", + "dsi1_ddr2", + "dsi1_ddr", +}; + struct bcm2835_cprman { struct device *dev; void __iomem *regs; spinlock_t regs_lock; /* spinlock for all clocks */ - const char *osc_name; + + /* + * Real names of cprman clock parents looked up through + * of_clk_get_parent_name(), which will be used in the + * parent_names[] arrays for clock registration. + */ + const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)]; /* Must be last */ struct clk_hw_onecell_data onecell; @@ -317,6 +340,61 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) return readl(cprman->regs + reg); } +/* Does a cycle of measuring a clock through the TCNT clock, which may + * source from many other clocks in the system. + */ +static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman, + u32 tcnt_mux) +{ + u32 osccount = 19200; /* 1ms */ + u32 count; + ktime_t timeout; + + spin_lock(&cprman->regs_lock); + + cprman_write(cprman, CM_TCNTCTL, CM_KILL); + + cprman_write(cprman, CM_TCNTCTL, + (tcnt_mux & CM_SRC_MASK) | + (tcnt_mux >> CM_SRC_BITS) << CM_TCNT_SRC1_SHIFT); + + cprman_write(cprman, CM_OSCCOUNT, osccount); + + /* do a kind delay at the start */ + mdelay(1); + + /* Finish off whatever is left of OSCCOUNT */ + timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); + while (cprman_read(cprman, CM_OSCCOUNT)) { + if (ktime_after(ktime_get(), timeout)) { + dev_err(cprman->dev, "timeout waiting for OSCCOUNT\n"); + count = 0; + goto out; + } + cpu_relax(); + } + + /* Wait for BUSY to clear. */ + timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); + while (cprman_read(cprman, CM_TCNTCTL) & CM_BUSY) { + if (ktime_after(ktime_get(), timeout)) { + dev_err(cprman->dev, "timeout waiting for !BUSY\n"); + count = 0; + goto out; + } + cpu_relax(); + } + + count = cprman_read(cprman, CM_TCNTCNT); + + cprman_write(cprman, CM_TCNTCTL, 0); + +out: + spin_unlock(&cprman->regs_lock); + + return count * 1000; +} + static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base, struct debugfs_reg32 *regs, size_t nregs, struct dentry *dentry) @@ -428,6 +506,7 @@ struct bcm2835_pll_divider_data { u32 load_mask; u32 hold_mask; u32 fixed_divider; + u32 flags; }; struct bcm2835_clock_data { @@ -451,6 +530,8 @@ struct bcm2835_clock_data { bool is_vpu_clock; bool is_mash_clock; + + u32 tcnt_mux; }; struct bcm2835_gate_data { @@ -906,6 +987,9 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, const struct bcm2835_clock_data *data = clock->data; u64 temp; + if (data->int_bits == 0 && data->frac_bits == 0) + return parent_rate; + /* * The divisor is a 12.12 fixed point field, but only some of * the bits are populated in any given clock. @@ -929,7 +1013,12 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct bcm2835_cprman *cprman = clock->cprman; const struct bcm2835_clock_data *data = clock->data; - u32 div = cprman_read(cprman, data->div_reg); + u32 div; + + if (data->int_bits == 0 && data->frac_bits == 0) + return parent_rate; + + div = cprman_read(cprman, data->div_reg); return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); } @@ -978,6 +1067,17 @@ static int bcm2835_clock_on(struct clk_hw *hw) CM_GATE); spin_unlock(&cprman->regs_lock); + /* Debug code to measure the clock once it's turned on to see + * if it's ticking at the rate we expect. + */ + if (data->tcnt_mux && false) { + dev_info(cprman->dev, + "clk %s: rate %ld, measure %ld\n", + data->name, + clk_hw_get_rate(hw), + bcm2835_measure_tcnt_mux(cprman, data->tcnt_mux)); + } + return 0; } @@ -1208,7 +1308,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, memset(&init, 0, sizeof(init)); /* All of the PLLs derive from the external oscillator. */ - init.parent_names = &cprman->osc_name; + init.parent_names = &cprman->real_parent_names[0]; init.num_parents = 1; init.name = data->name; init.ops = &bcm2835_pll_clk_ops; @@ -1252,7 +1352,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, init.num_parents = 1; init.name = divider_name; init.ops = &bcm2835_pll_divider_clk_ops; - init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; + init.flags = data->flags | CLK_IGNORE_UNUSED; divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL); if (!divider) @@ -1294,18 +1394,22 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, struct bcm2835_clock *clock; struct clk_init_data init; const char *parents[1 << CM_SRC_BITS]; - size_t i; + size_t i, j; int ret; /* - * Replace our "xosc" references with the oscillator's - * actual name. + * Replace our strings referencing parent clocks with the + * actual clock-output-name of the parent. */ for (i = 0; i < data->num_mux_parents; i++) { - if (strcmp(data->parents[i], "xosc") == 0) - parents[i] = cprman->osc_name; - else - parents[i] = data->parents[i]; + parents[i] = data->parents[i]; + + for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) { + if (strcmp(parents[i], cprman_parent_names[j]) == 0) { + parents[i] = cprman->real_parent_names[j]; + break; + } + } } memset(&init, 0, sizeof(init)); @@ -1432,6 +1536,47 @@ static const char *const bcm2835_clock_vpu_parents[] = { __VA_ARGS__) /* + * DSI parent clocks. The DSI byte/DDR/DDR2 clocks come from the DSI + * analog PHY. The _inv variants are generated internally to cprman, + * but we don't use them so they aren't hooked up. + */ +static const char *const bcm2835_clock_dsi0_parents[] = { + "gnd", + "xosc", + "testdebug0", + "testdebug1", + "dsi0_ddr", + "dsi0_ddr_inv", + "dsi0_ddr2", + "dsi0_ddr2_inv", + "dsi0_byte", + "dsi0_byte_inv", +}; + +static const char *const bcm2835_clock_dsi1_parents[] = { + "gnd", + "xosc", + "testdebug0", + "testdebug1", + "dsi1_ddr", + "dsi1_ddr_inv", + "dsi1_ddr2", + "dsi1_ddr2_inv", + "dsi1_byte", + "dsi1_byte_inv", +}; + +#define REGISTER_DSI0_CLK(...) REGISTER_CLK( \ + .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents), \ + .parents = bcm2835_clock_dsi0_parents, \ + __VA_ARGS__) + +#define REGISTER_DSI1_CLK(...) REGISTER_CLK( \ + .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents), \ + .parents = bcm2835_clock_dsi1_parents, \ + __VA_ARGS__) + +/* * the real definition of all the pll, pll_dividers and clocks * these make use of the above REGISTER_* macros */ @@ -1466,7 +1611,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLA_CORE, .load_mask = CM_PLLA_LOADCORE, .hold_mask = CM_PLLA_HOLDCORE, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( .name = "plla_per", .source_pll = "plla", @@ -1474,7 +1620,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLA_PER, .load_mask = CM_PLLA_LOADPER, .hold_mask = CM_PLLA_HOLDPER, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( .name = "plla_dsi0", .source_pll = "plla", @@ -1490,7 +1637,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLA_CCP2, .load_mask = CM_PLLA_LOADCCP2, .hold_mask = CM_PLLA_HOLDCCP2, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), /* PLLB is used for the ARM's clock. */ [BCM2835_PLLB] = REGISTER_PLL( @@ -1514,7 +1662,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLB_ARM, .load_mask = CM_PLLB_LOADARM, .hold_mask = CM_PLLB_HOLDARM, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), /* * PLLC is the core PLL, used to drive the core VPU clock. @@ -1543,7 +1692,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLC_CORE0, .load_mask = CM_PLLC_LOADCORE0, .hold_mask = CM_PLLC_HOLDCORE0, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV( .name = "pllc_core1", .source_pll = "pllc", @@ -1551,7 +1701,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLC_CORE1, .load_mask = CM_PLLC_LOADCORE1, .hold_mask = CM_PLLC_HOLDCORE1, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV( .name = "pllc_core2", .source_pll = "pllc", @@ -1559,7 +1710,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLC_CORE2, .load_mask = CM_PLLC_LOADCORE2, .hold_mask = CM_PLLC_HOLDCORE2, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLC_PER] = REGISTER_PLL_DIV( .name = "pllc_per", .source_pll = "pllc", @@ -1567,7 +1719,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLC_PER, .load_mask = CM_PLLC_LOADPER, .hold_mask = CM_PLLC_HOLDPER, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), /* * PLLD is the display PLL, used to drive DSI display panels. @@ -1596,7 +1749,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLD_CORE, .load_mask = CM_PLLD_LOADCORE, .hold_mask = CM_PLLD_HOLDCORE, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLD_PER] = REGISTER_PLL_DIV( .name = "plld_per", .source_pll = "plld", @@ -1604,7 +1758,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLD_PER, .load_mask = CM_PLLD_LOADPER, .hold_mask = CM_PLLD_HOLDPER, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV( .name = "plld_dsi0", .source_pll = "plld", @@ -1649,7 +1804,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLH_RCAL, .load_mask = CM_PLLH_LOADRCAL, .hold_mask = 0, - .fixed_divider = 10), + .fixed_divider = 10, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV( .name = "pllh_aux", .source_pll = "pllh", @@ -1657,7 +1813,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLH_AUX, .load_mask = CM_PLLH_LOADAUX, .hold_mask = 0, - .fixed_divider = 1), + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( .name = "pllh_pix", .source_pll = "pllh", @@ -1665,7 +1822,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .a2w_reg = A2W_PLLH_PIX, .load_mask = CM_PLLH_LOADPIX, .hold_mask = 0, - .fixed_divider = 10), + .fixed_divider = 10, + .flags = CLK_SET_RATE_PARENT), /* the clocks */ @@ -1677,7 +1835,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_OTPCTL, .div_reg = CM_OTPDIV, .int_bits = 4, - .frac_bits = 0), + .frac_bits = 0, + .tcnt_mux = 6), /* * Used for a 1Mhz clock for the system clocksource, and also used * bythe watchdog timer and the camera pulse generator. @@ -1711,13 +1870,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_H264CTL, .div_reg = CM_H264DIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 1), [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK( .name = "isp", .ctl_reg = CM_ISPCTL, .div_reg = CM_ISPDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 2), /* * Secondary SDRAM clock. Used for low-voltage modes when the PLL @@ -1728,13 +1889,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_SDCCTL, .div_reg = CM_SDCDIV, .int_bits = 6, - .frac_bits = 0), + .frac_bits = 0, + .tcnt_mux = 3), [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( .name = "v3d", .ctl_reg = CM_V3DCTL, .div_reg = CM_V3DDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 4), /* * VPU clock. This doesn't have an enable bit, since it drives * the bus for everything else, and is special so it doesn't need @@ -1748,7 +1911,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .int_bits = 12, .frac_bits = 8, .flags = CLK_IS_CRITICAL, - .is_vpu_clock = true), + .is_vpu_clock = true, + .tcnt_mux = 5), /* clocks with per parent mux */ [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK( @@ -1756,19 +1920,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_AVEOCTL, .div_reg = CM_AVEODIV, .int_bits = 4, - .frac_bits = 0), + .frac_bits = 0, + .tcnt_mux = 38), [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK( .name = "cam0", .ctl_reg = CM_CAM0CTL, .div_reg = CM_CAM0DIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 14), [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK( .name = "cam1", .ctl_reg = CM_CAM1CTL, .div_reg = CM_CAM1DIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 15), [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK( .name = "dft", .ctl_reg = CM_DFTCTL, @@ -1780,7 +1947,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_DPICTL, .div_reg = CM_DPIDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 17), /* Arasan EMMC clock */ [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( @@ -1788,7 +1956,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_EMMCCTL, .div_reg = CM_EMMCDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 39), /* General purpose (GPIO) clocks */ [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK( @@ -1797,7 +1966,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_GP0DIV, .int_bits = 12, .frac_bits = 12, - .is_mash_clock = true), + .is_mash_clock = true, + .tcnt_mux = 20), [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK( .name = "gp1", .ctl_reg = CM_GP1CTL, @@ -1805,7 +1975,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .int_bits = 12, .frac_bits = 12, .flags = CLK_IS_CRITICAL, - .is_mash_clock = true), + .is_mash_clock = true, + .tcnt_mux = 21), [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( .name = "gp2", .ctl_reg = CM_GP2CTL, @@ -1820,40 +1991,46 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_HSMCTL, .div_reg = CM_HSMDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 22), [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK( .name = "pcm", .ctl_reg = CM_PCMCTL, .div_reg = CM_PCMDIV, .int_bits = 12, .frac_bits = 12, - .is_mash_clock = true), + .is_mash_clock = true, + .tcnt_mux = 23), [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( .name = "pwm", .ctl_reg = CM_PWMCTL, .div_reg = CM_PWMDIV, .int_bits = 12, .frac_bits = 12, - .is_mash_clock = true), + .is_mash_clock = true, + .tcnt_mux = 24), [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK( .name = "slim", .ctl_reg = CM_SLIMCTL, .div_reg = CM_SLIMDIV, .int_bits = 12, .frac_bits = 12, - .is_mash_clock = true), + .is_mash_clock = true, + .tcnt_mux = 25), [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK( .name = "smi", .ctl_reg = CM_SMICTL, .div_reg = CM_SMIDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 27), [BCM2835_CLOCK_UART] = REGISTER_PER_CLK( .name = "uart", .ctl_reg = CM_UARTCTL, .div_reg = CM_UARTDIV, .int_bits = 10, - .frac_bits = 12), + .frac_bits = 12, + .tcnt_mux = 28), /* TV encoder clock. Only operating frequency is 108Mhz. */ [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( @@ -1866,7 +2043,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { * Allow rate change propagation only on PLLH_AUX which is * assigned index 7 in the parent array. */ - .set_rate_parent = BIT(7)), + .set_rate_parent = BIT(7), + .tcnt_mux = 29), /* dsi clocks */ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( @@ -1874,13 +2052,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_DSI0ECTL, .div_reg = CM_DSI0EDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 18), [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK( .name = "dsi1e", .ctl_reg = CM_DSI1ECTL, .div_reg = CM_DSI1EDIV, .int_bits = 4, - .frac_bits = 8), + .frac_bits = 8, + .tcnt_mux = 19), + [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( + .name = "dsi0p", + .ctl_reg = CM_DSI0PCTL, + .div_reg = CM_DSI0PDIV, + .int_bits = 0, + .frac_bits = 0, + .tcnt_mux = 12), + [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( + .name = "dsi1p", + .ctl_reg = CM_DSI1PCTL, + .div_reg = CM_DSI1PDIV, + .int_bits = 0, + .frac_bits = 0, + .tcnt_mux = 13), /* the gates */ @@ -1939,8 +2133,19 @@ static int bcm2835_clk_probe(struct platform_device *pdev) if (IS_ERR(cprman->regs)) return PTR_ERR(cprman->regs); - cprman->osc_name = of_clk_get_parent_name(dev->of_node, 0); - if (!cprman->osc_name) + memcpy(cprman->real_parent_names, cprman_parent_names, + sizeof(cprman_parent_names)); + of_clk_parent_fill(dev->of_node, cprman->real_parent_names, + ARRAY_SIZE(cprman_parent_names)); + + /* + * Make sure the external oscillator has been registered. + * + * The other (DSI) clocks are not present on older device + * trees, which we still need to support for backwards + * compatibility. + */ + if (!cprman->real_parent_names[0]) return -ENODEV; platform_set_drvdata(pdev, cprman); diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index f793b2d9238c..c933be01c7db 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -1,8 +1,8 @@ /* - * Driver for TI Dual PLL CDCE925 clock synthesizer + * Driver for TI Multi PLL CDCE913/925/937/949 clock synthesizer * - * This driver always connects the Y1 to the input clock, Y2/Y3 to PLL1 - * and Y4/Y5 to PLL2. PLL frequency is set on a first-come-first-serve + * This driver always connects the Y1 to the input clock, Y2/Y3 to PLL1, + * Y4/Y5 to PLL2, and so on. PLL frequency is set on a first-come-first-serve * basis. Clients can directly request any frequency that the chip can * deliver using the standard clk framework. In addition, the device can * be configured and activated via the devicetree. @@ -19,11 +19,32 @@ #include <linux/slab.h> #include <linux/gcd.h> -/* The chip has 2 PLLs which can be routed through dividers to 5 outputs. +/* Each chip has different number of PLLs and outputs, for example: + * The CECE925 has 2 PLLs which can be routed through dividers to 5 outputs. * Model this as 2 PLL clocks which are parents to the outputs. */ -#define NUMBER_OF_PLLS 2 -#define NUMBER_OF_OUTPUTS 5 + +enum { + CDCE913, + CDCE925, + CDCE937, + CDCE949, +}; + +struct clk_cdce925_chip_info { + int num_plls; + int num_outputs; +}; + +static const struct clk_cdce925_chip_info clk_cdce925_chip_info_tbl[] = { + [CDCE913] = { .num_plls = 1, .num_outputs = 3 }, + [CDCE925] = { .num_plls = 2, .num_outputs = 5 }, + [CDCE937] = { .num_plls = 3, .num_outputs = 7 }, + [CDCE949] = { .num_plls = 4, .num_outputs = 9 }, +}; + +#define MAX_NUMBER_OF_PLLS 4 +#define MAX_NUMBER_OF_OUTPUTS 9 #define CDCE925_REG_GLOBAL1 0x01 #define CDCE925_REG_Y1SPIPDIVH 0x02 @@ -43,7 +64,7 @@ struct clk_cdce925_output { struct clk_hw hw; struct clk_cdce925_chip *chip; u8 index; - u16 pdiv; /* 1..127 for Y2-Y5; 1..1023 for Y1 */ + u16 pdiv; /* 1..127 for Y2-Y9; 1..1023 for Y1 */ }; #define to_clk_cdce925_output(_hw) \ container_of(_hw, struct clk_cdce925_output, hw) @@ -60,8 +81,9 @@ struct clk_cdce925_pll { struct clk_cdce925_chip { struct regmap *regmap; struct i2c_client *i2c_client; - struct clk_cdce925_pll pll[NUMBER_OF_PLLS]; - struct clk_cdce925_output clk[NUMBER_OF_OUTPUTS]; + const struct clk_cdce925_chip_info *chip_info; + struct clk_cdce925_pll pll[MAX_NUMBER_OF_PLLS]; + struct clk_cdce925_output clk[MAX_NUMBER_OF_OUTPUTS]; }; /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ @@ -284,6 +306,18 @@ static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv) case 4: regmap_update_bits(data->chip->regmap, 0x27, 0x7F, pdiv); break; + case 5: + regmap_update_bits(data->chip->regmap, 0x36, 0x7F, pdiv); + break; + case 6: + regmap_update_bits(data->chip->regmap, 0x37, 0x7F, pdiv); + break; + case 7: + regmap_update_bits(data->chip->regmap, 0x46, 0x7F, pdiv); + break; + case 8: + regmap_update_bits(data->chip->regmap, 0x47, 0x7F, pdiv); + break; } } @@ -302,6 +336,14 @@ static void cdce925_clk_activate(struct clk_cdce925_output *data) case 4: regmap_update_bits(data->chip->regmap, 0x24, 0x03, 0x03); break; + case 5: + case 6: + regmap_update_bits(data->chip->regmap, 0x34, 0x03, 0x03); + break; + case 7: + case 8: + regmap_update_bits(data->chip->regmap, 0x44, 0x03, 0x03); + break; } } @@ -474,15 +516,6 @@ static const struct clk_ops cdce925_clk_y1_ops = { .set_rate = cdce925_clk_y1_set_rate, }; - -static struct regmap_config cdce925_regmap_config = { - .name = "configuration0", - .reg_bits = 8, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, - .max_register = 0x2F, -}; - #define CDCE925_I2C_COMMAND_BLOCK_TRANSFER 0x00 #define CDCE925_I2C_COMMAND_BYTE_TRANSFER 0x80 @@ -582,13 +615,19 @@ static int cdce925_probe(struct i2c_client *client, struct clk_cdce925_chip *data; struct device_node *node = client->dev.of_node; const char *parent_name; - const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,}; + const char *pll_clk_name[MAX_NUMBER_OF_PLLS] = {NULL,}; struct clk_init_data init; u32 value; int i; int err; struct device_node *np_output; char child_name[6]; + struct regmap_config config = { + .name = "configuration0", + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + }; dev_dbg(&client->dev, "%s\n", __func__); data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); @@ -596,8 +635,11 @@ static int cdce925_probe(struct i2c_client *client, return -ENOMEM; data->i2c_client = client; + data->chip_info = &clk_cdce925_chip_info_tbl[id->driver_data]; + config.max_register = CDCE925_OFFSET_PLL + + data->chip_info->num_plls * 0x10 - 1; data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus, - &client->dev, &cdce925_regmap_config); + &client->dev, &config); if (IS_ERR(data->regmap)) { dev_err(&client->dev, "failed to allocate register map\n"); return PTR_ERR(data->regmap); @@ -626,7 +668,7 @@ static int cdce925_probe(struct i2c_client *client, init.num_parents = parent_name ? 1 : 0; /* Register PLL clocks */ - for (i = 0; i < NUMBER_OF_PLLS; ++i) { + for (i = 0; i < data->chip_info->num_plls; ++i) { pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d", client->dev.of_node->name, i); init.name = pll_clk_name[i]; @@ -684,7 +726,7 @@ static int cdce925_probe(struct i2c_client *client, init.ops = &cdce925_clk_ops; init.flags = CLK_SET_RATE_PARENT; init.num_parents = 1; - for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) { + for (i = 1; i < data->chip_info->num_outputs; ++i) { init.name = kasprintf(GFP_KERNEL, "%s.Y%d", client->dev.of_node->name, i+1); data->clk[i].chip = data; @@ -702,6 +744,16 @@ static int cdce925_probe(struct i2c_client *client, /* Mux Y4/5 to PLL2 */ init.parent_names = &pll_clk_name[1]; break; + case 5: + case 6: + /* Mux Y6/7 to PLL3 */ + init.parent_names = &pll_clk_name[2]; + break; + case 7: + case 8: + /* Mux Y8/9 to PLL4 */ + init.parent_names = &pll_clk_name[3]; + break; } err = devm_clk_hw_register(&client->dev, &data->clk[i].hw); kfree(init.name); /* clock framework made a copy of the name */ @@ -720,7 +772,7 @@ static int cdce925_probe(struct i2c_client *client, err = 0; error: - for (i = 0; i < NUMBER_OF_PLLS; ++i) + for (i = 0; i < data->chip_info->num_plls; ++i) /* clock framework made a copy of the name */ kfree(pll_clk_name[i]); @@ -728,13 +780,19 @@ error: } static const struct i2c_device_id cdce925_id[] = { - { "cdce925", 0 }, + { "cdce913", CDCE913 }, + { "cdce925", CDCE925 }, + { "cdce937", CDCE937 }, + { "cdce949", CDCE949 }, { } }; MODULE_DEVICE_TABLE(i2c, cdce925_id); static const struct of_device_id clk_cdce925_of_match[] = { + { .compatible = "ti,cdce913" }, { .compatible = "ti,cdce925" }, + { .compatible = "ti,cdce937" }, + { .compatible = "ti,cdce949" }, { }, }; MODULE_DEVICE_TABLE(of, clk_cdce925_of_match); @@ -750,5 +808,5 @@ static struct i2c_driver cdce925_driver = { module_i2c_driver(cdce925_driver); MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); -MODULE_DESCRIPTION("cdce925 driver"); +MODULE_DESCRIPTION("TI CDCE913/925/937/949 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 674785d968a3..e0e02a6e5900 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -40,8 +40,9 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) return 0; pclk = of_clk_get_from_provider(&clkspec); if (IS_ERR(pclk)) { - pr_warn("clk: couldn't get parent clock %d for %s\n", - index, node->full_name); + if (PTR_ERR(pclk) != -EPROBE_DEFER) + pr_warn("clk: couldn't get parent clock %d for %s\n", + index, node->full_name); return PTR_ERR(pclk); } @@ -55,8 +56,9 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) } clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { - pr_warn("clk: couldn't get assigned clock %d for %s\n", - index, node->full_name); + if (PTR_ERR(clk) != -EPROBE_DEFER) + pr_warn("clk: couldn't get assigned clock %d for %s\n", + index, node->full_name); rc = PTR_ERR(clk); goto err; } @@ -99,8 +101,9 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { - pr_warn("clk: couldn't get clock %d for %s\n", - index, node->full_name); + if (PTR_ERR(clk) != -EPROBE_DEFER) + pr_warn("clk: couldn't get clock %d for %s\n", + index, node->full_name); return PTR_ERR(clk); } diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 021f3daf34e1..3fca0526d940 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -59,6 +59,10 @@ struct cs2000_priv { struct i2c_client *client; struct clk *clk_in; struct clk *ref_clk; + + /* suspend/resume */ + unsigned long saved_rate; + unsigned long saved_parent_rate; }; static const struct of_device_id cs2000_of_match[] = { @@ -286,6 +290,9 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, if (ret < 0) return ret; + priv->saved_rate = rate; + priv->saved_parent_rate = parent_rate; + return 0; } @@ -489,9 +496,24 @@ probe_err: return ret; } +static int cs2000_resume(struct device *dev) +{ + struct cs2000_priv *priv = dev_get_drvdata(dev); + int ch = 0; /* it uses ch0 only at this point */ + + return __cs2000_set_rate(priv, ch, + priv->saved_rate, + priv->saved_parent_rate); +} + +static const struct dev_pm_ops cs2000_pm_ops = { + .resume_early = cs2000_resume, +}; + static struct i2c_driver cs2000_driver = { .driver = { .name = "cs2000-cp", + .pm = &cs2000_pm_ops, .of_match_table = cs2000_of_match, }, .probe = cs2000_probe, diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 2a3e9d8e88b0..96d37175d0ad 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -290,13 +290,15 @@ static int scpi_clocks_probe(struct platform_device *pdev) of_node_put(child); return ret; } - } - /* Add the virtual cpufreq device */ - cpufreq_dev = platform_device_register_simple("scpi-cpufreq", - -1, NULL, 0); - if (IS_ERR(cpufreq_dev)) - pr_warn("unable to register cpufreq device"); + if (match->data != &scpi_dvfs_ops) + continue; + /* Add the virtual cpufreq device if it's DVFS clock provider */ + cpufreq_dev = platform_device_register_simple("scpi-cpufreq", + -1, NULL, 0); + if (IS_ERR(cpufreq_dev)) + pr_warn("unable to register cpufreq device"); + } return 0; } diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 5eb05dbf59b8..ab609a76706f 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -28,6 +28,14 @@ #include <linux/regmap.h> #include <linux/mfd/syscon.h> +/* + * Include list of clocks wich are not derived from system clock (SYSCLOCK) + * The index of these clocks is the secondary index of DT bindings + * + */ +#include <dt-bindings/clock/stm32fx-clock.h> + +#define STM32F4_RCC_CR 0x00 #define STM32F4_RCC_PLLCFGR 0x04 #define STM32F4_RCC_CFGR 0x08 #define STM32F4_RCC_AHB1ENR 0x30 @@ -37,6 +45,15 @@ #define STM32F4_RCC_APB2ENR 0x44 #define STM32F4_RCC_BDCR 0x70 #define STM32F4_RCC_CSR 0x74 +#define STM32F4_RCC_PLLI2SCFGR 0x84 +#define STM32F4_RCC_PLLSAICFGR 0x88 +#define STM32F4_RCC_DCKCFGR 0x8c +#define STM32F7_RCC_DCKCFGR2 0x90 + +#define NONE -1 +#define NO_IDX NONE +#define NO_MUX NONE +#define NO_GATE NONE struct stm32f4_gate_data { u8 offset; @@ -195,7 +212,7 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { { 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, "sdio", "pll48" }, + { STM32F4_RCC_APB2ENR, 11, "sdio", "sdmux" }, { STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" }, { STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" }, @@ -208,7 +225,79 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; -enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK }; +static const struct stm32f4_gate_data stm32f746_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, 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, 11, "wwdg", "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, 8, "adc1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 11, "sdmmc", "sdmux" }, + { 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" }, +}; /* * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx @@ -224,6 +313,10 @@ static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, 0x0000000000000003ull, 0x0c777f33f6fec9ffull }; +static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, + 0x0000000000000003ull, + 0x04f77f033e01c9ffull }; + static const u64 *stm32f4_gate_map; static struct clk_hw **clks; @@ -233,6 +326,8 @@ static void __iomem *base; static struct regmap *pdrm; +static int stm32fx_end_primary_clk; + /* * "Multiplier" device for APBx clocks. * @@ -324,23 +419,342 @@ static struct clk *clk_register_apb_mul(struct device *dev, const char *name, return clk; } -/* - * Decode current PLL state and (statically) model the state we inherit from - * the bootloader. - */ -static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk) +enum { + PLL, + PLL_I2S, + PLL_SAI, +}; + +static const struct clk_div_table pll_divp_table[] = { + { 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 } +}; + +static const struct clk_div_table pll_divr_table[] = { + { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 } +}; + +struct stm32f4_pll { + spinlock_t *lock; + struct clk_gate gate; + u8 offset; + u8 bit_rdy_idx; + u8 status; + u8 n_start; +}; + +#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate) + +struct stm32f4_pll_post_div_data { + int idx; + u8 pll_num; + const char *name; + const char *parent; + u8 flag; + u8 offset; + u8 shift; + u8 width; + u8 flag_div; + const struct clk_div_table *div_table; +}; + +struct stm32f4_vco_data { + const char *vco_name; + u8 offset; + u8 bit_idx; + u8 bit_rdy_idx; +}; + +static const struct stm32f4_vco_data vco_data[] = { + { "vco", STM32F4_RCC_PLLCFGR, 24, 25 }, + { "vco-i2s", STM32F4_RCC_PLLI2SCFGR, 26, 27 }, + { "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 }, +}; + + +static const struct clk_div_table post_divr_table[] = { + { 0, 2 }, { 1, 4 }, { 2, 8 }, { 3, 16 }, { 0 } +}; + +#define MAX_POST_DIV 3 +static const struct stm32f4_pll_post_div_data post_div_data[MAX_POST_DIV] = { + { CLK_I2SQ_PDIV, PLL_I2S, "plli2s-q-div", "plli2s-q", + CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL}, + + { CLK_SAIQ_PDIV, PLL_SAI, "pllsai-q-div", "pllsai-q", + CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL }, + + { NO_IDX, PLL_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT, + STM32F4_RCC_DCKCFGR, 16, 2, 0, post_divr_table }, +}; + +struct stm32f4_div_data { + u8 shift; + u8 width; + u8 flag_div; + const struct clk_div_table *div_table; +}; + +#define MAX_PLL_DIV 3 +static const struct stm32f4_div_data div_data[MAX_PLL_DIV] = { + { 16, 2, 0, pll_divp_table }, + { 24, 4, CLK_DIVIDER_ONE_BASED, NULL }, + { 28, 3, 0, pll_divr_table }, +}; + +struct stm32f4_pll_data { + u8 pll_num; + u8 n_start; + const char *div_name[MAX_PLL_DIV]; +}; + +static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = { + { PLL, 192, { "pll", "pll48", NULL } }, + { PLL_I2S, 192, { NULL, "plli2s-q", "plli2s-r" } }, + { PLL_SAI, 49, { NULL, "pllsai-q", "pllsai-r" } }, +}; + +static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = { + { PLL, 50, { "pll", "pll-q", NULL } }, + { PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } }, + { PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } }, +}; + +static int stm32f4_pll_is_enabled(struct clk_hw *hw) +{ + return clk_gate_ops.is_enabled(hw); +} + +static int stm32f4_pll_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32f4_pll *pll = to_stm32f4_pll(gate); + int ret = 0; + unsigned long reg; + + ret = clk_gate_ops.enable(hw); + + ret = readl_relaxed_poll_timeout_atomic(base + STM32F4_RCC_CR, reg, + reg & (1 << pll->bit_rdy_idx), 0, 10000); + + return ret; +} + +static void stm32f4_pll_disable(struct clk_hw *hw) +{ + clk_gate_ops.disable(hw); +} + +static unsigned long stm32f4_pll_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32f4_pll *pll = to_stm32f4_pll(gate); + unsigned long n; + + n = (readl(base + pll->offset) >> 6) & 0x1ff; + + return parent_rate * n; +} + +static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32f4_pll *pll = to_stm32f4_pll(gate); + unsigned long n; + + n = rate / *prate; + + if (n < pll->n_start) + n = pll->n_start; + else if (n > 432) + n = 432; + + return *prate * n; +} + +static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32f4_pll *pll = to_stm32f4_pll(gate); + + unsigned long n; + unsigned long val; + int pll_state; + + pll_state = stm32f4_pll_is_enabled(hw); + + if (pll_state) + stm32f4_pll_disable(hw); + + n = rate / parent_rate; + + val = readl(base + pll->offset) & ~(0x1ff << 6); + + writel(val | ((n & 0x1ff) << 6), base + pll->offset); + + if (pll_state) + stm32f4_pll_enable(hw); + + return 0; +} + +static const struct clk_ops stm32f4_pll_gate_ops = { + .enable = stm32f4_pll_enable, + .disable = stm32f4_pll_disable, + .is_enabled = stm32f4_pll_is_enabled, + .recalc_rate = stm32f4_pll_recalc, + .round_rate = stm32f4_pll_round_rate, + .set_rate = stm32f4_pll_set_rate, +}; + +struct stm32f4_pll_div { + struct clk_divider div; + struct clk_hw *hw_pll; +}; + +#define to_pll_div_clk(_div) container_of(_div, struct stm32f4_pll_div, div) + +static unsigned long stm32f4_pll_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return clk_divider_ops.recalc_rate(hw, parent_rate); +} + +static long stm32f4_pll_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return clk_divider_ops.round_rate(hw, rate, prate); +} + +static int stm32f4_pll_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - unsigned long pllcfgr = readl(base + STM32F4_RCC_PLLCFGR); + int pll_state, ret; + + struct clk_divider *div = to_clk_divider(hw); + struct stm32f4_pll_div *pll_div = to_pll_div_clk(div); + + pll_state = stm32f4_pll_is_enabled(pll_div->hw_pll); + + if (pll_state) + stm32f4_pll_disable(pll_div->hw_pll); + + ret = clk_divider_ops.set_rate(hw, rate, parent_rate); - unsigned long pllm = pllcfgr & 0x3f; - unsigned long plln = (pllcfgr >> 6) & 0x1ff; - unsigned long pllp = BIT(((pllcfgr >> 16) & 3) + 1); - const char *pllsrc = pllcfgr & BIT(22) ? hse_clk : hsi_clk; - unsigned long pllq = (pllcfgr >> 24) & 0xf; + if (pll_state) + stm32f4_pll_enable(pll_div->hw_pll); - clk_register_fixed_factor(NULL, "vco", pllsrc, 0, plln, pllm); - clk_register_fixed_factor(NULL, "pll", "vco", 0, 1, pllp); - clk_register_fixed_factor(NULL, "pll48", "vco", 0, 1, pllq); + return ret; +} + +static const struct clk_ops stm32f4_pll_div_ops = { + .recalc_rate = stm32f4_pll_div_recalc_rate, + .round_rate = stm32f4_pll_div_round_rate, + .set_rate = stm32f4_pll_div_set_rate, +}; + +static struct clk_hw *clk_register_pll_div(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, + struct clk_hw *pll_hw, spinlock_t *lock) +{ + struct stm32f4_pll_div *pll_div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + /* allocate the divider */ + pll_div = kzalloc(sizeof(*pll_div), GFP_KERNEL); + if (!pll_div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &stm32f4_pll_div_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_divider assignments */ + pll_div->div.reg = reg; + pll_div->div.shift = shift; + pll_div->div.width = width; + pll_div->div.flags = clk_divider_flags; + pll_div->div.lock = lock; + pll_div->div.table = table; + pll_div->div.hw.init = &init; + + pll_div->hw_pll = pll_hw; + + /* register the clock */ + hw = &pll_div->div.hw; + ret = clk_hw_register(NULL, hw); + if (ret) { + kfree(pll_div); + hw = ERR_PTR(ret); + } + + return hw; +} + +static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc, + const struct stm32f4_pll_data *data, spinlock_t *lock) +{ + struct stm32f4_pll *pll; + struct clk_init_data init = { NULL }; + void __iomem *reg; + struct clk_hw *pll_hw; + int ret; + int i; + const struct stm32f4_vco_data *vco; + + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + vco = &vco_data[data->pll_num]; + + init.name = vco->vco_name; + init.ops = &stm32f4_pll_gate_ops; + init.flags = CLK_SET_RATE_GATE; + init.parent_names = &pllsrc; + init.num_parents = 1; + + pll->gate.lock = lock; + pll->gate.reg = base + STM32F4_RCC_CR; + pll->gate.bit_idx = vco->bit_idx; + pll->gate.hw.init = &init; + + pll->offset = vco->offset; + pll->n_start = data->n_start; + pll->bit_rdy_idx = vco->bit_rdy_idx; + pll->status = (readl(base + STM32F4_RCC_CR) >> vco->bit_idx) & 0x1; + + reg = base + pll->offset; + + pll_hw = &pll->gate.hw; + ret = clk_hw_register(NULL, pll_hw); + if (ret) { + kfree(pll); + return ERR_PTR(ret); + } + + for (i = 0; i < MAX_PLL_DIV; i++) + if (data->div_name[i]) + clk_register_pll_div(data->div_name[i], + vco->vco_name, + 0, + reg, + div_data[i].shift, + div_data[i].width, + div_data[i].flag_div, + div_data[i].div_table, + pll_hw, + lock); + return pll_hw; } /* @@ -352,7 +766,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) u64 table[MAX_GATE_MAP]; if (primary == 1) { - if (WARN_ON(secondary >= END_PRIMARY_CLK)) + if (WARN_ON(secondary >= stm32fx_end_primary_clk)) return -EINVAL; return secondary; } @@ -369,7 +783,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) table[BIT_ULL_WORD(secondary)] &= GENMASK_ULL(secondary % BITS_PER_LONG_LONG, 0); - return END_PRIMARY_CLK - 1 + hweight64(table[0]) + + return stm32fx_end_primary_clk - 1 + hweight64(table[0]) + (BIT_ULL_WORD(secondary) >= 1 ? hweight64(table[1]) : 0) + (BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0); } @@ -611,22 +1025,291 @@ static const char *rtc_parents[4] = { "no-clock", "lse", "lsi", "hse-rtc" }; +static const char *lcd_parent[1] = { "pllsai-r-div" }; + +static const char *i2s_parents[2] = { "plli2s-r", NULL }; + +static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL, + "no-clock" }; + +static const char *pll48_parents[2] = { "pll-q", "pllsai-p" }; + +static const char *sdmux_parents[2] = { "pll48", "sys" }; + +static const char *hdmi_parents[2] = { "lse", "hsi_div488" }; + +static const char *spdif_parent[1] = { "plli2s-p" }; + +static const char *lptim_parent[4] = { "apb1_mul", "lsi", "hsi", "lse" }; + +static const char *uart_parents1[4] = { "apb2_div", "sys", "hsi", "lse" }; +static const char *uart_parents2[4] = { "apb1_div", "sys", "hsi", "lse" }; + +static const char *i2c_parents[4] = { "apb1_div", "sys", "hsi", "no-clock" }; + +struct stm32_aux_clk { + int idx; + const char *name; + const char * const *parent_names; + int num_parents; + int offset_mux; + u8 shift; + u8 mask; + int offset_gate; + u8 bit_idx; + unsigned long flags; +}; + struct stm32f4_clk_data { const struct stm32f4_gate_data *gates_data; const u64 *gates_map; int gates_num; + const struct stm32f4_pll_data *pll_data; + const struct stm32_aux_clk *aux_clk; + int aux_clk_num; + int end_primary; +}; + +static const struct stm32_aux_clk stm32f429_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-a", sai_parents, ARRAY_SIZE(sai_parents), + STM32F4_RCC_DCKCFGR, 20, 3, + STM32F4_RCC_APB2ENR, 22, + CLK_SET_RATE_PARENT + }, + { + CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents), + STM32F4_RCC_DCKCFGR, 22, 3, + STM32F4_RCC_APB2ENR, 22, + CLK_SET_RATE_PARENT + }, +}; + +static const struct stm32_aux_clk stm32f469_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-a", sai_parents, ARRAY_SIZE(sai_parents), + STM32F4_RCC_DCKCFGR, 20, 3, + STM32F4_RCC_APB2ENR, 22, + CLK_SET_RATE_PARENT + }, + { + CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents), + STM32F4_RCC_DCKCFGR, 22, 3, + STM32F4_RCC_APB2ENR, 22, + CLK_SET_RATE_PARENT + }, + { + NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents), + STM32F4_RCC_DCKCFGR, 27, 1, + NO_GATE, 0, + 0 + }, + { + NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents), + STM32F4_RCC_DCKCFGR, 28, 1, + NO_GATE, 0, + 0 + }, +}; + +static const struct stm32_aux_clk stm32f746_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, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents), + STM32F7_RCC_DCKCFGR2, 28, 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 + }, }; static const struct stm32f4_clk_data stm32f429_clk_data = { + .end_primary = END_PRIMARY_CLK, .gates_data = stm32f429_gates, .gates_map = stm32f42xx_gate_map, .gates_num = ARRAY_SIZE(stm32f429_gates), + .pll_data = stm32f429_pll, + .aux_clk = stm32f429_aux_clk, + .aux_clk_num = ARRAY_SIZE(stm32f429_aux_clk), }; static const struct stm32f4_clk_data stm32f469_clk_data = { + .end_primary = END_PRIMARY_CLK, .gates_data = stm32f469_gates, .gates_map = stm32f46xx_gate_map, .gates_num = ARRAY_SIZE(stm32f469_gates), + .pll_data = stm32f469_pll, + .aux_clk = stm32f469_aux_clk, + .aux_clk_num = ARRAY_SIZE(stm32f469_aux_clk), +}; + +static const struct stm32f4_clk_data stm32f746_clk_data = { + .end_primary = END_PRIMARY_CLK_F7, + .gates_data = stm32f746_gates, + .gates_map = stm32f746_gate_map, + .gates_num = ARRAY_SIZE(stm32f746_gates), + .pll_data = stm32f469_pll, + .aux_clk = stm32f746_aux_clk, + .aux_clk_num = ARRAY_SIZE(stm32f746_aux_clk), }; static const struct of_device_id stm32f4_of_match[] = { @@ -638,15 +1321,84 @@ static const struct of_device_id stm32f4_of_match[] = { .compatible = "st,stm32f469-rcc", .data = &stm32f469_clk_data }, + { + .compatible = "st,stm32f746-rcc", + .data = &stm32f746_clk_data + }, {} }; +static struct clk_hw *stm32_register_aux_clk(const char *name, + const char * const *parent_names, int num_parents, + int offset_mux, u8 shift, u8 mask, + int offset_gate, u8 bit_idx, + unsigned long flags, spinlock_t *lock) +{ + struct clk_hw *hw; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *mux_hw = NULL, *gate_hw = NULL; + const struct clk_ops *mux_ops = NULL, *gate_ops = NULL; + + if (offset_gate != NO_GATE) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + hw = ERR_PTR(-EINVAL); + goto fail; + } + + gate->reg = base + offset_gate; + gate->bit_idx = bit_idx; + gate->flags = 0; + gate->lock = lock; + gate_hw = &gate->hw; + gate_ops = &clk_gate_ops; + } + + if (offset_mux != NO_MUX) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) { + hw = ERR_PTR(-EINVAL); + goto fail; + } + + mux->reg = base + offset_mux; + mux->shift = shift; + mux->mask = mask; + mux->flags = 0; + mux_hw = &mux->hw; + mux_ops = &clk_mux_ops; + } + + if (mux_hw == NULL && gate_hw == NULL) { + hw = ERR_PTR(-EINVAL); + goto fail; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, mux_ops, + NULL, NULL, + gate_hw, gate_ops, + flags); + +fail: + if (IS_ERR(hw)) { + kfree(gate); + kfree(mux); + } + + return hw; +} + static void __init stm32f4_rcc_init(struct device_node *np) { - const char *hse_clk; + const char *hse_clk, *i2s_in_clk; int n; const struct of_device_id *match; const struct stm32f4_clk_data *data; + unsigned long pllcfgr; + const char *pllsrc; + unsigned long pllm; base = of_iomap(np, 0); if (!base) { @@ -666,7 +1418,9 @@ static void __init stm32f4_rcc_init(struct device_node *np) data = match->data; - clks = kmalloc_array(data->gates_num + END_PRIMARY_CLK, + stm32fx_end_primary_clk = data->end_primary; + + clks = kmalloc_array(data->gates_num + stm32fx_end_primary_clk, sizeof(*clks), GFP_KERNEL); if (!clks) goto fail; @@ -675,12 +1429,54 @@ static void __init stm32f4_rcc_init(struct device_node *np) hse_clk = of_clk_get_parent_name(np, 0); - clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0, - 16000000, 160000); - stm32f4_rcc_register_pll(hse_clk, "hsi"); + i2s_in_clk = of_clk_get_parent_name(np, 1); + + i2s_parents[1] = i2s_in_clk; + sai_parents[2] = i2s_in_clk; + + 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; + + clk_hw_register_fixed_factor(NULL, "vco_in", pllsrc, + 0, 1, pllm); + + stm32f4_rcc_register_pll("vco_in", &data->pll_data[0], + &stm32f4_clk_lock); + + clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in", + &data->pll_data[1], &stm32f4_clk_lock); + + clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in", + &data->pll_data[2], &stm32f4_clk_lock); + + for (n = 0; n < MAX_POST_DIV; n++) { + const struct stm32f4_pll_post_div_data *post_div; + struct clk_hw *hw; + + post_div = &post_div_data[n]; + + hw = clk_register_pll_div(post_div->name, + post_div->parent, + post_div->flag, + base + post_div->offset, + post_div->shift, + post_div->width, + post_div->flag_div, + post_div->div_table, + clks[post_div->pll_num], + &stm32f4_clk_lock); + + if (post_div->idx != NO_IDX) + clks[post_div->idx] = hw; + } sys_parents[1] = hse_clk; - clk_register_mux_table( + + clks[CLK_SYSCLK] = clk_hw_register_mux_table( NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0, base + STM32F4_RCC_CFGR, 0, 3, 0, NULL, &stm32f4_clk_lock); @@ -762,11 +1558,39 @@ static void __init stm32f4_rcc_init(struct device_node *np) goto fail; } + for (n = 0; n < data->aux_clk_num; n++) { + const struct stm32_aux_clk *aux_clk; + struct clk_hw *hw; + + aux_clk = &data->aux_clk[n]; + + hw = stm32_register_aux_clk(aux_clk->name, + aux_clk->parent_names, aux_clk->num_parents, + aux_clk->offset_mux, aux_clk->shift, + aux_clk->mask, aux_clk->offset_gate, + aux_clk->bit_idx, aux_clk->flags, + &stm32f4_clk_lock); + + if (IS_ERR(hw)) { + pr_warn("Unable to register %s clk\n", aux_clk->name); + continue; + } + + if (aux_clk->idx != NO_IDX) + clks[aux_clk->idx] = hw; + } + + if (of_device_is_compatible(np, "st,stm32f746-rcc")) + + clk_hw_register_fixed_factor(NULL, "hsi_div488", "hsi", 0, + 1, 488); + of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL); return; fail: kfree(clks); iounmap(base); } -CLK_OF_DECLARE(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); -CLK_OF_DECLARE(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); +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); diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c new file mode 100644 index 000000000000..56741f3cf0a3 --- /dev/null +++ b/drivers/clk/clk-versaclock5.c @@ -0,0 +1,791 @@ +/* + * Driver for IDT Versaclock 5 + * + * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Possible optimizations: + * - Use spread spectrum + * - Use integer divider in FOD if applicable + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/rational.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +/* VersaClock5 registers */ +#define VC5_OTP_CONTROL 0x00 + +/* Factory-reserved register block */ +#define VC5_RSVD_DEVICE_ID 0x01 +#define VC5_RSVD_ADC_GAIN_7_0 0x02 +#define VC5_RSVD_ADC_GAIN_15_8 0x03 +#define VC5_RSVD_ADC_OFFSET_7_0 0x04 +#define VC5_RSVD_ADC_OFFSET_15_8 0x05 +#define VC5_RSVD_TEMPY 0x06 +#define VC5_RSVD_OFFSET_TBIN 0x07 +#define VC5_RSVD_GAIN 0x08 +#define VC5_RSVD_TEST_NP 0x09 +#define VC5_RSVD_UNUSED 0x0a +#define VC5_RSVD_BANDGAP_TRIM_UP 0x0b +#define VC5_RSVD_BANDGAP_TRIM_DN 0x0c +#define VC5_RSVD_CLK_R_12_CLK_AMP_4 0x0d +#define VC5_RSVD_CLK_R_34_CLK_AMP_4 0x0e +#define VC5_RSVD_CLK_AMP_123 0x0f + +/* Configuration register block */ +#define VC5_PRIM_SRC_SHDN 0x10 +#define VC5_PRIM_SRC_SHDN_EN_XTAL BIT(7) +#define VC5_PRIM_SRC_SHDN_EN_CLKIN BIT(6) +#define VC5_PRIM_SRC_SHDN_SP BIT(1) +#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0) + +#define VC5_VCO_BAND 0x11 +#define VC5_XTAL_X1_LOAD_CAP 0x12 +#define VC5_XTAL_X2_LOAD_CAP 0x13 +#define VC5_REF_DIVIDER 0x15 +#define VC5_REF_DIVIDER_SEL_PREDIV2 BIT(7) +#define VC5_REF_DIVIDER_REF_DIV(n) ((n) & 0x3f) + +#define VC5_VCO_CTRL_AND_PREDIV 0x16 +#define VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV BIT(7) + +#define VC5_FEEDBACK_INT_DIV 0x17 +#define VC5_FEEDBACK_INT_DIV_BITS 0x18 +#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n)) +#define VC5_RC_CONTROL0 0x1e +#define VC5_RC_CONTROL1 0x1f +/* Register 0x20 is factory reserved */ + +/* Output divider control for divider 1,2,3,4 */ +#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10)) +#define VC5_OUT_DIV_CONTROL_RESET BIT(7) +#define VC5_OUT_DIV_CONTROL_SELB_NORM BIT(3) +#define VC5_OUT_DIV_CONTROL_SEL_EXT BIT(2) +#define VC5_OUT_DIV_CONTROL_INT_MODE BIT(1) +#define VC5_OUT_DIV_CONTROL_EN_FOD BIT(0) + +#define VC5_OUT_DIV_FRAC(idx, n) (0x22 + ((idx) * 0x10) + (n)) +#define VC5_OUT_DIV_FRAC4_OD_SCEE BIT(1) + +#define VC5_OUT_DIV_STEP_SPREAD(idx, n) (0x26 + ((idx) * 0x10) + (n)) +#define VC5_OUT_DIV_SPREAD_MOD(idx, n) (0x29 + ((idx) * 0x10) + (n)) +#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n)) +#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n)) +#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10)) +/* Registers 0x30, 0x40, 0x50 are factory reserved */ + +/* Clock control register for clock 1,2 */ +#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n)) +#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0) + +#define VC5_CLK_OE_SHDN 0x68 +#define VC5_CLK_OS_SHDN 0x69 + +#define VC5_GLOBAL_REGISTER 0x76 +#define VC5_GLOBAL_REGISTER_GLOBAL_RESET BIT(5) + +/* PLL/VCO runs between 2.5 GHz and 3.0 GHz */ +#define VC5_PLL_VCO_MIN 2500000000UL +#define VC5_PLL_VCO_MAX 3000000000UL + +/* VC5 Input mux settings */ +#define VC5_MUX_IN_XIN BIT(0) +#define VC5_MUX_IN_CLKIN BIT(1) + +/* Supported IDT VC5 models. */ +enum vc5_model { + IDT_VC5_5P49V5923, + IDT_VC5_5P49V5933, +}; + +struct vc5_driver_data; + +struct vc5_hw_data { + struct clk_hw hw; + struct vc5_driver_data *vc5; + u32 div_int; + u32 div_frc; + unsigned int num; +}; + +struct vc5_driver_data { + struct i2c_client *client; + struct regmap *regmap; + enum vc5_model model; + + struct clk *pin_xin; + struct clk *pin_clkin; + unsigned char clk_mux_ins; + struct clk_hw clk_mux; + struct vc5_hw_data clk_pll; + struct vc5_hw_data clk_fod[2]; + struct vc5_hw_data clk_out[3]; +}; + +static const char * const vc5_mux_names[] = { + "mux" +}; + +static const char * const vc5_pll_names[] = { + "pll" +}; + +static const char * const vc5_fod_names[] = { + "fod0", "fod1", "fod2", "fod3", +}; + +static const char * const vc5_clk_out_names[] = { + "out0_sel_i2cb", "out1", "out2", "out3", "out4", +}; + +/* + * VersaClock5 i2c regmap + */ +static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg) +{ + /* Factory reserved regs, make them read-only */ + if (reg <= 0xf) + return false; + + /* Factory reserved regs, make them read-only */ + if (reg == 0x14 || reg == 0x1c || reg == 0x1d) + return false; + + return true; +} + +static const struct regmap_config vc5_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = 0x76, + .writeable_reg = vc5_regmap_is_writeable, +}; + +/* + * VersaClock5 input multiplexer between XTAL and CLKIN divider + */ +static unsigned char vc5_mux_get_parent(struct clk_hw *hw) +{ + struct vc5_driver_data *vc5 = + container_of(hw, struct vc5_driver_data, clk_mux); + const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN; + unsigned int src; + + regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src); + src &= mask; + + if (src == VC5_PRIM_SRC_SHDN_EN_XTAL) + return 0; + + if (src == VC5_PRIM_SRC_SHDN_EN_CLKIN) + return 1; + + dev_warn(&vc5->client->dev, + "Invalid clock input configuration (%02x)\n", src); + return 0; +} + +static int vc5_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct vc5_driver_data *vc5 = + container_of(hw, struct vc5_driver_data, clk_mux); + const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN; + u8 src; + + if ((index > 1) || !vc5->clk_mux_ins) + return -EINVAL; + + if (vc5->clk_mux_ins == (VC5_MUX_IN_CLKIN | VC5_MUX_IN_XIN)) { + if (index == 0) + src = VC5_PRIM_SRC_SHDN_EN_XTAL; + if (index == 1) + src = VC5_PRIM_SRC_SHDN_EN_CLKIN; + } else { + if (index != 0) + return -EINVAL; + + if (vc5->clk_mux_ins == VC5_MUX_IN_XIN) + src = VC5_PRIM_SRC_SHDN_EN_XTAL; + if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN) + src = VC5_PRIM_SRC_SHDN_EN_CLKIN; + } + + return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src); +} + +static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vc5_driver_data *vc5 = + container_of(hw, struct vc5_driver_data, clk_mux); + unsigned int prediv, div; + + regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv); + + /* The bypass_prediv is set, PLL fed from Ref_in directly. */ + if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV) + return parent_rate; + + regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div); + + /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */ + if (div & VC5_REF_DIVIDER_SEL_PREDIV2) + return parent_rate / 2; + else + return parent_rate / VC5_REF_DIVIDER_REF_DIV(div); +} + +static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long idiv; + + /* PLL cannot operate with input clock above 50 MHz. */ + if (rate > 50000000) + return -EINVAL; + + /* CLKIN within range of PLL input, feed directly to PLL. */ + if (*parent_rate <= 50000000) + return *parent_rate; + + idiv = DIV_ROUND_UP(*parent_rate, rate); + if (idiv > 127) + return -EINVAL; + + return *parent_rate / idiv; +} + +static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct vc5_driver_data *vc5 = + container_of(hw, struct vc5_driver_data, clk_mux); + unsigned long idiv; + u8 div; + + /* CLKIN within range of PLL input, feed directly to PLL. */ + if (parent_rate <= 50000000) { + regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, + VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, + VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV); + regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00); + return 0; + } + + idiv = DIV_ROUND_UP(parent_rate, rate); + + /* We have dedicated div-2 predivider. */ + if (idiv == 2) + div = VC5_REF_DIVIDER_SEL_PREDIV2; + else + div = VC5_REF_DIVIDER_REF_DIV(idiv); + + regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div); + regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, + VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0); + + return 0; +} + +static const struct clk_ops vc5_mux_ops = { + .set_parent = vc5_mux_set_parent, + .get_parent = vc5_mux_get_parent, + .recalc_rate = vc5_mux_recalc_rate, + .round_rate = vc5_mux_round_rate, + .set_rate = vc5_mux_set_rate, +}; + +/* + * VersaClock5 PLL/VCO + */ +static unsigned long vc5_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + u32 div_int, div_frc; + u8 fb[5]; + + regmap_bulk_read(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5); + + div_int = (fb[0] << 4) | (fb[1] >> 4); + div_frc = (fb[2] << 16) | (fb[3] << 8) | fb[4]; + + /* The PLL divider has 12 integer bits and 24 fractional bits */ + return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24); +} + +static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + u32 div_int; + u64 div_frc; + + if (rate < VC5_PLL_VCO_MIN) + rate = VC5_PLL_VCO_MIN; + if (rate > VC5_PLL_VCO_MAX) + rate = VC5_PLL_VCO_MAX; + + /* Determine integer part, which is 12 bit wide */ + div_int = rate / *parent_rate; + if (div_int > 0xfff) + rate = *parent_rate * 0xfff; + + /* Determine best fractional part, which is 24 bit wide */ + div_frc = rate % *parent_rate; + div_frc *= BIT(24) - 1; + do_div(div_frc, *parent_rate); + + hwdata->div_int = div_int; + hwdata->div_frc = (u32)div_frc; + + return (*parent_rate * div_int) + ((*parent_rate * div_frc) >> 24); +} + +static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + u8 fb[5]; + + fb[0] = hwdata->div_int >> 4; + fb[1] = hwdata->div_int << 4; + fb[2] = hwdata->div_frc >> 16; + fb[3] = hwdata->div_frc >> 8; + fb[4] = hwdata->div_frc; + + return regmap_bulk_write(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5); +} + +static const struct clk_ops vc5_pll_ops = { + .recalc_rate = vc5_pll_recalc_rate, + .round_rate = vc5_pll_round_rate, + .set_rate = vc5_pll_set_rate, +}; + +static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + /* VCO frequency is divided by two before entering FOD */ + u32 f_in = parent_rate / 2; + u32 div_int, div_frc; + u8 od_int[2]; + u8 od_frc[4]; + + regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_INT(hwdata->num, 0), + od_int, 2); + regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0), + od_frc, 4); + + div_int = (od_int[0] << 4) | (od_int[1] >> 4); + div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) | + (od_frc[2] << 6) | (od_frc[3] >> 2); + + /* The PLL divider has 12 integer bits and 30 fractional bits */ + return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc); +} + +static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + /* VCO frequency is divided by two before entering FOD */ + u32 f_in = *parent_rate / 2; + u32 div_int; + u64 div_frc; + + /* Determine integer part, which is 12 bit wide */ + div_int = f_in / rate; + /* + * WARNING: The clock chip does not output signal if the integer part + * of the divider is 0xfff and fractional part is non-zero. + * Clamp the divider at 0xffe to keep the code simple. + */ + if (div_int > 0xffe) { + div_int = 0xffe; + rate = f_in / div_int; + } + + /* Determine best fractional part, which is 30 bit wide */ + div_frc = f_in % rate; + div_frc <<= 24; + do_div(div_frc, rate); + + hwdata->div_int = div_int; + hwdata->div_frc = (u32)div_frc; + + return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc); +} + +static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + u8 data[14] = { + hwdata->div_frc >> 22, hwdata->div_frc >> 14, + hwdata->div_frc >> 6, hwdata->div_frc << 2, + 0, 0, 0, 0, 0, + 0, 0, + hwdata->div_int >> 4, hwdata->div_int << 4, + 0 + }; + + regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0), + data, 14); + + /* + * Toggle magic bit in undocumented register for unknown reason. + * This is what the IDT timing commander tool does and the chip + * datasheet somewhat implies this is needed, but the register + * and the bit is not documented. + */ + regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER, + VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0); + regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER, + VC5_GLOBAL_REGISTER_GLOBAL_RESET, + VC5_GLOBAL_REGISTER_GLOBAL_RESET); + return 0; +} + +static const struct clk_ops vc5_fod_ops = { + .recalc_rate = vc5_fod_recalc_rate, + .round_rate = vc5_fod_round_rate, + .set_rate = vc5_fod_set_rate, +}; + +static int vc5_clk_out_prepare(struct clk_hw *hw) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + + /* Enable the clock buffer */ + regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), + VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, + VC5_CLK_OUTPUT_CFG1_EN_CLKBUF); + return 0; +} + +static void vc5_clk_out_unprepare(struct clk_hw *hw) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + + /* Enable the clock buffer */ + regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), + VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0); +} + +static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM | + VC5_OUT_DIV_CONTROL_SEL_EXT | + VC5_OUT_DIV_CONTROL_EN_FOD; + const u8 fodclkmask = VC5_OUT_DIV_CONTROL_SELB_NORM | + VC5_OUT_DIV_CONTROL_EN_FOD; + const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM | + VC5_OUT_DIV_CONTROL_SEL_EXT; + unsigned int src; + + regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src); + src &= mask; + + if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD) + return 0; + + if (src == extclk) + return 1; + + dev_warn(&vc5->client->dev, + "Invalid clock output configuration (%02x)\n", src); + return 0; +} + +static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index) +{ + struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); + struct vc5_driver_data *vc5 = hwdata->vc5; + const u8 mask = VC5_OUT_DIV_CONTROL_RESET | + VC5_OUT_DIV_CONTROL_SELB_NORM | + VC5_OUT_DIV_CONTROL_SEL_EXT | + VC5_OUT_DIV_CONTROL_EN_FOD; + const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM | + VC5_OUT_DIV_CONTROL_SEL_EXT; + u8 src = VC5_OUT_DIV_CONTROL_RESET; + + if (index == 0) + src |= VC5_OUT_DIV_CONTROL_EN_FOD; + else + src |= extclk; + + return regmap_update_bits(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), + mask, src); +} + +static const struct clk_ops vc5_clk_out_ops = { + .prepare = vc5_clk_out_prepare, + .unprepare = vc5_clk_out_unprepare, + .set_parent = vc5_clk_out_set_parent, + .get_parent = vc5_clk_out_get_parent, +}; + +static struct clk_hw *vc5_of_clk_get(struct of_phandle_args *clkspec, + void *data) +{ + struct vc5_driver_data *vc5 = data; + unsigned int idx = clkspec->args[0]; + + if (idx > 2) + return ERR_PTR(-EINVAL); + + return &vc5->clk_out[idx].hw; +} + +static int vc5_map_index_to_output(const enum vc5_model model, + const unsigned int n) +{ + switch (model) { + case IDT_VC5_5P49V5933: + return (n == 0) ? 0 : 3; + case IDT_VC5_5P49V5923: + default: + return n; + } +} + +static const struct of_device_id clk_vc5_of_match[]; + +static int vc5_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct of_device_id *of_id = + of_match_device(clk_vc5_of_match, &client->dev); + struct vc5_driver_data *vc5; + struct clk_init_data init; + const char *parent_names[2]; + unsigned int n, idx; + int ret; + + vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL); + if (vc5 == NULL) + return -ENOMEM; + + i2c_set_clientdata(client, vc5); + vc5->client = client; + vc5->model = (enum vc5_model)of_id->data; + + vc5->pin_xin = devm_clk_get(&client->dev, "xin"); + if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + vc5->pin_clkin = devm_clk_get(&client->dev, "clkin"); + if (PTR_ERR(vc5->pin_clkin) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config); + if (IS_ERR(vc5->regmap)) { + dev_err(&client->dev, "failed to allocate register map\n"); + return PTR_ERR(vc5->regmap); + } + + /* Register clock input mux */ + memset(&init, 0, sizeof(init)); + + if (!IS_ERR(vc5->pin_xin)) { + vc5->clk_mux_ins |= VC5_MUX_IN_XIN; + parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin); + } else if (vc5->model == IDT_VC5_5P49V5933) { + /* IDT VC5 5P49V5933 has built-in oscilator. */ + vc5->pin_xin = clk_register_fixed_rate(&client->dev, + "internal-xtal", NULL, + 0, 25000000); + if (IS_ERR(vc5->pin_xin)) + return PTR_ERR(vc5->pin_xin); + vc5->clk_mux_ins |= VC5_MUX_IN_XIN; + parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin); + } + + if (!IS_ERR(vc5->pin_clkin)) { + vc5->clk_mux_ins |= VC5_MUX_IN_CLKIN; + parent_names[init.num_parents++] = + __clk_get_name(vc5->pin_clkin); + } + + if (!init.num_parents) { + dev_err(&client->dev, "no input clock specified!\n"); + return -EINVAL; + } + + init.name = vc5_mux_names[0]; + init.ops = &vc5_mux_ops; + init.flags = 0; + init.parent_names = parent_names; + vc5->clk_mux.init = &init; + ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", init.name); + goto err_clk; + } + + /* Register PLL */ + memset(&init, 0, sizeof(init)); + init.name = vc5_pll_names[0]; + init.ops = &vc5_pll_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = vc5_mux_names; + init.num_parents = 1; + vc5->clk_pll.num = 0; + vc5->clk_pll.vc5 = vc5; + vc5->clk_pll.hw.init = &init; + ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", init.name); + goto err_clk; + } + + /* Register FODs */ + for (n = 0; n < 2; n++) { + idx = vc5_map_index_to_output(vc5->model, n); + memset(&init, 0, sizeof(init)); + init.name = vc5_fod_names[idx]; + init.ops = &vc5_fod_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = vc5_pll_names; + init.num_parents = 1; + vc5->clk_fod[n].num = idx; + vc5->clk_fod[n].vc5 = vc5; + vc5->clk_fod[n].hw.init = &init; + ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", + init.name); + goto err_clk; + } + } + + /* Register MUX-connected OUT0_I2C_SELB output */ + memset(&init, 0, sizeof(init)); + init.name = vc5_clk_out_names[0]; + init.ops = &vc5_clk_out_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = vc5_mux_names; + init.num_parents = 1; + vc5->clk_out[0].num = idx; + vc5->clk_out[0].vc5 = vc5; + vc5->clk_out[0].hw.init = &init; + ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", + init.name); + goto err_clk; + } + + /* Register FOD-connected OUTx outputs */ + for (n = 1; n < 3; n++) { + idx = vc5_map_index_to_output(vc5->model, n - 1); + parent_names[0] = vc5_fod_names[idx]; + if (n == 1) + parent_names[1] = vc5_mux_names[0]; + else + parent_names[1] = vc5_clk_out_names[n - 1]; + + memset(&init, 0, sizeof(init)); + init.name = vc5_clk_out_names[idx + 1]; + init.ops = &vc5_clk_out_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent_names; + init.num_parents = 2; + vc5->clk_out[n].num = idx; + vc5->clk_out[n].vc5 = vc5; + vc5->clk_out[n].hw.init = &init; + ret = devm_clk_hw_register(&client->dev, + &vc5->clk_out[n].hw); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", + init.name); + goto err_clk; + } + } + + ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5); + if (ret) { + dev_err(&client->dev, "unable to add clk provider\n"); + goto err_clk; + } + + return 0; + +err_clk: + if (vc5->model == IDT_VC5_5P49V5933) + clk_unregister_fixed_rate(vc5->pin_xin); + return ret; +} + +static int vc5_remove(struct i2c_client *client) +{ + struct vc5_driver_data *vc5 = i2c_get_clientdata(client); + + of_clk_del_provider(client->dev.of_node); + + if (vc5->model == IDT_VC5_5P49V5933) + clk_unregister_fixed_rate(vc5->pin_xin); + + return 0; +} + +static const struct i2c_device_id vc5_id[] = { + { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 }, + { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, vc5_id); + +static const struct of_device_id clk_vc5_of_match[] = { + { .compatible = "idt,5p49v5923", .data = (void *)IDT_VC5_5P49V5923 }, + { .compatible = "idt,5p49v5933", .data = (void *)IDT_VC5_5P49V5933 }, + { }, +}; +MODULE_DEVICE_TABLE(of, clk_vc5_of_match); + +static struct i2c_driver vc5_driver = { + .driver = { + .name = "vc5", + .of_match_table = clk_vc5_of_match, + }, + .probe = vc5_probe, + .remove = vc5_remove, + .id_table = vc5_id, +}; +module_i2c_driver(vc5_driver); + +MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("IDT VersaClock 5 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 0621fbfb4beb..a47960aacfa5 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -97,7 +97,8 @@ static int wm831x_fll_prepare(struct clk_hw *hw) if (ret != 0) dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret); - usleep_range(2000, 2000); + /* wait 2-3 ms for new frequency taking effect */ + usleep_range(2000, 3000); return ret; } diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index cbed6602172b..7098bfd32b1b 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -14,6 +14,13 @@ config COMMON_CLK_HI3519 help Build the clock driver for hi3519. +config COMMON_CLK_HI3660 + bool "Hi3660 Clock Driver" + depends on ARCH_HISI || COMPILE_TEST + default ARCH_HISI + help + Build the clock driver for hi3660. + config COMMON_CLK_HI3798CV200 tristate "Hi3798CV200 Clock Driver" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index 4eec5e511e4c..1e4c3ddbad84 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o obj-$(CONFIG_COMMON_CLK_HI3516CV300) += crg-hi3516cv300.o obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o +obj-$(CONFIG_COMMON_CLK_HI3660) += clk-hi3660.o obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o obj-$(CONFIG_RESET_HISI) += reset.o diff --git a/drivers/clk/hisilicon/clk-hi3660.c b/drivers/clk/hisilicon/clk-hi3660.c new file mode 100644 index 000000000000..96a9697b06cf --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3660.c @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2016-2017 Linaro Ltd. + * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <dt-bindings/clock/hi3660-clock.h> +#include <linux/clk-provider.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include "clk.h" + +static const struct hisi_fixed_rate_clock hi3660_fixed_rate_clks[] = { + { HI3660_CLKIN_SYS, "clkin_sys", NULL, 0, 19200000, }, + { HI3660_CLKIN_REF, "clkin_ref", NULL, 0, 32764, }, + { HI3660_CLK_FLL_SRC, "clk_fll_src", NULL, 0, 128000000, }, + { HI3660_CLK_PPLL0, "clk_ppll0", NULL, 0, 1600000000, }, + { HI3660_CLK_PPLL1, "clk_ppll1", NULL, 0, 1866000000, }, + { HI3660_CLK_PPLL2, "clk_ppll2", NULL, 0, 960000000, }, + { HI3660_CLK_PPLL3, "clk_ppll3", NULL, 0, 1290000000, }, + { HI3660_CLK_SCPLL, "clk_scpll", NULL, 0, 245760000, }, + { HI3660_PCLK, "pclk", NULL, 0, 20000000, }, + { HI3660_CLK_UART0_DBG, "clk_uart0_dbg", NULL, 0, 19200000, }, + { HI3660_CLK_UART6, "clk_uart6", NULL, 0, 19200000, }, + { HI3660_OSC32K, "osc32k", NULL, 0, 32764, }, + { HI3660_OSC19M, "osc19m", NULL, 0, 19200000, }, + { HI3660_CLK_480M, "clk_480m", NULL, 0, 480000000, }, + { HI3660_CLK_INV, "clk_inv", NULL, 0, 10000000, }, +}; + +/* crgctrl */ +static const struct hisi_fixed_factor_clock hi3660_crg_fixed_factor_clks[] = { + { HI3660_FACTOR_UART3, "clk_factor_uart3", "iomcu_peri0", 1, 8, 0, }, + { HI3660_CLK_FACTOR_MMC, "clk_factor_mmc", "clkin_sys", 1, 6, 0, }, + { HI3660_CLK_GATE_I2C0, "clk_gate_i2c0", "clk_i2c0_iomcu", 1, 4, 0, }, + { HI3660_CLK_GATE_I2C1, "clk_gate_i2c1", "clk_i2c1_iomcu", 1, 4, 0, }, + { HI3660_CLK_GATE_I2C2, "clk_gate_i2c2", "clk_i2c2_iomcu", 1, 4, 0, }, + { HI3660_CLK_GATE_I2C6, "clk_gate_i2c6", "clk_i2c6_iomcu", 1, 4, 0, }, + { HI3660_CLK_DIV_SYSBUS, "clk_div_sysbus", "clk_mux_sysbus", 1, 7, 0, }, + { HI3660_CLK_DIV_320M, "clk_div_320m", "clk_320m_pll_gt", 1, 5, 0, }, + { HI3660_CLK_DIV_A53, "clk_div_a53hpm", "clk_a53hpm_andgt", 1, 2, 0, }, + { HI3660_CLK_GATE_SPI0, "clk_gate_spi0", "clk_ppll0", 1, 8, 0, }, + { HI3660_CLK_GATE_SPI2, "clk_gate_spi2", "clk_ppll0", 1, 8, 0, }, + { HI3660_PCIEPHY_REF, "clk_pciephy_ref", "clk_div_pciephy", 1, 1, 0, }, + { HI3660_CLK_ABB_USB, "clk_abb_usb", "clk_gate_usb_tcxo_en", 1, 1, 0 }, +}; + +static const struct hisi_gate_clock hi3660_crgctrl_gate_sep_clks[] = { + { HI3660_HCLK_GATE_SDIO0, "hclk_gate_sdio0", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x0, 21, 0, }, + { HI3660_HCLK_GATE_SD, "hclk_gate_sd", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x0, 30, 0, }, + { HI3660_CLK_GATE_AOMM, "clk_gate_aomm", "clk_div_aomm", + CLK_SET_RATE_PARENT, 0x0, 31, 0, }, + { HI3660_PCLK_GPIO0, "pclk_gpio0", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 0, 0, }, + { HI3660_PCLK_GPIO1, "pclk_gpio1", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 1, 0, }, + { HI3660_PCLK_GPIO2, "pclk_gpio2", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 2, 0, }, + { HI3660_PCLK_GPIO3, "pclk_gpio3", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 3, 0, }, + { HI3660_PCLK_GPIO4, "pclk_gpio4", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 4, 0, }, + { HI3660_PCLK_GPIO5, "pclk_gpio5", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 5, 0, }, + { HI3660_PCLK_GPIO6, "pclk_gpio6", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 6, 0, }, + { HI3660_PCLK_GPIO7, "pclk_gpio7", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 7, 0, }, + { HI3660_PCLK_GPIO8, "pclk_gpio8", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 8, 0, }, + { HI3660_PCLK_GPIO9, "pclk_gpio9", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 9, 0, }, + { HI3660_PCLK_GPIO10, "pclk_gpio10", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 10, 0, }, + { HI3660_PCLK_GPIO11, "pclk_gpio11", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 11, 0, }, + { HI3660_PCLK_GPIO12, "pclk_gpio12", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 12, 0, }, + { HI3660_PCLK_GPIO13, "pclk_gpio13", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 13, 0, }, + { HI3660_PCLK_GPIO14, "pclk_gpio14", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 14, 0, }, + { HI3660_PCLK_GPIO15, "pclk_gpio15", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 15, 0, }, + { HI3660_PCLK_GPIO16, "pclk_gpio16", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 16, 0, }, + { HI3660_PCLK_GPIO17, "pclk_gpio17", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 17, 0, }, + { HI3660_PCLK_GPIO18, "pclk_gpio18", "clk_div_ioperi", + CLK_SET_RATE_PARENT, 0x10, 18, 0, }, + { HI3660_PCLK_GPIO19, "pclk_gpio19", "clk_div_ioperi", + CLK_SET_RATE_PARENT, 0x10, 19, 0, }, + { HI3660_PCLK_GPIO20, "pclk_gpio20", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 20, 0, }, + { HI3660_PCLK_GPIO21, "pclk_gpio21", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 21, 0, }, + { HI3660_CLK_GATE_SPI3, "clk_gate_spi3", "clk_div_ioperi", + CLK_SET_RATE_PARENT, 0x10, 30, 0, }, + { HI3660_CLK_GATE_I2C7, "clk_gate_i2c7", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x10, 31, 0, }, + { HI3660_CLK_GATE_I2C3, "clk_gate_i2c3", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x20, 7, 0, }, + { HI3660_CLK_GATE_SPI1, "clk_gate_spi1", "clk_mux_spi", + CLK_SET_RATE_PARENT, 0x20, 9, 0, }, + { HI3660_CLK_GATE_UART1, "clk_gate_uart1", "clk_mux_uarth", + CLK_SET_RATE_PARENT, 0x20, 11, 0, }, + { HI3660_CLK_GATE_UART2, "clk_gate_uart2", "clk_mux_uart1", + CLK_SET_RATE_PARENT, 0x20, 12, 0, }, + { HI3660_CLK_GATE_UART4, "clk_gate_uart4", "clk_mux_uarth", + CLK_SET_RATE_PARENT, 0x20, 14, 0, }, + { HI3660_CLK_GATE_UART5, "clk_gate_uart5", "clk_mux_uart1", + CLK_SET_RATE_PARENT, 0x20, 15, 0, }, + { HI3660_CLK_GATE_I2C4, "clk_gate_i2c4", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x20, 27, 0, }, + { HI3660_CLK_GATE_DMAC, "clk_gate_dmac", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x30, 1, 0, }, + { HI3660_PCLK_GATE_DSS, "pclk_gate_dss", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x30, 12, 0, }, + { HI3660_ACLK_GATE_DSS, "aclk_gate_dss", "clk_gate_vivobus", + CLK_SET_RATE_PARENT, 0x30, 13, 0, }, + { HI3660_CLK_GATE_LDI1, "clk_gate_ldi1", "clk_div_ldi1", + CLK_SET_RATE_PARENT, 0x30, 14, 0, }, + { HI3660_CLK_GATE_LDI0, "clk_gate_ldi0", "clk_div_ldi0", + CLK_SET_RATE_PARENT, 0x30, 15, 0, }, + { HI3660_CLK_GATE_VIVOBUS, "clk_gate_vivobus", "clk_div_vivobus", + CLK_SET_RATE_PARENT, 0x30, 16, 0, }, + { HI3660_CLK_GATE_EDC0, "clk_gate_edc0", "clk_div_edc0", + CLK_SET_RATE_PARENT, 0x30, 17, 0, }, + { HI3660_CLK_GATE_TXDPHY0_CFG, "clk_gate_txdphy0_cfg", "clkin_sys", + CLK_SET_RATE_PARENT, 0x30, 28, 0, }, + { HI3660_CLK_GATE_TXDPHY0_REF, "clk_gate_txdphy0_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x30, 29, 0, }, + { HI3660_CLK_GATE_TXDPHY1_CFG, "clk_gate_txdphy1_cfg", "clkin_sys", + CLK_SET_RATE_PARENT, 0x30, 30, 0, }, + { HI3660_CLK_GATE_TXDPHY1_REF, "clk_gate_txdphy1_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x30, 31, 0, }, + { HI3660_ACLK_GATE_USB3OTG, "aclk_gate_usb3otg", "clk_div_mmc0bus", + CLK_SET_RATE_PARENT, 0x40, 1, 0, }, + { HI3660_CLK_GATE_SPI4, "clk_gate_spi4", "clk_mux_spi", + CLK_SET_RATE_PARENT, 0x40, 4, 0, }, + { HI3660_CLK_GATE_SD, "clk_gate_sd", "clk_mux_sd_sys", + CLK_SET_RATE_PARENT, 0x40, 17, 0, }, + { HI3660_CLK_GATE_SDIO0, "clk_gate_sdio0", "clk_mux_sdio_sys", + CLK_SET_RATE_PARENT, 0x40, 19, 0, }, + { HI3660_CLK_GATE_UFS_SUBSYS, "clk_gate_ufs_subsys", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 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", + CLK_SET_RATE_PARENT, 0x50, 29, 0, }, + { HI3660_ACLK_GATE_PCIE, "aclk_gate_pcie", "clk_div_mmc1bus", + CLK_SET_RATE_PARENT, 0x420, 5, 0, }, + { HI3660_PCLK_GATE_PCIE_SYS, "pclk_gate_pcie_sys", "clk_div_mmc1bus", + CLK_SET_RATE_PARENT, 0x420, 7, 0, }, + { HI3660_CLK_GATE_PCIEAUX, "clk_gate_pcieaux", "clkin_sys", + CLK_SET_RATE_PARENT, 0x420, 8, 0, }, + { HI3660_PCLK_GATE_PCIE_PHY, "pclk_gate_pcie_phy", "clk_div_mmc1bus", + CLK_SET_RATE_PARENT, 0x420, 9, 0, }, +}; + +static const struct hisi_gate_clock hi3660_crgctrl_gate_clks[] = { + { HI3660_CLK_ANDGT_LDI0, "clk_andgt_ldi0", "clk_mux_ldi0", + CLK_SET_RATE_PARENT, 0xf0, 6, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_LDI1, "clk_andgt_ldi1", "clk_mux_ldi1", + CLK_SET_RATE_PARENT, 0xf0, 7, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_EDC0, "clk_andgt_edc0", "clk_mux_edc0", + CLK_SET_RATE_PARENT, 0xf0, 8, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_GATE_UFSPHY_GT, "clk_gate_ufsphy_gt", "clk_div_ufsperi", + CLK_SET_RATE_PARENT, 0xf4, 1, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_MMC, "clk_andgt_mmc", "clk_mux_mmc_pll", + CLK_SET_RATE_PARENT, 0xf4, 2, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_SD, "clk_andgt_sd", "clk_mux_sd_pll", + CLK_SET_RATE_PARENT, 0xf4, 3, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_A53HPM_ANDGT, "clk_a53hpm_andgt", "clk_mux_a53hpm", + CLK_SET_RATE_PARENT, 0xf4, 7, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_SDIO, "clk_andgt_sdio", "clk_mux_sdio_pll", + CLK_SET_RATE_PARENT, 0xf4, 8, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_UART0, "clk_andgt_uart0", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xf4, 9, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_UART1, "clk_andgt_uart1", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xf4, 10, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_UARTH, "clk_andgt_uarth", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xf4, 11, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_ANDGT_SPI, "clk_andgt_spi", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xf4, 13, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_VIVOBUS_ANDGT, "clk_vivobus_andgt", "clk_mux_vivobus", + CLK_SET_RATE_PARENT, 0xf8, 1, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_AOMM_ANDGT, "clk_aomm_andgt", "clk_ppll2", + CLK_SET_RATE_PARENT, 0xf8, 3, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_320M_PLL_GT, "clk_320m_pll_gt", "clk_mux_320m", + CLK_SET_RATE_PARENT, 0xf8, 10, 0, }, + { HI3660_AUTODIV_EMMC0BUS, "autodiv_emmc0bus", "autodiv_sysbus", + CLK_SET_RATE_PARENT, 0x404, 1, CLK_GATE_HIWORD_MASK, }, + { HI3660_AUTODIV_SYSBUS, "autodiv_sysbus", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x404, 5, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_GATE_UFSPHY_CFG, "clk_gate_ufsphy_cfg", + "clk_div_ufsphy_cfg", CLK_SET_RATE_PARENT, 0x420, 12, 0, }, + { HI3660_CLK_GATE_UFSIO_REF, "clk_gate_ufsio_ref", + "clk_gate_ufs_tcxo_en", CLK_SET_RATE_PARENT, 0x420, 14, 0, }, +}; + +static const char *const +clk_mux_sdio_sys_p[] = {"clk_factor_mmc", "clk_div_sdio",}; +static const char *const +clk_mux_sd_sys_p[] = {"clk_factor_mmc", "clk_div_sd",}; +static const char *const +clk_mux_pll_p[] = {"clk_ppll0", "clk_ppll1", "clk_ppll2", "clk_ppll2",}; +static const char *const +clk_mux_pll0123_p[] = {"clk_ppll0", "clk_ppll1", "clk_ppll2", "clk_ppll3",}; +static const char *const +clk_mux_edc0_p[] = {"clk_inv", "clk_ppll0", "clk_ppll1", "clk_inv", + "clk_ppll2", "clk_inv", "clk_inv", "clk_inv", + "clk_ppll3", "clk_inv", "clk_inv", "clk_inv", + "clk_inv", "clk_inv", "clk_inv", "clk_inv",}; +static const char *const +clk_mux_ldi0_p[] = {"clk_inv", "clk_ppll0", "clk_ppll2", "clk_inv", + "clk_ppll1", "clk_inv", "clk_inv", "clk_inv", + "clk_ppll3", "clk_inv", "clk_inv", "clk_inv", + "clk_inv", "clk_inv", "clk_inv", "clk_inv",}; +static const char *const +clk_mux_uart0_p[] = {"clkin_sys", "clk_div_uart0",}; +static const char *const +clk_mux_uart1_p[] = {"clkin_sys", "clk_div_uart1",}; +static const char *const +clk_mux_uarth_p[] = {"clkin_sys", "clk_div_uarth",}; +static const char *const +clk_mux_pll02p[] = {"clk_ppll0", "clk_ppll2",}; +static const char *const +clk_mux_ioperi_p[] = {"clk_div_320m", "clk_div_a53hpm",}; +static const char *const +clk_mux_spi_p[] = {"clkin_sys", "clk_div_spi",}; +static const char *const +clk_mux_i2c_p[] = {"clkin_sys", "clk_div_i2c",}; + +static const struct hisi_mux_clock hi3660_crgctrl_mux_clks[] = { + { HI3660_CLK_MUX_SYSBUS, "clk_mux_sysbus", clk_mux_sdio_sys_p, + ARRAY_SIZE(clk_mux_sdio_sys_p), CLK_SET_RATE_PARENT, 0xac, 0, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_UART0, "clk_mux_uart0", clk_mux_uart0_p, + ARRAY_SIZE(clk_mux_uart0_p), CLK_SET_RATE_PARENT, 0xac, 2, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_UART1, "clk_mux_uart1", clk_mux_uart1_p, + ARRAY_SIZE(clk_mux_uart1_p), CLK_SET_RATE_PARENT, 0xac, 3, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_UARTH, "clk_mux_uarth", clk_mux_uarth_p, + ARRAY_SIZE(clk_mux_uarth_p), CLK_SET_RATE_PARENT, 0xac, 4, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_SPI, "clk_mux_spi", clk_mux_spi_p, + ARRAY_SIZE(clk_mux_spi_p), CLK_SET_RATE_PARENT, 0xac, 8, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_I2C, "clk_mux_i2c", clk_mux_i2c_p, + ARRAY_SIZE(clk_mux_i2c_p), CLK_SET_RATE_PARENT, 0xac, 13, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_MMC_PLL, "clk_mux_mmc_pll", clk_mux_pll02p, + ARRAY_SIZE(clk_mux_pll02p), CLK_SET_RATE_PARENT, 0xb4, 0, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_LDI1, "clk_mux_ldi1", clk_mux_ldi0_p, + ARRAY_SIZE(clk_mux_ldi0_p), CLK_SET_RATE_PARENT, 0xb4, 8, 4, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_LDI0, "clk_mux_ldi0", clk_mux_ldi0_p, + ARRAY_SIZE(clk_mux_ldi0_p), CLK_SET_RATE_PARENT, 0xb4, 12, 4, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_SD_PLL, "clk_mux_sd_pll", clk_mux_pll_p, + ARRAY_SIZE(clk_mux_pll_p), CLK_SET_RATE_PARENT, 0xb8, 4, 2, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_SD_SYS, "clk_mux_sd_sys", clk_mux_sd_sys_p, + ARRAY_SIZE(clk_mux_sd_sys_p), CLK_SET_RATE_PARENT, 0xb8, 6, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_EDC0, "clk_mux_edc0", clk_mux_edc0_p, + ARRAY_SIZE(clk_mux_edc0_p), CLK_SET_RATE_PARENT, 0xbc, 6, 4, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_SDIO_SYS, "clk_mux_sdio_sys", clk_mux_sdio_sys_p, + ARRAY_SIZE(clk_mux_sdio_sys_p), CLK_SET_RATE_PARENT, 0xc0, 6, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_SDIO_PLL, "clk_mux_sdio_pll", clk_mux_pll_p, + ARRAY_SIZE(clk_mux_pll_p), CLK_SET_RATE_PARENT, 0xc0, 4, 2, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_VIVOBUS, "clk_mux_vivobus", clk_mux_pll0123_p, + ARRAY_SIZE(clk_mux_pll0123_p), CLK_SET_RATE_PARENT, 0xd0, 12, 2, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_A53HPM, "clk_mux_a53hpm", clk_mux_pll02p, + ARRAY_SIZE(clk_mux_pll02p), CLK_SET_RATE_PARENT, 0xd4, 9, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_320M, "clk_mux_320m", clk_mux_pll02p, + ARRAY_SIZE(clk_mux_pll02p), CLK_SET_RATE_PARENT, 0x100, 0, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_MUX_IOPERI, "clk_mux_ioperi", clk_mux_ioperi_p, + ARRAY_SIZE(clk_mux_ioperi_p), CLK_SET_RATE_PARENT, 0x108, 10, 1, + CLK_MUX_HIWORD_MASK, }, +}; + +static const struct hisi_divider_clock hi3660_crgctrl_divider_clks[] = { + { HI3660_CLK_DIV_UART0, "clk_div_uart0", "clk_andgt_uart0", + CLK_SET_RATE_PARENT, 0xb0, 4, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_UART1, "clk_div_uart1", "clk_andgt_uart1", + CLK_SET_RATE_PARENT, 0xb0, 8, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_UARTH, "clk_div_uarth", "clk_andgt_uarth", + CLK_SET_RATE_PARENT, 0xb0, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_MMC, "clk_div_mmc", "clk_andgt_mmc", + CLK_SET_RATE_PARENT, 0xb4, 3, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_SD, "clk_div_sd", "clk_andgt_sd", + CLK_SET_RATE_PARENT, 0xb8, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_EDC0, "clk_div_edc0", "clk_andgt_edc0", + CLK_SET_RATE_PARENT, 0xbc, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_LDI0, "clk_div_ldi0", "clk_andgt_ldi0", + CLK_SET_RATE_PARENT, 0xbc, 10, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_SDIO, "clk_div_sdio", "clk_andgt_sdio", + CLK_SET_RATE_PARENT, 0xc0, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_LDI1, "clk_div_ldi1", "clk_andgt_ldi1", + CLK_SET_RATE_PARENT, 0xc0, 8, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_SPI, "clk_div_spi", "clk_andgt_spi", + CLK_SET_RATE_PARENT, 0xc4, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_VIVOBUS, "clk_div_vivobus", "clk_vivobus_andgt", + CLK_SET_RATE_PARENT, 0xd0, 7, 5, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_I2C, "clk_div_i2c", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xe8, 4, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_UFSPHY, "clk_div_ufsphy_cfg", "clk_gate_ufsphy_gt", + CLK_SET_RATE_PARENT, 0xe8, 9, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_CFGBUS, "clk_div_cfgbus", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0xec, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_MMC0BUS, "clk_div_mmc0bus", "autodiv_emmc0bus", + CLK_SET_RATE_PARENT, 0xec, 2, 1, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_MMC1BUS, "clk_div_mmc1bus", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0xec, 3, 1, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_UFSPERI, "clk_div_ufsperi", "clk_gate_ufs_subsys", + CLK_SET_RATE_PARENT, 0xec, 14, 1, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_AOMM, "clk_div_aomm", "clk_aomm_andgt", + CLK_SET_RATE_PARENT, 0x100, 7, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_IOPERI, "clk_div_ioperi", "clk_mux_ioperi", + CLK_SET_RATE_PARENT, 0x108, 11, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, +}; + +/* clk_pmuctrl */ +/* pmu register need shift 2 bits */ +static const struct hisi_gate_clock hi3660_pmu_gate_clks[] = { + { HI3660_GATE_ABB_192, "clk_gate_abb_192", "clkin_sys", + CLK_SET_RATE_PARENT, (0x10a << 2), 3, 0, }, +}; + +/* clk_pctrl */ +static const struct hisi_gate_clock hi3660_pctrl_gate_clks[] = { + { HI3660_GATE_UFS_TCXO_EN, "clk_gate_ufs_tcxo_en", + "clk_gate_abb_192", CLK_SET_RATE_PARENT, 0x10, 0, + CLK_GATE_HIWORD_MASK, }, + { HI3660_GATE_USB_TCXO_EN, "clk_gate_usb_tcxo_en", "clk_gate_abb_192", + CLK_SET_RATE_PARENT, 0x10, 1, CLK_GATE_HIWORD_MASK, }, +}; + +/* clk_sctrl */ +static const struct hisi_gate_clock hi3660_sctrl_gate_sep_clks[] = { + { HI3660_PCLK_AO_GPIO0, "pclk_ao_gpio0", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 11, 0, }, + { HI3660_PCLK_AO_GPIO1, "pclk_ao_gpio1", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 12, 0, }, + { HI3660_PCLK_AO_GPIO2, "pclk_ao_gpio2", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 13, 0, }, + { HI3660_PCLK_AO_GPIO3, "pclk_ao_gpio3", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 14, 0, }, + { HI3660_PCLK_AO_GPIO4, "pclk_ao_gpio4", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 21, 0, }, + { HI3660_PCLK_AO_GPIO5, "pclk_ao_gpio5", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 22, 0, }, + { HI3660_PCLK_AO_GPIO6, "pclk_ao_gpio6", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 25, 0, }, + { HI3660_PCLK_GATE_MMBUF, "pclk_gate_mmbuf", "pclk_div_mmbuf", + CLK_SET_RATE_PARENT, 0x170, 23, 0, }, + { HI3660_CLK_GATE_DSS_AXI_MM, "clk_gate_dss_axi_mm", "aclk_mux_mmbuf", + CLK_SET_RATE_PARENT, 0x170, 24, 0, }, +}; + +static const struct hisi_gate_clock hi3660_sctrl_gate_clks[] = { + { HI3660_PCLK_MMBUF_ANDGT, "pclk_mmbuf_andgt", "clk_sw_mmbuf", + CLK_SET_RATE_PARENT, 0x258, 7, CLK_GATE_HIWORD_MASK, }, + { HI3660_CLK_MMBUF_PLL_ANDGT, "clk_mmbuf_pll_andgt", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x260, 11, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_FLL_MMBUF_ANDGT, "clk_fll_mmbuf_andgt", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x260, 12, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_SYS_MMBUF_ANDGT, "clk_sys_mmbuf_andgt", "clkin_sys", + CLK_SET_RATE_PARENT, 0x260, 13, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_GATE_PCIEPHY_GT, "clk_gate_pciephy_gt", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x268, 11, CLK_DIVIDER_HIWORD_MASK, 0, }, +}; + +static const char *const +aclk_mux_mmbuf_p[] = {"aclk_div_mmbuf", "clk_gate_aomm",}; +static const char *const +clk_sw_mmbuf_p[] = {"clk_sys_mmbuf_andgt", "clk_fll_mmbuf_andgt", + "aclk_mux_mmbuf", "aclk_mux_mmbuf"}; + +static const struct hisi_mux_clock hi3660_sctrl_mux_clks[] = { + { HI3660_ACLK_MUX_MMBUF, "aclk_mux_mmbuf", aclk_mux_mmbuf_p, + ARRAY_SIZE(aclk_mux_mmbuf_p), CLK_SET_RATE_PARENT, 0x250, 12, 1, + CLK_MUX_HIWORD_MASK, }, + { HI3660_CLK_SW_MMBUF, "clk_sw_mmbuf", clk_sw_mmbuf_p, + ARRAY_SIZE(clk_sw_mmbuf_p), CLK_SET_RATE_PARENT, 0x258, 8, 2, + CLK_MUX_HIWORD_MASK, }, +}; + +static const struct hisi_divider_clock hi3660_sctrl_divider_clks[] = { + { HI3660_CLK_DIV_AOBUS, "clk_div_aobus", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x254, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_PCLK_DIV_MMBUF, "pclk_div_mmbuf", "pclk_mmbuf_andgt", + CLK_SET_RATE_PARENT, 0x258, 10, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_ACLK_DIV_MMBUF, "aclk_div_mmbuf", "clk_mmbuf_pll_andgt", + CLK_SET_RATE_PARENT, 0x258, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3660_CLK_DIV_PCIEPHY, "clk_div_pciephy", "clk_gate_pciephy_gt", + CLK_SET_RATE_PARENT, 0x268, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, +}; + +/* clk_iomcu */ +static const struct hisi_gate_clock hi3660_iomcu_gate_sep_clks[] = { + { HI3660_CLK_I2C0_IOMCU, "clk_i2c0_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 3, 0, }, + { HI3660_CLK_I2C1_IOMCU, "clk_i2c1_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 4, 0, }, + { HI3660_CLK_I2C2_IOMCU, "clk_i2c2_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 5, 0, }, + { HI3660_CLK_I2C6_IOMCU, "clk_i2c6_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 27, 0, }, + { HI3660_CLK_IOMCU_PERI0, "iomcu_peri0", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x90, 0, 0, }, +}; + +static void hi3660_clk_iomcu_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3660_iomcu_gate_sep_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate_sep(hi3660_iomcu_gate_sep_clks, + ARRAY_SIZE(hi3660_iomcu_gate_sep_clks), + clk_data); +} + +static void hi3660_clk_pmuctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3660_pmu_gate_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate(hi3660_pmu_gate_clks, + ARRAY_SIZE(hi3660_pmu_gate_clks), clk_data); +} + +static void hi3660_clk_pctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3660_pctrl_gate_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + hisi_clk_register_gate(hi3660_pctrl_gate_clks, + ARRAY_SIZE(hi3660_pctrl_gate_clks), clk_data); +} + +static void hi3660_clk_sctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3660_sctrl_gate_clks) + + ARRAY_SIZE(hi3660_sctrl_gate_sep_clks) + + ARRAY_SIZE(hi3660_sctrl_mux_clks) + + ARRAY_SIZE(hi3660_sctrl_divider_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + hisi_clk_register_gate(hi3660_sctrl_gate_clks, + ARRAY_SIZE(hi3660_sctrl_gate_clks), clk_data); + hisi_clk_register_gate_sep(hi3660_sctrl_gate_sep_clks, + ARRAY_SIZE(hi3660_sctrl_gate_sep_clks), + clk_data); + hisi_clk_register_mux(hi3660_sctrl_mux_clks, + ARRAY_SIZE(hi3660_sctrl_mux_clks), clk_data); + hisi_clk_register_divider(hi3660_sctrl_divider_clks, + ARRAY_SIZE(hi3660_sctrl_divider_clks), + clk_data); +} + +static void hi3660_clk_crgctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3660_fixed_rate_clks) + + ARRAY_SIZE(hi3660_crgctrl_gate_sep_clks) + + ARRAY_SIZE(hi3660_crgctrl_gate_clks) + + ARRAY_SIZE(hi3660_crgctrl_mux_clks) + + ARRAY_SIZE(hi3660_crg_fixed_factor_clks) + + ARRAY_SIZE(hi3660_crgctrl_divider_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_fixed_rate(hi3660_fixed_rate_clks, + ARRAY_SIZE(hi3660_fixed_rate_clks), + clk_data); + hisi_clk_register_gate_sep(hi3660_crgctrl_gate_sep_clks, + ARRAY_SIZE(hi3660_crgctrl_gate_sep_clks), + clk_data); + hisi_clk_register_gate(hi3660_crgctrl_gate_clks, + ARRAY_SIZE(hi3660_crgctrl_gate_clks), + clk_data); + hisi_clk_register_mux(hi3660_crgctrl_mux_clks, + ARRAY_SIZE(hi3660_crgctrl_mux_clks), + clk_data); + hisi_clk_register_fixed_factor(hi3660_crg_fixed_factor_clks, + ARRAY_SIZE(hi3660_crg_fixed_factor_clks), + clk_data); + hisi_clk_register_divider(hi3660_crgctrl_divider_clks, + ARRAY_SIZE(hi3660_crgctrl_divider_clks), + clk_data); +} + +static const struct of_device_id hi3660_clk_match_table[] = { + { .compatible = "hisilicon,hi3660-crgctrl", + .data = hi3660_clk_crgctrl_init }, + { .compatible = "hisilicon,hi3660-pctrl", + .data = hi3660_clk_pctrl_init }, + { .compatible = "hisilicon,hi3660-pmuctrl", + .data = hi3660_clk_pmuctrl_init }, + { .compatible = "hisilicon,hi3660-sctrl", + .data = hi3660_clk_sctrl_init }, + { .compatible = "hisilicon,hi3660-iomcu", + .data = hi3660_clk_iomcu_init }, + { } +}; + +static int hi3660_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + void (*init_func)(struct device_node *np); + + init_func = of_device_get_match_data(dev); + if (!init_func) + return -ENODEV; + + init_func(np); + + return 0; +} + +static struct platform_driver hi3660_clk_driver = { + .probe = hi3660_clk_probe, + .driver = { + .name = "hi3660-clk", + .of_match_table = hi3660_clk_match_table, + }, +}; + +static int __init hi3660_clk_init(void) +{ + return platform_driver_register(&hi3660_clk_driver); +} +core_initcall(hi3660_clk_init); diff --git a/drivers/clk/hisilicon/clkgate-separated.c b/drivers/clk/hisilicon/clkgate-separated.c index a47812f56a17..7908bc3c9ec7 100644 --- a/drivers/clk/hisilicon/clkgate-separated.c +++ b/drivers/clk/hisilicon/clkgate-separated.c @@ -120,6 +120,7 @@ struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name, sclk->bit_idx = bit_idx; sclk->flags = clk_gate_flags; sclk->hw.init = &init; + sclk->lock = lock; clk = clk_register(dev, &sclk->hw); if (IS_ERR(clk)) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 42ffc1c92bab..c07df719b8a3 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -592,15 +592,20 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) imx6q_mmdc_ch1_mask_handshake(base); - /* - * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware - * bug. Set the muxes to the requested values before registering the - * ldb_di_sel clocks. - */ - init_ldb_clks(np, base); + if (clk_on_imx6qp()) { + clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); + clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); + } else { + /* + * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware + * bug. Set the muxes to the requested values before registering the + * ldb_di_sel clocks. + */ + init_ldb_clks(np, base); - clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); - clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + } clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index e7c7353a86fc..ae1d31be906e 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -803,6 +803,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0); clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0); clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0); + clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0); clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0); clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0); clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0); diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index ed3a2df536ea..f1099167ba31 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -21,6 +21,9 @@ #define PLL_NUM_OFFSET 0x10 #define PLL_DENOM_OFFSET 0x20 +#define PLL_VF610_NUM_OFFSET 0x20 +#define PLL_VF610_DENOM_OFFSET 0x30 + #define BM_PLL_POWER (0x1 << 12) #define BM_PLL_LOCK (0x1 << 31) #define IMX7_ENET_PLL_POWER (0x1 << 5) @@ -300,6 +303,99 @@ static const struct clk_ops clk_pllv3_av_ops = { .set_rate = clk_pllv3_av_set_rate, }; +struct clk_pllv3_vf610_mf { + u32 mfi; /* integer part, can be 20 or 22 */ + u32 mfn; /* numerator, 30-bit value */ + u32 mfd; /* denominator, 30-bit value, must be less than mfn */ +}; + +static unsigned long clk_pllv3_vf610_mf_to_rate(unsigned long parent_rate, + struct clk_pllv3_vf610_mf mf) +{ + u64 temp64; + + temp64 = parent_rate; + temp64 *= mf.mfn; + do_div(temp64, mf.mfd); + + return (parent_rate * mf.mfi) + temp64; +} + +static struct clk_pllv3_vf610_mf clk_pllv3_vf610_rate_to_mf( + unsigned long parent_rate, unsigned long rate) +{ + struct clk_pllv3_vf610_mf mf; + u64 temp64; + + mf.mfi = (rate >= 22 * parent_rate) ? 22 : 20; + mf.mfd = 0x3fffffff; /* use max supported value for best accuracy */ + + if (rate <= parent_rate * mf.mfi) + mf.mfn = 0; + else if (rate >= parent_rate * (mf.mfi + 1)) + mf.mfn = mf.mfd - 1; + else { + /* rate = parent_rate * (mfi + mfn/mfd) */ + temp64 = rate - parent_rate * mf.mfi; + temp64 *= mf.mfd; + do_div(temp64, parent_rate); + mf.mfn = temp64; + } + + return mf; +} + +static unsigned long clk_pllv3_vf610_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + 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.mfi = (readl_relaxed(pll->base) & pll->div_mask) ? 22 : 20; + + return clk_pllv3_vf610_mf_to_rate(parent_rate, mf); +} + +static long clk_pllv3_vf610_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_pllv3_vf610_mf mf = clk_pllv3_vf610_rate_to_mf(*prate, rate); + + return clk_pllv3_vf610_mf_to_rate(*prate, mf); +} + +static int clk_pllv3_vf610_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + struct clk_pllv3_vf610_mf mf = + clk_pllv3_vf610_rate_to_mf(parent_rate, rate); + u32 val; + + val = readl_relaxed(pll->base); + if (mf.mfi == 20) + val &= ~pll->div_mask; /* clear bit for mfi=20 */ + else + 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); + + return clk_pllv3_wait_lock(pll); +} + +static const struct clk_ops clk_pllv3_vf610_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .is_prepared = clk_pllv3_is_prepared, + .recalc_rate = clk_pllv3_vf610_recalc_rate, + .round_rate = clk_pllv3_vf610_round_rate, + .set_rate = clk_pllv3_vf610_set_rate, +}; + static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -334,6 +430,9 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, case IMX_PLLV3_SYS: ops = &clk_pllv3_sys_ops; break; + case IMX_PLLV3_SYS_VF610: + ops = &clk_pllv3_vf610_ops; + break; case IMX_PLLV3_USB_VF610: pll->div_shift = 1; case IMX_PLLV3_USB: diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 0476353ab423..59b1863deb88 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -219,8 +219,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", PLL6_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); clk[VF610_CLK_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", PLL7_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1); - clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1); + clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS_VF610, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1); + clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_SYS_VF610, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1); clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll3", "pll3_bypass_src", PLL3_CTRL, 0x2); clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f); clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 4afad3b96a61..e1f5e425db73 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -34,6 +34,7 @@ enum imx_pllv3_type { IMX_PLLV3_AV, IMX_PLLV3_ENET, IMX_PLLV3_ENET_IMX7, + IMX_PLLV3_SYS_VF610, }; struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 0bd631a41f6a..a01ef7806aed 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -8,52 +8,53 @@ config COMMON_CLK_MEDIATEK config COMMON_CLK_MT2701 bool "Clock driver for Mediatek MT2701" + depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK - default ARCH_MEDIATEK + default ARCH_MEDIATEK && ARM ---help--- This driver supports Mediatek MT2701 basic clocks. config COMMON_CLK_MT2701_MMSYS bool "Clock driver for Mediatek MT2701 mmsys" - select COMMON_CLK_MT2701 + depends on COMMON_CLK_MT2701 ---help--- This driver supports Mediatek MT2701 mmsys clocks. config COMMON_CLK_MT2701_IMGSYS bool "Clock driver for Mediatek MT2701 imgsys" - select COMMON_CLK_MT2701 + depends on COMMON_CLK_MT2701 ---help--- This driver supports Mediatek MT2701 imgsys clocks. config COMMON_CLK_MT2701_VDECSYS bool "Clock driver for Mediatek MT2701 vdecsys" - select COMMON_CLK_MT2701 + depends on COMMON_CLK_MT2701 ---help--- This driver supports Mediatek MT2701 vdecsys clocks. config COMMON_CLK_MT2701_HIFSYS bool "Clock driver for Mediatek MT2701 hifsys" - select COMMON_CLK_MT2701 + depends on COMMON_CLK_MT2701 ---help--- This driver supports Mediatek MT2701 hifsys clocks. config COMMON_CLK_MT2701_ETHSYS bool "Clock driver for Mediatek MT2701 ethsys" - select COMMON_CLK_MT2701 + depends on COMMON_CLK_MT2701 ---help--- This driver supports Mediatek MT2701 ethsys clocks. config COMMON_CLK_MT2701_BDPSYS bool "Clock driver for Mediatek MT2701 bdpsys" - select COMMON_CLK_MT2701 + depends on COMMON_CLK_MT2701 ---help--- This driver supports Mediatek MT2701 bdpsys clocks. config COMMON_CLK_MT8135 bool "Clock driver for Mediatek MT8135" - depends on ARCH_MEDIATEK || COMPILE_TEST + depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK - default ARCH_MEDIATEK + default ARCH_MEDIATEK && ARM ---help--- This driver supports Mediatek MT8135 clocks. diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 3f1be46cbb33..888494d4fb8a 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -607,7 +607,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) /* Populate the base address for the MPEG clks */ meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg; meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; - meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; /* Populate base address for gates */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++) diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c index 8181b919f062..f17702107ac5 100644 --- a/drivers/clk/mvebu/ap806-system-controller.c +++ b/drivers/clk/mvebu/ap806-system-controller.c @@ -55,21 +55,39 @@ static int ap806_syscon_clk_probe(struct platform_device *pdev) freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK; switch (freq_mode) { - case 0x0 ... 0x5: + case 0x0: + case 0x1: cpuclk_freq = 2000; break; - case 0x6 ... 0xB: + case 0x6: + case 0x7: cpuclk_freq = 1800; break; - case 0xC ... 0x11: + case 0x4: + case 0xB: + case 0xD: cpuclk_freq = 1600; break; - case 0x12 ... 0x16: + case 0x1a: cpuclk_freq = 1400; break; - case 0x17 ... 0x19: + case 0x14: + case 0x17: cpuclk_freq = 1300; break; + case 0x19: + cpuclk_freq = 1200; + break; + case 0x13: + case 0x1d: + cpuclk_freq = 1000; + break; + case 0x1c: + cpuclk_freq = 800; + break; + case 0x1b: + cpuclk_freq = 600; + break; default: dev_err(&pdev->dev, "invalid SAR value\n"); return -EINVAL; diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index b3094315a3c0..890a863ae0d0 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -52,6 +52,12 @@ static u32 __init axp_get_tclk_freq(void __iomem *sar) return 250000000; } +/* MV98DX3236 TCLK frequency is fixed to 200MHz */ +static u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar) +{ + return 200000000; +} + static const u32 axp_cpu_freqs[] __initconst = { 1000000000, 1066000000, @@ -89,6 +95,12 @@ static u32 __init axp_get_cpu_freq(void __iomem *sar) return cpu_freq; } +/* MV98DX3236 CLK frequency is fixed to 800MHz */ +static u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar) +{ + return 800000000; +} + static const int axp_nbclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 1}, {2, 3}, @@ -158,6 +170,11 @@ static const struct coreclk_soc_desc axp_coreclks = { .num_ratios = ARRAY_SIZE(axp_coreclk_ratios), }; +static const struct coreclk_soc_desc mv98dx3236_coreclks = { + .get_tclk_freq = mv98dx3236_get_tclk_freq, + .get_cpu_freq = mv98dx3236_get_cpu_freq, +}; + /* * Clock Gating Control */ @@ -195,6 +212,15 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = { { } }; +static const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = { + { "ge1", NULL, 3, 0 }, + { "ge0", NULL, 4, 0 }, + { "pex00", NULL, 5, 0 }, + { "sdio", NULL, 17, 0 }, + { "xor0", NULL, 22, 0 }, + { } +}; + static void __init axp_clk_init(struct device_node *np) { struct device_node *cgnp = @@ -206,3 +232,16 @@ static void __init axp_clk_init(struct device_node *np) mvebu_clk_gating_setup(cgnp, axp_gating_desc); } CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); + +static void __init mv98dx3236_clk_init(struct device_node *np) +{ + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock"); + + mvebu_coreclk_setup(np, &mv98dx3236_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); +} +CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", + mv98dx3236_clk_init); diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c index d1e5863d3375..8491979f4096 100644 --- a/drivers/clk/mvebu/clk-corediv.c +++ b/drivers/clk/mvebu/clk-corediv.c @@ -71,6 +71,10 @@ static const struct clk_corediv_desc mvebu_corediv_desc[] = { { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ }; +static const struct clk_corediv_desc mv98dx3236_corediv_desc[] = { + { .mask = 0x0f, .offset = 6, .fieldbit = 26 }, /* NAND clock */ +}; + #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) static int clk_corediv_is_enabled(struct clk_hw *hwclk) @@ -232,6 +236,18 @@ static const struct clk_corediv_soc_desc armada375_corediv_soc = { .ratio_offset = 0x4, }; +static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = { + .descs = mv98dx3236_corediv_desc, + .ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc), + .ops = { + .recalc_rate = clk_corediv_recalc_rate, + .round_rate = clk_corediv_round_rate, + .set_rate = clk_corediv_set_rate, + }, + .ratio_reload = BIT(10), + .ratio_offset = 0x8, +}; + static void __init mvebu_corediv_clk_init(struct device_node *node, const struct clk_corediv_soc_desc *soc_desc) @@ -313,3 +329,10 @@ static void __init armada380_corediv_clk_init(struct device_node *node) } CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock", armada380_corediv_clk_init); + +static void __init mv98dx3236_corediv_clk_init(struct device_node *node) +{ + return mvebu_corediv_clk_init(node, &mv98dx3236_corediv_soc); +} +CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock", + mv98dx3236_corediv_clk_init); diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index 5837eb8a212f..044892b6534d 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -245,3 +245,11 @@ cpuclk_out: CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock", of_cpu_clk_setup); + +static void __init of_mv98dx3236_cpu_clk_setup(struct device_node *node) +{ + of_clk_add_provider(node, of_clk_src_simple_get, NULL); +} + +CLK_OF_DECLARE(mv98dx3236_cpu_clock, "marvell,mv98dx3236-cpu-clock", + of_mv98dx3236_cpu_clk_setup); diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 07e2cc6ed781..3487c267833e 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -462,8 +462,79 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = { .num_clks = ARRAY_SIZE(msm8916_clks), }; +/* msm8974 */ +DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2); +DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3); +DEFINE_CLK_SMD_RPM(msm8974, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2); +DEFINE_CLK_SMD_RPM_QDSS(msm8974, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a1, cxo_a1_a, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a2, cxo_a2_a, 6); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, diff_clk, diff_a_clk, 7); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk1, div_a_clk1, 11); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk2, div_a_clk2, 12); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d0_pin, cxo_d0_a_pin, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d1_pin, cxo_d1_a_pin, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a0_pin, cxo_a0_a_pin, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6); + +static struct clk_smd_rpm *msm8974_clks[] = { + [RPM_SMD_PNOC_CLK] = &msm8974_pnoc_clk, + [RPM_SMD_PNOC_A_CLK] = &msm8974_pnoc_a_clk, + [RPM_SMD_SNOC_CLK] = &msm8974_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8974_snoc_a_clk, + [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk, + [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk, + [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk, + [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk, + [RPM_SMD_BIMC_CLK] = &msm8974_bimc_clk, + [RPM_SMD_BIMC_A_CLK] = &msm8974_bimc_a_clk, + [RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk, + [RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8974_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8974_qdss_a_clk, + [RPM_SMD_CXO_D0] = &msm8974_cxo_d0, + [RPM_SMD_CXO_D0_A] = &msm8974_cxo_d0_a, + [RPM_SMD_CXO_D1] = &msm8974_cxo_d1, + [RPM_SMD_CXO_D1_A] = &msm8974_cxo_d1_a, + [RPM_SMD_CXO_A0] = &msm8974_cxo_a0, + [RPM_SMD_CXO_A0_A] = &msm8974_cxo_a0_a, + [RPM_SMD_CXO_A1] = &msm8974_cxo_a1, + [RPM_SMD_CXO_A1_A] = &msm8974_cxo_a1_a, + [RPM_SMD_CXO_A2] = &msm8974_cxo_a2, + [RPM_SMD_CXO_A2_A] = &msm8974_cxo_a2_a, + [RPM_SMD_DIFF_CLK] = &msm8974_diff_clk, + [RPM_SMD_DIFF_A_CLK] = &msm8974_diff_a_clk, + [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1, + [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1, + [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2, + [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2, + [RPM_SMD_CXO_D0_PIN] = &msm8974_cxo_d0_pin, + [RPM_SMD_CXO_D0_A_PIN] = &msm8974_cxo_d0_a_pin, + [RPM_SMD_CXO_D1_PIN] = &msm8974_cxo_d1_pin, + [RPM_SMD_CXO_D1_A_PIN] = &msm8974_cxo_d1_a_pin, + [RPM_SMD_CXO_A0_PIN] = &msm8974_cxo_a0_pin, + [RPM_SMD_CXO_A0_A_PIN] = &msm8974_cxo_a0_a_pin, + [RPM_SMD_CXO_A1_PIN] = &msm8974_cxo_a1_pin, + [RPM_SMD_CXO_A1_A_PIN] = &msm8974_cxo_a1_a_pin, + [RPM_SMD_CXO_A2_PIN] = &msm8974_cxo_a2_pin, + [RPM_SMD_CXO_A2_A_PIN] = &msm8974_cxo_a2_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8974 = { + .clks = msm8974_clks, + .num_clks = ARRAY_SIZE(msm8974_clks), +}; static const struct of_device_id rpm_smd_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, + { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, { } }; MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table); diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index 33d09138f5e5..46cb256b4aa2 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -20,6 +20,9 @@ #include <linux/clk-provider.h> #include <linux/regmap.h> #include <linux/reset-controller.h> +#include <linux/math64.h> +#include <linux/delay.h> +#include <linux/clk.h> #include <dt-bindings/clock/qcom,gcc-ipq4019.h> @@ -28,6 +31,13 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "clk-regmap-divider.h" + +#define to_clk_regmap_div(_hw) container_of(to_clk_regmap(_hw),\ + struct clk_regmap_div, clkr) + +#define to_clk_fepll(_hw) container_of(to_clk_regmap_div(_hw),\ + struct clk_fepll, cdiv) enum { P_XO, @@ -40,6 +50,41 @@ enum { P_DDRPLLAPSS, }; +/* + * struct clk_fepll_vco - vco feedback divider corresponds for FEPLL clocks + * @fdbkdiv_shift: lowest bit for FDBKDIV + * @fdbkdiv_width: number of bits in FDBKDIV + * @refclkdiv_shift: lowest bit for REFCLKDIV + * @refclkdiv_width: number of bits in REFCLKDIV + * @reg: PLL_DIV register address + */ +struct clk_fepll_vco { + u32 fdbkdiv_shift; + u32 fdbkdiv_width; + u32 refclkdiv_shift; + u32 refclkdiv_width; + u32 reg; +}; + +/* + * struct clk_fepll - clk divider corresponds to FEPLL clocks + * @fixed_div: fixed divider value if divider is fixed + * @parent_map: map from software's parent index to hardware's src_sel field + * @cdiv: divider values for PLL_DIV + * @pll_vco: vco feedback divider + * @div_table: mapping for actual divider value to register divider value + * in case of non fixed divider + * @freq_tbl: frequency table + */ +struct clk_fepll { + u32 fixed_div; + const u8 *parent_map; + struct clk_regmap_div cdiv; + const struct clk_fepll_vco *pll_vco; + const struct clk_div_table *div_table; + const struct freq_tbl *freq_tbl; +}; + static struct parent_map gcc_xo_200_500_map[] = { { P_XO, 0 }, { P_FEPLL200, 1 }, @@ -80,7 +125,7 @@ static struct parent_map gcc_xo_sdcc1_500_map[] = { static const char * const gcc_xo_sdcc1_500[] = { "xo", - "ddrpll", + "ddrpllsdcc", "fepll500", }; @@ -121,6 +166,12 @@ static struct parent_map gcc_xo_ddr_500_200_map[] = { { P_DDRPLLAPSS, 1 }, }; +/* + * Contains index for safe clock during APSS freq change. + * fepll500 is being used as safe clock so initialize it + * with its index in parents list gcc_xo_ddr_500_200. + */ +static const int gcc_ipq4019_cpu_safe_parent = 2; static const char * const gcc_xo_ddr_500_200[] = { "xo", "fepll200", @@ -505,7 +556,7 @@ static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = { F(25000000, P_FEPLL500, 1, 1, 20), F(50000000, P_FEPLL500, 1, 1, 10), F(100000000, P_FEPLL500, 1, 1, 5), - F(193000000, P_DDRPLL, 1, 0, 0), + F(192000000, P_DDRPLL, 1, 0, 0), { } }; @@ -524,10 +575,20 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { }; static const struct freq_tbl ftbl_gcc_apps_clk[] = { - F(48000000, P_XO, 1, 0, 0), + F(48000000, P_XO, 1, 0, 0), F(200000000, P_FEPLL200, 1, 0, 0), + F(384000000, P_DDRPLLAPSS, 1, 0, 0), + F(413000000, P_DDRPLLAPSS, 1, 0, 0), + F(448000000, P_DDRPLLAPSS, 1, 0, 0), + F(488000000, P_DDRPLLAPSS, 1, 0, 0), F(500000000, P_FEPLL500, 1, 0, 0), - F(626000000, P_DDRPLLAPSS, 1, 0, 0), + F(512000000, P_DDRPLLAPSS, 1, 0, 0), + F(537000000, P_DDRPLLAPSS, 1, 0, 0), + F(565000000, P_DDRPLLAPSS, 1, 0, 0), + F(597000000, P_DDRPLLAPSS, 1, 0, 0), + F(632000000, P_DDRPLLAPSS, 1, 0, 0), + F(672000000, P_DDRPLLAPSS, 1, 0, 0), + F(716000000, P_DDRPLLAPSS, 1, 0, 0), { } }; @@ -541,6 +602,7 @@ static struct clk_rcg2 apps_clk_src = { .parent_names = gcc_xo_ddr_500_200, .num_parents = 4, .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -1154,6 +1216,364 @@ static struct clk_branch gcc_wcss5g_rtc_clk = { }, }; +/* Calculates the VCO rate for FEPLL. */ +static u64 clk_fepll_vco_calc_rate(struct clk_fepll *pll_div, + unsigned long parent_rate) +{ + const struct clk_fepll_vco *pll_vco = pll_div->pll_vco; + u32 fdbkdiv, refclkdiv, cdiv; + u64 vco; + + regmap_read(pll_div->cdiv.clkr.regmap, pll_vco->reg, &cdiv); + refclkdiv = (cdiv >> pll_vco->refclkdiv_shift) & + (BIT(pll_vco->refclkdiv_width) - 1); + fdbkdiv = (cdiv >> pll_vco->fdbkdiv_shift) & + (BIT(pll_vco->fdbkdiv_width) - 1); + + vco = parent_rate / refclkdiv; + vco *= 2; + vco *= fdbkdiv; + + return vco; +} + +static const struct clk_fepll_vco gcc_apss_ddrpll_vco = { + .fdbkdiv_shift = 16, + .fdbkdiv_width = 8, + .refclkdiv_shift = 24, + .refclkdiv_width = 5, + .reg = 0x2e020, +}; + +static const struct clk_fepll_vco gcc_fepll_vco = { + .fdbkdiv_shift = 16, + .fdbkdiv_width = 8, + .refclkdiv_shift = 24, + .refclkdiv_width = 5, + .reg = 0x2f020, +}; + +/* + * Round rate function for APSS CPU PLL Clock divider. + * It looks up the frequency table and returns the next higher frequency + * supported in hardware. + */ +static long clk_cpu_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate) +{ + struct clk_fepll *pll = to_clk_fepll(hw); + struct clk_hw *p_hw; + const struct freq_tbl *f; + + f = qcom_find_freq(pll->freq_tbl, rate); + if (!f) + return -EINVAL; + + p_hw = clk_hw_get_parent_by_index(hw, f->src); + *p_rate = clk_hw_get_rate(p_hw); + + return f->freq; +}; + +/* + * Clock set rate function for APSS CPU PLL Clock divider. + * It looks up the frequency table and updates the PLL divider to corresponding + * divider value. + */ +static int clk_cpu_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_fepll *pll = to_clk_fepll(hw); + const struct freq_tbl *f; + u32 mask; + int ret; + + f = qcom_find_freq(pll->freq_tbl, rate); + if (!f) + return -EINVAL; + + mask = (BIT(pll->cdiv.width) - 1) << pll->cdiv.shift; + ret = regmap_update_bits(pll->cdiv.clkr.regmap, + pll->cdiv.reg, mask, + f->pre_div << pll->cdiv.shift); + /* + * There is no status bit which can be checked for successful CPU + * divider update operation so using delay for the same. + */ + udelay(1); + + return 0; +}; + +/* + * Clock frequency calculation function for APSS CPU PLL Clock divider. + * This clock divider is nonlinear so this function calculates the actual + * divider and returns the output frequency by dividing VCO Frequency + * with this actual divider value. + */ +static unsigned long +clk_cpu_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fepll *pll = to_clk_fepll(hw); + u32 cdiv, pre_div; + u64 rate; + + regmap_read(pll->cdiv.clkr.regmap, pll->cdiv.reg, &cdiv); + cdiv = (cdiv >> pll->cdiv.shift) & (BIT(pll->cdiv.width) - 1); + + /* + * Some dividers have value in 0.5 fraction so multiply both VCO + * frequency(parent_rate) and pre_div with 2 to make integer + * calculation. + */ + if (cdiv > 10) + pre_div = (cdiv + 1) * 2; + else + pre_div = cdiv + 12; + + rate = clk_fepll_vco_calc_rate(pll, parent_rate) * 2; + do_div(rate, pre_div); + + return rate; +}; + +static const struct clk_ops clk_regmap_cpu_div_ops = { + .round_rate = clk_cpu_div_round_rate, + .set_rate = clk_cpu_div_set_rate, + .recalc_rate = clk_cpu_div_recalc_rate, +}; + +static const struct freq_tbl ftbl_apss_ddr_pll[] = { + { 384000000, P_XO, 0xd, 0, 0 }, + { 413000000, P_XO, 0xc, 0, 0 }, + { 448000000, P_XO, 0xb, 0, 0 }, + { 488000000, P_XO, 0xa, 0, 0 }, + { 512000000, P_XO, 0x9, 0, 0 }, + { 537000000, P_XO, 0x8, 0, 0 }, + { 565000000, P_XO, 0x7, 0, 0 }, + { 597000000, P_XO, 0x6, 0, 0 }, + { 632000000, P_XO, 0x5, 0, 0 }, + { 672000000, P_XO, 0x4, 0, 0 }, + { 716000000, P_XO, 0x3, 0, 0 }, + { 768000000, P_XO, 0x2, 0, 0 }, + { 823000000, P_XO, 0x1, 0, 0 }, + { 896000000, P_XO, 0x0, 0, 0 }, + { } +}; + +static struct clk_fepll gcc_apss_cpu_plldiv_clk = { + .cdiv.reg = 0x2e020, + .cdiv.shift = 4, + .cdiv.width = 4, + .cdiv.clkr = { + .enable_reg = 0x2e000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "ddrpllapss", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_regmap_cpu_div_ops, + }, + }, + .freq_tbl = ftbl_apss_ddr_pll, + .pll_vco = &gcc_apss_ddrpll_vco, +}; + +/* Calculates the rate for PLL divider. + * If the divider value is not fixed then it gets the actual divider value + * from divider table. Then, it calculate the clock rate by dividing the + * parent rate with actual divider value. + */ +static unsigned long +clk_regmap_clk_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fepll *pll = to_clk_fepll(hw); + u32 cdiv, pre_div = 1; + u64 rate; + const struct clk_div_table *clkt; + + if (pll->fixed_div) { + pre_div = pll->fixed_div; + } else { + regmap_read(pll->cdiv.clkr.regmap, pll->cdiv.reg, &cdiv); + cdiv = (cdiv >> pll->cdiv.shift) & (BIT(pll->cdiv.width) - 1); + + for (clkt = pll->div_table; clkt->div; clkt++) { + if (clkt->val == cdiv) + pre_div = clkt->div; + } + } + + rate = clk_fepll_vco_calc_rate(pll, parent_rate); + do_div(rate, pre_div); + + return rate; +}; + +static const struct clk_ops clk_fepll_div_ops = { + .recalc_rate = clk_regmap_clk_div_recalc_rate, +}; + +static struct clk_fepll gcc_apss_sdcc_clk = { + .fixed_div = 28, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "ddrpllsdcc", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .pll_vco = &gcc_apss_ddrpll_vco, +}; + +static struct clk_fepll gcc_fepll125_clk = { + .fixed_div = 32, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "fepll125", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .pll_vco = &gcc_fepll_vco, +}; + +static struct clk_fepll gcc_fepll125dly_clk = { + .fixed_div = 32, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "fepll125dly", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .pll_vco = &gcc_fepll_vco, +}; + +static struct clk_fepll gcc_fepll200_clk = { + .fixed_div = 20, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "fepll200", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .pll_vco = &gcc_fepll_vco, +}; + +static struct clk_fepll gcc_fepll500_clk = { + .fixed_div = 8, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "fepll500", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .pll_vco = &gcc_fepll_vco, +}; + +static const struct clk_div_table fepllwcss_clk_div_table[] = { + { 0, 15 }, + { 1, 16 }, + { 2, 18 }, + { 3, 20 }, + { }, +}; + +static struct clk_fepll gcc_fepllwcss2g_clk = { + .cdiv.reg = 0x2f020, + .cdiv.shift = 8, + .cdiv.width = 2, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "fepllwcss2g", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .div_table = fepllwcss_clk_div_table, + .pll_vco = &gcc_fepll_vco, +}; + +static struct clk_fepll gcc_fepllwcss5g_clk = { + .cdiv.reg = 0x2f020, + .cdiv.shift = 12, + .cdiv.width = 2, + .cdiv.clkr = { + .hw.init = &(struct clk_init_data){ + .name = "fepllwcss5g", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_fepll_div_ops, + }, + }, + .div_table = fepllwcss_clk_div_table, + .pll_vco = &gcc_fepll_vco, +}; + +static const struct freq_tbl ftbl_gcc_pcnoc_ahb_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(100000000, P_FEPLL200, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcnoc_ahb_clk_src = { + .cmd_rcgr = 0x21024, + .hid_width = 5, + .parent_map = gcc_xo_200_500_map, + .freq_tbl = ftbl_gcc_pcnoc_ahb_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcnoc_ahb_clk_src", + .parent_names = gcc_xo_200_500, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch pcnoc_clk_src = { + .halt_reg = 0x21030, + .clkr = { + .enable_reg = 0x21030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "pcnoc_clk_src", + .parent_names = (const char *[]){ + "gcc_pcnoc_ahb_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT | + CLK_IS_CRITICAL, + }, + }, +}; + static struct clk_regmap *gcc_ipq4019_clocks[] = { [AUDIO_CLK_SRC] = &audio_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, @@ -1214,6 +1634,16 @@ static struct clk_regmap *gcc_ipq4019_clocks[] = { [GCC_WCSS5G_CLK] = &gcc_wcss5g_clk.clkr, [GCC_WCSS5G_REF_CLK] = &gcc_wcss5g_ref_clk.clkr, [GCC_WCSS5G_RTC_CLK] = &gcc_wcss5g_rtc_clk.clkr, + [GCC_SDCC_PLLDIV_CLK] = &gcc_apss_sdcc_clk.cdiv.clkr, + [GCC_FEPLL125_CLK] = &gcc_fepll125_clk.cdiv.clkr, + [GCC_FEPLL125DLY_CLK] = &gcc_fepll125dly_clk.cdiv.clkr, + [GCC_FEPLL200_CLK] = &gcc_fepll200_clk.cdiv.clkr, + [GCC_FEPLL500_CLK] = &gcc_fepll500_clk.cdiv.clkr, + [GCC_FEPLL_WCSS2G_CLK] = &gcc_fepllwcss2g_clk.cdiv.clkr, + [GCC_FEPLL_WCSS5G_CLK] = &gcc_fepllwcss5g_clk.cdiv.clkr, + [GCC_APSS_CPU_PLLDIV_CLK] = &gcc_apss_cpu_plldiv_clk.cdiv.clkr, + [GCC_PCNOC_AHB_CLK_SRC] = &gcc_pcnoc_ahb_clk_src.clkr, + [GCC_PCNOC_AHB_CLK] = &pcnoc_clk_src.clkr, }; static const struct qcom_reset_map gcc_ipq4019_resets[] = { @@ -1294,7 +1724,7 @@ static const struct regmap_config gcc_ipq4019_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x2dfff, + .max_register = 0x2ffff, .fast_io = true, }; @@ -1312,23 +1742,44 @@ static const struct of_device_id gcc_ipq4019_match_table[] = { }; MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table); +static int +gcc_ipq4019_cpu_clk_notifier_fn(struct notifier_block *nb, + unsigned long action, void *data) +{ + int err = 0; + + if (action == PRE_RATE_CHANGE) + err = clk_rcg2_ops.set_parent(&apps_clk_src.clkr.hw, + gcc_ipq4019_cpu_safe_parent); + + return notifier_from_errno(err); +} + +static struct notifier_block gcc_ipq4019_cpu_clk_notifier = { + .notifier_call = gcc_ipq4019_cpu_clk_notifier_fn, +}; + static int gcc_ipq4019_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; + int err; - clk_register_fixed_rate(dev, "fepll125", "xo", 0, 200000000); - clk_register_fixed_rate(dev, "fepll125dly", "xo", 0, 200000000); - clk_register_fixed_rate(dev, "fepllwcss2g", "xo", 0, 200000000); - clk_register_fixed_rate(dev, "fepllwcss5g", "xo", 0, 200000000); - clk_register_fixed_rate(dev, "fepll200", "xo", 0, 200000000); - clk_register_fixed_rate(dev, "fepll500", "xo", 0, 200000000); - clk_register_fixed_rate(dev, "ddrpllapss", "xo", 0, 666000000); + err = qcom_cc_probe(pdev, &gcc_ipq4019_desc); + if (err) + return err; - return qcom_cc_probe(pdev, &gcc_ipq4019_desc); + return clk_notifier_register(apps_clk_src.clkr.hw.clk, + &gcc_ipq4019_cpu_clk_notifier); +} + +static int gcc_ipq4019_remove(struct platform_device *pdev) +{ + return clk_notifier_unregister(apps_clk_src.clkr.hw.clk, + &gcc_ipq4019_cpu_clk_notifier); } static struct platform_driver gcc_ipq4019_driver = { .probe = gcc_ipq4019_probe, + .remove = gcc_ipq4019_remove, .driver = { .name = "qcom,gcc-ipq4019", .of_match_table = gcc_ipq4019_match_table, diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c index 581a17f67379..b99dd406e907 100644 --- a/drivers/clk/qcom/gcc-mdm9615.c +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -1563,6 +1563,34 @@ static struct clk_branch rpm_msg_ram_h_clk = { }, }; +static struct clk_branch ebi2_clk = { + .hwcg_reg = 0x2664, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 24, + .clkr = { + .enable_reg = 0x2664, + .enable_mask = BIT(6) | BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "ebi2_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch ebi2_aon_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 23, + .clkr = { + .enable_reg = 0x2664, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "ebi2_aon_clk", + .ops = &clk_branch_ops, + }, + }, +}; + static struct clk_hw *gcc_mdm9615_hws[] = { &cxo.hw, }; @@ -1637,6 +1665,8 @@ static struct clk_regmap *gcc_mdm9615_clks[] = { [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr, [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr, [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr, + [EBI2_CLK] = &ebi2_clk.clkr, + [EBI2_AON_CLK] = &ebi2_aon_clk.clkr, }; static const struct qcom_reset_map gcc_mdm9615_resets[] = { diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 4b1fc1730d29..8abc200d4fd3 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -3448,6 +3448,7 @@ static const struct qcom_reset_map gcc_msm8996_resets[] = { [GCC_MSMPU_BCR] = { 0x8d000 }, [GCC_MSS_Q6_BCR] = { 0x8e000 }, [GCC_QREFS_VBG_CAL_BCR] = { 0x88020 }, + [GCC_MSS_RESTART] = { 0x8f008 }, }; static const struct regmap_config gcc_msm8996_regmap_config = { diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index 288186cce0ae..a4f3580587b7 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -63,11 +63,26 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en) return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val); } +static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en) +{ + ktime_t start; + + start = ktime_get(); + do { + if (gdsc_is_enabled(sc, reg) == en) + return 0; + } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US); + + if (gdsc_is_enabled(sc, reg) == en) + return 0; + + return -ETIMEDOUT; +} + static int gdsc_toggle_logic(struct gdsc *sc, bool en) { int ret; u32 val = en ? 0 : SW_COLLAPSE_MASK; - ktime_t start; unsigned int status_reg = sc->gdscr; ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val); @@ -100,16 +115,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en) udelay(1); } - start = ktime_get(); - do { - if (gdsc_is_enabled(sc, status_reg) == en) - return 0; - } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US); - - if (gdsc_is_enabled(sc, status_reg) == en) - return 0; - - return -ETIMEDOUT; + return gdsc_poll_status(sc, status_reg, en); } static inline int gdsc_deassert_reset(struct gdsc *sc) @@ -188,8 +194,20 @@ static int gdsc_enable(struct generic_pm_domain *domain) udelay(1); /* Turn on HW trigger mode if supported */ - if (sc->flags & HW_CTRL) - return gdsc_hwctrl(sc, true); + if (sc->flags & HW_CTRL) { + ret = gdsc_hwctrl(sc, true); + if (ret) + return ret; + /* + * Wait for the GDSC to go through a power down and + * up cycle. In case a firmware ends up polling status + * bits for the gdsc, it might read an 'on' status before + * the GDSC can finish the power cycle. + * We wait 1us before returning to ensure the firmware + * can't immediately poll the status bits. + */ + udelay(1); + } return 0; } @@ -204,9 +222,23 @@ static int gdsc_disable(struct generic_pm_domain *domain) /* Turn off HW trigger mode if supported */ if (sc->flags & HW_CTRL) { + unsigned int reg; + ret = gdsc_hwctrl(sc, false); if (ret < 0) return ret; + /* + * Wait for the GDSC to go through a power down and + * up cycle. In case we end up polling status + * bits for the gdsc before the power cycle is completed + * it might read an 'on' status wrongly. + */ + udelay(1); + + reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; + ret = gdsc_poll_status(sc, reg, true); + if (ret) + return ret; } if (sc->pwrsts & PWRSTS_OFF) diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 93506251f7ed..3ce819c26077 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -37,12 +37,14 @@ * @smstpcr: module stop control register * @mstpsr: module stop status register (optional) * @lock: protects writes to SMSTPCR + * @width_8bit: registers are 8-bit, not 32-bit */ struct mstp_clock_group { struct clk_onecell_data data; void __iomem *smstpcr; void __iomem *mstpsr; spinlock_t lock; + bool width_8bit; }; /** @@ -59,6 +61,18 @@ struct mstp_clock { #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) +static inline u32 cpg_mstp_read(struct mstp_clock_group *group, + u32 __iomem *reg) +{ + return group->width_8bit ? readb(reg) : clk_readl(reg); +} + +static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val, + u32 __iomem *reg) +{ + group->width_8bit ? writeb(val, reg) : clk_writel(val, reg); +} + static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) { struct mstp_clock *clock = to_mstp_clock(hw); @@ -70,12 +84,12 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) spin_lock_irqsave(&group->lock, flags); - value = clk_readl(group->smstpcr); + value = cpg_mstp_read(group, group->smstpcr); if (enable) value &= ~bitmask; else value |= bitmask; - clk_writel(value, group->smstpcr); + cpg_mstp_write(group, value, group->smstpcr); spin_unlock_irqrestore(&group->lock, flags); @@ -83,7 +97,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) return 0; for (i = 1000; i > 0; --i) { - if (!(clk_readl(group->mstpsr) & bitmask)) + if (!(cpg_mstp_read(group, group->mstpsr) & bitmask)) break; cpu_relax(); } @@ -114,9 +128,9 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) u32 value; if (group->mstpsr) - value = clk_readl(group->mstpsr); + value = cpg_mstp_read(group, group->mstpsr); else - value = clk_readl(group->smstpcr); + value = cpg_mstp_read(group, group->smstpcr); return !(value & BIT(clock->bit_index)); } @@ -193,6 +207,9 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) return; } + if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks")) + group->width_8bit = true; + for (i = 0; i < MSTP_MAX_CLOCKS; ++i) clks[i] = ERR_PTR(-ENOENT); diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 16e098c36f90..141971488f40 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-muxgrf.o obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o @@ -16,5 +17,6 @@ obj-y += clk-rk3036.o obj-y += clk-rk3188.o obj-y += clk-rk3228.o obj-y += clk-rk3288.o +obj-y += clk-rk3328.o obj-y += clk-rk3368.o obj-y += clk-rk3399.o diff --git a/drivers/clk/rockchip/clk-muxgrf.c b/drivers/clk/rockchip/clk-muxgrf.c new file mode 100644 index 000000000000..4f291180a26b --- /dev/null +++ b/drivers/clk/rockchip/clk-muxgrf.c @@ -0,0 +1,102 @@ +/* + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include <linux/slab.h> +#include <linux/bitops.h> +#include <linux/regmap.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include "clk.h" + +struct rockchip_muxgrf_clock { + struct clk_hw hw; + struct regmap *regmap; + u32 reg; + u32 shift; + u32 width; + int flags; +}; + +#define to_muxgrf_clock(_hw) container_of(_hw, struct rockchip_muxgrf_clock, hw) + +static u8 rockchip_muxgrf_get_parent(struct clk_hw *hw) +{ + struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); + unsigned int mask = GENMASK(mux->width - 1, 0); + unsigned int val; + + regmap_read(mux->regmap, mux->reg, &val); + + val >>= mux->shift; + val &= mask; + + return val; +} + +static int rockchip_muxgrf_set_parent(struct clk_hw *hw, u8 index) +{ + struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); + unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift); + unsigned int val; + + val = index; + val <<= mux->shift; + + if (mux->flags & CLK_MUX_HIWORD_MASK) + return regmap_write(mux->regmap, mux->reg, val | (mask << 16)); + else + return regmap_update_bits(mux->regmap, mux->reg, mask, val); +} + +static const struct clk_ops rockchip_muxgrf_clk_ops = { + .get_parent = rockchip_muxgrf_get_parent, + .set_parent = rockchip_muxgrf_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +struct clk *rockchip_clk_register_muxgrf(const char *name, + const char *const *parent_names, u8 num_parents, + int flags, struct regmap *regmap, int reg, + int shift, int width, int mux_flags) +{ + struct rockchip_muxgrf_clock *muxgrf_clock; + struct clk_init_data init; + struct clk *clk; + + if (IS_ERR(regmap)) { + pr_err("%s: regmap not available\n", __func__); + return ERR_PTR(-ENOTSUPP); + } + + muxgrf_clock = kmalloc(sizeof(*muxgrf_clock), GFP_KERNEL); + if (!muxgrf_clock) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = flags; + init.num_parents = num_parents; + init.parent_names = parent_names; + init.ops = &rockchip_muxgrf_clk_ops; + + muxgrf_clock->hw.init = &init; + muxgrf_clock->regmap = regmap; + muxgrf_clock->reg = reg; + muxgrf_clock->shift = shift; + muxgrf_clock->width = width; + muxgrf_clock->flags = mux_flags; + + clk = clk_register(NULL, &muxgrf_clock->hw); + if (IS_ERR(clk)) + kfree(muxgrf_clock); + + return clk; +} diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 6ed605776abd..eec51893a7e6 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -29,6 +29,7 @@ #define PLL_MODE_SLOW 0x0 #define PLL_MODE_NORM 0x1 #define PLL_MODE_DEEP 0x2 +#define PLL_RK3328_MODE_MASK 0x1 struct rockchip_clk_pll { struct clk_hw hw; @@ -848,7 +849,8 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, struct clk *pll_clk, *mux_clk; char pll_name[20]; - if (num_parents != 2) { + if ((pll_type != pll_rk3328 && num_parents != 2) || + (pll_type == pll_rk3328 && num_parents != 1)) { pr_err("%s: needs two parent clocks\n", __func__); return ERR_PTR(-EINVAL); } @@ -865,13 +867,17 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, pll_mux = &pll->pll_mux; pll_mux->reg = ctx->reg_base + mode_offset; pll_mux->shift = mode_shift; - pll_mux->mask = PLL_MODE_MASK; + if (pll_type == pll_rk3328) + pll_mux->mask = PLL_RK3328_MODE_MASK; + else + pll_mux->mask = PLL_MODE_MASK; pll_mux->flags = 0; pll_mux->lock = &ctx->lock; pll_mux->hw.init = &init; if (pll_type == pll_rk3036 || pll_type == pll_rk3066 || + pll_type == pll_rk3328 || pll_type == pll_rk3399) pll_mux->flags |= CLK_MUX_HIWORD_MASK; @@ -884,7 +890,10 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, init.flags = CLK_SET_RATE_PARENT; init.ops = pll->pll_mux_ops; init.parent_names = pll_parents; - init.num_parents = ARRAY_SIZE(pll_parents); + if (pll_type == pll_rk3328) + init.num_parents = 2; + else + init.num_parents = ARRAY_SIZE(pll_parents); mux_clk = clk_register(NULL, &pll_mux->hw); if (IS_ERR(mux_clk)) @@ -918,6 +927,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, switch (pll_type) { case pll_rk3036: + case pll_rk3328: if (!pll->rate_table || IS_ERR(ctx->grf)) init.ops = &rockchip_rk3036_pll_clk_norate_ops; else diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 062ef4960244..00ad0e5f8d66 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -507,8 +507,8 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS), GATE(PCLK_EFUSE, "pclk_efuse", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 2, GFLAGS), GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 3, GFLAGS), - GATE(0, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS), - GATE(0, "pclk_ddrpubl", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), + GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS), + GATE(PCLK_PUBL, "pclk_ddrpubl", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), GATE(0, "pclk_dbg", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS), GATE(PCLK_PMU, "pclk_pmu", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 5, GFLAGS), diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 39af05a589b3..60bff5f5295d 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -198,6 +198,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_usbphy480m_p) = { "sclk_otgphy1_480m", "sclk_otgphy2_480m", "sclk_otgphy0_480m" }; PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy480m_src" }; @@ -398,14 +399,12 @@ 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), - /* - * We use aclk_vdpu by default GRF_SOC_CON0[7] setting in system, - * so we ignore the mux and make clocks nodes as following, - */ - GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vdpu", 0, + MUXGRF(0, "aclk_vcodec_pre", mux_aclk_vcodec_pre_p, 0, + RK3288_GRF_SOC_CON(0), 7, 1, MFLAGS), + GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0, RK3288_CLKGATE_CON(9), 0, GFLAGS), - FACTOR_GATE(0, "hclk_vcodec_pre", "aclk_vdpu", 0, 1, 4, + FACTOR_GATE(0, "hclk_vcodec_pre", "aclk_vcodec_pre", 0, 1, 4, RK3288_CLKGATE_CON(3), 10, GFLAGS), GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, @@ -801,7 +800,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(0, "pclk_vip_in", "ext_vip", 0, RK3288_CLKGATE_CON(16), 0, GFLAGS), INVERTER(0, "pclk_vip", "pclk_vip_in", RK3288_CLKSEL_CON(29), 4, IFLAGS), - GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), + GATE(PCLK_ISP_IN, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS), }; diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c new file mode 100644 index 000000000000..1e384e143504 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -0,0 +1,895 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Elaine <zhangqing@rock-chips.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/syscore_ops.h> +#include <dt-bindings/clock/rk3328-cru.h> +#include "clk.h" + +#define RK3328_GRF_SOC_STATUS0 0x480 +#define RK3328_GRF_MAC_CON1 0x904 +#define RK3328_GRF_MAC_CON2 0x908 + +enum rk3328_plls { + apll, dpll, cpll, gpll, npll, +}; + +static struct rockchip_pll_rate_table rk3328_pll_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0), + RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0), + RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0), + RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), + RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0), + RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0), + RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0), + RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), + RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0), + RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0), + RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0), + RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0), + RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), + RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0), + RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0), + RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), + RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), + RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0), + RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), + RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), + RK3036_PLL_RATE(984000000, 1, 82, 2, 1, 1, 0), + RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0), + RK3036_PLL_RATE(936000000, 1, 78, 2, 1, 1, 0), + RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), + RK3036_PLL_RATE(900000000, 4, 300, 2, 1, 1, 0), + RK3036_PLL_RATE(888000000, 1, 74, 2, 1, 1, 0), + RK3036_PLL_RATE(864000000, 1, 72, 2, 1, 1, 0), + RK3036_PLL_RATE(840000000, 1, 70, 2, 1, 1, 0), + RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), + RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0), + RK3036_PLL_RATE(700000000, 6, 350, 2, 1, 1, 0), + RK3036_PLL_RATE(696000000, 1, 58, 2, 1, 1, 0), + RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), + RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), + RK3036_PLL_RATE(504000000, 1, 63, 3, 1, 1, 0), + RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0), + RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), + RK3036_PLL_RATE(312000000, 1, 52, 2, 2, 1, 0), + RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE(96000000, 1, 64, 4, 4, 1, 0), + { /* sentinel */ }, +}; + +static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217), + /* vco = 1016064000 */ + RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088), + /* vco = 983040000 */ + RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088), + /* vco = 983040000 */ + RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088), + /* vco = 860156000 */ + RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894), + /* vco = 903168000 */ + RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329), + /* vco = 819200000 */ + { /* sentinel */ }, +}; + +#define RK3328_DIV_ACLKM_MASK 0x7 +#define RK3328_DIV_ACLKM_SHIFT 4 +#define RK3328_DIV_PCLK_DBG_MASK 0xf +#define RK3328_DIV_PCLK_DBG_SHIFT 0 + +#define RK3328_CLKSEL1(_aclk_core, _pclk_dbg) \ +{ \ + .reg = RK3328_CLKSEL_CON(1), \ + .val = HIWORD_UPDATE(_aclk_core, RK3328_DIV_ACLKM_MASK, \ + RK3328_DIV_ACLKM_SHIFT) | \ + HIWORD_UPDATE(_pclk_dbg, RK3328_DIV_PCLK_DBG_MASK, \ + RK3328_DIV_PCLK_DBG_SHIFT), \ +} + +#define RK3328_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg) \ +{ \ + .prate = _prate, \ + .divs = { \ + RK3328_CLKSEL1(_aclk_core, _pclk_dbg), \ + }, \ +} + +static struct rockchip_cpuclk_rate_table rk3328_cpuclk_rates[] __initdata = { + RK3328_CPUCLK_RATE(1800000000, 1, 7), + RK3328_CPUCLK_RATE(1704000000, 1, 7), + RK3328_CPUCLK_RATE(1608000000, 1, 7), + RK3328_CPUCLK_RATE(1512000000, 1, 7), + RK3328_CPUCLK_RATE(1488000000, 1, 5), + RK3328_CPUCLK_RATE(1416000000, 1, 5), + RK3328_CPUCLK_RATE(1392000000, 1, 5), + RK3328_CPUCLK_RATE(1296000000, 1, 5), + RK3328_CPUCLK_RATE(1200000000, 1, 5), + RK3328_CPUCLK_RATE(1104000000, 1, 5), + RK3328_CPUCLK_RATE(1008000000, 1, 5), + RK3328_CPUCLK_RATE(912000000, 1, 5), + RK3328_CPUCLK_RATE(816000000, 1, 3), + RK3328_CPUCLK_RATE(696000000, 1, 3), + RK3328_CPUCLK_RATE(600000000, 1, 3), + RK3328_CPUCLK_RATE(408000000, 1, 1), + RK3328_CPUCLK_RATE(312000000, 1, 1), + RK3328_CPUCLK_RATE(216000000, 1, 1), + RK3328_CPUCLK_RATE(96000000, 1, 1), +}; + +static const struct rockchip_cpuclk_reg_data rk3328_cpuclk_data = { + .core_reg = RK3328_CLKSEL_CON(0), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_alt = 1, + .mux_core_main = 3, + .mux_core_shift = 6, + .mux_core_mask = 0x3, +}; + +PNAME(mux_pll_p) = { "xin24m" }; + +PNAME(mux_2plls_p) = { "cpll", "gpll" }; +PNAME(mux_gpll_cpll_p) = { "gpll", "cpll" }; +PNAME(mux_cpll_gpll_apll_p) = { "cpll", "gpll", "apll" }; +PNAME(mux_2plls_xin24m_p) = { "cpll", "gpll", "xin24m" }; +PNAME(mux_2plls_hdmiphy_p) = { "cpll", "gpll", + "dummy_hdmiphy" }; +PNAME(mux_4plls_p) = { "cpll", "gpll", + "dummy_hdmiphy", + "usb480m" }; +PNAME(mux_2plls_u480m_p) = { "cpll", "gpll", + "usb480m" }; +PNAME(mux_2plls_24m_u480m_p) = { "cpll", "gpll", + "xin24m", "usb480m" }; + +PNAME(mux_ddrphy_p) = { "dpll", "apll", "cpll" }; +PNAME(mux_armclk_p) = { "apll_core", + "gpll_core", + "dpll_core", + "npll_core"}; +PNAME(mux_hdmiphy_p) = { "hdmi_phy", "xin24m" }; +PNAME(mux_usb480m_p) = { "usb480m_phy", + "xin24m" }; + +PNAME(mux_i2s0_p) = { "clk_i2s0_div", + "clk_i2s0_frac", + "xin12m", + "xin12m" }; +PNAME(mux_i2s1_p) = { "clk_i2s1_div", + "clk_i2s1_frac", + "clkin_i2s1", + "xin12m" }; +PNAME(mux_i2s2_p) = { "clk_i2s2_div", + "clk_i2s2_frac", + "clkin_i2s2", + "xin12m" }; +PNAME(mux_i2s1out_p) = { "clk_i2s1", "xin12m"}; +PNAME(mux_i2s2out_p) = { "clk_i2s2", "xin12m" }; +PNAME(mux_spdif_p) = { "clk_spdif_div", + "clk_spdif_frac", + "xin12m", + "xin12m" }; +PNAME(mux_uart0_p) = { "clk_uart0_div", + "clk_uart0_frac", + "xin24m" }; +PNAME(mux_uart1_p) = { "clk_uart1_div", + "clk_uart1_frac", + "xin24m" }; +PNAME(mux_uart2_p) = { "clk_uart2_div", + "clk_uart2_frac", + "xin24m" }; + +PNAME(mux_sclk_cif_p) = { "clk_cif_src", + "xin24m" }; +PNAME(mux_dclk_lcdc_p) = { "hdmiphy", + "dclk_lcdc_src" }; +PNAME(mux_aclk_peri_pre_p) = { "cpll_peri", + "gpll_peri", + "hdmiphy_peri" }; +PNAME(mux_ref_usb3otg_src_p) = { "xin24m", + "clk_usb3otg_ref" }; +PNAME(mux_xin24m_32k_p) = { "xin24m", + "clk_rtc32k" }; +PNAME(mux_mac2io_src_p) = { "clk_mac2io_src", + "gmac_clkin" }; +PNAME(mux_mac2phy_src_p) = { "clk_mac2phy_src", + "phy_50m_out" }; + +static struct rockchip_pll_clock rk3328_pll_clks[] __initdata = { + [apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p, + 0, RK3328_PLL_CON(0), + RK3328_MODE_CON, 0, 4, 0, rk3328_pll_frac_rates), + [dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p, + 0, RK3328_PLL_CON(8), + RK3328_MODE_CON, 4, 3, 0, NULL), + [cpll] = PLL(pll_rk3328, PLL_CPLL, "cpll", mux_pll_p, + 0, RK3328_PLL_CON(16), + RK3328_MODE_CON, 8, 2, 0, rk3328_pll_rates), + [gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p, + 0, RK3328_PLL_CON(24), + RK3328_MODE_CON, 12, 1, 0, rk3328_pll_frac_rates), + [npll] = PLL(pll_rk3328, PLL_NPLL, "npll", mux_pll_p, + 0, RK3328_PLL_CON(40), + RK3328_MODE_CON, 1, 0, 0, rk3328_pll_rates), +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) + +static struct rockchip_clk_branch rk3328_i2s0_fracmux __initdata = + MUX(0, "i2s0_pre", mux_i2s0_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(6), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_i2s1_fracmux __initdata = + MUX(0, "i2s1_pre", mux_i2s1_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(8), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_i2s2_fracmux __initdata = + MUX(0, "i2s2_pre", mux_i2s2_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(10), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_spdif_fracmux __initdata = + MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(12), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_uart0_fracmux __initdata = + MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(14), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_uart1_fracmux __initdata = + MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(16), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_uart2_fracmux __initdata = + MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(18), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { + /* + * Clock-Architecture Diagram 1 + */ + + DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED, + RK3328_CLKSEL_CON(2), 8, 5, DFLAGS), + COMPOSITE(SCLK_RTC32K, "clk_rtc32k", mux_2plls_xin24m_p, 0, + RK3328_CLKSEL_CON(38), 14, 2, MFLAGS, 0, 14, DFLAGS, + RK3328_CLKGATE_CON(0), 11, GFLAGS), + + /* PD_MISC */ + MUX(HDMIPHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT, + RK3328_MISC_CON, 13, 1, MFLAGS), + MUX(USB480M, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT, + RK3328_MISC_CON, 15, 1, MFLAGS), + + /* + * Clock-Architecture Diagram 2 + */ + + /* PD_CORE */ + GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(0), 0, GFLAGS), + GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(0), 2, GFLAGS), + GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(0), 1, GFLAGS), + GATE(0, "npll_core", "npll", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(0), 12, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK3328_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3328_CLKGATE_CON(7), 0, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED, + RK3328_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3328_CLKGATE_CON(7), 1, GFLAGS), + GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(13), 0, GFLAGS), + GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(13), 1, GFLAGS), + + GATE(0, "clk_jtag", "jtag_clkin", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(7), 2, GFLAGS), + + /* PD_GPU */ + COMPOSITE(0, "aclk_gpu_pre", mux_4plls_p, 0, + RK3328_CLKSEL_CON(44), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 6, GFLAGS), + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(14), 0, GFLAGS), + GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(14), 1, GFLAGS), + + /* PD_DDR */ + COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IGNORE_UNUSED, + RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3328_CLKGATE_CON(0), 4, GFLAGS), + GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 6, GFLAGS), + GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 5, GFLAGS), + GATE(0, "aclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 4, GFLAGS), + GATE(0, "clk_ddrmon", "xin24m", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(0), 6, GFLAGS), + + COMPOSITE(PCLK_DDR, "pclk_ddr", mux_2plls_hdmiphy_p, 0, + RK3328_CLKSEL_CON(4), 13, 2, MFLAGS, 8, 3, DFLAGS, + RK3328_CLKGATE_CON(7), 4, GFLAGS), + GATE(0, "pclk_ddrupctl", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 1, GFLAGS), + GATE(0, "pclk_ddr_msch", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 2, GFLAGS), + GATE(0, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 3, GFLAGS), + GATE(0, "pclk_ddrstdby", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 7, GFLAGS), + GATE(0, "pclk_ddr_grf", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 9, GFLAGS), + + /* + * Clock-Architecture Diagram 3 + */ + + /* PD_BUS */ + COMPOSITE(ACLK_BUS_PRE, "aclk_bus_pre", mux_2plls_hdmiphy_p, 0, + RK3328_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(8), 0, GFLAGS), + COMPOSITE_NOMUX(HCLK_BUS_PRE, "hclk_bus_pre", "aclk_bus_pre", 0, + RK3328_CLKSEL_CON(1), 8, 2, DFLAGS, + RK3328_CLKGATE_CON(8), 1, GFLAGS), + COMPOSITE_NOMUX(PCLK_BUS_PRE, "pclk_bus_pre", "aclk_bus_pre", 0, + RK3328_CLKSEL_CON(1), 12, 3, DFLAGS, + RK3328_CLKGATE_CON(8), 2, GFLAGS), + GATE(0, "pclk_bus", "pclk_bus_pre", 0, + RK3328_CLKGATE_CON(8), 3, GFLAGS), + GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0, + RK3328_CLKGATE_CON(8), 4, GFLAGS), + + COMPOSITE(SCLK_TSP, "clk_tsp", mux_2plls_p, 0, + RK3328_CLKSEL_CON(21), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(2), 5, GFLAGS), + GATE(0, "clk_hsadc_tsp", "ext_gpio3a2", 0, + RK3328_CLKGATE_CON(17), 13, GFLAGS), + + /* PD_I2S */ + COMPOSITE(0, "clk_i2s0_div", mux_2plls_p, 0, + RK3328_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(1), 1, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(7), 0, + RK3328_CLKGATE_CON(1), 2, GFLAGS, + &rk3328_i2s0_fracmux), + GATE(SCLK_I2S0, "clk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(1), 3, GFLAGS), + + COMPOSITE(0, "clk_i2s1_div", mux_2plls_p, 0, + RK3328_CLKSEL_CON(8), 15, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(1), 4, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(9), 0, + RK3328_CLKGATE_CON(1), 5, GFLAGS, + &rk3328_i2s1_fracmux), + GATE(SCLK_I2S1, "clk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NODIV(SCLK_I2S1_OUT, "i2s1_out", mux_i2s1out_p, 0, + RK3328_CLKSEL_CON(8), 12, 1, MFLAGS, + RK3328_CLKGATE_CON(1), 7, GFLAGS), + + COMPOSITE(0, "clk_i2s2_div", mux_2plls_p, 0, + RK3328_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(1), 8, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(11), 0, + RK3328_CLKGATE_CON(1), 9, GFLAGS, + &rk3328_i2s2_fracmux), + GATE(SCLK_I2S2, "clk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(1), 10, GFLAGS), + COMPOSITE_NODIV(SCLK_I2S2_OUT, "i2s2_out", mux_i2s2out_p, 0, + RK3328_CLKSEL_CON(10), 12, 1, MFLAGS, + RK3328_CLKGATE_CON(1), 11, GFLAGS), + + COMPOSITE(0, "clk_spdif_div", mux_2plls_p, 0, + RK3328_CLKSEL_CON(12), 15, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(1), 12, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(13), 0, + RK3328_CLKGATE_CON(1), 13, GFLAGS, + &rk3328_spdif_fracmux), + + /* PD_UART */ + COMPOSITE(0, "clk_uart0_div", mux_2plls_u480m_p, 0, + RK3328_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(1), 14, GFLAGS), + COMPOSITE(0, "clk_uart1_div", mux_2plls_u480m_p, 0, + RK3328_CLKSEL_CON(16), 12, 2, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 0, GFLAGS), + COMPOSITE(0, "clk_uart2_div", mux_2plls_u480m_p, 0, + RK3328_CLKSEL_CON(18), 12, 2, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 2, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(15), 0, + RK3328_CLKGATE_CON(1), 15, GFLAGS, + &rk3328_uart0_fracmux), + COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(17), 0, + RK3328_CLKGATE_CON(2), 1, GFLAGS, + &rk3328_uart1_fracmux), + COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(19), 0, + RK3328_CLKGATE_CON(2), 3, GFLAGS, + &rk3328_uart2_fracmux), + + /* + * Clock-Architecture Diagram 4 + */ + + COMPOSITE(SCLK_I2C0, "clk_i2c0", mux_2plls_p, 0, + RK3328_CLKSEL_CON(34), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 9, GFLAGS), + COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_2plls_p, 0, + RK3328_CLKSEL_CON(34), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_2plls_p, 0, + RK3328_CLKSEL_CON(35), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 11, GFLAGS), + COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_2plls_p, 0, + 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_CLKGATE_CON(2), 4, GFLAGS), + COMPOSITE_NOMUX(SCLK_TSADC, "clk_tsadc", "clk_24m", 0, + RK3328_CLKSEL_CON(22), 0, 10, DFLAGS, + RK3328_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "clk_24m", 0, + RK3328_CLKSEL_CON(23), 0, 10, DFLAGS, + RK3328_CLKGATE_CON(2), 14, GFLAGS), + COMPOSITE(SCLK_SPI, "clk_spi", mux_2plls_p, 0, + RK3328_CLKSEL_CON(24), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 7, GFLAGS), + COMPOSITE(SCLK_PWM, "clk_pwm", mux_2plls_p, 0, + RK3328_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3328_CLKGATE_CON(2), 8, GFLAGS), + COMPOSITE(SCLK_OTP, "clk_otp", mux_2plls_xin24m_p, 0, + RK3328_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3328_CLKGATE_CON(3), 8, GFLAGS), + COMPOSITE(SCLK_EFUSE, "clk_efuse", mux_2plls_xin24m_p, 0, + RK3328_CLKSEL_CON(5), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(2), 13, GFLAGS), + COMPOSITE(SCLK_PDM, "clk_pdm", mux_cpll_gpll_apll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(2), 15, GFLAGS), + + GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0, + RK3328_CLKGATE_CON(8), 5, GFLAGS), + GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0, + RK3328_CLKGATE_CON(8), 6, GFLAGS), + GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0, + RK3328_CLKGATE_CON(8), 7, GFLAGS), + GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0, + RK3328_CLKGATE_CON(8), 8, GFLAGS), + GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0, + RK3328_CLKGATE_CON(8), 9, GFLAGS), + GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0, + RK3328_CLKGATE_CON(8), 10, GFLAGS), + + COMPOSITE(SCLK_WIFI, "clk_wifi", mux_2plls_u480m_p, 0, + RK3328_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3328_CLKGATE_CON(0), 10, GFLAGS), + + /* + * Clock-Architecture Diagram 5 + */ + + /* PD_VIDEO */ + COMPOSITE(ACLK_RKVDEC_PRE, "aclk_rkvdec_pre", mux_4plls_p, 0, + RK3328_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 0, GFLAGS), + FACTOR_GATE(HCLK_RKVDEC_PRE, "hclk_rkvdec_pre", "aclk_rkvdec_pre", 0, 1, 4, + RK3328_CLKGATE_CON(11), 0, GFLAGS), + GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(24), 0, GFLAGS), + GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(24), 1, GFLAGS), + GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(24), 2, GFLAGS), + GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(24), 3, GFLAGS), + + COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0, + RK3328_CLKSEL_CON(48), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 1, GFLAGS), + + COMPOSITE(SCLK_VDEC_CORE, "sclk_vdec_core", mux_4plls_p, 0, + RK3328_CLKSEL_CON(49), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 2, GFLAGS), + + COMPOSITE(ACLK_VPU_PRE, "aclk_vpu_pre", mux_4plls_p, 0, + RK3328_CLKSEL_CON(50), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 5, GFLAGS), + FACTOR_GATE(HCLK_VPU_PRE, "hclk_vpu_pre", "aclk_vpu_pre", 0, 1, 4, + RK3328_CLKGATE_CON(11), 8, GFLAGS), + GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(23), 0, GFLAGS), + GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(23), 1, GFLAGS), + GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(23), 2, GFLAGS), + GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(23), 3, GFLAGS), + + COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0, + RK3328_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 3, GFLAGS), + FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4, + RK3328_CLKGATE_CON(11), 4, GFLAGS), + GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(25), 0, GFLAGS), + GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(25), 1, GFLAGS), + GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0, + RK3328_CLKGATE_CON(25), 0, GFLAGS), + GATE(PCLK_H265, "pclk_h265", "hclk_rkvenc", 0, + RK3328_CLKGATE_CON(25), 1, GFLAGS), + GATE(ACLK_H264, "aclk_h264", "aclk_rkvenc", 0, + RK3328_CLKGATE_CON(25), 0, GFLAGS), + GATE(HCLK_H264, "hclk_h264", "hclk_rkvenc", 0, + RK3328_CLKGATE_CON(25), 1, GFLAGS), + GATE(ACLK_AXISRAM, "aclk_axisram", "aclk_rkvenc", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(25), 0, GFLAGS), + + COMPOSITE(SCLK_VENC_CORE, "sclk_venc_core", mux_4plls_p, 0, + RK3328_CLKSEL_CON(51), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 4, GFLAGS), + + COMPOSITE(SCLK_VENC_DSP, "sclk_venc_dsp", mux_4plls_p, 0, + RK3328_CLKSEL_CON(52), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(6), 7, GFLAGS), + + /* + * Clock-Architecture Diagram 6 + */ + + /* PD_VIO */ + COMPOSITE(ACLK_VIO_PRE, "aclk_vio_pre", mux_4plls_p, 0, + RK3328_CLKSEL_CON(37), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(5), 2, GFLAGS), + DIV(HCLK_VIO_PRE, "hclk_vio_pre", "aclk_vio_pre", 0, + RK3328_CLKSEL_CON(37), 8, 5, DFLAGS), + + COMPOSITE(ACLK_RGA_PRE, "aclk_rga_pre", mux_4plls_p, 0, + RK3328_CLKSEL_CON(36), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(5), 0, GFLAGS), + COMPOSITE(SCLK_RGA, "clk_rga", mux_4plls_p, 0, + RK3328_CLKSEL_CON(36), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(5), 1, GFLAGS), + COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0, + RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(5), 5, GFLAGS), + GATE(0, "clk_hdmi_sfc", "xin24m", 0, + RK3328_CLKGATE_CON(5), 4, GFLAGS), + + COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0, + RK3328_CLKSEL_CON(42), 7, 1, MFLAGS, + RK3328_CLKGATE_CON(5), 3, GFLAGS), + COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cif_out", mux_sclk_cif_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(42), 5, 1, MFLAGS, 0, 5, DFLAGS), + + COMPOSITE(DCLK_LCDC_SRC, "dclk_lcdc_src", mux_gpll_cpll_p, 0, + RK3328_CLKSEL_CON(40), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK3328_CLKGATE_CON(5), 6, GFLAGS), + DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0, + RK3328_CLKSEL_CON(40), 3, 3, DFLAGS), + MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0, + RK3328_CLKSEL_CON(40), 1, 1, MFLAGS), + + /* + * Clock-Architecture Diagram 7 + */ + + /* PD_PERI */ + GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(4), 0, GFLAGS), + GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(4), 1, GFLAGS), + GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(4), 2, GFLAGS), + COMPOSITE_NOGATE(ACLK_PERI_PRE, "aclk_peri_pre", mux_aclk_peri_pre_p, 0, + RK3328_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_pre", CLK_IGNORE_UNUSED, + RK3328_CLKSEL_CON(29), 0, 2, DFLAGS, + RK3328_CLKGATE_CON(10), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_pre", CLK_IGNORE_UNUSED, + RK3328_CLKSEL_CON(29), 4, 3, DFLAGS, + RK3328_CLKGATE_CON(10), 1, GFLAGS), + GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre", CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, + RK3328_CLKGATE_CON(10), 0, GFLAGS), + + COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_2plls_24m_u480m_p, 0, + RK3328_CLKSEL_CON(30), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3328_CLKGATE_CON(4), 3, GFLAGS), + + COMPOSITE(SCLK_SDIO, "clk_sdio", mux_2plls_24m_u480m_p, 0, + RK3328_CLKSEL_CON(31), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3328_CLKGATE_CON(4), 4, GFLAGS), + + COMPOSITE(SCLK_EMMC, "clk_emmc", mux_2plls_24m_u480m_p, 0, + RK3328_CLKSEL_CON(32), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3328_CLKGATE_CON(4), 5, GFLAGS), + + COMPOSITE(SCLK_SDMMC_EXT, "clk_sdmmc_ext", mux_2plls_24m_u480m_p, 0, + RK3328_CLKSEL_CON(43), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3328_CLKGATE_CON(4), 10, GFLAGS), + + COMPOSITE(SCLK_REF_USB3OTG_SRC, "clk_ref_usb3otg_src", mux_2plls_p, 0, + RK3328_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3328_CLKGATE_CON(4), 9, GFLAGS), + + MUX(SCLK_REF_USB3OTG, "clk_ref_usb3otg", mux_ref_usb3otg_src_p, CLK_SET_RATE_PARENT, + RK3328_CLKSEL_CON(45), 8, 1, MFLAGS), + + GATE(SCLK_USB3OTG_REF, "clk_usb3otg_ref", "xin24m", 0, + RK3328_CLKGATE_CON(4), 7, GFLAGS), + + COMPOSITE(SCLK_USB3OTG_SUSPEND, "clk_usb3otg_suspend", mux_xin24m_32k_p, 0, + RK3328_CLKSEL_CON(33), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3328_CLKGATE_CON(4), 8, GFLAGS), + + /* + * Clock-Architecture Diagram 8 + */ + + /* PD_GMAC */ + COMPOSITE(ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_p, 0, + RK3328_CLKSEL_CON(35), 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, + RK3328_CLKGATE_CON(9), 0, GFLAGS), + + COMPOSITE(SCLK_MAC2IO_SRC, "clk_mac2io_src", mux_2plls_p, 0, + RK3328_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(3), 1, GFLAGS), + GATE(SCLK_MAC2IO_REF, "clk_mac2io_ref", "clk_mac2io", 0, + RK3328_CLKGATE_CON(9), 7, GFLAGS), + GATE(SCLK_MAC2IO_RX, "clk_mac2io_rx", "clk_mac2io", 0, + RK3328_CLKGATE_CON(9), 4, GFLAGS), + GATE(SCLK_MAC2IO_TX, "clk_mac2io_tx", "clk_mac2io", 0, + RK3328_CLKGATE_CON(9), 5, GFLAGS), + GATE(SCLK_MAC2IO_REFOUT, "clk_mac2io_refout", "clk_mac2io", 0, + RK3328_CLKGATE_CON(9), 6, GFLAGS), + COMPOSITE(SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_p, 0, + RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3328_CLKGATE_CON(3), 5, GFLAGS), + + COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0, + RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3328_CLKGATE_CON(3), 0, GFLAGS), + GATE(SCLK_MAC2PHY_REF, "clk_mac2phy_ref", "clk_mac2phy", 0, + RK3328_CLKGATE_CON(9), 3, GFLAGS), + GATE(SCLK_MAC2PHY_RXTX, "clk_mac2phy_rxtx", "clk_mac2phy", 0, + RK3328_CLKGATE_CON(9), 1, GFLAGS), + COMPOSITE_NOMUX(SCLK_MAC2PHY_OUT, "clk_mac2phy_out", "clk_mac2phy", 0, + RK3328_CLKSEL_CON(26), 8, 2, DFLAGS, + RK3328_CLKGATE_CON(9), 2, GFLAGS), + + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + + /* + * Clock-Architecture Diagram 9 + */ + + /* PD_VOP */ + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(21), 10, GFLAGS), + GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 3, GFLAGS), + GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 2, GFLAGS), + GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 4, GFLAGS), + + GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 6, GFLAGS), + GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 8, GFLAGS), + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 15, GFLAGS), + GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 2, GFLAGS), + + GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 3, GFLAGS), + GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 5, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 7, GFLAGS), + GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 9, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 11, GFLAGS), + GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 12, GFLAGS), + GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 13, GFLAGS), + GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 14, GFLAGS), + GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 0, GFLAGS), + GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS), + GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 4, GFLAGS), + GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 5, GFLAGS), + + /* 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(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), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 2, GFLAGS), + GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 15, GFLAGS), + GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 6, GFLAGS), + GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 7, GFLAGS), + GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 8, GFLAGS), + GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 9, GFLAGS), + GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 12, GFLAGS), + GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 13, GFLAGS), + + /* PD_GMAC */ + GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 0, GFLAGS), + GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 2, GFLAGS), + GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 4, GFLAGS), + GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 1, GFLAGS), + GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 3, GFLAGS), + GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 5, GFLAGS), + + /* PD_BUS */ + GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 12, GFLAGS), + GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 11, GFLAGS), + GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 12, GFLAGS), + GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 0, GFLAGS), + GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 1, GFLAGS), + + GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 2, GFLAGS), + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 3, GFLAGS), + GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 4, GFLAGS), + GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 5, GFLAGS), + GATE(HCLK_SPDIF_8CH, "hclk_spdif_8ch", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 6, GFLAGS), + GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 11, GFLAGS), + GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 7, GFLAGS), + GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 8, GFLAGS), + GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 13, GFLAGS), + GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(28), 0, GFLAGS), + + GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 14, GFLAGS), + GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 9, GFLAGS), + GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 4, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 10, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 0, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 1, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 2, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer0", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 3, GFLAGS), + GATE(0, "pclk_stimer", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 4, GFLAGS), + GATE(PCLK_SPI, "pclk_spi", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 5, GFLAGS), + GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 6, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 7, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 8, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 9, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 10, GFLAGS), + GATE(PCLK_UART0, "pclk_uart0", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 11, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 12, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 13, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 14, GFLAGS), + GATE(PCLK_DCF, "pclk_dcf", "pclk_bus", 0, RK3328_CLKGATE_CON(16), 15, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 0, GFLAGS), + GATE(0, "pclk_cru", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 4, GFLAGS), + GATE(0, "pclk_sgrf", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 6, GFLAGS), + GATE(0, "pclk_sim", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 10, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0, RK3328_CLKGATE_CON(17), 15, GFLAGS), + GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 3, GFLAGS), + + GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 1, GFLAGS), + GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 2, GFLAGS), + GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 2, GFLAGS), + GATE(PCLK_USB2_GRF, "pclk_usb2_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 14, GFLAGS), + GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 13, GFLAGS), + GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 5, GFLAGS), + GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 7, GFLAGS), + GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 8, GFLAGS), + GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 15, GFLAGS), + + /* PD_MMC */ + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", + RK3328_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", + RK3328_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", + RK3328_SDIO_CON0, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", + RK3328_SDIO_CON1, 1), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", + RK3328_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", + RK3328_EMMC_CON1, 1), + + MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "sclk_sdmmc_ext", + RK3328_SDMMC_EXT_CON0, 1), + MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "sclk_sdmmc_ext", + RK3328_SDMMC_EXT_CON1, 1), +}; + +static const char *const rk3328_critical_clocks[] __initconst = { + "aclk_bus", + "pclk_bus", + "hclk_bus", + "aclk_peri", + "hclk_peri", + "pclk_peri", + "pclk_dbg", + "aclk_core_niu", + "aclk_gic400", + "aclk_intmem", + "hclk_rom", + "pclk_grf", + "pclk_cru", + "pclk_sgrf", + "pclk_timer0", + "clk_timer0", + "pclk_ddr_msch", + "pclk_ddr_mon", + "pclk_ddr_grf", + "clk_ddrupctl", + "clk_ddrmsch", + "hclk_ahb1tom", + "clk_jtag", + "pclk_ddrphy", + "pclk_pmu", + "hclk_otg_pmu", + "aclk_rga_niu", + "pclk_vio_h2p", + "hclk_vio_h2p", +}; + +static void __init rk3328_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); + return; + } + + rockchip_clk_register_plls(ctx, rk3328_pll_clks, + ARRAY_SIZE(rk3328_pll_clks), + RK3328_GRF_SOC_STATUS0); + rockchip_clk_register_branches(ctx, rk3328_clk_branches, + ARRAY_SIZE(rk3328_clk_branches)); + rockchip_clk_protect_critical(rk3328_critical_clocks, + ARRAY_SIZE(rk3328_critical_clocks)); + + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", + mux_armclk_p, ARRAY_SIZE(mux_armclk_p), + &rk3328_cpuclk_data, rk3328_cpuclk_rates, + ARRAY_SIZE(rk3328_cpuclk_rates)); + + rockchip_register_softrst(np, 11, reg_base + RK3328_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(ctx, RK3328_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); +} +CLK_OF_DECLARE(rk3328_cru, "rockchip,rk3328-cru", rk3328_clk_init); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index b886be30f34f..fe1d393cf678 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -344,7 +344,6 @@ struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np, ctx->clk_data.clks = clk_table; ctx->clk_data.clk_num = nr_clks; ctx->cru_node = np; - ctx->grf = ERR_PTR(-EPROBE_DEFER); spin_lock_init(&ctx->lock); ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, @@ -417,6 +416,13 @@ void __init rockchip_clk_register_branches( list->mux_shift, list->mux_width, list->mux_flags, &ctx->lock); break; + case branch_muxgrf: + clk = rockchip_clk_register_muxgrf(list->name, + list->parent_names, list->num_parents, + flags, ctx->grf, list->muxdiv_offset, + list->mux_shift, list->mux_width, + list->mux_flags); + break; case branch_divider: if (list->div_table) clk = clk_register_divider_table(NULL, diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index d67eecc4ade9..7c15473ea72b 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -91,6 +91,24 @@ struct clk; #define RK3288_EMMC_CON0 0x218 #define RK3288_EMMC_CON1 0x21c +#define RK3328_PLL_CON(x) RK2928_PLL_CON(x) +#define RK3328_CLKSEL_CON(x) ((x) * 0x4 + 0x100) +#define RK3328_CLKGATE_CON(x) ((x) * 0x4 + 0x200) +#define RK3328_GRFCLKSEL_CON(x) ((x) * 0x4 + 0x100) +#define RK3328_GLB_SRST_FST 0x9c +#define RK3328_GLB_SRST_SND 0x98 +#define RK3328_SOFTRST_CON(x) ((x) * 0x4 + 0x300) +#define RK3328_MODE_CON 0x80 +#define RK3328_MISC_CON 0x84 +#define RK3328_SDMMC_CON0 0x380 +#define RK3328_SDMMC_CON1 0x384 +#define RK3328_SDIO_CON0 0x388 +#define RK3328_SDIO_CON1 0x38c +#define RK3328_EMMC_CON0 0x390 +#define RK3328_EMMC_CON1 0x394 +#define RK3328_SDMMC_EXT_CON0 0x398 +#define RK3328_SDMMC_EXT_CON1 0x39C + #define RK3368_PLL_CON(x) RK2928_PLL_CON(x) #define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100) #define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200) @@ -130,6 +148,7 @@ struct clk; enum rockchip_pll_type { pll_rk3036, pll_rk3066, + pll_rk3328, pll_rk3399, }; @@ -317,11 +336,17 @@ struct clk *rockchip_clk_register_inverter(const char *name, void __iomem *reg, int shift, int flags, spinlock_t *lock); +struct clk *rockchip_clk_register_muxgrf(const char *name, + const char *const *parent_names, u8 num_parents, + int flags, struct regmap *grf, int reg, + int shift, int width, int mux_flags); + #define PNAME(x) static const char *const x[] __initconst enum rockchip_clk_branch_type { branch_composite, branch_mux, + branch_muxgrf, branch_divider, branch_fraction_divider, branch_gate, @@ -551,6 +576,21 @@ struct rockchip_clk_branch { .gate_offset = -1, \ } +#define MUXGRF(_id, cname, pnames, f, o, s, w, mf) \ + { \ + .id = _id, \ + .branch_type = branch_muxgrf, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = o, \ + .mux_shift = s, \ + .mux_width = w, \ + .mux_flags = mf, \ + .gate_offset = -1, \ + } + #define DIV(_id, cname, pname, f, o, s, w, df) \ { \ .id = _id, \ diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 57f4dc6dc447..7afc21dc374e 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o -obj-$(CONFIG_SOC_EXYNOS4415) += clk-exynos4415.o obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 17e68a724945..cb7df358a27d 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -44,7 +44,7 @@ static unsigned long reg_save[][2] = { { ASS_CLK_GATE, 0 }, }; -static int exynos_audss_clk_suspend(void) +static int exynos_audss_clk_suspend(struct device *dev) { int i; @@ -54,18 +54,15 @@ static int exynos_audss_clk_suspend(void) return 0; } -static void exynos_audss_clk_resume(void) +static int exynos_audss_clk_resume(struct device *dev) { int i; for (i = 0; i < ARRAY_SIZE(reg_save); i++) writel(reg_save[i][1], reg_base + reg_save[i][0]); -} -static struct syscore_ops exynos_audss_clk_syscore_ops = { - .suspend = exynos_audss_clk_suspend, - .resume = exynos_audss_clk_resume, -}; + return 0; +} #endif /* CONFIG_PM_SLEEP */ struct exynos_audss_clk_drvdata { @@ -251,9 +248,6 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) goto unregister; } -#ifdef CONFIG_PM_SLEEP - register_syscore_ops(&exynos_audss_clk_syscore_ops); -#endif return 0; unregister: @@ -267,10 +261,6 @@ unregister: static int exynos_audss_clk_remove(struct platform_device *pdev) { -#ifdef CONFIG_PM_SLEEP - unregister_syscore_ops(&exynos_audss_clk_syscore_ops); -#endif - of_clk_del_provider(pdev->dev.of_node); exynos_audss_clk_teardown(); @@ -281,10 +271,16 @@ static int exynos_audss_clk_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops exynos_audss_clk_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(exynos_audss_clk_suspend, + exynos_audss_clk_resume) +}; + static struct platform_driver exynos_audss_clk_driver = { .driver = { .name = "exynos-audss-clk", .of_match_table = exynos_audss_clk_of_match, + .pm = &exynos_audss_clk_pm_ops, }, .probe = exynos_audss_clk_probe, .remove = exynos_audss_clk_remove, diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index faab9b31baf5..e40b77583c47 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1298,6 +1298,8 @@ static const struct samsung_pll_rate_table exynos4210_vpll_rates[] __initconst = }; static const struct samsung_pll_rate_table exynos4x12_apll_rates[] __initconst = { + PLL_35XX_RATE(1704000000, 213, 3, 0), + PLL_35XX_RATE(1600000000, 200, 3, 0), PLL_35XX_RATE(1500000000, 250, 4, 0), PLL_35XX_RATE(1400000000, 175, 3, 0), PLL_35XX_RATE(1300000000, 325, 6, 0), @@ -1421,6 +1423,8 @@ static const struct exynos_cpuclk_cfg_data e4212_armclk_d[] __initconst = { (((cores) << 8) | ((hpm) << 4) | ((copy) << 0)) static const struct exynos_cpuclk_cfg_data e4412_armclk_d[] __initconst = { + { 1704000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4412_CPU_DIV1(7, 0, 7), }, + { 1600000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4412_CPU_DIV1(7, 0, 6), }, { 1500000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4412_CPU_DIV1(7, 0, 6), }, { 1400000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4412_CPU_DIV1(6, 0, 6), }, { 1300000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4412_CPU_DIV1(6, 0, 5), }, diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c deleted file mode 100644 index 6c9063159717..000000000000 --- a/drivers/clk/samsung/clk-exynos4415.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * Author: Chanwoo Choi <cw00.choi@samsung.com> - * - * 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. - * - * Common Clock Framework support for Exynos4415 SoC. - */ - -#include <linux/clk-provider.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/platform_device.h> -#include <linux/syscore_ops.h> - -#include <dt-bindings/clock/exynos4415.h> - -#include "clk.h" -#include "clk-pll.h" - -#define SRC_LEFTBUS 0x4200 -#define DIV_LEFTBUS 0x4500 -#define GATE_IP_LEFTBUS 0x4800 -#define GATE_IP_IMAGE 0x4930 -#define SRC_RIGHTBUS 0x8200 -#define DIV_RIGHTBUS 0x8500 -#define GATE_IP_RIGHTBUS 0x8800 -#define GATE_IP_PERIR 0x8960 -#define EPLL_LOCK 0xc010 -#define G3D_PLL_LOCK 0xc020 -#define DISP_PLL_LOCK 0xc030 -#define ISP_PLL_LOCK 0xc040 -#define EPLL_CON0 0xc110 -#define EPLL_CON1 0xc114 -#define EPLL_CON2 0xc118 -#define G3D_PLL_CON0 0xc120 -#define G3D_PLL_CON1 0xc124 -#define G3D_PLL_CON2 0xc128 -#define ISP_PLL_CON0 0xc130 -#define ISP_PLL_CON1 0xc134 -#define ISP_PLL_CON2 0xc138 -#define DISP_PLL_CON0 0xc140 -#define DISP_PLL_CON1 0xc144 -#define DISP_PLL_CON2 0xc148 -#define SRC_TOP0 0xc210 -#define SRC_TOP1 0xc214 -#define SRC_CAM 0xc220 -#define SRC_TV 0xc224 -#define SRC_MFC 0xc228 -#define SRC_G3D 0xc22c -#define SRC_LCD 0xc234 -#define SRC_ISP 0xc238 -#define SRC_MAUDIO 0xc23c -#define SRC_FSYS 0xc240 -#define SRC_PERIL0 0xc250 -#define SRC_PERIL1 0xc254 -#define SRC_CAM1 0xc258 -#define SRC_TOP_ISP0 0xc25c -#define SRC_TOP_ISP1 0xc260 -#define SRC_MASK_TOP 0xc310 -#define SRC_MASK_CAM 0xc320 -#define SRC_MASK_TV 0xc324 -#define SRC_MASK_LCD 0xc334 -#define SRC_MASK_ISP 0xc338 -#define SRC_MASK_MAUDIO 0xc33c -#define SRC_MASK_FSYS 0xc340 -#define SRC_MASK_PERIL0 0xc350 -#define SRC_MASK_PERIL1 0xc354 -#define DIV_TOP 0xc510 -#define DIV_CAM 0xc520 -#define DIV_TV 0xc524 -#define DIV_MFC 0xc528 -#define DIV_G3D 0xc52c -#define DIV_LCD 0xc534 -#define DIV_ISP 0xc538 -#define DIV_MAUDIO 0xc53c -#define DIV_FSYS0 0xc540 -#define DIV_FSYS1 0xc544 -#define DIV_FSYS2 0xc548 -#define DIV_PERIL0 0xc550 -#define DIV_PERIL1 0xc554 -#define DIV_PERIL2 0xc558 -#define DIV_PERIL3 0xc55c -#define DIV_PERIL4 0xc560 -#define DIV_PERIL5 0xc564 -#define DIV_CAM1 0xc568 -#define DIV_TOP_ISP1 0xc56c -#define DIV_TOP_ISP0 0xc570 -#define CLKDIV2_RATIO 0xc580 -#define GATE_SCLK_CAM 0xc820 -#define GATE_SCLK_TV 0xc824 -#define GATE_SCLK_MFC 0xc828 -#define GATE_SCLK_G3D 0xc82c -#define GATE_SCLK_LCD 0xc834 -#define GATE_SCLK_MAUDIO 0xc83c -#define GATE_SCLK_FSYS 0xc840 -#define GATE_SCLK_PERIL 0xc850 -#define GATE_IP_CAM 0xc920 -#define GATE_IP_TV 0xc924 -#define GATE_IP_MFC 0xc928 -#define GATE_IP_G3D 0xc92c -#define GATE_IP_LCD 0xc934 -#define GATE_IP_FSYS 0xc940 -#define GATE_IP_PERIL 0xc950 -#define GATE_BLOCK 0xc970 -#define APLL_LOCK 0x14000 -#define APLL_CON0 0x14100 -#define SRC_CPU 0x14200 -#define DIV_CPU0 0x14500 -#define DIV_CPU1 0x14504 - -static const unsigned long exynos4415_cmu_clk_regs[] __initconst = { - SRC_LEFTBUS, - DIV_LEFTBUS, - GATE_IP_LEFTBUS, - GATE_IP_IMAGE, - SRC_RIGHTBUS, - DIV_RIGHTBUS, - GATE_IP_RIGHTBUS, - GATE_IP_PERIR, - EPLL_LOCK, - G3D_PLL_LOCK, - DISP_PLL_LOCK, - ISP_PLL_LOCK, - EPLL_CON0, - EPLL_CON1, - EPLL_CON2, - G3D_PLL_CON0, - G3D_PLL_CON1, - G3D_PLL_CON2, - ISP_PLL_CON0, - ISP_PLL_CON1, - ISP_PLL_CON2, - DISP_PLL_CON0, - DISP_PLL_CON1, - DISP_PLL_CON2, - SRC_TOP0, - SRC_TOP1, - SRC_CAM, - SRC_TV, - SRC_MFC, - SRC_G3D, - SRC_LCD, - SRC_ISP, - SRC_MAUDIO, - SRC_FSYS, - SRC_PERIL0, - SRC_PERIL1, - SRC_CAM1, - SRC_TOP_ISP0, - SRC_TOP_ISP1, - SRC_MASK_TOP, - SRC_MASK_CAM, - SRC_MASK_TV, - SRC_MASK_LCD, - SRC_MASK_ISP, - SRC_MASK_MAUDIO, - SRC_MASK_FSYS, - SRC_MASK_PERIL0, - SRC_MASK_PERIL1, - DIV_TOP, - DIV_CAM, - DIV_TV, - DIV_MFC, - DIV_G3D, - DIV_LCD, - DIV_ISP, - DIV_MAUDIO, - DIV_FSYS0, - DIV_FSYS1, - DIV_FSYS2, - DIV_PERIL0, - DIV_PERIL1, - DIV_PERIL2, - DIV_PERIL3, - DIV_PERIL4, - DIV_PERIL5, - DIV_CAM1, - DIV_TOP_ISP1, - DIV_TOP_ISP0, - CLKDIV2_RATIO, - GATE_SCLK_CAM, - GATE_SCLK_TV, - GATE_SCLK_MFC, - GATE_SCLK_G3D, - GATE_SCLK_LCD, - GATE_SCLK_MAUDIO, - GATE_SCLK_FSYS, - GATE_SCLK_PERIL, - GATE_IP_CAM, - GATE_IP_TV, - GATE_IP_MFC, - GATE_IP_G3D, - GATE_IP_LCD, - GATE_IP_FSYS, - GATE_IP_PERIL, - GATE_BLOCK, - APLL_LOCK, - APLL_CON0, - SRC_CPU, - DIV_CPU0, - DIV_CPU1, -}; - -/* list of all parent clock list */ -PNAME(mout_g3d_pllsrc_p) = { "fin_pll", }; - -PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; -PNAME(mout_g3d_pll_p) = { "fin_pll", "fout_g3d_pll", }; -PNAME(mout_isp_pll_p) = { "fin_pll", "fout_isp_pll", }; -PNAME(mout_disp_pll_p) = { "fin_pll", "fout_disp_pll", }; - -PNAME(mout_mpll_user_p) = { "fin_pll", "div_mpll_pre", }; -PNAME(mout_epll_p) = { "fin_pll", "fout_epll", }; -PNAME(mout_core_p) = { "mout_apll", "mout_mpll_user_c", }; -PNAME(mout_hpm_p) = { "mout_apll", "mout_mpll_user_c", }; - -PNAME(mout_ebi_p) = { "div_aclk_200", "div_aclk_160", }; -PNAME(mout_ebi_1_p) = { "mout_ebi", "mout_g3d_pll", }; - -PNAME(mout_gdl_p) = { "mout_mpll_user_l", }; -PNAME(mout_gdr_p) = { "mout_mpll_user_r", }; - -PNAME(mout_aclk_266_p) = { "mout_mpll_user_t", "mout_g3d_pll", }; - -PNAME(group_epll_g3dpll_p) = { "mout_epll", "mout_g3d_pll" }; -PNAME(group_sclk_p) = { "xxti", "xusbxti", - "none", "mout_isp_pll", - "none", "none", "div_mpll_pre", - "mout_epll", "mout_g3d_pll", }; -PNAME(group_spdif_p) = { "mout_audio0", "mout_audio1", - "mout_audio2", "spdif_extclk", }; -PNAME(group_sclk_audio2_p) = { "audiocdclk2", "none", - "none", "mout_isp_pll", - "mout_disp_pll", "xusbxti", - "div_mpll_pre", "mout_epll", - "mout_g3d_pll", }; -PNAME(group_sclk_audio1_p) = { "audiocdclk1", "none", - "none", "mout_isp_pll", - "mout_disp_pll", "xusbxti", - "div_mpll_pre", "mout_epll", - "mout_g3d_pll", }; -PNAME(group_sclk_audio0_p) = { "audiocdclk0", "none", - "none", "mout_isp_pll", - "mout_disp_pll", "xusbxti", - "div_mpll_pre", "mout_epll", - "mout_g3d_pll", }; -PNAME(group_fimc_lclk_p) = { "xxti", "xusbxti", - "none", "mout_isp_pll", - "none", "mout_disp_pll", - "mout_mpll_user_t", "mout_epll", - "mout_g3d_pll", }; -PNAME(group_sclk_fimd0_p) = { "xxti", "xusbxti", - "m_bitclkhsdiv4_4l", "mout_isp_pll", - "mout_disp_pll", "sclk_hdmiphy", - "div_mpll_pre", "mout_epll", - "mout_g3d_pll", }; -PNAME(mout_hdmi_p) = { "sclk_pixel", "sclk_hdmiphy" }; -PNAME(mout_mfc_p) = { "mout_mfc_0", "mout_mfc_1" }; -PNAME(mout_g3d_p) = { "mout_g3d_0", "mout_g3d_1" }; -PNAME(mout_jpeg_p) = { "mout_jpeg_0", "mout_jpeg_1" }; -PNAME(mout_jpeg1_p) = { "mout_epll", "mout_g3d_pll" }; -PNAME(group_aclk_isp0_300_p) = { "mout_isp_pll", "div_mpll_pre" }; -PNAME(group_aclk_isp0_400_user_p) = { "fin_pll", "div_aclk_400_mcuisp" }; -PNAME(group_aclk_isp0_300_user_p) = { "fin_pll", "mout_aclk_isp0_300" }; -PNAME(group_aclk_isp1_300_user_p) = { "fin_pll", "mout_aclk_isp1_300" }; -PNAME(group_mout_mpll_user_t_p) = { "mout_mpll_user_t" }; - -static const struct samsung_fixed_factor_clock exynos4415_fixed_factor_clks[] __initconst = { - /* HACK: fin_pll hardcoded to xusbxti until detection is implemented. */ - FFACTOR(CLK_FIN_PLL, "fin_pll", "xusbxti", 1, 1, 0), -}; - -static const struct samsung_fixed_rate_clock exynos4415_fixed_rate_clks[] __initconst = { - FRATE(CLK_SCLK_HDMIPHY, "sclk_hdmiphy", NULL, 0, 27000000), -}; - -static const struct samsung_mux_clock exynos4415_mux_clks[] __initconst = { - /* - * NOTE: Following table is sorted by register address in ascending - * order and then bitfield shift in descending order, as it is done - * in the User's Manual. When adding new entries, please make sure - * that the order is preserved, to avoid merge conflicts and make - * further work with defined data easier. - */ - - /* SRC_LEFTBUS */ - MUX(CLK_MOUT_MPLL_USER_L, "mout_mpll_user_l", mout_mpll_user_p, - SRC_LEFTBUS, 4, 1), - MUX(CLK_MOUT_GDL, "mout_gdl", mout_gdl_p, SRC_LEFTBUS, 0, 1), - - /* SRC_RIGHTBUS */ - MUX(CLK_MOUT_MPLL_USER_R, "mout_mpll_user_r", mout_mpll_user_p, - SRC_RIGHTBUS, 4, 1), - MUX(CLK_MOUT_GDR, "mout_gdr", mout_gdr_p, SRC_RIGHTBUS, 0, 1), - - /* SRC_TOP0 */ - MUX(CLK_MOUT_EBI, "mout_ebi", mout_ebi_p, SRC_TOP0, 28, 1), - MUX(CLK_MOUT_ACLK_200, "mout_aclk_200", group_mout_mpll_user_t_p, - SRC_TOP0, 24, 1), - MUX(CLK_MOUT_ACLK_160, "mout_aclk_160", group_mout_mpll_user_t_p, - SRC_TOP0, 20, 1), - MUX(CLK_MOUT_ACLK_100, "mout_aclk_100", group_mout_mpll_user_t_p, - SRC_TOP0, 16, 1), - MUX(CLK_MOUT_ACLK_266, "mout_aclk_266", mout_aclk_266_p, - SRC_TOP0, 12, 1), - MUX(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p, - SRC_TOP0, 8, 1), - MUX(CLK_MOUT_EPLL, "mout_epll", mout_epll_p, SRC_TOP0, 4, 1), - MUX(CLK_MOUT_EBI_1, "mout_ebi_1", mout_ebi_1_p, SRC_TOP0, 0, 1), - - /* SRC_TOP1 */ - MUX(CLK_MOUT_ISP_PLL, "mout_isp_pll", mout_isp_pll_p, - SRC_TOP1, 28, 1), - MUX(CLK_MOUT_DISP_PLL, "mout_disp_pll", mout_disp_pll_p, - SRC_TOP1, 16, 1), - MUX(CLK_MOUT_MPLL_USER_T, "mout_mpll_user_t", mout_mpll_user_p, - SRC_TOP1, 12, 1), - MUX(CLK_MOUT_ACLK_400_MCUISP, "mout_aclk_400_mcuisp", - group_mout_mpll_user_t_p, SRC_TOP1, 8, 1), - MUX(CLK_MOUT_G3D_PLLSRC, "mout_g3d_pllsrc", mout_g3d_pllsrc_p, - SRC_TOP1, 0, 1), - - /* SRC_CAM */ - MUX(CLK_MOUT_CSIS1, "mout_csis1", group_fimc_lclk_p, SRC_CAM, 28, 4), - MUX(CLK_MOUT_CSIS0, "mout_csis0", group_fimc_lclk_p, SRC_CAM, 24, 4), - MUX(CLK_MOUT_CAM1, "mout_cam1", group_fimc_lclk_p, SRC_CAM, 20, 4), - MUX(CLK_MOUT_FIMC3_LCLK, "mout_fimc3_lclk", group_fimc_lclk_p, SRC_CAM, - 12, 4), - MUX(CLK_MOUT_FIMC2_LCLK, "mout_fimc2_lclk", group_fimc_lclk_p, SRC_CAM, - 8, 4), - MUX(CLK_MOUT_FIMC1_LCLK, "mout_fimc1_lclk", group_fimc_lclk_p, SRC_CAM, - 4, 4), - MUX(CLK_MOUT_FIMC0_LCLK, "mout_fimc0_lclk", group_fimc_lclk_p, SRC_CAM, - 0, 4), - - /* SRC_TV */ - MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), - - /* SRC_MFC */ - MUX(CLK_MOUT_MFC, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), - MUX(CLK_MOUT_MFC_1, "mout_mfc_1", group_epll_g3dpll_p, SRC_MFC, 4, 1), - MUX(CLK_MOUT_MFC_0, "mout_mfc_0", group_mout_mpll_user_t_p, SRC_MFC, 0, - 1), - - /* SRC_G3D */ - MUX(CLK_MOUT_G3D, "mout_g3d", mout_g3d_p, SRC_G3D, 8, 1), - MUX(CLK_MOUT_G3D_1, "mout_g3d_1", group_epll_g3dpll_p, SRC_G3D, 4, 1), - MUX(CLK_MOUT_G3D_0, "mout_g3d_0", group_mout_mpll_user_t_p, SRC_G3D, 0, - 1), - - /* SRC_LCD */ - MUX(CLK_MOUT_MIPI0, "mout_mipi0", group_fimc_lclk_p, SRC_LCD, 12, 4), - MUX(CLK_MOUT_FIMD0, "mout_fimd0", group_sclk_fimd0_p, SRC_LCD, 0, 4), - - /* SRC_ISP */ - MUX(CLK_MOUT_TSADC_ISP, "mout_tsadc_isp", group_fimc_lclk_p, SRC_ISP, - 16, 4), - MUX(CLK_MOUT_UART_ISP, "mout_uart_isp", group_fimc_lclk_p, SRC_ISP, - 12, 4), - MUX(CLK_MOUT_SPI1_ISP, "mout_spi1_isp", group_fimc_lclk_p, SRC_ISP, - 8, 4), - MUX(CLK_MOUT_SPI0_ISP, "mout_spi0_isp", group_fimc_lclk_p, SRC_ISP, - 4, 4), - MUX(CLK_MOUT_PWM_ISP, "mout_pwm_isp", group_fimc_lclk_p, SRC_ISP, - 0, 4), - - /* SRC_MAUDIO */ - MUX(CLK_MOUT_AUDIO0, "mout_audio0", group_sclk_audio0_p, SRC_MAUDIO, - 0, 4), - - /* SRC_FSYS */ - MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4), - MUX(CLK_MOUT_MMC2, "mout_mmc2", group_sclk_p, SRC_FSYS, 8, 4), - MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 4), - MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 4), - - /* SRC_PERIL0 */ - MUX(CLK_MOUT_UART3, "mout_uart3", group_sclk_p, SRC_PERIL0, 12, 4), - MUX(CLK_MOUT_UART2, "mout_uart2", group_sclk_p, SRC_PERIL0, 8, 4), - MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4), - MUX(CLK_MOUT_UART0, "mout_uart0", group_sclk_p, SRC_PERIL0, 0, 4), - - /* SRC_PERIL1 */ - MUX(CLK_MOUT_SPI2, "mout_spi2", group_sclk_p, SRC_PERIL1, 24, 4), - MUX(CLK_MOUT_SPI1, "mout_spi1", group_sclk_p, SRC_PERIL1, 20, 4), - MUX(CLK_MOUT_SPI0, "mout_spi0", group_sclk_p, SRC_PERIL1, 16, 4), - MUX(CLK_MOUT_SPDIF, "mout_spdif", group_spdif_p, SRC_PERIL1, 8, 4), - MUX(CLK_MOUT_AUDIO2, "mout_audio2", group_sclk_audio2_p, SRC_PERIL1, - 4, 4), - MUX(CLK_MOUT_AUDIO1, "mout_audio1", group_sclk_audio1_p, SRC_PERIL1, - 0, 4), - - /* SRC_CPU */ - MUX(CLK_MOUT_MPLL_USER_C, "mout_mpll_user_c", mout_mpll_user_p, - SRC_CPU, 24, 1), - MUX(CLK_MOUT_HPM, "mout_hpm", mout_hpm_p, SRC_CPU, 20, 1), - MUX_F(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1, 0, - CLK_MUX_READ_ONLY), - MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, - CLK_SET_RATE_PARENT, 0), - - /* SRC_CAM1 */ - MUX(CLK_MOUT_PXLASYNC_CSIS1_FIMC, "mout_pxlasync_csis1", - group_fimc_lclk_p, SRC_CAM1, 20, 1), - MUX(CLK_MOUT_PXLASYNC_CSIS0_FIMC, "mout_pxlasync_csis0", - group_fimc_lclk_p, SRC_CAM1, 16, 1), - MUX(CLK_MOUT_JPEG, "mout_jpeg", mout_jpeg_p, SRC_CAM1, 8, 1), - MUX(CLK_MOUT_JPEG1, "mout_jpeg_1", mout_jpeg1_p, SRC_CAM1, 4, 1), - MUX(CLK_MOUT_JPEG0, "mout_jpeg_0", group_mout_mpll_user_t_p, SRC_CAM1, - 0, 1), - - /* SRC_TOP_ISP0 */ - MUX(CLK_MOUT_ACLK_ISP0_300, "mout_aclk_isp0_300", - group_aclk_isp0_300_p, SRC_TOP_ISP0, 8, 1), - MUX(CLK_MOUT_ACLK_ISP0_400, "mout_aclk_isp0_400_user", - group_aclk_isp0_400_user_p, SRC_TOP_ISP0, 4, 1), - MUX(CLK_MOUT_ACLK_ISP0_300_USER, "mout_aclk_isp0_300_user", - group_aclk_isp0_300_user_p, SRC_TOP_ISP0, 0, 1), - - /* SRC_TOP_ISP1 */ - MUX(CLK_MOUT_ACLK_ISP1_300, "mout_aclk_isp1_300", - group_aclk_isp0_300_p, SRC_TOP_ISP1, 4, 1), - MUX(CLK_MOUT_ACLK_ISP1_300_USER, "mout_aclk_isp1_300_user", - group_aclk_isp1_300_user_p, SRC_TOP_ISP1, 0, 1), -}; - -static const struct samsung_div_clock exynos4415_div_clks[] __initconst = { - /* - * NOTE: Following table is sorted by register address in ascending - * order and then bitfield shift in descending order, as it is done - * in the User's Manual. When adding new entries, please make sure - * that the order is preserved, to avoid merge conflicts and make - * further work with defined data easier. - */ - - /* DIV_LEFTBUS */ - DIV(CLK_DIV_GPL, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3), - DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 4), - - /* DIV_RIGHTBUS */ - DIV(CLK_DIV_GPR, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3), - DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 4), - - /* DIV_TOP */ - DIV(CLK_DIV_ACLK_400_MCUISP, "div_aclk_400_mcuisp", - "mout_aclk_400_mcuisp", DIV_TOP, 24, 3), - DIV(CLK_DIV_EBI, "div_ebi", "mout_ebi_1", DIV_TOP, 16, 3), - DIV(CLK_DIV_ACLK_200, "div_aclk_200", "mout_aclk_200", DIV_TOP, 12, 3), - DIV(CLK_DIV_ACLK_160, "div_aclk_160", "mout_aclk_160", DIV_TOP, 8, 3), - DIV(CLK_DIV_ACLK_100, "div_aclk_100", "mout_aclk_100", DIV_TOP, 4, 4), - DIV(CLK_DIV_ACLK_266, "div_aclk_266", "mout_aclk_266", DIV_TOP, 0, 3), - - /* DIV_CAM */ - DIV(CLK_DIV_CSIS1, "div_csis1", "mout_csis1", DIV_CAM, 28, 4), - DIV(CLK_DIV_CSIS0, "div_csis0", "mout_csis0", DIV_CAM, 24, 4), - DIV(CLK_DIV_CAM1, "div_cam1", "mout_cam1", DIV_CAM, 20, 4), - DIV(CLK_DIV_FIMC3_LCLK, "div_fimc3_lclk", "mout_fimc3_lclk", DIV_CAM, - 12, 4), - DIV(CLK_DIV_FIMC2_LCLK, "div_fimc2_lclk", "mout_fimc2_lclk", DIV_CAM, - 8, 4), - DIV(CLK_DIV_FIMC1_LCLK, "div_fimc1_lclk", "mout_fimc1_lclk", DIV_CAM, - 4, 4), - DIV(CLK_DIV_FIMC0_LCLK, "div_fimc0_lclk", "mout_fimc0_lclk", DIV_CAM, - 0, 4), - - /* DIV_TV */ - DIV(CLK_DIV_TV_BLK, "div_tv_blk", "mout_g3d_pll", DIV_TV, 0, 4), - - /* DIV_MFC */ - DIV(CLK_DIV_MFC, "div_mfc", "mout_mfc", DIV_MFC, 0, 4), - - /* DIV_G3D */ - DIV(CLK_DIV_G3D, "div_g3d", "mout_g3d", DIV_G3D, 0, 4), - - /* DIV_LCD */ - DIV_F(CLK_DIV_MIPI0_PRE, "div_mipi0_pre", "div_mipi0", DIV_LCD, 20, 4, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_MIPI0, "div_mipi0", "mout_mipi0", DIV_LCD, 16, 4), - DIV(CLK_DIV_FIMD0, "div_fimd0", "mout_fimd0", DIV_LCD, 0, 4), - - /* DIV_ISP */ - DIV(CLK_DIV_UART_ISP, "div_uart_isp", "mout_uart_isp", DIV_ISP, 28, 4), - DIV_F(CLK_DIV_SPI1_ISP_PRE, "div_spi1_isp_pre", "div_spi1_isp", - DIV_ISP, 20, 8, CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4), - DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp", - DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 4, 4), - DIV(CLK_DIV_PWM_ISP, "div_pwm_isp", "mout_pwm_isp", DIV_ISP, 0, 4), - - /* DIV_MAUDIO */ - DIV(CLK_DIV_PCM0, "div_pcm0", "div_audio0", DIV_MAUDIO, 4, 8), - DIV(CLK_DIV_AUDIO0, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4), - - /* DIV_FSYS0 */ - DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_TSADC, "div_tsadc", "mout_tsadc", DIV_FSYS0, 0, 4), - - /* DIV_FSYS1 */ - DIV_F(CLK_DIV_MMC1_PRE, "div_mmc1_pre", "div_mmc1", DIV_FSYS1, 24, 8, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_MMC1, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4), - DIV_F(CLK_DIV_MMC0_PRE, "div_mmc0_pre", "div_mmc0", DIV_FSYS1, 8, 8, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_MMC0, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4), - - /* DIV_FSYS2 */ - DIV_F(CLK_DIV_MMC2_PRE, "div_mmc2_pre", "div_mmc2", DIV_FSYS2, 8, 8, - CLK_SET_RATE_PARENT, 0), - DIV_F(CLK_DIV_MMC2_PRE, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4, - CLK_SET_RATE_PARENT, 0), - - /* DIV_PERIL0 */ - DIV(CLK_DIV_UART3, "div_uart3", "mout_uart3", DIV_PERIL0, 12, 4), - DIV(CLK_DIV_UART2, "div_uart2", "mout_uart2", DIV_PERIL0, 8, 4), - DIV(CLK_DIV_UART1, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4), - DIV(CLK_DIV_UART0, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4), - - /* DIV_PERIL1 */ - DIV_F(CLK_DIV_SPI1_PRE, "div_spi1_pre", "div_spi1", DIV_PERIL1, 24, 8, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_SPI1, "div_spi1", "mout_spi1", DIV_PERIL1, 16, 4), - DIV_F(CLK_DIV_SPI0_PRE, "div_spi0_pre", "div_spi0", DIV_PERIL1, 8, 8, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_SPI0, "div_spi0", "mout_spi0", DIV_PERIL1, 0, 4), - - /* DIV_PERIL2 */ - DIV_F(CLK_DIV_SPI2_PRE, "div_spi2_pre", "div_spi2", DIV_PERIL2, 8, 8, - CLK_SET_RATE_PARENT, 0), - DIV(CLK_DIV_SPI2, "div_spi2", "mout_spi2", DIV_PERIL2, 0, 4), - - /* DIV_PERIL4 */ - DIV(CLK_DIV_PCM2, "div_pcm2", "div_audio2", DIV_PERIL4, 20, 8), - DIV(CLK_DIV_AUDIO2, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), - DIV(CLK_DIV_PCM1, "div_pcm1", "div_audio1", DIV_PERIL4, 20, 8), - DIV(CLK_DIV_AUDIO1, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4), - - /* DIV_PERIL5 */ - DIV(CLK_DIV_I2S1, "div_i2s1", "div_audio1", DIV_PERIL5, 0, 6), - - /* DIV_CAM1 */ - DIV(CLK_DIV_PXLASYNC_CSIS1_FIMC, "div_pxlasync_csis1_fimc", - "mout_pxlasync_csis1", DIV_CAM1, 24, 4), - DIV(CLK_DIV_PXLASYNC_CSIS0_FIMC, "div_pxlasync_csis0_fimc", - "mout_pxlasync_csis0", DIV_CAM1, 20, 4), - DIV(CLK_DIV_JPEG, "div_jpeg", "mout_jpeg", DIV_CAM1, 0, 4), - - /* DIV_CPU0 */ - DIV(CLK_DIV_CORE2, "div_core2", "div_core", DIV_CPU0, 28, 3), - DIV_F(CLK_DIV_APLL, "div_apll", "mout_apll", DIV_CPU0, 24, 3, - CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY), - DIV(CLK_DIV_PCLK_DBG, "div_pclk_dbg", "div_core2", DIV_CPU0, 20, 3), - DIV(CLK_DIV_ATB, "div_atb", "div_core2", DIV_CPU0, 16, 3), - DIV(CLK_DIV_PERIPH, "div_periph", "div_core2", DIV_CPU0, 12, 3), - DIV(CLK_DIV_COREM1, "div_corem1", "div_core2", DIV_CPU0, 8, 3), - DIV(CLK_DIV_COREM0, "div_corem0", "div_core2", DIV_CPU0, 4, 3), - DIV_F(CLK_DIV_CORE, "div_core", "mout_core", DIV_CPU0, 0, 3, - CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY), - - /* DIV_CPU1 */ - DIV(CLK_DIV_HPM, "div_hpm", "div_copy", DIV_CPU1, 4, 3), - DIV(CLK_DIV_COPY, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), -}; - -static const struct samsung_gate_clock exynos4415_gate_clks[] __initconst = { - /* - * NOTE: Following table is sorted by register address in ascending - * order and then bitfield shift in descending order, as it is done - * in the User's Manual. When adding new entries, please make sure - * that the order is preserved, to avoid merge conflicts and make - * further work with defined data easier. - */ - - /* GATE_IP_LEFTBUS */ - GATE(CLK_ASYNC_G3D, "async_g3d", "div_aclk_100", GATE_IP_LEFTBUS, 6, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_MFCL, "async_mfcl", "div_aclk_100", GATE_IP_LEFTBUS, 4, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_TVX, "async_tvx", "div_aclk_100", GATE_IP_LEFTBUS, 3, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_PPMULEFT, "ppmuleft", "div_aclk_100", GATE_IP_LEFTBUS, 1, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_GPIO_LEFT, "gpio_left", "div_aclk_100", GATE_IP_LEFTBUS, 0, - CLK_IGNORE_UNUSED, 0), - - /* GATE_IP_IMAGE */ - GATE(CLK_PPMUIMAGE, "ppmuimage", "div_aclk_100", GATE_IP_IMAGE, - 9, 0, 0), - GATE(CLK_QEMDMA2, "qe_mdma2", "div_aclk_100", GATE_IP_IMAGE, - 8, 0, 0), - GATE(CLK_QEROTATOR, "qe_rotator", "div_aclk_100", GATE_IP_IMAGE, - 7, 0, 0), - GATE(CLK_SMMUMDMA2, "smmu_mdam2", "div_aclk_100", GATE_IP_IMAGE, - 5, 0, 0), - GATE(CLK_SMMUROTATOR, "smmu_rotator", "div_aclk_100", GATE_IP_IMAGE, - 4, 0, 0), - GATE(CLK_MDMA2, "mdma2", "div_aclk_100", GATE_IP_IMAGE, 2, 0, 0), - GATE(CLK_ROTATOR, "rotator", "div_aclk_100", GATE_IP_IMAGE, 1, 0, 0), - - /* GATE_IP_RIGHTBUS */ - GATE(CLK_ASYNC_ISPMX, "async_ispmx", "div_aclk_100", - GATE_IP_RIGHTBUS, 9, CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_MAUDIOX, "async_maudiox", "div_aclk_100", - GATE_IP_RIGHTBUS, 7, CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_MFCR, "async_mfcr", "div_aclk_100", - GATE_IP_RIGHTBUS, 6, CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_FSYSD, "async_fsysd", "div_aclk_100", - GATE_IP_RIGHTBUS, 5, CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_LCD0X, "async_lcd0x", "div_aclk_100", - GATE_IP_RIGHTBUS, 3, CLK_IGNORE_UNUSED, 0), - GATE(CLK_ASYNC_CAMX, "async_camx", "div_aclk_100", - GATE_IP_RIGHTBUS, 2, CLK_IGNORE_UNUSED, 0), - GATE(CLK_PPMURIGHT, "ppmuright", "div_aclk_100", - GATE_IP_RIGHTBUS, 1, CLK_IGNORE_UNUSED, 0), - GATE(CLK_GPIO_RIGHT, "gpio_right", "div_aclk_100", - GATE_IP_RIGHTBUS, 0, CLK_IGNORE_UNUSED, 0), - - /* GATE_IP_PERIR */ - GATE(CLK_ANTIRBK_APBIF, "antirbk_apbif", "div_aclk_100", - GATE_IP_PERIR, 24, CLK_IGNORE_UNUSED, 0), - GATE(CLK_EFUSE_WRITER_APBIF, "efuse_writer_apbif", "div_aclk_100", - GATE_IP_PERIR, 23, CLK_IGNORE_UNUSED, 0), - GATE(CLK_MONOCNT, "monocnt", "div_aclk_100", GATE_IP_PERIR, 22, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC6, "tzpc6", "div_aclk_100", GATE_IP_PERIR, 21, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_PROVISIONKEY1, "provisionkey1", "div_aclk_100", - GATE_IP_PERIR, 20, CLK_IGNORE_UNUSED, 0), - GATE(CLK_PROVISIONKEY0, "provisionkey0", "div_aclk_100", - GATE_IP_PERIR, 19, CLK_IGNORE_UNUSED, 0), - GATE(CLK_CMU_ISPPART, "cmu_isppart", "div_aclk_100", GATE_IP_PERIR, 18, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TMU_APBIF, "tmu_apbif", "div_aclk_100", - GATE_IP_PERIR, 17, 0, 0), - GATE(CLK_KEYIF, "keyif", "div_aclk_100", GATE_IP_PERIR, 16, 0, 0), - GATE(CLK_RTC, "rtc", "div_aclk_100", GATE_IP_PERIR, 15, 0, 0), - GATE(CLK_WDT, "wdt", "div_aclk_100", GATE_IP_PERIR, 14, 0, 0), - GATE(CLK_MCT, "mct", "div_aclk_100", GATE_IP_PERIR, 13, 0, 0), - GATE(CLK_SECKEY, "seckey", "div_aclk_100", GATE_IP_PERIR, 12, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_HDMI_CEC, "hdmi_cec", "div_aclk_100", GATE_IP_PERIR, 11, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC5, "tzpc5", "div_aclk_100", GATE_IP_PERIR, 10, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC4, "tzpc4", "div_aclk_100", GATE_IP_PERIR, 9, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC3, "tzpc3", "div_aclk_100", GATE_IP_PERIR, 8, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC2, "tzpc2", "div_aclk_100", GATE_IP_PERIR, 7, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC1, "tzpc1", "div_aclk_100", GATE_IP_PERIR, 6, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_TZPC0, "tzpc0", "div_aclk_100", GATE_IP_PERIR, 5, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_CMU_COREPART, "cmu_corepart", "div_aclk_100", GATE_IP_PERIR, 4, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_CMU_TOPPART, "cmu_toppart", "div_aclk_100", GATE_IP_PERIR, 3, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_PMU_APBIF, "pmu_apbif", "div_aclk_100", GATE_IP_PERIR, 2, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_SYSREG, "sysreg", "div_aclk_100", GATE_IP_PERIR, 1, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_CHIP_ID, "chip_id", "div_aclk_100", GATE_IP_PERIR, 0, - CLK_IGNORE_UNUSED, 0), - - /* GATE_SCLK_CAM - non-completed */ - GATE(CLK_SCLK_PXLAYSNC_CSIS1_FIMC, "sclk_pxlasync_csis1_fimc", - "div_pxlasync_csis1_fimc", GATE_SCLK_CAM, 11, - CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_PXLAYSNC_CSIS0_FIMC, "sclk_pxlasync_csis0_fimc", - "div_pxlasync_csis0_fimc", GATE_SCLK_CAM, - 10, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_JPEG, "sclk_jpeg", "div_jpeg", - GATE_SCLK_CAM, 8, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_CSIS1, "sclk_csis1", "div_csis1", - GATE_SCLK_CAM, 7, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_CSIS0, "sclk_csis0", "div_csis0", - GATE_SCLK_CAM, 6, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_CAM1, "sclk_cam1", "div_cam1", - GATE_SCLK_CAM, 5, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_FIMC3_LCLK, "sclk_fimc3_lclk", "div_fimc3_lclk", - GATE_SCLK_CAM, 3, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_FIMC2_LCLK, "sclk_fimc2_lclk", "div_fimc2_lclk", - GATE_SCLK_CAM, 2, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_FIMC1_LCLK, "sclk_fimc1_lclk", "div_fimc1_lclk", - GATE_SCLK_CAM, 1, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_FIMC0_LCLK, "sclk_fimc0_lclk", "div_fimc0_lclk", - GATE_SCLK_CAM, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_TV */ - GATE(CLK_SCLK_PIXEL, "sclk_pixel", "div_tv_blk", - GATE_SCLK_TV, 3, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_HDMI, "sclk_hdmi", "mout_hdmi", - GATE_SCLK_TV, 2, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_MIXER, "sclk_mixer", "div_tv_blk", - GATE_SCLK_TV, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_MFC */ - GATE(CLK_SCLK_MFC, "sclk_mfc", "div_mfc", - GATE_SCLK_MFC, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_G3D */ - GATE(CLK_SCLK_G3D, "sclk_g3d", "div_g3d", - GATE_SCLK_G3D, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_LCD */ - GATE(CLK_SCLK_MIPIDPHY4L, "sclk_mipidphy4l", "div_mipi0", - GATE_SCLK_LCD, 4, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_MIPI0, "sclk_mipi0", "div_mipi0_pre", - GATE_SCLK_LCD, 3, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_MDNIE0, "sclk_mdnie0", "div_fimd0", - GATE_SCLK_LCD, 1, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_FIMD0, "sclk_fimd0", "div_fimd0", - GATE_SCLK_LCD, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_MAUDIO */ - GATE(CLK_SCLK_PCM0, "sclk_pcm0", "div_pcm0", - GATE_SCLK_MAUDIO, 1, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_AUDIO0, "sclk_audio0", "div_audio0", - GATE_SCLK_MAUDIO, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_FSYS */ - GATE(CLK_SCLK_TSADC, "sclk_tsadc", "div_tsadc_pre", - GATE_SCLK_FSYS, 9, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_EBI, "sclk_ebi", "div_ebi", - GATE_SCLK_FSYS, 6, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_MMC2, "sclk_mmc2", "div_mmc2_pre", - GATE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_MMC1, "sclk_mmc1", "div_mmc1_pre", - GATE_SCLK_FSYS, 1, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_MMC0, "sclk_mmc0", "div_mmc0_pre", - GATE_SCLK_FSYS, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_SCLK_PERIL */ - GATE(CLK_SCLK_I2S, "sclk_i2s1", "div_i2s1", - GATE_SCLK_PERIL, 18, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_PCM2, "sclk_pcm2", "div_pcm2", - GATE_SCLK_PERIL, 16, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_PCM1, "sclk_pcm1", "div_pcm1", - GATE_SCLK_PERIL, 15, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_AUDIO2, "sclk_audio2", "div_audio2", - GATE_SCLK_PERIL, 14, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_AUDIO1, "sclk_audio1", "div_audio1", - GATE_SCLK_PERIL, 13, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_SPDIF, "sclk_spdif", "mout_spdif", - GATE_SCLK_PERIL, 10, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_SPI2, "sclk_spi2", "div_spi2_pre", - GATE_SCLK_PERIL, 8, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_SPI1, "sclk_spi1", "div_spi1_pre", - GATE_SCLK_PERIL, 7, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_SPI0, "sclk_spi0", "div_spi0_pre", - GATE_SCLK_PERIL, 6, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_UART3, "sclk_uart3", "div_uart3", - GATE_SCLK_PERIL, 3, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_UART2, "sclk_uart2", "div_uart2", - GATE_SCLK_PERIL, 2, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_UART1, "sclk_uart1", "div_uart1", - GATE_SCLK_PERIL, 1, CLK_SET_RATE_PARENT, 0), - GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0", - GATE_SCLK_PERIL, 0, CLK_SET_RATE_PARENT, 0), - - /* GATE_IP_CAM */ - GATE(CLK_SMMUFIMC_LITE2, "smmufimc_lite2", "div_aclk_160", GATE_IP_CAM, - 22, CLK_IGNORE_UNUSED, 0), - GATE(CLK_FIMC_LITE2, "fimc_lite2", "div_aclk_160", GATE_IP_CAM, - 20, CLK_IGNORE_UNUSED, 0), - GATE(CLK_PIXELASYNCM1, "pixelasyncm1", "div_aclk_160", GATE_IP_CAM, - 18, CLK_IGNORE_UNUSED, 0), - GATE(CLK_PIXELASYNCM0, "pixelasyncm0", "div_aclk_160", GATE_IP_CAM, - 17, CLK_IGNORE_UNUSED, 0), - GATE(CLK_PPMUCAMIF, "ppmucamif", "div_aclk_160", GATE_IP_CAM, - 16, CLK_IGNORE_UNUSED, 0), - GATE(CLK_SMMUJPEG, "smmujpeg", "div_aclk_160", GATE_IP_CAM, 11, 0, 0), - GATE(CLK_SMMUFIMC3, "smmufimc3", "div_aclk_160", GATE_IP_CAM, 10, 0, 0), - GATE(CLK_SMMUFIMC2, "smmufimc2", "div_aclk_160", GATE_IP_CAM, 9, 0, 0), - GATE(CLK_SMMUFIMC1, "smmufimc1", "div_aclk_160", GATE_IP_CAM, 8, 0, 0), - GATE(CLK_SMMUFIMC0, "smmufimc0", "div_aclk_160", GATE_IP_CAM, 7, 0, 0), - GATE(CLK_JPEG, "jpeg", "div_aclk_160", GATE_IP_CAM, 6, 0, 0), - GATE(CLK_CSIS1, "csis1", "div_aclk_160", GATE_IP_CAM, 5, 0, 0), - GATE(CLK_CSIS0, "csis0", "div_aclk_160", GATE_IP_CAM, 4, 0, 0), - GATE(CLK_FIMC3, "fimc3", "div_aclk_160", GATE_IP_CAM, 3, 0, 0), - GATE(CLK_FIMC2, "fimc2", "div_aclk_160", GATE_IP_CAM, 2, 0, 0), - GATE(CLK_FIMC1, "fimc1", "div_aclk_160", GATE_IP_CAM, 1, 0, 0), - GATE(CLK_FIMC0, "fimc0", "div_aclk_160", GATE_IP_CAM, 0, 0, 0), - - /* GATE_IP_TV */ - GATE(CLK_PPMUTV, "ppmutv", "div_aclk_100", GATE_IP_TV, 5, 0, 0), - GATE(CLK_SMMUTV, "smmutv", "div_aclk_100", GATE_IP_TV, 4, 0, 0), - GATE(CLK_HDMI, "hdmi", "div_aclk_100", GATE_IP_TV, 3, 0, 0), - GATE(CLK_MIXER, "mixer", "div_aclk_100", GATE_IP_TV, 1, 0, 0), - GATE(CLK_VP, "vp", "div_aclk_100", GATE_IP_TV, 0, 0, 0), - - /* GATE_IP_MFC */ - GATE(CLK_PPMUMFC_R, "ppmumfc_r", "div_aclk_200", GATE_IP_MFC, 4, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_PPMUMFC_L, "ppmumfc_l", "div_aclk_200", GATE_IP_MFC, 3, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_SMMUMFC_R, "smmumfc_r", "div_aclk_200", GATE_IP_MFC, 2, 0, 0), - GATE(CLK_SMMUMFC_L, "smmumfc_l", "div_aclk_200", GATE_IP_MFC, 1, 0, 0), - GATE(CLK_MFC, "mfc", "div_aclk_200", GATE_IP_MFC, 0, 0, 0), - - /* GATE_IP_G3D */ - GATE(CLK_PPMUG3D, "ppmug3d", "div_aclk_200", GATE_IP_G3D, 1, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_G3D, "g3d", "div_aclk_200", GATE_IP_G3D, 0, 0, 0), - - /* GATE_IP_LCD */ - GATE(CLK_PPMULCD0, "ppmulcd0", "div_aclk_160", GATE_IP_LCD, 5, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_SMMUFIMD0, "smmufimd0", "div_aclk_160", GATE_IP_LCD, 4, 0, 0), - GATE(CLK_DSIM0, "dsim0", "div_aclk_160", GATE_IP_LCD, 3, 0, 0), - GATE(CLK_SMIES, "smies", "div_aclk_160", GATE_IP_LCD, 2, 0, 0), - GATE(CLK_MIE0, "mie0", "div_aclk_160", GATE_IP_LCD, 1, 0, 0), - GATE(CLK_FIMD0, "fimd0", "div_aclk_160", GATE_IP_LCD, 0, 0, 0), - - /* GATE_IP_FSYS */ - GATE(CLK_TSADC, "tsadc", "div_aclk_200", GATE_IP_FSYS, 20, 0, 0), - GATE(CLK_PPMUFILE, "ppmufile", "div_aclk_200", GATE_IP_FSYS, 17, - CLK_IGNORE_UNUSED, 0), - GATE(CLK_NFCON, "nfcon", "div_aclk_200", GATE_IP_FSYS, 16, 0, 0), - GATE(CLK_USBDEVICE, "usbdevice", "div_aclk_200", GATE_IP_FSYS, 13, - 0, 0), - GATE(CLK_USBHOST, "usbhost", "div_aclk_200", GATE_IP_FSYS, 12, 0, 0), - GATE(CLK_SROMC, "sromc", "div_aclk_200", GATE_IP_FSYS, 11, 0, 0), - GATE(CLK_SDMMC2, "sdmmc2", "div_aclk_200", GATE_IP_FSYS, 7, 0, 0), - GATE(CLK_SDMMC1, "sdmmc1", "div_aclk_200", GATE_IP_FSYS, 6, 0, 0), - GATE(CLK_SDMMC0, "sdmmc0", "div_aclk_200", GATE_IP_FSYS, 5, 0, 0), - GATE(CLK_PDMA1, "pdma1", "div_aclk_200", GATE_IP_FSYS, 1, 0, 0), - GATE(CLK_PDMA0, "pdma0", "div_aclk_200", GATE_IP_FSYS, 0, 0, 0), - - /* GATE_IP_PERIL */ - GATE(CLK_SPDIF, "spdif", "div_aclk_100", GATE_IP_PERIL, 26, 0, 0), - GATE(CLK_PWM, "pwm", "div_aclk_100", GATE_IP_PERIL, 24, 0, 0), - GATE(CLK_PCM2, "pcm2", "div_aclk_100", GATE_IP_PERIL, 23, 0, 0), - GATE(CLK_PCM1, "pcm1", "div_aclk_100", GATE_IP_PERIL, 22, 0, 0), - GATE(CLK_I2S1, "i2s1", "div_aclk_100", GATE_IP_PERIL, 20, 0, 0), - GATE(CLK_SPI2, "spi2", "div_aclk_100", GATE_IP_PERIL, 18, 0, 0), - GATE(CLK_SPI1, "spi1", "div_aclk_100", GATE_IP_PERIL, 17, 0, 0), - GATE(CLK_SPI0, "spi0", "div_aclk_100", GATE_IP_PERIL, 16, 0, 0), - GATE(CLK_I2CHDMI, "i2chdmi", "div_aclk_100", GATE_IP_PERIL, 14, 0, 0), - GATE(CLK_I2C7, "i2c7", "div_aclk_100", GATE_IP_PERIL, 13, 0, 0), - GATE(CLK_I2C6, "i2c6", "div_aclk_100", GATE_IP_PERIL, 12, 0, 0), - GATE(CLK_I2C5, "i2c5", "div_aclk_100", GATE_IP_PERIL, 11, 0, 0), - GATE(CLK_I2C4, "i2c4", "div_aclk_100", GATE_IP_PERIL, 10, 0, 0), - GATE(CLK_I2C3, "i2c3", "div_aclk_100", GATE_IP_PERIL, 9, 0, 0), - GATE(CLK_I2C2, "i2c2", "div_aclk_100", GATE_IP_PERIL, 8, 0, 0), - GATE(CLK_I2C1, "i2c1", "div_aclk_100", GATE_IP_PERIL, 7, 0, 0), - GATE(CLK_I2C0, "i2c0", "div_aclk_100", GATE_IP_PERIL, 6, 0, 0), - GATE(CLK_UART3, "uart3", "div_aclk_100", GATE_IP_PERIL, 3, 0, 0), - GATE(CLK_UART2, "uart2", "div_aclk_100", GATE_IP_PERIL, 2, 0, 0), - GATE(CLK_UART1, "uart1", "div_aclk_100", GATE_IP_PERIL, 1, 0, 0), - GATE(CLK_UART0, "uart0", "div_aclk_100", GATE_IP_PERIL, 0, 0, 0), -}; - -/* - * APLL & MPLL & BPLL & ISP_PLL & DISP_PLL & G3D_PLL - */ -static const struct samsung_pll_rate_table exynos4415_pll_rates[] __initconst = { - PLL_35XX_RATE(1600000000, 400, 3, 1), - PLL_35XX_RATE(1500000000, 250, 2, 1), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 3, 1), - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1066000000, 533, 6, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(960000000, 320, 4, 1), - PLL_35XX_RATE(900000000, 300, 4, 1), - PLL_35XX_RATE(850000000, 425, 6, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(667000000, 667, 12, 1), - PLL_35XX_RATE(600000000, 400, 4, 2), - PLL_35XX_RATE(550000000, 275, 3, 2), - PLL_35XX_RATE(533000000, 533, 6, 2), - PLL_35XX_RATE(520000000, 260, 3, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(440000000, 220, 3, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(350000000, 175, 3, 2), - PLL_35XX_RATE(300000000, 300, 3, 3), - PLL_35XX_RATE(266000000, 266, 3, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), - PLL_35XX_RATE(160000000, 160, 3, 3), - PLL_35XX_RATE(100000000, 200, 3, 4), - { /* sentinel */ } -}; - -/* EPLL */ -static const struct samsung_pll_rate_table exynos4415_epll_rates[] __initconst = { - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(288000000, 96, 2, 2, 0), - PLL_36XX_RATE(192000000, 128, 2, 3, 0), - PLL_36XX_RATE(144000000, 96, 2, 3, 0), - PLL_36XX_RATE(96000000, 128, 2, 4, 0), - PLL_36XX_RATE(84000000, 112, 2, 4, 0), - PLL_36XX_RATE(80750011, 107, 2, 4, 43691), - PLL_36XX_RATE(73728004, 98, 2, 4, 19923), - PLL_36XX_RATE(67987602, 271, 3, 5, 62285), - PLL_36XX_RATE(65911004, 175, 2, 5, 49982), - PLL_36XX_RATE(50000000, 200, 3, 5, 0), - PLL_36XX_RATE(49152003, 131, 2, 5, 4719), - PLL_36XX_RATE(48000000, 128, 2, 5, 0), - PLL_36XX_RATE(45250000, 181, 3, 5, 0), - { /* sentinel */ } -}; - -static const struct samsung_pll_clock exynos4415_plls[] __initconst = { - PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", - APLL_LOCK, APLL_CON0, exynos4415_pll_rates), - PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll", - EPLL_LOCK, EPLL_CON0, exynos4415_epll_rates), - PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "mout_g3d_pllsrc", - G3D_PLL_LOCK, G3D_PLL_CON0, exynos4415_pll_rates), - PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll", - ISP_PLL_LOCK, ISP_PLL_CON0, exynos4415_pll_rates), - PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll", - "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, exynos4415_pll_rates), -}; - -static const struct samsung_cmu_info cmu_info __initconst = { - .pll_clks = exynos4415_plls, - .nr_pll_clks = ARRAY_SIZE(exynos4415_plls), - .mux_clks = exynos4415_mux_clks, - .nr_mux_clks = ARRAY_SIZE(exynos4415_mux_clks), - .div_clks = exynos4415_div_clks, - .nr_div_clks = ARRAY_SIZE(exynos4415_div_clks), - .gate_clks = exynos4415_gate_clks, - .nr_gate_clks = ARRAY_SIZE(exynos4415_gate_clks), - .fixed_clks = exynos4415_fixed_rate_clks, - .nr_fixed_clks = ARRAY_SIZE(exynos4415_fixed_rate_clks), - .fixed_factor_clks = exynos4415_fixed_factor_clks, - .nr_fixed_factor_clks = ARRAY_SIZE(exynos4415_fixed_factor_clks), - .nr_clk_ids = CLK_NR_CLKS, - .clk_regs = exynos4415_cmu_clk_regs, - .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_clk_regs), -}; - -static void __init exynos4415_cmu_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &cmu_info); -} -CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init); - -/* - * CMU DMC - */ - -#define MPLL_LOCK 0x008 -#define MPLL_CON0 0x108 -#define MPLL_CON1 0x10c -#define MPLL_CON2 0x110 -#define BPLL_LOCK 0x118 -#define BPLL_CON0 0x218 -#define BPLL_CON1 0x21c -#define BPLL_CON2 0x220 -#define SRC_DMC 0x300 -#define DIV_DMC1 0x504 - -static const unsigned long exynos4415_cmu_dmc_clk_regs[] __initconst = { - MPLL_LOCK, - MPLL_CON0, - MPLL_CON1, - MPLL_CON2, - BPLL_LOCK, - BPLL_CON0, - BPLL_CON1, - BPLL_CON2, - SRC_DMC, - DIV_DMC1, -}; - -PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", }; -PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", }; -PNAME(mbpll_p) = { "mout_mpll", "mout_bpll", }; - -static const struct samsung_mux_clock exynos4415_dmc_mux_clks[] __initconst = { - MUX(CLK_DMC_MOUT_MPLL, "mout_mpll", mout_mpll_p, SRC_DMC, 12, 1), - MUX(CLK_DMC_MOUT_BPLL, "mout_bpll", mout_bpll_p, SRC_DMC, 10, 1), - MUX(CLK_DMC_MOUT_DPHY, "mout_dphy", mbpll_p, SRC_DMC, 8, 1), - MUX(CLK_DMC_MOUT_DMC_BUS, "mout_dmc_bus", mbpll_p, SRC_DMC, 4, 1), -}; - -static const struct samsung_div_clock exynos4415_dmc_div_clks[] __initconst = { - DIV(CLK_DMC_DIV_DMC, "div_dmc", "div_dmc_pre", DIV_DMC1, 27, 3), - DIV(CLK_DMC_DIV_DPHY, "div_dphy", "mout_dphy", DIV_DMC1, 23, 3), - DIV(CLK_DMC_DIV_DMC_PRE, "div_dmc_pre", "mout_dmc_bus", - DIV_DMC1, 19, 2), - DIV(CLK_DMC_DIV_DMCP, "div_dmcp", "div_dmcd", DIV_DMC1, 15, 3), - DIV(CLK_DMC_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3), - DIV(CLK_DMC_DIV_MPLL_PRE, "div_mpll_pre", "mout_mpll", DIV_DMC1, 8, 2), -}; - -static const struct samsung_pll_clock exynos4415_dmc_plls[] __initconst = { - PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll", - MPLL_LOCK, MPLL_CON0, exynos4415_pll_rates), - PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll", - BPLL_LOCK, BPLL_CON0, exynos4415_pll_rates), -}; - -static const struct samsung_cmu_info cmu_dmc_info __initconst = { - .pll_clks = exynos4415_dmc_plls, - .nr_pll_clks = ARRAY_SIZE(exynos4415_dmc_plls), - .mux_clks = exynos4415_dmc_mux_clks, - .nr_mux_clks = ARRAY_SIZE(exynos4415_dmc_mux_clks), - .div_clks = exynos4415_dmc_div_clks, - .nr_div_clks = ARRAY_SIZE(exynos4415_dmc_div_clks), - .nr_clk_ids = NR_CLKS_DMC, - .clk_regs = exynos4415_cmu_dmc_clk_regs, - .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs), -}; - -static void __init exynos4415_cmu_dmc_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &cmu_dmc_info); -} -CLK_OF_DECLARE(exynos4415_cmu_dmc, "samsung,exynos4415-cmu-dmc", - exynos4415_cmu_dmc_init); diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 8c8b495cbf0d..cdc092a1d9ef 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -586,7 +586,7 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = { GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam", GATE_BUS_TOP, 24, 0, 0), GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler", - GATE_BUS_TOP, 27, 0, 0), + GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0), }; static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { @@ -956,20 +956,20 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0), GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys", - GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0), + GATE_BUS_FSYS0, 9, CLK_IS_CRITICAL, 0), GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2", GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d", GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d", - GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 1, CLK_IS_CRITICAL, 0), GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg", GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0", GATE_BUS_TOP, 5, 0, 0), GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl", - GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0), GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl", GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp", @@ -983,20 +983,20 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(0, "aclk166", "mout_user_aclk166", GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333", - GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0), GATE(0, "aclk400_isp", "mout_user_aclk400_isp", GATE_BUS_TOP, 16, 0, 0), GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl", GATE_BUS_TOP, 17, 0, 0), GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1", - GATE_BUS_TOP, 18, 0, 0), + GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0), GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24", GATE_BUS_TOP, 28, 0, 0), GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m", GATE_BUS_TOP, 29, 0, 0), GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1", - SRC_MASK_TOP2, 24, 0, 0), + SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0), GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk", SRC_MASK_TOP7, 20, 0, 0), diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f096bd7df40c..0db5204c307c 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -549,10 +549,10 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { 29, CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_BUS0_400, "aclk_bus0_400", "div_aclk_bus0_400", ENABLE_ACLK_TOP, 26, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), GATE(CLK_ACLK_BUS1_400, "aclk_bus1_400", "div_aclk_bus1_400", ENABLE_ACLK_TOP, 25, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), GATE(CLK_ACLK_IMEM_200, "aclk_imem_200", "div_aclk_imem_266", ENABLE_ACLK_TOP, 24, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), @@ -616,7 +616,7 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { /* ENABLE_SCLK_TOP_MSCL */ GATE(CLK_SCLK_JPEG_MSCL, "sclk_jpeg_mscl", "div_sclk_jpeg", - ENABLE_SCLK_TOP_MSCL, 0, 0, 0), + ENABLE_SCLK_TOP_MSCL, 0, CLK_SET_RATE_PARENT, 0), /* ENABLE_SCLK_TOP_CAM1 */ GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "div_sclk_isp_sensor2_b", @@ -1382,7 +1382,7 @@ static const struct samsung_gate_clock mif_gate_clks[] __initconst = { /* ENABLE_ACLK_MIF3 */ GATE(CLK_ACLK_BUS2_400, "aclk_bus2_400", "div_aclk_bus2_400", ENABLE_ACLK_MIF3, 4, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), GATE(CLK_ACLK_DISP_333, "aclk_disp_333", "div_aclk_disp_333", ENABLE_ACLK_MIF3, 1, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index b4e5de16e561..6bb87784a0d6 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -140,6 +140,35 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div) return true; } +static int _div_round_up(const struct clk_div_table *table, + unsigned long parent_rate, unsigned long rate) +{ + const struct clk_div_table *clkt; + int up = INT_MAX; + int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); + + for (clkt = table; clkt->div; clkt++) { + if (clkt->div == div) + return clkt->div; + else if (clkt->div < div) + continue; + + if ((clkt->div - div) < (up - div)) + up = clkt->div; + } + + return up; +} + +static int _div_round(const struct clk_div_table *table, + unsigned long parent_rate, unsigned long rate) +{ + if (!table) + return DIV_ROUND_UP(parent_rate, rate); + + return _div_round_up(table, parent_rate, rate); +} + static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate) { @@ -155,7 +184,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { parent_rate = *best_parent_rate; - bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = _div_round(divider->table, parent_rate, rate); bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; return bestdiv; diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 0007218ce6a0..2cf386347f0c 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -90,11 +90,8 @@ static int uniphier_clk_probe(struct platform_device *pdev) dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx); hw = uniphier_clk_register(dev, regmap, p); - if (IS_ERR(hw)) { - dev_err(dev, "failed to register %s (error %ld)\n", - p->name, PTR_ERR(hw)); - return PTR_ERR(hw); - } + if (WARN(IS_ERR(hw), "failed to register %s", p->name)) + continue; if (p->idx >= 0) hw_data->hws[p->idx] = hw; diff --git a/drivers/clk/uniphier/clk-uniphier-cpugear.c b/drivers/clk/uniphier/clk-uniphier-cpugear.c index 9bff26e0cbb0..ec11f55594ad 100644 --- a/drivers/clk/uniphier/clk-uniphier-cpugear.c +++ b/drivers/clk/uniphier/clk-uniphier-cpugear.c @@ -14,7 +14,6 @@ */ #include <linux/clk-provider.h> -#include <linux/delay.h> #include <linux/device.h> #include <linux/regmap.h> diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c index a07c31e6f26d..2257d12ba988 100644 --- a/drivers/clk/ux500/abx500-clk.c +++ b/drivers/clk/ux500/abx500-clk.c @@ -10,20 +10,26 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500-sysctrl.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> -#include <linux/mfd/dbx500-prcmu.h> +#include <dt-bindings/clock/ste-ab8500.h> #include "clk.h" +#define AB8500_NUM_CLKS 6 + +static struct clk *ab8500_clks[AB8500_NUM_CLKS]; +static struct clk_onecell_data ab8500_clk_data; + /* Clock definitions for ab8500 */ static int ab8500_reg_clks(struct device *dev) { int ret; struct clk *clk; - + struct device_node *np = dev->of_node; const char *intclk_parents[] = {"ab8500_sysclk", "ulpclk"}; u16 intclk_reg_sel[] = {0 , AB8500_SYSULPCLKCTRL1}; u8 intclk_reg_mask[] = {0 , AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK}; @@ -32,55 +38,52 @@ static int ab8500_reg_clks(struct device *dev) (1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT) }; - dev_info(dev, "register clocks for ab850x\n"); - /* Enable SWAT */ ret = ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE); if (ret) return ret; - /* ab8500_sysclk */ - clk = clk_reg_prcmu_gate("ab8500_sysclk", NULL, PRCMU_SYSCLK, 0); - clk_register_clkdev(clk, "sysclk", "ab8500-usb.0"); - clk_register_clkdev(clk, "sysclk", "ab-iddet.0"); - clk_register_clkdev(clk, "sysclk", "snd-soc-mop500.0"); - clk_register_clkdev(clk, "sysclk", "shrm_bus"); - /* ab8500_sysclk2 */ clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk2", "ab8500_sysclk", AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 0, 0); - clk_register_clkdev(clk, "sysclk", "0-0070"); + ab8500_clks[AB8500_SYSCLK_BUF2] = clk; /* ab8500_sysclk3 */ clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk3", "ab8500_sysclk", AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 0, 0); - clk_register_clkdev(clk, "sysclk", "cg1960_core.0"); + ab8500_clks[AB8500_SYSCLK_BUF3] = clk; /* ab8500_sysclk4 */ clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk4", "ab8500_sysclk", AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 0, 0); + ab8500_clks[AB8500_SYSCLK_BUF4] = clk; /* ab_ulpclk */ clk = clk_reg_sysctrl_gate_fixed_rate(dev, "ulpclk", NULL, AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ, AB8500_SYSULPCLKCTRL1_ULPCLKREQ, 38400000, 9000, 0); - clk_register_clkdev(clk, "ulpclk", "snd-soc-mop500.0"); + ab8500_clks[AB8500_SYSCLK_ULP] = clk; /* ab8500_intclk */ clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2, intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0); - clk_register_clkdev(clk, "intclk", "snd-soc-mop500.0"); - clk_register_clkdev(clk, NULL, "ab8500-pwm.1"); + ab8500_clks[AB8500_SYSCLK_INT] = clk; /* ab8500_audioclk */ clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk", AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0); - clk_register_clkdev(clk, "audioclk", "ab8500-codec.0"); + ab8500_clks[AB8500_SYSCLK_AUDIO] = clk; + + ab8500_clk_data.clks = ab8500_clks; + ab8500_clk_data.clk_num = ARRAY_SIZE(ab8500_clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &ab8500_clk_data); + + dev_info(dev, "registered clocks for ab850x\n"); return 0; } @@ -116,9 +119,15 @@ static int abx500_clk_probe(struct platform_device *pdev) return ret; } +static const struct of_device_id abx500_clk_match[] = { + { .compatible = "stericsson,ab8500-clk", }, + {} +}; + static struct platform_driver abx500_clk_driver = { .driver = { .name = "abx500-clk", + .of_match_table = abx500_clk_match, }, .probe = abx500_clk_probe, }; @@ -127,7 +136,6 @@ static int __init abx500_clk_init(void) { return platform_driver_register(&abx500_clk_driver); } - arch_initcall(abx500_clk_init); MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org"); diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c index e960d686d9db..d5888591e1a9 100644 --- a/drivers/clk/ux500/u8500_of_clk.c +++ b/drivers/clk/ux500/u8500_of_clk.c @@ -206,6 +206,9 @@ static void u8500_clk_init(struct device_node *np) clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, 0); prcmu_clk[PRCMU_TIMCLK] = clk; + clk = clk_reg_prcmu_gate("ab8500_sysclk", NULL, PRCMU_SYSCLK, 0); + prcmu_clk[PRCMU_SYSCLK] = clk; + clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK, 100000000, CLK_SET_RATE_GATE); prcmu_clk[PRCMU_SDMMCCLK] = clk; diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile index 04781389d0fb..1367afb03858 100644 --- a/drivers/clk/x86/Makefile +++ b/drivers/clk/x86/Makefile @@ -1,2 +1,3 @@ clk-x86-lpss-objs := clk-lpt.o obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o +obj-$(CONFIG_PMC_ATOM) += clk-pmc-atom.o diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c new file mode 100644 index 000000000000..2b60577703ef --- /dev/null +++ b/drivers/clk/x86/clk-pmc-atom.c @@ -0,0 +1,371 @@ +/* + * Intel Atom platform clocks driver for BayTrail and CherryTrail SoCs + * + * Copyright (C) 2016, Intel Corporation + * Author: Irina Tirdea <irina.tirdea@intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/platform_data/x86/clk-pmc-atom.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define PLT_CLK_NAME_BASE "pmc_plt_clk" + +#define PMC_CLK_CTL_OFFSET 0x60 +#define PMC_CLK_CTL_SIZE 4 +#define PMC_CLK_NUM 6 +#define PMC_CLK_CTL_GATED_ON_D3 0x0 +#define PMC_CLK_CTL_FORCE_ON 0x1 +#define PMC_CLK_CTL_FORCE_OFF 0x2 +#define PMC_CLK_CTL_RESERVED 0x3 +#define PMC_MASK_CLK_CTL GENMASK(1, 0) +#define PMC_MASK_CLK_FREQ BIT(2) +#define PMC_CLK_FREQ_XTAL (0 << 2) /* 25 MHz */ +#define PMC_CLK_FREQ_PLL (1 << 2) /* 19.2 MHz */ + +struct clk_plt_fixed { + struct clk_hw *clk; + struct clk_lookup *lookup; +}; + +struct clk_plt { + struct clk_hw hw; + void __iomem *reg; + struct clk_lookup *lookup; + /* protect access to PMC registers */ + spinlock_t lock; +}; + +#define to_clk_plt(_hw) container_of(_hw, struct clk_plt, hw) + +struct clk_plt_data { + struct clk_plt_fixed **parents; + u8 nparents; + struct clk_plt *clks[PMC_CLK_NUM]; +}; + +/* Return an index in parent table */ +static inline int plt_reg_to_parent(int reg) +{ + switch (reg & PMC_MASK_CLK_FREQ) { + default: + case PMC_CLK_FREQ_XTAL: + return 0; + case PMC_CLK_FREQ_PLL: + return 1; + } +} + +/* Return clk index of parent */ +static inline int plt_parent_to_reg(int index) +{ + switch (index) { + default: + case 0: + return PMC_CLK_FREQ_XTAL; + case 1: + return PMC_CLK_FREQ_PLL; + } +} + +/* Abstract status in simpler enabled/disabled value */ +static inline int plt_reg_to_enabled(int reg) +{ + switch (reg & PMC_MASK_CLK_CTL) { + case PMC_CLK_CTL_GATED_ON_D3: + case PMC_CLK_CTL_FORCE_ON: + return 1; /* enabled */ + case PMC_CLK_CTL_FORCE_OFF: + case PMC_CLK_CTL_RESERVED: + default: + return 0; /* disabled */ + } +} + +static void plt_clk_reg_update(struct clk_plt *clk, u32 mask, u32 val) +{ + u32 tmp; + unsigned long flags; + + spin_lock_irqsave(&clk->lock, flags); + + tmp = readl(clk->reg); + tmp = (tmp & ~mask) | (val & mask); + writel(tmp, clk->reg); + + spin_unlock_irqrestore(&clk->lock, flags); +} + +static int plt_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_plt *clk = to_clk_plt(hw); + + plt_clk_reg_update(clk, PMC_MASK_CLK_FREQ, plt_parent_to_reg(index)); + + return 0; +} + +static u8 plt_clk_get_parent(struct clk_hw *hw) +{ + struct clk_plt *clk = to_clk_plt(hw); + u32 value; + + value = readl(clk->reg); + + return plt_reg_to_parent(value); +} + +static int plt_clk_enable(struct clk_hw *hw) +{ + struct clk_plt *clk = to_clk_plt(hw); + + plt_clk_reg_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_ON); + + return 0; +} + +static void plt_clk_disable(struct clk_hw *hw) +{ + struct clk_plt *clk = to_clk_plt(hw); + + plt_clk_reg_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_OFF); +} + +static int plt_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_plt *clk = to_clk_plt(hw); + u32 value; + + value = readl(clk->reg); + + return plt_reg_to_enabled(value); +} + +static const struct clk_ops plt_clk_ops = { + .enable = plt_clk_enable, + .disable = plt_clk_disable, + .is_enabled = plt_clk_is_enabled, + .get_parent = plt_clk_get_parent, + .set_parent = plt_clk_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id, + void __iomem *base, + const char **parent_names, + int num_parents) +{ + struct clk_plt *pclk; + struct clk_init_data init; + int ret; + + pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL); + if (!pclk) + return ERR_PTR(-ENOMEM); + + init.name = kasprintf(GFP_KERNEL, "%s_%d", PLT_CLK_NAME_BASE, id); + init.ops = &plt_clk_ops; + init.flags = 0; + init.parent_names = parent_names; + init.num_parents = num_parents; + + pclk->hw.init = &init; + pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE; + spin_lock_init(&pclk->lock); + + ret = devm_clk_hw_register(&pdev->dev, &pclk->hw); + if (ret) { + pclk = ERR_PTR(ret); + goto err_free_init; + } + + pclk->lookup = clkdev_hw_create(&pclk->hw, init.name, NULL); + if (!pclk->lookup) { + pclk = ERR_PTR(-ENOMEM); + goto err_free_init; + } + +err_free_init: + kfree(init.name); + return pclk; +} + +static void plt_clk_unregister(struct clk_plt *pclk) +{ + clkdev_drop(pclk->lookup); +} + +static struct clk_plt_fixed *plt_clk_register_fixed_rate(struct platform_device *pdev, + const char *name, + const char *parent_name, + unsigned long fixed_rate) +{ + struct clk_plt_fixed *pclk; + + pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL); + if (!pclk) + return ERR_PTR(-ENOMEM); + + pclk->clk = clk_hw_register_fixed_rate(&pdev->dev, name, parent_name, + 0, fixed_rate); + if (IS_ERR(pclk->clk)) + return ERR_CAST(pclk->clk); + + pclk->lookup = clkdev_hw_create(pclk->clk, name, NULL); + if (!pclk->lookup) { + clk_hw_unregister_fixed_rate(pclk->clk); + return ERR_PTR(-ENOMEM); + } + + return pclk; +} + +static void plt_clk_unregister_fixed_rate(struct clk_plt_fixed *pclk) +{ + clkdev_drop(pclk->lookup); + clk_hw_unregister_fixed_rate(pclk->clk); +} + +static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data, + unsigned int i) +{ + while (i--) + plt_clk_unregister_fixed_rate(data->parents[i]); +} + +static void plt_clk_free_parent_names_loop(const char **parent_names, + unsigned int i) +{ + while (i--) + kfree_const(parent_names[i]); + kfree(parent_names); +} + +static void plt_clk_unregister_loop(struct clk_plt_data *data, + unsigned int i) +{ + while (i--) + plt_clk_unregister(data->clks[i]); +} + +static const char **plt_clk_register_parents(struct platform_device *pdev, + struct clk_plt_data *data, + const struct pmc_clk *clks) +{ + const char **parent_names; + unsigned int i; + int err; + int nparents = 0; + + data->nparents = 0; + while (clks[nparents].name) + nparents++; + + data->parents = devm_kcalloc(&pdev->dev, nparents, + sizeof(*data->parents), GFP_KERNEL); + if (!data->parents) + return ERR_PTR(-ENOMEM); + + parent_names = kcalloc(nparents, sizeof(*parent_names), + GFP_KERNEL); + if (!parent_names) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < nparents; i++) { + data->parents[i] = + plt_clk_register_fixed_rate(pdev, clks[i].name, + clks[i].parent_name, + clks[i].freq); + if (IS_ERR(data->parents[i])) { + err = PTR_ERR(data->parents[i]); + goto err_unreg; + } + parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL); + } + + data->nparents = nparents; + return parent_names; + +err_unreg: + plt_clk_unregister_fixed_rate_loop(data, i); + plt_clk_free_parent_names_loop(parent_names, i); + return ERR_PTR(err); +} + +static void plt_clk_unregister_parents(struct clk_plt_data *data) +{ + plt_clk_unregister_fixed_rate_loop(data, data->nparents); +} + +static int plt_clk_probe(struct platform_device *pdev) +{ + const struct pmc_clk_data *pmc_data; + const char **parent_names; + struct clk_plt_data *data; + unsigned int i; + int err; + + pmc_data = dev_get_platdata(&pdev->dev); + if (!pmc_data || !pmc_data->clks) + return -EINVAL; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + parent_names = plt_clk_register_parents(pdev, data, pmc_data->clks); + if (IS_ERR(parent_names)) + return PTR_ERR(parent_names); + + for (i = 0; i < PMC_CLK_NUM; i++) { + data->clks[i] = plt_clk_register(pdev, i, pmc_data->base, + parent_names, data->nparents); + if (IS_ERR(data->clks[i])) { + err = PTR_ERR(data->clks[i]); + goto err_unreg_clk_plt; + } + } + + plt_clk_free_parent_names_loop(parent_names, data->nparents); + + platform_set_drvdata(pdev, data); + return 0; + +err_unreg_clk_plt: + plt_clk_unregister_loop(data, i); + plt_clk_unregister_parents(data); + plt_clk_free_parent_names_loop(parent_names, data->nparents); + return err; +} + +static int plt_clk_remove(struct platform_device *pdev) +{ + struct clk_plt_data *data; + + data = platform_get_drvdata(pdev); + + plt_clk_unregister_loop(data, PMC_CLK_NUM); + plt_clk_unregister_parents(data); + return 0; +} + +static struct platform_driver plt_clk_driver = { + .driver = { + .name = "clk-pmc-atom", + }, + .probe = plt_clk_probe, + .remove = plt_clk_remove, +}; +builtin_platform_driver(plt_clk_driver); diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c index 707d62956e9b..ad5d1dfb3682 100644 --- a/drivers/clk/zte/clk-zx296718.c +++ b/drivers/clk/zte/clk-zx296718.c @@ -610,9 +610,12 @@ static int __init top_clocks_init(struct device_node *np) } } - if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &top_hw_onecell_data)) - panic("could not register clk provider\n"); - pr_info("top clk init over, nr:%d\n", TOP_NR_CLKS); + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &top_hw_onecell_data); + if (ret) { + pr_err("failed to register top clk provider: %d\n", ret); + return ret; + } return 0; } @@ -776,9 +779,12 @@ static int __init lsp0_clocks_init(struct device_node *np) } } - if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp0_hw_onecell_data)) - panic("could not register clk provider\n"); - pr_info("lsp0-clk init over:%d\n", LSP0_NR_CLKS); + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &lsp0_hw_onecell_data); + if (ret) { + pr_err("failed to register lsp0 clk provider: %d\n", ret); + return ret; + } return 0; } @@ -881,9 +887,138 @@ static int __init lsp1_clocks_init(struct device_node *np) } } - if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp1_hw_onecell_data)) - panic("could not register clk provider\n"); - pr_info("lsp1-clk init over, nr:%d\n", LSP1_NR_CLKS); + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &lsp1_hw_onecell_data); + if (ret) { + pr_err("failed to register lsp1 clk provider: %d\n", ret); + return ret; + } + + return 0; +} + +PNAME(audio_wclk_common_p) = { + "audio_99m", + "audio_24m", +}; + +PNAME(audio_timer_p) = { + "audio_24m", + "audio_32k", +}; + +static struct zx_clk_mux audio_mux_clk[] = { + MUX(0, "i2s0_wclk_mux", audio_wclk_common_p, AUDIO_I2S0_CLK, 0, 1), + MUX(0, "i2s1_wclk_mux", audio_wclk_common_p, AUDIO_I2S1_CLK, 0, 1), + MUX(0, "i2s2_wclk_mux", audio_wclk_common_p, AUDIO_I2S2_CLK, 0, 1), + MUX(0, "i2s3_wclk_mux", audio_wclk_common_p, AUDIO_I2S3_CLK, 0, 1), + MUX(0, "i2c0_wclk_mux", audio_wclk_common_p, AUDIO_I2C0_CLK, 0, 1), + MUX(0, "spdif0_wclk_mux", audio_wclk_common_p, AUDIO_SPDIF0_CLK, 0, 1), + MUX(0, "spdif1_wclk_mux", audio_wclk_common_p, AUDIO_SPDIF1_CLK, 0, 1), + MUX(0, "timer_wclk_mux", audio_timer_p, AUDIO_TIMER_CLK, 0, 1), +}; + +static struct clk_zx_audio_divider audio_adiv_clk[] = { + AUDIO_DIV(0, "i2s0_wclk_div", "i2s0_wclk_mux", AUDIO_I2S0_DIV_CFG1), + AUDIO_DIV(0, "i2s1_wclk_div", "i2s1_wclk_mux", AUDIO_I2S1_DIV_CFG1), + AUDIO_DIV(0, "i2s2_wclk_div", "i2s2_wclk_mux", AUDIO_I2S2_DIV_CFG1), + AUDIO_DIV(0, "i2s3_wclk_div", "i2s3_wclk_mux", AUDIO_I2S3_DIV_CFG1), + AUDIO_DIV(0, "spdif0_wclk_div", "spdif0_wclk_mux", AUDIO_SPDIF0_DIV_CFG1), + AUDIO_DIV(0, "spdif1_wclk_div", "spdif1_wclk_mux", AUDIO_SPDIF1_DIV_CFG1), +}; + +static struct zx_clk_div audio_div_clk[] = { + DIV_T(0, "tdm_wclk_div", "audio_16m384", AUDIO_TDM_CLK, 8, 4, 0, common_div_table), +}; + +static struct zx_clk_gate audio_gate_clk[] = { + GATE(AUDIO_I2S0_WCLK, "i2s0_wclk", "i2s0_wclk_div", AUDIO_I2S0_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_I2S1_WCLK, "i2s1_wclk", "i2s1_wclk_div", AUDIO_I2S1_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_I2S2_WCLK, "i2s2_wclk", "i2s2_wclk_div", AUDIO_I2S2_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_I2S3_WCLK, "i2s3_wclk", "i2s3_wclk_div", AUDIO_I2S3_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_I2C0_WCLK, "i2c0_wclk", "i2c0_wclk_mux", AUDIO_I2C0_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_SPDIF0_WCLK, "spdif0_wclk", "spdif0_wclk_div", AUDIO_SPDIF0_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_SPDIF1_WCLK, "spdif1_wclk", "spdif1_wclk_div", AUDIO_SPDIF1_CLK, 9, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_TDM_WCLK, "tdm_wclk", "tdm_wclk_div", AUDIO_TDM_CLK, 17, CLK_SET_RATE_PARENT, 0), + GATE(AUDIO_TS_PCLK, "tempsensor_pclk", "clk49m5", AUDIO_TS_CLK, 1, 0, 0), +}; + +static struct clk_hw_onecell_data audio_hw_onecell_data = { + .num = AUDIO_NR_CLKS, + .hws = { + [AUDIO_NR_CLKS - 1] = NULL, + }, +}; + +static int __init audio_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map audio clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(audio_mux_clk); i++) { + if (audio_mux_clk[i].id) + audio_hw_onecell_data.hws[audio_mux_clk[i].id] = + &audio_mux_clk[i].mux.hw; + + audio_mux_clk[i].mux.reg += (uintptr_t)reg_base; + ret = clk_hw_register(NULL, &audio_mux_clk[i].mux.hw); + if (ret) { + pr_warn("audio clk %s init error!\n", + audio_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(audio_adiv_clk); i++) { + if (audio_adiv_clk[i].id) + audio_hw_onecell_data.hws[audio_adiv_clk[i].id] = + &audio_adiv_clk[i].hw; + + audio_adiv_clk[i].reg_base += (uintptr_t)reg_base; + ret = clk_hw_register(NULL, &audio_adiv_clk[i].hw); + if (ret) { + pr_warn("audio clk %s init error!\n", + audio_adiv_clk[i].hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(audio_div_clk); i++) { + if (audio_div_clk[i].id) + audio_hw_onecell_data.hws[audio_div_clk[i].id] = + &audio_div_clk[i].div.hw; + + audio_div_clk[i].div.reg += (uintptr_t)reg_base; + ret = clk_hw_register(NULL, &audio_div_clk[i].div.hw); + if (ret) { + pr_warn("audio clk %s init error!\n", + audio_div_clk[i].div.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(audio_gate_clk); i++) { + if (audio_gate_clk[i].id) + audio_hw_onecell_data.hws[audio_gate_clk[i].id] = + &audio_gate_clk[i].gate.hw; + + audio_gate_clk[i].gate.reg += (uintptr_t)reg_base; + ret = clk_hw_register(NULL, &audio_gate_clk[i].gate.hw); + if (ret) { + pr_warn("audio clk %s init error!\n", + audio_gate_clk[i].gate.hw.init->name); + } + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &audio_hw_onecell_data); + if (ret) { + pr_err("failed to register audio clk provider: %d\n", ret); + return ret; + } return 0; } @@ -892,6 +1027,7 @@ static const struct of_device_id zx_clkc_match_table[] = { { .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init }, { .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init }, { .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init }, + { .compatible = "zte,zx296718-audiocrm", .data = &audio_clocks_init }, { } }; diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c index c4c1251bc1e7..878d879b23ff 100644 --- a/drivers/clk/zte/clk.c +++ b/drivers/clk/zte/clk.c @@ -9,6 +9,7 @@ #include <linux/clk-provider.h> #include <linux/err.h> +#include <linux/gcd.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/slab.h> @@ -310,3 +311,129 @@ struct clk *clk_register_zx_audio(const char *name, return clk; } + +#define CLK_AUDIO_DIV_FRAC BIT(0) +#define CLK_AUDIO_DIV_INT BIT(1) +#define CLK_AUDIO_DIV_UNCOMMON BIT(1) + +#define CLK_AUDIO_DIV_FRAC_NSHIFT 16 +#define CLK_AUDIO_DIV_INT_FRAC_RE BIT(16) +#define CLK_AUDIO_DIV_INT_FRAC_MAX (0xffff) +#define CLK_AUDIO_DIV_INT_FRAC_MIN (0x2) +#define CLK_AUDIO_DIV_INT_INT_SHIFT 24 +#define CLK_AUDIO_DIV_INT_INT_WIDTH 4 + +struct zx_clk_audio_div_table { + unsigned long rate; + unsigned int int_reg; + unsigned int frac_reg; +}; + +#define to_clk_zx_audio_div(_hw) container_of(_hw, struct clk_zx_audio_divider, hw) + +static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div, + u32 reg_frac, u32 reg_int, + unsigned long parent_rate) +{ + unsigned long rate, m, n; + + m = reg_frac & 0xffff; + n = (reg_frac >> 16) & 0xffff; + + m = (reg_int & 0xffff) * n + m; + rate = (parent_rate * n) / m; + + return rate; +} + +static void audio_calc_reg(struct clk_zx_audio_divider *audio_div, + struct zx_clk_audio_div_table *div_table, + unsigned long rate, unsigned long parent_rate) +{ + unsigned int reg_int, reg_frac; + unsigned long m, n, div; + + reg_int = parent_rate / rate; + + if (reg_int > CLK_AUDIO_DIV_INT_FRAC_MAX) + reg_int = CLK_AUDIO_DIV_INT_FRAC_MAX; + else if (reg_int < CLK_AUDIO_DIV_INT_FRAC_MIN) + reg_int = 0; + m = parent_rate - rate * reg_int; + n = rate; + + div = gcd(m, n); + m = m / div; + n = n / div; + + if ((m >> 16) || (n >> 16)) { + if (m > n) { + n = n * 0xffff / m; + m = 0xffff; + } else { + m = m * 0xffff / n; + n = 0xffff; + } + } + reg_frac = m | (n << 16); + + div_table->rate = parent_rate * n / (reg_int * n + m); + div_table->int_reg = reg_int; + div_table->frac_reg = reg_frac; +} + +static unsigned long zx_audio_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw); + u32 reg_frac, reg_int; + + reg_frac = readl_relaxed(zx_audio_div->reg_base); + reg_int = readl_relaxed(zx_audio_div->reg_base + 0x4); + + return audio_calc_rate(zx_audio_div, reg_frac, reg_int, parent_rate); +} + +static long zx_audio_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw); + struct zx_clk_audio_div_table divt; + + audio_calc_reg(zx_audio_div, &divt, rate, *prate); + + return audio_calc_rate(zx_audio_div, divt.frac_reg, divt.int_reg, *prate); +} + +static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw); + struct zx_clk_audio_div_table divt; + unsigned int val; + + audio_calc_reg(zx_audio_div, &divt, rate, parent_rate); + if (divt.rate != rate) + pr_debug("the real rate is:%ld", divt.rate); + + writel_relaxed(divt.frac_reg, zx_audio_div->reg_base); + + val = readl_relaxed(zx_audio_div->reg_base + 0x4); + val &= ~0xffff; + val |= divt.int_reg | CLK_AUDIO_DIV_INT_FRAC_RE; + writel_relaxed(val, zx_audio_div->reg_base + 0x4); + + mdelay(1); + + val = readl_relaxed(zx_audio_div->reg_base + 0x4); + val &= ~CLK_AUDIO_DIV_INT_FRAC_RE; + writel_relaxed(val, zx_audio_div->reg_base + 0x4); + + return 0; +} + +const struct clk_ops zx_audio_div_ops = { + .recalc_rate = zx_audio_div_recalc_rate, + .round_rate = zx_audio_div_round_rate, + .set_rate = zx_audio_div_set_rate, +}; diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 0df3474b2cf3..84a55a3e2bd4 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -153,6 +153,25 @@ struct zx_clk_div { .id = _id, \ } +struct clk_zx_audio_divider { + struct clk_hw hw; + void __iomem *reg_base; + unsigned int rate_count; + spinlock_t *lock; + u16 id; +}; + +#define AUDIO_DIV(_id, _name, _parent, _reg) \ +{ \ + .reg_base = (void __iomem *) _reg, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &zx_audio_div_ops, \ + 0), \ + .id = _id, \ +} + struct clk *clk_register_zx_pll(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg_base, const struct zx_pll_config *lookup_table, int count, spinlock_t *lock); @@ -167,4 +186,6 @@ struct clk *clk_register_zx_audio(const char *name, unsigned long flags, void __iomem *reg_base); extern const struct clk_ops zx_pll_ops; +extern const struct clk_ops zx_audio_div_ops; + #endif diff --git a/drivers/crypto/marvell/cesa.h b/drivers/crypto/marvell/cesa.h index a768da7138a1..b7872f62f674 100644 --- a/drivers/crypto/marvell/cesa.h +++ b/drivers/crypto/marvell/cesa.h @@ -273,7 +273,8 @@ struct mv_cesa_op_ctx { #define CESA_TDMA_SRC_IN_SRAM BIT(30) #define CESA_TDMA_END_OF_REQ BIT(29) #define CESA_TDMA_BREAK_CHAIN BIT(28) -#define CESA_TDMA_TYPE_MSK GENMASK(27, 0) +#define CESA_TDMA_SET_STATE BIT(27) +#define CESA_TDMA_TYPE_MSK GENMASK(26, 0) #define CESA_TDMA_DUMMY 0 #define CESA_TDMA_DATA 1 #define CESA_TDMA_OP 2 diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 317cf029c0cf..77c0fb936f47 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -280,13 +280,32 @@ static void mv_cesa_ahash_std_prepare(struct ahash_request *req) sreq->offset = 0; } +static void mv_cesa_ahash_dma_step(struct ahash_request *req) +{ + struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); + struct mv_cesa_req *base = &creq->base; + + /* We must explicitly set the digest state. */ + if (base->chain.first->flags & CESA_TDMA_SET_STATE) { + struct mv_cesa_engine *engine = base->engine; + int i; + + /* Set the hash state in the IVDIG regs. */ + for (i = 0; i < ARRAY_SIZE(creq->state); i++) + writel_relaxed(creq->state[i], engine->regs + + CESA_IVDIG(i)); + } + + mv_cesa_dma_step(base); +} + static void mv_cesa_ahash_step(struct crypto_async_request *req) { struct ahash_request *ahashreq = ahash_request_cast(req); struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) - mv_cesa_dma_step(&creq->base); + mv_cesa_ahash_dma_step(ahashreq); else mv_cesa_ahash_std_step(ahashreq); } @@ -584,12 +603,16 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) struct mv_cesa_ahash_dma_iter iter; struct mv_cesa_op_ctx *op = NULL; unsigned int frag_len; + bool set_state = false; int ret; u32 type; basereq->chain.first = NULL; basereq->chain.last = NULL; + if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl)) + set_state = true; + if (creq->src_nents) { ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE); @@ -683,6 +706,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) if (type != CESA_TDMA_RESULT) basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN; + if (set_state) { + /* + * Put the CESA_TDMA_SET_STATE flag on the first tdma desc to + * let the step logic know that the IVDIG registers should be + * explicitly set before launching a TDMA chain. + */ + basereq->chain.first->flags |= CESA_TDMA_SET_STATE; + } + return 0; err_free_tdma: diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index 4416b88eca70..c76375ff376d 100644 --- a/drivers/crypto/marvell/tdma.c +++ b/drivers/crypto/marvell/tdma.c @@ -109,7 +109,14 @@ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine, last->next = dreq->chain.first; engine->chain.last = dreq->chain.last; - if (!(last->flags & CESA_TDMA_BREAK_CHAIN)) + /* + * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on + * the last element of the current chain, or if the request + * being queued needs the IV regs to be set before lauching + * the request. + */ + if (!(last->flags & CESA_TDMA_BREAK_CHAIN) && + !(dreq->chain.first->flags & CESA_TDMA_SET_STATE)) last->next_dma = dreq->chain.first->cur_dma; } } diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index cbeea915f026..8037426ec50f 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -900,10 +900,10 @@ static void korina_restart_task(struct work_struct *work) DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR, &lp->rx_dma_regs->dmasm); - korina_free_ring(dev); - napi_disable(&lp->napi); + korina_free_ring(dev); + if (korina_init(dev) < 0) { printk(KERN_ERR "%s: cannot restart device\n", dev->name); return; @@ -1064,12 +1064,12 @@ static int korina_close(struct net_device *dev) tmp = tmp | DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR; writel(tmp, &lp->rx_dma_regs->dmasm); - korina_free_ring(dev); - napi_disable(&lp->napi); cancel_work_sync(&lp->restart_task); + korina_free_ring(dev); + free_irq(lp->rx_irq, dev); free_irq(lp->tx_irq, dev); free_irq(lp->ovr_irq, dev); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index bcd955339058..edbe200ac2fa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1638,7 +1638,8 @@ int mlx4_en_start_port(struct net_device *dev) /* Configure tx cq's and rings */ for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { - u8 num_tx_rings_p_up = t == TX ? priv->num_tx_rings_p_up : 1; + u8 num_tx_rings_p_up = t == TX ? + priv->num_tx_rings_p_up : priv->tx_ring_num[t]; for (i = 0; i < priv->tx_ring_num[t]; i++) { /* Configure cq */ diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index f9b97f5946f8..44389c90056a 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -326,6 +326,7 @@ enum cfg_version { static const struct pci_device_id rtl8169_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index fda01f770eff..b0344c213752 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -116,7 +116,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, unsigned int mii_address = priv->hw->mii.addr; unsigned int mii_data = priv->hw->mii.data; - u32 value = MII_WRITE | MII_BUSY; + u32 value = MII_BUSY; value |= (phyaddr << priv->hw->mii.addr_shift) & priv->hw->mii.addr_mask; @@ -126,6 +126,8 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, & priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4) value |= MII_GMAC4_WRITE; + else + value |= MII_WRITE; /* Wait until any existing MII operation is complete */ if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 031093e1c25f..dbfbb33ac66c 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -99,6 +99,11 @@ struct ipvl_port { int count; }; +struct ipvl_skb_cb { + bool tx_pkt; +}; +#define IPVL_SKB_CB(_skb) ((struct ipvl_skb_cb *)&((_skb)->cb[0])) + static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d) { return rcu_dereference(d->rx_handler_data); diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index b4e990743e1d..83ce74acf82d 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -198,7 +198,7 @@ void ipvlan_process_multicast(struct work_struct *work) unsigned int mac_hash; int ret; u8 pkt_type; - bool hlocal, dlocal; + bool tx_pkt; __skb_queue_head_init(&list); @@ -207,8 +207,11 @@ void ipvlan_process_multicast(struct work_struct *work) spin_unlock_bh(&port->backlog.lock); while ((skb = __skb_dequeue(&list)) != NULL) { + struct net_device *dev = skb->dev; + bool consumed = false; + ethh = eth_hdr(skb); - hlocal = ether_addr_equal(ethh->h_source, port->dev->dev_addr); + tx_pkt = IPVL_SKB_CB(skb)->tx_pkt; mac_hash = ipvlan_mac_hash(ethh->h_dest); if (ether_addr_equal(ethh->h_dest, port->dev->broadcast)) @@ -216,41 +219,45 @@ void ipvlan_process_multicast(struct work_struct *work) else pkt_type = PACKET_MULTICAST; - dlocal = false; rcu_read_lock(); list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) { - if (hlocal && (ipvlan->dev == skb->dev)) { - dlocal = true; + if (tx_pkt && (ipvlan->dev == skb->dev)) continue; - } if (!test_bit(mac_hash, ipvlan->mac_filters)) continue; - + if (!(ipvlan->dev->flags & IFF_UP)) + continue; ret = NET_RX_DROP; len = skb->len + ETH_HLEN; nskb = skb_clone(skb, GFP_ATOMIC); - if (!nskb) - goto acct; - - nskb->pkt_type = pkt_type; - nskb->dev = ipvlan->dev; - if (hlocal) - ret = dev_forward_skb(ipvlan->dev, nskb); - else - ret = netif_rx(nskb); -acct: + local_bh_disable(); + if (nskb) { + consumed = true; + nskb->pkt_type = pkt_type; + nskb->dev = ipvlan->dev; + if (tx_pkt) + ret = dev_forward_skb(ipvlan->dev, nskb); + else + ret = netif_rx(nskb); + } ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true); + local_bh_enable(); } rcu_read_unlock(); - if (dlocal) { + if (tx_pkt) { /* If the packet originated here, send it out. */ skb->dev = port->dev; skb->pkt_type = pkt_type; dev_queue_xmit(skb); } else { - kfree_skb(skb); + if (consumed) + consume_skb(skb); + else + kfree_skb(skb); } + if (dev) + dev_put(dev); } } @@ -470,15 +477,24 @@ out: } static void ipvlan_multicast_enqueue(struct ipvl_port *port, - struct sk_buff *skb) + struct sk_buff *skb, bool tx_pkt) { if (skb->protocol == htons(ETH_P_PAUSE)) { kfree_skb(skb); return; } + /* Record that the deferred packet is from TX or RX path. By + * looking at mac-addresses on packet will lead to erronus decisions. + * (This would be true for a loopback-mode on master device or a + * hair-pin mode of the switch.) + */ + IPVL_SKB_CB(skb)->tx_pkt = tx_pkt; + spin_lock(&port->backlog.lock); if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) { + if (skb->dev) + dev_hold(skb->dev); __skb_queue_tail(&port->backlog, skb); spin_unlock(&port->backlog.lock); schedule_work(&port->wq); @@ -537,7 +553,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) } else if (is_multicast_ether_addr(eth->h_dest)) { ipvlan_skb_crossing_ns(skb, NULL); - ipvlan_multicast_enqueue(ipvlan->port, skb); + ipvlan_multicast_enqueue(ipvlan->port, skb, true); return NET_XMIT_SUCCESS; } @@ -634,7 +650,7 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, */ if (nskb) { ipvlan_skb_crossing_ns(nskb, NULL); - ipvlan_multicast_enqueue(port, nskb); + ipvlan_multicast_enqueue(port, nskb, false); } } } else { diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 693ec5b66222..8b0f99300cbc 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -135,6 +135,7 @@ err: static void ipvlan_port_destroy(struct net_device *dev) { struct ipvl_port *port = ipvlan_port_get_rtnl(dev); + struct sk_buff *skb; dev->priv_flags &= ~IFF_IPVLAN_MASTER; if (port->mode == IPVLAN_MODE_L3S) { @@ -144,7 +145,11 @@ static void ipvlan_port_destroy(struct net_device *dev) } netdev_rx_handler_unregister(dev); cancel_work_sync(&port->wq); - __skb_queue_purge(&port->backlog); + while ((skb = __skb_dequeue(&port->backlog)) != NULL) { + if (skb->dev) + dev_put(skb->dev); + kfree_skb(skb); + } kfree(port); } diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 5fe8be089b8b..bd1b1ff99000 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1077,3 +1077,8 @@ config MLX_CPLD_PLATFORM cables and fans on the wide range Mellanox IB and Ethernet systems. endif # X86_PLATFORM_DEVICES + +config PMC_ATOM + def_bool y + depends on PCI + select COMMON_CLK diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d4111f0f8a78..49ee7ef283bb 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -74,5 +74,6 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ intel_telemetry_debugfs.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o +obj-$(CONFIG_PMC_ATOM) += pmc_atom.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o diff --git a/arch/x86/platform/atom/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index 964ff4fc61f9..77bac859342d 100644 --- a/arch/x86/platform/atom/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -15,14 +15,15 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/debugfs.h> +#include <linux/device.h> #include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_data/x86/clk-pmc-atom.h> +#include <linux/platform_data/x86/pmc_atom.h> +#include <linux/platform_device.h> #include <linux/pci.h> -#include <linux/device.h> -#include <linux/debugfs.h> #include <linux/seq_file.h> -#include <linux/io.h> - -#include <asm/pmc_atom.h> struct pmc_bit_map { const char *name; @@ -37,6 +38,11 @@ struct pmc_reg_map { const struct pmc_bit_map *pss; }; +struct pmc_data { + const struct pmc_reg_map *map; + const struct pmc_clk *clks; +}; + struct pmc_dev { u32 base_addr; void __iomem *regmap; @@ -50,6 +56,29 @@ struct pmc_dev { static struct pmc_dev pmc_device; static u32 acpi_base_addr; +static const struct pmc_clk byt_clks[] = { + { + .name = "xtal", + .freq = 25000000, + .parent_name = NULL, + }, + { + .name = "pll", + .freq = 19200000, + .parent_name = "xtal", + }, + {}, +}; + +static const struct pmc_clk cht_clks[] = { + { + .name = "xtal", + .freq = 19200000, + .parent_name = NULL, + }, + {}, +}; + static const struct pmc_bit_map d3_sts_0_map[] = { {"LPSS1_F0_DMA", BIT_LPSS1_F0_DMA}, {"LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1}, @@ -169,6 +198,16 @@ static const struct pmc_reg_map cht_reg_map = { .pss = cht_pss_map, }; +static const struct pmc_data byt_data = { + .map = &byt_reg_map, + .clks = byt_clks, +}; + +static const struct pmc_data cht_data = { + .map = &cht_reg_map, + .clks = cht_clks, +}; + static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) { return readl(pmc->regmap + reg_offset); @@ -382,10 +421,37 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc) } #endif /* CONFIG_DEBUG_FS */ +static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap, + const struct pmc_data *pmc_data) +{ + struct platform_device *clkdev; + struct pmc_clk_data *clk_data; + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->base = pmc_regmap; /* offset is added by client */ + clk_data->clks = pmc_data->clks; + + clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom", + PLATFORM_DEVID_NONE, + clk_data, sizeof(*clk_data)); + if (IS_ERR(clkdev)) { + kfree(clk_data); + return PTR_ERR(clkdev); + } + + kfree(clk_data); + + return 0; +} + static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) { struct pmc_dev *pmc = &pmc_device; - const struct pmc_reg_map *map = (struct pmc_reg_map *)ent->driver_data; + const struct pmc_data *data = (struct pmc_data *)ent->driver_data; + const struct pmc_reg_map *map = data->map; int ret; /* Obtain ACPI base address */ @@ -414,6 +480,12 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) dev_warn(&pdev->dev, "debugfs register failed\n"); + /* Register platform clocks - PMC_PLT_CLK [0..5] */ + ret = pmc_setup_clks(pdev, pmc->regmap, data); + if (ret) + dev_warn(&pdev->dev, "platform clocks register failed: %d\n", + ret); + pmc->init = true; return ret; } @@ -424,8 +496,8 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) * used by pci_match_id() call below. */ static const struct pci_device_id pmc_pci_ids[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_reg_map }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_reg_map }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data }, { 0, }, }; @@ -451,16 +451,37 @@ void dax_wake_mapping_entry_waiter(struct address_space *mapping, __wake_up(wq, TASK_NORMAL, wake_all ? 0 : 1, &key); } +static int __dax_invalidate_mapping_entry(struct address_space *mapping, + pgoff_t index, bool trunc) +{ + int ret = 0; + void *entry; + struct radix_tree_root *page_tree = &mapping->page_tree; + + spin_lock_irq(&mapping->tree_lock); + entry = get_unlocked_mapping_entry(mapping, index, NULL); + if (!entry || !radix_tree_exceptional_entry(entry)) + goto out; + if (!trunc && + (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) || + radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE))) + goto out; + radix_tree_delete(page_tree, index); + mapping->nrexceptional--; + ret = 1; +out: + put_unlocked_mapping_entry(mapping, index, entry); + spin_unlock_irq(&mapping->tree_lock); + return ret; +} /* * Delete exceptional DAX entry at @index from @mapping. Wait for radix tree * entry to get unlocked before deleting it. */ int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index) { - void *entry; + int ret = __dax_invalidate_mapping_entry(mapping, index, true); - spin_lock_irq(&mapping->tree_lock); - entry = get_unlocked_mapping_entry(mapping, index, NULL); /* * This gets called from truncate / punch_hole path. As such, the caller * must hold locks protecting against concurrent modifications of the @@ -468,16 +489,46 @@ int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index) * caller has seen exceptional entry for this index, we better find it * at that index as well... */ - if (WARN_ON_ONCE(!entry || !radix_tree_exceptional_entry(entry))) { - spin_unlock_irq(&mapping->tree_lock); - return 0; - } - radix_tree_delete(&mapping->page_tree, index); + WARN_ON_ONCE(!ret); + return ret; +} + +/* + * Invalidate exceptional DAX entry if easily possible. This handles DAX + * entries for invalidate_inode_pages() so we evict the entry only if we can + * do so without blocking. + */ +int dax_invalidate_mapping_entry(struct address_space *mapping, pgoff_t index) +{ + int ret = 0; + void *entry, **slot; + struct radix_tree_root *page_tree = &mapping->page_tree; + + spin_lock_irq(&mapping->tree_lock); + entry = __radix_tree_lookup(page_tree, index, NULL, &slot); + if (!entry || !radix_tree_exceptional_entry(entry) || + slot_locked(mapping, slot)) + goto out; + if (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) || + radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE)) + goto out; + radix_tree_delete(page_tree, index); mapping->nrexceptional--; + ret = 1; +out: spin_unlock_irq(&mapping->tree_lock); - dax_wake_mapping_entry_waiter(mapping, index, entry, true); + if (ret) + dax_wake_mapping_entry_waiter(mapping, index, entry, true); + return ret; +} - return 1; +/* + * Invalidate exceptional DAX entry if it is clean. + */ +int dax_invalidate_mapping_entry_sync(struct address_space *mapping, + pgoff_t index) +{ + return __dax_invalidate_mapping_entry(mapping, index, false); } /* @@ -488,15 +539,16 @@ int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index) * otherwise it will simply fall out of the page cache under memory * pressure without ever having been dirtied. */ -static int dax_load_hole(struct address_space *mapping, void *entry, +static int dax_load_hole(struct address_space *mapping, void **entry, struct vm_fault *vmf) { struct page *page; + int ret; /* Hole page already exists? Return it... */ - if (!radix_tree_exceptional_entry(entry)) { - vmf->page = entry; - return VM_FAULT_LOCKED; + if (!radix_tree_exceptional_entry(*entry)) { + page = *entry; + goto out; } /* This will replace locked radix tree entry with a hole page */ @@ -504,8 +556,17 @@ static int dax_load_hole(struct address_space *mapping, void *entry, vmf->gfp_mask | __GFP_ZERO); if (!page) return VM_FAULT_OOM; + out: vmf->page = page; - return VM_FAULT_LOCKED; + ret = finish_fault(vmf); + vmf->page = NULL; + *entry = page; + if (!ret) { + /* Grab reference for PTE that is now referencing the page */ + get_page(page); + return VM_FAULT_NOPAGE; + } + return ret; } static int copy_user_dax(struct block_device *bdev, sector_t sector, size_t size, @@ -934,6 +995,17 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, if (WARN_ON_ONCE(iomap->type != IOMAP_MAPPED)) return -EIO; + /* + * Write can allocate block for an area which has a hole page mapped + * into page tables. We have to tear down these mappings so that data + * written by write(2) is visible in mmap. + */ + if ((iomap->flags & IOMAP_F_NEW) && inode->i_mapping->nrpages) { + invalidate_inode_pages2_range(inode->i_mapping, + pos >> PAGE_SHIFT, + (end - 1) >> PAGE_SHIFT); + } + while (pos < end) { unsigned offset = pos & (PAGE_SIZE - 1); struct blk_dax_ctl dax = { 0 }; @@ -992,23 +1064,6 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, if (iov_iter_rw(iter) == WRITE) flags |= IOMAP_WRITE; - /* - * Yes, even DAX files can have page cache attached to them: A zeroed - * page is inserted into the pagecache when we have to serve a write - * fault on a hole. It should never be dirtied and can simply be - * dropped from the pagecache once we get real data for the page. - * - * XXX: This is racy against mmap, and there's nothing we can do about - * it. We'll eventually need to shift this down even further so that - * we can check if we allocated blocks over a hole first. - */ - if (mapping->nrpages) { - ret = invalidate_inode_pages2_range(mapping, - pos >> PAGE_SHIFT, - (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT); - WARN_ON_ONCE(ret); - } - while (iov_iter_count(iter)) { ret = iomap_apply(inode, pos, iov_iter_count(iter), flags, ops, iter, dax_iomap_actor); @@ -1023,6 +1078,15 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, } EXPORT_SYMBOL_GPL(dax_iomap_rw); +static int dax_fault_return(int error) +{ + if (error == 0) + return VM_FAULT_NOPAGE; + if (error == -ENOMEM) + return VM_FAULT_OOM; + return VM_FAULT_SIGBUS; +} + /** * dax_iomap_fault - handle a page fault on a DAX file * @vma: The virtual memory area where the fault occurred @@ -1055,12 +1119,6 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, if (pos >= i_size_read(inode)) return VM_FAULT_SIGBUS; - entry = grab_mapping_entry(mapping, vmf->pgoff, 0); - if (IS_ERR(entry)) { - error = PTR_ERR(entry); - goto out; - } - if ((vmf->flags & FAULT_FLAG_WRITE) && !vmf->cow_page) flags |= IOMAP_WRITE; @@ -1071,9 +1129,15 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, */ error = ops->iomap_begin(inode, pos, PAGE_SIZE, flags, &iomap); if (error) - goto unlock_entry; + return dax_fault_return(error); if (WARN_ON_ONCE(iomap.offset + iomap.length < pos + PAGE_SIZE)) { - error = -EIO; /* fs corruption? */ + vmf_ret = dax_fault_return(-EIO); /* fs corruption? */ + goto finish_iomap; + } + + entry = grab_mapping_entry(mapping, vmf->pgoff, 0); + if (IS_ERR(entry)) { + vmf_ret = dax_fault_return(PTR_ERR(entry)); goto finish_iomap; } @@ -1096,13 +1160,13 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, } if (error) - goto finish_iomap; + goto error_unlock_entry; __SetPageUptodate(vmf->cow_page); vmf_ret = finish_fault(vmf); if (!vmf_ret) vmf_ret = VM_FAULT_DONE_COW; - goto finish_iomap; + goto unlock_entry; } switch (iomap.type) { @@ -1114,12 +1178,15 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, } error = dax_insert_mapping(mapping, iomap.bdev, sector, PAGE_SIZE, &entry, vma, vmf); + /* -EBUSY is fine, somebody else faulted on the same PTE */ + if (error == -EBUSY) + error = 0; break; case IOMAP_UNWRITTEN: case IOMAP_HOLE: if (!(vmf->flags & FAULT_FLAG_WRITE)) { - vmf_ret = dax_load_hole(mapping, entry, vmf); - break; + vmf_ret = dax_load_hole(mapping, &entry, vmf); + goto unlock_entry; } /*FALLTHRU*/ default: @@ -1128,31 +1195,25 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, break; } + error_unlock_entry: + vmf_ret = dax_fault_return(error) | major; + unlock_entry: + put_locked_mapping_entry(mapping, vmf->pgoff, entry); finish_iomap: if (ops->iomap_end) { - if (error || (vmf_ret & VM_FAULT_ERROR)) { - /* keep previous error */ - ops->iomap_end(inode, pos, PAGE_SIZE, 0, flags, - &iomap); - } else { - error = ops->iomap_end(inode, pos, PAGE_SIZE, - PAGE_SIZE, flags, &iomap); - } - } - unlock_entry: - if (vmf_ret != VM_FAULT_LOCKED || error) - put_locked_mapping_entry(mapping, vmf->pgoff, entry); - out: - if (error == -ENOMEM) - return VM_FAULT_OOM | major; - /* -EBUSY is fine, somebody else faulted on the same PTE */ - if (error < 0 && error != -EBUSY) - return VM_FAULT_SIGBUS | major; - if (vmf_ret) { - WARN_ON_ONCE(error); /* -EBUSY from ops->iomap_end? */ - return vmf_ret; + int copied = PAGE_SIZE; + + if (vmf_ret & VM_FAULT_ERROR) + copied = 0; + /* + * The fault is done by now and there's no way back (other + * thread may be already happily using PTE we have installed). + * Just ignore error from ->iomap_end since we cannot do much + * with it. + */ + ops->iomap_end(inode, pos, PAGE_SIZE, copied, flags, &iomap); } - return VM_FAULT_NOPAGE | major; + return vmf_ret; } EXPORT_SYMBOL_GPL(dax_iomap_fault); @@ -1277,16 +1338,6 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address, goto fallback; /* - * grab_mapping_entry() will make sure we get a 2M empty entry, a DAX - * PMD or a HZP entry. If it can't (because a 4k page is already in - * the tree, for instance), it will return -EEXIST and we just fall - * back to 4k entries. - */ - entry = grab_mapping_entry(mapping, pgoff, RADIX_DAX_PMD); - if (IS_ERR(entry)) - goto fallback; - - /* * Note that we don't use iomap_apply here. We aren't doing I/O, only * setting up a mapping, so really we're using iomap_begin() as a way * to look up our filesystem block. @@ -1294,10 +1345,21 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address, pos = (loff_t)pgoff << PAGE_SHIFT; error = ops->iomap_begin(inode, pos, PMD_SIZE, iomap_flags, &iomap); if (error) - goto unlock_entry; + goto fallback; + if (iomap.offset + iomap.length < pos + PMD_SIZE) goto finish_iomap; + /* + * grab_mapping_entry() will make sure we get a 2M empty entry, a DAX + * PMD or a HZP entry. If it can't (because a 4k page is already in + * the tree, for instance), it will return -EEXIST and we just fall + * back to 4k entries. + */ + entry = grab_mapping_entry(mapping, pgoff, RADIX_DAX_PMD); + if (IS_ERR(entry)) + goto finish_iomap; + vmf.pgoff = pgoff; vmf.flags = flags; vmf.gfp_mask = mapping_gfp_mask(mapping) | __GFP_IO; @@ -1310,7 +1372,7 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address, case IOMAP_UNWRITTEN: case IOMAP_HOLE: if (WARN_ON_ONCE(write)) - goto finish_iomap; + goto unlock_entry; result = dax_pmd_load_hole(vma, pmd, &vmf, address, &iomap, &entry); break; @@ -1319,20 +1381,23 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address, break; } + unlock_entry: + put_locked_mapping_entry(mapping, pgoff, entry); finish_iomap: if (ops->iomap_end) { - if (result == VM_FAULT_FALLBACK) { - ops->iomap_end(inode, pos, PMD_SIZE, 0, iomap_flags, - &iomap); - } else { - error = ops->iomap_end(inode, pos, PMD_SIZE, PMD_SIZE, - iomap_flags, &iomap); - if (error) - result = VM_FAULT_FALLBACK; - } + int copied = PMD_SIZE; + + if (result == VM_FAULT_FALLBACK) + copied = 0; + /* + * The fault is done by now and there's no way back (other + * thread may be already happily using PMD we have installed). + * Just ignore error from ->iomap_end since we cannot do much + * with it. + */ + ops->iomap_end(inode, pos, PMD_SIZE, copied, iomap_flags, + &iomap); } - unlock_entry: - put_locked_mapping_entry(mapping, pgoff, entry); fallback: if (result == VM_FAULT_FALLBACK) { split_huge_pmd(vma, pmd, address); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 0093ea2512a8..f073bfca694b 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -751,9 +751,8 @@ static int ext2_get_blocks(struct inode *inode, mutex_unlock(&ei->truncate_mutex); goto cleanup; } - } else { - *new = true; } + *new = true; ext2_splice_branch(inode, iblock, partial, indirect_blks, count); mutex_unlock(&ei->truncate_mutex); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index b5f184493c57..d663d3d7c81c 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -258,7 +258,6 @@ out: static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { int result; - handle_t *handle = NULL; struct inode *inode = file_inode(vma->vm_file); struct super_block *sb = inode->i_sb; bool write = vmf->flags & FAULT_FLAG_WRITE; @@ -266,24 +265,12 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (write) { sb_start_pagefault(sb); file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, - EXT4_DATA_TRANS_BLOCKS(sb)); - } else - down_read(&EXT4_I(inode)->i_mmap_sem); - - if (IS_ERR(handle)) - result = VM_FAULT_SIGBUS; - else - result = dax_iomap_fault(vma, vmf, &ext4_iomap_ops); - - if (write) { - if (!IS_ERR(handle)) - ext4_journal_stop(handle); - up_read(&EXT4_I(inode)->i_mmap_sem); + } + down_read(&EXT4_I(inode)->i_mmap_sem); + result = dax_iomap_fault(vma, vmf, &ext4_iomap_ops); + up_read(&EXT4_I(inode)->i_mmap_sem); + if (write) sb_end_pagefault(sb); - } else - up_read(&EXT4_I(inode)->i_mmap_sem); return result; } @@ -292,7 +279,6 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd, unsigned int flags) { int result; - handle_t *handle = NULL; struct inode *inode = file_inode(vma->vm_file); struct super_block *sb = inode->i_sb; bool write = flags & FAULT_FLAG_WRITE; @@ -300,27 +286,13 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, if (write) { sb_start_pagefault(sb); file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, - ext4_chunk_trans_blocks(inode, - PMD_SIZE / PAGE_SIZE)); - } else - down_read(&EXT4_I(inode)->i_mmap_sem); - - if (IS_ERR(handle)) - result = VM_FAULT_SIGBUS; - else { - result = dax_iomap_pmd_fault(vma, addr, pmd, flags, - &ext4_iomap_ops); } - - if (write) { - if (!IS_ERR(handle)) - ext4_journal_stop(handle); - up_read(&EXT4_I(inode)->i_mmap_sem); + down_read(&EXT4_I(inode)->i_mmap_sem); + result = dax_iomap_pmd_fault(vma, addr, pmd, flags, + &ext4_iomap_ops); + up_read(&EXT4_I(inode)->i_mmap_sem); + if (write) sb_end_pagefault(sb); - } else - up_read(&EXT4_I(inode)->i_mmap_sem); return result; } diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h index 360e00cefd35..a0c812b0fa39 100644 --- a/include/dt-bindings/clock/bcm2835.h +++ b/include/dt-bindings/clock/bcm2835.h @@ -64,3 +64,5 @@ #define BCM2835_CLOCK_CAM1 46 #define BCM2835_CLOCK_DSI0E 47 #define BCM2835_CLOCK_DSI1E 48 +#define BCM2835_CLOCK_DSI0P 49 +#define BCM2835_CLOCK_DSI1P 50 diff --git a/include/dt-bindings/clock/exynos4415.h b/include/dt-bindings/clock/exynos4415.h deleted file mode 100644 index 7eed55100721..000000000000 --- a/include/dt-bindings/clock/exynos4415.h +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * Author: Chanwoo Choi <cw00.choi@samsung.com> - * - * 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. - * - * Device Tree binding constants for Samsung Exynos4415 clock controllers. - */ - -#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS4415_CLOCK_H -#define _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS4415_CLOCK_H - -/* - * Let each exported clock get a unique index, which is used on DT-enabled - * platforms to lookup the clock from a clock specifier. These indices are - * therefore considered an ABI and so must not be changed. This implies - * that new clocks should be added either in free spaces between clock groups - * or at the end. - */ - -/* - * Main CMU - */ - -#define CLK_OSCSEL 1 -#define CLK_FIN_PLL 2 -#define CLK_FOUT_APLL 3 -#define CLK_FOUT_MPLL 4 -#define CLK_FOUT_EPLL 5 -#define CLK_FOUT_G3D_PLL 6 -#define CLK_FOUT_ISP_PLL 7 -#define CLK_FOUT_DISP_PLL 8 - -/* Muxes */ -#define CLK_MOUT_MPLL_USER_L 16 -#define CLK_MOUT_GDL 17 -#define CLK_MOUT_MPLL_USER_R 18 -#define CLK_MOUT_GDR 19 -#define CLK_MOUT_EBI 20 -#define CLK_MOUT_ACLK_200 21 -#define CLK_MOUT_ACLK_160 22 -#define CLK_MOUT_ACLK_100 23 -#define CLK_MOUT_ACLK_266 24 -#define CLK_MOUT_G3D_PLL 25 -#define CLK_MOUT_EPLL 26 -#define CLK_MOUT_EBI_1 27 -#define CLK_MOUT_ISP_PLL 28 -#define CLK_MOUT_DISP_PLL 29 -#define CLK_MOUT_MPLL_USER_T 30 -#define CLK_MOUT_ACLK_400_MCUISP 31 -#define CLK_MOUT_G3D_PLLSRC 32 -#define CLK_MOUT_CSIS1 33 -#define CLK_MOUT_CSIS0 34 -#define CLK_MOUT_CAM1 35 -#define CLK_MOUT_FIMC3_LCLK 36 -#define CLK_MOUT_FIMC2_LCLK 37 -#define CLK_MOUT_FIMC1_LCLK 38 -#define CLK_MOUT_FIMC0_LCLK 39 -#define CLK_MOUT_MFC 40 -#define CLK_MOUT_MFC_1 41 -#define CLK_MOUT_MFC_0 42 -#define CLK_MOUT_G3D 43 -#define CLK_MOUT_G3D_1 44 -#define CLK_MOUT_G3D_0 45 -#define CLK_MOUT_MIPI0 46 -#define CLK_MOUT_FIMD0 47 -#define CLK_MOUT_TSADC_ISP 48 -#define CLK_MOUT_UART_ISP 49 -#define CLK_MOUT_SPI1_ISP 50 -#define CLK_MOUT_SPI0_ISP 51 -#define CLK_MOUT_PWM_ISP 52 -#define CLK_MOUT_AUDIO0 53 -#define CLK_MOUT_TSADC 54 -#define CLK_MOUT_MMC2 55 -#define CLK_MOUT_MMC1 56 -#define CLK_MOUT_MMC0 57 -#define CLK_MOUT_UART3 58 -#define CLK_MOUT_UART2 59 -#define CLK_MOUT_UART1 60 -#define CLK_MOUT_UART0 61 -#define CLK_MOUT_SPI2 62 -#define CLK_MOUT_SPI1 63 -#define CLK_MOUT_SPI0 64 -#define CLK_MOUT_SPDIF 65 -#define CLK_MOUT_AUDIO2 66 -#define CLK_MOUT_AUDIO1 67 -#define CLK_MOUT_MPLL_USER_C 68 -#define CLK_MOUT_HPM 69 -#define CLK_MOUT_CORE 70 -#define CLK_MOUT_APLL 71 -#define CLK_MOUT_PXLASYNC_CSIS1_FIMC 72 -#define CLK_MOUT_PXLASYNC_CSIS0_FIMC 73 -#define CLK_MOUT_JPEG 74 -#define CLK_MOUT_JPEG1 75 -#define CLK_MOUT_JPEG0 76 -#define CLK_MOUT_ACLK_ISP0_300 77 -#define CLK_MOUT_ACLK_ISP0_400 78 -#define CLK_MOUT_ACLK_ISP0_300_USER 79 -#define CLK_MOUT_ACLK_ISP1_300 80 -#define CLK_MOUT_ACLK_ISP1_300_USER 81 -#define CLK_MOUT_HDMI 82 - -/* Dividers */ -#define CLK_DIV_GPL 90 -#define CLK_DIV_GDL 91 -#define CLK_DIV_GPR 92 -#define CLK_DIV_GDR 93 -#define CLK_DIV_ACLK_400_MCUISP 94 -#define CLK_DIV_EBI 95 -#define CLK_DIV_ACLK_200 96 -#define CLK_DIV_ACLK_160 97 -#define CLK_DIV_ACLK_100 98 -#define CLK_DIV_ACLK_266 99 -#define CLK_DIV_CSIS1 100 -#define CLK_DIV_CSIS0 101 -#define CLK_DIV_CAM1 102 -#define CLK_DIV_FIMC3_LCLK 103 -#define CLK_DIV_FIMC2_LCLK 104 -#define CLK_DIV_FIMC1_LCLK 105 -#define CLK_DIV_FIMC0_LCLK 106 -#define CLK_DIV_TV_BLK 107 -#define CLK_DIV_MFC 108 -#define CLK_DIV_G3D 109 -#define CLK_DIV_MIPI0_PRE 110 -#define CLK_DIV_MIPI0 111 -#define CLK_DIV_FIMD0 112 -#define CLK_DIV_UART_ISP 113 -#define CLK_DIV_SPI1_ISP_PRE 114 -#define CLK_DIV_SPI1_ISP 115 -#define CLK_DIV_SPI0_ISP_PRE 116 -#define CLK_DIV_SPI0_ISP 117 -#define CLK_DIV_PWM_ISP 118 -#define CLK_DIV_PCM0 119 -#define CLK_DIV_AUDIO0 120 -#define CLK_DIV_TSADC_PRE 121 -#define CLK_DIV_TSADC 122 -#define CLK_DIV_MMC1_PRE 123 -#define CLK_DIV_MMC1 124 -#define CLK_DIV_MMC0_PRE 125 -#define CLK_DIV_MMC0 126 -#define CLK_DIV_MMC2_PRE 127 -#define CLK_DIV_MMC2 128 -#define CLK_DIV_UART3 129 -#define CLK_DIV_UART2 130 -#define CLK_DIV_UART1 131 -#define CLK_DIV_UART0 132 -#define CLK_DIV_SPI1_PRE 133 -#define CLK_DIV_SPI1 134 -#define CLK_DIV_SPI0_PRE 135 -#define CLK_DIV_SPI0 136 -#define CLK_DIV_SPI2_PRE 137 -#define CLK_DIV_SPI2 138 -#define CLK_DIV_PCM2 139 -#define CLK_DIV_AUDIO2 140 -#define CLK_DIV_PCM1 141 -#define CLK_DIV_AUDIO1 142 -#define CLK_DIV_I2S1 143 -#define CLK_DIV_PXLASYNC_CSIS1_FIMC 144 -#define CLK_DIV_PXLASYNC_CSIS0_FIMC 145 -#define CLK_DIV_JPEG 146 -#define CLK_DIV_CORE2 147 -#define CLK_DIV_APLL 148 -#define CLK_DIV_PCLK_DBG 149 -#define CLK_DIV_ATB 150 -#define CLK_DIV_PERIPH 151 -#define CLK_DIV_COREM1 152 -#define CLK_DIV_COREM0 153 -#define CLK_DIV_CORE 154 -#define CLK_DIV_HPM 155 -#define CLK_DIV_COPY 156 - -/* Gates */ -#define CLK_ASYNC_G3D 180 -#define CLK_ASYNC_MFCL 181 -#define CLK_ASYNC_TVX 182 -#define CLK_PPMULEFT 183 -#define CLK_GPIO_LEFT 184 -#define CLK_PPMUIMAGE 185 -#define CLK_QEMDMA2 186 -#define CLK_QEROTATOR 187 -#define CLK_SMMUMDMA2 188 -#define CLK_SMMUROTATOR 189 -#define CLK_MDMA2 190 -#define CLK_ROTATOR 191 -#define CLK_ASYNC_ISPMX 192 -#define CLK_ASYNC_MAUDIOX 193 -#define CLK_ASYNC_MFCR 194 -#define CLK_ASYNC_FSYSD 195 -#define CLK_ASYNC_LCD0X 196 -#define CLK_ASYNC_CAMX 197 -#define CLK_PPMURIGHT 198 -#define CLK_GPIO_RIGHT 199 -#define CLK_ANTIRBK_APBIF 200 -#define CLK_EFUSE_WRITER_APBIF 201 -#define CLK_MONOCNT 202 -#define CLK_TZPC6 203 -#define CLK_PROVISIONKEY1 204 -#define CLK_PROVISIONKEY0 205 -#define CLK_CMU_ISPPART 206 -#define CLK_TMU_APBIF 207 -#define CLK_KEYIF 208 -#define CLK_RTC 209 -#define CLK_WDT 210 -#define CLK_MCT 211 -#define CLK_SECKEY 212 -#define CLK_HDMI_CEC 213 -#define CLK_TZPC5 214 -#define CLK_TZPC4 215 -#define CLK_TZPC3 216 -#define CLK_TZPC2 217 -#define CLK_TZPC1 218 -#define CLK_TZPC0 219 -#define CLK_CMU_COREPART 220 -#define CLK_CMU_TOPPART 221 -#define CLK_PMU_APBIF 222 -#define CLK_SYSREG 223 -#define CLK_CHIP_ID 224 -#define CLK_SMMUFIMC_LITE2 225 -#define CLK_FIMC_LITE2 226 -#define CLK_PIXELASYNCM1 227 -#define CLK_PIXELASYNCM0 228 -#define CLK_PPMUCAMIF 229 -#define CLK_SMMUJPEG 230 -#define CLK_SMMUFIMC3 231 -#define CLK_SMMUFIMC2 232 -#define CLK_SMMUFIMC1 233 -#define CLK_SMMUFIMC0 234 -#define CLK_JPEG 235 -#define CLK_CSIS1 236 -#define CLK_CSIS0 237 -#define CLK_FIMC3 238 -#define CLK_FIMC2 239 -#define CLK_FIMC1 240 -#define CLK_FIMC0 241 -#define CLK_PPMUTV 242 -#define CLK_SMMUTV 243 -#define CLK_HDMI 244 -#define CLK_MIXER 245 -#define CLK_VP 246 -#define CLK_PPMUMFC_R 247 -#define CLK_PPMUMFC_L 248 -#define CLK_SMMUMFC_R 249 -#define CLK_SMMUMFC_L 250 -#define CLK_MFC 251 -#define CLK_PPMUG3D 252 -#define CLK_G3D 253 -#define CLK_PPMULCD0 254 -#define CLK_SMMUFIMD0 255 -#define CLK_DSIM0 256 -#define CLK_SMIES 257 -#define CLK_MIE0 258 -#define CLK_FIMD0 259 -#define CLK_TSADC 260 -#define CLK_PPMUFILE 261 -#define CLK_NFCON 262 -#define CLK_USBDEVICE 263 -#define CLK_USBHOST 264 -#define CLK_SROMC 265 -#define CLK_SDMMC2 266 -#define CLK_SDMMC1 267 -#define CLK_SDMMC0 268 -#define CLK_PDMA1 269 -#define CLK_PDMA0 270 -#define CLK_SPDIF 271 -#define CLK_PWM 272 -#define CLK_PCM2 273 -#define CLK_PCM1 274 -#define CLK_I2S1 275 -#define CLK_SPI2 276 -#define CLK_SPI1 277 -#define CLK_SPI0 278 -#define CLK_I2CHDMI 279 -#define CLK_I2C7 280 -#define CLK_I2C6 281 -#define CLK_I2C5 282 -#define CLK_I2C4 283 -#define CLK_I2C3 284 -#define CLK_I2C2 285 -#define CLK_I2C1 286 -#define CLK_I2C0 287 -#define CLK_UART3 288 -#define CLK_UART2 289 -#define CLK_UART1 290 -#define CLK_UART0 291 - -/* Special clocks */ -#define CLK_SCLK_PXLAYSNC_CSIS1_FIMC 330 -#define CLK_SCLK_PXLAYSNC_CSIS0_FIMC 331 -#define CLK_SCLK_JPEG 332 -#define CLK_SCLK_CSIS1 333 -#define CLK_SCLK_CSIS0 334 -#define CLK_SCLK_CAM1 335 -#define CLK_SCLK_FIMC3_LCLK 336 -#define CLK_SCLK_FIMC2_LCLK 337 -#define CLK_SCLK_FIMC1_LCLK 338 -#define CLK_SCLK_FIMC0_LCLK 339 -#define CLK_SCLK_PIXEL 340 -#define CLK_SCLK_HDMI 341 -#define CLK_SCLK_MIXER 342 -#define CLK_SCLK_MFC 343 -#define CLK_SCLK_G3D 344 -#define CLK_SCLK_MIPIDPHY4L 345 -#define CLK_SCLK_MIPI0 346 -#define CLK_SCLK_MDNIE0 347 -#define CLK_SCLK_FIMD0 348 -#define CLK_SCLK_PCM0 349 -#define CLK_SCLK_AUDIO0 350 -#define CLK_SCLK_TSADC 351 -#define CLK_SCLK_EBI 352 -#define CLK_SCLK_MMC2 353 -#define CLK_SCLK_MMC1 354 -#define CLK_SCLK_MMC0 355 -#define CLK_SCLK_I2S 356 -#define CLK_SCLK_PCM2 357 -#define CLK_SCLK_PCM1 358 -#define CLK_SCLK_AUDIO2 359 -#define CLK_SCLK_AUDIO1 360 -#define CLK_SCLK_SPDIF 361 -#define CLK_SCLK_SPI2 362 -#define CLK_SCLK_SPI1 363 -#define CLK_SCLK_SPI0 364 -#define CLK_SCLK_UART3 365 -#define CLK_SCLK_UART2 366 -#define CLK_SCLK_UART1 367 -#define CLK_SCLK_UART0 368 -#define CLK_SCLK_HDMIPHY 369 - -/* - * Total number of clocks of main CMU. - * NOTE: Must be equal to last clock ID increased by one. - */ -#define CLK_NR_CLKS 370 - -/* - * CMU DMC - */ -#define CLK_DMC_FOUT_MPLL 1 -#define CLK_DMC_FOUT_BPLL 2 - -#define CLK_DMC_MOUT_MPLL 3 -#define CLK_DMC_MOUT_BPLL 4 -#define CLK_DMC_MOUT_DPHY 5 -#define CLK_DMC_MOUT_DMC_BUS 6 - -#define CLK_DMC_DIV_DMC 7 -#define CLK_DMC_DIV_DPHY 8 -#define CLK_DMC_DIV_DMC_PRE 9 -#define CLK_DMC_DIV_DMCP 10 -#define CLK_DMC_DIV_DMCD 11 -#define CLK_DMC_DIV_MPLL_PRE 12 - -/* - * Total number of clocks of CMU_DMC. - * NOTE: Must be equal to highest clock ID increased by one. - */ -#define NR_CLKS_DMC 13 - -#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS4415_CLOCK_H */ diff --git a/include/dt-bindings/clock/hi3660-clock.h b/include/dt-bindings/clock/hi3660-clock.h new file mode 100644 index 000000000000..1c00b7fe296f --- /dev/null +++ b/include/dt-bindings/clock/hi3660-clock.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016-2017 Linaro Ltd. + * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __DTS_HI3660_CLOCK_H +#define __DTS_HI3660_CLOCK_H + +/* fixed rate clocks */ +#define HI3660_CLKIN_SYS 0 +#define HI3660_CLKIN_REF 1 +#define HI3660_CLK_FLL_SRC 2 +#define HI3660_CLK_PPLL0 3 +#define HI3660_CLK_PPLL1 4 +#define HI3660_CLK_PPLL2 5 +#define HI3660_CLK_PPLL3 6 +#define HI3660_CLK_SCPLL 7 +#define HI3660_PCLK 8 +#define HI3660_CLK_UART0_DBG 9 +#define HI3660_CLK_UART6 10 +#define HI3660_OSC32K 11 +#define HI3660_OSC19M 12 +#define HI3660_CLK_480M 13 +#define HI3660_CLK_INV 14 + +/* clk in crgctrl */ +#define HI3660_FACTOR_UART3 15 +#define HI3660_CLK_FACTOR_MMC 16 +#define HI3660_CLK_GATE_I2C0 17 +#define HI3660_CLK_GATE_I2C1 18 +#define HI3660_CLK_GATE_I2C2 19 +#define HI3660_CLK_GATE_I2C6 20 +#define HI3660_CLK_DIV_SYSBUS 21 +#define HI3660_CLK_DIV_320M 22 +#define HI3660_CLK_DIV_A53 23 +#define HI3660_CLK_GATE_SPI0 24 +#define HI3660_CLK_GATE_SPI2 25 +#define HI3660_PCIEPHY_REF 26 +#define HI3660_CLK_ABB_USB 27 +#define HI3660_HCLK_GATE_SDIO0 28 +#define HI3660_HCLK_GATE_SD 29 +#define HI3660_CLK_GATE_AOMM 30 +#define HI3660_PCLK_GPIO0 31 +#define HI3660_PCLK_GPIO1 32 +#define HI3660_PCLK_GPIO2 33 +#define HI3660_PCLK_GPIO3 34 +#define HI3660_PCLK_GPIO4 35 +#define HI3660_PCLK_GPIO5 36 +#define HI3660_PCLK_GPIO6 37 +#define HI3660_PCLK_GPIO7 38 +#define HI3660_PCLK_GPIO8 39 +#define HI3660_PCLK_GPIO9 40 +#define HI3660_PCLK_GPIO10 41 +#define HI3660_PCLK_GPIO11 42 +#define HI3660_PCLK_GPIO12 43 +#define HI3660_PCLK_GPIO13 44 +#define HI3660_PCLK_GPIO14 45 +#define HI3660_PCLK_GPIO15 46 +#define HI3660_PCLK_GPIO16 47 +#define HI3660_PCLK_GPIO17 48 +#define HI3660_PCLK_GPIO18 49 +#define HI3660_PCLK_GPIO19 50 +#define HI3660_PCLK_GPIO20 51 +#define HI3660_PCLK_GPIO21 52 +#define HI3660_CLK_GATE_SPI3 53 +#define HI3660_CLK_GATE_I2C7 54 +#define HI3660_CLK_GATE_I2C3 55 +#define HI3660_CLK_GATE_SPI1 56 +#define HI3660_CLK_GATE_UART1 57 +#define HI3660_CLK_GATE_UART2 58 +#define HI3660_CLK_GATE_UART4 59 +#define HI3660_CLK_GATE_UART5 60 +#define HI3660_CLK_GATE_I2C4 61 +#define HI3660_CLK_GATE_DMAC 62 +#define HI3660_PCLK_GATE_DSS 63 +#define HI3660_ACLK_GATE_DSS 64 +#define HI3660_CLK_GATE_LDI1 65 +#define HI3660_CLK_GATE_LDI0 66 +#define HI3660_CLK_GATE_VIVOBUS 67 +#define HI3660_CLK_GATE_EDC0 68 +#define HI3660_CLK_GATE_TXDPHY0_CFG 69 +#define HI3660_CLK_GATE_TXDPHY0_REF 70 +#define HI3660_CLK_GATE_TXDPHY1_CFG 71 +#define HI3660_CLK_GATE_TXDPHY1_REF 72 +#define HI3660_ACLK_GATE_USB3OTG 73 +#define HI3660_CLK_GATE_SPI4 74 +#define HI3660_CLK_GATE_SD 75 +#define HI3660_CLK_GATE_SDIO0 76 +#define HI3660_CLK_GATE_UFS_SUBSYS 77 +#define HI3660_PCLK_GATE_DSI0 78 +#define HI3660_PCLK_GATE_DSI1 79 +#define HI3660_ACLK_GATE_PCIE 80 +#define HI3660_PCLK_GATE_PCIE_SYS 81 +#define HI3660_CLK_GATE_PCIEAUX 82 +#define HI3660_PCLK_GATE_PCIE_PHY 83 +#define HI3660_CLK_ANDGT_LDI0 84 +#define HI3660_CLK_ANDGT_LDI1 85 +#define HI3660_CLK_ANDGT_EDC0 86 +#define HI3660_CLK_GATE_UFSPHY_GT 87 +#define HI3660_CLK_ANDGT_MMC 88 +#define HI3660_CLK_ANDGT_SD 89 +#define HI3660_CLK_A53HPM_ANDGT 90 +#define HI3660_CLK_ANDGT_SDIO 91 +#define HI3660_CLK_ANDGT_UART0 92 +#define HI3660_CLK_ANDGT_UART1 93 +#define HI3660_CLK_ANDGT_UARTH 94 +#define HI3660_CLK_ANDGT_SPI 95 +#define HI3660_CLK_VIVOBUS_ANDGT 96 +#define HI3660_CLK_AOMM_ANDGT 97 +#define HI3660_CLK_320M_PLL_GT 98 +#define HI3660_AUTODIV_EMMC0BUS 99 +#define HI3660_AUTODIV_SYSBUS 100 +#define HI3660_CLK_GATE_UFSPHY_CFG 101 +#define HI3660_CLK_GATE_UFSIO_REF 102 +#define HI3660_CLK_MUX_SYSBUS 103 +#define HI3660_CLK_MUX_UART0 104 +#define HI3660_CLK_MUX_UART1 105 +#define HI3660_CLK_MUX_UARTH 106 +#define HI3660_CLK_MUX_SPI 107 +#define HI3660_CLK_MUX_I2C 108 +#define HI3660_CLK_MUX_MMC_PLL 109 +#define HI3660_CLK_MUX_LDI1 110 +#define HI3660_CLK_MUX_LDI0 111 +#define HI3660_CLK_MUX_SD_PLL 112 +#define HI3660_CLK_MUX_SD_SYS 113 +#define HI3660_CLK_MUX_EDC0 114 +#define HI3660_CLK_MUX_SDIO_SYS 115 +#define HI3660_CLK_MUX_SDIO_PLL 116 +#define HI3660_CLK_MUX_VIVOBUS 117 +#define HI3660_CLK_MUX_A53HPM 118 +#define HI3660_CLK_MUX_320M 119 +#define HI3660_CLK_MUX_IOPERI 120 +#define HI3660_CLK_DIV_UART0 121 +#define HI3660_CLK_DIV_UART1 122 +#define HI3660_CLK_DIV_UARTH 123 +#define HI3660_CLK_DIV_MMC 124 +#define HI3660_CLK_DIV_SD 125 +#define HI3660_CLK_DIV_EDC0 126 +#define HI3660_CLK_DIV_LDI0 127 +#define HI3660_CLK_DIV_SDIO 128 +#define HI3660_CLK_DIV_LDI1 129 +#define HI3660_CLK_DIV_SPI 130 +#define HI3660_CLK_DIV_VIVOBUS 131 +#define HI3660_CLK_DIV_I2C 132 +#define HI3660_CLK_DIV_UFSPHY 133 +#define HI3660_CLK_DIV_CFGBUS 134 +#define HI3660_CLK_DIV_MMC0BUS 135 +#define HI3660_CLK_DIV_MMC1BUS 136 +#define HI3660_CLK_DIV_UFSPERI 137 +#define HI3660_CLK_DIV_AOMM 138 +#define HI3660_CLK_DIV_IOPERI 139 + +/* clk in pmuctrl */ +#define HI3660_GATE_ABB_192 0 + +/* clk in pctrl */ +#define HI3660_GATE_UFS_TCXO_EN 0 +#define HI3660_GATE_USB_TCXO_EN 1 + +/* clk in sctrl */ +#define HI3660_PCLK_AO_GPIO0 0 +#define HI3660_PCLK_AO_GPIO1 1 +#define HI3660_PCLK_AO_GPIO2 2 +#define HI3660_PCLK_AO_GPIO3 3 +#define HI3660_PCLK_AO_GPIO4 4 +#define HI3660_PCLK_AO_GPIO5 5 +#define HI3660_PCLK_AO_GPIO6 6 +#define HI3660_PCLK_GATE_MMBUF 7 +#define HI3660_CLK_GATE_DSS_AXI_MM 8 +#define HI3660_PCLK_MMBUF_ANDGT 9 +#define HI3660_CLK_MMBUF_PLL_ANDGT 10 +#define HI3660_CLK_FLL_MMBUF_ANDGT 11 +#define HI3660_CLK_SYS_MMBUF_ANDGT 12 +#define HI3660_CLK_GATE_PCIEPHY_GT 13 +#define HI3660_ACLK_MUX_MMBUF 14 +#define HI3660_CLK_SW_MMBUF 15 +#define HI3660_CLK_DIV_AOBUS 16 +#define HI3660_PCLK_DIV_MMBUF 17 +#define HI3660_ACLK_DIV_MMBUF 18 +#define HI3660_CLK_DIV_PCIEPHY 19 + +/* clk in iomcu */ +#define HI3660_CLK_I2C0_IOMCU 0 +#define HI3660_CLK_I2C1_IOMCU 1 +#define HI3660_CLK_I2C2_IOMCU 2 +#define HI3660_CLK_I2C6_IOMCU 3 +#define HI3660_CLK_IOMCU_PERI0 4 + +#endif /* __DTS_HI3660_CLOCK_H */ diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h index 1183347c383f..a7a1a50f33ef 100644 --- a/include/dt-bindings/clock/imx7d-clock.h +++ b/include/dt-bindings/clock/imx7d-clock.h @@ -449,5 +449,6 @@ #define IMX7D_ADC_ROOT_CLK 436 #define IMX7D_CLK_ARM 437 #define IMX7D_CKIL 438 -#define IMX7D_CLK_END 439 +#define IMX7D_OCOTP_CLK 439 +#define IMX7D_CLK_END 440 #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */ diff --git a/include/dt-bindings/clock/qcom,gcc-ipq4019.h b/include/dt-bindings/clock/qcom,gcc-ipq4019.h index 6240e5b0e900..7e8a7be6dcda 100644 --- a/include/dt-bindings/clock/qcom,gcc-ipq4019.h +++ b/include/dt-bindings/clock/qcom,gcc-ipq4019.h @@ -81,6 +81,17 @@ #define GCC_WCSS5G_CLK 62 #define GCC_WCSS5G_REF_CLK 63 #define GCC_WCSS5G_RTC_CLK 64 +#define GCC_APSS_DDRPLL_VCO 65 +#define GCC_SDCC_PLLDIV_CLK 66 +#define GCC_FEPLL_VCO 67 +#define GCC_FEPLL125_CLK 68 +#define GCC_FEPLL125DLY_CLK 69 +#define GCC_FEPLL200_CLK 70 +#define GCC_FEPLL500_CLK 71 +#define GCC_FEPLL_WCSS2G_CLK 72 +#define GCC_FEPLL_WCSS5G_CLK 73 +#define GCC_APSS_CPU_PLLDIV_CLK 74 +#define GCC_PCNOC_AHB_CLK_SRC 75 #define WIFI0_CPU_INIT_RESET 0 #define WIFI0_RADIO_SRIF_RESET 1 diff --git a/include/dt-bindings/clock/qcom,gcc-mdm9615.h b/include/dt-bindings/clock/qcom,gcc-mdm9615.h index 9ab2c4087120..787e448958bd 100644 --- a/include/dt-bindings/clock/qcom,gcc-mdm9615.h +++ b/include/dt-bindings/clock/qcom,gcc-mdm9615.h @@ -323,5 +323,7 @@ #define CE3_H_CLK 305 #define USB_HS1_SYSTEM_CLK_SRC 306 #define USB_HS1_SYSTEM_CLK 307 +#define EBI2_CLK 308 +#define EBI2_AON_CLK 309 #endif diff --git a/include/dt-bindings/clock/qcom,gcc-msm8996.h b/include/dt-bindings/clock/qcom,gcc-msm8996.h index 1828723eb621..1f5c42254798 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8996.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8996.h @@ -339,6 +339,7 @@ #define GCC_PCIE_PHY_COM_NOCSR_BCR 102 #define GCC_USB3_PHY_BCR 103 #define GCC_USB3PHY_PHY_BCR 104 +#define GCC_MSS_RESTART 105 /* Indexes for GDSCs */ diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index 5924cdb71336..96b63c00249e 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -14,7 +14,7 @@ #ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H #define _DT_BINDINGS_CLK_MSM_RPMCC_H -/* apq8064 */ +/* RPM clocks */ #define RPM_PXO_CLK 0 #define RPM_PXO_A_CLK 1 #define RPM_CXO_CLK 2 @@ -38,7 +38,7 @@ #define RPM_SFPB_CLK 20 #define RPM_SFPB_A_CLK 21 -/* msm8916 */ +/* SMD RPM clocks */ #define RPM_SMD_XO_CLK_SRC 0 #define RPM_SMD_XO_A_CLK_SRC 1 #define RPM_SMD_PCNOC_CLK 2 @@ -65,5 +65,41 @@ #define RPM_SMD_RF_CLK1_A_PIN 23 #define RPM_SMD_RF_CLK2_PIN 24 #define RPM_SMD_RF_CLK2_A_PIN 25 +#define RPM_SMD_PNOC_CLK 26 +#define RPM_SMD_PNOC_A_CLK 27 +#define RPM_SMD_CNOC_CLK 28 +#define RPM_SMD_CNOC_A_CLK 29 +#define RPM_SMD_MMSSNOC_AHB_CLK 30 +#define RPM_SMD_MMSSNOC_AHB_A_CLK 31 +#define RPM_SMD_GFX3D_CLK_SRC 32 +#define RPM_SMD_GFX3D_A_CLK_SRC 33 +#define RPM_SMD_OCMEMGX_CLK 34 +#define RPM_SMD_OCMEMGX_A_CLK 35 +#define RPM_SMD_CXO_D0 36 +#define RPM_SMD_CXO_D0_A 37 +#define RPM_SMD_CXO_D1 38 +#define RPM_SMD_CXO_D1_A 39 +#define RPM_SMD_CXO_A0 40 +#define RPM_SMD_CXO_A0_A 41 +#define RPM_SMD_CXO_A1 42 +#define RPM_SMD_CXO_A1_A 43 +#define RPM_SMD_CXO_A2 44 +#define RPM_SMD_CXO_A2_A 45 +#define RPM_SMD_DIV_CLK1 46 +#define RPM_SMD_DIV_A_CLK1 47 +#define RPM_SMD_DIV_CLK2 48 +#define RPM_SMD_DIV_A_CLK2 49 +#define RPM_SMD_DIFF_CLK 50 +#define RPM_SMD_DIFF_A_CLK 51 +#define RPM_SMD_CXO_D0_PIN 52 +#define RPM_SMD_CXO_D0_A_PIN 53 +#define RPM_SMD_CXO_D1_PIN 54 +#define RPM_SMD_CXO_D1_A_PIN 55 +#define RPM_SMD_CXO_A0_PIN 56 +#define RPM_SMD_CXO_A0_A_PIN 57 +#define RPM_SMD_CXO_A1_PIN 58 +#define RPM_SMD_CXO_A1_A_PIN 59 +#define RPM_SMD_CXO_A2_PIN 60 +#define RPM_SMD_CXO_A2_A_PIN 61 #endif diff --git a/include/dt-bindings/clock/rk3188-cru-common.h b/include/dt-bindings/clock/rk3188-cru-common.h index d141c1f0c778..eff4319d008b 100644 --- a/include/dt-bindings/clock/rk3188-cru-common.h +++ b/include/dt-bindings/clock/rk3188-cru-common.h @@ -108,6 +108,8 @@ #define PCLK_TSADC 349 #define PCLK_CPU 350 #define PCLK_PERI 351 +#define PCLK_DDRUPCTL 352 +#define PCLK_PUBL 353 /* hclk gates */ #define HCLK_SDMMC 448 diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h index 9a586e2d9c91..08de7de649e2 100644 --- a/include/dt-bindings/clock/rk3288-cru.h +++ b/include/dt-bindings/clock/rk3288-cru.h @@ -168,6 +168,7 @@ #define PCLK_WDT 368 #define PCLK_EFUSE256 369 #define PCLK_EFUSE1024 370 +#define PCLK_ISP_IN 371 /* hclk gates */ #define HCLK_GPS 448 diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h new file mode 100644 index 000000000000..ee702c8e4c09 --- /dev/null +++ b/include/dt-bindings/clock/rk3328-cru.h @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Elaine <zhangqing@rock-chips.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3328_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3328_H + +/* core clocks */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_CPLL 3 +#define PLL_GPLL 4 +#define PLL_NPLL 5 +#define ARMCLK 6 + +/* sclk gates (special clocks) */ +#define SCLK_RTC32K 30 +#define SCLK_SDMMC_EXT 31 +#define SCLK_SPI 32 +#define SCLK_SDMMC 33 +#define SCLK_SDIO 34 +#define SCLK_EMMC 35 +#define SCLK_TSADC 36 +#define SCLK_SARADC 37 +#define SCLK_UART0 38 +#define SCLK_UART1 39 +#define SCLK_UART2 40 +#define SCLK_I2S0 41 +#define SCLK_I2S1 42 +#define SCLK_I2S2 43 +#define SCLK_I2S1_OUT 44 +#define SCLK_I2S2_OUT 45 +#define SCLK_SPDIF 46 +#define SCLK_TIMER0 47 +#define SCLK_TIMER1 48 +#define SCLK_TIMER2 49 +#define SCLK_TIMER3 50 +#define SCLK_TIMER4 51 +#define SCLK_TIMER5 52 +#define SCLK_WIFI 53 +#define SCLK_CIF_OUT 54 +#define SCLK_I2C0 55 +#define SCLK_I2C1 56 +#define SCLK_I2C2 57 +#define SCLK_I2C3 58 +#define SCLK_CRYPTO 59 +#define SCLK_PWM 60 +#define SCLK_PDM 61 +#define SCLK_EFUSE 62 +#define SCLK_OTP 63 +#define SCLK_DDRCLK 64 +#define SCLK_VDEC_CABAC 65 +#define SCLK_VDEC_CORE 66 +#define SCLK_VENC_DSP 67 +#define SCLK_VENC_CORE 68 +#define SCLK_RGA 69 +#define SCLK_HDMI_SFC 70 +#define SCLK_HDMI_CEC 71 +#define SCLK_USB3_REF 72 +#define SCLK_USB3_SUSPEND 73 +#define SCLK_SDMMC_DRV 74 +#define SCLK_SDIO_DRV 75 +#define SCLK_EMMC_DRV 76 +#define SCLK_SDMMC_EXT_DRV 77 +#define SCLK_SDMMC_SAMPLE 78 +#define SCLK_SDIO_SAMPLE 79 +#define SCLK_EMMC_SAMPLE 80 +#define SCLK_SDMMC_EXT_SAMPLE 81 +#define SCLK_VOP 82 +#define SCLK_MAC2PHY_RXTX 83 +#define SCLK_MAC2PHY_SRC 84 +#define SCLK_MAC2PHY_REF 85 +#define SCLK_MAC2PHY_OUT 86 +#define SCLK_MAC2IO_RX 87 +#define SCLK_MAC2IO_TX 88 +#define SCLK_MAC2IO_REFOUT 89 +#define SCLK_MAC2IO_REF 90 +#define SCLK_MAC2IO_OUT 91 +#define SCLK_TSP 92 +#define SCLK_HSADC_TSP 93 +#define SCLK_USB3PHY_REF 94 +#define SCLK_REF_USB3OTG 95 +#define SCLK_USB3OTG_REF 96 +#define SCLK_USB3OTG_SUSPEND 97 +#define SCLK_REF_USB3OTG_SRC 98 +#define SCLK_MAC2IO_SRC 99 +#define SCLK_MAC2IO 100 +#define SCLK_MAC2PHY 101 + +/* dclk gates */ +#define DCLK_LCDC 120 +#define DCLK_HDMIPHY 121 +#define HDMIPHY 122 +#define USB480M 123 +#define DCLK_LCDC_SRC 124 + +/* aclk gates */ +#define ACLK_AXISRAM 130 +#define ACLK_VOP_PRE 131 +#define ACLK_USB3OTG 132 +#define ACLK_RGA_PRE 133 +#define ACLK_DMAC 134 +#define ACLK_GPU 135 +#define ACLK_BUS_PRE 136 +#define ACLK_PERI_PRE 137 +#define ACLK_RKVDEC_PRE 138 +#define ACLK_RKVDEC 139 +#define ACLK_RKVENC 140 +#define ACLK_VPU_PRE 141 +#define ACLK_VIO_PRE 142 +#define ACLK_VPU 143 +#define ACLK_VIO 144 +#define ACLK_VOP 145 +#define ACLK_GMAC 146 +#define ACLK_H265 147 +#define ACLK_H264 148 +#define ACLK_MAC2PHY 149 +#define ACLK_MAC2IO 150 +#define ACLK_DCF 151 +#define ACLK_TSP 152 +#define ACLK_PERI 153 +#define ACLK_RGA 154 +#define ACLK_IEP 155 +#define ACLK_CIF 156 +#define ACLK_HDCP 157 + +/* pclk gates */ +#define PCLK_GPIO0 200 +#define PCLK_GPIO1 201 +#define PCLK_GPIO2 202 +#define PCLK_GPIO3 203 +#define PCLK_GRF 204 +#define PCLK_I2C0 205 +#define PCLK_I2C1 206 +#define PCLK_I2C2 207 +#define PCLK_I2C3 208 +#define PCLK_SPI 209 +#define PCLK_UART0 210 +#define PCLK_UART1 211 +#define PCLK_UART2 212 +#define PCLK_TSADC 213 +#define PCLK_PWM 214 +#define PCLK_TIMER 215 +#define PCLK_BUS_PRE 216 +#define PCLK_PERI_PRE 217 +#define PCLK_HDMI_CTRL 218 +#define PCLK_HDMI_PHY 219 +#define PCLK_GMAC 220 +#define PCLK_H265 221 +#define PCLK_MAC2PHY 222 +#define PCLK_MAC2IO 223 +#define PCLK_USB3PHY_OTG 224 +#define PCLK_USB3PHY_PIPE 225 +#define PCLK_USB3_GRF 226 +#define PCLK_USB2_GRF 227 +#define PCLK_HDMIPHY 228 +#define PCLK_DDR 229 +#define PCLK_PERI 230 +#define PCLK_HDMI 231 +#define PCLK_HDCP 232 +#define PCLK_DCF 233 +#define PCLK_SARADC 234 + +/* hclk gates */ +#define HCLK_PERI 308 +#define HCLK_TSP 309 +#define HCLK_GMAC 310 +#define HCLK_I2S0_8CH 311 +#define HCLK_I2S1_8CH 313 +#define HCLK_I2S2_2CH 313 +#define HCLK_SPDIF_8CH 314 +#define HCLK_VOP 315 +#define HCLK_NANDC 316 +#define HCLK_SDMMC 317 +#define HCLK_SDIO 318 +#define HCLK_EMMC 319 +#define HCLK_SDMMC_EXT 320 +#define HCLK_RKVDEC_PRE 321 +#define HCLK_RKVDEC 322 +#define HCLK_RKVENC 323 +#define HCLK_VPU_PRE 324 +#define HCLK_VIO_PRE 325 +#define HCLK_VPU 326 +#define HCLK_VIO 327 +#define HCLK_BUS_PRE 328 +#define HCLK_PERI_PRE 329 +#define HCLK_H264 330 +#define HCLK_CIF 331 +#define HCLK_OTG_PMU 332 +#define HCLK_OTG 333 +#define HCLK_HOST0 334 +#define HCLK_HOST0_ARB 335 +#define HCLK_CRYPTO_MST 336 +#define HCLK_CRYPTO_SLV 337 +#define HCLK_PDM 338 +#define HCLK_IEP 339 +#define HCLK_RGA 340 +#define HCLK_HDCP 341 + +#define CLK_NR_CLKS (HCLK_HDCP + 1) + +/* soft-reset indices */ +#define SRST_CORE0_PO 0 +#define SRST_CORE1_PO 1 +#define SRST_CORE2_PO 2 +#define SRST_CORE3_PO 3 +#define SRST_CORE0 4 +#define SRST_CORE1 5 +#define SRST_CORE2 6 +#define SRST_CORE3 7 +#define SRST_CORE0_DBG 8 +#define SRST_CORE1_DBG 9 +#define SRST_CORE2_DBG 10 +#define SRST_CORE3_DBG 11 +#define SRST_TOPDBG 12 +#define SRST_CORE_NIU 13 +#define SRST_STRC_A 14 +#define SRST_L2C 15 + +#define SRST_A53_GIC 18 +#define SRST_DAP 19 +#define SRST_PMU_P 21 +#define SRST_EFUSE 22 +#define SRST_BUSSYS_H 23 +#define SRST_BUSSYS_P 24 +#define SRST_SPDIF 25 +#define SRST_INTMEM 26 +#define SRST_ROM 27 +#define SRST_GPIO0 28 +#define SRST_GPIO1 29 +#define SRST_GPIO2 30 +#define SRST_GPIO3 31 + +#define SRST_I2S0 32 +#define SRST_I2S1 33 +#define SRST_I2S2 34 +#define SRST_I2S0_H 35 +#define SRST_I2S1_H 36 +#define SRST_I2S2_H 37 +#define SRST_UART0 38 +#define SRST_UART1 39 +#define SRST_UART2 40 +#define SRST_UART0_P 41 +#define SRST_UART1_P 42 +#define SRST_UART2_P 43 +#define SRST_I2C0 44 +#define SRST_I2C1 45 +#define SRST_I2C2 46 +#define SRST_I2C3 47 + +#define SRST_I2C0_P 48 +#define SRST_I2C1_P 49 +#define SRST_I2C2_P 50 +#define SRST_I2C3_P 51 +#define SRST_EFUSE_SE_P 52 +#define SRST_EFUSE_NS_P 53 +#define SRST_PWM0 54 +#define SRST_PWM0_P 55 +#define SRST_DMA 56 +#define SRST_TSP_A 57 +#define SRST_TSP_H 58 +#define SRST_TSP 59 +#define SRST_TSP_HSADC 60 +#define SRST_DCF_A 61 +#define SRST_DCF_P 62 + +#define SRST_SCR 64 +#define SRST_SPI 65 +#define SRST_TSADC 66 +#define SRST_TSADC_P 67 +#define SRST_CRYPTO 68 +#define SRST_SGRF 69 +#define SRST_GRF 70 +#define SRST_USB_GRF 71 +#define SRST_TIMER_6CH_P 72 +#define SRST_TIMER0 73 +#define SRST_TIMER1 74 +#define SRST_TIMER2 75 +#define SRST_TIMER3 76 +#define SRST_TIMER4 77 +#define SRST_TIMER5 78 +#define SRST_USB3GRF 79 + +#define SRST_PHYNIU 80 +#define SRST_HDMIPHY 81 +#define SRST_VDAC 82 +#define SRST_ACODEC_p 83 +#define SRST_SARADC 85 +#define SRST_SARADC_P 86 +#define SRST_GRF_DDR 87 +#define SRST_DFIMON 88 +#define SRST_MSCH 89 +#define SRST_DDRMSCH 91 +#define SRST_DDRCTRL 92 +#define SRST_DDRCTRL_P 93 +#define SRST_DDRPHY 94 +#define SRST_DDRPHY_P 95 + +#define SRST_GMAC_NIU_A 96 +#define SRST_GMAC_NIU_P 97 +#define SRST_GMAC2PHY_A 98 +#define SRST_GMAC2IO_A 99 +#define SRST_MACPHY 100 +#define SRST_OTP_PHY 101 +#define SRST_GPU_A 102 +#define SRST_GPU_NIU_A 103 +#define SRST_SDMMCEXT 104 +#define SRST_PERIPH_NIU_A 105 +#define SRST_PERIHP_NIU_H 106 +#define SRST_PERIHP_P 107 +#define SRST_PERIPHSYS_H 108 +#define SRST_MMC0 109 +#define SRST_SDIO 110 +#define SRST_EMMC 111 + +#define SRST_USB2OTG_H 112 +#define SRST_USB2OTG 113 +#define SRST_USB2OTG_ADP 114 +#define SRST_USB2HOST_H 115 +#define SRST_USB2HOST_ARB 116 +#define SRST_USB2HOST_AUX 117 +#define SRST_USB2HOST_EHCIPHY 118 +#define SRST_USB2HOST_UTMI 119 +#define SRST_USB3OTG 120 +#define SRST_USBPOR 121 +#define SRST_USB2OTG_UTMI 122 +#define SRST_USB2HOST_PHY_UTMI 123 +#define SRST_USB3OTG_UTMI 124 +#define SRST_USB3PHY_U2 125 +#define SRST_USB3PHY_U3 126 +#define SRST_USB3PHY_PIPE 127 + +#define SRST_VIO_A 128 +#define SRST_VIO_BUS_H 129 +#define SRST_VIO_H2P_H 130 +#define SRST_VIO_ARBI_H 131 +#define SRST_VOP_NIU_A 132 +#define SRST_VOP_A 133 +#define SRST_VOP_H 134 +#define SRST_VOP_D 135 +#define SRST_RGA 136 +#define SRST_RGA_NIU_A 137 +#define SRST_RGA_A 138 +#define SRST_RGA_H 139 +#define SRST_IEP_A 140 +#define SRST_IEP_H 141 +#define SRST_HDMI 142 +#define SRST_HDMI_P 143 + +#define SRST_HDCP_A 144 +#define SRST_HDCP 145 +#define SRST_HDCP_H 146 +#define SRST_CIF_A 147 +#define SRST_CIF_H 148 +#define SRST_CIF_P 149 +#define SRST_OTP_P 150 +#define SRST_OTP_SBPI 151 +#define SRST_OTP_USER 152 +#define SRST_DDRCTRL_A 153 +#define SRST_DDRSTDY_P 154 +#define SRST_DDRSTDY 155 +#define SRST_PDM_H 156 +#define SRST_PDM 157 +#define SRST_USB3PHY_OTG_P 158 +#define SRST_USB3PHY_PIPE_P 159 + +#define SRST_VCODEC_A 160 +#define SRST_VCODEC_NIU_A 161 +#define SRST_VCODEC_H 162 +#define SRST_VCODEC_NIU_H 163 +#define SRST_VDEC_A 164 +#define SRST_VDEC_NIU_A 165 +#define SRST_VDEC_H 166 +#define SRST_VDEC_NIU_H 167 +#define SRST_VDEC_CORE 168 +#define SRST_VDEC_CABAC 169 +#define SRST_DDRPHYDIV 175 + +#define SRST_RKVENC_NIU_A 176 +#define SRST_RKVENC_NIU_H 177 +#define SRST_RKVENC_H265_A 178 +#define SRST_RKVENC_H265_P 179 +#define SRST_RKVENC_H265_CORE 180 +#define SRST_RKVENC_H265_DSP 181 +#define SRST_RKVENC_H264_A 182 +#define SRST_RKVENC_H264_H 183 +#define SRST_RKVENC_INTMEM 184 + +#endif diff --git a/include/dt-bindings/clock/ste-ab8500.h b/include/dt-bindings/clock/ste-ab8500.h new file mode 100644 index 000000000000..6731f1f00a84 --- /dev/null +++ b/include/dt-bindings/clock/ste-ab8500.h @@ -0,0 +1,11 @@ +#ifndef __STE_CLK_AB8500_H__ +#define __STE_CLK_AB8500_H__ + +#define AB8500_SYSCLK_BUF2 0 +#define AB8500_SYSCLK_BUF3 1 +#define AB8500_SYSCLK_BUF4 2 +#define AB8500_SYSCLK_ULP 3 +#define AB8500_SYSCLK_INT 4 +#define AB8500_SYSCLK_AUDIO 5 + +#endif diff --git a/include/dt-bindings/clock/stm32fx-clock.h b/include/dt-bindings/clock/stm32fx-clock.h new file mode 100644 index 000000000000..49bb3c203e5c --- /dev/null +++ b/include/dt-bindings/clock/stm32fx-clock.h @@ -0,0 +1,59 @@ +/* + * stm32fx-clock.h + * + * Copyright (C) 2016 STMicroelectronics + * Author: Gabriel Fernandez for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +/* + * List of clocks wich are not derived from system clock (SYSCLOCK) + * + * The index of these clocks is the secondary index of DT bindings + * (see Documentatoin/devicetree/bindings/clock/st,stm32-rcc.txt) + * + * e.g: + <assigned-clocks = <&rcc 1 CLK_LSE>; +*/ + +#ifndef _DT_BINDINGS_CLK_STMFX_H +#define _DT_BINDINGS_CLK_STMFX_H + +#define SYSTICK 0 +#define FCLK 1 +#define CLK_LSI 2 +#define CLK_LSE 3 +#define CLK_HSE_RTC 4 +#define CLK_RTC 5 +#define PLL_VCO_I2S 6 +#define PLL_VCO_SAI 7 +#define CLK_LCD 8 +#define CLK_I2S 9 +#define CLK_SAI1 10 +#define CLK_SAI2 11 +#define CLK_I2SQ_PDIV 12 +#define CLK_SAIQ_PDIV 13 + +#define END_PRIMARY_CLK 14 + +#define CLK_HSI 14 +#define CLK_SYSCLK 15 +#define CLK_HDMI_CEC 16 +#define CLK_SPDIF 17 +#define CLK_USART1 18 +#define CLK_USART2 19 +#define CLK_USART3 20 +#define CLK_UART4 21 +#define CLK_UART5 22 +#define CLK_USART6 23 +#define CLK_UART7 24 +#define CLK_UART8 25 +#define CLK_I2C1 26 +#define CLK_I2C2 27 +#define CLK_I2C3 28 +#define CLK_I2C4 29 +#define CLK_LPTIMER 30 + +#define END_PRIMARY_CLK_F7 31 + +#endif diff --git a/include/linux/dax.h b/include/linux/dax.h index f97bcfe79472..24ad71173995 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -41,6 +41,9 @@ ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, struct iomap_ops *ops); int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index); +int dax_invalidate_mapping_entry(struct address_space *mapping, pgoff_t index); +int dax_invalidate_mapping_entry_sync(struct address_space *mapping, + pgoff_t index); void dax_wake_mapping_entry_waiter(struct address_space *mapping, pgoff_t index, void *entry, bool wake_all); diff --git a/include/linux/filter.h b/include/linux/filter.h index 702314253797..a0934e6c9bab 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -610,7 +610,6 @@ bool bpf_helper_changes_pkt_data(void *func); struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, const struct bpf_insn *patch, u32 len); void bpf_warn_invalid_xdp_action(u32 act); -void bpf_warn_invalid_xdp_buffer(void); #ifdef CONFIG_BPF_JIT extern int bpf_jit_enable; diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index c56b39890a41..6b5818d6de32 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -73,13 +73,13 @@ */ enum pageflags { PG_locked, /* Page is locked. Don't touch. */ - PG_waiters, /* Page has waiters, check its waitqueue */ PG_error, PG_referenced, PG_uptodate, PG_dirty, PG_lru, PG_active, + PG_waiters, /* Page has waiters, check its waitqueue. Must be bit #7 and in the same byte as "PG_locked" */ PG_slab, PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ PG_arch_1, diff --git a/include/linux/platform_data/x86/clk-pmc-atom.h b/include/linux/platform_data/x86/clk-pmc-atom.h new file mode 100644 index 000000000000..3ab892208343 --- /dev/null +++ b/include/linux/platform_data/x86/clk-pmc-atom.h @@ -0,0 +1,44 @@ +/* + * Intel Atom platform clocks for BayTrail and CherryTrail SoC. + * + * Copyright (C) 2016, Intel Corporation + * Author: Irina Tirdea <irina.tirdea@intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#ifndef __PLATFORM_DATA_X86_CLK_PMC_ATOM_H +#define __PLATFORM_DATA_X86_CLK_PMC_ATOM_H + +/** + * struct pmc_clk - PMC platform clock configuration + * + * @name: identified, typically pmc_plt_clk_<x>, x=[0..5] + * @freq: in Hz, 19.2MHz and 25MHz (Baytrail only) supported + * @parent_name: one of 'xtal' or 'osc' + */ +struct pmc_clk { + const char *name; + unsigned long freq; + const char *parent_name; +}; + +/** + * struct pmc_clk_data - common PMC clock configuration + * + * @base: PMC clock register base offset + * @clks: pointer to set of registered clocks, typically 0..5 + */ +struct pmc_clk_data { + void __iomem *base; + const struct pmc_clk *clks; +}; + +#endif /* __PLATFORM_DATA_X86_CLK_PMC_ATOM_H */ diff --git a/arch/x86/include/asm/pmc_atom.h b/include/linux/platform_data/x86/pmc_atom.h index aa8744c77c6d..e4905fe69c38 100644 --- a/arch/x86/include/asm/pmc_atom.h +++ b/include/linux/platform_data/x86/pmc_atom.h @@ -50,7 +50,7 @@ BIT_ORED_DEDICATED_IRQ_GPSC | \ BIT_SHARED_IRQ_GPSS) -/* The timers acumulate time spent in sleep state */ +/* The timers accumulate time spent in sleep state */ #define PMC_S0IR_TMR 0x80 #define PMC_S0I1_TMR 0x84 #define PMC_S0I2_TMR 0x88 diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index f0cf5a1b777e..0378e88f6fd3 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -110,6 +110,7 @@ struct netns_ipv4 { int sysctl_tcp_orphan_retries; int sysctl_tcp_fin_timeout; unsigned int sysctl_tcp_notsent_lowat; + int sysctl_tcp_tw_reuse; int sysctl_igmp_max_memberships; int sysctl_igmp_max_msf; diff --git a/include/net/tcp.h b/include/net/tcp.h index 207147b4c6b2..6061963cca98 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -252,7 +252,6 @@ extern int sysctl_tcp_wmem[3]; extern int sysctl_tcp_rmem[3]; extern int sysctl_tcp_app_win; extern int sysctl_tcp_adv_win_scale; -extern int sysctl_tcp_tw_reuse; extern int sysctl_tcp_frto; extern int sysctl_tcp_low_latency; extern int sysctl_tcp_nometrics_save; diff --git a/kernel/cpu.c b/kernel/cpu.c index 042fd7e8e030..f75c4d031eeb 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1471,6 +1471,7 @@ int __cpuhp_setup_state(enum cpuhp_state state, bool multi_instance) { int cpu, ret = 0; + bool dynstate; if (cpuhp_cb_check(state) || !name) return -EINVAL; @@ -1480,6 +1481,12 @@ int __cpuhp_setup_state(enum cpuhp_state state, ret = cpuhp_store_callbacks(state, name, startup, teardown, multi_instance); + dynstate = state == CPUHP_AP_ONLINE_DYN; + if (ret > 0 && dynstate) { + state = ret; + ret = 0; + } + if (ret || !invoke || !startup) goto out; @@ -1508,7 +1515,7 @@ out: * If the requested state is CPUHP_AP_ONLINE_DYN, return the * dynamically allocated state in case of success. */ - if (!ret && state == CPUHP_AP_ONLINE_DYN) + if (!ret && dynstate) return state; return ret; } diff --git a/mm/filemap.c b/mm/filemap.c index 82f26cde830c..d0e4d1002059 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -912,6 +912,29 @@ void add_page_wait_queue(struct page *page, wait_queue_t *waiter) } EXPORT_SYMBOL_GPL(add_page_wait_queue); +#ifndef clear_bit_unlock_is_negative_byte + +/* + * PG_waiters is the high bit in the same byte as PG_lock. + * + * On x86 (and on many other architectures), we can clear PG_lock and + * test the sign bit at the same time. But if the architecture does + * not support that special operation, we just do this all by hand + * instead. + * + * The read of PG_waiters has to be after (or concurrently with) PG_locked + * being cleared, but a memory barrier should be unneccssary since it is + * in the same byte as PG_locked. + */ +static inline bool clear_bit_unlock_is_negative_byte(long nr, volatile void *mem) +{ + clear_bit_unlock(nr, mem); + /* smp_mb__after_atomic(); */ + return test_bit(PG_waiters, mem); +} + +#endif + /** * unlock_page - unlock a locked page * @page: the page @@ -921,16 +944,19 @@ EXPORT_SYMBOL_GPL(add_page_wait_queue); * mechanism between PageLocked pages and PageWriteback pages is shared. * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep. * - * The mb is necessary to enforce ordering between the clear_bit and the read - * of the waitqueue (to avoid SMP races with a parallel wait_on_page_locked()). + * Note that this depends on PG_waiters being the sign bit in the byte + * that contains PG_locked - thus the BUILD_BUG_ON(). That allows us to + * clear the PG_locked bit and test PG_waiters at the same time fairly + * portably (architectures that do LL/SC can test any bit, while x86 can + * test the sign bit). */ void unlock_page(struct page *page) { + BUILD_BUG_ON(PG_waiters != 7); page = compound_head(page); VM_BUG_ON_PAGE(!PageLocked(page), page); - clear_bit_unlock(PG_locked, &page->flags); - smp_mb__after_atomic(); - wake_up_page(page, PG_locked); + if (clear_bit_unlock_is_negative_byte(PG_locked, &page->flags)) + wake_up_page_bit(page, PG_locked); } EXPORT_SYMBOL(unlock_page); diff --git a/mm/truncate.c b/mm/truncate.c index fd97f1dbce29..dd7b24e083c5 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -24,20 +24,12 @@ #include <linux/rmap.h> #include "internal.h" -static void clear_exceptional_entry(struct address_space *mapping, - pgoff_t index, void *entry) +static void clear_shadow_entry(struct address_space *mapping, pgoff_t index, + void *entry) { struct radix_tree_node *node; void **slot; - /* Handled by shmem itself */ - if (shmem_mapping(mapping)) - return; - - if (dax_mapping(mapping)) { - dax_delete_mapping_entry(mapping, index); - return; - } spin_lock_irq(&mapping->tree_lock); /* * Regular page slots are stabilized by the page lock even @@ -55,6 +47,56 @@ unlock: spin_unlock_irq(&mapping->tree_lock); } +/* + * Unconditionally remove exceptional entry. Usually called from truncate path. + */ +static void truncate_exceptional_entry(struct address_space *mapping, + pgoff_t index, void *entry) +{ + /* Handled by shmem itself */ + if (shmem_mapping(mapping)) + return; + + if (dax_mapping(mapping)) { + dax_delete_mapping_entry(mapping, index); + return; + } + clear_shadow_entry(mapping, index, entry); +} + +/* + * Invalidate exceptional entry if easily possible. This handles exceptional + * entries for invalidate_inode_pages() so for DAX it evicts only unlocked and + * clean entries. + */ +static int invalidate_exceptional_entry(struct address_space *mapping, + pgoff_t index, void *entry) +{ + /* Handled by shmem itself */ + if (shmem_mapping(mapping)) + return 1; + if (dax_mapping(mapping)) + return dax_invalidate_mapping_entry(mapping, index); + clear_shadow_entry(mapping, index, entry); + return 1; +} + +/* + * Invalidate exceptional entry if clean. This handles exceptional entries for + * invalidate_inode_pages2() so for DAX it evicts only clean entries. + */ +static int invalidate_exceptional_entry2(struct address_space *mapping, + pgoff_t index, void *entry) +{ + /* Handled by shmem itself */ + if (shmem_mapping(mapping)) + return 1; + if (dax_mapping(mapping)) + return dax_invalidate_mapping_entry_sync(mapping, index); + clear_shadow_entry(mapping, index, entry); + return 1; +} + /** * do_invalidatepage - invalidate part or all of a page * @page: the page which is affected @@ -262,7 +304,8 @@ void truncate_inode_pages_range(struct address_space *mapping, break; if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); + truncate_exceptional_entry(mapping, index, + page); continue; } @@ -351,7 +394,8 @@ void truncate_inode_pages_range(struct address_space *mapping, } if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); + truncate_exceptional_entry(mapping, index, + page); continue; } @@ -470,7 +514,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, break; if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); + invalidate_exceptional_entry(mapping, index, + page); continue; } @@ -592,7 +637,9 @@ int invalidate_inode_pages2_range(struct address_space *mapping, break; if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); + if (!invalidate_exceptional_entry2(mapping, + index, page)) + ret = -EBUSY; continue; } diff --git a/net/core/filter.c b/net/core/filter.c index e6c412b94dec..1969b3f118c1 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2972,12 +2972,6 @@ void bpf_warn_invalid_xdp_action(u32 act) } EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action); -void bpf_warn_invalid_xdp_buffer(void) -{ - WARN_ONCE(1, "Illegal XDP buffer encountered, expect throughput degradation\n"); -} -EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_buffer); - static u32 sk_filter_convert_ctx_access(enum bpf_access_type type, int dst_reg, int src_reg, int ctx_off, struct bpf_insn *insn_buf, diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 80bc36b25de2..22cbd61079b5 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -433,13 +433,6 @@ static struct ctl_table ipv4_table[] = { .extra2 = &tcp_adv_win_scale_max, }, { - .procname = "tcp_tw_reuse", - .data = &sysctl_tcp_tw_reuse, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { .procname = "tcp_frto", .data = &sysctl_tcp_frto, .maxlen = sizeof(int), @@ -960,6 +953,13 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "tcp_tw_reuse", + .data = &init_net.ipv4.sysctl_tcp_tw_reuse, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, #ifdef CONFIG_IP_ROUTE_MULTIPATH { .procname = "fib_multipath_use_neigh", diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 30d81f533ada..fe9da4fb96bf 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -84,7 +84,6 @@ #include <crypto/hash.h> #include <linux/scatterlist.h> -int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; #ifdef CONFIG_TCP_MD5SIG @@ -120,7 +119,7 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) and use initial timestamp retrieved from peer table. */ if (tcptw->tw_ts_recent_stamp && - (!twp || (sysctl_tcp_tw_reuse && + (!twp || (sock_net(sk)->ipv4.sysctl_tcp_tw_reuse && get_seconds() - tcptw->tw_ts_recent_stamp > 1))) { tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; if (tp->write_seq == 0) @@ -2456,6 +2455,7 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.sysctl_tcp_orphan_retries = 0; net->ipv4.sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; net->ipv4.sysctl_tcp_notsent_lowat = UINT_MAX; + net->ipv4.sysctl_tcp_tw_reuse = 0; return 0; fail: diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 2d4c4d3911c0..9c62b6325f7a 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -606,7 +606,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) rcu_assign_pointer(flow->sf_acts, acts); packet->priority = flow->key.phy.priority; packet->mark = flow->key.phy.skb_mark; - packet->protocol = flow->key.eth.type; rcu_read_lock(); dp = get_dp_rcu(net, ovs_header->dp_ifindex); diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 08aa926cd5cf..2c0a00f7f1b7 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -312,7 +312,8 @@ static bool icmp6hdr_ok(struct sk_buff *skb) * Returns 0 if it encounters a non-vlan or incomplete packet. * Returns 1 after successfully parsing vlan tag. */ -static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh) +static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh, + bool untag_vlan) { struct vlan_head *vh = (struct vlan_head *)skb->data; @@ -330,7 +331,20 @@ static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh) key_vh->tci = vh->tci | htons(VLAN_TAG_PRESENT); key_vh->tpid = vh->tpid; - __skb_pull(skb, sizeof(struct vlan_head)); + if (unlikely(untag_vlan)) { + int offset = skb->data - skb_mac_header(skb); + u16 tci; + int err; + + __skb_push(skb, offset); + err = __skb_vlan_pop(skb, &tci); + __skb_pull(skb, offset); + if (err) + return err; + __vlan_hwaccel_put_tag(skb, key_vh->tpid, tci); + } else { + __skb_pull(skb, sizeof(struct vlan_head)); + } return 1; } @@ -351,13 +365,13 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) key->eth.vlan.tpid = skb->vlan_proto; } else { /* Parse outer vlan tag in the non-accelerated case. */ - res = parse_vlan_tag(skb, &key->eth.vlan); + res = parse_vlan_tag(skb, &key->eth.vlan, true); if (res <= 0) return res; } /* Parse inner vlan tag. */ - res = parse_vlan_tag(skb, &key->eth.cvlan); + res = parse_vlan_tag(skb, &key->eth.cvlan, false); if (res <= 0) return res; @@ -800,29 +814,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, if (err) return err; - if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { - /* key_extract assumes that skb->protocol is set-up for - * layer 3 packets which is the case for other callers, - * in particular packets recieved from the network stack. - * Here the correct value can be set from the metadata - * extracted above. - */ - skb->protocol = key->eth.type; - } else { - struct ethhdr *eth; - - skb_reset_mac_header(skb); - eth = eth_hdr(skb); - - /* Normally, setting the skb 'protocol' field would be - * handled by a call to eth_type_trans(), but it assumes - * there's a sending device, which we may not have. - */ - if (eth_proto_is_802_3(eth->h_proto)) - skb->protocol = eth->h_proto; - else - skb->protocol = htons(ETH_P_802_2); - } + /* key_extract assumes that skb->protocol is set-up for + * layer 3 packets which is the case for other callers, + * in particular packets received from the network stack. + * Here the correct value can be set from the metadata + * extracted above. + * For L2 packet key eth type would be zero. skb protocol + * would be set to correct value later during key-extact. + */ + skb->protocol = key->eth.type; return key_extract(skb, key); } diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 3fbba79a4ef0..1ecdf809b5fa 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -148,13 +148,15 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) unsigned long cl; unsigned long fh; int err; - int tp_created = 0; + int tp_created; if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; replay: + tp_created = 0; + err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL); if (err < 0) return err; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 333c5dae0072..800caaa699a1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -441,15 +441,19 @@ static void __tipc_shutdown(struct socket *sock, int error) while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { if (TIPC_SKB_CB(skb)->bytes_read) { kfree_skb(skb); - } else { - if (!tipc_sk_type_connectionless(sk) && - sk->sk_state != TIPC_DISCONNECTING) { - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - tipc_node_remove_conn(net, dnode, tsk->portid); - } - tipc_sk_respond(sk, skb, error); + continue; + } + if (!tipc_sk_type_connectionless(sk) && + sk->sk_state != TIPC_DISCONNECTING) { + tipc_set_sk_state(sk, TIPC_DISCONNECTING); + tipc_node_remove_conn(net, dnode, tsk->portid); } + tipc_sk_respond(sk, skb, error); } + + if (tipc_sk_type_connectionless(sk)) + return; + if (sk->sk_state != TIPC_DISCONNECTING) { skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, @@ -457,10 +461,8 @@ static void __tipc_shutdown(struct socket *sock, int error) tsk->portid, error); if (skb) tipc_node_xmit_skb(net, skb, dnode, tsk->portid); - if (!tipc_sk_type_connectionless(sk)) { - tipc_node_remove_conn(net, dnode, tsk->portid); - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - } + tipc_node_remove_conn(net, dnode, tsk->portid); + tipc_set_sk_state(sk, TIPC_DISCONNECTING); } } |