From a8aede7948438f3a9c830a5a865ae6a78c5fc4ca Mon Sep 17 00:00:00 2001 From: James Liao Date: Thu, 23 Apr 2015 10:35:41 +0200 Subject: clk: mediatek: Add basic clocks for Mediatek MT8135. This patch adds basic clocks for MT8135, including TOPCKGEN, PLLs, INFRA and PERI clocks. Signed-off-by: James Liao Signed-off-by: Henry Chen Signed-off-by: Sascha Hauer Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/mt8135-clk.h | 194 +++++++++++++++++++++ .../dt-bindings/reset-controller/mt8135-resets.h | 64 +++++++ 2 files changed, 258 insertions(+) create mode 100644 include/dt-bindings/clock/mt8135-clk.h create mode 100644 include/dt-bindings/reset-controller/mt8135-resets.h (limited to 'include/dt-bindings') diff --git a/include/dt-bindings/clock/mt8135-clk.h b/include/dt-bindings/clock/mt8135-clk.h new file mode 100644 index 000000000000..6dac6c091dd2 --- /dev/null +++ b/include/dt-bindings/clock/mt8135-clk.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: James Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MT8135_H +#define _DT_BINDINGS_CLK_MT8135_H + +/* TOPCKGEN */ + +#define CLK_TOP_DSI0_LNTC_DSICLK 1 +#define CLK_TOP_HDMITX_CLKDIG_CTS 2 +#define CLK_TOP_CLKPH_MCK 3 +#define CLK_TOP_CPUM_TCK_IN 4 +#define CLK_TOP_MAINPLL_806M 5 +#define CLK_TOP_MAINPLL_537P3M 6 +#define CLK_TOP_MAINPLL_322P4M 7 +#define CLK_TOP_MAINPLL_230P3M 8 +#define CLK_TOP_UNIVPLL_624M 9 +#define CLK_TOP_UNIVPLL_416M 10 +#define CLK_TOP_UNIVPLL_249P6M 11 +#define CLK_TOP_UNIVPLL_178P3M 12 +#define CLK_TOP_UNIVPLL_48M 13 +#define CLK_TOP_MMPLL_D2 14 +#define CLK_TOP_MMPLL_D3 15 +#define CLK_TOP_MMPLL_D5 16 +#define CLK_TOP_MMPLL_D7 17 +#define CLK_TOP_MMPLL_D4 18 +#define CLK_TOP_MMPLL_D6 19 +#define CLK_TOP_SYSPLL_D2 20 +#define CLK_TOP_SYSPLL_D4 21 +#define CLK_TOP_SYSPLL_D6 22 +#define CLK_TOP_SYSPLL_D8 23 +#define CLK_TOP_SYSPLL_D10 24 +#define CLK_TOP_SYSPLL_D12 25 +#define CLK_TOP_SYSPLL_D16 26 +#define CLK_TOP_SYSPLL_D24 27 +#define CLK_TOP_SYSPLL_D3 28 +#define CLK_TOP_SYSPLL_D2P5 29 +#define CLK_TOP_SYSPLL_D5 30 +#define CLK_TOP_SYSPLL_D3P5 31 +#define CLK_TOP_UNIVPLL1_D2 32 +#define CLK_TOP_UNIVPLL1_D4 33 +#define CLK_TOP_UNIVPLL1_D6 34 +#define CLK_TOP_UNIVPLL1_D8 35 +#define CLK_TOP_UNIVPLL1_D10 36 +#define CLK_TOP_UNIVPLL2_D2 37 +#define CLK_TOP_UNIVPLL2_D4 38 +#define CLK_TOP_UNIVPLL2_D6 39 +#define CLK_TOP_UNIVPLL2_D8 40 +#define CLK_TOP_UNIVPLL_D3 41 +#define CLK_TOP_UNIVPLL_D5 42 +#define CLK_TOP_UNIVPLL_D7 43 +#define CLK_TOP_UNIVPLL_D10 44 +#define CLK_TOP_UNIVPLL_D26 45 +#define CLK_TOP_APLL 46 +#define CLK_TOP_APLL_D4 47 +#define CLK_TOP_APLL_D8 48 +#define CLK_TOP_APLL_D16 49 +#define CLK_TOP_APLL_D24 50 +#define CLK_TOP_LVDSPLL_D2 51 +#define CLK_TOP_LVDSPLL_D4 52 +#define CLK_TOP_LVDSPLL_D8 53 +#define CLK_TOP_LVDSTX_CLKDIG_CT 54 +#define CLK_TOP_VPLL_DPIX 55 +#define CLK_TOP_TVHDMI_H 56 +#define CLK_TOP_HDMITX_CLKDIG_D2 57 +#define CLK_TOP_HDMITX_CLKDIG_D3 58 +#define CLK_TOP_TVHDMI_D2 59 +#define CLK_TOP_TVHDMI_D4 60 +#define CLK_TOP_MEMPLL_MCK_D4 61 +#define CLK_TOP_AXI_SEL 62 +#define CLK_TOP_SMI_SEL 63 +#define CLK_TOP_MFG_SEL 64 +#define CLK_TOP_IRDA_SEL 65 +#define CLK_TOP_CAM_SEL 66 +#define CLK_TOP_AUD_INTBUS_SEL 67 +#define CLK_TOP_JPG_SEL 68 +#define CLK_TOP_DISP_SEL 69 +#define CLK_TOP_MSDC30_1_SEL 70 +#define CLK_TOP_MSDC30_2_SEL 71 +#define CLK_TOP_MSDC30_3_SEL 72 +#define CLK_TOP_MSDC30_4_SEL 73 +#define CLK_TOP_USB20_SEL 74 +#define CLK_TOP_VENC_SEL 75 +#define CLK_TOP_SPI_SEL 76 +#define CLK_TOP_UART_SEL 77 +#define CLK_TOP_MEM_SEL 78 +#define CLK_TOP_CAMTG_SEL 79 +#define CLK_TOP_AUDIO_SEL 80 +#define CLK_TOP_FIX_SEL 81 +#define CLK_TOP_VDEC_SEL 82 +#define CLK_TOP_DDRPHYCFG_SEL 83 +#define CLK_TOP_DPILVDS_SEL 84 +#define CLK_TOP_PMICSPI_SEL 85 +#define CLK_TOP_MSDC30_0_SEL 86 +#define CLK_TOP_SMI_MFG_AS_SEL 87 +#define CLK_TOP_GCPU_SEL 88 +#define CLK_TOP_DPI1_SEL 89 +#define CLK_TOP_CCI_SEL 90 +#define CLK_TOP_APLL_SEL 91 +#define CLK_TOP_HDMIPLL_SEL 92 +#define CLK_TOP_NR_CLK 93 + +/* APMIXED_SYS */ + +#define CLK_APMIXED_ARMPLL1 1 +#define CLK_APMIXED_ARMPLL2 2 +#define CLK_APMIXED_MAINPLL 3 +#define CLK_APMIXED_UNIVPLL 4 +#define CLK_APMIXED_MMPLL 5 +#define CLK_APMIXED_MSDCPLL 6 +#define CLK_APMIXED_TVDPLL 7 +#define CLK_APMIXED_LVDSPLL 8 +#define CLK_APMIXED_AUDPLL 9 +#define CLK_APMIXED_VDECPLL 10 +#define CLK_APMIXED_NR_CLK 11 + +/* INFRA_SYS */ + +#define CLK_INFRA_PMIC_WRAP 1 +#define CLK_INFRA_PMICSPI 2 +#define CLK_INFRA_CCIF1_AP_CTRL 3 +#define CLK_INFRA_CCIF0_AP_CTRL 4 +#define CLK_INFRA_KP 5 +#define CLK_INFRA_CPUM 6 +#define CLK_INFRA_M4U 7 +#define CLK_INFRA_MFGAXI 8 +#define CLK_INFRA_DEVAPC 9 +#define CLK_INFRA_AUDIO 10 +#define CLK_INFRA_MFG_BUS 11 +#define CLK_INFRA_SMI 12 +#define CLK_INFRA_DBGCLK 13 +#define CLK_INFRA_NR_CLK 14 + +/* PERI_SYS */ + +#define CLK_PERI_I2C5 1 +#define CLK_PERI_I2C4 2 +#define CLK_PERI_I2C3 3 +#define CLK_PERI_I2C2 4 +#define CLK_PERI_I2C1 5 +#define CLK_PERI_I2C0 6 +#define CLK_PERI_UART3 7 +#define CLK_PERI_UART2 8 +#define CLK_PERI_UART1 9 +#define CLK_PERI_UART0 10 +#define CLK_PERI_IRDA 11 +#define CLK_PERI_NLI 12 +#define CLK_PERI_MD_HIF 13 +#define CLK_PERI_AP_HIF 14 +#define CLK_PERI_MSDC30_3 15 +#define CLK_PERI_MSDC30_2 16 +#define CLK_PERI_MSDC30_1 17 +#define CLK_PERI_MSDC20_2 18 +#define CLK_PERI_MSDC20_1 19 +#define CLK_PERI_AP_DMA 20 +#define CLK_PERI_USB1 21 +#define CLK_PERI_USB0 22 +#define CLK_PERI_PWM 23 +#define CLK_PERI_PWM7 24 +#define CLK_PERI_PWM6 25 +#define CLK_PERI_PWM5 26 +#define CLK_PERI_PWM4 27 +#define CLK_PERI_PWM3 28 +#define CLK_PERI_PWM2 29 +#define CLK_PERI_PWM1 30 +#define CLK_PERI_THERM 31 +#define CLK_PERI_NFI 32 +#define CLK_PERI_USBSLV 33 +#define CLK_PERI_USB1_MCU 34 +#define CLK_PERI_USB0_MCU 35 +#define CLK_PERI_GCPU 36 +#define CLK_PERI_FHCTL 37 +#define CLK_PERI_SPI1 38 +#define CLK_PERI_AUXADC 39 +#define CLK_PERI_PERI_PWRAP 40 +#define CLK_PERI_I2C6 41 +#define CLK_PERI_UART0_SEL 42 +#define CLK_PERI_UART1_SEL 43 +#define CLK_PERI_UART2_SEL 44 +#define CLK_PERI_UART3_SEL 45 +#define CLK_PERI_NR_CLK 46 + +#endif /* _DT_BINDINGS_CLK_MT8135_H */ diff --git a/include/dt-bindings/reset-controller/mt8135-resets.h b/include/dt-bindings/reset-controller/mt8135-resets.h new file mode 100644 index 000000000000..1fb629508db2 --- /dev/null +++ b/include/dt-bindings/reset-controller/mt8135-resets.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Flora Fu, MediaTek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8135 +#define _DT_BINDINGS_RESET_CONTROLLER_MT8135 + +/* INFRACFG resets */ +#define MT8135_INFRA_EMI_REG_RST 0 +#define MT8135_INFRA_DRAMC0_A0_RST 1 +#define MT8135_INFRA_CCIF0_RST 2 +#define MT8135_INFRA_APCIRQ_EINT_RST 3 +#define MT8135_INFRA_APXGPT_RST 4 +#define MT8135_INFRA_SCPSYS_RST 5 +#define MT8135_INFRA_CCIF1_RST 6 +#define MT8135_INFRA_PMIC_WRAP_RST 7 +#define MT8135_INFRA_KP_RST 8 +#define MT8135_INFRA_EMI_RST 32 +#define MT8135_INFRA_DRAMC0_RST 34 +#define MT8135_INFRA_SMI_RST 35 +#define MT8135_INFRA_M4U_RST 36 + +/* PERICFG resets */ +#define MT8135_PERI_UART0_SW_RST 0 +#define MT8135_PERI_UART1_SW_RST 1 +#define MT8135_PERI_UART2_SW_RST 2 +#define MT8135_PERI_UART3_SW_RST 3 +#define MT8135_PERI_IRDA_SW_RST 4 +#define MT8135_PERI_PTP_SW_RST 5 +#define MT8135_PERI_AP_HIF_SW_RST 6 +#define MT8135_PERI_GPCU_SW_RST 7 +#define MT8135_PERI_MD_HIF_SW_RST 8 +#define MT8135_PERI_NLI_SW_RST 9 +#define MT8135_PERI_AUXADC_SW_RST 10 +#define MT8135_PERI_DMA_SW_RST 11 +#define MT8135_PERI_NFI_SW_RST 14 +#define MT8135_PERI_PWM_SW_RST 15 +#define MT8135_PERI_THERM_SW_RST 16 +#define MT8135_PERI_MSDC0_SW_RST 17 +#define MT8135_PERI_MSDC1_SW_RST 18 +#define MT8135_PERI_MSDC2_SW_RST 19 +#define MT8135_PERI_MSDC3_SW_RST 20 +#define MT8135_PERI_I2C0_SW_RST 22 +#define MT8135_PERI_I2C1_SW_RST 23 +#define MT8135_PERI_I2C2_SW_RST 24 +#define MT8135_PERI_I2C3_SW_RST 25 +#define MT8135_PERI_I2C4_SW_RST 26 +#define MT8135_PERI_I2C5_SW_RST 27 +#define MT8135_PERI_I2C6_SW_RST 28 +#define MT8135_PERI_USB_SW_RST 29 +#define MT8135_PERI_SPI1_SW_RST 33 +#define MT8135_PERI_PWRAP_BRIDGE_SW_RST 34 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8135 */ -- cgit v1.2.3 From c1e81a3bef36cb046c079480948fa3e0eca590d6 Mon Sep 17 00:00:00 2001 From: James Liao Date: Thu, 23 Apr 2015 10:35:42 +0200 Subject: clk: mediatek: Add basic clocks for Mediatek MT8173. This patch adds basic clocks for MT8173, including TOPCKGEN, PLLs, INFRA and PERI clocks. Signed-off-by: James Liao Signed-off-by: Henry Chen Signed-off-by: Sascha Hauer Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8173.c | 830 +++++++++++++++++++++ include/dt-bindings/clock/mt8173-clk.h | 235 ++++++ .../dt-bindings/reset-controller/mt8173-resets.h | 63 ++ 4 files changed, 1129 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8173.c create mode 100644 include/dt-bindings/clock/mt8173-clk.h create mode 100644 include/dt-bindings/reset-controller/mt8173-resets.h (limited to 'include/dt-bindings') diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 12ce576e628a..8e4b2a4635b9 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,3 +1,4 @@ obj-y += clk-mtk.o clk-pll.o clk-gate.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o obj-y += clk-mt8135.o +obj-y += clk-mt8173.o diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c new file mode 100644 index 000000000000..357b080eb04f --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -0,0 +1,830 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: James Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include + +static DEFINE_SPINLOCK(mt8173_clk_lock); + +static const struct mtk_fixed_factor root_clk_alias[] __initconst = { + FACTOR(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", "clk_null", 1, 1), + FACTOR(CLK_TOP_DPI, "dpi_ck", "clk_null", 1, 1), + FACTOR(CLK_TOP_USB_SYSPLL_125M, "usb_syspll_125m", "clk_null", 1, 1), + FACTOR(CLK_TOP_HDMITX_DIG_CTS, "hdmitx_dig_cts", "clk_null", 1, 1), +}; + +static const struct mtk_fixed_factor top_divs[] __initconst = { + FACTOR(CLK_TOP_ARMCA7PLL_754M, "armca7pll_754m", "armca7pll", 1, 2), + FACTOR(CLK_TOP_ARMCA7PLL_502M, "armca7pll_502m", "armca7pll", 1, 3), + + FACTOR(CLK_TOP_MAIN_H546M, "main_h546m", "mainpll", 1, 2), + FACTOR(CLK_TOP_MAIN_H364M, "main_h364m", "mainpll", 1, 3), + FACTOR(CLK_TOP_MAIN_H218P4M, "main_h218p4m", "mainpll", 1, 5), + FACTOR(CLK_TOP_MAIN_H156M, "main_h156m", "mainpll", 1, 7), + + FACTOR(CLK_TOP_TVDPLL_445P5M, "tvdpll_445p5m", "tvdpll", 1, 4), + FACTOR(CLK_TOP_TVDPLL_594M, "tvdpll_594m", "tvdpll", 1, 3), + + FACTOR(CLK_TOP_UNIV_624M, "univ_624m", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIV_416M, "univ_416m", "univpll", 1, 3), + FACTOR(CLK_TOP_UNIV_249P6M, "univ_249p6m", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIV_178P3M, "univ_178p3m", "univpll", 1, 7), + FACTOR(CLK_TOP_UNIV_48M, "univ_48m", "univpll", 1, 26), + + FACTOR(CLK_TOP_CLKRTC_EXT, "clkrtc_ext", "clk32k", 1, 1), + FACTOR(CLK_TOP_CLKRTC_INT, "clkrtc_int", "clk26m", 1, 793), + FACTOR(CLK_TOP_FPC, "fpc_ck", "clk26m", 1, 1), + + FACTOR(CLK_TOP_HDMITXPLL_D2, "hdmitxpll_d2", "hdmitx_dig_cts", 1, 2), + FACTOR(CLK_TOP_HDMITXPLL_D3, "hdmitxpll_d3", "hdmitx_dig_cts", 1, 3), + + FACTOR(CLK_TOP_ARMCA7PLL_D2, "armca7pll_d2", "armca7pll_754m", 1, 1), + FACTOR(CLK_TOP_ARMCA7PLL_D3, "armca7pll_d3", "armca7pll_502m", 1, 1), + + FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1), + FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1), + + FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "clkph_mck_o", 1, 1), + FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2), + FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4), + FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8), + FACTOR(CLK_TOP_DMPLL_D16, "dmpll_d16", "clkph_mck_o", 1, 16), + + FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2), + FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4), + FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8), + + FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), + + FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), + FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4), + FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, 1), + FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2", 1, 2), + FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2", 1, 4), + + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "main_h546m", 1, 1), + FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "main_h546m", 1, 2), + FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "main_h546m", 1, 4), + FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "main_h546m", 1, 8), + FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "main_h546m", 1, 16), + FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "main_h364m", 1, 1), + FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "main_h364m", 1, 2), + FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "main_h364m", 1, 4), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "main_h218p4m", 1, 1), + FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "main_h218p4m", 1, 2), + FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "main_h218p4m", 1, 4), + FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "main_h156m", 1, 1), + FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "main_h156m", 1, 2), + FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "main_h156m", 1, 4), + + FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll_594m", 1, 1), + FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_594m", 1, 2), + FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_594m", 1, 4), + FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_594m", 1, 8), + FACTOR(CLK_TOP_TVDPLL_D16, "tvdpll_d16", "tvdpll_594m", 1, 16), + + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univ_624m", 1, 1), + FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univ_624m", 1, 2), + FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univ_624m", 1, 4), + FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univ_624m", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univ_416m", 1, 1), + FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univ_416m", 1, 2), + FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univ_416m", 1, 4), + FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univ_416m", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univ_249p6m", 1, 1), + FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univ_249p6m", 1, 2), + FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univ_249p6m", 1, 4), + FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univ_249p6m", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univ_178p3m", 1, 1), + FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univ_48m", 1, 1), + FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univ_48m", 1, 2), + + FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, 3), + FACTOR(CLK_TOP_VCODECPLL_370P5, "vcodecpll_370p5", "vcodecpll", 1, 4), + + FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, 1), + FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll", 1, 2), + FACTOR(CLK_TOP_VENCPLL_D4, "vencpll_d4", "vencpll", 1, 4), +}; + +static const char * const axi_parents[] __initconst = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const mem_parents[] __initconst = { + "clk26m", + "dmpll_ck" +}; + +static const char * const ddrphycfg_parents[] __initconst = { + "clk26m", + "syspll1_d8" +}; + +static const char * const mm_parents[] __initconst = { + "clk26m", + "vencpll_d2", + "main_h364m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll1_d2", + "univpll2_d2", + "dmpll_d2" +}; + +static const char * const pwm_parents[] __initconst = { + "clk26m", + "univpll2_d4", + "univpll3_d2", + "univpll1_d4" +}; + +static const char * const vdec_parents[] __initconst = { + "clk26m", + "vcodecpll_ck", + "tvdpll_445p5m", + "univpll_d3", + "vencpll_d2", + "syspll_d3", + "univpll1_d2", + "mmpll_d2", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const venc_parents[] __initconst = { + "clk26m", + "vcodecpll_ck", + "tvdpll_445p5m", + "univpll_d3", + "vencpll_d2", + "syspll_d3", + "univpll1_d2", + "univpll2_d2", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const mfg_parents[] __initconst = { + "clk26m", + "mmpll_ck", + "dmpll_ck", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "syspll_d3", + "syspll1_d2", + "syspll_d5", + "univpll_d3", + "univpll1_d2", + "univpll_d5", + "univpll2_d2" +}; + +static const char * const camtg_parents[] __initconst = { + "clk26m", + "univpll_d26", + "univpll2_d2", + "syspll3_d2", + "syspll3_d4", + "univpll1_d4" +}; + +static const char * const uart_parents[] __initconst = { + "clk26m", + "univpll2_d8" +}; + +static const char * const spi_parents[] __initconst = { + "clk26m", + "syspll3_d2", + "syspll1_d4", + "syspll4_d2", + "univpll3_d2", + "univpll2_d4", + "univpll1_d8" +}; + +static const char * const usb20_parents[] __initconst = { + "clk26m", + "univpll1_d8", + "univpll3_d4" +}; + +static const char * const usb30_parents[] __initconst = { + "clk26m", + "univpll3_d2", + "usb_syspll_125m", + "univpll2_d4" +}; + +static const char * const msdc50_0_h_parents[] __initconst = { + "clk26m", + "syspll1_d2", + "syspll2_d2", + "syspll4_d2", + "univpll_d5", + "univpll1_d4" +}; + +static const char * const msdc50_0_parents[] __initconst = { + "clk26m", + "msdcpll_ck", + "msdcpll_d2", + "univpll1_d4", + "syspll2_d2", + "syspll_d7", + "msdcpll_d4", + "vencpll_d4", + "tvdpll_ck", + "univpll_d2", + "univpll1_d2", + "mmpll_ck", + "msdcpll2_ck", + "msdcpll2_d2", + "msdcpll2_d4" +}; + +static const char * const msdc30_1_parents[] __initconst = { + "clk26m", + "univpll2_d2", + "msdcpll_d4", + "univpll1_d4", + "syspll2_d2", + "syspll_d7", + "univpll_d7", + "vencpll_d4" +}; + +static const char * const msdc30_2_parents[] __initconst = { + "clk26m", + "univpll2_d2", + "msdcpll_d4", + "univpll1_d4", + "syspll2_d2", + "syspll_d7", + "univpll_d7", + "vencpll_d2" +}; + +static const char * const msdc30_3_parents[] __initconst = { + "clk26m", + "msdcpll2_ck", + "msdcpll2_d2", + "univpll2_d2", + "msdcpll2_d4", + "msdcpll_d4", + "univpll1_d4", + "syspll2_d2", + "syspll_d7", + "univpll_d7", + "vencpll_d4", + "msdcpll_ck", + "msdcpll_d2", + "msdcpll_d4" +}; + +static const char * const audio_parents[] __initconst = { + "clk26m", + "syspll3_d4", + "syspll4_d4", + "syspll1_d16" +}; + +static const char * const aud_intbus_parents[] __initconst = { + "clk26m", + "syspll1_d4", + "syspll4_d2", + "univpll3_d2", + "univpll2_d8", + "dmpll_d4", + "dmpll_d8" +}; + +static const char * const pmicspi_parents[] __initconst = { + "clk26m", + "syspll1_d8", + "syspll3_d4", + "syspll1_d16", + "univpll3_d4", + "univpll_d26", + "dmpll_d8", + "dmpll_d16" +}; + +static const char * const scp_parents[] __initconst = { + "clk26m", + "syspll1_d2", + "univpll_d5", + "syspll_d5", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const atb_parents[] __initconst = { + "clk26m", + "syspll1_d2", + "univpll_d5", + "dmpll_d2" +}; + +static const char * const venc_lt_parents[] __initconst = { + "clk26m", + "univpll_d3", + "vcodecpll_ck", + "tvdpll_445p5m", + "vencpll_d2", + "syspll_d3", + "univpll1_d2", + "univpll2_d2", + "syspll1_d2", + "univpll_d5", + "vcodecpll_370p5", + "dmpll_ck" +}; + +static const char * const dpi0_parents[] __initconst = { + "clk26m", + "tvdpll_d2", + "tvdpll_d4", + "clk26m", + "clk26m", + "tvdpll_d8", + "tvdpll_d16" +}; + +static const char * const irda_parents[] __initconst = { + "clk26m", + "univpll2_d4", + "syspll2_d4" +}; + +static const char * const cci400_parents[] __initconst = { + "clk26m", + "vencpll_ck", + "armca7pll_754m", + "armca7pll_502m", + "univpll_d2", + "syspll_d2", + "msdcpll_ck", + "dmpll_ck" +}; + +static const char * const aud_1_parents[] __initconst = { + "clk26m", + "apll1_ck", + "univpll2_d4", + "univpll2_d8" +}; + +static const char * const aud_2_parents[] __initconst = { + "clk26m", + "apll2_ck", + "univpll2_d4", + "univpll2_d8" +}; + +static const char * const mem_mfg_in_parents[] __initconst = { + "clk26m", + "mmpll_ck", + "dmpll_ck", + "clk26m" +}; + +static const char * const axi_mfg_in_parents[] __initconst = { + "clk26m", + "axi_sel", + "dmpll_d2" +}; + +static const char * const scam_parents[] __initconst = { + "clk26m", + "syspll3_d2", + "univpll2_d4", + "dmpll_d4" +}; + +static const char * const spinfi_ifr_parents[] __initconst = { + "clk26m", + "univpll2_d8", + "univpll3_d4", + "syspll4_d2", + "univpll2_d4", + "univpll3_d2", + "syspll1_d4", + "univpll1_d4" +}; + +static const char * const hdmi_parents[] __initconst = { + "clk26m", + "hdmitx_dig_cts", + "hdmitxpll_d2", + "hdmitxpll_d3" +}; + +static const char * const dpilvds_parents[] __initconst = { + "clk26m", + "lvdspll", + "lvdspll_d2", + "lvdspll_d4", + "lvdspll_d8", + "fpc_ck" +}; + +static const char * const msdc50_2_h_parents[] __initconst = { + "clk26m", + "syspll1_d2", + "syspll2_d2", + "syspll4_d2", + "univpll_d5", + "univpll1_d4" +}; + +static const char * const hdcp_parents[] __initconst = { + "clk26m", + "syspll4_d2", + "syspll3_d4", + "univpll2_d4" +}; + +static const char * const hdcp_24m_parents[] __initconst = { + "clk26m", + "univpll_d26", + "univpll_d52", + "univpll2_d8" +}; + +static const char * const rtc_parents[] __initconst = { + "clkrtc_int", + "clkrtc_ext", + "clk26m", + "univpll3_d8" +}; + +static const char * const i2s0_m_ck_parents[] __initconst = { + "apll1_div1", + "apll2_div1" +}; + +static const char * const i2s1_m_ck_parents[] __initconst = { + "apll1_div2", + "apll2_div2" +}; + +static const char * const i2s2_m_ck_parents[] __initconst = { + "apll1_div3", + "apll2_div3" +}; + +static const char * const i2s3_m_ck_parents[] __initconst = { + "apll1_div4", + "apll2_div4" +}; + +static const char * const i2s3_b_ck_parents[] __initconst = { + "apll1_div5", + "apll2_div5" +}; + +static const struct mtk_composite top_muxes[] __initconst = { + /* CLK_CFG_0 */ + MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3), + MUX(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1), + MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23), + MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 4, 31), + /* CLK_CFG_1 */ + MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7), + MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15), + MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0050, 16, 4, 23), + MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 24, 4, 31), + /* CLK_CFG_2 */ + MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0060, 0, 3, 7), + MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 8, 1, 15), + MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0060, 16, 3, 23), + MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 24, 2, 31), + /* CLK_CFG_3 */ + MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", usb30_parents, 0x0070, 0, 2, 7), + MUX_GATE(CLK_TOP_MSDC50_0_H_SEL, "msdc50_0_h_sel", msdc50_0_h_parents, 0x0070, 8, 3, 15), + MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_parents, 0x0070, 16, 4, 23), + MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents, 0x0070, 24, 3, 31), + /* CLK_CFG_4 */ + MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_2_parents, 0x0080, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_parents, 0x0080, 8, 4, 15), + MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, 0x0080, 16, 2, 23), + MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0080, 24, 3, 31), + /* CLK_CFG_5 */ + MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0090, 0, 3, 7 /* 7:5 */), + MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0090, 8, 3, 15), + MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x0090, 16, 2, 23), + MUX_GATE(CLK_TOP_VENC_LT_SEL, "venclt_sel", venc_lt_parents, 0x0090, 24, 4, 31), + /* CLK_CFG_6 */ + MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x00a0, 0, 3, 7), + MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x00a0, 8, 2, 15), + MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", cci400_parents, 0x00a0, 16, 3, 23), + MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x00a0, 24, 2, 31), + /* CLK_CFG_7 */ + MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", aud_2_parents, 0x00b0, 0, 2, 7), + MUX_GATE(CLK_TOP_MEM_MFG_IN_SEL, "mem_mfg_in_sel", mem_mfg_in_parents, 0x00b0, 8, 2, 15), + MUX_GATE(CLK_TOP_AXI_MFG_IN_SEL, "axi_mfg_in_sel", axi_mfg_in_parents, 0x00b0, 16, 2, 23), + MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", scam_parents, 0x00b0, 24, 2, 31), + /* CLK_CFG_12 */ + MUX_GATE(CLK_TOP_SPINFI_IFR_SEL, "spinfi_ifr_sel", spinfi_ifr_parents, 0x00c0, 0, 3, 7), + MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x00c0, 8, 2, 15), + MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x00c0, 24, 3, 31), + /* CLK_CFG_13 */ + MUX_GATE(CLK_TOP_MSDC50_2_H_SEL, "msdc50_2_h_sel", msdc50_2_h_parents, 0x00d0, 0, 3, 7), + MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", hdcp_parents, 0x00d0, 8, 2, 15), + MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", hdcp_24m_parents, 0x00d0, 16, 2, 23), + MUX(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00d0, 24, 2), + + DIV_GATE(CLK_TOP_APLL1_DIV0, "apll1_div0", "aud_1_sel", 0x12c, 8, 0x120, 4, 24), + DIV_GATE(CLK_TOP_APLL1_DIV1, "apll1_div1", "aud_1_sel", 0x12c, 9, 0x124, 8, 0), + DIV_GATE(CLK_TOP_APLL1_DIV2, "apll1_div2", "aud_1_sel", 0x12c, 10, 0x124, 8, 8), + DIV_GATE(CLK_TOP_APLL1_DIV3, "apll1_div3", "aud_1_sel", 0x12c, 11, 0x124, 8, 16), + DIV_GATE(CLK_TOP_APLL1_DIV4, "apll1_div4", "aud_1_sel", 0x12c, 12, 0x124, 8, 24), + DIV_GATE(CLK_TOP_APLL1_DIV5, "apll1_div5", "apll1_div4", 0x12c, 13, 0x12c, 4, 0), + + DIV_GATE(CLK_TOP_APLL2_DIV0, "apll2_div0", "aud_2_sel", 0x12c, 16, 0x120, 4, 28), + DIV_GATE(CLK_TOP_APLL2_DIV1, "apll2_div1", "aud_2_sel", 0x12c, 17, 0x128, 8, 0), + DIV_GATE(CLK_TOP_APLL2_DIV2, "apll2_div2", "aud_2_sel", 0x12c, 18, 0x128, 8, 8), + DIV_GATE(CLK_TOP_APLL2_DIV3, "apll2_div3", "aud_2_sel", 0x12c, 19, 0x128, 8, 16), + DIV_GATE(CLK_TOP_APLL2_DIV4, "apll2_div4", "aud_2_sel", 0x12c, 20, 0x128, 8, 24), + DIV_GATE(CLK_TOP_APLL2_DIV5, "apll2_div5", "apll2_div4", 0x12c, 21, 0x12c, 4, 4), + + MUX(CLK_TOP_I2S0_M_SEL, "i2s0_m_ck_sel", i2s0_m_ck_parents, 0x120, 4, 1), + MUX(CLK_TOP_I2S1_M_SEL, "i2s1_m_ck_sel", i2s1_m_ck_parents, 0x120, 5, 1), + MUX(CLK_TOP_I2S2_M_SEL, "i2s2_m_ck_sel", i2s2_m_ck_parents, 0x120, 6, 1), + MUX(CLK_TOP_I2S3_M_SEL, "i2s3_m_ck_sel", i2s3_m_ck_parents, 0x120, 7, 1), + MUX(CLK_TOP_I2S3_B_SEL, "i2s3_b_ck_sel", i2s3_b_ck_parents, 0x120, 8, 1), +}; + +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x0040, + .clr_ofs = 0x0044, + .sta_ofs = 0x0048, +}; + +#define GATE_ICG(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate infra_clks[] __initconst = { + GATE_ICG(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0), + GATE_ICG(CLK_INFRA_SMI, "infra_smi", "mm_sel", 1), + GATE_ICG(CLK_INFRA_AUDIO, "infra_audio", "aud_intbus_sel", 5), + GATE_ICG(CLK_INFRA_GCE, "infra_gce", "axi_sel", 6), + GATE_ICG(CLK_INFRA_L2C_SRAM, "infra_l2c_sram", "axi_sel", 7), + GATE_ICG(CLK_INFRA_M4U, "infra_m4u", "mem_sel", 8), + GATE_ICG(CLK_INFRA_CPUM, "infra_cpum", "clk_null", 15), + GATE_ICG(CLK_INFRA_KP, "infra_kp", "axi_sel", 16), + GATE_ICG(CLK_INFRA_CEC, "infra_cec", "clk26m", 18), + GATE_ICG(CLK_INFRA_PMICSPI, "infra_pmicspi", "pmicspi_sel", 22), + GATE_ICG(CLK_INFRA_PMICWRAP, "infra_pmicwrap", "axi_sel", 23), +}; + +static const struct mtk_gate_regs peri0_cg_regs = { + .set_ofs = 0x0008, + .clr_ofs = 0x0010, + .sta_ofs = 0x0018, +}; + +static const struct mtk_gate_regs peri1_cg_regs = { + .set_ofs = 0x000c, + .clr_ofs = 0x0014, + .sta_ofs = 0x001c, +}; + +#define GATE_PERI0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_PERI1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate peri_gates[] __initconst = { + /* PERI0 */ + GATE_PERI0(CLK_PERI_NFI, "peri_nfi", "axi_sel", 0), + GATE_PERI0(CLK_PERI_THERM, "peri_therm", "axi_sel", 1), + GATE_PERI0(CLK_PERI_PWM1, "peri_pwm1", "axi_sel", 2), + GATE_PERI0(CLK_PERI_PWM2, "peri_pwm2", "axi_sel", 3), + GATE_PERI0(CLK_PERI_PWM3, "peri_pwm3", "axi_sel", 4), + GATE_PERI0(CLK_PERI_PWM4, "peri_pwm4", "axi_sel", 5), + GATE_PERI0(CLK_PERI_PWM5, "peri_pwm5", "axi_sel", 6), + GATE_PERI0(CLK_PERI_PWM6, "peri_pwm6", "axi_sel", 7), + GATE_PERI0(CLK_PERI_PWM7, "peri_pwm7", "axi_sel", 8), + GATE_PERI0(CLK_PERI_PWM, "peri_pwm", "axi_sel", 9), + GATE_PERI0(CLK_PERI_USB0, "peri_usb0", "usb20_sel", 10), + GATE_PERI0(CLK_PERI_USB1, "peri_usb1", "usb20_sel", 11), + GATE_PERI0(CLK_PERI_AP_DMA, "peri_ap_dma", "axi_sel", 12), + GATE_PERI0(CLK_PERI_MSDC30_0, "peri_msdc30_0", "msdc50_0_sel", 13), + GATE_PERI0(CLK_PERI_MSDC30_1, "peri_msdc30_1", "msdc30_1_sel", 14), + GATE_PERI0(CLK_PERI_MSDC30_2, "peri_msdc30_2", "msdc30_2_sel", 15), + GATE_PERI0(CLK_PERI_MSDC30_3, "peri_msdc30_3", "msdc30_3_sel", 16), + GATE_PERI0(CLK_PERI_NLI_ARB, "peri_nli_arb", "axi_sel", 17), + GATE_PERI0(CLK_PERI_IRDA, "peri_irda", "irda_sel", 18), + GATE_PERI0(CLK_PERI_UART0, "peri_uart0", "axi_sel", 19), + GATE_PERI0(CLK_PERI_UART1, "peri_uart1", "axi_sel", 20), + GATE_PERI0(CLK_PERI_UART2, "peri_uart2", "axi_sel", 21), + GATE_PERI0(CLK_PERI_UART3, "peri_uart3", "axi_sel", 22), + GATE_PERI0(CLK_PERI_I2C0, "peri_i2c0", "axi_sel", 23), + GATE_PERI0(CLK_PERI_I2C1, "peri_i2c1", "axi_sel", 24), + GATE_PERI0(CLK_PERI_I2C2, "peri_i2c2", "axi_sel", 25), + GATE_PERI0(CLK_PERI_I2C3, "peri_i2c3", "axi_sel", 26), + GATE_PERI0(CLK_PERI_I2C4, "peri_i2c4", "axi_sel", 27), + GATE_PERI0(CLK_PERI_AUXADC, "peri_auxadc", "clk26m", 28), + GATE_PERI0(CLK_PERI_SPI0, "peri_spi0", "spi_sel", 29), + GATE_PERI0(CLK_PERI_I2C5, "peri_i2c5", "axi_sel", 30), + GATE_PERI0(CLK_PERI_NFIECC, "peri_nfiecc", "axi_sel", 31), + /* PERI1 */ + GATE_PERI1(CLK_PERI_SPI, "peri_spi", "spi_sel", 0), + GATE_PERI1(CLK_PERI_IRRX, "peri_irrx", "spi_sel", 1), + GATE_PERI1(CLK_PERI_I2C6, "peri_i2c6", "axi_sel", 2), +}; + +static const char * const uart_ck_sel_parents[] __initconst = { + "clk26m", + "uart_sel", +}; + +static const struct mtk_composite peri_clks[] __initconst = { + MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1), + MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1), + MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1), + MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1), +}; + +static void __init mtk_topckgen_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + void __iomem *base; + int r; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return; + } + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + + mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data); + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); + mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, + &mt8173_clk_lock, clk_data); + + clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init); + +static void __init mtk_infrasys_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + + clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); + + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + mtk_register_reset_controller(node, 2, 0x30); +} +CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8173-infracfg", mtk_infrasys_init); + +static void __init mtk_pericfg_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return; + } + + clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); + + mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates), + clk_data); + mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base, + &mt8173_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + mtk_register_reset_controller(node, 2, 0); +} +CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init); + +#define MT8173_PLL_FMAX (3000UL * MHZ) + +#define CON0_MT8173_RST_BAR BIT(24) + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \ + _tuner_reg, _pcw_reg, _pcw_shift) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT8173_RST_BAR, \ + .fmax = MT8173_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + } + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0), + PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0), + PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0), + PLL(CLK_APMIXED_MPLL, "mpll", 0x280, 0x28c, 0x00000001, 0, 21, 0x280, 4, 0x0, 0x284, 0), + PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x290, 0x29c, 0x00000001, 0, 21, 0x290, 4, 0x0, 0x294, 0), + PLL(CLK_APMIXED_APLL1, "apll1", 0x2a0, 0x2b0, 0x00000001, 0, 31, 0x2a0, 4, 0x2a4, 0x2a4, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x2b4, 0x2c4, 0x00000001, 0, 31, 0x2b4, 4, 0x2b8, 0x2b8, 0), + PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2d0, 0x2dc, 0x00000001, 0, 21, 0x2d0, 4, 0x0, 0x2d4, 0), + PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x2f0, 0x2fc, 0x00000001, 0, 21, 0x2f0, 4, 0x0, 0x2f4, 0), +}; + +static void __init mtk_apmixedsys_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls)); + if (!clk_data) + return; + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + + clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]); +} +CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys", + mtk_apmixedsys_init); diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h new file mode 100644 index 000000000000..4ad76ed882ad --- /dev/null +++ b/include/dt-bindings/clock/mt8173-clk.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: James Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MT8173_H +#define _DT_BINDINGS_CLK_MT8173_H + +/* TOPCKGEN */ + +#define CLK_TOP_CLKPH_MCK_O 1 +#define CLK_TOP_DPI 2 +#define CLK_TOP_USB_SYSPLL_125M 3 +#define CLK_TOP_HDMITX_DIG_CTS 4 +#define CLK_TOP_ARMCA7PLL_754M 5 +#define CLK_TOP_ARMCA7PLL_502M 6 +#define CLK_TOP_MAIN_H546M 7 +#define CLK_TOP_MAIN_H364M 8 +#define CLK_TOP_MAIN_H218P4M 9 +#define CLK_TOP_MAIN_H156M 10 +#define CLK_TOP_TVDPLL_445P5M 11 +#define CLK_TOP_TVDPLL_594M 12 +#define CLK_TOP_UNIV_624M 13 +#define CLK_TOP_UNIV_416M 14 +#define CLK_TOP_UNIV_249P6M 15 +#define CLK_TOP_UNIV_178P3M 16 +#define CLK_TOP_UNIV_48M 17 +#define CLK_TOP_CLKRTC_EXT 18 +#define CLK_TOP_CLKRTC_INT 19 +#define CLK_TOP_FPC 20 +#define CLK_TOP_HDMITXPLL_D2 21 +#define CLK_TOP_HDMITXPLL_D3 22 +#define CLK_TOP_ARMCA7PLL_D2 23 +#define CLK_TOP_ARMCA7PLL_D3 24 +#define CLK_TOP_APLL1 25 +#define CLK_TOP_APLL2 26 +#define CLK_TOP_DMPLL 27 +#define CLK_TOP_DMPLL_D2 28 +#define CLK_TOP_DMPLL_D4 29 +#define CLK_TOP_DMPLL_D8 30 +#define CLK_TOP_DMPLL_D16 31 +#define CLK_TOP_LVDSPLL_D2 32 +#define CLK_TOP_LVDSPLL_D4 33 +#define CLK_TOP_LVDSPLL_D8 34 +#define CLK_TOP_MMPLL 35 +#define CLK_TOP_MMPLL_D2 36 +#define CLK_TOP_MSDCPLL 37 +#define CLK_TOP_MSDCPLL_D2 38 +#define CLK_TOP_MSDCPLL_D4 39 +#define CLK_TOP_MSDCPLL2 40 +#define CLK_TOP_MSDCPLL2_D2 41 +#define CLK_TOP_MSDCPLL2_D4 42 +#define CLK_TOP_SYSPLL_D2 43 +#define CLK_TOP_SYSPLL1_D2 44 +#define CLK_TOP_SYSPLL1_D4 45 +#define CLK_TOP_SYSPLL1_D8 46 +#define CLK_TOP_SYSPLL1_D16 47 +#define CLK_TOP_SYSPLL_D3 48 +#define CLK_TOP_SYSPLL2_D2 49 +#define CLK_TOP_SYSPLL2_D4 50 +#define CLK_TOP_SYSPLL_D5 51 +#define CLK_TOP_SYSPLL3_D2 52 +#define CLK_TOP_SYSPLL3_D4 53 +#define CLK_TOP_SYSPLL_D7 54 +#define CLK_TOP_SYSPLL4_D2 55 +#define CLK_TOP_SYSPLL4_D4 56 +#define CLK_TOP_TVDPLL 57 +#define CLK_TOP_TVDPLL_D2 58 +#define CLK_TOP_TVDPLL_D4 59 +#define CLK_TOP_TVDPLL_D8 60 +#define CLK_TOP_TVDPLL_D16 61 +#define CLK_TOP_UNIVPLL_D2 62 +#define CLK_TOP_UNIVPLL1_D2 63 +#define CLK_TOP_UNIVPLL1_D4 64 +#define CLK_TOP_UNIVPLL1_D8 65 +#define CLK_TOP_UNIVPLL_D3 66 +#define CLK_TOP_UNIVPLL2_D2 67 +#define CLK_TOP_UNIVPLL2_D4 68 +#define CLK_TOP_UNIVPLL2_D8 69 +#define CLK_TOP_UNIVPLL_D5 70 +#define CLK_TOP_UNIVPLL3_D2 71 +#define CLK_TOP_UNIVPLL3_D4 72 +#define CLK_TOP_UNIVPLL3_D8 73 +#define CLK_TOP_UNIVPLL_D7 74 +#define CLK_TOP_UNIVPLL_D26 75 +#define CLK_TOP_UNIVPLL_D52 76 +#define CLK_TOP_VCODECPLL 77 +#define CLK_TOP_VCODECPLL_370P5 78 +#define CLK_TOP_VENCPLL 79 +#define CLK_TOP_VENCPLL_D2 80 +#define CLK_TOP_VENCPLL_D4 81 +#define CLK_TOP_AXI_SEL 82 +#define CLK_TOP_MEM_SEL 83 +#define CLK_TOP_DDRPHYCFG_SEL 84 +#define CLK_TOP_MM_SEL 85 +#define CLK_TOP_PWM_SEL 86 +#define CLK_TOP_VDEC_SEL 87 +#define CLK_TOP_VENC_SEL 88 +#define CLK_TOP_MFG_SEL 89 +#define CLK_TOP_CAMTG_SEL 90 +#define CLK_TOP_UART_SEL 91 +#define CLK_TOP_SPI_SEL 92 +#define CLK_TOP_USB20_SEL 93 +#define CLK_TOP_USB30_SEL 94 +#define CLK_TOP_MSDC50_0_H_SEL 95 +#define CLK_TOP_MSDC50_0_SEL 96 +#define CLK_TOP_MSDC30_1_SEL 97 +#define CLK_TOP_MSDC30_2_SEL 98 +#define CLK_TOP_MSDC30_3_SEL 99 +#define CLK_TOP_AUDIO_SEL 100 +#define CLK_TOP_AUD_INTBUS_SEL 101 +#define CLK_TOP_PMICSPI_SEL 102 +#define CLK_TOP_SCP_SEL 103 +#define CLK_TOP_ATB_SEL 104 +#define CLK_TOP_VENC_LT_SEL 105 +#define CLK_TOP_DPI0_SEL 106 +#define CLK_TOP_IRDA_SEL 107 +#define CLK_TOP_CCI400_SEL 108 +#define CLK_TOP_AUD_1_SEL 109 +#define CLK_TOP_AUD_2_SEL 110 +#define CLK_TOP_MEM_MFG_IN_SEL 111 +#define CLK_TOP_AXI_MFG_IN_SEL 112 +#define CLK_TOP_SCAM_SEL 113 +#define CLK_TOP_SPINFI_IFR_SEL 114 +#define CLK_TOP_HDMI_SEL 115 +#define CLK_TOP_DPILVDS_SEL 116 +#define CLK_TOP_MSDC50_2_H_SEL 117 +#define CLK_TOP_HDCP_SEL 118 +#define CLK_TOP_HDCP_24M_SEL 119 +#define CLK_TOP_RTC_SEL 120 +#define CLK_TOP_APLL1_DIV0 121 +#define CLK_TOP_APLL1_DIV1 122 +#define CLK_TOP_APLL1_DIV2 123 +#define CLK_TOP_APLL1_DIV3 124 +#define CLK_TOP_APLL1_DIV4 125 +#define CLK_TOP_APLL1_DIV5 126 +#define CLK_TOP_APLL2_DIV0 127 +#define CLK_TOP_APLL2_DIV1 128 +#define CLK_TOP_APLL2_DIV2 129 +#define CLK_TOP_APLL2_DIV3 130 +#define CLK_TOP_APLL2_DIV4 131 +#define CLK_TOP_APLL2_DIV5 132 +#define CLK_TOP_I2S0_M_SEL 133 +#define CLK_TOP_I2S1_M_SEL 134 +#define CLK_TOP_I2S2_M_SEL 135 +#define CLK_TOP_I2S3_M_SEL 136 +#define CLK_TOP_I2S3_B_SEL 137 +#define CLK_TOP_NR_CLK 138 + +/* APMIXED_SYS */ + +#define CLK_APMIXED_ARMCA15PLL 1 +#define CLK_APMIXED_ARMCA7PLL 2 +#define CLK_APMIXED_MAINPLL 3 +#define CLK_APMIXED_UNIVPLL 4 +#define CLK_APMIXED_MMPLL 5 +#define CLK_APMIXED_MSDCPLL 6 +#define CLK_APMIXED_VENCPLL 7 +#define CLK_APMIXED_TVDPLL 8 +#define CLK_APMIXED_MPLL 9 +#define CLK_APMIXED_VCODECPLL 10 +#define CLK_APMIXED_APLL1 11 +#define CLK_APMIXED_APLL2 12 +#define CLK_APMIXED_LVDSPLL 13 +#define CLK_APMIXED_MSDCPLL2 14 +#define CLK_APMIXED_NR_CLK 15 + +/* INFRA_SYS */ + +#define CLK_INFRA_DBGCLK 1 +#define CLK_INFRA_SMI 2 +#define CLK_INFRA_AUDIO 3 +#define CLK_INFRA_GCE 4 +#define CLK_INFRA_L2C_SRAM 5 +#define CLK_INFRA_M4U 6 +#define CLK_INFRA_CPUM 7 +#define CLK_INFRA_KP 8 +#define CLK_INFRA_CEC 9 +#define CLK_INFRA_PMICSPI 10 +#define CLK_INFRA_PMICWRAP 11 +#define CLK_INFRA_NR_CLK 12 + +/* PERI_SYS */ + +#define CLK_PERI_NFI 1 +#define CLK_PERI_THERM 2 +#define CLK_PERI_PWM1 3 +#define CLK_PERI_PWM2 4 +#define CLK_PERI_PWM3 5 +#define CLK_PERI_PWM4 6 +#define CLK_PERI_PWM5 7 +#define CLK_PERI_PWM6 8 +#define CLK_PERI_PWM7 9 +#define CLK_PERI_PWM 10 +#define CLK_PERI_USB0 11 +#define CLK_PERI_USB1 12 +#define CLK_PERI_AP_DMA 13 +#define CLK_PERI_MSDC30_0 14 +#define CLK_PERI_MSDC30_1 15 +#define CLK_PERI_MSDC30_2 16 +#define CLK_PERI_MSDC30_3 17 +#define CLK_PERI_NLI_ARB 18 +#define CLK_PERI_IRDA 19 +#define CLK_PERI_UART0 20 +#define CLK_PERI_UART1 21 +#define CLK_PERI_UART2 22 +#define CLK_PERI_UART3 23 +#define CLK_PERI_I2C0 24 +#define CLK_PERI_I2C1 25 +#define CLK_PERI_I2C2 26 +#define CLK_PERI_I2C3 27 +#define CLK_PERI_I2C4 28 +#define CLK_PERI_AUXADC 29 +#define CLK_PERI_SPI0 30 +#define CLK_PERI_I2C5 31 +#define CLK_PERI_NFIECC 32 +#define CLK_PERI_SPI 33 +#define CLK_PERI_IRRX 34 +#define CLK_PERI_I2C6 35 +#define CLK_PERI_UART0_SEL 36 +#define CLK_PERI_UART1_SEL 37 +#define CLK_PERI_UART2_SEL 38 +#define CLK_PERI_UART3_SEL 39 +#define CLK_PERI_NR_CLK 40 + +#endif /* _DT_BINDINGS_CLK_MT8173_H */ diff --git a/include/dt-bindings/reset-controller/mt8173-resets.h b/include/dt-bindings/reset-controller/mt8173-resets.h new file mode 100644 index 000000000000..9464b37cf68c --- /dev/null +++ b/include/dt-bindings/reset-controller/mt8173-resets.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Flora Fu, MediaTek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8173 +#define _DT_BINDINGS_RESET_CONTROLLER_MT8173 + +/* INFRACFG resets */ +#define MT8173_INFRA_EMI_REG_RST 0 +#define MT8173_INFRA_DRAMC0_A0_RST 1 +#define MT8173_INFRA_APCIRQ_EINT_RST 3 +#define MT8173_INFRA_APXGPT_RST 4 +#define MT8173_INFRA_SCPSYS_RST 5 +#define MT8173_INFRA_KP_RST 6 +#define MT8173_INFRA_PMIC_WRAP_RST 7 +#define MT8173_INFRA_MPIP_RST 8 +#define MT8173_INFRA_CEC_RST 9 +#define MT8173_INFRA_EMI_RST 32 +#define MT8173_INFRA_DRAMC0_RST 34 +#define MT8173_INFRA_APMIXEDSYS_RST 35 +#define MT8173_INFRA_MIPI_DSI_RST 36 +#define MT8173_INFRA_TRNG_RST 37 +#define MT8173_INFRA_SYSIRQ_RST 38 +#define MT8173_INFRA_MIPI_CSI_RST 39 +#define MT8173_INFRA_GCE_FAXI_RST 40 +#define MT8173_INFRA_MMIOMMURST 47 + + +/* PERICFG resets */ +#define MT8173_PERI_UART0_SW_RST 0 +#define MT8173_PERI_UART1_SW_RST 1 +#define MT8173_PERI_UART2_SW_RST 2 +#define MT8173_PERI_UART3_SW_RST 3 +#define MT8173_PERI_IRRX_SW_RST 4 +#define MT8173_PERI_PWM_SW_RST 8 +#define MT8173_PERI_AUXADC_SW_RST 10 +#define MT8173_PERI_DMA_SW_RST 11 +#define MT8173_PERI_I2C6_SW_RST 13 +#define MT8173_PERI_NFI_SW_RST 14 +#define MT8173_PERI_THERM_SW_RST 16 +#define MT8173_PERI_MSDC2_SW_RST 17 +#define MT8173_PERI_MSDC3_SW_RST 18 +#define MT8173_PERI_MSDC0_SW_RST 19 +#define MT8173_PERI_MSDC1_SW_RST 20 +#define MT8173_PERI_I2C0_SW_RST 22 +#define MT8173_PERI_I2C1_SW_RST 23 +#define MT8173_PERI_I2C2_SW_RST 24 +#define MT8173_PERI_I2C3_SW_RST 25 +#define MT8173_PERI_I2C4_SW_RST 26 +#define MT8173_PERI_HDMI_SW_RST 29 +#define MT8173_PERI_SPI0_SW_RST 33 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8173 */ -- cgit v1.2.3 From 8a3d9c164152e461e5f80db65aaaa0fbfdb2eed3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 11 May 2015 17:25:19 -0500 Subject: dt-bindings: Add pxa1928 clock binding This adds the clock binding documentation for the Marvell PXA1928 SOC. The PXA1928 has 3 clock control blocks for different subsystems of the chip. Signed-off-by: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/marvell,pxa1928.txt | 21 ++++++++ include/dt-bindings/clock/marvell,pxa1928.h | 57 ++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/marvell,pxa1928.txt create mode 100644 include/dt-bindings/clock/marvell,pxa1928.h (limited to 'include/dt-bindings') diff --git a/Documentation/devicetree/bindings/clock/marvell,pxa1928.txt b/Documentation/devicetree/bindings/clock/marvell,pxa1928.txt new file mode 100644 index 000000000000..809c5a2d8d9d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,pxa1928.txt @@ -0,0 +1,21 @@ +* Marvell PXA1928 Clock Controllers + +The PXA1928 clock subsystem generates and supplies clock to various +controllers within the PXA1928 SoC. The PXA1928 contains 3 clock controller +blocks called APMU, MPMU, and APBC roughly corresponding to internal buses. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,pxa1928-apmu" - APMU controller compatible + - "marvell,pxa1928-mpmu" - MPMU controller compatible + - "marvell,pxa1928-apbc" - APBC controller compatible +- reg: physical base address of the clock controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use the clock controller +phandle and this identifier to specify the clock which they consume. + +All these identifiers can be found in . diff --git a/include/dt-bindings/clock/marvell,pxa1928.h b/include/dt-bindings/clock/marvell,pxa1928.h new file mode 100644 index 000000000000..d4f2e18919ff --- /dev/null +++ b/include/dt-bindings/clock/marvell,pxa1928.h @@ -0,0 +1,57 @@ +#ifndef __DTS_MARVELL_PXA1928_CLOCK_H +#define __DTS_MARVELL_PXA1928_CLOCK_H + +/* + * Clock ID values here correspond to the control register offset/4. + */ + +/* apb peripherals */ +#define PXA1928_CLK_RTC 0x00 +#define PXA1928_CLK_TWSI0 0x01 +#define PXA1928_CLK_TWSI1 0x02 +#define PXA1928_CLK_TWSI2 0x03 +#define PXA1928_CLK_TWSI3 0x04 +#define PXA1928_CLK_OWIRE 0x05 +#define PXA1928_CLK_KPC 0x06 +#define PXA1928_CLK_TB_ROTARY 0x07 +#define PXA1928_CLK_SW_JTAG 0x08 +#define PXA1928_CLK_TIMER1 0x09 +#define PXA1928_CLK_UART0 0x0b +#define PXA1928_CLK_UART1 0x0c +#define PXA1928_CLK_UART2 0x0d +#define PXA1928_CLK_GPIO 0x0e +#define PXA1928_CLK_PWM0 0x0f +#define PXA1928_CLK_PWM1 0x10 +#define PXA1928_CLK_PWM2 0x11 +#define PXA1928_CLK_PWM3 0x12 +#define PXA1928_CLK_SSP0 0x13 +#define PXA1928_CLK_SSP1 0x14 +#define PXA1928_CLK_SSP2 0x15 + +#define PXA1928_CLK_TWSI4 0x1f +#define PXA1928_CLK_TWSI5 0x20 +#define PXA1928_CLK_UART3 0x22 +#define PXA1928_CLK_THSENS_GLOB 0x24 +#define PXA1928_CLK_THSENS_CPU 0x26 +#define PXA1928_CLK_THSENS_VPU 0x27 +#define PXA1928_CLK_THSENS_GC 0x28 +#define PXA1928_APBC_NR_CLKS 0x30 + + +/* axi peripherals */ +#define PXA1928_CLK_SDH0 0x15 +#define PXA1928_CLK_SDH1 0x16 +#define PXA1928_CLK_USB 0x17 +#define PXA1928_CLK_NAND 0x18 +#define PXA1928_CLK_DMA 0x19 + +#define PXA1928_CLK_SDH2 0x3a +#define PXA1928_CLK_SDH3 0x3b +#define PXA1928_CLK_HSIC 0x3e +#define PXA1928_CLK_SDH4 0x57 +#define PXA1928_CLK_GC3D 0x5d +#define PXA1928_CLK_GC2D 0x5f + +#define PXA1928_APMU_NR_CLKS 0x60 + +#endif -- cgit v1.2.3 From 2a40a2ea109269def06f991f771c2bf2f6c0f396 Mon Sep 17 00:00:00 2001 From: Bintian Wang Date: Fri, 29 May 2015 10:08:37 +0800 Subject: dt-bindings: Add header file of hi6220 clock driver Add the header file "hi6220-clock.h" used by both hi6220 clock driver and hi6220 device tree file. Suggested-by: Stephen Boyd Signed-off-by: Bintian Wang Tested-by: Will Deacon Tested-by: Tyler Baker Tested-by: Kevin Hilman Signed-off-by: Michael Turquette --- include/dt-bindings/clock/hi6220-clock.h | 173 +++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 include/dt-bindings/clock/hi6220-clock.h (limited to 'include/dt-bindings') diff --git a/include/dt-bindings/clock/hi6220-clock.h b/include/dt-bindings/clock/hi6220-clock.h new file mode 100644 index 000000000000..70ee3833a7a0 --- /dev/null +++ b/include/dt-bindings/clock/hi6220-clock.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015 Hisilicon Limited. + * + * Author: Bintian Wang + * + * 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. + */ + +#ifndef __DT_BINDINGS_CLOCK_HI6220_H +#define __DT_BINDINGS_CLOCK_HI6220_H + +/* clk in Hi6220 AO (always on) controller */ +#define HI6220_NONE_CLOCK 0 + +/* fixed rate clocks */ +#define HI6220_REF32K 1 +#define HI6220_CLK_TCXO 2 +#define HI6220_MMC1_PAD 3 +#define HI6220_MMC2_PAD 4 +#define HI6220_MMC0_PAD 5 +#define HI6220_PLL_BBP 6 +#define HI6220_PLL_GPU 7 +#define HI6220_PLL1_DDR 8 +#define HI6220_PLL_SYS 9 +#define HI6220_PLL_SYS_MEDIA 10 +#define HI6220_DDR_SRC 11 +#define HI6220_PLL_MEDIA 12 +#define HI6220_PLL_DDR 13 + +/* fixed factor clocks */ +#define HI6220_300M 14 +#define HI6220_150M 15 +#define HI6220_PICOPHY_SRC 16 +#define HI6220_MMC0_SRC_SEL 17 +#define HI6220_MMC1_SRC_SEL 18 +#define HI6220_MMC2_SRC_SEL 19 +#define HI6220_VPU_CODEC 20 +#define HI6220_MMC0_SMP 21 +#define HI6220_MMC1_SMP 22 +#define HI6220_MMC2_SMP 23 + +/* gate clocks */ +#define HI6220_WDT0_PCLK 24 +#define HI6220_WDT1_PCLK 25 +#define HI6220_WDT2_PCLK 26 +#define HI6220_TIMER0_PCLK 27 +#define HI6220_TIMER1_PCLK 28 +#define HI6220_TIMER2_PCLK 29 +#define HI6220_TIMER3_PCLK 30 +#define HI6220_TIMER4_PCLK 31 +#define HI6220_TIMER5_PCLK 32 +#define HI6220_TIMER6_PCLK 33 +#define HI6220_TIMER7_PCLK 34 +#define HI6220_TIMER8_PCLK 35 +#define HI6220_UART0_PCLK 36 + +#define HI6220_AO_NR_CLKS 37 + +/* clk in Hi6220 systrl */ +/* gate clock */ +#define HI6220_MMC0_CLK 1 +#define HI6220_MMC0_CIUCLK 2 +#define HI6220_MMC1_CLK 3 +#define HI6220_MMC1_CIUCLK 4 +#define HI6220_MMC2_CLK 5 +#define HI6220_MMC2_CIUCLK 6 +#define HI6220_USBOTG_HCLK 7 +#define HI6220_CLK_PICOPHY 8 +#define HI6220_HIFI 9 +#define HI6220_DACODEC_PCLK 10 +#define HI6220_EDMAC_ACLK 11 +#define HI6220_CS_ATB 12 +#define HI6220_I2C0_CLK 13 +#define HI6220_I2C1_CLK 14 +#define HI6220_I2C2_CLK 15 +#define HI6220_I2C3_CLK 16 +#define HI6220_UART1_PCLK 17 +#define HI6220_UART2_PCLK 18 +#define HI6220_UART3_PCLK 19 +#define HI6220_UART4_PCLK 20 +#define HI6220_SPI_CLK 21 +#define HI6220_TSENSOR_CLK 22 +#define HI6220_MMU_CLK 23 +#define HI6220_HIFI_SEL 24 +#define HI6220_MMC0_SYSPLL 25 +#define HI6220_MMC1_SYSPLL 26 +#define HI6220_MMC2_SYSPLL 27 +#define HI6220_MMC0_SEL 28 +#define HI6220_MMC1_SEL 29 +#define HI6220_BBPPLL_SEL 30 +#define HI6220_MEDIA_PLL_SRC 31 +#define HI6220_MMC2_SEL 32 +#define HI6220_CS_ATB_SYSPLL 33 + +/* mux clocks */ +#define HI6220_MMC0_SRC 34 +#define HI6220_MMC0_SMP_IN 35 +#define HI6220_MMC1_SRC 36 +#define HI6220_MMC1_SMP_IN 37 +#define HI6220_MMC2_SRC 38 +#define HI6220_MMC2_SMP_IN 39 +#define HI6220_HIFI_SRC 40 +#define HI6220_UART1_SRC 41 +#define HI6220_UART2_SRC 42 +#define HI6220_UART3_SRC 43 +#define HI6220_UART4_SRC 44 +#define HI6220_MMC0_MUX0 45 +#define HI6220_MMC1_MUX0 46 +#define HI6220_MMC2_MUX0 47 +#define HI6220_MMC0_MUX1 48 +#define HI6220_MMC1_MUX1 49 +#define HI6220_MMC2_MUX1 50 + +/* divider clocks */ +#define HI6220_CLK_BUS 51 +#define HI6220_MMC0_DIV 52 +#define HI6220_MMC1_DIV 53 +#define HI6220_MMC2_DIV 54 +#define HI6220_HIFI_DIV 55 +#define HI6220_BBPPLL0_DIV 56 +#define HI6220_CS_DAPB 57 +#define HI6220_CS_ATB_DIV 58 + +#define HI6220_SYS_NR_CLKS 59 + +/* clk in Hi6220 media controller */ +/* gate clocks */ +#define HI6220_DSI_PCLK 1 +#define HI6220_G3D_PCLK 2 +#define HI6220_ACLK_CODEC_VPU 3 +#define HI6220_ISP_SCLK 4 +#define HI6220_ADE_CORE 5 +#define HI6220_MED_MMU 6 +#define HI6220_CFG_CSI4PHY 7 +#define HI6220_CFG_CSI2PHY 8 +#define HI6220_ISP_SCLK_GATE 9 +#define HI6220_ISP_SCLK_GATE1 10 +#define HI6220_ADE_CORE_GATE 11 +#define HI6220_CODEC_VPU_GATE 12 +#define HI6220_MED_SYSPLL 13 + +/* mux clocks */ +#define HI6220_1440_1200 14 +#define HI6220_1000_1200 15 +#define HI6220_1000_1440 16 + +/* divider clocks */ +#define HI6220_CODEC_JPEG 17 +#define HI6220_ISP_SCLK_SRC 18 +#define HI6220_ISP_SCLK1 19 +#define HI6220_ADE_CORE_SRC 20 +#define HI6220_ADE_PIX_SRC 21 +#define HI6220_G3D_CLK 22 +#define HI6220_CODEC_VPU_SRC 23 + +#define HI6220_MEDIA_NR_CLKS 24 + +/* clk in Hi6220 power controller */ +/* gate clocks */ +#define HI6220_PLL_GPU_GATE 1 +#define HI6220_PLL1_DDR_GATE 2 +#define HI6220_PLL_DDR_GATE 3 +#define HI6220_PLL_MEDIA_GATE 4 +#define HI6220_PLL0_BBP_GATE 5 + +/* divider clocks */ +#define HI6220_DDRC_SRC 6 +#define HI6220_DDRC_AXI1 7 + +#define HI6220_POWER_NR_CLKS 8 +#endif -- cgit v1.2.3 From a35247c6ee7265b024d606f7503fef44e88d9d2d Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Thu, 30 Apr 2015 09:53:40 +0800 Subject: clk: mmp: add fixed clock UBS_PLL for pxa910/pxa168 USB will drive clock from USB_PLL. Signed-off-by: Chao Xie Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-pxa168.c | 1 + drivers/clk/mmp/clk-of-pxa910.c | 1 + include/dt-bindings/clock/marvell,pxa168.h | 1 + include/dt-bindings/clock/marvell,pxa910.h | 1 + 4 files changed, 4 insertions(+) (limited to 'include/dt-bindings') diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index 5b1810dc4bd2..01a650e6f8a4 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -58,6 +58,7 @@ static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { {PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, {PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, {PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, + {PXA168_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, }; static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c index 5e3c80dad336..cca98eff641a 100644 --- a/drivers/clk/mmp/clk-of-pxa910.c +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -57,6 +57,7 @@ static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { {PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, {PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, {PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, + {PXA910_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, }; static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { diff --git a/include/dt-bindings/clock/marvell,pxa168.h b/include/dt-bindings/clock/marvell,pxa168.h index 79630b9d74b8..84ce5de6c83d 100644 --- a/include/dt-bindings/clock/marvell,pxa168.h +++ b/include/dt-bindings/clock/marvell,pxa168.h @@ -19,6 +19,7 @@ #define PXA168_CLK_PLL1_2_1_5 19 #define PXA168_CLK_PLL1_3_16 20 #define PXA168_CLK_UART_PLL 27 +#define PXA168_CLK_USB_PLL 28 /* apb periphrals */ #define PXA168_CLK_TWSI0 60 diff --git a/include/dt-bindings/clock/marvell,pxa910.h b/include/dt-bindings/clock/marvell,pxa910.h index 719cffb2bea2..bea08b60298b 100644 --- a/include/dt-bindings/clock/marvell,pxa910.h +++ b/include/dt-bindings/clock/marvell,pxa910.h @@ -19,6 +19,7 @@ #define PXA910_CLK_PLL1_2_1_5 19 #define PXA910_CLK_PLL1_3_16 20 #define PXA910_CLK_UART_PLL 27 +#define PXA910_CLK_USB_PLL 28 /* apb periphrals */ #define PXA910_CLK_TWSI0 60 -- cgit v1.2.3 From 24c65a02b23509284cce5185d81a150d699837b5 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Thu, 30 Apr 2015 09:53:42 +0800 Subject: clk: mmp: add timer clock for pxa168/mmp2/pxa910 Timer has external fast clock, and it is a mux clock. Add the timer clock type for timer driver. Signed-off-by: Chao Xie Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 6 ++++++ drivers/clk/mmp/clk-of-pxa168.c | 7 +++++++ drivers/clk/mmp/clk-of-pxa910.c | 11 +++++++++++ include/dt-bindings/clock/marvell,mmp2.h | 1 + include/dt-bindings/clock/marvell,pxa168.h | 2 ++ include/dt-bindings/clock/marvell,pxa910.h | 3 +++ 6 files changed, 30 insertions(+) (limited to 'include/dt-bindings') diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index b7e0b89b2e3f..251533d87c65 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -30,6 +30,7 @@ #define APBC_TWSI4 0x7c #define APBC_TWSI5 0x80 #define APBC_KPC 0x18 +#define APBC_TIMER 0x24 #define APBC_UART0 0x2c #define APBC_UART1 0x30 #define APBC_UART2 0x34 @@ -132,6 +133,9 @@ static DEFINE_SPINLOCK(ssp2_lock); static DEFINE_SPINLOCK(ssp3_lock); static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; +static DEFINE_SPINLOCK(timer_lock); +static const char *timer_parent_names[] = {"clk32", "vctcxo_2", "vctcxo_4", "vctcxo"}; + static DEFINE_SPINLOCK(reset_lock); static struct mmp_param_mux_clk apbc_mux_clks[] = { @@ -143,6 +147,7 @@ static struct mmp_param_mux_clk apbc_mux_clks[] = { {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock}, {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock}, + {0, "timer_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER, 4, 3, 0, &timer_lock}, }; static struct mmp_param_gate_clk apbc_gate_clks[] = { @@ -168,6 +173,7 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = { {MMP2_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock}, {MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock}, {MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock}, + {MMP2_CLK_TIMER, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT, APBC_TIMER, 0x7, 0x3, 0x0, 0, &timer_lock}, }; static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit) diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index 01a650e6f8a4..64eaf4141c69 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -32,6 +32,7 @@ #define APBC_PWM1 0x10 #define APBC_PWM2 0x14 #define APBC_PWM3 0x18 +#define APBC_TIMER 0x34 #define APBC_SSP0 0x81c #define APBC_SSP1 0x820 #define APBC_SSP2 0x84c @@ -71,6 +72,7 @@ static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { {PXA168_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0}, {PXA168_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0}, {PXA168_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0}, + {PXA168_CLK_PLL1_192, "pll1_192", "pll1_96", 1, 2, 0}, {PXA168_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0}, {PXA168_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0}, {PXA168_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0}, @@ -120,6 +122,9 @@ static DEFINE_SPINLOCK(ssp3_lock); static DEFINE_SPINLOCK(ssp4_lock); static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; +static DEFINE_SPINLOCK(timer_lock); +static const char *timer_parent_names[] = {"pll1_48", "clk32", "pll1_96", "pll1_192"}; + static DEFINE_SPINLOCK(reset_lock); static struct mmp_param_mux_clk apbc_mux_clks[] = { @@ -131,6 +136,7 @@ static struct mmp_param_mux_clk apbc_mux_clks[] = { {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock}, {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock}, {0, "ssp4_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP4, 4, 3, 0, &ssp4_lock}, + {0, "timer_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER, 4, 3, 0, &timer_lock}, }; static struct mmp_param_gate_clk apbc_gate_clks[] = { @@ -152,6 +158,7 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = { {PXA168_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x3, 0x3, 0x0, 0, &ssp2_lock}, {PXA168_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x3, 0x3, 0x0, 0, &ssp3_lock}, {PXA168_CLK_SSP4, "ssp4_clk", "ssp4_mux", CLK_SET_RATE_PARENT, APBC_SSP4, 0x3, 0x3, 0x0, 0, &ssp4_lock}, + {PXA168_CLK_TIMER, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT, APBC_TIMER, 0x3, 0x3, 0x0, 0, &timer_lock}, }; static void pxa168_apb_periph_clk_init(struct pxa168_clk_unit *pxa_unit) diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c index cca98eff641a..13d6173326a4 100644 --- a/drivers/clk/mmp/clk-of-pxa910.c +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -35,6 +35,8 @@ #define APBC_SSP0 0x1c #define APBC_SSP1 0x20 #define APBC_SSP2 0x4c +#define APBC_TIMER0 0x30 +#define APBC_TIMER1 0x44 #define APBCP_TWSI1 0x28 #define APBCP_UART2 0x1c #define APMU_SDH0 0x54 @@ -70,6 +72,7 @@ static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { {PXA910_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0}, {PXA910_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0}, {PXA910_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0}, + {PXA910_CLK_PLL1_192, "pll1_192", "pll1_96", 1, 2, 0}, {PXA910_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0}, {PXA910_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0}, {PXA910_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0}, @@ -116,6 +119,10 @@ static DEFINE_SPINLOCK(ssp0_lock); static DEFINE_SPINLOCK(ssp1_lock); static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; +static DEFINE_SPINLOCK(timer0_lock); +static DEFINE_SPINLOCK(timer1_lock); +static const char *timer_parent_names[] = {"pll1_48", "clk32", "pll1_96"}; + static DEFINE_SPINLOCK(reset_lock); static struct mmp_param_mux_clk apbc_mux_clks[] = { @@ -123,6 +130,8 @@ static struct mmp_param_mux_clk apbc_mux_clks[] = { {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, + {0, "timer0_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER0, 4, 3, 0, &timer0_lock}, + {0, "timer1_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER1, 4, 3, 0, &timer1_lock}, }; static struct mmp_param_mux_clk apbcp_mux_clks[] = { @@ -143,6 +152,8 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = { {PXA910_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock}, {PXA910_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock}, {PXA910_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock}, + {PXA910_CLK_TIMER0, "timer0_clk", "timer0_mux", CLK_SET_RATE_PARENT, APBC_TIMER0, 0x3, 0x3, 0x0, 0, &timer0_lock}, + {PXA910_CLK_TIMER1, "timer1_clk", "timer1_mux", CLK_SET_RATE_PARENT, APBC_TIMER1, 0x3, 0x3, 0x0, 0, &timer1_lock}, }; static struct mmp_param_gate_clk apbcp_gate_clks[] = { diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h index 591f7fba89e2..7a510384a82a 100644 --- a/include/dt-bindings/clock/marvell,mmp2.h +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -48,6 +48,7 @@ #define MMP2_CLK_SSP1 78 #define MMP2_CLK_SSP2 79 #define MMP2_CLK_SSP3 80 +#define MMP2_CLK_TIMER 81 /* axi periphrals */ #define MMP2_CLK_SDH0 101 diff --git a/include/dt-bindings/clock/marvell,pxa168.h b/include/dt-bindings/clock/marvell,pxa168.h index 84ce5de6c83d..3e45bdfe1aa4 100644 --- a/include/dt-bindings/clock/marvell,pxa168.h +++ b/include/dt-bindings/clock/marvell,pxa168.h @@ -18,6 +18,7 @@ #define PXA168_CLK_PLL1_13_1_5 18 #define PXA168_CLK_PLL1_2_1_5 19 #define PXA168_CLK_PLL1_3_16 20 +#define PXA168_CLK_PLL1_192 21 #define PXA168_CLK_UART_PLL 27 #define PXA168_CLK_USB_PLL 28 @@ -41,6 +42,7 @@ #define PXA168_CLK_SSP2 76 #define PXA168_CLK_SSP3 77 #define PXA168_CLK_SSP4 78 +#define PXA168_CLK_TIMER 79 /* axi periphrals */ #define PXA168_CLK_DFC 100 diff --git a/include/dt-bindings/clock/marvell,pxa910.h b/include/dt-bindings/clock/marvell,pxa910.h index bea08b60298b..135082a0b62f 100644 --- a/include/dt-bindings/clock/marvell,pxa910.h +++ b/include/dt-bindings/clock/marvell,pxa910.h @@ -18,6 +18,7 @@ #define PXA910_CLK_PLL1_13_1_5 18 #define PXA910_CLK_PLL1_2_1_5 19 #define PXA910_CLK_PLL1_3_16 20 +#define PXA910_CLK_PLL1_192 21 #define PXA910_CLK_UART_PLL 27 #define PXA910_CLK_USB_PLL 28 @@ -38,6 +39,8 @@ #define PXA910_CLK_UART2 73 #define PXA910_CLK_SSP0 74 #define PXA910_CLK_SSP1 75 +#define PXA910_CLK_TIMER0 76 +#define PXA910_CLK_TIMER1 77 /* axi periphrals */ #define PXA910_CLK_DFC 100 -- cgit v1.2.3 From 7a29a869434e8b7a71972227f0920e2f8ea777bd Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Mon, 1 Jun 2015 13:13:53 +0200 Subject: clk: meson: Add support for Meson clock controller This patchset adds the infrastructure for registering and managing the core clocks found on Amlogic MesonX SoCs. In particular: - PLLs - CPU clock - Fixed rate clocks, fixed factor clocks, ... Signed-off-by: Carlo Caione Signed-off-by: Stephen Boyd --- drivers/clk/Makefile | 1 + drivers/clk/meson/Makefile | 5 + drivers/clk/meson/clk-cpu.c | 234 +++++++++++++++++++++++++++++ drivers/clk/meson/clk-pll.c | 227 ++++++++++++++++++++++++++++ drivers/clk/meson/clkc.c | 250 +++++++++++++++++++++++++++++++ drivers/clk/meson/clkc.h | 187 +++++++++++++++++++++++ include/dt-bindings/clock/meson8b-clkc.h | 25 ++++ 7 files changed, 929 insertions(+) create mode 100644 drivers/clk/meson/Makefile create mode 100644 drivers/clk/meson/clk-cpu.c create mode 100644 drivers/clk/meson/clk-pll.c create mode 100644 drivers/clk/meson/clkc.c create mode 100644 drivers/clk/meson/clkc.h create mode 100644 include/dt-bindings/clock/meson8b-clkc.h (limited to 'include/dt-bindings') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 3d00c25382c5..9c4ddb1b0845 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -55,6 +55,7 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif obj-$(CONFIG_PLAT_ORION) += mvebu/ +obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile new file mode 100644 index 000000000000..66c6d8d23553 --- /dev/null +++ b/drivers/clk/meson/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Meson specific clk +# + +obj-y += clkc.o clk-pll.o clk-cpu.o diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c new file mode 100644 index 000000000000..148e99fc5970 --- /dev/null +++ b/drivers/clk/meson/clk-cpu.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/* + * CPU clock path: + * + * +-[/N]-----|3| + * MUX2 +--[/3]-+----------|2| MUX1 + * [sys_pll]---|1| |--[/2]------------|1|-|1| + * | |---+------------------|0| | |----- [a5_clk] + * +--|0| | | + * [xtal]---+-------------------------------|0| + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MESON_CPU_CLK_CNTL1 0x00 +#define MESON_CPU_CLK_CNTL 0x40 + +#define MESON_CPU_CLK_MUX1 BIT(7) +#define MESON_CPU_CLK_MUX2 BIT(0) + +#define MESON_N_WIDTH 9 +#define MESON_N_SHIFT 20 +#define MESON_SEL_WIDTH 2 +#define MESON_SEL_SHIFT 2 + +#include "clkc.h" + +struct meson_clk_cpu { + struct notifier_block clk_nb; + const struct clk_div_table *div_table; + struct clk_hw hw; + void __iomem *base; + u16 reg_off; +}; +#define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw) +#define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb) + +static long meson_clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); + + return divider_round_rate(hw, rate, prate, clk_cpu->div_table, + MESON_N_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); +} + +static int meson_clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); + unsigned int div, sel, N = 0; + u32 reg; + + div = DIV_ROUND_UP(parent_rate, rate); + + if (div <= 3) { + sel = div - 1; + } else { + sel = 3; + N = div / 2; + } + + reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); + reg = PARM_SET(MESON_N_WIDTH, MESON_N_SHIFT, reg, N); + writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); + + reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); + reg = PARM_SET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg, sel); + writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); + + return 0; +} + +static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); + unsigned int N, sel; + unsigned int div = 1; + u32 reg; + + reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); + N = PARM_GET(MESON_N_WIDTH, MESON_N_SHIFT, reg); + + reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); + sel = PARM_GET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg); + + if (sel < 3) + div = sel + 1; + else + div = 2 * N; + + return parent_rate / div; +} + +static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu, + struct clk_notifier_data *ndata) +{ + u32 cpu_clk_cntl; + + /* switch MUX1 to xtal */ + cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off + + MESON_CPU_CLK_CNTL); + cpu_clk_cntl &= ~MESON_CPU_CLK_MUX1; + writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off + + MESON_CPU_CLK_CNTL); + udelay(100); + + /* switch MUX2 to sys-pll */ + cpu_clk_cntl |= MESON_CPU_CLK_MUX2; + writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off + + MESON_CPU_CLK_CNTL); + + return 0; +} + +static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu, + struct clk_notifier_data *ndata) +{ + u32 cpu_clk_cntl; + + /* switch MUX1 to divisors' output */ + cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off + + MESON_CPU_CLK_CNTL); + cpu_clk_cntl |= MESON_CPU_CLK_MUX1; + writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off + + MESON_CPU_CLK_CNTL); + udelay(100); + + return 0; +} + +/* + * This clock notifier is called when the frequency of the of the parent + * PLL clock is to be changed. We use the xtal input as temporary parent + * while the PLL frequency is stabilized. + */ +static int meson_clk_cpu_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct clk_notifier_data *ndata = data; + struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_nb(nb); + int ret = 0; + + if (event == PRE_RATE_CHANGE) + ret = meson_clk_cpu_pre_rate_change(clk_cpu, ndata); + else if (event == POST_RATE_CHANGE) + ret = meson_clk_cpu_post_rate_change(clk_cpu, ndata); + + return notifier_from_errno(ret); +} + +static const struct clk_ops meson_clk_cpu_ops = { + .recalc_rate = meson_clk_cpu_recalc_rate, + .round_rate = meson_clk_cpu_round_rate, + .set_rate = meson_clk_cpu_set_rate, +}; + +struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf, + void __iomem *reg_base, + spinlock_t *lock) +{ + struct clk *clk; + struct clk *pclk; + struct meson_clk_cpu *clk_cpu; + struct clk_init_data init; + int ret; + + clk_cpu = kzalloc(sizeof(*clk_cpu), GFP_KERNEL); + if (!clk_cpu) + return ERR_PTR(-ENOMEM); + + clk_cpu->base = reg_base; + clk_cpu->reg_off = clk_conf->reg_off; + clk_cpu->div_table = clk_conf->conf.div_table; + clk_cpu->clk_nb.notifier_call = meson_clk_cpu_notifier_cb; + + init.name = clk_conf->clk_name; + init.ops = &meson_clk_cpu_ops; + init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE; + init.flags |= CLK_SET_RATE_PARENT; + init.parent_names = clk_conf->clks_parent; + init.num_parents = 1; + + clk_cpu->hw.init = &init; + + pclk = __clk_lookup(clk_conf->clks_parent[0]); + if (!pclk) { + pr_err("%s: could not lookup parent clock %s\n", + __func__, clk_conf->clks_parent[0]); + return ERR_PTR(-EINVAL); + } + + ret = clk_notifier_register(pclk, &clk_cpu->clk_nb); + if (ret) { + pr_err("%s: failed to register clock notifier for %s\n", + __func__, clk_conf->clk_name); + return ERR_PTR(-EINVAL); + } + + clk = clk_register(NULL, &clk_cpu->hw); + if (IS_ERR(clk)) { + clk_notifier_unregister(pclk, &clk_cpu->clk_nb); + kfree(clk_cpu); + } + + return clk; +} + diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c new file mode 100644 index 000000000000..664edf0708ea --- /dev/null +++ b/drivers/clk/meson/clk-pll.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/* + * In the most basic form, a Meson PLL is composed as follows: + * + * PLL + * +------------------------------+ + * | | + * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out + * | ^ ^ | + * +------------------------------+ + * | | + * FREF VCO + * + * out = (in * M / N) >> OD + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clkc.h" + +#define MESON_PLL_RESET BIT(29) +#define MESON_PLL_LOCK BIT(31) + +struct meson_clk_pll { + struct clk_hw hw; + void __iomem *base; + struct pll_conf *conf; + unsigned int rate_count; + spinlock_t *lock; +}; +#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) + +static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + struct parm *p; + unsigned long parent_rate_mhz = parent_rate / 1000000; + unsigned long rate_mhz; + u16 n, m, od; + u32 reg; + + p = &pll->conf->n; + reg = readl(pll->base + p->reg_off); + n = PARM_GET(p->width, p->shift, reg); + + p = &pll->conf->m; + reg = readl(pll->base + p->reg_off); + m = PARM_GET(p->width, p->shift, reg); + + p = &pll->conf->od; + reg = readl(pll->base + p->reg_off); + od = PARM_GET(p->width, p->shift, reg); + + rate_mhz = (parent_rate_mhz * m / n) >> od; + + return rate_mhz * 1000000; +} + +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + const struct pll_rate_table *rate_table = pll->conf->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) { + if (rate <= rate_table[i].rate) + return rate_table[i].rate; + } + + /* else return the smallest value */ + return rate_table[0].rate; +} + +static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, + unsigned long rate) +{ + const struct pll_rate_table *rate_table = pll->conf->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) { + if (rate == rate_table[i].rate) + return &rate_table[i]; + } + return NULL; +} + +static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, + struct parm *p_n) +{ + int delay = 24000000; + u32 reg; + + while (delay > 0) { + reg = readl(pll->base + p_n->reg_off); + + if (reg & MESON_PLL_LOCK) + return 0; + delay--; + } + return -ETIMEDOUT; +} + +static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + struct parm *p; + const struct pll_rate_table *rate_set; + unsigned long old_rate; + int ret = 0; + u32 reg; + + if (parent_rate == 0 || rate == 0) + return -EINVAL; + + old_rate = rate; + + rate_set = meson_clk_get_pll_settings(pll, rate); + if (!rate_set) + return -EINVAL; + + /* PLL reset */ + p = &pll->conf->n; + reg = readl(pll->base + p->reg_off); + writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); + + reg = PARM_SET(p->width, p->shift, reg, rate_set->n); + writel(reg, pll->base + p->reg_off); + + p = &pll->conf->m; + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->m); + writel(reg, pll->base + p->reg_off); + + p = &pll->conf->od; + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->od); + writel(reg, pll->base + p->reg_off); + + p = &pll->conf->n; + ret = meson_clk_pll_wait_lock(pll, p); + if (ret) { + pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", + __func__, old_rate); + meson_clk_pll_set_rate(hw, old_rate, parent_rate); + } + + return ret; +} + +static const struct clk_ops meson_clk_pll_ops = { + .recalc_rate = meson_clk_pll_recalc_rate, + .round_rate = meson_clk_pll_round_rate, + .set_rate = meson_clk_pll_set_rate, +}; + +static const struct clk_ops meson_clk_pll_ro_ops = { + .recalc_rate = meson_clk_pll_recalc_rate, +}; + +struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf, + void __iomem *reg_base, + spinlock_t *lock) +{ + struct clk *clk; + struct meson_clk_pll *clk_pll; + struct clk_init_data init; + + clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL); + if (!clk_pll) + return ERR_PTR(-ENOMEM); + + clk_pll->base = reg_base + clk_conf->reg_off; + clk_pll->lock = lock; + clk_pll->conf = clk_conf->conf.pll; + + init.name = clk_conf->clk_name; + init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE; + + init.parent_names = &clk_conf->clks_parent[0]; + init.num_parents = 1; + init.ops = &meson_clk_pll_ro_ops; + + /* If no rate_table is specified we assume the PLL is read-only */ + if (clk_pll->conf->rate_table) { + int len; + + for (len = 0; clk_pll->conf->rate_table[len].rate != 0; ) + len++; + + clk_pll->rate_count = len; + init.ops = &meson_clk_pll_ops; + } + + clk_pll->hw.init = &init; + + clk = clk_register(NULL, &clk_pll->hw); + if (IS_ERR(clk)) + kfree(clk_pll); + + return clk; +} diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c new file mode 100644 index 000000000000..b8c511c5e7a7 --- /dev/null +++ b/drivers/clk/meson/clkc.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include + +#include "clkc.h" + +static DEFINE_SPINLOCK(clk_lock); + +static struct clk **clks; +static struct clk_onecell_data clk_data; + +struct clk ** __init meson_clk_init(struct device_node *np, + unsigned long nr_clks) +{ + clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL); + if (!clks) + return ERR_PTR(-ENOMEM); + + clk_data.clks = clks; + clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + return clks; +} + +static void meson_clk_add_lookup(struct clk *clk, unsigned int id) +{ + if (clks && id) + clks[id] = clk; +} + +static struct clk * __init +meson_clk_register_composite(const struct clk_conf *clk_conf, + void __iomem *clk_base) +{ + struct clk *clk; + struct clk_mux *mux = NULL; + struct clk_divider *div = NULL; + struct clk_gate *gate = NULL; + const struct clk_ops *mux_ops = NULL; + const struct composite_conf *composite_conf; + + composite_conf = clk_conf->conf.composite; + + if (clk_conf->num_parents > 1) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = clk_base + clk_conf->reg_off + + composite_conf->mux_parm.reg_off; + mux->shift = composite_conf->mux_parm.shift; + mux->mask = BIT(composite_conf->mux_parm.width) - 1; + mux->flags = composite_conf->mux_flags; + mux->lock = &clk_lock; + mux->table = composite_conf->mux_table; + mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ? + &clk_mux_ro_ops : &clk_mux_ops; + } + + if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) { + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) { + clk = ERR_PTR(-ENOMEM); + goto error; + } + + div->reg = clk_base + clk_conf->reg_off + + composite_conf->div_parm.reg_off; + div->shift = composite_conf->div_parm.shift; + div->width = composite_conf->div_parm.width; + div->lock = &clk_lock; + div->flags = composite_conf->div_flags; + div->table = composite_conf->div_table; + } + + if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + clk = ERR_PTR(-ENOMEM); + goto error; + } + + gate->reg = clk_base + clk_conf->reg_off + + composite_conf->div_parm.reg_off; + gate->bit_idx = composite_conf->gate_parm.shift; + gate->flags = composite_conf->gate_flags; + gate->lock = &clk_lock; + } + + clk = clk_register_composite(NULL, clk_conf->clk_name, + clk_conf->clks_parent, + clk_conf->num_parents, + mux ? &mux->hw : NULL, mux_ops, + div ? &div->hw : NULL, &clk_divider_ops, + gate ? &gate->hw : NULL, &clk_gate_ops, + clk_conf->flags); + if (IS_ERR(clk)) + goto error; + + return clk; + +error: + kfree(gate); + kfree(div); + kfree(mux); + + return clk; +} + +static struct clk * __init +meson_clk_register_fixed_factor(const struct clk_conf *clk_conf, + void __iomem *clk_base) +{ + struct clk *clk; + const struct fixed_fact_conf *fixed_fact_conf; + const struct parm *p; + unsigned int mult, div; + u32 reg; + + fixed_fact_conf = &clk_conf->conf.fixed_fact; + + mult = clk_conf->conf.fixed_fact.mult; + div = clk_conf->conf.fixed_fact.div; + + if (!mult) { + mult = 1; + p = &fixed_fact_conf->mult_parm; + if (MESON_PARM_APPLICABLE(p)) { + reg = readl(clk_base + clk_conf->reg_off + p->reg_off); + mult = PARM_GET(p->width, p->shift, reg); + } + } + + if (!div) { + div = 1; + p = &fixed_fact_conf->div_parm; + if (MESON_PARM_APPLICABLE(p)) { + reg = readl(clk_base + clk_conf->reg_off + p->reg_off); + mult = PARM_GET(p->width, p->shift, reg); + } + } + + clk = clk_register_fixed_factor(NULL, + clk_conf->clk_name, + clk_conf->clks_parent[0], + clk_conf->flags, + mult, div); + + return clk; +} + +static struct clk * __init +meson_clk_register_fixed_rate(const struct clk_conf *clk_conf, + void __iomem *clk_base) +{ + struct clk *clk; + const struct fixed_rate_conf *fixed_rate_conf; + const struct parm *r; + unsigned long rate; + u32 reg; + + fixed_rate_conf = &clk_conf->conf.fixed_rate; + rate = fixed_rate_conf->rate; + + if (!rate) { + r = &fixed_rate_conf->rate_parm; + reg = readl(clk_base + clk_conf->reg_off + r->reg_off); + rate = PARM_GET(r->width, r->shift, reg); + } + + rate *= 1000000; + + clk = clk_register_fixed_rate(NULL, + clk_conf->clk_name, + clk_conf->num_parents + ? clk_conf->clks_parent[0] : NULL, + clk_conf->flags, rate); + + return clk; +} + +void __init meson_clk_register_clks(const struct clk_conf *clk_confs, + size_t nr_confs, + void __iomem *clk_base) +{ + unsigned int i; + struct clk *clk = NULL; + + for (i = 0; i < nr_confs; i++) { + const struct clk_conf *clk_conf = &clk_confs[i]; + + switch (clk_conf->clk_type) { + case CLK_FIXED_RATE: + clk = meson_clk_register_fixed_rate(clk_conf, + clk_base); + break; + case CLK_FIXED_FACTOR: + clk = meson_clk_register_fixed_factor(clk_conf, + clk_base); + break; + case CLK_COMPOSITE: + clk = meson_clk_register_composite(clk_conf, + clk_base); + break; + case CLK_CPU: + clk = meson_clk_register_cpu(clk_conf, clk_base, + &clk_lock); + break; + case CLK_PLL: + clk = meson_clk_register_pll(clk_conf, clk_base, + &clk_lock); + break; + default: + clk = NULL; + } + + if (!clk) { + pr_err("%s: unknown clock type %d\n", __func__, + clk_conf->clk_type); + continue; + } + + if (IS_ERR(clk)) { + pr_warn("%s: Unable to create %s clock\n", __func__, + clk_conf->clk_name); + continue; + } + + meson_clk_add_lookup(clk, clk_conf->clk_id); + } +} diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h new file mode 100644 index 000000000000..609ae92cc13f --- /dev/null +++ b/drivers/clk/meson/clkc.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __CLKC_H +#define __CLKC_H + +#define PMASK(width) GENMASK(width - 1, 0) +#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) +#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) + +#define PARM_GET(width, shift, reg) \ + (((reg) & SETPMASK(width, shift)) >> (shift)) +#define PARM_SET(width, shift, reg, val) \ + (((reg) & CLRPMASK(width, shift)) | (val << (shift))) + +#define MESON_PARM_APPLICABLE(p) (!!((p)->width)) + +struct parm { + u16 reg_off; + u8 shift; + u8 width; +}; +#define PARM(_r, _s, _w) \ + { \ + .reg_off = (_r), \ + .shift = (_s), \ + .width = (_w), \ + } \ + +struct pll_rate_table { + unsigned long rate; + u16 m; + u16 n; + u16 od; +}; +#define PLL_RATE(_r, _m, _n, _od) \ + { \ + .rate = (_r), \ + .m = (_m), \ + .n = (_n), \ + .od = (_od), \ + } \ + +struct pll_conf { + const struct pll_rate_table *rate_table; + struct parm m; + struct parm n; + struct parm od; +}; + +struct fixed_fact_conf { + unsigned int div; + unsigned int mult; + struct parm div_parm; + struct parm mult_parm; +}; + +struct fixed_rate_conf { + unsigned long rate; + struct parm rate_parm; +}; + +struct composite_conf { + struct parm mux_parm; + struct parm div_parm; + struct parm gate_parm; + struct clk_div_table *div_table; + u32 *mux_table; + u8 mux_flags; + u8 div_flags; + u8 gate_flags; +}; + +#define PNAME(x) static const char *x[] + +enum clk_type { + CLK_FIXED_FACTOR, + CLK_FIXED_RATE, + CLK_COMPOSITE, + CLK_CPU, + CLK_PLL, +}; + +struct clk_conf { + u16 reg_off; + enum clk_type clk_type; + unsigned int clk_id; + const char *clk_name; + const char **clks_parent; + int num_parents; + unsigned long flags; + union { + struct fixed_fact_conf fixed_fact; + struct fixed_rate_conf fixed_rate; + const struct composite_conf *composite; + struct pll_conf *pll; + const struct clk_div_table *div_table; + } conf; +}; + +#define FIXED_RATE_P(_ro, _ci, _cn, _f, _c) \ + { \ + .reg_off = (_ro), \ + .clk_type = CLK_FIXED_RATE, \ + .clk_id = (_ci), \ + .clk_name = (_cn), \ + .flags = (_f), \ + .conf.fixed_rate.rate_parm = _c, \ + } \ + +#define FIXED_RATE(_ci, _cn, _f, _r) \ + { \ + .clk_type = CLK_FIXED_RATE, \ + .clk_id = (_ci), \ + .clk_name = (_cn), \ + .flags = (_f), \ + .conf.fixed_rate.rate = (_r), \ + } \ + +#define PLL(_ro, _ci, _cn, _cp, _f, _c) \ + { \ + .reg_off = (_ro), \ + .clk_type = CLK_PLL, \ + .clk_id = (_ci), \ + .clk_name = (_cn), \ + .clks_parent = (_cp), \ + .num_parents = ARRAY_SIZE(_cp), \ + .flags = (_f), \ + .conf.pll = (_c), \ + } \ + +#define FIXED_FACTOR_DIV(_ci, _cn, _cp, _f, _d) \ + { \ + .clk_type = CLK_FIXED_FACTOR, \ + .clk_id = (_ci), \ + .clk_name = (_cn), \ + .clks_parent = (_cp), \ + .num_parents = ARRAY_SIZE(_cp), \ + .conf.fixed_fact.div = (_d), \ + } \ + +#define CPU(_ro, _ci, _cn, _cp, _dt) \ + { \ + .reg_off = (_ro), \ + .clk_type = CLK_CPU, \ + .clk_id = (_ci), \ + .clk_name = (_cn), \ + .clks_parent = (_cp), \ + .num_parents = ARRAY_SIZE(_cp), \ + .conf.div_table = (_dt), \ + } \ + +#define COMPOSITE(_ro, _ci, _cn, _cp, _f, _c) \ + { \ + .reg_off = (_ro), \ + .clk_type = CLK_COMPOSITE, \ + .clk_id = (_ci), \ + .clk_name = (_cn), \ + .clks_parent = (_cp), \ + .num_parents = ARRAY_SIZE(_cp), \ + .flags = (_f), \ + .conf.composite = (_c), \ + } \ + +struct clk **meson_clk_init(struct device_node *np, unsigned long nr_clks); +void meson_clk_register_clks(const struct clk_conf *clk_confs, + unsigned int nr_confs, void __iomem *clk_base); +struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf, + void __iomem *reg_base, spinlock_t *lock); +struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf, + void __iomem *reg_base, spinlock_t *lock); + +#endif /* __CLKC_H */ diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h new file mode 100644 index 000000000000..bd2720d58e0c --- /dev/null +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -0,0 +1,25 @@ +/* + * Meson8b clock tree IDs + */ + +#ifndef __MESON8B_CLKC_H +#define __MESON8B_CLKC_H + +#define CLKID_UNUSED 0 +#define CLKID_XTAL 1 +#define CLKID_PLL_FIXED 2 +#define CLKID_PLL_VID 3 +#define CLKID_PLL_SYS 4 +#define CLKID_FCLK_DIV2 5 +#define CLKID_FCLK_DIV3 6 +#define CLKID_FCLK_DIV4 7 +#define CLKID_FCLK_DIV5 8 +#define CLKID_FCLK_DIV7 9 +#define CLKID_CLK81 10 +#define CLKID_MALI 11 +#define CLKID_CPUCLK 12 +#define CLKID_ZERO 13 + +#define CLK_NR_CLKS (CLKID_ZERO + 1) + +#endif /* __MESON8B_CLKC_H */ -- cgit v1.2.3 From 61ca7b0c7fffb968bd16394daf05b7e888e9541e Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Tue, 5 May 2015 11:13:21 -0700 Subject: clk: cygnus: add clock support for Broadcom Cygnus The Broadcom Cygnus SoC is architected under the iProc architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, MIPIPLL, all dervied from an onboard crystal. Cygnus also has various ASIU clocks that are derived directly from the onboard crystal. Signed-off-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Michael Turquette --- drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-cygnus.c | 265 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 68 +++++++++ 3 files changed, 334 insertions(+) create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 include/dt-bindings/clock/bcm-cygnus.h (limited to 'include/dt-bindings') diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index 0facbbc5652c..8a7a477862c7 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o +obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c new file mode 100644 index 000000000000..316c60337661 --- /dev/null +++ b/drivers/clk/bcm/clk-cygnus.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; 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 "clk-iproc.h" + +#define reg_val(o, s, w) { .offset = o, .shift = s, .width = w, } + +#define aon_val(o, pw, ps, is) { .offset = o, .pwr_width = pw, \ + .pwr_shift = ps, .iso_shift = is } + +#define sw_ctrl_val(o, s) { .offset = o, .shift = s, } + +#define asiu_div_val(o, es, hs, hw, ls, lw) \ + { .offset = o, .en_shift = es, .high_shift = hs, \ + .high_width = hw, .low_shift = ls, .low_width = lw } + +#define reset_val(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \ + .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \ + .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \ + .ka_width = kaw } + +#define vco_ctrl_val(uo, lo) { .u_offset = uo, .l_offset = lo } + +#define enable_val(o, es, hs, bs) { .offset = o, .enable_shift = es, \ + .hold_shift = hs, .bypass_shift = bs } + +#define asiu_gate_val(o, es) { .offset = o, .en_shift = es } + +static void __init cygnus_armpll_init(struct device_node *node) +{ + iproc_armpll_setup(node); +} +CLK_OF_DECLARE(cygnus_armpll, "brcm,cygnus-armpll", cygnus_armpll_init); + +static const struct iproc_pll_ctrl genpll = { + .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC | + IPROC_CLK_PLL_NEEDS_SW_CFG, + .aon = aon_val(0x0, 2, 1, 0), + .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 3), + .sw_ctrl = sw_ctrl_val(0x10, 31), + .ndiv_int = reg_val(0x10, 20, 10), + .ndiv_frac = reg_val(0x10, 0, 20), + .pdiv = reg_val(0x14, 0, 4), + .vco_ctrl = vco_ctrl_val(0x18, 0x1c), + .status = reg_val(0x28, 12, 1), +}; + +static const struct iproc_clk_ctrl genpll_clk[] = { + [BCM_CYGNUS_GENPLL_AXI21_CLK] = { + .channel = BCM_CYGNUS_GENPLL_AXI21_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x4, 6, 0, 12), + .mdiv = reg_val(0x20, 0, 8), + }, + [BCM_CYGNUS_GENPLL_250MHZ_CLK] = { + .channel = BCM_CYGNUS_GENPLL_250MHZ_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x4, 7, 1, 13), + .mdiv = reg_val(0x20, 10, 8), + }, + [BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = { + .channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x4, 8, 2, 14), + .mdiv = reg_val(0x20, 20, 8), + }, + [BCM_CYGNUS_GENPLL_ENET_SW_CLK] = { + .channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x4, 9, 3, 15), + .mdiv = reg_val(0x24, 0, 8), + }, + [BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = { + .channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x4, 10, 4, 16), + .mdiv = reg_val(0x24, 10, 8), + }, + [BCM_CYGNUS_GENPLL_CAN_CLK] = { + .channel = BCM_CYGNUS_GENPLL_CAN_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x4, 11, 5, 17), + .mdiv = reg_val(0x24, 20, 8), + }, +}; + +static void __init cygnus_genpll_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk, + ARRAY_SIZE(genpll_clk)); +} +CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init); + +static const struct iproc_pll_ctrl lcpll0 = { + .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG, + .aon = aon_val(0x0, 2, 5, 4), + .reset = reset_val(0x0, 31, 30, 27, 3, 23, 4, 19, 4), + .sw_ctrl = sw_ctrl_val(0x4, 31), + .ndiv_int = reg_val(0x4, 16, 10), + .pdiv = reg_val(0x4, 26, 4), + .vco_ctrl = vco_ctrl_val(0x10, 0x14), + .status = reg_val(0x18, 12, 1), +}; + +static const struct iproc_clk_ctrl lcpll0_clk[] = { + [BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = { + .channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x0, 7, 1, 13), + .mdiv = reg_val(0x8, 0, 8), + }, + [BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = { + .channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x0, 8, 2, 14), + .mdiv = reg_val(0x8, 10, 8), + }, + [BCM_CYGNUS_LCPLL0_SDIO_CLK] = { + .channel = BCM_CYGNUS_LCPLL0_SDIO_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x0, 9, 3, 15), + .mdiv = reg_val(0x8, 20, 8), + }, + [BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = { + .channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x0, 10, 4, 16), + .mdiv = reg_val(0xc, 0, 8), + }, + [BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = { + .channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x0, 11, 5, 17), + .mdiv = reg_val(0xc, 10, 8), + }, + [BCM_CYGNUS_LCPLL0_CH5_UNUSED] = { + .channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED, + .flags = IPROC_CLK_AON, + .enable = enable_val(0x0, 12, 6, 18), + .mdiv = reg_val(0xc, 20, 8), + }, +}; + +static void __init cygnus_lcpll0_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk, + ARRAY_SIZE(lcpll0_clk)); +} +CLK_OF_DECLARE(cygnus_lcpll0, "brcm,cygnus-lcpll0", cygnus_lcpll0_clk_init); + +/* + * MIPI PLL VCO frequency parameter table + */ +static const struct iproc_pll_vco_param mipipll_vco_params[] = { + /* rate (Hz) ndiv_int ndiv_frac pdiv */ + { 750000000UL, 30, 0, 1 }, + { 1000000000UL, 40, 0, 1 }, + { 1350000000ul, 54, 0, 1 }, + { 2000000000UL, 80, 0, 1 }, + { 2100000000UL, 84, 0, 1 }, + { 2250000000UL, 90, 0, 1 }, + { 2500000000UL, 100, 0, 1 }, + { 2700000000UL, 54, 0, 0 }, + { 2975000000UL, 119, 0, 1 }, + { 3100000000UL, 124, 0, 1 }, + { 3150000000UL, 126, 0, 1 }, +}; + +static const struct iproc_pll_ctrl mipipll = { + .flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC | + IPROC_CLK_NEEDS_READ_BACK, + .aon = aon_val(0x0, 4, 17, 16), + .asiu = asiu_gate_val(0x0, 3), + .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 4), + .ndiv_int = reg_val(0x10, 20, 10), + .ndiv_frac = reg_val(0x10, 0, 20), + .pdiv = reg_val(0x14, 0, 4), + .vco_ctrl = vco_ctrl_val(0x18, 0x1c), + .status = reg_val(0x28, 12, 1), +}; + +static const struct iproc_clk_ctrl mipipll_clk[] = { + [BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = { + .channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED, + .flags = IPROC_CLK_NEEDS_READ_BACK, + .enable = enable_val(0x4, 12, 6, 18), + .mdiv = reg_val(0x20, 0, 8), + }, + [BCM_CYGNUS_MIPIPLL_CH1_LCD] = { + .channel = BCM_CYGNUS_MIPIPLL_CH1_LCD, + .flags = IPROC_CLK_NEEDS_READ_BACK, + .enable = enable_val(0x4, 13, 7, 19), + .mdiv = reg_val(0x20, 10, 8), + }, + [BCM_CYGNUS_MIPIPLL_CH2_V3D] = { + .channel = BCM_CYGNUS_MIPIPLL_CH2_V3D, + .flags = IPROC_CLK_NEEDS_READ_BACK, + .enable = enable_val(0x4, 14, 8, 20), + .mdiv = reg_val(0x20, 20, 8), + }, + [BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = { + .channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED, + .flags = IPROC_CLK_NEEDS_READ_BACK, + .enable = enable_val(0x4, 15, 9, 21), + .mdiv = reg_val(0x24, 0, 8), + }, + [BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = { + .channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED, + .flags = IPROC_CLK_NEEDS_READ_BACK, + .enable = enable_val(0x4, 16, 10, 22), + .mdiv = reg_val(0x24, 10, 8), + }, + [BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = { + .channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED, + .flags = IPROC_CLK_NEEDS_READ_BACK, + .enable = enable_val(0x4, 17, 11, 23), + .mdiv = reg_val(0x24, 20, 8), + }, +}; + +static void __init cygnus_mipipll_clk_init(struct device_node *node) +{ + iproc_pll_clk_setup(node, &mipipll, mipipll_vco_params, + ARRAY_SIZE(mipipll_vco_params), mipipll_clk, + ARRAY_SIZE(mipipll_clk)); +} +CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init); + +static const struct iproc_asiu_div asiu_div[] = { + [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_div_val(0x0, 31, 16, 10, 0, 10), + [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_div_val(0x4, 31, 16, 10, 0, 10), + [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_div_val(0x8, 31, 16, 10, 0, 10), +}; + +static const struct iproc_asiu_gate asiu_gate[] = { + [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_gate_val(0x0, 7), + [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_gate_val(0x0, 9), + [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0), +}; + +static void __init cygnus_asiu_init(struct device_node *node) +{ + iproc_asiu_setup(node, asiu_div, asiu_gate, ARRAY_SIZE(asiu_div)); +} +CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init); diff --git a/include/dt-bindings/clock/bcm-cygnus.h b/include/dt-bindings/clock/bcm-cygnus.h new file mode 100644 index 000000000000..32fbc475087a --- /dev/null +++ b/include/dt-bindings/clock/bcm-cygnus.h @@ -0,0 +1,68 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2014 Broadcom Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CLOCK_BCM_CYGNUS_H +#define _CLOCK_BCM_CYGNUS_H + +/* GENPLL clock ID */ +#define BCM_CYGNUS_GENPLL 0 +#define BCM_CYGNUS_GENPLL_AXI21_CLK 1 +#define BCM_CYGNUS_GENPLL_250MHZ_CLK 2 +#define BCM_CYGNUS_GENPLL_IHOST_SYS_CLK 3 +#define BCM_CYGNUS_GENPLL_ENET_SW_CLK 4 +#define BCM_CYGNUS_GENPLL_AUDIO_125_CLK 5 +#define BCM_CYGNUS_GENPLL_CAN_CLK 6 + +/* LCPLL0 clock ID */ +#define BCM_CYGNUS_LCPLL0 0 +#define BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK 1 +#define BCM_CYGNUS_LCPLL0_DDR_PHY_CLK 2 +#define BCM_CYGNUS_LCPLL0_SDIO_CLK 3 +#define BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK 4 +#define BCM_CYGNUS_LCPLL0_SMART_CARD_CLK 5 +#define BCM_CYGNUS_LCPLL0_CH5_UNUSED 6 + +/* MIPI PLL clock ID */ +#define BCM_CYGNUS_MIPIPLL 0 +#define BCM_CYGNUS_MIPIPLL_CH0_UNUSED 1 +#define BCM_CYGNUS_MIPIPLL_CH1_LCD 2 +#define BCM_CYGNUS_MIPIPLL_CH2_V3D 3 +#define BCM_CYGNUS_MIPIPLL_CH3_UNUSED 4 +#define BCM_CYGNUS_MIPIPLL_CH4_UNUSED 5 +#define BCM_CYGNUS_MIPIPLL_CH5_UNUSED 6 + +/* ASIU clock ID */ +#define BCM_CYGNUS_ASIU_KEYPAD_CLK 0 +#define BCM_CYGNUS_ASIU_ADC_CLK 1 +#define BCM_CYGNUS_ASIU_PWM_CLK 2 + +#endif /* _CLOCK_BCM_CYGNUS_H */ -- cgit v1.2.3 From b04e0b8fd5443b61c04e6103f16c5d1e1821e295 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 28 May 2015 22:31:43 +0200 Subject: clk: add lpc18xx cgu clk driver Add driver for NXP LPC18xx/43xx Clock Generation Unit (CGU). The CGU contains several clock generators and output stages that route the clocks either directly to peripherals or to a Clock Control Unit (CCU). Signed-off-by: Joachim Eastwood Signed-off-by: Michael Turquette --- drivers/clk/Makefile | 1 + drivers/clk/nxp/Makefile | 1 + drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 ++++++++++++++++++++++++++++++++ include/dt-bindings/clock/lpc18xx-cgu.h | 41 +++ 4 files changed, 678 insertions(+) create mode 100644 drivers/clk/nxp/Makefile create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h (limited to 'include/dt-bindings') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d4bc8ed29984..256977ed050a 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -57,6 +57,7 @@ endif obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_ARCH_MXS) += mxs/ +obj-$(CONFIG_ARCH_LPC18XX) += nxp/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile new file mode 100644 index 000000000000..aca9d3e4f7fe --- /dev/null +++ b/drivers/clk/nxp/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c new file mode 100644 index 000000000000..81e9e1c788f4 --- /dev/null +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -0,0 +1,635 @@ +/* + * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU) + * + * Copyright (C) 2015 Joachim Eastwood + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* Clock Generation Unit (CGU) registers */ +#define LPC18XX_CGU_XTAL_OSC_CTRL 0x018 +#define LPC18XX_CGU_PLL0USB_STAT 0x01c +#define LPC18XX_CGU_PLL0USB_CTRL 0x020 +#define LPC18XX_CGU_PLL0USB_MDIV 0x024 +#define LPC18XX_CGU_PLL0USB_NP_DIV 0x028 +#define LPC18XX_CGU_PLL0AUDIO_STAT 0x02c +#define LPC18XX_CGU_PLL0AUDIO_CTRL 0x030 +#define LPC18XX_CGU_PLL0AUDIO_MDIV 0x034 +#define LPC18XX_CGU_PLL0AUDIO_NP_DIV 0x038 +#define LPC18XX_CGU_PLL0AUDIO_FRAC 0x03c +#define LPC18XX_CGU_PLL1_STAT 0x040 +#define LPC18XX_CGU_PLL1_CTRL 0x044 +#define LPC18XX_PLL1_CTRL_FBSEL BIT(6) +#define LPC18XX_PLL1_CTRL_DIRECT BIT(7) +#define LPC18XX_CGU_IDIV_CTRL(n) (0x048 + (n) * sizeof(u32)) +#define LPC18XX_CGU_BASE_CLK(id) (0x05c + (id) * sizeof(u32)) +#define LPC18XX_CGU_PLL_CTRL_OFFSET 0x4 + +/* PLL0 bits common to both audio and USB PLL */ +#define LPC18XX_PLL0_STAT_LOCK BIT(0) +#define LPC18XX_PLL0_CTRL_PD BIT(0) +#define LPC18XX_PLL0_CTRL_BYPASS BIT(1) +#define LPC18XX_PLL0_CTRL_DIRECTI BIT(2) +#define LPC18XX_PLL0_CTRL_DIRECTO BIT(3) +#define LPC18XX_PLL0_CTRL_CLKEN BIT(4) +#define LPC18XX_PLL0_MDIV_MDEC_MASK 0x1ffff +#define LPC18XX_PLL0_MDIV_SELP_SHIFT 17 +#define LPC18XX_PLL0_MDIV_SELI_SHIFT 22 +#define LPC18XX_PLL0_MSEL_MAX BIT(15) + +/* Register value that gives PLL0 post/pre dividers equal to 1 */ +#define LPC18XX_PLL0_NP_DIVS_1 0x00302062 + +enum { + CLK_SRC_OSC32, + CLK_SRC_IRC, + CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, + CLK_SRC_GP_CLKIN, + CLK_SRC_RESERVED1, + CLK_SRC_OSC, + CLK_SRC_PLL0USB, + CLK_SRC_PLL0AUDIO, + CLK_SRC_PLL1, + CLK_SRC_RESERVED2, + CLK_SRC_RESERVED3, + CLK_SRC_IDIVA, + CLK_SRC_IDIVB, + CLK_SRC_IDIVC, + CLK_SRC_IDIVD, + CLK_SRC_IDIVE, + CLK_SRC_MAX +}; + +static const char *clk_src_names[CLK_SRC_MAX] = { + [CLK_SRC_OSC32] = "osc32", + [CLK_SRC_IRC] = "irc", + [CLK_SRC_ENET_RX_CLK] = "enet_rx_clk", + [CLK_SRC_ENET_TX_CLK] = "enet_tx_clk", + [CLK_SRC_GP_CLKIN] = "gp_clkin", + [CLK_SRC_OSC] = "osc", + [CLK_SRC_PLL0USB] = "pll0usb", + [CLK_SRC_PLL0AUDIO] = "pll0audio", + [CLK_SRC_PLL1] = "pll1", + [CLK_SRC_IDIVA] = "idiva", + [CLK_SRC_IDIVB] = "idivb", + [CLK_SRC_IDIVC] = "idivc", + [CLK_SRC_IDIVD] = "idivd", + [CLK_SRC_IDIVE] = "idive", +}; + +static const char *clk_base_names[BASE_CLK_MAX] = { + [BASE_SAFE_CLK] = "base_safe_clk", + [BASE_USB0_CLK] = "base_usb0_clk", + [BASE_PERIPH_CLK] = "base_periph_clk", + [BASE_USB1_CLK] = "base_usb1_clk", + [BASE_CPU_CLK] = "base_cpu_clk", + [BASE_SPIFI_CLK] = "base_spifi_clk", + [BASE_SPI_CLK] = "base_spi_clk", + [BASE_PHY_RX_CLK] = "base_phy_rx_clk", + [BASE_PHY_TX_CLK] = "base_phy_tx_clk", + [BASE_APB1_CLK] = "base_apb1_clk", + [BASE_APB3_CLK] = "base_apb3_clk", + [BASE_LCD_CLK] = "base_lcd_clk", + [BASE_ADCHS_CLK] = "base_adchs_clk", + [BASE_SDIO_CLK] = "base_sdio_clk", + [BASE_SSP0_CLK] = "base_ssp0_clk", + [BASE_SSP1_CLK] = "base_ssp1_clk", + [BASE_UART0_CLK] = "base_uart0_clk", + [BASE_UART1_CLK] = "base_uart1_clk", + [BASE_UART2_CLK] = "base_uart2_clk", + [BASE_UART3_CLK] = "base_uart3_clk", + [BASE_OUT_CLK] = "base_out_clk", + [BASE_AUDIO_CLK] = "base_audio_clk", + [BASE_CGU_OUT0_CLK] = "base_cgu_out0_clk", + [BASE_CGU_OUT1_CLK] = "base_cgu_out1_clk", +}; + +static u32 lpc18xx_cgu_pll0_src_ids[] = { + CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, + CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC, + CLK_SRC_IDIVD, CLK_SRC_IDIVE, +}; + +static u32 lpc18xx_cgu_pll1_src_ids[] = { + CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, + CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA, + CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE, +}; + +static u32 lpc18xx_cgu_idiva_src_ids[] = { + CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, + CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1 +}; + +static u32 lpc18xx_cgu_idivbcde_src_ids[] = { + CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, + CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA, +}; + +static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC}; + +static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB}; + +static u32 lpc18xx_cgu_base_common_src_ids[] = { + CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, + CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA, + CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE, +}; + +static u32 lpc18xx_cgu_base_all_src_ids[] = { + CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, + CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, + CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, + CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC, + CLK_SRC_IDIVD, CLK_SRC_IDIVE, +}; + +struct lpc18xx_cgu_src_clk_div { + u8 clk_id; + u8 n_parents; + struct clk_divider div; + struct clk_mux mux; + struct clk_gate gate; +}; + +#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table) \ +{ \ + .clk_id = CLK_SRC_ ##_id, \ + .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ + .div = { \ + .shift = 2, \ + .width = _width, \ + }, \ + .mux = { \ + .mask = 0x1f, \ + .shift = 24, \ + .table = lpc18xx_cgu_ ##_table, \ + }, \ + .gate = { \ + .bit_idx = 0, \ + .flags = CLK_GATE_SET_TO_DISABLE, \ + }, \ +} + +static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = { + LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids), + LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids), + LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids), + LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids), + LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids), +}; + +struct lpc18xx_cgu_base_clk { + u8 clk_id; + u8 n_parents; + struct clk_mux mux; + struct clk_gate gate; +}; + +#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags) \ +{ \ + .clk_id = BASE_ ##_id ##_CLK, \ + .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ + .mux = { \ + .mask = 0x1f, \ + .shift = 24, \ + .table = lpc18xx_cgu_ ##_table, \ + .flags = _flags, \ + }, \ + .gate = { \ + .bit_idx = 0, \ + .flags = CLK_GATE_SET_TO_DISABLE, \ + }, \ +} + +static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = { + LPC1XX_CGU_BASE_CLK(SAFE, base_irc_src_ids, CLK_MUX_READ_ONLY), + LPC1XX_CGU_BASE_CLK(USB0, base_usb0_src_ids, 0), + LPC1XX_CGU_BASE_CLK(PERIPH, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(USB1, base_all_src_ids, 0), + LPC1XX_CGU_BASE_CLK(CPU, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(SPIFI, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(SPI, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(PHY_RX, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(PHY_TX, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(APB1, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(APB3, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(LCD, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(ADCHS, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(SDIO, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(SSP0, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(SSP1, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(UART0, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(UART1, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(UART2, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(UART3, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(OUT, base_all_src_ids, 0), + { /* 21 reserved */ }, + { /* 22 reserved */ }, + { /* 23 reserved */ }, + { /* 24 reserved */ }, + LPC1XX_CGU_BASE_CLK(AUDIO, base_common_src_ids, 0), + LPC1XX_CGU_BASE_CLK(CGU_OUT0, base_all_src_ids, 0), + LPC1XX_CGU_BASE_CLK(CGU_OUT1, base_all_src_ids, 0), +}; + +struct lpc18xx_pll { + struct clk_hw hw; + void __iomem *reg; + spinlock_t *lock; + u8 flags; +}; + +#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw) + +struct lpc18xx_cgu_pll_clk { + u8 clk_id; + u8 n_parents; + u8 reg_offset; + struct clk_mux mux; + struct clk_gate gate; + struct lpc18xx_pll pll; + const struct clk_ops *pll_ops; +}; + +#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops) \ +{ \ + .clk_id = CLK_SRC_ ##_id, \ + .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ + .reg_offset = LPC18XX_CGU_ ##_id ##_STAT, \ + .mux = { \ + .mask = 0x1f, \ + .shift = 24, \ + .table = lpc18xx_cgu_ ##_table, \ + }, \ + .gate = { \ + .bit_idx = 0, \ + .flags = CLK_GATE_SET_TO_DISABLE, \ + }, \ + .pll_ops = &lpc18xx_ ##_pll_ops, \ +} + +/* + * PLL0 uses a special register value encoding. The compute functions below + * are taken or derived from the LPC1850 user manual (section 12.6.3.3). + */ + +/* Compute PLL0 multiplier from decoded version */ +static u32 lpc18xx_pll0_mdec2msel(u32 x) +{ + int i; + + switch (x) { + case 0x18003: return 1; + case 0x10003: return 2; + default: + for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--) + x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff); + return i; + } +} +/* Compute PLL0 decoded multiplier from binary version */ +static u32 lpc18xx_pll0_msel2mdec(u32 msel) +{ + u32 i, x = 0x4000; + + switch (msel) { + case 0: return 0; + case 1: return 0x18003; + case 2: return 0x10003; + default: + for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++) + x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff); + return x; + } +} + +/* Compute PLL0 bandwidth SELI reg from multiplier */ +static u32 lpc18xx_pll0_msel2seli(u32 msel) +{ + u32 tmp; + + if (msel > 16384) return 1; + if (msel > 8192) return 2; + if (msel > 2048) return 4; + if (msel >= 501) return 8; + if (msel >= 60) { + tmp = 1024 / (msel + 9); + return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4; + } + + return (msel & 0x3c) + 4; +} + +/* Compute PLL0 bandwidth SELP reg from multiplier */ +static u32 lpc18xx_pll0_msel2selp(u32 msel) +{ + if (msel < 60) + return (msel >> 1) + 1; + + return 31; +} + +static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct lpc18xx_pll *pll = to_lpc_pll(hw); + u32 ctrl, mdiv, msel, npdiv; + + ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV); + npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); + + if (ctrl & LPC18XX_PLL0_CTRL_BYPASS) + return parent_rate; + + if (npdiv != LPC18XX_PLL0_NP_DIVS_1) { + pr_warn("%s: pre/post dividers not supported\n", __func__); + return 0; + } + + msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK); + if (msel) + return 2 * msel * parent_rate; + + pr_warn("%s: unable to calculate rate\n", __func__); + + return 0; +} + +static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long m; + + if (*prate < rate) { + pr_warn("%s: pll dividers not supported\n", __func__); + return -EINVAL; + } + + m = DIV_ROUND_UP_ULL(*prate, rate * 2); + if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { + pr_warn("%s: unable to support rate %lu\n", __func__, rate); + return -EINVAL; + } + + return 2 * *prate * m; +} + +static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct lpc18xx_pll *pll = to_lpc_pll(hw); + u32 ctrl, stat, m; + int retry = 3; + + if (parent_rate < rate) { + pr_warn("%s: pll dividers not supported\n", __func__); + return -EINVAL; + } + + m = DIV_ROUND_UP_ULL(parent_rate, rate * 2); + if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { + pr_warn("%s: unable to support rate %lu\n", __func__, rate); + return -EINVAL; + } + + m = lpc18xx_pll0_msel2mdec(m); + m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT; + m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT; + + /* Power down PLL, disable clk output and dividers */ + ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + ctrl |= LPC18XX_PLL0_CTRL_PD; + ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI | + LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN); + clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + + /* Configure new PLL settings */ + clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV); + clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); + + /* Power up PLL and wait for lock */ + ctrl &= ~LPC18XX_PLL0_CTRL_PD; + clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + do { + udelay(10); + stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT); + if (stat & LPC18XX_PLL0_STAT_LOCK) { + ctrl |= LPC18XX_PLL0_CTRL_CLKEN; + clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); + + return 0; + } + } while (retry--); + + pr_warn("%s: unable to lock pll\n", __func__); + + return -EINVAL; +} + +static const struct clk_ops lpc18xx_pll0_ops = { + .recalc_rate = lpc18xx_pll0_recalc_rate, + .round_rate = lpc18xx_pll0_round_rate, + .set_rate = lpc18xx_pll0_set_rate, +}; + +static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct lpc18xx_pll *pll = to_lpc_pll(hw); + u16 msel, nsel, psel; + bool direct, fbsel; + u32 stat, ctrl; + + stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT); + ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL); + + direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false; + fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false; + + msel = ((ctrl >> 16) & 0xff) + 1; + nsel = ((ctrl >> 12) & 0x3) + 1; + + if (direct || fbsel) + return msel * (parent_rate / nsel); + + psel = (ctrl >> 8) & 0x3; + psel = 1 << psel; + + return (msel / (2 * psel)) * (parent_rate / nsel); +} + +static const struct clk_ops lpc18xx_pll1_ops = { + .recalc_rate = lpc18xx_pll1_recalc_rate, +}; + +static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = { + LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops), + LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops), + LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops), +}; + +static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size) +{ + int i; + + for (i = 0; i < size; i++) + parent[i] = clk_src_names[id[i]]; +} + +static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk, + void __iomem *base, int n) +{ + void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n); + const char *name = clk_src_names[clk->clk_id]; + const char *parents[CLK_SRC_MAX]; + + clk->div.reg = reg; + clk->mux.reg = reg; + clk->gate.reg = reg; + + lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); + + return clk_register_composite(NULL, name, parents, clk->n_parents, + &clk->mux.hw, &clk_mux_ops, + &clk->div.hw, &clk_divider_ops, + &clk->gate.hw, &clk_gate_ops, 0); +} + + +static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk, + void __iomem *reg_base, int n) +{ + void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n); + const char *name = clk_base_names[clk->clk_id]; + const char *parents[CLK_SRC_MAX]; + + if (clk->n_parents == 0) + return ERR_PTR(-ENOENT); + + clk->mux.reg = reg; + clk->gate.reg = reg; + + lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); + + /* SAFE_CLK can not be turned off */ + if (n == BASE_SAFE_CLK) + return clk_register_composite(NULL, name, parents, clk->n_parents, + &clk->mux.hw, &clk_mux_ops, + NULL, NULL, NULL, NULL, 0); + + return clk_register_composite(NULL, name, parents, clk->n_parents, + &clk->mux.hw, &clk_mux_ops, + NULL, NULL, + &clk->gate.hw, &clk_gate_ops, 0); +} + + +static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk, + void __iomem *base) +{ + const char *name = clk_src_names[clk->clk_id]; + const char *parents[CLK_SRC_MAX]; + + clk->pll.reg = base; + clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; + clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; + + lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); + + return clk_register_composite(NULL, name, parents, clk->n_parents, + &clk->mux.hw, &clk_mux_ops, + &clk->pll.hw, clk->pll_ops, + &clk->gate.hw, &clk_gate_ops, 0); +} + +static void __init lpc18xx_cgu_register_source_clks(struct device_node *np, + void __iomem *base) +{ + const char *parents[CLK_SRC_MAX]; + struct clk *clk; + int i; + + /* Register the internal 12 MHz RC oscillator (IRC) */ + clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC], + NULL, CLK_IS_ROOT, 12000000); + if (IS_ERR(clk)) + pr_warn("%s: failed to register irc clk\n", __func__); + + /* Register crystal oscillator controlller */ + parents[0] = of_clk_get_parent_name(np, 0); + clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0], + 0, base + LPC18XX_CGU_XTAL_OSC_CTRL, + 0, CLK_GATE_SET_TO_DISABLE, NULL); + if (IS_ERR(clk)) + pr_warn("%s: failed to register osc clk\n", __func__); + + /* Register all PLLs */ + for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) { + clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i], + base); + if (IS_ERR(clk)) + pr_warn("%s: failed to register pll (%d)\n", __func__, i); + } + + /* Register all clock dividers A-E */ + for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) { + clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i], + base, i); + if (IS_ERR(clk)) + pr_warn("%s: failed to register div %d\n", __func__, i); + } +} + +static struct clk *clk_base[BASE_CLK_MAX]; +static struct clk_onecell_data clk_base_data = { + .clks = clk_base, + .clk_num = BASE_CLK_MAX, +}; + +static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base) +{ + int i; + + for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) { + clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i], + reg_base, i); + if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT) + pr_warn("%s: register base clk %d failed\n", __func__, i); + } +} + +static void __init lpc18xx_cgu_init(struct device_node *np) +{ + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_warn("%s: failed to map address range\n", __func__); + return; + } + + lpc18xx_cgu_register_source_clks(np, reg_base); + lpc18xx_cgu_register_base_clks(reg_base); + + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data); +} +CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init); diff --git a/include/dt-bindings/clock/lpc18xx-cgu.h b/include/dt-bindings/clock/lpc18xx-cgu.h new file mode 100644 index 000000000000..6e57c6d2ca66 --- /dev/null +++ b/include/dt-bindings/clock/lpc18xx-cgu.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Joachim Eastwood + * + * This code is released using a dual license strategy: BSD/GPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of 3-clause BSD License + * Released under the terms of GNU General Public License Version 2.0 + * + */ + +/* LPC18xx/43xx base clock ids */ +#define BASE_SAFE_CLK 0 +#define BASE_USB0_CLK 1 +#define BASE_PERIPH_CLK 2 +#define BASE_USB1_CLK 3 +#define BASE_CPU_CLK 4 +#define BASE_SPIFI_CLK 5 +#define BASE_SPI_CLK 6 +#define BASE_PHY_RX_CLK 7 +#define BASE_PHY_TX_CLK 8 +#define BASE_APB1_CLK 9 +#define BASE_APB3_CLK 10 +#define BASE_LCD_CLK 11 +#define BASE_ADCHS_CLK 12 +#define BASE_SDIO_CLK 13 +#define BASE_SSP0_CLK 14 +#define BASE_SSP1_CLK 15 +#define BASE_UART0_CLK 16 +#define BASE_UART1_CLK 17 +#define BASE_UART2_CLK 18 +#define BASE_UART3_CLK 19 +#define BASE_OUT_CLK 20 +#define BASE_RES1_CLK 21 +#define BASE_RES2_CLK 22 +#define BASE_RES3_CLK 23 +#define BASE_RES4_CLK 24 +#define BASE_AUDIO_CLK 25 +#define BASE_CGU_OUT0_CLK 26 +#define BASE_CGU_OUT1_CLK 27 +#define BASE_CLK_MAX (BASE_CGU_OUT1_CLK + 1) -- cgit v1.2.3 From 472cd304a36e0a1b21045ddc802ffb16a1cbac65 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 28 May 2015 22:31:45 +0200 Subject: clk: add lpc18xx ccu clk driver Add driver for NXP LPC18xx/43xx Clock Control Unit (CCU). The CCU provides fine grained gating of most clocks present in the SoC. Signed-off-by: Joachim Eastwood Signed-off-by: Michael Turquette --- drivers/clk/nxp/Makefile | 1 + drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++++++++++++++++++++++++ include/dt-bindings/clock/lpc18xx-ccu.h | 74 ++++++++ 3 files changed, 368 insertions(+) create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h (limited to 'include/dt-bindings') diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile index aca9d3e4f7fe..7f608b0ad7b4 100644 --- a/drivers/clk/nxp/Makefile +++ b/drivers/clk/nxp/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o +obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-ccu.o diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c new file mode 100644 index 000000000000..eeaee97da110 --- /dev/null +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -0,0 +1,293 @@ +/* + * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU) + * + * Copyright (C) 2015 Joachim Eastwood + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Bit defines for CCU branch configuration register */ +#define LPC18XX_CCU_RUN BIT(0) +#define LPC18XX_CCU_AUTO BIT(1) +#define LPC18XX_CCU_DIV BIT(5) +#define LPC18XX_CCU_DIVSTAT BIT(27) + +/* CCU branch feature bits */ +#define CCU_BRANCH_IS_BUS BIT(0) +#define CCU_BRANCH_HAVE_DIV2 BIT(1) + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +struct lpc18xx_branch_clk_data { + const char **name; + int num; +}; + +struct lpc18xx_clk_branch { + const char *base_name; + const char *name; + u16 offset; + u16 flags; + struct clk *clk; + struct clk_gate gate; +}; + +static struct lpc18xx_clk_branch clk_branches[] = { + {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS}, + {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0}, + {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0}, + {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0}, + {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0}, + {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0}, + + {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS}, + {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0}, + {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0}, + {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0}, + {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0}, + + {"base_spifi_clk", "spifi", CLK_SPIFI, 0}, + + {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS}, + {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0}, + {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0}, + {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0}, + {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0}, + {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0}, + {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0}, + {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0}, + {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0}, + {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0}, + {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0}, + {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0}, + {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2}, + {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2}, + {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2}, + {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2}, + {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2}, + {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2}, + {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0}, + {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0}, + {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0}, + {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0}, + {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0}, + {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0}, + {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0}, + {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0}, + {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0}, + {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0}, + {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0}, + {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0}, + {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0}, + {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0}, + {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0}, + + {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS}, + {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0}, + {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0}, + + {"base_usb0_clk", "usb0", CLK_USB0, 0}, + {"base_usb1_clk", "usb1", CLK_USB1, 0}, + {"base_spi_clk", "spi", CLK_SPI, 0}, + {"base_adchs_clk", "adchs", CLK_ADCHS, 0}, + + {"base_audio_clk", "audio", CLK_AUDIO, 0}, + {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0}, + {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0}, + {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0}, + {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0}, + {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0}, + {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0}, + {"base_sdio_clk", "sdio", CLK_SDIO, 0}, +}; + +static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec, + void *data) +{ + struct lpc18xx_branch_clk_data *clk_data = data; + unsigned int offset = clkspec->args[0]; + int i, j; + + for (i = 0; i < ARRAY_SIZE(clk_branches); i++) { + if (clk_branches[i].offset != offset) + continue; + + for (j = 0; j < clk_data->num; j++) { + if (!strcmp(clk_branches[i].base_name, clk_data->name[j])) + return clk_branches[i].clk; + } + } + + pr_err("%s: invalid clock offset %d\n", __func__, offset); + + return ERR_PTR(-EINVAL); +} + +static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable) +{ + struct clk_gate *gate = to_clk_gate(hw); + u32 val; + + /* + * Divider field is write only, so divider stat field must + * be read so divider field can be set accordingly. + */ + val = clk_readl(gate->reg); + if (val & LPC18XX_CCU_DIVSTAT) + val |= LPC18XX_CCU_DIV; + + if (enable) { + val |= LPC18XX_CCU_RUN; + } else { + /* + * To safely disable a branch clock a squence of two separate + * writes must be used. First write should set the AUTO bit + * and the next write should clear the RUN bit. + */ + val |= LPC18XX_CCU_AUTO; + clk_writel(val, gate->reg); + + val &= ~LPC18XX_CCU_RUN; + } + + clk_writel(val, gate->reg); + + return 0; +} + +static int lpc18xx_ccu_gate_enable(struct clk_hw *hw) +{ + return lpc18xx_ccu_gate_endisable(hw, true); +} + +static void lpc18xx_ccu_gate_disable(struct clk_hw *hw) +{ + lpc18xx_ccu_gate_endisable(hw, false); +} + +static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + + return clk_readl(gate->reg) & LPC18XX_CCU_RUN; +} + +static const struct clk_ops lpc18xx_ccu_gate_ops = { + .enable = lpc18xx_ccu_gate_enable, + .disable = lpc18xx_ccu_gate_disable, + .is_enabled = lpc18xx_ccu_gate_is_enabled, +}; + +static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch, + void __iomem *reg_base, + const char *parent) +{ + const struct clk_ops *div_ops = NULL; + struct clk_divider *div = NULL; + struct clk_hw *div_hw = NULL; + + if (branch->flags & CCU_BRANCH_HAVE_DIV2) { + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return; + + div->reg = branch->offset + reg_base; + div->flags = CLK_DIVIDER_READ_ONLY; + div->shift = 27; + div->width = 1; + + div_hw = &div->hw; + div_ops = &clk_divider_ops; + } + + branch->gate.reg = branch->offset + reg_base; + branch->gate.bit_idx = 0; + + branch->clk = clk_register_composite(NULL, branch->name, &parent, 1, + NULL, NULL, + div_hw, div_ops, + &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0); + if (IS_ERR(branch->clk)) { + kfree(div); + pr_warn("%s: failed to register %s\n", __func__, branch->name); + return; + } + + /* Grab essential branch clocks for CPU and SDRAM */ + switch (branch->offset) { + case CLK_CPU_EMC: + case CLK_CPU_CORE: + case CLK_CPU_CREG: + case CLK_CPU_EMCDIV: + clk_prepare_enable(branch->clk); + } +} + +static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base, + const char *base_name) +{ + const char *parent = base_name; + int i; + + for (i = 0; i < ARRAY_SIZE(clk_branches); i++) { + if (strcmp(clk_branches[i].base_name, base_name)) + continue; + + lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base, + parent); + + if (clk_branches[i].flags & CCU_BRANCH_IS_BUS) + parent = clk_branches[i].name; + } +} + +static void __init lpc18xx_ccu_init(struct device_node *np) +{ + struct lpc18xx_branch_clk_data *clk_data; + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_warn("%s: failed to map address range\n", __func__); + return; + } + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = of_property_count_strings(np, "clock-names"); + clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL); + if (!clk_data->name) { + kfree(clk_data); + return; + } + + for (i = 0; i < clk_data->num; i++) { + ret = of_property_read_string_index(np, "clock-names", i, + &clk_data->name[i]); + if (ret) { + pr_warn("%s: failed to get clock name at idx %d\n", + __func__, i); + continue; + } + + lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]); + } + + of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data); +} +CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init); diff --git a/include/dt-bindings/clock/lpc18xx-ccu.h b/include/dt-bindings/clock/lpc18xx-ccu.h new file mode 100644 index 000000000000..bbfe00b6ab7d --- /dev/null +++ b/include/dt-bindings/clock/lpc18xx-ccu.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015 Joachim Eastwood + * + * This code is released using a dual license strategy: BSD/GPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of 3-clause BSD License + * Released under the terms of GNU General Public License Version 2.0 + * + */ + +/* Clock Control Unit 1 (CCU1) clock offsets */ +#define CLK_APB3_BUS 0x100 +#define CLK_APB3_I2C1 0x108 +#define CLK_APB3_DAC 0x110 +#define CLK_APB3_ADC0 0x118 +#define CLK_APB3_ADC1 0x120 +#define CLK_APB3_CAN0 0x128 +#define CLK_APB1_BUS 0x200 +#define CLK_APB1_MOTOCON_PWM 0x208 +#define CLK_APB1_I2C0 0x210 +#define CLK_APB1_I2S 0x218 +#define CLK_APB1_CAN1 0x220 +#define CLK_SPIFI 0x300 +#define CLK_CPU_BUS 0x400 +#define CLK_CPU_SPIFI 0x408 +#define CLK_CPU_GPIO 0x410 +#define CLK_CPU_LCD 0x418 +#define CLK_CPU_ETHERNET 0x420 +#define CLK_CPU_USB0 0x428 +#define CLK_CPU_EMC 0x430 +#define CLK_CPU_SDIO 0x438 +#define CLK_CPU_DMA 0x440 +#define CLK_CPU_CORE 0x448 +#define CLK_CPU_SCT 0x468 +#define CLK_CPU_USB1 0x470 +#define CLK_CPU_EMCDIV 0x478 +#define CLK_CPU_FLASHA 0x480 +#define CLK_CPU_FLASHB 0x488 +#define CLK_CPU_M0APP 0x490 +#define CLK_CPU_ADCHS 0x498 +#define CLK_CPU_EEPROM 0x4a0 +#define CLK_CPU_WWDT 0x500 +#define CLK_CPU_UART0 0x508 +#define CLK_CPU_UART1 0x510 +#define CLK_CPU_SSP0 0x518 +#define CLK_CPU_TIMER0 0x520 +#define CLK_CPU_TIMER1 0x528 +#define CLK_CPU_SCU 0x530 +#define CLK_CPU_CREG 0x538 +#define CLK_CPU_RITIMER 0x600 +#define CLK_CPU_UART2 0x608 +#define CLK_CPU_UART3 0x610 +#define CLK_CPU_TIMER2 0x618 +#define CLK_CPU_TIMER3 0x620 +#define CLK_CPU_SSP1 0x628 +#define CLK_CPU_QEI 0x630 +#define CLK_PERIPH_BUS 0x700 +#define CLK_PERIPH_CORE 0x710 +#define CLK_PERIPH_SGPIO 0x718 +#define CLK_USB0 0x800 +#define CLK_USB1 0x900 +#define CLK_SPI 0xA00 +#define CLK_ADCHS 0xB00 + +/* Clock Control Unit 2 (CCU2) clock offsets */ +#define CLK_AUDIO 0x100 +#define CLK_APB2_UART3 0x200 +#define CLK_APB2_UART2 0x300 +#define CLK_APB0_UART1 0x400 +#define CLK_APB0_UART0 0x500 +#define CLK_APB2_SSP1 0x600 +#define CLK_APB0_SSP0 0x700 +#define CLK_SDIO 0x800 -- cgit v1.2.3