From d783f36fce334b96d951ed52c53c57570c4774dd Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Oct 2016 17:07:52 +0200 Subject: dt-bindings: clk: oxnas,stdclk: Add OX820 bindings Add OX820 bindings and remove clock indices from bindings since they are present in the dt-bindings headers files. Signed-off-by: Neil Armstrong Acked-by: Rob Herring Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/20161005150752.22618-7-narmstrong@baylibre.com --- .../devicetree/bindings/clock/oxnas,stdclk.txt | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt b/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt index 208cca6ac4ec..b652f3fb7796 100644 --- a/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt +++ b/Documentation/devicetree/bindings/clock/oxnas,stdclk.txt @@ -5,22 +5,15 @@ Please also refer to clock-bindings.txt in this directory for common clock bindings usage. Required properties: -- compatible: Should be "oxsemi,ox810se-stdclk" +- compatible: For OX810SE, should be "oxsemi,ox810se-stdclk" + For OX820, should be "oxsemi,ox820-stdclk" - #clock-cells: 1, see below Parent node should have the following properties : -- compatible: Should be "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd" - -For OX810SE, the clock indices are : - - 0: LEON - - 1: DMA_SGDMA - - 2: CIPHER - - 3: SATA - - 4: AUDIO - - 5: USBMPH - - 6: ETHA - - 7: PCIA - - 8: NAND +- compatible: For OX810SE, should be + "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd" + For OX820, should be + "oxsemi,ox820-sys-ctrl", "syscon", "simple-mfd" example: -- cgit v1.2.3 From a064a07f72e92cae31cb09c5734ec3c4edd52f47 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Fri, 21 Oct 2016 11:23:30 +0200 Subject: clk: stm32f469: Add QSPI clock This patch adds the QSPI clock for stm32f469 discovery board. The gate mapping is a little bit different from stm32f429 soc. Signed-off-by: Gabriel Fernandez Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/st,stm32-rcc.txt | 4 +- drivers/clk/clk-stm32f4.c | 173 ++++++++++++++++++--- 2 files changed, 158 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt index c209de6cfadb..0532d815dae3 100644 --- a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt +++ b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt @@ -7,7 +7,9 @@ Please refer to clock-bindings.txt for common clock controller binding usage. Please also refer to reset.txt for common reset controller binding usage. Required properties: -- compatible: Should be "st,stm32f42xx-rcc" +- compatible: Should be: + "st,stm32f42xx-rcc" + "st,stm32f469-rcc" - reg: should be register base and length as documented in the datasheet - #reset-cells: 1, see below diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index cbc814868508..5eb05dbf59b8 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -46,7 +46,7 @@ struct stm32f4_gate_data { unsigned long flags; }; -static const struct stm32f4_gate_data stm32f4_gates[] __initconst = { +static const struct stm32f4_gate_data stm32f429_gates[] __initconst = { { STM32F4_RCC_AHB1ENR, 0, "gpioa", "ahb_div" }, { STM32F4_RCC_AHB1ENR, 1, "gpiob", "ahb_div" }, { STM32F4_RCC_AHB1ENR, 2, "gpioc", "ahb_div" }, @@ -126,22 +126,108 @@ static const struct stm32f4_gate_data stm32f4_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; +static const struct stm32f4_gate_data stm32f469_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, "ccmdatam", "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, 17, "uart2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 18, "uart3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 19, "uart4", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 20, "uart5", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 21, "i2c1", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 22, "i2c2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 23, "i2c3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 25, "can1", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 26, "can2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 28, "pwr", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 29, "dac", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 30, "uart7", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 31, "uart8", "apb1_div" }, + + { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 4, "usart1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 5, "usart6", "apb2_div" }, + { 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, 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, 26, "ltdc", "apb2_div" }, +}; + enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK }; -/* - * MAX_CLKS is the maximum value in the enumeration below plus the combined - * hweight of stm32f42xx_gate_map (plus one). - */ -#define MAX_CLKS (71 + END_PRIMARY_CLK + 1) /* * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx * have gate bits associated with them. Its combined hweight is 71. */ -static const u64 stm32f42xx_gate_map[] = { 0x000000f17ef417ffull, - 0x0000000000000001ull, - 0x04777f33f6fec9ffull }; +#define MAX_GATE_MAP 3 + +static const u64 stm32f42xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, + 0x0000000000000001ull, + 0x04777f33f6fec9ffull }; + +static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, + 0x0000000000000003ull, + 0x0c777f33f6fec9ffull }; + +static const u64 *stm32f4_gate_map; + +static struct clk_hw **clks; -static struct clk_hw *clks[MAX_CLKS]; static DEFINE_SPINLOCK(stm32f4_clk_lock); static void __iomem *base; @@ -263,7 +349,7 @@ static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk) */ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) { - u64 table[ARRAY_SIZE(stm32f42xx_gate_map)]; + u64 table[MAX_GATE_MAP]; if (primary == 1) { if (WARN_ON(secondary >= END_PRIMARY_CLK)) @@ -271,7 +357,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) return secondary; } - memcpy(table, stm32f42xx_gate_map, sizeof(table)); + memcpy(table, stm32f4_gate_map, sizeof(table)); /* only bits set in table can be used as indices */ if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) || @@ -525,10 +611,42 @@ static const char *rtc_parents[4] = { "no-clock", "lse", "lsi", "hse-rtc" }; +struct stm32f4_clk_data { + const struct stm32f4_gate_data *gates_data; + const u64 *gates_map; + int gates_num; +}; + +static const struct stm32f4_clk_data stm32f429_clk_data = { + .gates_data = stm32f429_gates, + .gates_map = stm32f42xx_gate_map, + .gates_num = ARRAY_SIZE(stm32f429_gates), +}; + +static const struct stm32f4_clk_data stm32f469_clk_data = { + .gates_data = stm32f469_gates, + .gates_map = stm32f46xx_gate_map, + .gates_num = ARRAY_SIZE(stm32f469_gates), +}; + +static const struct of_device_id stm32f4_of_match[] = { + { + .compatible = "st,stm32f42xx-rcc", + .data = &stm32f429_clk_data + }, + { + .compatible = "st,stm32f469-rcc", + .data = &stm32f469_clk_data + }, + {} +}; + static void __init stm32f4_rcc_init(struct device_node *np) { const char *hse_clk; int n; + const struct of_device_id *match; + const struct stm32f4_clk_data *data; base = of_iomap(np, 0); if (!base) { @@ -542,6 +660,19 @@ static void __init stm32f4_rcc_init(struct device_node *np) pr_warn("%s: Unable to get syscfg\n", __func__); } + match = of_match_node(stm32f4_of_match, np); + if (WARN_ON(!match)) + return; + + data = match->data; + + clks = kmalloc_array(data->gates_num + END_PRIMARY_CLK, + sizeof(*clks), GFP_KERNEL); + if (!clks) + goto fail; + + stm32f4_gate_map = data->gates_map; + hse_clk = of_clk_get_parent_name(np, 0); clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0, @@ -574,11 +705,15 @@ static void __init stm32f4_rcc_init(struct device_node *np) clks[FCLK] = clk_hw_register_fixed_factor(NULL, "fclk", "ahb_div", 0, 1, 1); - for (n = 0; n < ARRAY_SIZE(stm32f4_gates); n++) { - const struct stm32f4_gate_data *gd = &stm32f4_gates[n]; - unsigned int secondary = - 8 * (gd->offset - STM32F4_RCC_AHB1ENR) + gd->bit_idx; - int idx = stm32f4_rcc_lookup_clk_idx(0, secondary); + for (n = 0; n < data->gates_num; n++) { + const struct stm32f4_gate_data *gd; + unsigned int secondary; + int idx; + + gd = &data->gates_data[n]; + secondary = 8 * (gd->offset - STM32F4_RCC_AHB1ENR) + + gd->bit_idx; + idx = stm32f4_rcc_lookup_clk_idx(0, secondary); if (idx < 0) goto fail; @@ -630,6 +765,8 @@ static void __init stm32f4_rcc_init(struct device_node *np) of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL); return; fail: + kfree(clks); iounmap(base); } -CLK_OF_DECLARE(stm32f4_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); -- cgit v1.2.3 From 362922a1a5345d17a9d4ad7e3f848aa4fdf79d75 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 1 Sep 2015 16:30:12 +0200 Subject: reset: Add renesas,rst DT bindings Add DT bindings for the Renesas R-Car Reset Controller (R-Car Gen1 RESET/WDT and R-Car Gen2/Gen3 and RZ/G RST). As the features provided by the hardware module differ a lot across the various SoC families and members, only SoC-specific compatible values are defined. For now we use the RST only for providing access to the state of the mode pins, which is needed by the clock driver. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Acked-by: Dirk Behme Acked-by: Laurent Pinchart Acked-by: Philipp Zabel Acked-by: Rob Herring --- .../devicetree/bindings/reset/renesas,rst.txt | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/renesas,rst.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/reset/renesas,rst.txt b/Documentation/devicetree/bindings/reset/renesas,rst.txt new file mode 100644 index 000000000000..fe5e0f37b3c9 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/renesas,rst.txt @@ -0,0 +1,37 @@ +DT bindings for the Renesas R-Car and RZ/G Reset Controllers + +The R-Car and RZ/G Reset Controllers provide reset control, and implement the +following functions: + - Latching of the levels on mode pins when PRESET# is negated, + - Mode monitoring register, + - Reset control of peripheral devices (on R-Car Gen1), + - Watchdog timer (on R-Car Gen1), + - Register-based reset control and boot address registers for the various CPU + cores (on R-Car Gen2 and Gen3, and on RZ/G). + + +Required properties: + - compatible: Should be + - "renesas,-reset-wdt" for R-Car Gen1, + - "renesas,-rst" for R-Car Gen2 and Gen3, and RZ/G + Examples with soctypes are: + - "renesas,r8a7743-rst" (RZ/G1M) + - "renesas,r8a7745-rst" (RZ/G1E) + - "renesas,r8a7778-reset-wdt" (R-Car M1A) + - "renesas,r8a7779-reset-wdt" (R-Car H1) + - "renesas,r8a7790-rst" (R-Car H2) + - "renesas,r8a7791-rst" (R-Car M2-W) + - "renesas,r8a7792-rst" (R-Car V2H + - "renesas,r8a7793-rst" (R-Car M2-N) + - "renesas,r8a7794-rst" (R-Car E2) + - "renesas,r8a7795-rst" (R-Car H3) + - "renesas,r8a7796-rst" (R-Car M3-W) + - reg: Address start and address range for the device. + + +Example: + + rst: reset-controller@e6160000 { + compatible = "renesas,r8a7795-rst"; + reg = <0 0xe6160000 0 0x0200>; + }; -- cgit v1.2.3 From c6a0637460c29799f1e63a6a4a65bda22caf4a54 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 6 Jul 2016 08:31:34 +0200 Subject: clk: sunxi-ng: Add A64 clocks Add the A64 CCU clocks set. Acked-by: Rob Herring Acked-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- .../devicetree/bindings/clock/sunxi-ccu.txt | 1 + drivers/clk/sunxi-ng/Kconfig | 11 + drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 915 +++++++++++++++++++++ drivers/clk/sunxi-ng/ccu-sun50i-a64.h | 72 ++ include/dt-bindings/clock/sun50i-a64-ccu.h | 134 +++ include/dt-bindings/reset/sun50i-a64-ccu.h | 98 +++ 7 files changed, 1232 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a64.c create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a64.h create mode 100644 include/dt-bindings/clock/sun50i-a64-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-a64-ccu.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt index 3868458a5feb..74d44a4273f2 100644 --- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt +++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt @@ -7,6 +7,7 @@ Required properties : - "allwinner,sun8i-a23-ccu" - "allwinner,sun8i-a33-ccu" - "allwinner,sun8i-h3-ccu" + - "allwinner,sun50i-a64-ccu" - reg: Must contain the registers base address and length - clocks: phandle to the oscillators feeding the CCU. Two are needed: diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 1b4c55a53d7a..8454c6e3dd65 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -53,6 +53,17 @@ config SUNXI_CCU_MP # SoC Drivers +config SUN50I_A64_CCU + bool "Support for the Allwinner A64 CCU" + select SUNXI_CCU_DIV + select SUNXI_CCU_NK + select SUNXI_CCU_NKM + select SUNXI_CCU_NKMP + select SUNXI_CCU_NM + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default ARM64 && ARCH_SUNXI + config SUN6I_A31_CCU bool "Support for the Allwinner A31/A31s CCU" select SUNXI_CCU_DIV diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 106cba27c331..24fbc6e5deb8 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SUNXI_CCU_NM) += ccu_nm.o obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o # SoC support +obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c new file mode 100644 index 000000000000..0674515e2bad --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -0,0 +1,915 @@ +/* + * Copyright (c) 2016 Maxime Ripard. All rights reserved. + * + * 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 +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_phase.h" + +#include "ccu-sun50i-a64.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT(4, 2), + .m = _SUNXI_CCU_DIV(0, 2), + .p = _SUNXI_CCU_DIV_MAX(16, 2, 4), + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", + "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from + * the base (2x, 4x and 8x), and one variable divider (the one true + * pll audio). + * + * We don't have any need for the variable divider for now, so we just + * hardcode it to match with the clock names + */ +#define SUN50I_A64_PLL_AUDIO_REG 0x008 + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", + "osc24M", 0x010, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", + "osc24M", 0x018, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr0_clk, "pll-ddr0", + "osc24M", 0x020, + 8, 5, /* N */ + 4, 2, /* K */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static struct ccu_nk pll_periph0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), + .fixed_post_div = 2, + .common = { + .reg = 0x028, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", + &ccu_nk_ops, CLK_SET_RATE_UNGATE), + }, +}; + +static struct ccu_nk pll_periph1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), + .fixed_post_div = 2, + .common = { + .reg = 0x02c, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", + &ccu_nk_ops, CLK_SET_RATE_UNGATE), + }, +}; + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", + "osc24M", 0x030, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", + "osc24M", 0x038, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +/* + * The output function can be changed to something more complex that + * we do not handle yet. + * + * Hardcode the mode so that we don't fall in that case. + */ +#define SUN50I_A64_PLL_MIPI_REG 0x040 + +struct ccu_nkm pll_mipi_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 4), + .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), + .m = _SUNXI_CCU_DIV(0, 4), + .common = { + .reg = 0x040, + .hw.init = CLK_HW_INIT("pll-mipi", "pll-video0", + &ccu_nkm_ops, CLK_SET_RATE_UNGATE), + }, +}; + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_hsic_clk, "pll-hsic", + "osc24M", 0x044, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", + "osc24M", 0x048, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", + "osc24M", 0x04c, + 8, 7, /* N */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static const char * const cpux_parents[] = { "osc32k", "osc24M", + "pll-cpux" , "pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x050, 16, 2, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0); + +static const char * const ahb1_parents[] = { "osc32k", "osc24M", + "axi" , "pll-periph0" }; +static struct ccu_div ahb1_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 12, + .width = 2, + + .variable_prediv = { + .index = 3, + .shift = 6, + .width = 2, + }, + }, + + .common = { + .reg = 0x054, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb1", + ahb1_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct clk_div_table apb1_div_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { /* Sentinel */ }, +}; +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char * const apb2_parents[] = { "osc32k", "osc24M", + "pll-periph0-2x" , + "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const char * const ahb2_parents[] = { "ahb1" , "pll-periph0" }; +static const struct ccu_mux_fixed_prediv ahb2_fixed_predivs[] = { + { .index = 1, .div = 2 }, +}; +static struct ccu_mux ahb2_clk = { + .mux = { + .shift = 0, + .width = 1, + .fixed_predivs = ahb2_fixed_predivs, + .n_predivs = ARRAY_SIZE(ahb2_fixed_predivs), + }, + + .common = { + .reg = 0x05c, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb2", + ahb2_parents, + &ccu_mux_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb1", + 0x060, BIT(1), 0); +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "ahb1", + 0x060, BIT(5), 0); +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2", + 0x060, BIT(17), 0); +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb1", + 0x060, BIT(18), 0); +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1", + 0x060, BIT(20), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1", + 0x060, BIT(23), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb1", + 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2", + 0x060, BIT(25), 0); +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb1", + 0x060, BIT(28), 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb2", + 0x060, BIT(29), 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1", + 0x064, BIT(3), 0); +static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "ahb1", + 0x064, BIT(5), 0); +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1", + 0x064, BIT(11), 0); +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1", + 0x064, BIT(21), 0); +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1", + 0x064, BIT(22), 0); + +static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", + 0x068, BIT(1), 0); +static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", + 0x068, BIT(8), 0); +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", + 0x068, BIT(13), 0); +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", + 0x068, BIT(14), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_scr_clk, "bus-scr", "apb2", + 0x06c, BIT(5), 0); +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", + 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", + 0x06c, BIT(20), 0); + +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "ahb1", + 0x070, BIT(7), 0); + +static struct clk_div_table ths_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, +}; +static const char * const ths_parents[] = { "osc24M" }; +static struct ccu_div ths_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_TABLE(0, 2, ths_div_table), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0x074, + .hw.init = CLK_HW_INIT_PARENTS("ths", + ths_parents, + &ccu_div_ops, + 0), + }, +}; + +static const char * const mod0_default_parents[] = { "osc24M", "pll-periph0", + "pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_default_parents, 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const ts_parents[] = { "osc24M", "pll-periph0", }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 4, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", mmc_default_parents, 0x09c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x", + "pll-audio-2x", "pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents, + 0x0b0, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents, + 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s_parents, + 0x0b8, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", + 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_hsic_12m_clk, "usb-hsic-12M", "osc12M", + 0x0cc, BIT(11), 0); +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", + 0x0cc, BIT(16), 0); +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "usb-ohci0", + 0x0cc, BIT(17), 0); + +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents, + 0x0f4, 0, 4, 20, 2, CLK_IS_CRITICAL); + +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram", + 0x100, BIT(2), 0); +static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram", + 0x100, BIT(3), 0); + +static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, + 0x104, 0, 4, 24, 3, BIT(31), 0); + +static const char * const tcon0_parents[] = { "pll-mipi", "pll-video0-2x" }; +static const u8 tcon0_table[] = { 0, 2, }; +static SUNXI_CCU_MUX_TABLE_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, + tcon0_table, 0x118, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); + +static const char * const tcon1_parents[] = { "pll-video0", "pll-video1" }; +static const u8 tcon1_table[] = { 0, 2, }; +struct ccu_div tcon1_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV(0, 4), + .mux = _SUNXI_CCU_MUX_TABLE(24, 2, tcon1_table), + .common = { + .reg = 0x11c, + .hw.init = CLK_HW_INIT_PARENTS("tcon1", + tcon1_parents, + &ccu_div_ops, + CLK_SET_RATE_PARENT), + }, +}; + +static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents, + 0x124, 0, 4, 24, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", + 0x130, BIT(31), 0); + +static const char * const csi_sclk_parents[] = { "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_sclk_clk, "csi-sclk", csi_sclk_parents, + 0x134, 16, 4, 24, 3, BIT(31), 0); + +static const char * const csi_mclk_parents[] = { "osc24M", "pll-video1", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, + 0x134, 0, 5, 8, 3, BIT(15), 0); + +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", + 0x140, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(ac_dig_4x_clk, "ac-dig-4x", "pll-audio-4x", + 0x140, BIT(30), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); + +static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, + 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", + 0x154, BIT(31), 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", + "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, + 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); + +static const char * const dsi_dphy_parents[] = { "pll-video0", "pll-periph0" }; +static const u8 dsi_dphy_table[] = { 0, 2, }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_dphy_clk, "dsi-dphy", + dsi_dphy_parents, dsi_dphy_table, + 0x168, 0, 4, 8, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", + 0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT); + +/* Fixed Factor clocks */ +static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 1, 2, 0); + +/* We hardcode the divider to 4 for now */ +static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", + "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x", + "pll-periph1", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x", + "pll-video0", 1, 2, CLK_SET_RATE_PARENT); + +static struct ccu_common *sun50i_a64_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_audio_base_clk.common, + &pll_video0_clk.common, + &pll_ve_clk.common, + &pll_ddr0_clk.common, + &pll_periph0_clk.common, + &pll_periph1_clk.common, + &pll_video1_clk.common, + &pll_gpu_clk.common, + &pll_mipi_clk.common, + &pll_hsic_clk.common, + &pll_de_clk.common, + &pll_ddr1_clk.common, + &cpux_clk.common, + &axi_clk.common, + &ahb1_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &ahb2_clk.common, + &bus_mipi_dsi_clk.common, + &bus_ce_clk.common, + &bus_dma_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_nand_clk.common, + &bus_dram_clk.common, + &bus_emac_clk.common, + &bus_ts_clk.common, + &bus_hstimer_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_otg_clk.common, + &bus_ehci0_clk.common, + &bus_ehci1_clk.common, + &bus_ohci0_clk.common, + &bus_ohci1_clk.common, + &bus_ve_clk.common, + &bus_tcon0_clk.common, + &bus_tcon1_clk.common, + &bus_deinterlace_clk.common, + &bus_csi_clk.common, + &bus_hdmi_clk.common, + &bus_de_clk.common, + &bus_gpu_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_codec_clk.common, + &bus_spdif_clk.common, + &bus_pio_clk.common, + &bus_ths_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_scr_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_uart4_clk.common, + &bus_dbg_clk.common, + &ths_clk.common, + &nand_clk.common, + &mmc0_clk.common, + &mmc1_clk.common, + &mmc2_clk.common, + &ts_clk.common, + &ce_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &spdif_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_hsic_clk.common, + &usb_hsic_12m_clk.common, + &usb_ohci0_clk.common, + &usb_ohci1_clk.common, + &dram_clk.common, + &dram_ve_clk.common, + &dram_csi_clk.common, + &dram_deinterlace_clk.common, + &dram_ts_clk.common, + &de_clk.common, + &tcon0_clk.common, + &tcon1_clk.common, + &deinterlace_clk.common, + &csi_misc_clk.common, + &csi_sclk_clk.common, + &csi_mclk_clk.common, + &ve_clk.common, + &ac_dig_clk.common, + &ac_dig_4x_clk.common, + &avs_clk.common, + &hdmi_clk.common, + &hdmi_ddc_clk.common, + &mbus_clk.common, + &dsi_dphy_clk.common, + &gpu_clk.common, +}; + +static struct clk_hw_onecell_data sun50i_a64_hw_clks = { + .hws = { + [CLK_OSC_12M] = &osc12M_clk.hw, + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, + [CLK_PLL_VIDEO0_2X] = &pll_video0_2x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_MIPI] = &pll_mipi_clk.common.hw, + [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_AHB1] = &ahb1_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_AHB2] = &ahb2_clk.common.hw, + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw, + [CLK_BUS_CE] = &bus_ce_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw, + [CLK_BUS_TS] = &bus_ts_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_TCON0] = &bus_tcon0_clk.common.hw, + [CLK_BUS_TCON1] = &bus_tcon1_clk.common.hw, + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_CODEC] = &bus_codec_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_BUS_PIO] = &bus_pio_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_UART4] = &bus_uart4_clk.common.hw, + [CLK_BUS_SCR] = &bus_scr_clk.common.hw, + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, + [CLK_THS] = &ths_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_TS] = &ts_clk.common.hw, + [CLK_CE] = &ce_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_I2S2] = &i2s2_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_HSIC] = &usb_hsic_clk.common.hw, + [CLK_USB_HSIC_12M] = &usb_hsic_12m_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_DRAM] = &dram_clk.common.hw, + [CLK_DRAM_VE] = &dram_ve_clk.common.hw, + [CLK_DRAM_CSI] = &dram_csi_clk.common.hw, + [CLK_DRAM_DEINTERLACE] = &dram_deinterlace_clk.common.hw, + [CLK_DRAM_TS] = &dram_ts_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_TCON0] = &tcon0_clk.common.hw, + [CLK_TCON1] = &tcon1_clk.common.hw, + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, + [CLK_CSI_MISC] = &csi_misc_clk.common.hw, + [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_AC_DIG] = &ac_dig_clk.common.hw, + [CLK_AC_DIG_4X] = &ac_dig_4x_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_DDC] = &hdmi_ddc_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DSI_DPHY] = &dsi_dphy_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun50i_a64_ccu_resets[] = { + [RST_USB_PHY0] = { 0x0cc, BIT(0) }, + [RST_USB_PHY1] = { 0x0cc, BIT(1) }, + [RST_USB_HSIC] = { 0x0cc, BIT(2) }, + + [RST_DRAM] = { 0x0f4, BIT(31) }, + [RST_MBUS] = { 0x0fc, BIT(31) }, + + [RST_BUS_MIPI_DSI] = { 0x2c0, BIT(1) }, + [RST_BUS_CE] = { 0x2c0, BIT(5) }, + [RST_BUS_DMA] = { 0x2c0, BIT(6) }, + [RST_BUS_MMC0] = { 0x2c0, BIT(8) }, + [RST_BUS_MMC1] = { 0x2c0, BIT(9) }, + [RST_BUS_MMC2] = { 0x2c0, BIT(10) }, + [RST_BUS_NAND] = { 0x2c0, BIT(13) }, + [RST_BUS_DRAM] = { 0x2c0, BIT(14) }, + [RST_BUS_EMAC] = { 0x2c0, BIT(17) }, + [RST_BUS_TS] = { 0x2c0, BIT(18) }, + [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) }, + [RST_BUS_SPI0] = { 0x2c0, BIT(20) }, + [RST_BUS_SPI1] = { 0x2c0, BIT(21) }, + [RST_BUS_OTG] = { 0x2c0, BIT(23) }, + [RST_BUS_EHCI0] = { 0x2c0, BIT(24) }, + [RST_BUS_EHCI1] = { 0x2c0, BIT(25) }, + [RST_BUS_OHCI0] = { 0x2c0, BIT(28) }, + [RST_BUS_OHCI1] = { 0x2c0, BIT(29) }, + + [RST_BUS_VE] = { 0x2c4, BIT(0) }, + [RST_BUS_TCON0] = { 0x2c4, BIT(3) }, + [RST_BUS_TCON1] = { 0x2c4, BIT(4) }, + [RST_BUS_DEINTERLACE] = { 0x2c4, BIT(5) }, + [RST_BUS_CSI] = { 0x2c4, BIT(8) }, + [RST_BUS_HDMI0] = { 0x2c4, BIT(10) }, + [RST_BUS_HDMI1] = { 0x2c4, BIT(11) }, + [RST_BUS_DE] = { 0x2c4, BIT(12) }, + [RST_BUS_GPU] = { 0x2c4, BIT(20) }, + [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) }, + [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) }, + [RST_BUS_DBG] = { 0x2c4, BIT(31) }, + + [RST_BUS_LVDS] = { 0x2c8, BIT(0) }, + + [RST_BUS_CODEC] = { 0x2d0, BIT(0) }, + [RST_BUS_SPDIF] = { 0x2d0, BIT(1) }, + [RST_BUS_THS] = { 0x2d0, BIT(8) }, + [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, + [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, + [RST_BUS_I2S2] = { 0x2d0, BIT(14) }, + + [RST_BUS_I2C0] = { 0x2d8, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d8, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d8, BIT(2) }, + [RST_BUS_SCR] = { 0x2d8, BIT(5) }, + [RST_BUS_UART0] = { 0x2d8, BIT(16) }, + [RST_BUS_UART1] = { 0x2d8, BIT(17) }, + [RST_BUS_UART2] = { 0x2d8, BIT(18) }, + [RST_BUS_UART3] = { 0x2d8, BIT(19) }, + [RST_BUS_UART4] = { 0x2d8, BIT(20) }, +}; + +static const struct sunxi_ccu_desc sun50i_a64_ccu_desc = { + .ccu_clks = sun50i_a64_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a64_ccu_clks), + + .hw_clks = &sun50i_a64_hw_clks, + + .resets = sun50i_a64_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_a64_ccu_resets), +}; + +static int sun50i_a64_ccu_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *reg; + u32 val; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* Force the PLL-Audio-1x divider to 4 */ + val = readl(reg + SUN50I_A64_PLL_AUDIO_REG); + val &= ~GENMASK(19, 16); + writel(val | (3 << 16), reg + SUN50I_A64_PLL_AUDIO_REG); + + writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); + + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); +} + +static const struct of_device_id sun50i_a64_ccu_ids[] = { + { .compatible = "allwinner,sun50i-a64-ccu" }, + { } +}; + +static struct platform_driver sun50i_a64_ccu_driver = { + .probe = sun50i_a64_ccu_probe, + .driver = { + .name = "sun50i-a64-ccu", + .of_match_table = sun50i_a64_ccu_ids, + }, +}; +builtin_platform_driver(sun50i_a64_ccu_driver); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h new file mode 100644 index 000000000000..9b3cd24b78d2 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h @@ -0,0 +1,72 @@ +/* + * Copyright 2016 Maxime Ripard + * + * Maxime Ripard + * + * 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 _CCU_SUN50I_A64_H_ +#define _CCU_SUN50I_A64_H_ + +#include +#include + +#define CLK_OSC_12M 0 +#define CLK_PLL_CPUX 1 +#define CLK_PLL_AUDIO_BASE 2 +#define CLK_PLL_AUDIO 3 +#define CLK_PLL_AUDIO_2X 4 +#define CLK_PLL_AUDIO_4X 5 +#define CLK_PLL_AUDIO_8X 6 +#define CLK_PLL_VIDEO0 7 +#define CLK_PLL_VIDEO0_2X 8 +#define CLK_PLL_VE 9 +#define CLK_PLL_DDR0 10 +#define CLK_PLL_PERIPH0 11 +#define CLK_PLL_PERIPH0_2X 12 +#define CLK_PLL_PERIPH1 13 +#define CLK_PLL_PERIPH1_2X 14 +#define CLK_PLL_VIDEO1 15 +#define CLK_PLL_GPU 16 +#define CLK_PLL_MIPI 17 +#define CLK_PLL_HSIC 18 +#define CLK_PLL_DE 19 +#define CLK_PLL_DDR1 20 +#define CLK_CPUX 21 +#define CLK_AXI 22 +#define CLK_APB 23 +#define CLK_AHB1 24 +#define CLK_APB1 25 +#define CLK_APB2 26 +#define CLK_AHB2 27 + +/* All the bus gates are exported */ + +/* The first bunch of module clocks are exported */ + +#define CLK_USB_OHCI0_12M 90 + +#define CLK_USB_OHCI1_12M 92 + +#define CLK_DRAM 94 + +/* All the DRAM gates are exported */ + +/* Some more module clocks are exported */ + +#define CLK_MBUS 112 + +/* And the DSI and GPU module clock is exported */ + +#define CLK_NUMBER (CLK_GPU + 1) + +#endif /* _CCU_SUN50I_A64_H_ */ diff --git a/include/dt-bindings/clock/sun50i-a64-ccu.h b/include/dt-bindings/clock/sun50i-a64-ccu.h new file mode 100644 index 000000000000..370c0a0473fc --- /dev/null +++ b/include/dt-bindings/clock/sun50i-a64-ccu.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2016 Maxime Ripard + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_A64_H_ +#define _DT_BINDINGS_CLK_SUN50I_A64_H_ + +#define CLK_BUS_MIPI_DSI 28 +#define CLK_BUS_CE 29 +#define CLK_BUS_DMA 30 +#define CLK_BUS_MMC0 31 +#define CLK_BUS_MMC1 32 +#define CLK_BUS_MMC2 33 +#define CLK_BUS_NAND 34 +#define CLK_BUS_DRAM 35 +#define CLK_BUS_EMAC 36 +#define CLK_BUS_TS 37 +#define CLK_BUS_HSTIMER 38 +#define CLK_BUS_SPI0 39 +#define CLK_BUS_SPI1 40 +#define CLK_BUS_OTG 41 +#define CLK_BUS_EHCI0 42 +#define CLK_BUS_EHCI1 43 +#define CLK_BUS_OHCI0 44 +#define CLK_BUS_OHCI1 45 +#define CLK_BUS_VE 46 +#define CLK_BUS_TCON0 47 +#define CLK_BUS_TCON1 48 +#define CLK_BUS_DEINTERLACE 49 +#define CLK_BUS_CSI 50 +#define CLK_BUS_HDMI 51 +#define CLK_BUS_DE 52 +#define CLK_BUS_GPU 53 +#define CLK_BUS_MSGBOX 54 +#define CLK_BUS_SPINLOCK 55 +#define CLK_BUS_CODEC 56 +#define CLK_BUS_SPDIF 57 +#define CLK_BUS_PIO 58 +#define CLK_BUS_THS 59 +#define CLK_BUS_I2S0 60 +#define CLK_BUS_I2S1 61 +#define CLK_BUS_I2S2 62 +#define CLK_BUS_I2C0 63 +#define CLK_BUS_I2C1 64 +#define CLK_BUS_I2C2 65 +#define CLK_BUS_SCR 66 +#define CLK_BUS_UART0 67 +#define CLK_BUS_UART1 68 +#define CLK_BUS_UART2 69 +#define CLK_BUS_UART3 70 +#define CLK_BUS_UART4 71 +#define CLK_BUS_DBG 72 +#define CLK_THS 73 +#define CLK_NAND 74 +#define CLK_MMC0 75 +#define CLK_MMC1 76 +#define CLK_MMC2 77 +#define CLK_TS 78 +#define CLK_CE 79 +#define CLK_SPI0 80 +#define CLK_SPI1 81 +#define CLK_I2S0 82 +#define CLK_I2S1 83 +#define CLK_I2S2 84 +#define CLK_SPDIF 85 +#define CLK_USB_PHY0 86 +#define CLK_USB_PHY1 87 +#define CLK_USB_HSIC 88 +#define CLK_USB_HSIC_12M 89 + +#define CLK_USB_OHCI0 91 + +#define CLK_USB_OHCI1 93 + +#define CLK_DRAM_VE 95 +#define CLK_DRAM_CSI 96 +#define CLK_DRAM_DEINTERLACE 97 +#define CLK_DRAM_TS 98 +#define CLK_DE 99 +#define CLK_TCON0 100 +#define CLK_TCON1 101 +#define CLK_DEINTERLACE 102 +#define CLK_CSI_MISC 103 +#define CLK_CSI_SCLK 104 +#define CLK_CSI_MCLK 105 +#define CLK_VE 106 +#define CLK_AC_DIG 107 +#define CLK_AC_DIG_4X 108 +#define CLK_AVS 109 +#define CLK_HDMI 110 +#define CLK_HDMI_DDC 111 + +#define CLK_DSI_DPHY 113 +#define CLK_GPU 114 + +#endif /* _DT_BINDINGS_CLK_SUN50I_H_ */ diff --git a/include/dt-bindings/reset/sun50i-a64-ccu.h b/include/dt-bindings/reset/sun50i-a64-ccu.h new file mode 100644 index 000000000000..db60b29ddb11 --- /dev/null +++ b/include/dt-bindings/reset/sun50i-a64-ccu.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016 Maxime Ripard + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DT_BINDINGS_RST_SUN50I_A64_H_ +#define _DT_BINDINGS_RST_SUN50I_A64_H_ + +#define RST_USB_PHY0 0 +#define RST_USB_PHY1 1 +#define RST_USB_HSIC 2 +#define RST_DRAM 3 +#define RST_MBUS 4 +#define RST_BUS_MIPI_DSI 5 +#define RST_BUS_CE 6 +#define RST_BUS_DMA 7 +#define RST_BUS_MMC0 8 +#define RST_BUS_MMC1 9 +#define RST_BUS_MMC2 10 +#define RST_BUS_NAND 11 +#define RST_BUS_DRAM 12 +#define RST_BUS_EMAC 13 +#define RST_BUS_TS 14 +#define RST_BUS_HSTIMER 15 +#define RST_BUS_SPI0 16 +#define RST_BUS_SPI1 17 +#define RST_BUS_OTG 18 +#define RST_BUS_EHCI0 19 +#define RST_BUS_EHCI1 20 +#define RST_BUS_OHCI0 21 +#define RST_BUS_OHCI1 22 +#define RST_BUS_VE 23 +#define RST_BUS_TCON0 24 +#define RST_BUS_TCON1 25 +#define RST_BUS_DEINTERLACE 26 +#define RST_BUS_CSI 27 +#define RST_BUS_HDMI0 28 +#define RST_BUS_HDMI1 29 +#define RST_BUS_DE 30 +#define RST_BUS_GPU 31 +#define RST_BUS_MSGBOX 32 +#define RST_BUS_SPINLOCK 33 +#define RST_BUS_DBG 34 +#define RST_BUS_LVDS 35 +#define RST_BUS_CODEC 36 +#define RST_BUS_SPDIF 37 +#define RST_BUS_THS 38 +#define RST_BUS_I2S0 39 +#define RST_BUS_I2S1 40 +#define RST_BUS_I2S2 41 +#define RST_BUS_I2C0 42 +#define RST_BUS_I2C1 43 +#define RST_BUS_I2C2 44 +#define RST_BUS_SCR 45 +#define RST_BUS_UART0 46 +#define RST_BUS_UART1 47 +#define RST_BUS_UART2 48 +#define RST_BUS_UART3 49 +#define RST_BUS_UART4 50 + +#endif /* _DT_BINDINGS_RST_SUN50I_A64_H_ */ -- cgit v1.2.3 From c0b2d75d2a4bf6a3f29d13c4bfa2557dfa22828d Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 9 Nov 2016 00:21:50 +0300 Subject: clk: renesas: cpg-mssr: Add R8A7743 support Add RZ/G1M (R8A7743) Clock Pulse Generator / Module Standby and Software Reset support, using the CPG/MSSR driver core and the common R-Car Gen2 (and RZ/G) code. Based on the proof-of-concept R8A7791 CPG/MSSR patch by Geert Uytterhoeven . Signed-off-by: Sergei Shtylyov Acked-by: Rob Herring Signed-off-by: Geert Uytterhoeven --- .../devicetree/bindings/clock/renesas,cpg-mssr.txt | 4 +- drivers/clk/renesas/Kconfig | 1 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r8a7743-cpg-mssr.c | 270 +++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.c | 6 + drivers/clk/renesas/renesas-cpg-mssr.h | 1 + 6 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/renesas/r8a7743-cpg-mssr.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt index 394d725ac7e0..c0c4d77898ea 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt @@ -13,6 +13,7 @@ They provide the following functionalities: Required Properties: - compatible: Must be one of: + - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3) - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W) @@ -22,8 +23,9 @@ Required Properties: - clocks: References to external parent clocks, one entry for each entry in clock-names - clock-names: List of external parent clock names. Valid names are: - - "extal" (r8a7795, r8a7796) + - "extal" (r8a7743, r8a7795, r8a7796) - "extalr" (r8a7795, r8a7796) + - "usb_extal" (r8a7743) - #clock-cells: Must be 2 - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 41a12d376799..e1cd3bfb6f97 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -1,5 +1,6 @@ config CLK_RENESAS_CPG_MSSR bool + default y if ARCH_R8A7743 default y if ARCH_R8A7795 default y if ARCH_R8A7796 diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 90dd0db7d9c6..81082bd79430 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-div6.o obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-div6.o +obj-$(CONFIG_ARCH_R8A7743) += r8a7743-cpg-mssr.o rcar-gen2-cpg.o obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-div6.o diff --git a/drivers/clk/renesas/r8a7743-cpg-mssr.c b/drivers/clk/renesas/r8a7743-cpg-mssr.c new file mode 100644 index 000000000000..6dc0b3082aa6 --- /dev/null +++ b/drivers/clk/renesas/r8a7743-cpg-mssr.c @@ -0,0 +1,270 @@ +/* + * r8a7743 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2016 Cogent Embedded Inc. + * + * 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; of the License. + */ + +#include +#include +#include +#include + +#include + +#include "renesas-cpg-mssr.h" +#include "rcar-gen2-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A7743_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_USB_EXTAL, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL3, + CLK_PLL1_DIV2, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a7743_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("usb_extal", CLK_USB_EXTAL), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN2_MAIN, CLK_EXTAL), + DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN2_PLL0, CLK_MAIN), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN2_PLL1, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN2_PLL3, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + + /* Core Clock Outputs */ + DEF_BASE("z", R8A7743_CLK_Z, CLK_TYPE_GEN2_Z, CLK_PLL0), + DEF_BASE("lb", R8A7743_CLK_LB, CLK_TYPE_GEN2_LB, CLK_PLL1), + DEF_BASE("sdh", R8A7743_CLK_SDH, CLK_TYPE_GEN2_SDH, CLK_PLL1), + DEF_BASE("sd0", R8A7743_CLK_SD0, CLK_TYPE_GEN2_SD0, CLK_PLL1), + DEF_BASE("qspi", R8A7743_CLK_QSPI, CLK_TYPE_GEN2_QSPI, CLK_PLL1_DIV2), + DEF_BASE("rcan", R8A7743_CLK_RCAN, CLK_TYPE_GEN2_RCAN, CLK_USB_EXTAL), + + DEF_FIXED("zg", R8A7743_CLK_ZG, CLK_PLL1, 3, 1), + DEF_FIXED("zx", R8A7743_CLK_ZX, CLK_PLL1, 3, 1), + DEF_FIXED("zs", R8A7743_CLK_ZS, CLK_PLL1, 6, 1), + DEF_FIXED("hp", R8A7743_CLK_HP, CLK_PLL1, 12, 1), + DEF_FIXED("b", R8A7743_CLK_B, CLK_PLL1, 12, 1), + DEF_FIXED("p", R8A7743_CLK_P, CLK_PLL1, 24, 1), + DEF_FIXED("cl", R8A7743_CLK_CL, CLK_PLL1, 48, 1), + DEF_FIXED("m2", R8A7743_CLK_M2, CLK_PLL1, 8, 1), + DEF_FIXED("zb3", R8A7743_CLK_ZB3, CLK_PLL3, 4, 1), + DEF_FIXED("zb3d2", R8A7743_CLK_ZB3D2, CLK_PLL3, 8, 1), + DEF_FIXED("ddr", R8A7743_CLK_DDR, CLK_PLL3, 8, 1), + DEF_FIXED("mp", R8A7743_CLK_MP, CLK_PLL1_DIV2, 15, 1), + DEF_FIXED("cp", R8A7743_CLK_CP, CLK_EXTAL, 2, 1), + DEF_FIXED("r", R8A7743_CLK_R, CLK_PLL1, 49152, 1), + DEF_FIXED("osc", R8A7743_CLK_OSC, CLK_PLL1, 12288, 1), + + DEF_DIV6P1("sd2", R8A7743_CLK_SD2, CLK_PLL1_DIV2, 0x078), + DEF_DIV6P1("sd3", R8A7743_CLK_SD3, CLK_PLL1_DIV2, 0x26c), + DEF_DIV6P1("mmc0", R8A7743_CLK_MMC0, CLK_PLL1_DIV2, 0x240), +}; + +static const struct mssr_mod_clk r8a7743_mod_clks[] __initconst = { + DEF_MOD("msiof0", 0, R8A7743_CLK_MP), + DEF_MOD("vcp0", 101, R8A7743_CLK_ZS), + DEF_MOD("vpc0", 103, R8A7743_CLK_ZS), + DEF_MOD("tmu1", 111, R8A7743_CLK_P), + DEF_MOD("3dg", 112, R8A7743_CLK_ZG), + DEF_MOD("2d-dmac", 115, R8A7743_CLK_ZS), + DEF_MOD("fdp1-1", 118, R8A7743_CLK_ZS), + DEF_MOD("fdp1-0", 119, R8A7743_CLK_ZS), + DEF_MOD("tmu3", 121, R8A7743_CLK_P), + DEF_MOD("tmu2", 122, R8A7743_CLK_P), + DEF_MOD("cmt0", 124, R8A7743_CLK_R), + DEF_MOD("tmu0", 125, R8A7743_CLK_CP), + DEF_MOD("vsp1du1", 127, R8A7743_CLK_ZS), + DEF_MOD("vsp1du0", 128, R8A7743_CLK_ZS), + DEF_MOD("vsp1-sy", 131, R8A7743_CLK_ZS), + DEF_MOD("scifa2", 202, R8A7743_CLK_MP), + DEF_MOD("scifa1", 203, R8A7743_CLK_MP), + DEF_MOD("scifa0", 204, R8A7743_CLK_MP), + DEF_MOD("msiof2", 205, R8A7743_CLK_MP), + DEF_MOD("scifb0", 206, R8A7743_CLK_MP), + DEF_MOD("scifb1", 207, R8A7743_CLK_MP), + DEF_MOD("msiof1", 208, R8A7743_CLK_MP), + DEF_MOD("scifb2", 216, R8A7743_CLK_MP), + DEF_MOD("sys-dmac1", 218, R8A7743_CLK_ZS), + DEF_MOD("sys-dmac0", 219, R8A7743_CLK_ZS), + DEF_MOD("tpu0", 304, R8A7743_CLK_CP), + DEF_MOD("sdhi3", 311, R8A7743_CLK_SD3), + DEF_MOD("sdhi2", 312, R8A7743_CLK_SD2), + DEF_MOD("sdhi0", 314, R8A7743_CLK_SD0), + DEF_MOD("mmcif0", 315, R8A7743_CLK_MMC0), + DEF_MOD("iic0", 318, R8A7743_CLK_HP), + DEF_MOD("pciec", 319, R8A7743_CLK_MP), + DEF_MOD("iic1", 323, R8A7743_CLK_HP), + DEF_MOD("usb3.0", 328, R8A7743_CLK_MP), + DEF_MOD("cmt1", 329, R8A7743_CLK_R), + DEF_MOD("usbhs-dmac0", 330, R8A7743_CLK_HP), + DEF_MOD("usbhs-dmac1", 331, R8A7743_CLK_HP), + DEF_MOD("irqc", 407, R8A7743_CLK_CP), + DEF_MOD("intc-sys", 408, R8A7743_CLK_ZS), + DEF_MOD("audio-dmac1", 501, R8A7743_CLK_HP), + DEF_MOD("audio-dmac0", 502, R8A7743_CLK_HP), + DEF_MOD("thermal", 522, CLK_EXTAL), + DEF_MOD("pwm", 523, R8A7743_CLK_P), + DEF_MOD("usb-ehci", 703, R8A7743_CLK_MP), + DEF_MOD("usbhs", 704, R8A7743_CLK_HP), + DEF_MOD("hscif2", 713, R8A7743_CLK_ZS), + DEF_MOD("scif5", 714, R8A7743_CLK_P), + DEF_MOD("scif4", 715, R8A7743_CLK_P), + DEF_MOD("hscif1", 716, R8A7743_CLK_ZS), + DEF_MOD("hscif0", 717, R8A7743_CLK_ZS), + DEF_MOD("scif3", 718, R8A7743_CLK_P), + DEF_MOD("scif2", 719, R8A7743_CLK_P), + DEF_MOD("scif1", 720, R8A7743_CLK_P), + DEF_MOD("scif0", 721, R8A7743_CLK_P), + DEF_MOD("du1", 723, R8A7743_CLK_ZX), + DEF_MOD("du0", 724, R8A7743_CLK_ZX), + DEF_MOD("lvds0", 726, R8A7743_CLK_ZX), + DEF_MOD("ipmmu-sgx", 800, R8A7743_CLK_ZX), + DEF_MOD("vin2", 809, R8A7743_CLK_ZG), + DEF_MOD("vin1", 810, R8A7743_CLK_ZG), + DEF_MOD("vin0", 811, R8A7743_CLK_ZG), + DEF_MOD("etheravb", 812, R8A7743_CLK_HP), + DEF_MOD("ether", 813, R8A7743_CLK_P), + DEF_MOD("sata1", 814, R8A7743_CLK_ZS), + DEF_MOD("sata0", 815, R8A7743_CLK_ZS), + DEF_MOD("gpio7", 904, R8A7743_CLK_CP), + DEF_MOD("gpio6", 905, R8A7743_CLK_CP), + DEF_MOD("gpio5", 907, R8A7743_CLK_CP), + DEF_MOD("gpio4", 908, R8A7743_CLK_CP), + DEF_MOD("gpio3", 909, R8A7743_CLK_CP), + DEF_MOD("gpio2", 910, R8A7743_CLK_CP), + DEF_MOD("gpio1", 911, R8A7743_CLK_CP), + DEF_MOD("gpio0", 912, R8A7743_CLK_CP), + DEF_MOD("can1", 915, R8A7743_CLK_P), + DEF_MOD("can0", 916, R8A7743_CLK_P), + DEF_MOD("qspi_mod", 917, R8A7743_CLK_QSPI), + DEF_MOD("i2c5", 925, R8A7743_CLK_HP), + DEF_MOD("iicdvfs", 926, R8A7743_CLK_CP), + DEF_MOD("i2c4", 927, R8A7743_CLK_HP), + DEF_MOD("i2c3", 928, R8A7743_CLK_HP), + DEF_MOD("i2c2", 929, R8A7743_CLK_HP), + DEF_MOD("i2c1", 930, R8A7743_CLK_HP), + DEF_MOD("i2c0", 931, R8A7743_CLK_HP), + DEF_MOD("ssi-all", 1005, R8A7743_CLK_P), + DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)), + DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)), + DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)), + DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)), + DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)), + DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)), + DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)), + DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)), + DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)), + DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)), + DEF_MOD("scu-all", 1017, R8A7743_CLK_P), + DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)), + DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)), + DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)), + DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)), + DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)), + DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)), + DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)), + DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)), + DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)), + DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)), + DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)), + DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)), + DEF_MOD("scifa3", 1106, R8A7743_CLK_MP), + DEF_MOD("scifa4", 1107, R8A7743_CLK_MP), + DEF_MOD("scifa5", 1108, R8A7743_CLK_MP), +}; + +static const unsigned int r8a7743_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-SYS (GIC) */ +}; + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL3 + * 14 13 19 (MHz) *1 *1 + *--------------------------------------------------- + * 0 0 0 15 x172/2 x208/2 x106 + * 0 0 1 15 x172/2 x208/2 x88 + * 0 1 0 20 x130/2 x156/2 x80 + * 0 1 1 20 x130/2 x156/2 x66 + * 1 0 0 26 / 2 x200/2 x240/2 x122 + * 1 0 1 26 / 2 x200/2 x240/2 x102 + * 1 1 0 30 / 2 x172/2 x208/2 x106 + * 1 1 1 30 / 2 x172/2 x208/2 x88 + * + * *1 : Table 7.5a indicates VCO output (PLLx = VCO/2) + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ + (((md) & BIT(13)) >> 12) | \ + (((md) & BIT(19)) >> 19)) + +static const struct rcar_gen2_cpg_pll_config cpg_pll_configs[8] __initconst = { + /* EXTAL div PLL1 mult PLL3 mult */ + { 1, 208, 106, }, + { 1, 208, 88, }, + { 1, 156, 80, }, + { 1, 156, 66, }, + { 2, 240, 122, }, + { 2, 240, 102, }, + { 2, 208, 106, }, + { 2, 208, 88, }, +}; + +static int __init r8a7743_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen2_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + return rcar_gen2_cpg_init(cpg_pll_config, 2, cpg_mode); +} + +const struct cpg_mssr_info r8a7743_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a7743_core_clks, + .num_core_clks = ARRAY_SIZE(r8a7743_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a7743_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a7743_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a7743_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a7743_crit_mod_clks), + + /* Callbacks */ + .init = r8a7743_cpg_mssr_init, + .cpg_clk_register = rcar_gen2_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index bdd46fb08d38..e87504c68391 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -502,6 +502,12 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, } static const struct of_device_id cpg_mssr_match[] = { +#ifdef CONFIG_ARCH_R8A7743 + { + .compatible = "renesas,r8a7743-cpg-mssr", + .data = &r8a7743_cpg_mssr_info, + }, +#endif #ifdef CONFIG_ARCH_R8A7795 { .compatible = "renesas,r8a7795-cpg-mssr", diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index ee7edfaf1408..7a50639fd43b 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -130,6 +130,7 @@ struct cpg_mssr_info { struct clk **clks, void __iomem *base); }; +extern const struct cpg_mssr_info r8a7743_cpg_mssr_info; extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; extern const struct cpg_mssr_info r8a7796_cpg_mssr_info; #endif -- cgit v1.2.3 From 9127d54bb89471592b3c8af6c6273c21db6de6a6 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 9 Nov 2016 00:25:08 +0300 Subject: clk: renesas: cpg-mssr: Add R8A7745 support Add RZ/G1E (R8A7745) Clock Pulse Generator / Module Standby and Software Reset support, using the CPG/MSSR driver core and the common R-Car Gen2 (and RZ/G) code. Based on the proof-of-concept R8A7791 CPG/MSSR patch by Geert Uytterhoeven . Signed-off-by: Sergei Shtylyov Acked-by: Rob Herring Signed-off-by: Geert Uytterhoeven --- .../devicetree/bindings/clock/renesas,cpg-mssr.txt | 5 +- drivers/clk/renesas/Kconfig | 1 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r8a7745-cpg-mssr.c | 259 +++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.c | 6 + drivers/clk/renesas/renesas-cpg-mssr.h | 1 + 6 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/renesas/r8a7745-cpg-mssr.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt index c0c4d77898ea..c46919412953 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt @@ -14,6 +14,7 @@ They provide the following functionalities: Required Properties: - compatible: Must be one of: - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) + - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3) - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W) @@ -23,9 +24,9 @@ Required Properties: - clocks: References to external parent clocks, one entry for each entry in clock-names - clock-names: List of external parent clock names. Valid names are: - - "extal" (r8a7743, r8a7795, r8a7796) + - "extal" (r8a7743, r8a7745, r8a7795, r8a7796) - "extalr" (r8a7795, r8a7796) - - "usb_extal" (r8a7743) + - "usb_extal" (r8a7743, r8a7745) - #clock-cells: Must be 2 - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index e1cd3bfb6f97..2586dfa0026b 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -1,6 +1,7 @@ config CLK_RENESAS_CPG_MSSR bool default y if ARCH_R8A7743 + default y if ARCH_R8A7745 default y if ARCH_R8A7795 default y if ARCH_R8A7796 diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 81082bd79430..1072f7653c0c 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-div6.o obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-div6.o obj-$(CONFIG_ARCH_R8A7743) += r8a7743-cpg-mssr.o rcar-gen2-cpg.o +obj-$(CONFIG_ARCH_R8A7745) += r8a7745-cpg-mssr.o rcar-gen2-cpg.o obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-div6.o diff --git a/drivers/clk/renesas/r8a7745-cpg-mssr.c b/drivers/clk/renesas/r8a7745-cpg-mssr.c new file mode 100644 index 000000000000..2f15ba786c3b --- /dev/null +++ b/drivers/clk/renesas/r8a7745-cpg-mssr.c @@ -0,0 +1,259 @@ +/* + * r8a7745 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2016 Cogent Embedded Inc. + * + * 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; of the License. + */ + +#include +#include +#include +#include + +#include + +#include "renesas-cpg-mssr.h" +#include "rcar-gen2-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A7745_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_USB_EXTAL, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL3, + CLK_PLL1_DIV2, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a7745_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("usb_extal", CLK_USB_EXTAL), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN2_MAIN, CLK_EXTAL), + DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN2_PLL0, CLK_MAIN), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN2_PLL1, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN2_PLL3, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + + /* Core Clock Outputs */ + DEF_BASE("lb", R8A7745_CLK_LB, CLK_TYPE_GEN2_LB, CLK_PLL1), + DEF_BASE("sdh", R8A7745_CLK_SDH, CLK_TYPE_GEN2_SDH, CLK_PLL1), + DEF_BASE("sd0", R8A7745_CLK_SD0, CLK_TYPE_GEN2_SD0, CLK_PLL1), + DEF_BASE("qspi", R8A7745_CLK_QSPI, CLK_TYPE_GEN2_QSPI, CLK_PLL1_DIV2), + DEF_BASE("rcan", R8A7745_CLK_RCAN, CLK_TYPE_GEN2_RCAN, CLK_USB_EXTAL), + + DEF_FIXED("z2", R8A7745_CLK_Z2, CLK_PLL0, 1, 1), + DEF_FIXED("zg", R8A7745_CLK_ZG, CLK_PLL1, 6, 1), + DEF_FIXED("zx", R8A7745_CLK_ZX, CLK_PLL1, 3, 1), + DEF_FIXED("zs", R8A7745_CLK_ZS, CLK_PLL1, 6, 1), + DEF_FIXED("hp", R8A7745_CLK_HP, CLK_PLL1, 12, 1), + DEF_FIXED("b", R8A7745_CLK_B, CLK_PLL1, 12, 1), + DEF_FIXED("p", R8A7745_CLK_P, CLK_PLL1, 24, 1), + DEF_FIXED("cl", R8A7745_CLK_CL, CLK_PLL1, 48, 1), + DEF_FIXED("cp", R8A7745_CLK_CP, CLK_PLL1, 48, 1), + DEF_FIXED("m2", R8A7745_CLK_M2, CLK_PLL1, 8, 1), + DEF_FIXED("zb3", R8A7745_CLK_ZB3, CLK_PLL3, 4, 1), + DEF_FIXED("zb3d2", R8A7745_CLK_ZB3D2, CLK_PLL3, 8, 1), + DEF_FIXED("ddr", R8A7745_CLK_DDR, CLK_PLL3, 8, 1), + DEF_FIXED("mp", R8A7745_CLK_MP, CLK_PLL1_DIV2, 15, 1), + DEF_FIXED("cpex", R8A7745_CLK_CPEX, CLK_EXTAL, 2, 1), + DEF_FIXED("r", R8A7745_CLK_R, CLK_PLL1, 49152, 1), + DEF_FIXED("osc", R8A7745_CLK_OSC, CLK_PLL1, 12288, 1), + + DEF_DIV6P1("sd2", R8A7745_CLK_SD2, CLK_PLL1_DIV2, 0x078), + DEF_DIV6P1("sd3", R8A7745_CLK_SD3, CLK_PLL1_DIV2, 0x26c), + DEF_DIV6P1("mmc0", R8A7745_CLK_MMC0, CLK_PLL1_DIV2, 0x240), +}; + +static const struct mssr_mod_clk r8a7745_mod_clks[] __initconst = { + DEF_MOD("msiof0", 0, R8A7745_CLK_MP), + DEF_MOD("vcp0", 101, R8A7745_CLK_ZS), + DEF_MOD("vpc0", 103, R8A7745_CLK_ZS), + DEF_MOD("tmu1", 111, R8A7745_CLK_P), + DEF_MOD("3dg", 112, R8A7745_CLK_ZG), + DEF_MOD("2d-dmac", 115, R8A7745_CLK_ZS), + DEF_MOD("fdp1-0", 119, R8A7745_CLK_ZS), + DEF_MOD("tmu3", 121, R8A7745_CLK_P), + DEF_MOD("tmu2", 122, R8A7745_CLK_P), + DEF_MOD("cmt0", 124, R8A7745_CLK_R), + DEF_MOD("tmu0", 125, R8A7745_CLK_CP), + DEF_MOD("vsp1du0", 128, R8A7745_CLK_ZS), + DEF_MOD("vsp1-sy", 131, R8A7745_CLK_ZS), + DEF_MOD("scifa2", 202, R8A7745_CLK_MP), + DEF_MOD("scifa1", 203, R8A7745_CLK_MP), + DEF_MOD("scifa0", 204, R8A7745_CLK_MP), + DEF_MOD("msiof2", 205, R8A7745_CLK_MP), + DEF_MOD("scifb0", 206, R8A7745_CLK_MP), + DEF_MOD("scifb1", 207, R8A7745_CLK_MP), + DEF_MOD("msiof1", 208, R8A7745_CLK_MP), + DEF_MOD("scifb2", 216, R8A7745_CLK_MP), + DEF_MOD("sys-dmac1", 218, R8A7745_CLK_ZS), + DEF_MOD("sys-dmac0", 219, R8A7745_CLK_ZS), + DEF_MOD("tpu0", 304, R8A7745_CLK_CP), + DEF_MOD("sdhi3", 311, R8A7745_CLK_SD3), + DEF_MOD("sdhi2", 312, R8A7745_CLK_SD2), + DEF_MOD("sdhi0", 314, R8A7745_CLK_SD0), + DEF_MOD("mmcif0", 315, R8A7745_CLK_MMC0), + DEF_MOD("iic0", 318, R8A7745_CLK_HP), + DEF_MOD("iic1", 323, R8A7745_CLK_HP), + DEF_MOD("cmt1", 329, R8A7745_CLK_R), + DEF_MOD("usbhs-dmac0", 330, R8A7745_CLK_HP), + DEF_MOD("usbhs-dmac1", 331, R8A7745_CLK_HP), + DEF_MOD("irqc", 407, R8A7745_CLK_CP), + DEF_MOD("intc-sys", 408, R8A7745_CLK_ZS), + DEF_MOD("audio-dmac0", 502, R8A7745_CLK_HP), + DEF_MOD("pwm", 523, R8A7745_CLK_P), + DEF_MOD("usb-ehci", 703, R8A7745_CLK_MP), + DEF_MOD("usbhs", 704, R8A7745_CLK_HP), + DEF_MOD("hscif2", 713, R8A7745_CLK_ZS), + DEF_MOD("scif5", 714, R8A7745_CLK_P), + DEF_MOD("scif4", 715, R8A7745_CLK_P), + DEF_MOD("hscif1", 716, R8A7745_CLK_ZS), + DEF_MOD("hscif0", 717, R8A7745_CLK_ZS), + DEF_MOD("scif3", 718, R8A7745_CLK_P), + DEF_MOD("scif2", 719, R8A7745_CLK_P), + DEF_MOD("scif1", 720, R8A7745_CLK_P), + DEF_MOD("scif0", 721, R8A7745_CLK_P), + DEF_MOD("du0", 724, R8A7745_CLK_ZX), + DEF_MOD("ipmmu-sgx", 800, R8A7745_CLK_ZX), + DEF_MOD("vin1", 810, R8A7745_CLK_ZG), + DEF_MOD("vin0", 811, R8A7745_CLK_ZG), + DEF_MOD("etheravb", 812, R8A7745_CLK_HP), + DEF_MOD("ether", 813, R8A7745_CLK_P), + DEF_MOD("gpio6", 905, R8A7745_CLK_CP), + DEF_MOD("gpio5", 907, R8A7745_CLK_CP), + DEF_MOD("gpio4", 908, R8A7745_CLK_CP), + DEF_MOD("gpio3", 909, R8A7745_CLK_CP), + DEF_MOD("gpio2", 910, R8A7745_CLK_CP), + DEF_MOD("gpio1", 911, R8A7745_CLK_CP), + DEF_MOD("gpio0", 912, R8A7745_CLK_CP), + DEF_MOD("can1", 915, R8A7745_CLK_P), + DEF_MOD("can0", 916, R8A7745_CLK_P), + DEF_MOD("qspi_mod", 917, R8A7745_CLK_QSPI), + DEF_MOD("i2c5", 925, R8A7745_CLK_HP), + DEF_MOD("i2c4", 927, R8A7745_CLK_HP), + DEF_MOD("i2c3", 928, R8A7745_CLK_HP), + DEF_MOD("i2c2", 929, R8A7745_CLK_HP), + DEF_MOD("i2c1", 930, R8A7745_CLK_HP), + DEF_MOD("i2c0", 931, R8A7745_CLK_HP), + DEF_MOD("ssi-all", 1005, R8A7745_CLK_P), + DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)), + DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)), + DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)), + DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)), + DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)), + DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)), + DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)), + DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)), + DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)), + DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)), + DEF_MOD("scu-all", 1017, R8A7745_CLK_P), + DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)), + DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)), + DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)), + DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)), + DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)), + DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)), + DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)), + DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)), + DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)), + DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)), + DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)), + DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)), + DEF_MOD("scifa3", 1106, R8A7745_CLK_MP), + DEF_MOD("scifa4", 1107, R8A7745_CLK_MP), + DEF_MOD("scifa5", 1108, R8A7745_CLK_MP), +}; + +static const unsigned int r8a7745_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-SYS (GIC) */ +}; + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL3 + * 14 13 19 (MHz) *1 *2 + *--------------------------------------------------- + * 0 0 0 15 x200/3 x208/2 x106 + * 0 0 1 15 x200/3 x208/2 x88 + * 0 1 0 20 x150/3 x156/2 x80 + * 0 1 1 20 x150/3 x156/2 x66 + * 1 0 0 26 / 2 x230/3 x240/2 x122 + * 1 0 1 26 / 2 x230/3 x240/2 x102 + * 1 1 0 30 / 2 x200/3 x208/2 x106 + * 1 1 1 30 / 2 x200/3 x208/2 x88 + * + * *1 : Table 7.5b indicates VCO output (PLL0 = VCO/3) + * *2 : Table 7.5b indicates VCO output (PLL1 = VCO/2) + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ + (((md) & BIT(13)) >> 12) | \ + (((md) & BIT(19)) >> 19)) + +static const struct rcar_gen2_cpg_pll_config cpg_pll_configs[8] __initconst = { + /* EXTAL div PLL1 mult PLL3 mult PLL0 mult */ + { 1, 208, 106, 200 }, + { 1, 208, 88, 200 }, + { 1, 156, 80, 150 }, + { 1, 156, 66, 150 }, + { 2, 240, 122, 230 }, + { 2, 240, 102, 230 }, + { 2, 208, 106, 200 }, + { 2, 208, 88, 200 }, +}; + +static int __init r8a7745_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen2_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + return rcar_gen2_cpg_init(cpg_pll_config, 3, cpg_mode); +} + +const struct cpg_mssr_info r8a7745_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a7745_core_clks, + .num_core_clks = ARRAY_SIZE(r8a7745_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a7745_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a7745_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a7745_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a7745_crit_mod_clks), + + /* Callbacks */ + .init = r8a7745_cpg_mssr_init, + .cpg_clk_register = rcar_gen2_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index e87504c68391..8359ce75db7a 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -508,6 +508,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a7743_cpg_mssr_info, }, #endif +#ifdef CONFIG_ARCH_R8A7745 + { + .compatible = "renesas,r8a7745-cpg-mssr", + .data = &r8a7745_cpg_mssr_info, + }, +#endif #ifdef CONFIG_ARCH_R8A7795 { .compatible = "renesas,r8a7795-cpg-mssr", diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 7a50639fd43b..4bb7a80c6469 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -131,6 +131,7 @@ struct cpg_mssr_info { }; extern const struct cpg_mssr_info r8a7743_cpg_mssr_info; +extern const struct cpg_mssr_info r8a7745_cpg_mssr_info; extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; extern const struct cpg_mssr_info r8a7796_cpg_mssr_info; #endif -- cgit v1.2.3 From 49e28282430b770f7662f3218c70a4d6b310ff41 Mon Sep 17 00:00:00 2001 From: Jeremy McNicoll Date: Fri, 4 Nov 2016 13:56:32 -0700 Subject: dt-bindings: qcom: clocks: Add msm8994 clock bindings Signed-off-by: Jeremy McNicoll [sboyd@codeaurora.org: Dropped unused and incorrect GDSC defines] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,gcc.txt | 1 + include/dt-bindings/clock/qcom,gcc-msm8994.h | 137 +++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 include/dt-bindings/clock/qcom,gcc-msm8994.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 3cf44217068e..5b4dfc1ea54f 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -14,6 +14,7 @@ Required properties : "qcom,gcc-msm8974" "qcom,gcc-msm8974pro" "qcom,gcc-msm8974pro-ac" + "qcom,gcc-msm8994" "qcom,gcc-msm8996" "qcom,gcc-mdm9615" diff --git a/include/dt-bindings/clock/qcom,gcc-msm8994.h b/include/dt-bindings/clock/qcom,gcc-msm8994.h new file mode 100644 index 000000000000..8fa535be2ebc --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-msm8994.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#ifndef _DT_BINDINGS_CLK_MSM_GCC_8994_H +#define _DT_BINDINGS_CLK_MSM_GCC_8994_H + +#define GPLL0_EARLY 0 +#define GPLL0 1 +#define GPLL4_EARLY 2 +#define GPLL4 3 +#define UFS_AXI_CLK_SRC 4 +#define USB30_MASTER_CLK_SRC 5 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 6 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 7 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 8 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 9 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 10 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 11 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 12 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 13 +#define BLSP1_QUP5_I2C_APPS_CLK_SRC 14 +#define BLSP1_QUP5_SPI_APPS_CLK_SRC 15 +#define BLSP1_QUP6_I2C_APPS_CLK_SRC 16 +#define BLSP1_QUP6_SPI_APPS_CLK_SRC 17 +#define BLSP1_UART1_APPS_CLK_SRC 18 +#define BLSP1_UART2_APPS_CLK_SRC 19 +#define BLSP1_UART3_APPS_CLK_SRC 20 +#define BLSP1_UART4_APPS_CLK_SRC 21 +#define BLSP1_UART5_APPS_CLK_SRC 22 +#define BLSP1_UART6_APPS_CLK_SRC 23 +#define BLSP2_QUP1_I2C_APPS_CLK_SRC 24 +#define BLSP2_QUP1_SPI_APPS_CLK_SRC 25 +#define BLSP2_QUP2_I2C_APPS_CLK_SRC 26 +#define BLSP2_QUP2_SPI_APPS_CLK_SRC 27 +#define BLSP2_QUP3_I2C_APPS_CLK_SRC 28 +#define BLSP2_QUP3_SPI_APPS_CLK_SRC 29 +#define BLSP2_QUP4_I2C_APPS_CLK_SRC 30 +#define BLSP2_QUP4_SPI_APPS_CLK_SRC 31 +#define BLSP2_QUP5_I2C_APPS_CLK_SRC 32 +#define BLSP2_QUP5_SPI_APPS_CLK_SRC 33 +#define BLSP2_QUP6_I2C_APPS_CLK_SRC 34 +#define BLSP2_QUP6_SPI_APPS_CLK_SRC 35 +#define BLSP2_UART1_APPS_CLK_SRC 36 +#define BLSP2_UART2_APPS_CLK_SRC 37 +#define BLSP2_UART3_APPS_CLK_SRC 38 +#define BLSP2_UART4_APPS_CLK_SRC 39 +#define BLSP2_UART5_APPS_CLK_SRC 40 +#define BLSP2_UART6_APPS_CLK_SRC 41 +#define GP1_CLK_SRC 42 +#define GP2_CLK_SRC 43 +#define GP3_CLK_SRC 44 +#define PCIE_0_AUX_CLK_SRC 45 +#define PCIE_0_PIPE_CLK_SRC 46 +#define PCIE_1_AUX_CLK_SRC 47 +#define PCIE_1_PIPE_CLK_SRC 48 +#define PDM2_CLK_SRC 49 +#define SDCC1_APPS_CLK_SRC 50 +#define SDCC2_APPS_CLK_SRC 51 +#define SDCC3_APPS_CLK_SRC 52 +#define SDCC4_APPS_CLK_SRC 53 +#define TSIF_REF_CLK_SRC 54 +#define USB30_MOCK_UTMI_CLK_SRC 55 +#define USB3_PHY_AUX_CLK_SRC 56 +#define USB_HS_SYSTEM_CLK_SRC 57 +#define GCC_BLSP1_AHB_CLK 58 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 59 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 60 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 61 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 62 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 63 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 64 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 65 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 66 +#define GCC_BLSP1_QUP5_I2C_APPS_CLK 67 +#define GCC_BLSP1_QUP5_SPI_APPS_CLK 68 +#define GCC_BLSP1_QUP6_I2C_APPS_CLK 69 +#define GCC_BLSP1_QUP6_SPI_APPS_CLK 70 +#define GCC_BLSP1_UART1_APPS_CLK 71 +#define GCC_BLSP1_UART2_APPS_CLK 72 +#define GCC_BLSP1_UART3_APPS_CLK 73 +#define GCC_BLSP1_UART4_APPS_CLK 74 +#define GCC_BLSP1_UART5_APPS_CLK 75 +#define GCC_BLSP1_UART6_APPS_CLK 76 +#define GCC_BLSP2_AHB_CLK 77 +#define GCC_BLSP2_QUP1_I2C_APPS_CLK 78 +#define GCC_BLSP2_QUP1_SPI_APPS_CLK 79 +#define GCC_BLSP2_QUP2_I2C_APPS_CLK 80 +#define GCC_BLSP2_QUP2_SPI_APPS_CLK 81 +#define GCC_BLSP2_QUP3_I2C_APPS_CLK 82 +#define GCC_BLSP2_QUP3_SPI_APPS_CLK 83 +#define GCC_BLSP2_QUP4_I2C_APPS_CLK 84 +#define GCC_BLSP2_QUP4_SPI_APPS_CLK 85 +#define GCC_BLSP2_QUP5_I2C_APPS_CLK 86 +#define GCC_BLSP2_QUP5_SPI_APPS_CLK 87 +#define GCC_BLSP2_QUP6_I2C_APPS_CLK 88 +#define GCC_BLSP2_QUP6_SPI_APPS_CLK 89 +#define GCC_BLSP2_UART1_APPS_CLK 90 +#define GCC_BLSP2_UART2_APPS_CLK 91 +#define GCC_BLSP2_UART3_APPS_CLK 92 +#define GCC_BLSP2_UART4_APPS_CLK 93 +#define GCC_BLSP2_UART5_APPS_CLK 94 +#define GCC_BLSP2_UART6_APPS_CLK 95 +#define GCC_GP1_CLK 96 +#define GCC_GP2_CLK 97 +#define GCC_GP3_CLK 98 +#define GCC_PCIE_0_AUX_CLK 99 +#define GCC_PCIE_0_PIPE_CLK 100 +#define GCC_PCIE_1_AUX_CLK 101 +#define GCC_PCIE_1_PIPE_CLK 102 +#define GCC_PDM2_CLK 103 +#define GCC_SDCC1_APPS_CLK 104 +#define GCC_SDCC2_APPS_CLK 105 +#define GCC_SDCC3_APPS_CLK 106 +#define GCC_SDCC4_APPS_CLK 107 +#define GCC_SYS_NOC_UFS_AXI_CLK 108 +#define GCC_SYS_NOC_USB3_AXI_CLK 109 +#define GCC_TSIF_REF_CLK 110 +#define GCC_UFS_AXI_CLK 111 +#define GCC_UFS_RX_CFG_CLK 112 +#define GCC_UFS_TX_CFG_CLK 113 +#define GCC_USB30_MASTER_CLK 114 +#define GCC_USB30_MOCK_UTMI_CLK 115 +#define GCC_USB3_PHY_AUX_CLK 116 +#define GCC_USB_HS_SYSTEM_CLK 117 + +#endif -- cgit v1.2.3 From 00f64b58874e14dec2b9c02f7d63147315e0a09b Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 2 Nov 2016 17:56:56 +0200 Subject: clk: qcom: Add support for SMD-RPM Clocks This adds initial support for clocks controlled by the Resource Power Manager (RPM) processor on some Qualcomm SoCs, which use the qcom_smd_rpm driver to communicate with RPM. Such platforms are msm8916, apq8084 and msm8974. The RPM is a dedicated hardware engine for managing the shared SoC resources in order to keep the lowest power profile. It communicates with other hardware subsystems via shared memory and accepts clock requests, aggregates the requests and turns the clocks on/off or scales them on demand. This driver is based on the codeaurora.org driver: https://www.codeaurora.org/cgit/quic/la/kernel/msm-3.10/tree/drivers/clk/qcom/clock-rpm.c Signed-off-by: Georgi Djakov Acked-by: Rob Herring [sboyd@codeaurora.org: Remove useless braces for single line if] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,rpmcc.txt | 36 ++ drivers/clk/qcom/Kconfig | 16 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-smd-rpm.c | 570 +++++++++++++++++++++ include/dt-bindings/clock/qcom,rpmcc.h | 45 ++ 5 files changed, 668 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,rpmcc.txt create mode 100644 drivers/clk/qcom/clk-smd-rpm.c create mode 100644 include/dt-bindings/clock/qcom,rpmcc.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt new file mode 100644 index 000000000000..e3e13226d798 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt @@ -0,0 +1,36 @@ +Qualcomm RPM Clock Controller Binding +------------------------------------------------ +The RPM is a dedicated hardware engine for managing the shared +SoC resources in order to keep the lowest power profile. It +communicates with other hardware subsystems via shared memory +and accepts clock requests, aggregates the requests and turns +the clocks on/off or scales them on demand. + +Required properties : +- compatible : shall contain only one of the following. The generic + compatible "qcom,rpmcc" should be also included. + + "qcom,rpmcc-msm8916", "qcom,rpmcc" + +- #clock-cells : shall contain 1 + +Example: + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8916"; + qcom,smd-channels = "rpm_requests"; + + rpmcc: clock-controller { + compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc"; + #clock-cells = <1>; + }; + }; + }; + }; diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 0146d3c2547f..b537c59dcfe6 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -2,6 +2,9 @@ config QCOM_GDSC bool select PM_GENERIC_DOMAINS if PM +config QCOM_RPMCC + bool + config COMMON_CLK_QCOM tristate "Support for Qualcomm's clock controllers" depends on OF @@ -9,6 +12,19 @@ config COMMON_CLK_QCOM select REGMAP_MMIO select RESET_CONTROLLER +config QCOM_CLK_SMD_RPM + tristate "RPM over SMD based Clock Controller" + depends on COMMON_CLK_QCOM && QCOM_SMD_RPM + select QCOM_RPMCC + help + The RPM (Resource Power Manager) is a dedicated hardware engine for + managing the shared SoC resources in order to keep the lowest power + profile. It communicates with other hardware subsystems via shared + memory and accepts clock requests, aggregates the requests and turns + the clocks on/off or scales them on demand. + Say Y if you want to support the clocks exposed by the RPM on + platforms such as apq8016, apq8084, msm8974 etc. + config APQ_GCC_8084 tristate "APQ8084 Global Clock Controller" select QCOM_GDSC diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 1fb1f5476cb0..0dd72e56b7e4 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c new file mode 100644 index 000000000000..a27013dbc0aa --- /dev/null +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2016, Linaro Limited + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define QCOM_RPM_KEY_SOFTWARE_ENABLE 0x6e657773 +#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370 +#define QCOM_RPM_SMD_KEY_RATE 0x007a484b +#define QCOM_RPM_SMD_KEY_ENABLE 0x62616e45 +#define QCOM_RPM_SMD_KEY_STATE 0x54415453 +#define QCOM_RPM_SCALING_ENABLE_ID 0x2 + +#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id, \ + key) \ + static struct clk_smd_rpm _platform##_##_active; \ + static struct clk_smd_rpm _platform##_##_name = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .peer = &_platform##_##_active, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_smd_rpm _platform##_##_active = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .active_only = true, \ + .rpm_key = (key), \ + .peer = &_platform##_##_name, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, \ + stat_id, r, key) \ + static struct clk_smd_rpm _platform##_##_active; \ + static struct clk_smd_rpm _platform##_##_name = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .branch = true, \ + .peer = &_platform##_##_active, \ + .rate = (r), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_branch_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_smd_rpm _platform##_##_active = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .active_only = true, \ + .rpm_key = (key), \ + .branch = true, \ + .peer = &_platform##_##_name, \ + .rate = (r), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_branch_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id) \ + __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, \ + 0, QCOM_RPM_SMD_KEY_RATE) + +#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r) \ + __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, \ + r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE) + +#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id) \ + __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, \ + 0, QCOM_RPM_SMD_KEY_STATE) + +#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id) \ + __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, \ + QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000, \ + QCOM_RPM_KEY_SOFTWARE_ENABLE) + +#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \ + __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, \ + QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000, \ + QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY) + +#define to_clk_smd_rpm(_hw) container_of(_hw, struct clk_smd_rpm, hw) + +struct clk_smd_rpm { + const int rpm_res_type; + const int rpm_key; + const int rpm_clk_id; + const int rpm_status_id; + const bool active_only; + bool enabled; + bool branch; + struct clk_smd_rpm *peer; + struct clk_hw hw; + unsigned long rate; + struct qcom_smd_rpm *rpm; +}; + +struct clk_smd_rpm_req { + __le32 key; + __le32 nbytes; + __le32 value; +}; + +struct rpm_cc { + struct qcom_rpm *rpm; + struct clk_hw_onecell_data data; + struct clk_hw *hws[]; +}; + +struct rpm_smd_clk_desc { + struct clk_smd_rpm **clks; + size_t num_clks; +}; + +static DEFINE_MUTEX(rpm_smd_clk_lock); + +static int clk_smd_rpm_handoff(struct clk_smd_rpm *r) +{ + int ret; + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(r->rpm_key), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(INT_MAX), + }; + + ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); + if (ret) + return ret; + ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); + if (ret) + return ret; + + return 0; +} + +static int clk_smd_rpm_set_rate_active(struct clk_smd_rpm *r, + unsigned long rate) +{ + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(r->rpm_key), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(DIV_ROUND_UP(rate, 1000)), /* to kHz */ + }; + + return qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); +} + +static int clk_smd_rpm_set_rate_sleep(struct clk_smd_rpm *r, + unsigned long rate) +{ + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(r->rpm_key), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(DIV_ROUND_UP(rate, 1000)), /* to kHz */ + }; + + return qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); +} + +static void to_active_sleep(struct clk_smd_rpm *r, unsigned long rate, + unsigned long *active, unsigned long *sleep) +{ + *active = rate; + + /* + * Active-only clocks don't care what the rate is during sleep. So, + * they vote for zero. + */ + if (r->active_only) + *sleep = 0; + else + *sleep = *active; +} + +static int clk_smd_rpm_prepare(struct clk_hw *hw) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + struct clk_smd_rpm *peer = r->peer; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret = 0; + + mutex_lock(&rpm_smd_clk_lock); + + /* Don't send requests to the RPM if the rate has not been set. */ + if (!r->rate) + goto out; + + to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + + if (r->branch) + active_rate = !!active_rate; + + ret = clk_smd_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + if (r->branch) + sleep_rate = !!sleep_rate; + + ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + /* Undo the active set vote and restore it */ + ret = clk_smd_rpm_set_rate_active(r, peer_rate); + +out: + if (!ret) + r->enabled = true; + + mutex_unlock(&rpm_smd_clk_lock); + + return ret; +} + +static void clk_smd_rpm_unprepare(struct clk_hw *hw) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + struct clk_smd_rpm *peer = r->peer; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret; + + mutex_lock(&rpm_smd_clk_lock); + + if (!r->rate) + goto out; + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, &peer_rate, + &peer_sleep_rate); + + active_rate = r->branch ? !!peer_rate : peer_rate; + ret = clk_smd_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate; + ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->enabled = false; + +out: + mutex_unlock(&rpm_smd_clk_lock); +} + +static int clk_smd_rpm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + struct clk_smd_rpm *peer = r->peer; + unsigned long active_rate, sleep_rate; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + int ret = 0; + + mutex_lock(&rpm_smd_clk_lock); + + if (!r->enabled) + goto out; + + to_active_sleep(r, rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + ret = clk_smd_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->rate = rate; + +out: + mutex_unlock(&rpm_smd_clk_lock); + + return ret; +} + +static long clk_smd_rpm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate is requested. + */ + return rate; +} + +static unsigned long clk_smd_rpm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate was set. + */ + return r->rate; +} + +static int clk_smd_rpm_enable_scaling(struct qcom_smd_rpm *rpm) +{ + int ret; + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(QCOM_RPM_SMD_KEY_ENABLE), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(1), + }; + + ret = qcom_rpm_smd_write(rpm, QCOM_SMD_RPM_SLEEP_STATE, + QCOM_SMD_RPM_MISC_CLK, + QCOM_RPM_SCALING_ENABLE_ID, &req, sizeof(req)); + if (ret) { + pr_err("RPM clock scaling (sleep set) not enabled!\n"); + return ret; + } + + ret = qcom_rpm_smd_write(rpm, QCOM_SMD_RPM_ACTIVE_STATE, + QCOM_SMD_RPM_MISC_CLK, + QCOM_RPM_SCALING_ENABLE_ID, &req, sizeof(req)); + if (ret) { + pr_err("RPM clock scaling (active set) not enabled!\n"); + return ret; + } + + pr_debug("%s: RPM clock scaling is enabled\n", __func__); + return 0; +} + +static const struct clk_ops clk_smd_rpm_ops = { + .prepare = clk_smd_rpm_prepare, + .unprepare = clk_smd_rpm_unprepare, + .set_rate = clk_smd_rpm_set_rate, + .round_rate = clk_smd_rpm_round_rate, + .recalc_rate = clk_smd_rpm_recalc_rate, +}; + +static const struct clk_ops clk_smd_rpm_branch_ops = { + .prepare = clk_smd_rpm_prepare, + .unprepare = clk_smd_rpm_unprepare, + .round_rate = clk_smd_rpm_round_rate, + .recalc_rate = clk_smd_rpm_recalc_rate, +}; + +/* msm8916 */ +DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); +DEFINE_CLK_SMD_RPM_QDSS(msm8916, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk1, bb_clk1_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk2, bb_clk2_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk1, rf_clk1_a, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk2, rf_clk2_a, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk1_pin, bb_clk1_a_pin, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk2_pin, bb_clk2_a_pin, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk1_pin, rf_clk1_a_pin, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk2_pin, rf_clk2_a_pin, 5); + +static struct clk_smd_rpm *msm8916_clks[] = { + [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk, + [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk, + [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk, + [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk, + [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk, + [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1, + [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a, + [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2, + [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a, + [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1, + [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a, + [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2, + [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a, + [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin, + [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin, + [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin, + [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin, + [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin, + [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin, + [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin, + [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8916 = { + .clks = msm8916_clks, + .num_clks = ARRAY_SIZE(msm8916_clks), +}; + +static const struct of_device_id rpm_smd_clk_match_table[] = { + { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, + { } +}; +MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table); + +static int rpm_smd_clk_probe(struct platform_device *pdev) +{ + struct clk_hw **hws; + struct rpm_cc *rcc; + struct clk_hw_onecell_data *data; + int ret; + size_t num_clks, i; + struct qcom_smd_rpm *rpm; + struct clk_smd_rpm **rpm_smd_clks; + const struct rpm_smd_clk_desc *desc; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); + return -ENODEV; + } + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rpm_smd_clks = desc->clks; + num_clks = desc->num_clks; + + rcc = devm_kzalloc(&pdev->dev, sizeof(*rcc) + sizeof(*hws) * num_clks, + GFP_KERNEL); + if (!rcc) + return -ENOMEM; + + hws = rcc->hws; + data = &rcc->data; + data->num = num_clks; + + for (i = 0; i < num_clks; i++) { + if (!rpm_smd_clks[i]) + continue; + + rpm_smd_clks[i]->rpm = rpm; + + ret = clk_smd_rpm_handoff(rpm_smd_clks[i]); + if (ret) + goto err; + } + + ret = clk_smd_rpm_enable_scaling(rpm); + if (ret) + goto err; + + for (i = 0; i < num_clks; i++) { + if (!rpm_smd_clks[i]) { + data->hws[i] = ERR_PTR(-ENOENT); + continue; + } + + ret = devm_clk_hw_register(&pdev->dev, &rpm_smd_clks[i]->hw); + if (ret) + goto err; + } + + ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + data); + if (ret) + goto err; + + return 0; +err: + dev_err(&pdev->dev, "Error registering SMD clock driver (%d)\n", ret); + return ret; +} + +static int rpm_smd_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static struct platform_driver rpm_smd_clk_driver = { + .driver = { + .name = "qcom-clk-smd-rpm", + .of_match_table = rpm_smd_clk_match_table, + }, + .probe = rpm_smd_clk_probe, + .remove = rpm_smd_clk_remove, +}; + +static int __init rpm_smd_clk_init(void) +{ + return platform_driver_register(&rpm_smd_clk_driver); +} +core_initcall(rpm_smd_clk_init); + +static void __exit rpm_smd_clk_exit(void) +{ + platform_driver_unregister(&rpm_smd_clk_driver); +} +module_exit(rpm_smd_clk_exit); + +MODULE_DESCRIPTION("Qualcomm RPM over SMD Clock Controller Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-clk-smd-rpm"); diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h new file mode 100644 index 000000000000..9fae52dfe35a --- /dev/null +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Linaro Limited + * + * 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. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H +#define _DT_BINDINGS_CLK_MSM_RPMCC_H + +/* msm8916 */ +#define RPM_SMD_XO_CLK_SRC 0 +#define RPM_SMD_XO_A_CLK_SRC 1 +#define RPM_SMD_PCNOC_CLK 2 +#define RPM_SMD_PCNOC_A_CLK 3 +#define RPM_SMD_SNOC_CLK 4 +#define RPM_SMD_SNOC_A_CLK 5 +#define RPM_SMD_BIMC_CLK 6 +#define RPM_SMD_BIMC_A_CLK 7 +#define RPM_SMD_QDSS_CLK 8 +#define RPM_SMD_QDSS_A_CLK 9 +#define RPM_SMD_BB_CLK1 10 +#define RPM_SMD_BB_CLK1_A 11 +#define RPM_SMD_BB_CLK2 12 +#define RPM_SMD_BB_CLK2_A 13 +#define RPM_SMD_RF_CLK1 14 +#define RPM_SMD_RF_CLK1_A 15 +#define RPM_SMD_RF_CLK2 16 +#define RPM_SMD_RF_CLK2_A 17 +#define RPM_SMD_BB_CLK1_PIN 18 +#define RPM_SMD_BB_CLK1_A_PIN 19 +#define RPM_SMD_BB_CLK2_PIN 20 +#define RPM_SMD_BB_CLK2_A_PIN 21 +#define RPM_SMD_RF_CLK1_PIN 22 +#define RPM_SMD_RF_CLK1_A_PIN 23 +#define RPM_SMD_RF_CLK2_PIN 24 +#define RPM_SMD_RF_CLK2_A_PIN 25 + +#endif -- cgit v1.2.3 From 872f91b5ea720c72f81fb46d353c43ecb3263ffa Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 2 Nov 2016 17:56:57 +0200 Subject: clk: qcom: Add support for RPM Clocks This adds initial support for clocks controlled by the Resource Power Manager (RPM) processor on some Qualcomm SoCs, which use the qcom_rpm driver to communicate with RPM. Such platforms are apq8064 and msm8960. Signed-off-by: Georgi Djakov Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,rpmcc.txt | 1 + drivers/clk/qcom/Kconfig | 13 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-rpm.c | 489 +++++++++++++++++++++ include/dt-bindings/clock/qcom,rpmcc.h | 24 + 5 files changed, 528 insertions(+) create mode 100644 drivers/clk/qcom/clk-rpm.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt index e3e13226d798..87d3714b956a 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-apq8064", "qcom,rpmcc" - #clock-cells : shall contain 1 diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index b537c59dcfe6..b82d2f33c9e4 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -12,6 +12,19 @@ config COMMON_CLK_QCOM select REGMAP_MMIO select RESET_CONTROLLER +config QCOM_CLK_RPM + tristate "RPM based Clock Controller" + depends on COMMON_CLK_QCOM && MFD_QCOM_RPM + select QCOM_RPMCC + help + The RPM (Resource Power Manager) is a dedicated hardware engine for + managing the shared SoC resources in order to keep the lowest power + profile. It communicates with other hardware subsystems via shared + memory and accepts clock requests, aggregates the requests and turns + the clocks on/off or scales them on demand. + Say Y if you want to support the clocks exposed by the RPM on + platforms such as apq8064, msm8660, msm8960 etc. + config QCOM_CLK_SMD_RPM tristate "RPM over SMD based Clock Controller" depends on COMMON_CLK_QCOM && QCOM_SMD_RPM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 0dd72e56b7e4..eb2dfb32d960 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c new file mode 100644 index 000000000000..1950a9572624 --- /dev/null +++ b/drivers/clk/qcom/clk-rpm.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2016, Linaro Limited + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63 +#define QCOM_RPM_SCALING_ENABLE_ID 0x2 + +#define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_active, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_name, \ + .active_only = true, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, _active, r_id, r) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .active_only = true, \ + .peer = &_platform##_##_active, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_name, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_RPM_CXO_BRANCH(_platform, _name, _active, r_id, r) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_active, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ + .rpm_clk_id = (r_id), \ + .active_only = true, \ + .peer = &_platform##_##_name, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw) + +struct clk_rpm { + const int rpm_clk_id; + const bool active_only; + unsigned long rate; + bool enabled; + bool branch; + struct clk_rpm *peer; + struct clk_hw hw; + struct qcom_rpm *rpm; +}; + +struct rpm_cc { + struct qcom_rpm *rpm; + struct clk_hw_onecell_data data; + struct clk_hw *hws[]; +}; + +struct rpm_clk_desc { + struct clk_rpm **clks; + size_t num_clks; +}; + +static DEFINE_MUTEX(rpm_clk_lock); + +static int clk_rpm_handoff(struct clk_rpm *r) +{ + int ret; + u32 value = INT_MAX; + + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, + r->rpm_clk_id, &value, 1); + if (ret) + return ret; + ret = qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE, + r->rpm_clk_id, &value, 1); + if (ret) + return ret; + + return 0; +} + +static int clk_rpm_set_rate_active(struct clk_rpm *r, unsigned long rate) +{ + u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */ + + return qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, + r->rpm_clk_id, &value, 1); +} + +static int clk_rpm_set_rate_sleep(struct clk_rpm *r, unsigned long rate) +{ + u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */ + + return qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE, + r->rpm_clk_id, &value, 1); +} + +static void to_active_sleep(struct clk_rpm *r, unsigned long rate, + unsigned long *active, unsigned long *sleep) +{ + *active = rate; + + /* + * Active-only clocks don't care what the rate is during sleep. So, + * they vote for zero. + */ + if (r->active_only) + *sleep = 0; + else + *sleep = *active; +} + +static int clk_rpm_prepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct clk_rpm *peer = r->peer; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret = 0; + + mutex_lock(&rpm_clk_lock); + + /* Don't send requests to the RPM if the rate has not been set. */ + if (!r->rate) + goto out; + + to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + + if (r->branch) + active_rate = !!active_rate; + + ret = clk_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + if (r->branch) + sleep_rate = !!sleep_rate; + + ret = clk_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + /* Undo the active set vote and restore it */ + ret = clk_rpm_set_rate_active(r, peer_rate); + +out: + if (!ret) + r->enabled = true; + + mutex_unlock(&rpm_clk_lock); + + return ret; +} + +static void clk_rpm_unprepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct clk_rpm *peer = r->peer; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret; + + mutex_lock(&rpm_clk_lock); + + if (!r->rate) + goto out; + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, &peer_rate, + &peer_sleep_rate); + + active_rate = r->branch ? !!peer_rate : peer_rate; + ret = clk_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate; + ret = clk_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->enabled = false; + +out: + mutex_unlock(&rpm_clk_lock); +} + +static int clk_rpm_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct clk_rpm *peer = r->peer; + unsigned long active_rate, sleep_rate; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + int ret = 0; + + mutex_lock(&rpm_clk_lock); + + if (!r->enabled) + goto out; + + to_active_sleep(r, rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + ret = clk_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + ret = clk_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->rate = rate; + +out: + mutex_unlock(&rpm_clk_lock); + + return ret; +} + +static long clk_rpm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate is requested. + */ + return rate; +} + +static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_rpm *r = to_clk_rpm(hw); + + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate was set. + */ + return r->rate; +} + +static const struct clk_ops clk_rpm_ops = { + .prepare = clk_rpm_prepare, + .unprepare = clk_rpm_unprepare, + .set_rate = clk_rpm_set_rate, + .round_rate = clk_rpm_round_rate, + .recalc_rate = clk_rpm_recalc_rate, +}; + +static const struct clk_ops clk_rpm_branch_ops = { + .prepare = clk_rpm_prepare, + .unprepare = clk_rpm_unprepare, + .round_rate = clk_rpm_round_rate, + .recalc_rate = clk_rpm_recalc_rate, +}; + +/* apq8064 */ +DEFINE_CLK_RPM(apq8064, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); +DEFINE_CLK_RPM(apq8064, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); +DEFINE_CLK_RPM(apq8064, mmfab_clk, mmfab_a_clk, QCOM_RPM_MM_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK); +DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); +DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); + +static struct clk_rpm *apq8064_clks[] = { + [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk, + [RPM_APPS_FABRIC_A_CLK] = &apq8064_afab_a_clk, + [RPM_CFPB_CLK] = &apq8064_cfpb_clk, + [RPM_CFPB_A_CLK] = &apq8064_cfpb_a_clk, + [RPM_DAYTONA_FABRIC_CLK] = &apq8064_daytona_clk, + [RPM_DAYTONA_FABRIC_A_CLK] = &apq8064_daytona_a_clk, + [RPM_EBI1_CLK] = &apq8064_ebi1_clk, + [RPM_EBI1_A_CLK] = &apq8064_ebi1_a_clk, + [RPM_MM_FABRIC_CLK] = &apq8064_mmfab_clk, + [RPM_MM_FABRIC_A_CLK] = &apq8064_mmfab_a_clk, + [RPM_MMFPB_CLK] = &apq8064_mmfpb_clk, + [RPM_MMFPB_A_CLK] = &apq8064_mmfpb_a_clk, + [RPM_SYS_FABRIC_CLK] = &apq8064_sfab_clk, + [RPM_SYS_FABRIC_A_CLK] = &apq8064_sfab_a_clk, + [RPM_SFPB_CLK] = &apq8064_sfpb_clk, + [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk, + [RPM_QDSS_CLK] = &apq8064_qdss_clk, + [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk, +}; + +static const struct rpm_clk_desc rpm_clk_apq8064 = { + .clks = apq8064_clks, + .num_clks = ARRAY_SIZE(apq8064_clks), +}; + +static const struct of_device_id rpm_clk_match_table[] = { + { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, + { } +}; +MODULE_DEVICE_TABLE(of, rpm_clk_match_table); + +static int rpm_clk_probe(struct platform_device *pdev) +{ + struct clk_hw **hws; + struct rpm_cc *rcc; + struct clk_hw_onecell_data *data; + int ret; + size_t num_clks, i; + struct qcom_rpm *rpm; + struct clk_rpm **rpm_clks; + const struct rpm_clk_desc *desc; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); + return -ENODEV; + } + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rpm_clks = desc->clks; + num_clks = desc->num_clks; + + rcc = devm_kzalloc(&pdev->dev, sizeof(*rcc) + sizeof(*hws) * num_clks, + GFP_KERNEL); + if (!rcc) + return -ENOMEM; + + hws = rcc->hws; + data = &rcc->data; + data->num = num_clks; + + for (i = 0; i < num_clks; i++) { + if (!rpm_clks[i]) + continue; + + rpm_clks[i]->rpm = rpm; + + ret = clk_rpm_handoff(rpm_clks[i]); + if (ret) + goto err; + } + + for (i = 0; i < num_clks; i++) { + if (!rpm_clks[i]) { + data->hws[i] = ERR_PTR(-ENOENT); + continue; + } + + ret = devm_clk_hw_register(&pdev->dev, &rpm_clks[i]->hw); + if (ret) + goto err; + } + + ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + data); + if (ret) + goto err; + + return 0; +err: + dev_err(&pdev->dev, "Error registering RPM Clock driver (%d)\n", ret); + return ret; +} + +static int rpm_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static struct platform_driver rpm_clk_driver = { + .driver = { + .name = "qcom-clk-rpm", + .of_match_table = rpm_clk_match_table, + }, + .probe = rpm_clk_probe, + .remove = rpm_clk_remove, +}; + +static int __init rpm_clk_init(void) +{ + return platform_driver_register(&rpm_clk_driver); +} +core_initcall(rpm_clk_init); + +static void __exit rpm_clk_exit(void) +{ + platform_driver_unregister(&rpm_clk_driver); +} +module_exit(rpm_clk_exit); + +MODULE_DESCRIPTION("Qualcomm RPM Clock Controller Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-clk-rpm"); diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index 9fae52dfe35a..5924cdb71336 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -14,6 +14,30 @@ #ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H #define _DT_BINDINGS_CLK_MSM_RPMCC_H +/* apq8064 */ +#define RPM_PXO_CLK 0 +#define RPM_PXO_A_CLK 1 +#define RPM_CXO_CLK 2 +#define RPM_CXO_A_CLK 3 +#define RPM_APPS_FABRIC_CLK 4 +#define RPM_APPS_FABRIC_A_CLK 5 +#define RPM_CFPB_CLK 6 +#define RPM_CFPB_A_CLK 7 +#define RPM_QDSS_CLK 8 +#define RPM_QDSS_A_CLK 9 +#define RPM_DAYTONA_FABRIC_CLK 10 +#define RPM_DAYTONA_FABRIC_A_CLK 11 +#define RPM_EBI1_CLK 12 +#define RPM_EBI1_A_CLK 13 +#define RPM_MM_FABRIC_CLK 14 +#define RPM_MM_FABRIC_A_CLK 15 +#define RPM_MMFPB_CLK 16 +#define RPM_MMFPB_A_CLK 17 +#define RPM_SYS_FABRIC_CLK 18 +#define RPM_SYS_FABRIC_A_CLK 19 +#define RPM_SFPB_CLK 20 +#define RPM_SFPB_A_CLK 21 + /* msm8916 */ #define RPM_SMD_XO_CLK_SRC 0 #define RPM_SMD_XO_A_CLK_SRC 1 -- cgit v1.2.3 From 707d33cb0b731472b7564d9fad8d45cbbd7fece3 Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Sat, 29 Oct 2016 14:13:37 +0800 Subject: clk: hisilicon: add CRG driver for Hi3798CV200 SoC Add CRG driver for Hi3798CV200 SoC. CRG(Clock and Reset Generator) module generates clock and reset signals used by other module blocks on SoC. Signed-off-by: Jiancheng Xue Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/hi3519-crg.txt | 46 --- .../devicetree/bindings/clock/hisi-crg.txt | 50 +++ drivers/clk/hisilicon/Kconfig | 8 + drivers/clk/hisilicon/Makefile | 1 + drivers/clk/hisilicon/crg-hi3798cv200.c | 337 +++++++++++++++++++++ drivers/clk/hisilicon/crg.h | 34 +++ include/dt-bindings/clock/histb-clock.h | 66 ++++ 7 files changed, 496 insertions(+), 46 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/hi3519-crg.txt create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt create mode 100644 drivers/clk/hisilicon/crg-hi3798cv200.c create mode 100644 drivers/clk/hisilicon/crg.h create mode 100644 include/dt-bindings/clock/histb-clock.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/hi3519-crg.txt b/Documentation/devicetree/bindings/clock/hi3519-crg.txt deleted file mode 100644 index acd1f235d548..000000000000 --- a/Documentation/devicetree/bindings/clock/hi3519-crg.txt +++ /dev/null @@ -1,46 +0,0 @@ -* Hisilicon Hi3519 Clock and Reset Generator(CRG) - -The Hi3519 CRG module provides clock and reset signals to various -controllers within the SoC. - -This binding uses the following bindings: - Documentation/devicetree/bindings/clock/clock-bindings.txt - Documentation/devicetree/bindings/reset/reset.txt - -Required Properties: - -- compatible: should be one of the following. - - "hisilicon,hi3519-crg" - controller compatible with Hi3519 SoC. - -- 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 . - -- #reset-cells: should be 2. - -A reset signal can be controlled by writing a bit register in the CRG module. -The reset specifier consists of two cells. The first cell represents the -register offset relative to the base address. The second cell represents the -bit index in the register. - -Example: CRG nodes -CRG: clock-reset-controller@12010000 { - compatible = "hisilicon,hi3519-crg"; - reg = <0x12010000 0x10000>; - #clock-cells = <1>; - #reset-cells = <2>; -}; - -Example: consumer nodes -i2c0: i2c@12110000 { - compatible = "hisilicon,hi3519-i2c"; - reg = <0x12110000 0x1000>; - clocks = <&CRG HI3519_I2C0_RST>; - resets = <&CRG 0xe4 0>; -}; diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt new file mode 100644 index 000000000000..cc60b3d423f3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt @@ -0,0 +1,50 @@ +* HiSilicon Clock and Reset Generator(CRG) + +The CRG module provides clock and reset signals to various +modules within the SoC. + +This binding uses the following bindings: + Documentation/devicetree/bindings/clock/clock-bindings.txt + Documentation/devicetree/bindings/reset/reset.txt + +Required Properties: + +- compatible: should be one of the following. + - "hisilicon,hi3516cv300-crg" + - "hisilicon,hi3516cv300-sysctrl" + - "hisilicon,hi3519-crg" + - "hisilicon,hi3798cv200-crg" + - "hisilicon,hi3798cv200-sysctrl" + +- 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 . + +- #reset-cells: should be 2. + +A reset signal can be controlled by writing a bit register in the CRG module. +The reset specifier consists of two cells. The first cell represents the +register offset relative to the base address. The second cell represents the +bit index in the register. + +Example: CRG nodes +CRG: clock-reset-controller@12010000 { + compatible = "hisilicon,hi3519-crg"; + reg = <0x12010000 0x10000>; + #clock-cells = <1>; + #reset-cells = <2>; +}; + +Example: consumer nodes +i2c0: i2c@12110000 { + compatible = "hisilicon,hi3519-i2c"; + reg = <0x12110000 0x1000>; + clocks = <&CRG HI3519_I2C0_RST>; + resets = <&CRG 0xe4 0>; +}; diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index 3f537a04c6a6..c41b6d23e4aa 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -6,6 +6,14 @@ config COMMON_CLK_HI3519 help Build the clock driver for hi3519. +config COMMON_CLK_HI3798CV200 + tristate "Hi3798CV200 Clock Driver" + depends on ARCH_HISI || COMPILE_TEST + select RESET_HISI + default ARCH_HISI + help + Build the clock driver for hi3798cv200. + config COMMON_CLK_HI6220 bool "Hi6220 Clock Driver" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index e169ec7da023..581989111215 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o +obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o obj-$(CONFIG_RESET_HISI) += reset.o obj-$(CONFIG_STUB_CLK_HI6220) += clk-hi6220-stub.o diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c new file mode 100644 index 000000000000..fc8b5bc2d50d --- /dev/null +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -0,0 +1,337 @@ +/* + * Hi3798CV200 Clock and Reset Generator Driver + * + * Copyright (c) 2016 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include "clk.h" +#include "crg.h" +#include "reset.h" + +/* hi3798CV200 core CRG */ +#define HI3798CV200_INNER_CLK_OFFSET 64 +#define HI3798CV200_FIXED_24M 65 +#define HI3798CV200_FIXED_25M 66 +#define HI3798CV200_FIXED_50M 67 +#define HI3798CV200_FIXED_75M 68 +#define HI3798CV200_FIXED_100M 69 +#define HI3798CV200_FIXED_150M 70 +#define HI3798CV200_FIXED_200M 71 +#define HI3798CV200_FIXED_250M 72 +#define HI3798CV200_FIXED_300M 73 +#define HI3798CV200_FIXED_400M 74 +#define HI3798CV200_MMC_MUX 75 +#define HI3798CV200_ETH_PUB_CLK 76 +#define HI3798CV200_ETH_BUS_CLK 77 +#define HI3798CV200_ETH_BUS0_CLK 78 +#define HI3798CV200_ETH_BUS1_CLK 79 +#define HI3798CV200_COMBPHY1_MUX 80 + +#define HI3798CV200_CRG_NR_CLKS 128 + +static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = { + { HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, }, + { HISTB_APB_CLK, "clk_apb", NULL, 0, 100000000, }, + { HISTB_AHB_CLK, "clk_ahb", NULL, 0, 200000000, }, + { HI3798CV200_FIXED_24M, "24m", NULL, 0, 24000000, }, + { HI3798CV200_FIXED_25M, "25m", NULL, 0, 25000000, }, + { HI3798CV200_FIXED_50M, "50m", NULL, 0, 50000000, }, + { HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, }, + { HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, }, + { HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, }, + { HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, }, + { HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, }, +}; + +static const char *const mmc_mux_p[] = { + "100m", "50m", "25m", "200m", "150m" }; +static u32 mmc_mux_table[] = {0, 1, 2, 3, 6}; + +static const char *const comphy1_mux_p[] = { + "100m", "25m"}; +static u32 comphy1_mux_table[] = {2, 3}; + +static struct hisi_mux_clock hi3798cv200_mux_clks[] = { + { HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, }, + { HI3798CV200_COMBPHY1_MUX, "combphy1_mux", + comphy1_mux_p, ARRAY_SIZE(comphy1_mux_p), + CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy1_mux_table, }, +}; + +static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { + /* UART */ + { HISTB_UART2_CLK, "clk_uart2", "75m", + CLK_SET_RATE_PARENT, 0x68, 4, 0, }, + /* I2C */ + { HISTB_I2C0_CLK, "clk_i2c0", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 4, 0, }, + { HISTB_I2C1_CLK, "clk_i2c1", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 8, 0, }, + { HISTB_I2C2_CLK, "clk_i2c2", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 12, 0, }, + { HISTB_I2C3_CLK, "clk_i2c3", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 16, 0, }, + { HISTB_I2C4_CLK, "clk_i2c4", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 20, 0, }, + /* SPI */ + { HISTB_SPI0_CLK, "clk_spi0", "clk_apb", + CLK_SET_RATE_PARENT, 0x70, 0, 0, }, + /* SDIO */ + { HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m", + CLK_SET_RATE_PARENT, 0x9c, 0, 0, }, + { HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "mmc_mux", + CLK_SET_RATE_PARENT, 0x9c, 1, 0, }, + /* EMMC */ + { HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m", + CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, + { HISTB_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", + CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, + /* PCIE*/ + { HISTB_PCIE_BUS_CLK, "clk_pcie_bus", "200m", + CLK_SET_RATE_PARENT, 0x18c, 0, 0, }, + { HISTB_PCIE_SYS_CLK, "clk_pcie_sys", "100m", + CLK_SET_RATE_PARENT, 0x18c, 1, 0, }, + { HISTB_PCIE_PIPE_CLK, "clk_pcie_pipe", "250m", + CLK_SET_RATE_PARENT, 0x18c, 2, 0, }, + { HISTB_PCIE_AUX_CLK, "clk_pcie_aux", "24m", + CLK_SET_RATE_PARENT, 0x18c, 3, 0, }, + /* Ethernet */ + { HI3798CV200_ETH_PUB_CLK, "clk_pub", NULL, + CLK_SET_RATE_PARENT, 0xcc, 5, 0, }, + { HI3798CV200_ETH_BUS_CLK, "clk_bus", "clk_pub", + CLK_SET_RATE_PARENT, 0xcc, 0, 0, }, + { HI3798CV200_ETH_BUS0_CLK, "clk_bus_m0", "clk_bus", + CLK_SET_RATE_PARENT, 0xcc, 1, 0, }, + { HI3798CV200_ETH_BUS1_CLK, "clk_bus_m1", "clk_bus", + CLK_SET_RATE_PARENT, 0xcc, 2, 0, }, + { HISTB_ETH0_MAC_CLK, "clk_mac0", "clk_bus_m0", + CLK_SET_RATE_PARENT, 0xcc, 3, 0, }, + { HISTB_ETH0_MACIF_CLK, "clk_macif0", "clk_bus_m0", + CLK_SET_RATE_PARENT, 0xcc, 24, 0, }, + { HISTB_ETH1_MAC_CLK, "clk_mac1", "clk_bus_m1", + CLK_SET_RATE_PARENT, 0xcc, 4, 0, }, + { HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1", + CLK_SET_RATE_PARENT, 0xcc, 25, 0, }, + /* COMBPHY1 */ + { HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux", + CLK_SET_RATE_PARENT, 0x188, 8, 0, }, +}; + +static struct hisi_clock_data *hi3798cv200_clk_register( + struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3798CV200_CRG_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), + clk_data); + if (ret) + return ERR_PTR(ret); + + ret = hisi_clk_register_mux(hi3798cv200_mux_clks, + ARRAY_SIZE(hi3798cv200_mux_clks), + clk_data); + if (ret) + goto unregister_fixed_rate; + + ret = hisi_clk_register_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), + clk_data); + if (ret) + goto unregister_mux; + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_fixed_rate: + hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), + clk_data); + +unregister_mux: + hisi_clk_unregister_mux(hi3798cv200_mux_clks, + ARRAY_SIZE(hi3798cv200_mux_clks), + clk_data); +unregister_gate: + hisi_clk_unregister_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), + clk_data); + return ERR_PTR(ret); +} + +static void hi3798cv200_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), + crg->clk_data); + hisi_clk_unregister_mux(hi3798cv200_mux_clks, + ARRAY_SIZE(hi3798cv200_mux_clks), + crg->clk_data); + hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), + crg->clk_data); +} + +static const struct hisi_crg_funcs hi3798cv200_crg_funcs = { + .register_clks = hi3798cv200_clk_register, + .unregister_clks = hi3798cv200_clk_unregister, +}; + +/* hi3798CV200 sysctrl CRG */ + +#define HI3798CV200_SYSCTRL_NR_CLKS 16 + +static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = { + { HISTB_IR_CLK, "clk_ir", "100m", + CLK_SET_RATE_PARENT, 0x48, 4, 0, }, + { HISTB_TIMER01_CLK, "clk_timer01", "24m", + CLK_SET_RATE_PARENT, 0x48, 6, 0, }, + { HISTB_UART0_CLK, "clk_uart0", "75m", + CLK_SET_RATE_PARENT, 0x48, 10, 0, }, +}; + +static struct hisi_clock_data *hi3798cv200_sysctrl_clk_register( + struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3798CV200_SYSCTRL_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_gate(hi3798cv200_sysctrl_gate_clks, + ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks), + clk_data); + if (ret) + return ERR_PTR(ret); + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_gate: + hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks, + ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks), + clk_data); + return ERR_PTR(ret); +} + +static void hi3798cv200_sysctrl_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks, + ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks), + crg->clk_data); +} + +static const struct hisi_crg_funcs hi3798cv200_sysctrl_funcs = { + .register_clks = hi3798cv200_sysctrl_clk_register, + .unregister_clks = hi3798cv200_sysctrl_clk_unregister, +}; + +static const struct of_device_id hi3798cv200_crg_match_table[] = { + { .compatible = "hisilicon,hi3798cv200-crg", + .data = &hi3798cv200_crg_funcs }, + { .compatible = "hisilicon,hi3798cv200-sysctrl", + .data = &hi3798cv200_sysctrl_funcs }, + { } +}; +MODULE_DEVICE_TABLE(of, hi3798cv200_crg_match_table); + +static int hi3798cv200_crg_probe(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg; + + crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL); + if (!crg) + return -ENOMEM; + + crg->funcs = of_device_get_match_data(&pdev->dev); + if (!crg->funcs) + return -ENOENT; + + crg->rstc = hisi_reset_init(pdev); + if (!crg->rstc) + return -ENOMEM; + + crg->clk_data = crg->funcs->register_clks(pdev); + if (IS_ERR(crg->clk_data)) { + hisi_reset_exit(crg->rstc); + return PTR_ERR(crg->clk_data); + } + + platform_set_drvdata(pdev, crg); + return 0; +} + +static int hi3798cv200_crg_remove(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + hisi_reset_exit(crg->rstc); + crg->funcs->unregister_clks(pdev); + return 0; +} + +static struct platform_driver hi3798cv200_crg_driver = { + .probe = hi3798cv200_crg_probe, + .remove = hi3798cv200_crg_remove, + .driver = { + .name = "hi3798cv200-crg", + .of_match_table = hi3798cv200_crg_match_table, + }, +}; + +static int __init hi3798cv200_crg_init(void) +{ + return platform_driver_register(&hi3798cv200_crg_driver); +} +core_initcall(hi3798cv200_crg_init); + +static void __exit hi3798cv200_crg_exit(void) +{ + platform_driver_unregister(&hi3798cv200_crg_driver); +} +module_exit(hi3798cv200_crg_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon Hi3798CV200 CRG Driver"); diff --git a/drivers/clk/hisilicon/crg.h b/drivers/clk/hisilicon/crg.h new file mode 100644 index 000000000000..e0739717de9a --- /dev/null +++ b/drivers/clk/hisilicon/crg.h @@ -0,0 +1,34 @@ +/* + * HiSilicon Clock and Reset Driver Header + * + * Copyright (c) 2016 HiSilicon Limited. + * + * 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 __HISI_CRG_H +#define __HISI_CRG_H + +struct hisi_clock_data; +struct hisi_reset_controller; + +struct hisi_crg_funcs { + struct hisi_clock_data* (*register_clks)(struct platform_device *pdev); + void (*unregister_clks)(struct platform_device *pdev); +}; + +struct hisi_crg_dev { + struct hisi_clock_data *clk_data; + struct hisi_reset_controller *rstc; + const struct hisi_crg_funcs *funcs; +}; + +#endif /* __HISI_CRG_H */ diff --git a/include/dt-bindings/clock/histb-clock.h b/include/dt-bindings/clock/histb-clock.h new file mode 100644 index 000000000000..181c0f070f7c --- /dev/null +++ b/include/dt-bindings/clock/histb-clock.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __DTS_HISTB_CLOCK_H +#define __DTS_HISTB_CLOCK_H + +/* clocks provided by core CRG */ +#define HISTB_OSC_CLK 0 +#define HISTB_APB_CLK 1 +#define HISTB_AHB_CLK 2 +#define HISTB_UART1_CLK 3 +#define HISTB_UART2_CLK 4 +#define HISTB_UART3_CLK 5 +#define HISTB_I2C0_CLK 6 +#define HISTB_I2C1_CLK 7 +#define HISTB_I2C2_CLK 8 +#define HISTB_I2C3_CLK 9 +#define HISTB_I2C4_CLK 10 +#define HISTB_I2C5_CLK 11 +#define HISTB_SPI0_CLK 12 +#define HISTB_SPI1_CLK 13 +#define HISTB_SPI2_CLK 14 +#define HISTB_SCI_CLK 15 +#define HISTB_FMC_CLK 16 +#define HISTB_MMC_BIU_CLK 17 +#define HISTB_MMC_CIU_CLK 18 +#define HISTB_MMC_DRV_CLK 19 +#define HISTB_MMC_SAMPLE_CLK 20 +#define HISTB_SDIO0_BIU_CLK 21 +#define HISTB_SDIO0_CIU_CLK 22 +#define HISTB_SDIO0_DRV_CLK 23 +#define HISTB_SDIO0_SAMPLE_CLK 24 +#define HISTB_PCIE_AUX_CLK 25 +#define HISTB_PCIE_PIPE_CLK 26 +#define HISTB_PCIE_SYS_CLK 27 +#define HISTB_PCIE_BUS_CLK 28 +#define HISTB_ETH0_MAC_CLK 29 +#define HISTB_ETH0_MACIF_CLK 30 +#define HISTB_ETH1_MAC_CLK 31 +#define HISTB_ETH1_MACIF_CLK 32 +#define HISTB_COMBPHY1_CLK 33 + + +/* clocks provided by mcu CRG */ +#define HISTB_MCE_CLK 1 +#define HISTB_IR_CLK 2 +#define HISTB_TIMER01_CLK 3 +#define HISTB_LEDC_CLK 4 +#define HISTB_UART0_CLK 5 +#define HISTB_LSADC_CLK 6 + +#endif /* __DTS_HISTB_CLOCK_H */ -- cgit v1.2.3 From aac343ebb35e3428cf3b101cc16f8aa082817b37 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 16 Nov 2016 16:49:21 +0800 Subject: dt-bindings: add documentation for rk1108 cru This adds the dt-binding documentation for the clock and reset unit found on Rockchip rk1108 SoCs. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- .../bindings/clock/rockchip,rk1108-cru.txt | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk1108-cru.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk1108-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk1108-cru.txt new file mode 100644 index 000000000000..4da126116cf0 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk1108-cru.txt @@ -0,0 +1,59 @@ +* Rockchip RK1108 Clock and Reset Unit + +The RK1108 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,rk1108-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/rk1108-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, + - "ext_vip" - external VIP clock - optional + - "ext_i2s" - external I2S clock - optional + - "ext_gmac" - external GMAC clock - optional + - "hdmiphy" - external clock input derived from HDMI PHY - optional + - "usbphy" - external clock input derived from USB PHY - optional + +Example: Clock controller node: + + cru: cru@20200000 { + compatible = "rockchip,rk1108-cru"; + reg = <0x20200000 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@10230000 { + compatible = "rockchip,rk1108-uart", "snps,dw-apb-uart"; + reg = <0x10230000 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>; + }; -- cgit v1.2.3 From 9a81188e4c8abbaab92d5b77850dd855f5487440 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 17 Nov 2016 12:42:52 +0100 Subject: clk: exynos5433: Fix parent clocks for FSYS block The proper parent clock for FSYS block is "aclk_fsys_200" according to the Exynos5433 reference manual. Signed-off-by: Marek Szyprowski Reviewed-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- Documentation/devicetree/bindings/clock/exynos5433-clock.txt | 6 +++--- drivers/clk/samsung/clk-exynos5433.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 63379b04e052..ffff67a0e9cd 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -79,7 +79,7 @@ Required Properties: Input clocks for fsys clock controller: - oscclk - sclk_ufs_mphy - - div_aclk_fsys_200 + - aclk_fsys_200 - sclk_pcie_100_fsys - sclk_ufsunipro_fsys - sclk_mmc2_fsys @@ -235,7 +235,7 @@ Example 2: Examples of clock controller nodes are listed below. clock-names = "oscclk", "sclk_ufs_mphy", - "div_aclk_fsys_200", + "aclk_fsys_200", "sclk_pcie_100_fsys", "sclk_ufsunipro_fsys", "sclk_mmc2_fsys", @@ -245,7 +245,7 @@ Example 2: Examples of clock controller nodes are listed below. "sclk_usbdrd30_fsys"; clocks = <&xxti>, <&cmu_cpif CLK_SCLK_UFS_MPHY>, - <&cmu_top CLK_DIV_ACLK_FSYS_200>, + <&cmu_top CLK_ACLK_FSYS_200>, <&cmu_top CLK_SCLK_PCIE_100_FSYS>, <&cmu_top CLK_SCLK_UFSUNIPRO_FSYS>, <&cmu_top CLK_SCLK_MMC2_FSYS>, diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ea1608682d7f..a8bb60b1f804 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -1929,7 +1929,7 @@ CLK_OF_DECLARE(exynos5433_cmu_peris, "samsung,exynos5433-cmu-peris", /* list of all parent clock list */ PNAME(mout_sclk_ufs_mphy_user_p) = { "oscclk", "sclk_ufs_mphy", }; -PNAME(mout_aclk_fsys_200_user_p) = { "oscclk", "div_aclk_fsys_200", }; +PNAME(mout_aclk_fsys_200_user_p) = { "oscclk", "aclk_fsys_200", }; PNAME(mout_sclk_pcie_100_user_p) = { "oscclk", "sclk_pcie_100_fsys",}; PNAME(mout_sclk_ufsunipro_user_p) = { "oscclk", "sclk_ufsunipro_fsys",}; PNAME(mout_sclk_mmc2_user_p) = { "oscclk", "sclk_mmc2_fsys", }; -- cgit v1.2.3 From 4c9e92df790a2453adbdcebc4d94ef0bc4631d58 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 17 Nov 2016 12:42:53 +0100 Subject: clk: exynos5433: Add documentation for the audio block parent clocks Audio block requires access to two parent clocks: audio PLL and oscillator, so add this information to device tree bindings documentation. Signed-off-by: Marek Szyprowski Reviewed-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- Documentation/devicetree/bindings/clock/exynos5433-clock.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index ffff67a0e9cd..1dc80f8811fe 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -104,6 +104,10 @@ Required Properties: - sclk_decon_tv_vclk_disp - aclk_disp_333 + Input clocks for audio clock controller: + - oscclk + - fout_aud_pll + Input clocks for bus0 clock controller: - aclk_bus0_400 @@ -297,6 +301,9 @@ Example 2: Examples of clock controller nodes are listed below. compatible = "samsung,exynos5433-cmu-aud"; reg = <0x114c0000 0x0b04>; #clock-cells = <1>; + + clock-names = "oscclk", "fout_aud_pll"; + clocks = <&xxti>, <&cmu_top CLK_FOUT_AUD_PLL>; }; cmu_bus0: clock-controller@13600000 { -- cgit v1.2.3