diff options
author | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:02:07 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:02:07 +0800 |
commit | 9872ac864756839cbe0557ba4cdc975c44ec70d7 (patch) | |
tree | 9df4298c118128f7dacdc52f558488faaf75140b | |
parent | 1e188020fb52fdde34c9782d2189d068f6ef4d28 (diff) | |
parent | c8505b1bc2dd3a3d6f9e0b624f58f2d45a258a4f (diff) |
Merge branch 'clock/next' into next
* clock/next: (122 commits)
LF-279 clk: imx: scu: ignore cpu resources when do owned check
clk: s32v234: Enable FlexCAN clock
clk: s32v234: Add definitions for CAN clocks
clk: imx: Add missing mipi1_dsi_phy_clk
LF-202-3 clk: imx: scu: ignore clks not owned
...
69 files changed, 4365 insertions, 898 deletions
diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt index c149fadc6f47..fc5c22e81c61 100644 --- a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt @@ -89,7 +89,7 @@ Required properties: "fsl,imx8qm-clock" "fsl,imx8qxp-clock" followed by "fsl,scu-clk" -- #clock-cells: Should be 1. Contains the Clock ID value. +- #clock-cells: Should be 2: Contains the Resource and Clock ID value. - clocks: List of clock specifiers, must contain an entry for each required entry in clock-names - clock-names: Should include entries "xtal_32KHz", "xtal_24MHz" @@ -97,9 +97,6 @@ Required properties: The clock consumer should specify the desired clock by having the clock ID in its "clocks" phandle cell. -See the full list of clock IDs from: -include/dt-bindings/clock/imx8qxp-clock.h - Pinctrl bindings based on SCU Message Protocol ------------------------------------------------------------ @@ -186,7 +183,7 @@ firmware { clk: clk { compatible = "fsl,imx8qxp-clk", "fsl,scu-clk"; - #clock-cells = <1>; + #clock-cells = <2>; }; iomuxc { @@ -231,8 +228,7 @@ serial@5a060000 { ... pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart0>; - clocks = <&clk IMX8QXP_UART0_CLK>, - <&clk IMX8QXP_UART0_IPG_CLK>; - clock-names = "per", "ipg"; + clocks = <&uart0_clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER>; + clock-names = "ipg"; power-domains = <&pd IMX_SC_R_UART_0>; }; diff --git a/Documentation/devicetree/bindings/clock/fsl,plldig.yaml b/Documentation/devicetree/bindings/clock/fsl,plldig.yaml new file mode 100644 index 000000000000..ee5b5c61a471 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fsl,plldig.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/clock/fsl,plldig.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP QorIQ Layerscape LS1028A Display PIXEL Clock Binding + +maintainers: + - Wen He <wen.he_1@nxp.com> + +description: | + NXP LS1028A has a clock domain PXLCLK0 used for the Display output + interface in the display core, as implemented in TSMC CLN28HPM PLL. + which generate and offers pixel clocks to Display. + +properties: + compatible: + const: fsl,ls1028a-plldig + + reg: + maxItems: 1 + + '#clock-cells': + const: 0 + + vco-frequency: + $ref: '/schemas/types.yaml#/definitions/uint32' + description: Optional for VCO frequency of the PLL in Hertz. + The VCO frequency of this PLL cannot be changed during runtime + only at startup. Therefore, the output frequencies are very + limited and might not even closely match the requested frequency. + To work around this restriction the user may specify its own + desired VCO frequency for the PLL. The frequency has to be in the + range of 650000000 to 1300000000. + If not set, the default frequency is 1188000000. + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +examples: + # Display PIXEL Clock node: + - | + dpclk: clock-display@f1f0000 { + compatible = "fsl,ls1028a-plldig"; + reg = <0x0 0xf1f0000 0x0 0xffff>; + #clock-cells = <0>; + clocks = <&osc_27m>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt index a4f8cd478f92..93d89adb7afe 100644 --- a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -82,7 +82,6 @@ pcc2: pcc2@403f0000 { <&scg1 IMX7ULP_CLK_APLL_PFD0>, <&scg1 IMX7ULP_CLK_UPLL>, <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>, - <&scg1 IMX7ULP_CLK_MIPI_PLL>, <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>, <&scg1 IMX7ULP_CLK_ROSC>, <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>; diff --git a/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt b/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt index 965cfa42e025..8faee11b20b4 100644 --- a/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt +++ b/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt @@ -11,32 +11,38 @@ enabled by these control bits, it might still not be running based on the base resource. Required properties: -- compatible: Should be one of: - "fsl,imx8qxp-lpcg-adma", - "fsl,imx8qxp-lpcg-conn", - "fsl,imx8qxp-lpcg-dc", - "fsl,imx8qxp-lpcg-dsp", - "fsl,imx8qxp-lpcg-gpu", - "fsl,imx8qxp-lpcg-hsio", - "fsl,imx8qxp-lpcg-img", - "fsl,imx8qxp-lpcg-lsio", - "fsl,imx8qxp-lpcg-vpu" -- reg: Address and length of the register set -- #clock-cells: Should be <1> +- compatible: Should be one of: + "fsl,imx8qxp-lpcg" + "fsl,imx8qm-lpcg" followed by "fsl,imx8qxp-lpcg". +- reg: Address and length of the register set. +- #clock-cells: Should be 1. One LPCG supports multiple clocks. +- clocks: Input parent clocks phandle array for each clock. +- bit-offset: An integer array indicating the bit offset for each clock. +- hw-autogate: Boolean array indicating whether supports HW autogate for + each clock. +- clock-output-names: Shall be the corresponding names of the outputs. + NOTE this property must be specified in the same order + as the clock bit-offset and hw-autogate property. +- power-domains: Should contain the power domain used by this clock. The clock consumer should specify the desired clock by having the clock ID in its "clocks" phandle cell. -See the full list of clock IDs from: -include/dt-bindings/clock/imx8qxp-clock.h Examples: #include <dt-bindings/clock/imx8qxp-clock.h> -conn_lpcg: clock-controller@5b200000 { - compatible = "fsl,imx8qxp-lpcg-conn"; - reg = <0x5b200000 0xb0000>; +sdhc0_lpcg: clock-controller@5b200000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5b200000 0x10000>; #clock-cells = <1>; + clocks = <&sdhc0_clk IMX_SC_PM_CLK_PER>, + <&conn_ipg_clk>, <&conn_axi_clk>; + bit-offset = <0 16 20>; + clock-output-names = "sdhc0_lpcg_per_clk", + "sdhc0_lpcg_ipg_clk", + "sdhc0_lpcg_ahb_clk"; + power-domains = <&pd IMX_SC_R_SDHC_0>; }; usdhc1: mmc@5b010000 { @@ -44,8 +50,8 @@ usdhc1: mmc@5b010000 { interrupt-parent = <&gic>; interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>; reg = <0x5b010000 0x10000>; - clocks = <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_IPG_CLK>, - <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_PER_CLK>, - <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_HCLK>; + clocks = <&sdhc0_lpcg 1>, + <&sdhc0_lpcg 0>, + <&sdhc0_lpcg 2>; clock-names = "ipg", "per", "ahb"; }; diff --git a/Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt b/Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt new file mode 100644 index 000000000000..d0d43e6ae597 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt @@ -0,0 +1,31 @@ +* NXP S32V234 Clock Generation Modules (MC_CGMs) + +The SoC supports four Clock Generation Modules, which provide registers for +system and peripherals clock source selection and division. See chapters 22 +("Clocking"), 23 ("Clock Generation Module (MC_CGM)") and 69 ("Mode Entry +Module (MC_ME)") in the reference manual[1]. + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: + Should be: + - "fsl,s32v234-mc_cgm0" for MC_CGM_0 + - "fsl,s32v234-mc_cgm1" for MC_CGM_1 + - "fsl,s32v234-mc_cgm2" for MC_CGM_2 + - "fsl,s32v234-mc_cgm3" for MC_CGM_3 +- reg: + Location and length of the register set +- #clock-cells (only for MC_CGM_0): + Should be <1>. See dt-bindings/clock/s32v234-clock.h for the clock + specifiers allowed in the clocks property of consumers. + +Example: +clks: mc_cgm0@4003c000 { + compatible = "fsl,s32v234-mc_cgm0"; + reg = <0x0 0x4003C000 0x0 0x1000>; + #clock-cells = <1>; +}; + +[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM diff --git a/Documentation/devicetree/bindings/clock/s32v234-mc_me.txt b/Documentation/devicetree/bindings/clock/s32v234-mc_me.txt new file mode 100644 index 000000000000..e9f4dcc3a257 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/s32v234-mc_me.txt @@ -0,0 +1,16 @@ +* NXP S32V234 Mode Entry Module (MC_ME) + +See chapters 22 ("Clocking") and 69 ("Mode Entry Module (MC_ME)") in the +reference manual[1]. + +Required properties: +- compatible: Should be "fsl,s32v234-mc_me" +- reg: Location and length of the register set + +Example: +mc_me: mc_me@4004a000 { + compatible = "fsl,s32v234-mc_me"; + reg = <0x0 0x4004A000 0x0 0x1000>; +}; + +[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 577c8ae2a0c2..b4a5a4de80ee 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -218,6 +218,12 @@ config ARCH_ROCKCHIP This enables support for the ARMv8 based Rockchip chipsets, like the RK3368. +config ARCH_S32 + bool "NXP S32 SoC Family" + select ARCH_S32_CLK + help + This enables support for the NXP S32 family of processors. + config ARCH_SEATTLE bool "AMD Seattle SoC Family" help diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c44247d0b83e..2e67d597ab12 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -218,6 +218,16 @@ config CLK_QORIQ This adds the clock driver support for Freescale QorIQ platforms using common clock framework. +config CLK_LS1028A_PLLDIG + tristate "Clock driver for LS1028A Display output" + depends on ARCH_LAYERSCAPE || COMPILE_TEST + default ARCH_LAYERSCAPE + help + This driver support the Display output interfaces(LCD, DPHY) pixel clocks + of the QorIQ Layerscape LS1028A, as implemented TSMC CLN28HPM PLL. Not all + features of the PLL are currently supported by the driver. By default, + configured bypass mode with this PLL. + config COMMON_CLK_XGENE bool "Clock driver for APM XGene SoC" default ARCH_XGENE @@ -318,6 +328,7 @@ source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" source "drivers/clk/renesas/Kconfig" +source "drivers/clk/s32/Kconfig" source "drivers/clk/samsung/Kconfig" source "drivers/clk/sifive/Kconfig" source "drivers/clk/sprd/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 0138fb14e6f8..15488d4d358b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o +obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o @@ -97,6 +98,7 @@ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ +obj-$(CONFIG_ARCH_S32) += s32/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ obj-$(CONFIG_CLK_SIFIVE) += sifive/ obj-$(CONFIG_ARCH_SIRF) += sirf/ diff --git a/drivers/clk/clk-plldig.c b/drivers/clk/clk-plldig.c new file mode 100644 index 000000000000..365edd30da8c --- /dev/null +++ b/drivers/clk/clk-plldig.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + * + * Clock driver for LS1028A Display output interfaces(LCD, DPHY). + */ + +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/bitfield.h> + +/* PLLDIG register offsets and bit masks */ +#define PLLDIG_REG_PLLSR 0x24 +#define PLLDIG_LOCK_MASK BIT(2) +#define PLLDIG_REG_PLLDV 0x28 +#define PLLDIG_MFD_MASK GENMASK(7, 0) +#define PLLDIG_RFDPHI1_MASK GENMASK(30, 25) +#define PLLDIG_REG_PLLFM 0x2c +#define PLLDIG_SSCGBYP_ENABLE BIT(30) +#define PLLDIG_REG_PLLFD 0x30 +#define PLLDIG_FDEN BIT(30) +#define PLLDIG_FRAC_MASK GENMASK(15, 0) +#define PLLDIG_DTH_MASK GENMASK(17, 16) +#define PLLDIG_DTH_DISABLE 3 +#define PLLDIG_REG_PLLCAL1 0x38 +#define PLLDIG_REG_PLLCAL2 0x3c + +/* Range of the VCO frequencies, in Hz */ +#define PLLDIG_MIN_VCO_FREQ 650000000 +#define PLLDIG_MAX_VCO_FREQ 1300000000 + +/* Range of the output frequencies, in Hz */ +#define PHI1_MIN_FREQ 27000000 +#define PHI1_MAX_FREQ 600000000 + +/* Maximum value of the reduced frequency divider */ +#define MAX_RFDPHI1 63UL + +/* Best value of multiplication factor divider */ +#define PLLDIG_DEFAULT_MFD 44 + +/* + * Denominator part of the fractional part of the + * loop multiplication factor. + */ +#define MFDEN 20480 + +static const struct clk_parent_data parent_data[] = { + {.index = 0}, +}; + +struct clk_plldig { + struct clk_hw hw; + void __iomem *regs; + unsigned int vco_freq; +}; + +#define to_clk_plldig(_hw) container_of(_hw, struct clk_plldig, hw) + +static int plldig_enable(struct clk_hw *hw) +{ + struct clk_plldig *data = to_clk_plldig(hw); + u32 val; + + val = readl(data->regs + PLLDIG_REG_PLLFM); + /* + * Use Bypass mode with PLL off by default, the frequency overshoot + * detector output was disable. SSCG Bypass mode should be enable. + */ + val |= PLLDIG_SSCGBYP_ENABLE; + writel(val, data->regs + PLLDIG_REG_PLLFM); + + return 0; +} + +static void plldig_disable(struct clk_hw *hw) +{ + struct clk_plldig *data = to_clk_plldig(hw); + u32 val; + + val = readl(data->regs + PLLDIG_REG_PLLFM); + + val &= ~PLLDIG_SSCGBYP_ENABLE; + val |= FIELD_PREP(PLLDIG_SSCGBYP_ENABLE, 0x0); + + writel(val, data->regs + PLLDIG_REG_PLLFM); +} + +static int plldig_is_enabled(struct clk_hw *hw) +{ + struct clk_plldig *data = to_clk_plldig(hw); + + return (readl(data->regs + PLLDIG_REG_PLLFM) & + PLLDIG_SSCGBYP_ENABLE); +} + +static unsigned long plldig_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_plldig *data = to_clk_plldig(hw); + u32 val, rfdphi1; + + val = readl(data->regs + PLLDIG_REG_PLLDV); + + /* Check if PLL is bypassed */ + if (val & PLLDIG_SSCGBYP_ENABLE) + return parent_rate; + + rfdphi1 = FIELD_GET(PLLDIG_RFDPHI1_MASK, val); + + /* + * If RFDPHI1 has a value of 1 the VCO frequency is also divided by + * one. + */ + if (!rfdphi1) + rfdphi1 = 1; + + return DIV_ROUND_UP(data->vco_freq, rfdphi1); +} + +static unsigned long plldig_calc_target_div(unsigned long vco_freq, + unsigned long target_rate) +{ + unsigned long div; + + div = DIV_ROUND_CLOSEST(vco_freq, target_rate); + div = max(1UL, div); + div = min(div, MAX_RFDPHI1); + + return div; +} + +static int plldig_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_plldig *data = to_clk_plldig(hw); + unsigned int div; + + if (req->rate < PHI1_MIN_FREQ) + req->rate = PHI1_MIN_FREQ; + if (req->rate > PHI1_MAX_FREQ) + req->rate = PHI1_MAX_FREQ; + + div = plldig_calc_target_div(data->vco_freq, req->rate); + req->rate = DIV_ROUND_UP(data->vco_freq, div); + + return 0; +} + +static int plldig_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_plldig *data = to_clk_plldig(hw); + unsigned int val, cond; + unsigned int rfdphi1; + + if (rate < PHI1_MIN_FREQ) + rate = PHI1_MIN_FREQ; + if (rate > PHI1_MAX_FREQ) + rate = PHI1_MAX_FREQ; + + rfdphi1 = plldig_calc_target_div(data->vco_freq, rate); + + /* update the divider value */ + val = readl(data->regs + PLLDIG_REG_PLLDV); + val &= ~PLLDIG_RFDPHI1_MASK; + val |= FIELD_PREP(PLLDIG_RFDPHI1_MASK, rfdphi1); + writel(val, data->regs + PLLDIG_REG_PLLDV); + + /* delay 200us make sure that old lock state is cleared */ + udelay(200); + + /* Wait until PLL is locked or timeout (maximum 1000 usecs) */ + return readl_poll_timeout_atomic(data->regs + PLLDIG_REG_PLLSR, cond, + cond & PLLDIG_LOCK_MASK, 0, + USEC_PER_MSEC); +} + +static const struct clk_ops plldig_clk_ops = { + .enable = plldig_enable, + .disable = plldig_disable, + .is_enabled = plldig_is_enabled, + .recalc_rate = plldig_recalc_rate, + .determine_rate = plldig_determine_rate, + .set_rate = plldig_set_rate, +}; + +static int plldig_init(struct clk_hw *hw) +{ + struct clk_plldig *data = to_clk_plldig(hw); + struct clk_hw *parent = clk_hw_get_parent(hw); + unsigned long parent_rate = clk_hw_get_rate(parent); + unsigned long val; + unsigned long long lltmp; + unsigned int mfd, fracdiv = 0; + + if (!parent) + return -EINVAL; + + if (data->vco_freq) { + mfd = data->vco_freq / parent_rate; + lltmp = data->vco_freq % parent_rate; + lltmp *= MFDEN; + do_div(lltmp, parent_rate); + fracdiv = lltmp; + } else { + mfd = PLLDIG_DEFAULT_MFD; + data->vco_freq = parent_rate * mfd; + } + + val = FIELD_PREP(PLLDIG_MFD_MASK, mfd); + writel(val, data->regs + PLLDIG_REG_PLLDV); + + if (fracdiv) { + val = FIELD_PREP(PLLDIG_FRAC_MASK, fracdiv); + /* Enable fractional divider */ + val |= PLLDIG_FDEN; + /* Disable dither */ + val |= FIELD_PREP(PLLDIG_DTH_MASK, PLLDIG_DTH_DISABLE); + writel(val, data->regs + PLLDIG_REG_PLLFD); + } + + return 0; +} + +static int plldig_clk_probe(struct platform_device *pdev) +{ + struct clk_plldig *data; + struct resource *mem; + struct device *dev = &pdev->dev; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(data->regs)) + return PTR_ERR(data->regs); + + data->hw.init = CLK_HW_INIT_PARENTS_DATA("dpclk", + parent_data, + &plldig_clk_ops, + 0); + + ret = devm_clk_hw_register(dev, &data->hw); + if (ret) { + dev_err(dev, "failed to register %s clock\n", + dev->of_node->name); + return ret; + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &data->hw); + if (ret) { + dev_err(dev, "unable to add clk provider\n"); + return ret; + } + + /* + * The frequency of the VCO cannot be changed during runtime. + * Therefore, let the user specify a desired frequency. + */ + if (!of_property_read_u32(dev->of_node, "vco-frequency", + &data->vco_freq)) { + if (data->vco_freq < PLLDIG_MIN_VCO_FREQ || + data->vco_freq > PLLDIG_MAX_VCO_FREQ) + return -EINVAL; + } + + return plldig_init(&data->hw); +} + +static const struct of_device_id plldig_clk_id[] = { + { .compatible = "fsl,ls1028a-plldig"}, + { } +}; +MODULE_DEVICE_TABLE(of, plldig_clk_id); + +static struct platform_driver plldig_clk_driver = { + .driver = { + .name = "plldig-clock", + .of_match_table = plldig_clk_id, + }, + .probe = plldig_clk_probe, +}; +module_platform_driver(plldig_clk_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Wen He <wen.he_1@nxp.com>"); +MODULE_DESCRIPTION("LS1028A Display output interface pixel clock driver"); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1c677d7f7f53..c5c6ae99051d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2465,7 +2465,8 @@ static int clk_core_set_parent_nolock(struct clk_core *core, if (!core) return 0; - if (core->parent == parent) + if ((core->parent == parent) && + !(core->flags & CLK_SET_PARENT_NOCACHE)) return 0; /* verify ops for multi-parent clks */ diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 77a3d714f1d5..1140f1c1a116 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -28,8 +28,8 @@ obj-$(CONFIG_MXC_CLK_SCU) += \ obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o -obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o - +obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o clk-imx8qxp-acm.o \ + clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o clk-imx8qm-acm.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o obj-$(CONFIG_SOC_IMX25) += clk-imx25.o diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c index 060f8600ea0d..82eabd33e067 100644 --- a/drivers/clk/imx/clk-composite-7ulp.c +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -7,6 +7,7 @@ #include <linux/clk-provider.h> #include <linux/err.h> +#include <linux/io.h> #include <linux/slab.h> #include "clk.h" @@ -32,6 +33,7 @@ struct clk_hw *imx7ulp_clk_composite(const char *name, struct clk_gate *gate = NULL; struct clk_mux *mux = NULL; struct clk_hw *hw; + u32 val; if (mux_present) { mux = kzalloc(sizeof(*mux), GFP_KERNEL); @@ -70,6 +72,18 @@ struct clk_hw *imx7ulp_clk_composite(const char *name, gate_hw = &gate->hw; gate->reg = reg; gate->bit_idx = PCG_CGC_SHIFT; + /* + * make sure clock is gated during clock tree initialization, + * the HW ONLY allow clock parent/rate changed with clock gated, + * during clock tree initialization, clocks could be enabled + * by bootloader, so the HW status will mismatch with clock tree + * prepare count, then clock core driver will allow parent/rate + * change since the prepare count is zero, but HW actually + * prevent the parent/rate change due to the clock is enabled. + */ + val = readl_relaxed(reg); + val &= ~(1 << PCG_CGC_SHIFT); + writel_relaxed(val, reg); } hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 388bdb94f841..fd37389a84ef 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -154,13 +154,18 @@ struct clk *imx8m_clk_composite_flags(const char *name, div->lock = &imx_ccm_lock; div->flags = CLK_DIVIDER_ROUND_CLOSEST; - gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) - goto fail; - - gate_hw = &gate->hw; - gate->reg = reg; - gate->bit_idx = PCG_CGC_SHIFT; + /* skip registering the gate ops if M4 is enabled */ + if (imx_src_is_m4_enabled()) { + gate_hw = NULL; + } else { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto fail; + + gate_hw = &gate->hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, mux_hw, &clk_mux_ops, div_hw, diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 7d44ce814806..d9a4487dd384 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -7,11 +7,13 @@ */ #include <linux/clk-provider.h> +#include <linux/imx_sema4.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/err.h> #include <linux/string.h> +#include <soc/imx/src.h> #include "clk.h" /** @@ -35,11 +37,56 @@ struct clk_gate2 { }; #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) +#define CCM_CCGR_FULL_ENABLE 0x3 + +static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable) +{ + u32 reg; + + reg = readl(gate->reg); + if (enable) + reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx; + else + reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx); + writel(reg, gate->reg); +} + +static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable) +{ + struct clk_gate2 *gate = to_clk_gate2(hw); + + if (imx_src_is_m4_enabled() && clk_on_imx6sx()) { +#ifdef CONFIG_SOC_IMX6SX + if (!amp_power_mutex || !shared_mem) { + if (enable) + clk_gate2_do_hardware(gate, enable); + return; + } + + imx_sema4_mutex_lock(amp_power_mutex); + if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER || + shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) { + imx_sema4_mutex_unlock(amp_power_mutex); + return; + } + + if (!imx_update_shared_mem(hw, enable)) { + imx_sema4_mutex_unlock(amp_power_mutex); + return; + } + + clk_gate2_do_hardware(gate, enable); + + imx_sema4_mutex_unlock(amp_power_mutex); +#endif + } else { + clk_gate2_do_hardware(gate, enable); + } +} static int clk_gate2_enable(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - u32 reg; unsigned long flags = 0; spin_lock_irqsave(gate->lock, flags); @@ -47,11 +94,7 @@ static int clk_gate2_enable(struct clk_hw *hw) if (gate->share_count && (*gate->share_count)++ > 0) goto out; - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - reg |= gate->cgr_val << gate->bit_idx; - writel(reg, gate->reg); - + clk_gate2_do_shared_clks(hw, true); out: spin_unlock_irqrestore(gate->lock, flags); @@ -61,7 +104,6 @@ out: static void clk_gate2_disable(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); - u32 reg; unsigned long flags = 0; spin_lock_irqsave(gate->lock, flags); @@ -73,10 +115,7 @@ static void clk_gate2_disable(struct clk_hw *hw) goto out; } - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - writel(reg, gate->reg); - + clk_gate2_do_shared_clks(hw, false); out: spin_unlock_irqrestore(gate->lock, flags); } @@ -102,15 +141,11 @@ static void clk_gate2_disable_unused(struct clk_hw *hw) { struct clk_gate2 *gate = to_clk_gate2(hw); unsigned long flags = 0; - u32 reg; spin_lock_irqsave(gate->lock, flags); - if (!gate->share_count || *gate->share_count == 0) { - reg = readl(gate->reg); - reg &= ~(3 << gate->bit_idx); - writel(reg, gate->reg); - } + if (!gate->share_count || *gate->share_count == 0) + clk_gate2_do_shared_clks(hw, false); spin_unlock_irqrestore(gate->lock, flags); } diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c index a66cabfbf94f..cc013b343e62 100644 --- a/drivers/clk/imx/clk-imx25.c +++ b/drivers/clk/imx/clk-imx25.c @@ -73,16 +73,6 @@ enum mx25_clks { static struct clk *clk[clk_max]; -static struct clk ** const uart_clks[] __initconst = { - &clk[uart_ipg_per], - &clk[uart1_ipg], - &clk[uart2_ipg], - &clk[uart3_ipg], - &clk[uart4_ipg], - &clk[uart5_ipg], - NULL -}; - static int __init __mx25_clocks_init(void __iomem *ccm_base) { BUG_ON(!ccm_base); @@ -228,7 +218,7 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base) */ clk_set_parent(clk[cko_sel], clk[ipg]); - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); return 0; } diff --git a/drivers/clk/imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c index a3753067fc12..ee9ef5079e40 100644 --- a/drivers/clk/imx/clk-imx27.c +++ b/drivers/clk/imx/clk-imx27.c @@ -49,17 +49,6 @@ static const char *ssi_sel_clks[] = { "spll_gate", "mpll", }; static struct clk *clk[IMX27_CLK_MAX]; static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks[] __initconst = { - &clk[IMX27_CLK_PER1_GATE], - &clk[IMX27_CLK_UART1_IPG_GATE], - &clk[IMX27_CLK_UART2_IPG_GATE], - &clk[IMX27_CLK_UART3_IPG_GATE], - &clk[IMX27_CLK_UART4_IPG_GATE], - &clk[IMX27_CLK_UART5_IPG_GATE], - &clk[IMX27_CLK_UART6_IPG_GATE], - NULL -}; - static void __init _mx27_clocks_init(unsigned long fref) { BUG_ON(!ccm); @@ -176,7 +165,7 @@ static void __init _mx27_clocks_init(unsigned long fref) clk_prepare_enable(clk[IMX27_CLK_EMI_AHB_GATE]); - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); imx_print_silicon_rev("i.MX27", mx27_revision()); } diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c index 4bb05e440cdd..ae9ff78d45bf 100644 --- a/drivers/clk/imx/clk-imx31.c +++ b/drivers/clk/imx/clk-imx31.c @@ -51,16 +51,6 @@ enum mx31_clks { static struct clk *clk[clk_max]; static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks[] __initconst = { - &clk[ipg], - &clk[uart1_gate], - &clk[uart2_gate], - &clk[uart3_gate], - &clk[uart4_gate], - &clk[uart5_gate], - NULL -}; - static void __init _mx31_clocks_init(void __iomem *base, unsigned long fref) { clk[dummy] = imx_clk_fixed("dummy", 0); @@ -197,7 +187,7 @@ int __init mx31_clocks_init(unsigned long fref) clk_register_clkdev(clk[iim_gate], "iim", NULL); - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT, GPT_TYPE_IMX31); return 0; diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index e595f559907f..c97511360e09 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -82,14 +82,6 @@ enum mx35_clks { static struct clk *clk[clk_max]; -static struct clk ** const uart_clks[] __initconst = { - &clk[ipg], - &clk[uart1_gate], - &clk[uart2_gate], - &clk[uart3_gate], - NULL -}; - static void __init _mx35_clocks_init(void) { void __iomem *base; @@ -243,7 +235,7 @@ static void __init _mx35_clocks_init(void) */ clk_prepare_enable(clk[scc_gate]); - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); imx_print_silicon_rev("i.MX35", mx35_revision()); } diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c index 01e079b81026..b82044911603 100644 --- a/drivers/clk/imx/clk-imx5.c +++ b/drivers/clk/imx/clk-imx5.c @@ -128,30 +128,6 @@ static const char *ieee1588_sels[] = { "pll3_sw", "pll4_sw", "dummy" /* usbphy2_ static struct clk *clk[IMX5_CLK_END]; static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks_mx51[] __initconst = { - &clk[IMX5_CLK_UART1_IPG_GATE], - &clk[IMX5_CLK_UART1_PER_GATE], - &clk[IMX5_CLK_UART2_IPG_GATE], - &clk[IMX5_CLK_UART2_PER_GATE], - &clk[IMX5_CLK_UART3_IPG_GATE], - &clk[IMX5_CLK_UART3_PER_GATE], - NULL -}; - -static struct clk ** const uart_clks_mx50_mx53[] __initconst = { - &clk[IMX5_CLK_UART1_IPG_GATE], - &clk[IMX5_CLK_UART1_PER_GATE], - &clk[IMX5_CLK_UART2_IPG_GATE], - &clk[IMX5_CLK_UART2_PER_GATE], - &clk[IMX5_CLK_UART3_IPG_GATE], - &clk[IMX5_CLK_UART3_PER_GATE], - &clk[IMX5_CLK_UART4_IPG_GATE], - &clk[IMX5_CLK_UART4_PER_GATE], - &clk[IMX5_CLK_UART5_IPG_GATE], - &clk[IMX5_CLK_UART5_PER_GATE], - NULL -}; - static void __init mx5_clocks_common_init(void __iomem *ccm_base) { clk[IMX5_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -382,7 +358,7 @@ static void __init mx50_clocks_init(struct device_node *np) r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); - imx_register_uart_clocks(uart_clks_mx50_mx53); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init); @@ -488,7 +464,7 @@ static void __init mx51_clocks_init(struct device_node *np) val |= 1 << 23; writel(val, MXC_CCM_CLPCR); - imx_register_uart_clocks(uart_clks_mx51); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init); @@ -633,6 +609,6 @@ static void __init mx53_clocks_init(struct device_node *np) r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); - imx_register_uart_clocks(uart_clks_mx50_mx53); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init); diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 60f2de851f39..f32c57d39d96 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -26,7 +26,8 @@ static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; -static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", }; +static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *axi_sels[] = { "periph", "axi_alt_sel", }; static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; static const char *gpu_axi_sels[] = { "axi", "ahb", }; static const char *pre_axi_sels[] = { "axi", "ahb", }; @@ -36,15 +37,17 @@ static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_p static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll3_pfd0_720m", }; static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; static const char *ldb_di_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", }; +static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", }; +static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", }; static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; -static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", }; -static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", }; -static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", }; -static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", }; +static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", }; +static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", }; +static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", }; +static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", }; static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", }; static const char *pcie_axi_sels[] = { "axi", "ahb", }; static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", }; @@ -90,6 +93,7 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; static struct clk_hw **hws; static struct clk_hw_onecell_data *clk_hw_data; +static void __iomem *ccm_base; static struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, @@ -139,13 +143,6 @@ static inline int clk_on_imx6dl(void) return of_machine_is_compatible("fsl,imx6dl"); } -static const int uart_clk_ids[] __initconst = { - IMX6QDL_CLK_UART_IPG, - IMX6QDL_CLK_UART_SERIAL, -}; - -static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata; - static int ldb_di_sel_by_clock_id(int clock_id) { switch (clock_id) { @@ -258,6 +255,11 @@ static bool pll6_bypassed(struct device_node *node) #define CCM_CCSR 0x0c #define CCM_CS2CDR 0x2c +#define CCM_CSCDR3 0x3c +#define CCM_CCGR0 0x68 +#define CCM_CCGR3 0x74 + +#define ANATOP_PLL3_PFD 0xf0 #define CCSR_PLL3_SW_CLK_SEL BIT(0) @@ -394,6 +396,62 @@ static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base) #define PFD2_CLKGATE BIT(23) #define PFD3_CLKGATE BIT(31) +/* + * workaround for ERR010579, when switching the clock source of IPU clock + * root in CCM. even setting CCGR3[CG0]=0x0 to gate off clock before + * switching, IPU may hang due to no IPU clock from CCM. + */ +static void __init init_ipu_clk(void __iomem *anatop_base) +{ + u32 val, origin_podf; + + /* gate off the IPU1_IPU clock */ + val = readl_relaxed(ccm_base + CCM_CCGR3); + val &= ~0x3; + writel_relaxed(val, ccm_base + CCM_CCGR3); + + /* gate off IPU DCIC1/2 clocks */ + val = readl_relaxed(ccm_base + CCM_CCGR0); + val &= ~(0xf << 24); + writel_relaxed(val, ccm_base + CCM_CCGR0); + + /* set IPU_PODF to 3'b000 */ + val = readl_relaxed(ccm_base + CCM_CSCDR3); + origin_podf = val & (0x7 << 11); + val &= ~(0x7 << 11); + writel_relaxed(val, ccm_base + CCM_CSCDR3); + + /* disable PLL3_PFD1 */ + val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD); + val &= ~(0x1 << 15); + writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD); + + /* switch IPU_SEL clock to PLL3_PFD1 */ + val = readl_relaxed(ccm_base + CCM_CSCDR3); + val |= (0x3 << 9); + writel_relaxed(val, ccm_base + CCM_CSCDR3); + + /* restore the IPU PODF*/ + val = readl_relaxed(ccm_base + CCM_CSCDR3); + val |= origin_podf; + writel_relaxed(val, ccm_base + CCM_CSCDR3); + + /* enable PLL3_PFD1 */ + val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD); + val |= (0x1 << 15); + writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD); + + /* enable IPU1_IPU clock */ + val = readl_relaxed(ccm_base + CCM_CCGR3); + val |= 0x3; + writel_relaxed(val, ccm_base + CCM_CCGR3); + + /* enable IPU DCIC1/2 clock */ + val = readl_relaxed(ccm_base + CCM_CCGR0); + val |= (0xf << 24); + writel_relaxed(val, ccm_base + CCM_CCGR0); +} + static void disable_anatop_clocks(void __iomem *anatop_base) { unsigned int reg; @@ -439,7 +497,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) struct device_node *np; void __iomem *anatop_base, *base; int ret; - int i; clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX6QDL_CLK_END), GFP_KERNEL); @@ -604,6 +661,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) np = ccm_node; base = of_iomap(np, 0); + ccm_base = base; WARN_ON(!base); /* name reg shift width parent_names num_parents */ @@ -613,7 +671,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) hws[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); hws[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); - hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels)); + hws[IMX6QDL_CLK_AXI_ALT_SEL] = imx_clk_hw_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels)); + hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels)); hws[IMX6QDL_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); hws[IMX6QDL_CLK_ASRC_SEL] = imx_clk_hw_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); hws[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); @@ -659,6 +718,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) hws[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_hw_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); } + hws[IMX6QDL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT); + hws[IMX6QDL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT); hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); @@ -727,6 +788,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6); hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7); hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7); + hws[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0", 1, 7); + hws[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1", 1, 7); } else { hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "pll3_60m", base + 0x20, 2, 6); @@ -734,6 +797,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + hws[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); + hws[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); } if (clk_on_imx6dl()) @@ -919,8 +984,19 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk_hw_register_clkdev(hws[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL); clk_set_rate(hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk, 540000000); - if (clk_on_imx6dl()) + if (clk_on_imx6dl()) { + init_ipu_clk(anatop_base); clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk); + clk_set_parent(hws[IMX6QDL_CLK_AXI_ALT_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk); + clk_set_parent(hws[IMX6QDL_CLK_AXI_SEL]->clk, hws[IMX6QDL_CLK_AXI_ALT_SEL]->clk); + /* set epdc/pxp axi clock to 200Mhz */ + clk_set_parent(hws[IMX6QDL_CLK_IPU2_SEL]->clk, hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk); + clk_set_rate(hws[IMX6QDL_CLK_IPU2]->clk, 200000000); + } else { + clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk); + + clk_set_parent(hws[IMX6QDL_CLK_IPU2_SEL]->clk, hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk); + } clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk); clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk); @@ -978,12 +1054,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk); } - for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) { - int index = uart_clk_ids[i]; - - uart_clks[i] = &hws[index]->clk; - } - - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c index 4bd44d89eaaa..f26435960784 100644 --- a/drivers/clk/imx/clk-imx6sl.c +++ b/drivers/clk/imx/clk-imx6sl.c @@ -177,19 +177,11 @@ void imx6sl_set_wait_clk(bool enter) imx6sl_enable_pll_arm(false); } -static const int uart_clk_ids[] __initconst = { - IMX6SL_CLK_UART, - IMX6SL_CLK_UART_SERIAL, -}; - -static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata; - static void __init imx6sl_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; int ret; - int i; clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX6SL_CLK_END), GFP_KERNEL); @@ -438,19 +430,23 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) /* Audio-related clocks configuration */ clk_set_parent(hws[IMX6SL_CLK_SPDIF0_SEL]->clk, hws[IMX6SL_CLK_PLL3_PFD3]->clk); + /* Initialize Video PLLs to valid frequency (650MHz). */ + clk_set_rate(hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk, 650000000); + /* set PLL5 video as lcdif pix parent clock */ clk_set_parent(hws[IMX6SL_CLK_LCDIF_PIX_SEL]->clk, hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk); + /* Configure EPDC clocks */ + clk_set_parent(hws[IMX6SL_CLK_EPDC_PIX_SEL]->clk, + hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk); + clk_set_parent(hws[IMX6SL_CLK_EPDC_AXI_SEL]->clk, + hws[IMX6SL_CLK_PLL2_PFD2]->clk); + clk_set_rate(hws[IMX6SL_CLK_EPDC_AXI]->clk, 200000000); + clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk, hws[IMX6SL_CLK_PLL2_PFD2]->clk); - for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) { - int index = uart_clk_ids[i]; - - uart_clks[i] = &hws[index]->clk; - } - - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init); diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c index 5f3e92c09a5e..1035ef0e55a3 100644 --- a/drivers/clk/imx/clk-imx6sll.c +++ b/drivers/clk/imx/clk-imx6sll.c @@ -76,26 +76,10 @@ static u32 share_count_ssi1; static u32 share_count_ssi2; static u32 share_count_ssi3; -static const int uart_clk_ids[] __initconst = { - IMX6SLL_CLK_UART1_IPG, - IMX6SLL_CLK_UART1_SERIAL, - IMX6SLL_CLK_UART2_IPG, - IMX6SLL_CLK_UART2_SERIAL, - IMX6SLL_CLK_UART3_IPG, - IMX6SLL_CLK_UART3_SERIAL, - IMX6SLL_CLK_UART4_IPG, - IMX6SLL_CLK_UART4_SERIAL, - IMX6SLL_CLK_UART5_IPG, - IMX6SLL_CLK_UART5_SERIAL, -}; - -static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata; - static void __init imx6sll_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX6SLL_CLK_END), GFP_KERNEL); @@ -356,13 +340,12 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); - for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) { - int index = uart_clk_ids[i]; - - uart_clks[i] = &hws[index]->clk; - } - - imx_register_uart_clocks(uart_clks); + /* Set the UART parent if needed */ + if (uart_from_osc) + clk_set_parent(hws[IMX6SLL_CLK_UART_SEL]->clk, hws[IMX6SLL_CLK_OSC]->clk); + else + clk_set_parent(hws[IMX6SLL_CLK_UART_SEL]->clk, hws[IMX6SLL_CLK_PLL3_80M]->clk); + imx_register_uart_clocks(); /* Lower the AHB clock rate before changing the clock source. */ clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000); @@ -372,6 +355,10 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_CLK2]->clk); clk_set_parent(hws[IMX6SLL_CLK_PERIPH_PRE]->clk, hws[IMX6SLL_CLK_PLL2_BUS]->clk); clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_PRE]->clk); + /* Configure EPDC clocks */ + clk_set_rate(hws[IMX6SLL_CLK_PLL3_PFD2]->clk, 320000000); + clk_set_parent(hws[IMX6SLL_CLK_EPDC_PRE_SEL]->clk, + hws[IMX6SLL_CLK_PLL3_PFD2]->clk); clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 132000000); } diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index c4685c01929a..beed221ed4bd 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -10,13 +10,18 @@ #include <linux/err.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/imx_sema4.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/types.h> +#include <soc/imx/gpc.h> +#include <soc/imx/src.h> #include "clk.h" +#define CCM_CCGR_OFFSET(index) (index * 2) + static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; @@ -83,6 +88,12 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; static struct clk_hw **hws; static struct clk_hw_onecell_data *clk_hw_data; +struct imx_sema4_mutex *amp_power_mutex; + +static int clks_shared[MAX_SHARED_CLK_NUMBER]; + +struct imx_shared_mem *shared_mem; +static unsigned int shared_mem_paddr, shared_mem_size; static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, @@ -116,18 +127,43 @@ static u32 share_count_ssi3; static u32 share_count_sai1; static u32 share_count_sai2; -static const int uart_clk_ids[] __initconst = { - IMX6SX_CLK_UART_IPG, - IMX6SX_CLK_UART_SERIAL, -}; +/* + * As IMX6SX_CLK_M4_PRE_SEL is NOT a glitchless MUX, so when + * M4 is trying to change its clk parent, need to ask A9 to + * help do it, and M4 must be hold in wfi. To avoid glitch + * occur, need to gate M4 clk first before switching its parent. + */ +void imx6sx_set_m4_highfreq(bool high_freq) +{ + static struct clk *m4_high_freq_sel; + + imx_gpc_hold_m4_in_sleep(); + + clk_disable_unprepare(hws[IMX6SX_CLK_M4]->clk); + clk_set_parent(hws[IMX6SX_CLK_M4_SEL]->clk, + hws[IMX6SX_CLK_LDB_DI0]->clk); + + if (high_freq) { + /* FIXME: m4_high_freq_sel possible used without intialization? */ + clk_set_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk, + m4_high_freq_sel); + } else { + m4_high_freq_sel = clk_get_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk); + clk_set_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk, + hws[IMX6SX_CLK_OSC]->clk); + } + + clk_set_parent(hws[IMX6SX_CLK_M4_SEL]->clk, + hws[IMX6SX_CLK_M4_PRE_SEL]->clk); + clk_prepare_enable(hws[IMX6SX_CLK_M4]->clk); -static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata; + imx_gpc_release_m4_in_sleep(); +} static void __init imx6sx_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX6SX_CLK_CLK_END), GFP_KERNEL); @@ -189,7 +225,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clk_set_parent(hws[IMX6SX_PLL6_BYPASS]->clk, hws[IMX6SX_CLK_PLL6]->clk); clk_set_parent(hws[IMX6SX_PLL7_BYPASS]->clk, hws[IMX6SX_CLK_PLL7]->clk); - hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_gate("pll1_sys", "pll1_bypass", base + 0x00, 13); + hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); hws[IMX6SX_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); hws[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); hws[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); @@ -405,7 +441,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) hws[IMX6SX_CLK_GPT_BUS] = imx_clk_hw_gate2("gpt_bus", "perclk", base + 0x6c, 20); hws[IMX6SX_CLK_GPT_SERIAL] = imx_clk_hw_gate2("gpt_serial", "perclk", base + 0x6c, 22); hws[IMX6SX_CLK_GPU] = imx_clk_hw_gate2("gpu", "gpu_core_podf", base + 0x6c, 26); - hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2("ocram_s", "ahb", base + 0x6c, 28); + hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2_flags("ocram_s", "ahb", base + 0x6c, 28, CLK_IS_CRITICAL); hws[IMX6SX_CLK_CANFD] = imx_clk_hw_gate2("canfd", "can_podf", base + 0x6c, 30); /* CCGR2 */ @@ -489,13 +525,59 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) hws[IMX6SX_CLK_CKO1] = imx_clk_hw_gate("cko1", "cko1_podf", base + 0x60, 7); hws[IMX6SX_CLK_CKO2] = imx_clk_hw_gate("cko2", "cko2_podf", base + 0x60, 24); + /* get those shared clk nodes if M4 is active */ + if (imx_src_is_m4_enabled()) { + u32 num; + + of_property_read_u32(np, "fsl,shared-clks-number", &num); + if (num > MAX_SHARED_CLK_NUMBER) + pr_err("clk: shared clk nodes exceed the max number!\n"); + of_property_read_u32_array(np, "fsl,shared-clks-index", + clks_shared, num); + if (of_property_read_u32(np, "fsl,shared-mem-addr", + &shared_mem_paddr)) + pr_err("clk: fsl,shared-mem-addr NOT found!\n"); + if (of_property_read_u32(np, "fsl,shared-mem-size", + &shared_mem_size)) + pr_err("clk: fsl,shared-mem-size NOT found!\n"); + } + /* mask handshake of mmdc */ imx_mmdc_mask_handshake(base, 0); imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END); + /* + * QSPI2/GPMI_IO share the same clock source but with the + * different gate, need explicitely gate the QSPI2 & GPMI_IO + * during the clock init phase according to the SOC design. + */ + if (!imx_src_is_m4_enabled()) { + writel_relaxed(readl_relaxed(base + 0x78) & + ~(3 << CCM_CCGR_OFFSET(5)), base + 0x78); + writel_relaxed(readl_relaxed(base + 0x78) & + ~(3 << CCM_CCGR_OFFSET(14)), base + 0x78); + } + + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); + /* + * As some of the modules need to access ocotp in MSL, + * need to make sure ocotp clk(CCM_CCGR2_CG6) is enabled + * during MSL, as on i.MX6SX, accessing OCOTP registers + * needs its clk on, it will be disabled by clk late + * init and managed by ocotp driver. + */ + writel_relaxed(readl_relaxed(base + 0x70) | 1 << 12, base + 0x70); + + /* maintain M4 usecount */ + if (imx_src_is_m4_enabled()) + clk_prepare_enable(hws[IMX6SX_CLK_M4]->clk); + + /* set perclk to from OSC */ + clk_set_parent(hws[IMX6SX_CLK_PERCLK_SEL]->clk, hws[IMX6SX_CLK_OSC]->clk); + if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { clk_prepare_enable(hws[IMX6SX_CLK_USBPHY1_GATE]->clk); clk_prepare_enable(hws[IMX6SX_CLK_USBPHY2_GATE]->clk); @@ -542,6 +624,12 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clk_set_parent(hws[IMX6SX_CLK_ESAI_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk); clk_set_rate(hws[IMX6SX_CLK_ESAI_PODF]->clk, 24576000); + /* Set the UART parent if needed. */ + if (uart_from_osc) + clk_set_parent(hws[IMX6SX_CLK_UART_SEL]->clk, hws[IMX6SX_CLK_OSC]->clk); + else + clk_set_parent(hws[IMX6SX_CLK_UART_SEL]->clk, hws[IMX6SX_CLK_PLL3_80M]->clk); + /* Set parent clock for vadc */ clk_set_parent(hws[IMX6SX_CLK_VID_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk); @@ -551,16 +639,74 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) /* Update gpu clock from default 528M to 720M */ clk_set_parent(hws[IMX6SX_CLK_GPU_CORE_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk); clk_set_parent(hws[IMX6SX_CLK_GPU_AXI_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk); + if (!imx_src_is_m4_enabled()) + /* default parent of can_sel clock is invalid, manually set it here */ + clk_set_parent(hws[IMX6SX_CLK_CAN_SEL]->clk, hws[IMX6SX_CLK_PLL3_60M]->clk); clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk); clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk); - for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) { - int index = uart_clk_ids[i]; + imx_register_uart_clocks(); +} +CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init); + +int imx_update_shared_mem(struct clk_hw *hw, bool enable) +{ + int i; - uart_clks[i] = &hws[index]->clk; + for (i = 0; i < ARRAY_SIZE(clks_shared); i++) { + if (shared_mem->imx_clk[i].self == hw->clk) + break; } - imx_register_uart_clocks(uart_clks); + if (i >= ARRAY_SIZE(clks_shared)) + return 1; + + /* update ca9 clk status in shared memory */ + if (enable) + shared_mem->imx_clk[i].ca9_enabled = 1; + else + shared_mem->imx_clk[i].ca9_enabled = 0; + + if (shared_mem->imx_clk[i].cm4_enabled == 0) + return 1; + + return 0; } -CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init); + +static int __init imx_amp_power_init(void) +{ + int i; + void __iomem *shared_mem_base; + + if (!(imx_src_is_m4_enabled() && clk_on_imx6sx())) + return 0; + + amp_power_mutex = imx_sema4_mutex_create(0, MCC_POWER_SHMEM_NUMBER); + + shared_mem_base = ioremap_nocache(shared_mem_paddr, shared_mem_size); + + if (!amp_power_mutex) { + pr_err("Failed to create sema4 mutex!\n"); + return 0; + } + + shared_mem = (struct imx_shared_mem *)shared_mem_base; + + for (i = 0; i < ARRAY_SIZE(clks_shared); i++) { + shared_mem->imx_clk[i].self = hws[clks_shared[i]]->clk; + shared_mem->imx_clk[i].ca9_enabled = 1; + pr_debug("%d: name %s, addr 0x%x\n", i, + __clk_get_name(shared_mem->imx_clk[i].self), + (u32)&(shared_mem->imx_clk[i])); + } + /* enable amp power management */ + shared_mem->ca9_valid = SHARED_MEM_MAGIC_NUMBER; + + pr_info("A9-M4 sema4 num %d, A9-M4 magic number 0x%x - 0x%x.\n", + amp_power_mutex->gate_num, shared_mem->ca9_valid, + shared_mem->cm4_valid); + + return 0; +} +late_initcall(imx_amp_power_init); diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index bc931988fe7b..6c0a8e0a7ef4 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -495,6 +495,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clk_set_rate(hws[IMX6UL_CLK_ENET2_REF]->clk, 50000000); clk_set_rate(hws[IMX6UL_CLK_CSI]->clk, 24000000); + /* Set the UART parent if needed */ + if (uart_from_osc) + clk_set_parent(hws[IMX6UL_CLK_UART_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk); + else + clk_set_parent(hws[IMX6UL_CLK_UART_SEL]->clk, hws[IMX6UL_CLK_PLL3_80M]->clk); + if (clk_on_imx6ull()) clk_prepare_enable(hws[IMX6UL_CLK_AIPSTZ3]->clk); diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index fbea774ef687..ed70a57e2e6d 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -14,6 +14,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/types.h> +#include <soc/imx/src.h> #include "clk.h" @@ -23,6 +24,7 @@ static u32 share_count_sai3; static u32 share_count_nand; static u32 share_count_enet1; static u32 share_count_enet2; +static u32 share_count_pxp; static const struct clk_div_table test_div_table[] = { { .val = 3, .div = 1, }, @@ -376,23 +378,10 @@ static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_ static struct clk_hw **hws; static struct clk_hw_onecell_data *clk_hw_data; -static const int uart_clk_ids[] __initconst = { - IMX7D_UART1_ROOT_CLK, - IMX7D_UART2_ROOT_CLK, - IMX7D_UART3_ROOT_CLK, - IMX7D_UART4_ROOT_CLK, - IMX7D_UART5_ROOT_CLK, - IMX7D_UART6_ROOT_CLK, - IMX7D_UART7_ROOT_CLK, -}; - -static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata; - static void __init imx7d_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX7D_CLK_END), GFP_KERNEL); @@ -865,6 +854,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0); hws[IMX7D_USB_PHY2_CLK] = imx_clk_hw_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0); hws[IMX7D_ADC_ROOT_CLK] = imx_clk_hw_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0); + hws[IMX7D_PXP_IPG_CLK] = imx_clk_hw_gate2_shared2("pxp_ipg_clk", "ipg_root_clk", base + 0x44c0, 0, &share_count_pxp); + hws[IMX7D_PXP_AXI_CLK] = imx_clk_hw_gate2_shared2("pxp_axi_clk", "main_axi_root_clk", base + 0x44c0, 0, &share_count_pxp); hws[IMX7D_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8); @@ -887,6 +878,12 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk); + if (imx_src_is_m4_enabled()) { + clk_set_parent(hws[IMX7D_ARM_M4_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_240M_CLK]->clk); + clk_prepare_enable(hws[IMX7D_ARM_M4_ROOT_CLK]->clk); + clk_prepare_enable(hws[IMX7D_UART2_ROOT_CLK]->clk); + } + /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */ clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk); @@ -894,14 +891,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1); hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1); - for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) { - int index = uart_clk_ids[i]; - - uart_clks[i] = &hws[index]->clk; - } - + /* set parent of EPDC pixel clock */ + clk_set_parent(hws[IMX7D_EPDC_PIXEL_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_CLK]->clk); - imx_register_uart_clocks(uart_clks); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init); diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c index 2022d9bead91..7745ad3e1425 100644 --- a/drivers/clk/imx/clk-imx7ulp.c +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -28,7 +28,7 @@ static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dumm static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; static const char * const nic_sels[] = { "firc", "ddr_clk", }; static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; -static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; +static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "dummy", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; static const char * const arm_sels[] = { "divcore", "dummy", "dummy", "hsrun_divcore", }; /* used by sosc/sirc/firc/ddr/spll/apll dividers */ @@ -40,6 +40,7 @@ static const struct clk_div_table ulp_div_table[] = { { .val = 5, .div = 16, }, { .val = 6, .div = 32, }, { .val = 7, .div = 64, }, + { /* sentinel */ }, }; static const int pcc2_uart_clk_ids[] __initconst = { @@ -47,14 +48,6 @@ static const int pcc2_uart_clk_ids[] __initconst = { IMX7ULP_CLK_LPUART5, }; -static const int pcc3_uart_clk_ids[] __initconst = { - IMX7ULP_CLK_LPUART6, - IMX7ULP_CLK_LPUART7, -}; - -static struct clk **pcc2_uart_clks[ARRAY_SIZE(pcc2_uart_clk_ids) + 1] __initdata; -static struct clk **pcc3_uart_clks[ARRAY_SIZE(pcc3_uart_clk_ids) + 1] __initdata; - static void __init imx7ulp_clk_scg1_init(struct device_node *np) { struct clk_hw_onecell_data *clk_data; @@ -75,7 +68,6 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np) clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); - clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll"); /* SCG1 */ @@ -148,7 +140,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np) struct clk_hw_onecell_data *clk_data; struct clk_hw **clks; void __iomem *base; - int i; clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC2_END), GFP_KERNEL); @@ -187,14 +178,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np) imx_check_clk_hws(clks, clk_data->num); of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); - - for (i = 0; i < ARRAY_SIZE(pcc2_uart_clk_ids); i++) { - int index = pcc2_uart_clk_ids[i]; - - pcc2_uart_clks[i] = &clks[index]->clk; - } - - imx_register_uart_clocks(pcc2_uart_clks); } CLK_OF_DECLARE(imx7ulp_clk_pcc2, "fsl,imx7ulp-pcc2", imx7ulp_clk_pcc2_init); @@ -203,7 +186,6 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np) struct clk_hw_onecell_data *clk_data; struct clk_hw **clks; void __iomem *base; - int i; clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC3_END), GFP_KERNEL); @@ -242,13 +224,7 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np) of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); - for (i = 0; i < ARRAY_SIZE(pcc3_uart_clk_ids); i++) { - int index = pcc3_uart_clk_ids[i]; - - pcc3_uart_clks[i] = &clks[index]->clk; - } - - imx_register_uart_clocks(pcc3_uart_clks); + imx_register_uart_clocks(); } CLK_OF_DECLARE(imx7ulp_clk_pcc3, "fsl,imx7ulp-pcc3", imx7ulp_clk_pcc3_init); diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 172589e94f60..f1e4e29a9107 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -12,7 +12,9 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <linux/types.h> +#include <soc/imx/soc.h> #include "clk.h" @@ -357,13 +359,31 @@ static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", static struct clk *clks[IMX8MM_CLK_END]; static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks[] = { - &clks[IMX8MM_CLK_UART1_ROOT], - &clks[IMX8MM_CLK_UART2_ROOT], - &clks[IMX8MM_CLK_UART3_ROOT], - &clks[IMX8MM_CLK_UART4_ROOT], - NULL -}; +static int __init imx_clk_init_on(struct device_node *np, + struct clk * const clks[]) +{ + u32 *array; + int i, ret, elems; + + elems = of_property_count_u32_elems(np, "init-on-array"); + if (elems < 0) + return elems; + array = kcalloc(elems, sizeof(elems), GFP_KERNEL); + if (IS_ERR_OR_NULL(array)) + return PTR_ERR(array); + + ret = of_property_read_u32_array(np, "init-on-array", array, elems); + if (ret) + return ret; + + for (i = 0; i < elems; i++) { + ret = clk_prepare_enable(clks[array[i]]); + if (ret) + pr_err("clk_prepare_enable failed %d\n", array[i]); + } + + return 0; +} static int imx8mm_clocks_probe(struct platform_device *pdev) { @@ -372,6 +392,8 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) void __iomem *base; int ret; + check_m4_enabled(); + clks[IMX8MM_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clks[IMX8MM_CLK_24M] = of_clk_get_by_name(np, "osc_24m"); clks[IMX8MM_CLK_32K] = of_clk_get_by_name(np, "osc_32k"); @@ -477,7 +499,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) /* BUS */ clks[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); clks[IMX8MM_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880); - clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900); + clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900); clks[IMX8MM_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980); clks[IMX8MM_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00); clks[IMX8MM_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80); @@ -650,7 +672,16 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) goto unregister_clks; } - imx_register_uart_clocks(uart_clks); + imx_clk_init_on(np, clks); + + clk_set_parent(clks[IMX8MM_CLK_PCIE1_CTRL], clks[IMX8MM_SYS_PLL2_250M]); + clk_set_parent(clks[IMX8MM_CLK_PCIE1_PHY], clks[IMX8MM_SYS_PLL2_100M]); + + clk_set_parent(clks[IMX8MM_CLK_CSI1_CORE], clks[IMX8MM_SYS_PLL2_1000M]); + clk_set_parent(clks[IMX8MM_CLK_CSI1_PHY_REF], clks[IMX8MM_SYS_PLL2_1000M]); + clk_set_parent(clks[IMX8MM_CLK_CSI1_ESC], clks[IMX8MM_SYS_PLL1_800M]); + + imx_register_uart_clocks(); return 0; diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 58b5acee3830..d5f18731eea7 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -12,7 +12,9 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <linux/types.h> +#include <soc/imx/soc.h> #include "clk.h" @@ -368,13 +370,31 @@ static const char * const imx8mn_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sy static struct clk *clks[IMX8MN_CLK_END]; static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks[] = { - &clks[IMX8MN_CLK_UART1_ROOT], - &clks[IMX8MN_CLK_UART2_ROOT], - &clks[IMX8MN_CLK_UART3_ROOT], - &clks[IMX8MN_CLK_UART4_ROOT], - NULL -}; +static int __init imx_clk_init_on(struct device_node *np, + struct clk * const clks[]) +{ + u32 *array; + int i, ret, elems; + + elems = of_property_count_u32_elems(np, "init-on-array"); + if (elems < 0) + return elems; + array = kcalloc(elems, sizeof(elems), GFP_KERNEL); + if (IS_ERR_OR_NULL(array)) + return PTR_ERR(array); + + ret = of_property_read_u32_array(np, "init-on-array", array, elems); + if (ret) + return ret; + + for (i = 0; i < elems; i++) { + ret = clk_prepare_enable(clks[array[i]]); + if (ret) + pr_err("clk_prepare_enable failed %d\n", array[i]); + } + + return 0; +} static int imx8mn_clocks_probe(struct platform_device *pdev) { @@ -383,6 +403,8 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) void __iomem *base; int ret; + check_m4_enabled(); + clks[IMX8MN_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clks[IMX8MN_CLK_24M] = of_clk_get_by_name(np, "osc_24m"); clks[IMX8MN_CLK_32K] = of_clk_get_by_name(np, "osc_32k"); @@ -622,7 +644,13 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) goto unregister_clks; } - imx_register_uart_clocks(uart_clks); + imx_clk_init_on(np, clks); + + clk_set_parent(clks[IMX8MN_CLK_AUDIO_AHB], clks[IMX8MN_SYS_PLL1_800M]); + clk_set_rate(clks[IMX8MN_CLK_AUDIO_AHB], 400000000); + clk_set_rate(clks[IMX8MN_CLK_IPG_AUDIO_ROOT], 400000000); + + imx_register_uart_clocks(); return 0; diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 41fc9c63356e..02d863b4b32f 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -12,6 +12,8 @@ #include <linux/of_address.h> #include <linux/types.h> #include <linux/platform_device.h> +#include <linux/slab.h> +#include <soc/imx/soc.h> #include "clk.h" @@ -26,7 +28,7 @@ static u32 share_count_nand; static struct clk *clks[IMX8MQ_CLK_END]; -static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "phy_27m", "dummy", }; static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; @@ -38,6 +40,7 @@ static const char * const sys1_pll_out_sels[] = {"sys1_pll1_ref_sel", }; static const char * const sys2_pll_out_sels[] = {"sys1_pll1_ref_sel", "sys2_pll1_ref_sel", }; static const char * const sys3_pll_out_sels[] = {"sys3_pll1_ref_sel", "sys2_pll1_ref_sel", }; static const char * const dram_pll_out_sels[] = {"dram_pll1_ref_sel", }; +static const char *video2_pll_out_sels[] = {"video2_pll1_ref_sel", }; /* CCM ROOT */ static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", @@ -272,13 +275,31 @@ static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sy static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks[] = { - &clks[IMX8MQ_CLK_UART1_ROOT], - &clks[IMX8MQ_CLK_UART2_ROOT], - &clks[IMX8MQ_CLK_UART3_ROOT], - &clks[IMX8MQ_CLK_UART4_ROOT], - NULL -}; +static int __init imx_clk_init_on(struct device_node *np, + struct clk * const clks[]) +{ + u32 *array; + int i, ret, elems; + + elems = of_property_count_u32_elems(np, "init-on-array"); + if (elems < 0) + return elems; + array = kzalloc(elems * sizeof(elems), GFP_KERNEL); + if (IS_ERR_OR_NULL(array)) + return PTR_ERR(array); + + ret = of_property_read_u32_array(np, "init-on-array", array, elems); + if (ret) + return ret; + + for (i = 0; i < elems; i++) { + ret = clk_prepare_enable(clks[array[i]]); + if (ret) + pr_err("clk_prepare_enable failed %d\n", array[i]); + } + + return 0; +} static int imx8mq_clocks_probe(struct platform_device *pdev) { @@ -287,6 +308,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) void __iomem *base; int err; + check_m4_enabled(); + clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil"); clks[IMX8MQ_CLK_25M] = of_clk_get_by_name(np, "osc_25m"); @@ -295,6 +318,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) clks[IMX8MQ_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2"); clks[IMX8MQ_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3"); clks[IMX8MQ_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4"); + clks[IMX8MQ_CLK_PHY_27MHZ] = imx_clk_fixed("phy_27m", 27000000); np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop"); base = of_iomap(np, 0); @@ -311,6 +335,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) clks[IMX8MQ_SYS2_PLL1_REF_SEL] = imx_clk_mux("sys2_pll1_ref_sel", base + 0x3c, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); clks[IMX8MQ_SYS3_PLL1_REF_SEL] = imx_clk_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); clks[IMX8MQ_DRAM_PLL1_REF_SEL] = imx_clk_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MQ_VIDEO2_PLL1_REF_SEL] = imx_clk_mux("video2_pll1_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); clks[IMX8MQ_ARM_PLL_REF_DIV] = imx_clk_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6); clks[IMX8MQ_GPU_PLL_REF_DIV] = imx_clk_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6); @@ -334,6 +359,13 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels)); clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels)); + /* unbypass all the plls */ + clk_set_parent(clks[IMX8MQ_GPU_PLL_BYPASS], clks[IMX8MQ_GPU_PLL]); + clk_set_parent(clks[IMX8MQ_VPU_PLL_BYPASS], clks[IMX8MQ_VPU_PLL]); + clk_set_parent(clks[IMX8MQ_AUDIO_PLL1_BYPASS], clks[IMX8MQ_AUDIO_PLL1]); + clk_set_parent(clks[IMX8MQ_AUDIO_PLL2_BYPASS], clks[IMX8MQ_AUDIO_PLL2]); + clk_set_parent(clks[IMX8MQ_VIDEO_PLL1_BYPASS], clks[IMX8MQ_VIDEO_PLL1]); + /* PLL OUT GATE */ clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21); clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21); @@ -346,6 +378,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_sccg_pll("sys2_pll_out", sys2_pll_out_sels, ARRAY_SIZE(sys2_pll_out_sels), 0, 0, 1, base + 0x3c, CLK_IS_CRITICAL); clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_sccg_pll("sys3_pll_out", sys3_pll_out_sels, ARRAY_SIZE(sys3_pll_out_sels), 0, 0, 1, base + 0x48, CLK_IS_CRITICAL); clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_sccg_pll("dram_pll_out", dram_pll_out_sels, ARRAY_SIZE(dram_pll_out_sels), 0, 0, 0, base + 0x60, CLK_IS_CRITICAL); + clks[IMX8MQ_VIDEO2_PLL_OUT] = imx_clk_sccg_pll("video2_pll_out", video2_pll_out_sels, ARRAY_SIZE(video2_pll_out_sels), 0, 0, 0, base + 0x54, 0); + /* SYS PLL fixed output */ clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20); clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10); @@ -567,7 +601,17 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) goto unregister_clks; } - imx_register_uart_clocks(uart_clks); + /* enable all the clocks just for bringup */ + imx_clk_init_on(np, clks); + + clk_set_parent(clks[IMX8MQ_CLK_CSI1_CORE], clks[IMX8MQ_SYS1_PLL_266M]); + clk_set_parent(clks[IMX8MQ_CLK_CSI1_PHY_REF], clks[IMX8MQ_SYS2_PLL_1000M]); + clk_set_parent(clks[IMX8MQ_CLK_CSI1_ESC], clks[IMX8MQ_SYS1_PLL_800M]); + clk_set_parent(clks[IMX8MQ_CLK_CSI2_CORE], clks[IMX8MQ_SYS1_PLL_266M]); + clk_set_parent(clks[IMX8MQ_CLK_CSI2_PHY_REF], clks[IMX8MQ_SYS2_PLL_1000M]); + clk_set_parent(clks[IMX8MQ_CLK_CSI2_ESC], clks[IMX8MQ_SYS1_PLL_800M]); + + imx_register_uart_clocks(); return 0; diff --git a/drivers/clk/imx/clk-imx8qm-acm.c b/drivers/clk/imx/clk-imx8qm-acm.c new file mode 100644 index 000000000000..325727efa356 --- /dev/null +++ b/drivers/clk/imx/clk-imx8qm-acm.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> + +#include "clk.h" +#include "clk-scu.h" + +#include <dt-bindings/clock/imx8-clock.h> + +struct imx8qm_acm_priv { + void __iomem *reg; + u32 regs[32]; +}; + +static const char *aud_clk_sels[] = { + "aud_rec_clk0_lpcg_clk", + "aud_rec_clk1_lpcg_clk", + "mlb_clk", + "hdmi_rx_mclk", + "ext_aud_mclk0", + "ext_aud_mclk1", + "esai0_rx_clk", + "esai0_rx_hf_clk", + "esai0_tx_clk", + "esai0_tx_hf_clk", + "esai1_rx_clk", + "esai1_rx_hf_clk", + "esai1_tx_clk", + "esai1_tx_hf_clk", + "spdif0_rx", + "spdif1_rx", + "sai0_rx_bclk", + "sai0_tx_bclk", + "sai1_rx_bclk", + "sai1_tx_bclk", + "sai2_rx_bclk", + "sai3_rx_bclk", + "sai4_rx_bclk", +}; + +static const char *mclk_out_sels[] = { + "aud_rec_clk0_lpcg_clk", + "aud_rec_clk1_lpcg_clk", + "mlb_clk", + "hdmi_rx_mclk", + "spdif0_rx", + "spdif1_rx", + "sai4_rx_bclk", + "sai6_rx_bclk", +}; + +static const char *sai_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static const char *asrc_mux_clk_sels[] = { + "sai4_rx_bclk", + "sai5_tx_bclk", + "dummy", + "mlb_clk", +}; + +static const char *esai_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static const char *spdif_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static const char *mqs_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static int imx8qm_acm_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct clk_onecell_data *clk_data; + struct imx8qm_acm_priv *priv; + struct resource *res; + struct clk **clks; + void __iomem *base; + int num_domains; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap(dev, res->start, resource_size(res)); + if (!base) + return -ENOMEM; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reg = base; + + platform_set_drvdata(pdev, priv); + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = kcalloc(IMX_ADMA_ACM_CLK_END, + sizeof(*clk_data->clks), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = IMX_ADMA_ACM_CLK_END; + + clks = clk_data->clks; + + num_domains = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + for (i = 0; i < num_domains; i++) { + struct device *pd_dev; + struct device_link *link; + + pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(pd_dev)) + return PTR_ERR(pd_dev); + + link = device_link_add(&pdev->dev, pd_dev, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(link)) + return PTR_ERR(link); + } + + clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0); + clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0); + clks[IMX_ADMA_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0); + clks[IMX_ADMA_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0); + clks[IMX_ADMA_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0); + clks[IMX_ADMA_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0); + clks[IMX_ADMA_ESAI1_RX_CLK] = imx_clk_fixed("esai1_rx_clk", 0); + clks[IMX_ADMA_ESAI1_RX_HF_CLK] = imx_clk_fixed("esai1_rx_hf_clk", 0); + clks[IMX_ADMA_ESAI1_TX_CLK] = imx_clk_fixed("esai1_tx_clk", 0); + clks[IMX_ADMA_ESAI1_TX_HF_CLK] = imx_clk_fixed("esai1_tx_hf_clk", 0); + clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0); + clks[IMX_ADMA_SPDIF1_RX] = imx_clk_fixed("spdif1_rx", 0); + clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0); + clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0); + clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0); + clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0); + clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0); + clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0); + clks[IMX_ADMA_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0); + clks[IMX_ADMA_SAI5_TX_BCLK] = imx_clk_fixed("sai5_tx_bclk", 0); + clks[IMX_ADMA_SAI6_RX_BCLK] = imx_clk_fixed("sai6_rx_bclk", 0); + clks[IMX_ADMA_HDMI_RX_MCLK] = imx_clk_fixed("hdmi_rx_mclk", 0); + clks[IMX_ADMA_MLB_CLK] = imx_clk_fixed("mlb_clk", 0); + + + clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_clk_mux("acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels)); + clks[IMX_ADMA_ACM_AUD_CLK1_CLK] = imx_clk_mux("acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels)); + + clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_clk_mux("acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels)); + clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_clk_mux("acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels)); + + clks[IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL] = imx_clk_mux("acm_asrc0_mclk_sel", base+0x040000, 0, 2, asrc_mux_clk_sels, ARRAY_SIZE(asrc_mux_clk_sels)); + + clks[IMX_ADMA_ACM_ESAI0_MCLK_SEL] = imx_clk_mux("acm_esai0_mclk_sel", base+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels)); + clks[IMX_ADMA_ACM_ESAI1_MCLK_SEL] = imx_clk_mux("acm_esai1_mclk_sel", base+0x070000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_clk_mux("acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_clk_mux("acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_clk_mux("acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_clk_mux("acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI4_MCLK_SEL] = imx_clk_mux("acm_sai4_mclk_sel", base+0x120000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI5_MCLK_SEL] = imx_clk_mux("acm_sai5_mclk_sel", base+0x130000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI6_MCLK_SEL] = imx_clk_mux("acm_sai6_mclk_sel", base+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI7_MCLK_SEL] = imx_clk_mux("acm_sai7_mclk_sel", base+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + + clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_clk_mux("acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels)); + clks[IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL] = imx_clk_mux("acm_spdif1_mclk_sel", base+0x1B0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels)); + clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_clk_mux("acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels)); + + for (i = 0; i < clk_data->clk_num; i++) { + if (IS_ERR(clks[i])) + pr_warn("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); + } + + return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id imx8qm_acm_match[] = { + { .compatible = "nxp,imx8qm-acm", }, + { /* sentinel */ } +}; + +static int __maybe_unused imx8qm_acm_suspend(struct device *dev) +{ + struct imx8qm_acm_priv *priv = dev_get_drvdata(dev); + + priv->regs[0] = readl_relaxed(priv->reg + 0x000000); + priv->regs[1] = readl_relaxed(priv->reg + 0x010000); + priv->regs[2] = readl_relaxed(priv->reg + 0x020000); + priv->regs[3] = readl_relaxed(priv->reg + 0x030000); + priv->regs[4] = readl_relaxed(priv->reg + 0x040000); + priv->regs[6] = readl_relaxed(priv->reg + 0x060000); + priv->regs[7] = readl_relaxed(priv->reg + 0x070000); + priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000); + priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000); + priv->regs[16] = readl_relaxed(priv->reg + 0x100000); + priv->regs[17] = readl_relaxed(priv->reg + 0x110000); + priv->regs[18] = readl_relaxed(priv->reg + 0x120000); + priv->regs[19] = readl_relaxed(priv->reg + 0x130000); + priv->regs[20] = readl_relaxed(priv->reg + 0x140000); + priv->regs[21] = readl_relaxed(priv->reg + 0x150000); + priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000); + priv->regs[27] = readl_relaxed(priv->reg + 0x1B0000); + priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000); + + return 0; +} + +static int __maybe_unused imx8qm_acm_resume(struct device *dev) +{ + struct imx8qm_acm_priv *priv = dev_get_drvdata(dev); + + writel_relaxed(priv->regs[0], priv->reg + 0x000000); + writel_relaxed(priv->regs[1], priv->reg + 0x010000); + writel_relaxed(priv->regs[2], priv->reg + 0x020000); + writel_relaxed(priv->regs[3], priv->reg + 0x030000); + writel_relaxed(priv->regs[4], priv->reg + 0x040000); + writel_relaxed(priv->regs[6], priv->reg + 0x060000); + writel_relaxed(priv->regs[7], priv->reg + 0x070000); + writel_relaxed(priv->regs[14], priv->reg + 0x0E0000); + writel_relaxed(priv->regs[15], priv->reg + 0x0F0000); + writel_relaxed(priv->regs[16], priv->reg + 0x100000); + writel_relaxed(priv->regs[17], priv->reg + 0x110000); + writel_relaxed(priv->regs[18], priv->reg + 0x120000); + writel_relaxed(priv->regs[19], priv->reg + 0x130000); + writel_relaxed(priv->regs[20], priv->reg + 0x140000); + writel_relaxed(priv->regs[21], priv->reg + 0x150000); + writel_relaxed(priv->regs[26], priv->reg + 0x1A0000); + writel_relaxed(priv->regs[27], priv->reg + 0x1B0000); + writel_relaxed(priv->regs[28], priv->reg + 0x1C0000); + + return 0; +} + +static const struct dev_pm_ops imx8qm_acm_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx8qm_acm_suspend, + imx8qm_acm_resume) +}; + +static struct platform_driver imx8qm_acm_clk_driver = { + .driver = { + .name = "imx8qm-acm", + .of_match_table = imx8qm_acm_match, + .pm = &imx8qm_acm_pm_ops, + .suppress_bind_attrs = true, + }, + .probe = imx8qm_acm_clk_probe, +}; + +static int __init imx8qm_acm_init(void) +{ + return platform_driver_register(&imx8qm_acm_clk_driver); +} +fs_initcall(imx8qm_acm_init); diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c new file mode 100644 index 000000000000..3f683f765e13 --- /dev/null +++ b/drivers/clk/imx/clk-imx8qm-rsrc.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/firmware/imx/rsrc.h> + +#include "clk-scu.h" + +/* Keep sorted in the ascending order */ +static u32 imx8qm_clk_scu_rsrc_table[] = { + IMX_SC_R_A53, + IMX_SC_R_A72, + IMX_SC_R_DC_0_VIDEO0, + IMX_SC_R_DC_0_VIDEO1, + IMX_SC_R_DC_0, + IMX_SC_R_DC_0_PLL_0, + IMX_SC_R_DC_0_PLL_1, + IMX_SC_R_DC_1_VIDEO0, + IMX_SC_R_DC_1_VIDEO1, + IMX_SC_R_DC_1, + IMX_SC_R_DC_1_PLL_0, + IMX_SC_R_DC_1_PLL_1, + IMX_SC_R_SPI_0, + IMX_SC_R_SPI_1, + IMX_SC_R_SPI_2, + IMX_SC_R_SPI_3, + IMX_SC_R_UART_0, + IMX_SC_R_UART_1, + IMX_SC_R_UART_2, + IMX_SC_R_UART_3, + IMX_SC_R_UART_4, + IMX_SC_R_EMVSIM_0, + IMX_SC_R_EMVSIM_1, + IMX_SC_R_I2C_0, + IMX_SC_R_I2C_1, + IMX_SC_R_I2C_2, + IMX_SC_R_I2C_3, + IMX_SC_R_I2C_4, + IMX_SC_R_ADC_0, + IMX_SC_R_ADC_1, + IMX_SC_R_FTM_0, + IMX_SC_R_FTM_1, + IMX_SC_R_CAN_0, + IMX_SC_R_CAN_1, + IMX_SC_R_CAN_2, + IMX_SC_R_GPU_0_PID0, + IMX_SC_R_GPU_1_PID0, + IMX_SC_R_PWM_0, + IMX_SC_R_PWM_1, + IMX_SC_R_PWM_2, + IMX_SC_R_PWM_3, + IMX_SC_R_PWM_4, + IMX_SC_R_PWM_5, + IMX_SC_R_PWM_6, + IMX_SC_R_PWM_7, + IMX_SC_R_GPT_0, + IMX_SC_R_GPT_1, + IMX_SC_R_GPT_2, + IMX_SC_R_GPT_3, + IMX_SC_R_GPT_4, + IMX_SC_R_FSPI_0, + IMX_SC_R_FSPI_1, + IMX_SC_R_SDHC_0, + IMX_SC_R_SDHC_1, + IMX_SC_R_SDHC_2, + IMX_SC_R_ENET_0, + IMX_SC_R_ENET_1, + IMX_SC_R_MLB_0, + IMX_SC_R_USB_2, + IMX_SC_R_NAND, + IMX_SC_R_LVDS_0, + IMX_SC_R_LVDS_0_PWM_0, + IMX_SC_R_LVDS_0_I2C_0, + IMX_SC_R_LVDS_0_I2C_1, + IMX_SC_R_LVDS_1, + IMX_SC_R_LVDS_1_PWM_0, + IMX_SC_R_LVDS_1_I2C_0, + IMX_SC_R_LVDS_1_I2C_1, + IMX_SC_R_M4_0_I2C, + IMX_SC_R_M4_1_I2C, + IMX_SC_R_AUDIO_PLL_0, + IMX_SC_R_VPU_UART, + IMX_SC_R_VPUCORE, + IMX_SC_R_MIPI_0, + IMX_SC_R_MIPI_0_PWM_0, + IMX_SC_R_MIPI_0_I2C_0, + IMX_SC_R_MIPI_0_I2C_1, + IMX_SC_R_MIPI_1, + IMX_SC_R_MIPI_1_PWM_0, + IMX_SC_R_MIPI_1_I2C_0, + IMX_SC_R_MIPI_1_I2C_1, + IMX_SC_R_CSI_0, + IMX_SC_R_CSI_0_PWM_0, + IMX_SC_R_CSI_0_I2C_0, + IMX_SC_R_CSI_1, + IMX_SC_R_CSI_1_PWM_0, + IMX_SC_R_CSI_1_I2C_0, + IMX_SC_R_HDMI, + IMX_SC_R_HDMI_I2S, + IMX_SC_R_HDMI_I2C_0, + IMX_SC_R_HDMI_PLL_0, + IMX_SC_R_HDMI_RX, + IMX_SC_R_HDMI_RX_BYPASS, + IMX_SC_R_HDMI_RX_I2C_0, + IMX_SC_R_AUDIO_PLL_1, + IMX_SC_R_AUDIO_CLK_0, + IMX_SC_R_AUDIO_CLK_1, + IMX_SC_R_HDMI_RX_PWM_0, + IMX_SC_R_HDMI_PLL_1, + IMX_SC_R_VPU, +}; + +const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm = { + .rsrc = imx8qm_clk_scu_rsrc_table, + .num = ARRAY_SIZE(imx8qm_clk_scu_rsrc_table), +}; diff --git a/drivers/clk/imx/clk-imx8qxp-acm.c b/drivers/clk/imx/clk-imx8qxp-acm.c new file mode 100644 index 000000000000..187c86067e50 --- /dev/null +++ b/drivers/clk/imx/clk-imx8qxp-acm.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> + +#include "clk.h" +#include "clk-scu.h" + +#include <dt-bindings/clock/imx8-clock.h> + +struct imx8qxp_acm_priv { + void __iomem *reg; + u32 regs[0x20]; +}; + +static const char *aud_clk_sels[] = { + "aud_rec_clk0_lpcg_clk", + "aud_rec_clk1_lpcg_clk", + "ext_aud_mclk0", + "ext_aud_mclk1", + "esai0_rx_clk", + "esai0_rx_hf_clk", + "esai0_tx_clk", + "esai0_tx_hf_clk", + "spdif0_rx", + "sai0_rx_bclk", + "sai0_tx_bclk", + "sai1_rx_bclk", + "sai1_tx_bclk", + "sai2_rx_bclk", + "sai3_rx_bclk", +}; + +static const char *mclk_out_sels[] = { + "aud_rec_clk0_lpcg_clk", + "aud_rec_clk1_lpcg_clk", + "dummy", + "dummy", + "spdif0_rx", + "dummy", + "dummy", + "sai4_rx_bclk", +}; + +static const char *sai_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static const char *esai_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static const char *spdif_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static const char *mqs_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", + "acm_aud_clk0_sel", + "acm_aud_clk1_sel", +}; + +static int imx8qxp_acm_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct clk_onecell_data *clk_data; + struct imx8qxp_acm_priv *priv; + struct resource *res; + struct clk **clks; + void __iomem *base; + int num_domains; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap(dev, res->start, resource_size(res)); + if (!base) + return -ENOMEM; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reg = base; + + platform_set_drvdata(pdev, priv); + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = kcalloc(IMX_ADMA_ACM_CLK_END, + sizeof(*clk_data->clks), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = IMX_ADMA_ACM_CLK_END; + + clks = clk_data->clks; + + num_domains = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + for (i = 0; i < num_domains; i++) { + struct device *pd_dev; + struct device_link *link; + + pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(pd_dev)) + return PTR_ERR(pd_dev); + + link = device_link_add(&pdev->dev, pd_dev, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(link)) + return PTR_ERR(link); + } + + clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0); + clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0); + clks[IMX_ADMA_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0); + clks[IMX_ADMA_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0); + clks[IMX_ADMA_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0); + clks[IMX_ADMA_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0); + clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0); + clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0); + clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0); + clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0); + clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0); + clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0); + clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0); + clks[IMX_ADMA_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0); + + + clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_clk_mux("acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels)); + clks[IMX_ADMA_ACM_AUD_CLK1_CLK] = imx_clk_mux("acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels)); + + clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_clk_mux("acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels)); + clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_clk_mux("acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels)); + + clks[IMX_ADMA_ACM_ESAI0_MCLK_SEL] = imx_clk_mux("acm_esai0_mclk_sel", base+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_clk_mux("acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_clk_mux("acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_clk_mux("acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_clk_mux("acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI4_MCLK_SEL] = imx_clk_mux("acm_sai4_mclk_sel", base+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI5_MCLK_SEL] = imx_clk_mux("acm_sai5_mclk_sel", base+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + + clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_clk_mux("acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels)); + clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_clk_mux("acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels)); + + for (i = 0; i < clk_data->clk_num; i++) { + if (IS_ERR(clks[i])) + pr_warn("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); + } + + return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id imx8qxp_acm_match[] = { + { .compatible = "nxp,imx8qxp-acm", }, + { /* sentinel */ } +}; + +static int __maybe_unused imx8qxp_acm_suspend(struct device *dev) +{ + struct imx8qxp_acm_priv *priv = dev_get_drvdata(dev); + + priv->regs[0] = readl_relaxed(priv->reg + 0x000000); + priv->regs[1] = readl_relaxed(priv->reg + 0x010000); + priv->regs[2] = readl_relaxed(priv->reg + 0x020000); + priv->regs[3] = readl_relaxed(priv->reg + 0x030000); + priv->regs[6] = readl_relaxed(priv->reg + 0x060000); + priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000); + priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000); + priv->regs[16] = readl_relaxed(priv->reg + 0x100000); + priv->regs[17] = readl_relaxed(priv->reg + 0x110000); + priv->regs[20] = readl_relaxed(priv->reg + 0x140000); + priv->regs[21] = readl_relaxed(priv->reg + 0x150000); + priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000); + priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000); + + return 0; +} + +static int __maybe_unused imx8qxp_acm_resume(struct device *dev) +{ + struct imx8qxp_acm_priv *priv = dev_get_drvdata(dev); + + writel_relaxed(priv->regs[0], priv->reg + 0x000000); + writel_relaxed(priv->regs[1], priv->reg + 0x010000); + writel_relaxed(priv->regs[2], priv->reg + 0x020000); + writel_relaxed(priv->regs[3], priv->reg + 0x030000); + writel_relaxed(priv->regs[6], priv->reg + 0x060000); + writel_relaxed(priv->regs[14], priv->reg + 0x0E0000); + writel_relaxed(priv->regs[15], priv->reg + 0x0F0000); + writel_relaxed(priv->regs[16], priv->reg + 0x100000); + writel_relaxed(priv->regs[17], priv->reg + 0x110000); + writel_relaxed(priv->regs[20], priv->reg + 0x140000); + writel_relaxed(priv->regs[21], priv->reg + 0x150000); + writel_relaxed(priv->regs[26], priv->reg + 0x1A0000); + writel_relaxed(priv->regs[28], priv->reg + 0x1C0000); + + return 0; +} + +const struct dev_pm_ops imx8qxp_acm_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx8qxp_acm_suspend, + imx8qxp_acm_resume) +}; + +static struct platform_driver imx8qxp_acm_clk_driver = { + .driver = { + .name = "imx8qxp-acm", + .of_match_table = imx8qxp_acm_match, + .pm = &imx8qxp_acm_pm_ops, + .suppress_bind_attrs = true, + }, + .probe = imx8qxp_acm_clk_probe, +}; + +static int __init imx8qxp_acm_init(void) +{ + return platform_driver_register(&imx8qxp_acm_clk_driver); +} +fs_initcall(imx8qxp_acm_init); diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index c0aff7ca6374..741b73e4c609 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -9,205 +9,106 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include "clk-scu.h" -#include "clk-imx8qxp-lpcg.h" -#include <dt-bindings/clock/imx8-clock.h> - -/* - * struct imx8qxp_lpcg_data - Description of one LPCG clock - * @id: clock ID - * @name: clock name - * @parent: parent clock name - * @flags: common clock flags - * @offset: offset of this LPCG clock - * @bit_idx: bit index of this LPCG clock - * @hw_gate: whether supports HW autogate - * - * This structure describes one LPCG clock - */ -struct imx8qxp_lpcg_data { - int id; - char *name; - char *parent; - unsigned long flags; - u32 offset; - u8 bit_idx; - bool hw_gate; -}; - -/* - * struct imx8qxp_ss_lpcg - Description of one subsystem LPCG clocks - * @lpcg: LPCG clocks array of one subsystem - * @num_lpcg: the number of LPCG clocks - * @num_max: the maximum number of LPCG clocks - * - * This structure describes each subsystem LPCG clocks information - * which then will be used to create respective LPCGs clocks - */ -struct imx8qxp_ss_lpcg { - const struct imx8qxp_lpcg_data *lpcg; - u8 num_lpcg; - u8 num_max; -}; - -static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = { - { IMX_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_UART2_IPG_CLK, "uart2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_2_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_UART2_BAUD_CLK, "uart2_lpcg_baud_clk", "uart2_clk", 0, ADMA_LPUART_2_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_UART3_IPG_CLK, "uart3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_3_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_UART3_BAUD_CLK, "uart3_lpcg_baud_clk", "uart3_clk", 0, ADMA_LPUART_3_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_I2C0_IPG_CLK, "i2c0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_0_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_I2C0_CLK, "i2c0_lpcg_clk", "i2c0_clk", 0, ADMA_LPI2C_0_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_I2C1_IPG_CLK, "i2c1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_1_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_I2C1_CLK, "i2c1_lpcg_clk", "i2c1_clk", 0, ADMA_LPI2C_1_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_I2C2_IPG_CLK, "i2c2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_2_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, }, - { IMX_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, }, - - { IMX_ADMA_LPCG_DSP_CORE_CLK, "dsp_lpcg_core_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 28, 0, }, - { IMX_ADMA_LPCG_DSP_IPG_CLK, "dsp_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 20, 0, }, - { IMX_ADMA_LPCG_DSP_ADB_CLK, "dsp_lpcg_adb_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 16, 0, }, - { IMX_ADMA_LPCG_OCRAM_IPG_CLK, "ocram_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_OCRAM_LPCG, 16, 0, }, -}; - -static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = { - .lpcg = imx8qxp_lpcg_adma, - .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_adma), - .num_max = IMX_ADMA_LPCG_CLK_END, -}; - -static const struct imx8qxp_lpcg_data imx8qxp_lpcg_conn[] = { - { IMX_CONN_LPCG_SDHC0_PER_CLK, "sdhc0_lpcg_per_clk", "sdhc0_clk", 0, CONN_USDHC_0_LPCG, 0, 0, }, - { IMX_CONN_LPCG_SDHC0_IPG_CLK, "sdhc0_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_0_LPCG, 16, 0, }, - { IMX_CONN_LPCG_SDHC0_HCLK, "sdhc0_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_0_LPCG, 20, 0, }, - { IMX_CONN_LPCG_SDHC1_PER_CLK, "sdhc1_lpcg_per_clk", "sdhc1_clk", 0, CONN_USDHC_1_LPCG, 0, 0, }, - { IMX_CONN_LPCG_SDHC1_IPG_CLK, "sdhc1_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_1_LPCG, 16, 0, }, - { IMX_CONN_LPCG_SDHC1_HCLK, "sdhc1_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_1_LPCG, 20, 0, }, - { IMX_CONN_LPCG_SDHC2_PER_CLK, "sdhc2_lpcg_per_clk", "sdhc2_clk", 0, CONN_USDHC_2_LPCG, 0, 0, }, - { IMX_CONN_LPCG_SDHC2_IPG_CLK, "sdhc2_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_2_LPCG, 16, 0, }, - { IMX_CONN_LPCG_SDHC2_HCLK, "sdhc2_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_2_LPCG, 20, 0, }, - { IMX_CONN_LPCG_ENET0_ROOT_CLK, "enet0_ipg_root_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 0, 0, }, - { IMX_CONN_LPCG_ENET0_TX_CLK, "enet0_tx_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 4, 0, }, - { IMX_CONN_LPCG_ENET0_AHB_CLK, "enet0_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_0_LPCG, 8, 0, }, - { IMX_CONN_LPCG_ENET0_IPG_S_CLK, "enet0_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_0_LPCG, 20, 0, }, - { IMX_CONN_LPCG_ENET0_IPG_CLK, "enet0_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_0_LPCG, 16, 0, }, - { IMX_CONN_LPCG_ENET1_ROOT_CLK, "enet1_ipg_root_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 0, 0, }, - { IMX_CONN_LPCG_ENET1_TX_CLK, "enet1_tx_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 4, 0, }, - { IMX_CONN_LPCG_ENET1_AHB_CLK, "enet1_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_1_LPCG, 8, 0, }, - { IMX_CONN_LPCG_ENET1_IPG_S_CLK, "enet1_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_1_LPCG, 20, 0, }, - { IMX_CONN_LPCG_ENET1_IPG_CLK, "enet1_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_1_LPCG, 16, 0, }, -}; - -static const struct imx8qxp_ss_lpcg imx8qxp_ss_conn = { - .lpcg = imx8qxp_lpcg_conn, - .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_conn), - .num_max = IMX_CONN_LPCG_CLK_END, -}; - -static const struct imx8qxp_lpcg_data imx8qxp_lpcg_lsio[] = { - { IMX_LSIO_LPCG_PWM0_IPG_CLK, "pwm0_lpcg_ipg_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM0_IPG_HF_CLK, "pwm0_lpcg_ipg_hf_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM0_IPG_S_CLK, "pwm0_lpcg_ipg_s_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM0_IPG_SLV_CLK, "pwm0_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_0_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM0_IPG_MSTR_CLK, "pwm0_lpcg_ipg_mstr_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 24, 0, }, - { IMX_LSIO_LPCG_PWM1_IPG_CLK, "pwm1_lpcg_ipg_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM1_IPG_HF_CLK, "pwm1_lpcg_ipg_hf_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM1_IPG_S_CLK, "pwm1_lpcg_ipg_s_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM1_IPG_SLV_CLK, "pwm1_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_1_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM1_IPG_MSTR_CLK, "pwm1_lpcg_ipg_mstr_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 24, 0, }, - { IMX_LSIO_LPCG_PWM2_IPG_CLK, "pwm2_lpcg_ipg_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM2_IPG_HF_CLK, "pwm2_lpcg_ipg_hf_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM2_IPG_S_CLK, "pwm2_lpcg_ipg_s_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM2_IPG_SLV_CLK, "pwm2_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_2_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM2_IPG_MSTR_CLK, "pwm2_lpcg_ipg_mstr_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 24, 0, }, - { IMX_LSIO_LPCG_PWM3_IPG_CLK, "pwm3_lpcg_ipg_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM3_IPG_HF_CLK, "pwm3_lpcg_ipg_hf_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM3_IPG_S_CLK, "pwm3_lpcg_ipg_s_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM3_IPG_SLV_CLK, "pwm3_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_3_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM3_IPG_MSTR_CLK, "pwm3_lpcg_ipg_mstr_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 24, 0, }, - { IMX_LSIO_LPCG_PWM4_IPG_CLK, "pwm4_lpcg_ipg_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM4_IPG_HF_CLK, "pwm4_lpcg_ipg_hf_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM4_IPG_S_CLK, "pwm4_lpcg_ipg_s_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM4_IPG_SLV_CLK, "pwm4_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_4_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM4_IPG_MSTR_CLK, "pwm4_lpcg_ipg_mstr_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 24, 0, }, - { IMX_LSIO_LPCG_PWM5_IPG_CLK, "pwm5_lpcg_ipg_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM5_IPG_HF_CLK, "pwm5_lpcg_ipg_hf_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM5_IPG_S_CLK, "pwm5_lpcg_ipg_s_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM5_IPG_SLV_CLK, "pwm5_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_5_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM5_IPG_MSTR_CLK, "pwm5_lpcg_ipg_mstr_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 24, 0, }, - { IMX_LSIO_LPCG_PWM6_IPG_CLK, "pwm6_lpcg_ipg_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 0, 0, }, - { IMX_LSIO_LPCG_PWM6_IPG_HF_CLK, "pwm6_lpcg_ipg_hf_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 4, 0, }, - { IMX_LSIO_LPCG_PWM6_IPG_S_CLK, "pwm6_lpcg_ipg_s_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 16, 0, }, - { IMX_LSIO_LPCG_PWM6_IPG_SLV_CLK, "pwm6_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_6_LPCG, 20, 0, }, - { IMX_LSIO_LPCG_PWM6_IPG_MSTR_CLK, "pwm6_lpcg_ipg_mstr_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 24, 0, }, -}; - -static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = { - .lpcg = imx8qxp_lpcg_lsio, - .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_lsio), - .num_max = IMX_LSIO_LPCG_CLK_END, -}; +#define IMX_LPCG_MAX_CLKS 8 static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; + struct device_node *np = pdev->dev.of_node; + const char *output_names[IMX_LPCG_MAX_CLKS]; + const char *parent_names[IMX_LPCG_MAX_CLKS]; + unsigned int bit_offset[IMX_LPCG_MAX_CLKS]; struct clk_hw_onecell_data *clk_data; - const struct imx8qxp_ss_lpcg *ss_lpcg; - const struct imx8qxp_lpcg_data *lpcg; + struct clk_hw **clk_hws; struct resource *res; - struct clk_hw **clks; void __iomem *base; + bool autogate; + int count; + int ret; int i; - ss_lpcg = of_device_get_match_data(dev); - if (!ss_lpcg) - return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + count = of_property_count_u32_elems(np, "bit-offset"); + if (count < 0) { + dev_err(&pdev->dev, "failed to count clocks\n"); return -EINVAL; - base = devm_ioremap(dev, res->start, resource_size(res)); - if (!base) - return -ENOMEM; + } - clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, - ss_lpcg->num_max), GFP_KERNEL); + clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, count), + GFP_KERNEL); if (!clk_data) return -ENOMEM; - clk_data->num = ss_lpcg->num_max; - clks = clk_data->hws; + clk_data->num = count; + clk_hws = clk_data->hws; - for (i = 0; i < ss_lpcg->num_lpcg; i++) { - lpcg = ss_lpcg->lpcg + i; - clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name, lpcg->parent, - lpcg->flags, base + lpcg->offset, - lpcg->bit_idx, lpcg->hw_gate); + ret = of_property_read_u32_array(np, "bit-offset", bit_offset, + clk_data->num); + if (ret < 0) { + dev_err(&pdev->dev, "failed to read clocks bit-offset\n"); + return -EINVAL; } + ret = of_clk_parent_fill(np, parent_names, clk_data->num); + if (ret != clk_data->num) { + dev_err(&pdev->dev, "failed to get clock parent names\n"); + return -EINVAL; + } + + ret = of_property_read_string_array(np, "clock-output-names", + output_names, clk_data->num); + if (ret != clk_data->num) { + dev_err(&pdev->dev, "failed to read clock-output-names\n"); + return -EINVAL; + } + + autogate = of_property_read_bool(np, "hw-autogate"); + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 500); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + for (i = 0; i < clk_data->num; i++) { - if (IS_ERR(clks[i])) - pr_warn("i.MX clk %u: register failed with %ld\n", - i, PTR_ERR(clks[i])); + if (bit_offset[i] > 31) { + dev_warn(&pdev->dev, "invalid bit offset of clock %d\n", + i); + return -EINVAL; + } + + clk_hws[i] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i], + parent_names[i], 0, base, + bit_offset[i], autogate); + if (IS_ERR(clk_hws[i])) { + dev_warn(&pdev->dev, "failed to register clock %d\n", + i); + return -EINVAL; + } } - return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); + ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get, + clk_data); + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + return ret; } static const struct of_device_id imx8qxp_lpcg_match[] = { - { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, }, - { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, }, - { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, }, + { .compatible = "fsl,imx8qxp-lpcg", NULL }, { /* sentinel */ } }; @@ -215,6 +116,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = { .driver = { .name = "imx8qxp-lpcg-clk", .of_match_table = imx8qxp_lpcg_match, + .pm = &imx_clk_lpcg_scu_pm_ops, .suppress_bind_attrs = true, }, .probe = imx8qxp_lpcg_clk_probe, diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.h b/drivers/clk/imx/clk-imx8qxp-lpcg.h index 2a37ce57c500..d435cd5c5713 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.h +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.h @@ -99,4 +99,49 @@ #define ADMA_FLEXCAN_1_LPCG 0x1ce0000 #define ADMA_FLEXCAN_2_LPCG 0x1cf0000 +/* CM40 SS */ +#define CM40_I2C_LPCG 0x60000 + +/* HSIO SS */ +#define HSIO_PCIEA_LPCG 0x00000 +#define HSIO_PCIEB_LPCG 0x10000 +#define HSIO_SATA0_LPCG 0x20000 +#define HSIO_PHYX2_LPCG 0x30000 +#define HSIO_PHYX1_LPCG 0x40000 +#define HSIO_CRR_0_LPCG 0x50000 +#define HSIO_CRR_1_LPCG 0x60000 +#define HSIO_CRR_2_LPCG 0x70000 +#define HSIO_CRR_3_LPCG 0x80000 +#define HSIO_CRR_4_LPCG 0x90000 +#define HSIO_CRR_5_LPCG 0xa0000 +#define HSIO_GPIO_LPCG 0xb0000 + +/* IMG SS */ +#define IMG_PDMA0_LPCG 0x00000 +#define IMG_PDMA1_LPCG 0x10000 +#define IMG_PDMA2_LPCG 0x20000 +#define IMG_PDMA3_LPCG 0x30000 +#define IMG_PDMA4_LPCG 0x40000 +#define IMG_PDMA5_LPCG 0x50000 +#define IMG_PDMA6_LPCG 0x60000 +#define IMG_PDMA7_LPCG 0x70000 +#define IMG_MIPI_CSI0_LPCG 0x80000 +#define IMG_MIPI_CSI1_LPCG 0x90000 + +/* CSI SS */ +#define CSI_CSI0_CORE_LPCG 0x18 +#define CSI_CSI0_ESC_LPCG 0x1C +#define CSI_CSI0_I2C0_LPCG 0x14 +#define CSI_CSI1_CORE_LPCG 0x18 +#define CSI_CSI1_ESC_LPCG 0x1C +#define CSI_CSI1_I2C0_LPCG 0x14 + +/* Parallel Interface SS */ +#define PI_PI0_PIXEL_LPCG 0x18 +#define PI_PI0_IPG_LPCG 0x04 +#define PI_PI0_MISC_LPCG 0x1C + +/* DC0 SS */ +/* TODO: ADD DC LPCGs */ + #endif /* _IMX8QXP_LPCG_H */ diff --git a/drivers/clk/imx/clk-imx8qxp-rsrc.c b/drivers/clk/imx/clk-imx8qxp-rsrc.c new file mode 100644 index 000000000000..e2295b8b99c8 --- /dev/null +++ b/drivers/clk/imx/clk-imx8qxp-rsrc.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <dt-bindings/firmware/imx/rsrc.h> + +#include "clk-scu.h" + +/* Keep sorted in the ascending order */ +static u32 imx8qxp_clk_scu_rsrc_table[] = { + IMX_SC_R_DC_0_VIDEO0, + IMX_SC_R_DC_0_VIDEO1, + IMX_SC_R_DC_0, + IMX_SC_R_DC_0_PLL_0, + IMX_SC_R_DC_0_PLL_1, + IMX_SC_R_SPI_0, + IMX_SC_R_SPI_1, + IMX_SC_R_SPI_2, + IMX_SC_R_SPI_3, + IMX_SC_R_UART_0, + IMX_SC_R_UART_1, + IMX_SC_R_UART_2, + IMX_SC_R_UART_3, + IMX_SC_R_I2C_0, + IMX_SC_R_I2C_1, + IMX_SC_R_I2C_2, + IMX_SC_R_I2C_3, + IMX_SC_R_ADC_0, + IMX_SC_R_FTM_0, + IMX_SC_R_FTM_1, + IMX_SC_R_CAN_0, + IMX_SC_R_GPU_0_PID0, + IMX_SC_R_LCD_0, + IMX_SC_R_LCD_0_PWM_0, + IMX_SC_R_PWM_0, + IMX_SC_R_PWM_1, + IMX_SC_R_PWM_2, + IMX_SC_R_PWM_3, + IMX_SC_R_PWM_4, + IMX_SC_R_PWM_5, + IMX_SC_R_PWM_6, + IMX_SC_R_PWM_7, + IMX_SC_R_GPT_0, + IMX_SC_R_GPT_1, + IMX_SC_R_GPT_2, + IMX_SC_R_GPT_3, + IMX_SC_R_GPT_4, + IMX_SC_R_FSPI_0, + IMX_SC_R_FSPI_1, + IMX_SC_R_SDHC_0, + IMX_SC_R_SDHC_1, + IMX_SC_R_SDHC_2, + IMX_SC_R_ENET_0, + IMX_SC_R_ENET_1, + IMX_SC_R_MLB_0, + IMX_SC_R_USB_2, + IMX_SC_R_NAND, + IMX_SC_R_LVDS_0, + IMX_SC_R_LVDS_1, + IMX_SC_R_M4_0_I2C, + IMX_SC_R_ELCDIF_PLL, + IMX_SC_R_AUDIO_PLL_0, + IMX_SC_R_PI_0, + IMX_SC_R_PI_0_PLL, + IMX_SC_R_MIPI_0, + IMX_SC_R_MIPI_0_PWM_0, + IMX_SC_R_MIPI_0_I2C_0, + IMX_SC_R_MIPI_0_I2C_1, + IMX_SC_R_MIPI_1, + IMX_SC_R_MIPI_1_PWM_0, + IMX_SC_R_MIPI_1_I2C_0, + IMX_SC_R_MIPI_1_I2C_1, + IMX_SC_R_CSI_0, + IMX_SC_R_CSI_0_PWM_0, + IMX_SC_R_CSI_0_I2C_0, + IMX_SC_R_AUDIO_PLL_1, + IMX_SC_R_AUDIO_CLK_0, + IMX_SC_R_AUDIO_CLK_1, + IMX_SC_R_A35, + IMX_SC_R_VPU_DEC_0, + IMX_SC_R_VPU_ENC_0, +}; + +const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp = { + .rsrc = imx8qxp_clk_scu_rsrc_table, + .num = ARRAY_SIZE(imx8qxp_clk_scu_rsrc_table), +}; diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 5e2903efc488..57ad5c07476d 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -9,139 +9,244 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <dt-bindings/firmware/imx/rsrc.h> + #include "clk-scu.h" -#include <dt-bindings/clock/imx8-clock.h> -#include <dt-bindings/firmware/imx/rsrc.h> +static const char *sdhc0_sels[] = { + "dummy", + "conn_pll0_clk", + "conn_pll1_clk", + "dummy", + "dummy", +}; + +static const char *pll0_sels[] = { + "dummy", + "pi_dpll_clk", + "dummy", + "dummy", + "dummy", +}; + +static const char *enet0_rgmii_txc_sels[] = { + "enet0_ref_div", + "dummy", +}; + +static const char *enet1_rgmii_txc_sels[] = { + "enet1_ref_div", + "dummy", +}; + +static const char *dc0_sels[] = { + "clk_dummy", + "clk_dummy", + "dc0_pll0_clk", + "dc0_pll1_clk", + "dc0_bypass0_clk", +}; + +static const char *dc1_sels[] = { + "clk_dummy", + "clk_dummy", + "dc1_pll0_clk", + "dc1_pll1_clk", + "dc1_bypass0_clk", +}; + +static const char *hdmi_sels[] = { + "dummy", + "hdmi_dig_pll_clk", + "dummy", + "dummy", + "hdmi_av_pll_clk", +}; + +static const struct of_device_id imx8qxp_match[] = { + { .compatible = "fsl,scu-clk", }, + { .compatible = "fsl,imx8qxp-clk", &imx_clk_scu_rsrc_imx8qxp, }, + { .compatible = "fsl,imx8qm-clk", &imx_clk_scu_rsrc_imx8qm, }, + { /* sentinel */ } +}; static int imx8qxp_clk_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(imx8qxp_match, &pdev->dev); struct device_node *ccm_node = pdev->dev.of_node; - struct clk_hw_onecell_data *clk_data; - struct clk_hw **clks; - int ret, i; + int ret; - ret = imx_clk_scu_init(); + ret = imx_clk_scu_init(ccm_node, of_id->data); if (ret) return ret; - clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, - IMX_SCU_CLK_END), GFP_KERNEL); - if (!clk_data) - return -ENOMEM; - - clk_data->num = IMX_SCU_CLK_END; - clks = clk_data->hws; - - /* Fixed clocks */ - clks[IMX_CLK_DUMMY] = clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0); - clks[IMX_ADMA_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "dma_ipg_clk_root", NULL, 0, 120000000); - clks[IMX_CONN_AXI_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_axi_clk_root", NULL, 0, 333333333); - clks[IMX_CONN_AHB_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ahb_clk_root", NULL, 0, 166666666); - clks[IMX_CONN_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ipg_clk_root", NULL, 0, 83333333); - clks[IMX_DC_AXI_EXT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_ext_clk_root", NULL, 0, 800000000); - clks[IMX_DC_AXI_INT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_int_clk_root", NULL, 0, 400000000); - clks[IMX_DC_CFG_CLK] = clk_hw_register_fixed_rate(NULL, "dc_cfg_clk_root", NULL, 0, 100000000); - clks[IMX_MIPI_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "mipi_ipg_clk_root", NULL, 0, 120000000); - clks[IMX_IMG_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "img_axi_clk_root", NULL, 0, 400000000); - clks[IMX_IMG_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "img_ipg_clk_root", NULL, 0, 200000000); - clks[IMX_IMG_PXL_CLK] = clk_hw_register_fixed_rate(NULL, "img_pxl_clk_root", NULL, 0, 600000000); - clks[IMX_HSIO_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_axi_clk_root", NULL, 0, 400000000); - clks[IMX_HSIO_PER_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_per_clk_root", NULL, 0, 133333333); - clks[IMX_LSIO_MEM_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_mem_clk_root", NULL, 0, 200000000); - clks[IMX_LSIO_BUS_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000); - /* ARM core */ - clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU); + imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU); + imx_clk_scu("a53_clk", IMX_SC_R_A53, IMX_SC_PM_CLK_CPU); + imx_clk_scu("a72_clk", IMX_SC_R_A72, IMX_SC_PM_CLK_CPU); /* LSIO SS */ - clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER); - clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER); - - /* ADMA SS */ - clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER); - clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER); + imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER); + imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER); + imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER); + + /* DMA SS */ + imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER); + imx_clk_scu("uart4_clk", IMX_SC_R_UART_4, IMX_SC_PM_CLK_PER); + imx_clk_scu("sim0_clk", IMX_SC_R_EMVSIM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER); + imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("can1_clk", IMX_SC_R_CAN_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("can2_clk", IMX_SC_R_CAN_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER); + imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER); + + /* Audio SS */ + imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL); + imx_clk_scu("audio_pll1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_PLL); + imx_clk_scu("audio_pll_div_clk0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_MISC0); + imx_clk_scu("audio_pll_div_clk1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_MISC0); + imx_clk_scu("audio_rec_clk0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("audio_rec_clk1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_MISC1); /* Connectivity */ - clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS); - clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0); - clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS); - clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0); - clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS); - clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER); - clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS); - clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC); + imx_clk_scu2("sdhc0_clk", sdhc0_sels, ARRAY_SIZE(sdhc0_sels), IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER); + imx_clk_divider_gpr_scu("enet0_ref_div", "enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_C_CLKDIV); + imx_clk_mux_gpr_scu("enet0_rgmii_txc_sel", enet0_rgmii_txc_sels, ARRAY_SIZE(enet0_rgmii_txc_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK); + imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0); + imx_clk_gate_gpr_scu("enet0_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true); + imx_clk_scu("enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER); + imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV); + imx_clk_mux_gpr_scu("enet1_rgmii_txc_sel", enet1_rgmii_txc_sels, ARRAY_SIZE(enet1_rgmii_txc_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK); + imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0); + imx_clk_gate_gpr_scu("enet1_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true); + imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS); + imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER); + imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER); + imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS); + imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC); /* Display controller SS */ - clks[IMX_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); - clks[IMX_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); + imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); + imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS); + + imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0); + imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("dc1_pll0_clk", IMX_SC_R_DC_1_PLL_0, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc1_pll1_clk", IMX_SC_R_DC_1_PLL_1, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc1_bypass0_clk", IMX_SC_R_DC_1_VIDEO0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("dc1_bypass1_clk", IMX_SC_R_DC_1_VIDEO1, IMX_SC_PM_CLK_BYPASS); /* MIPI-LVDS SS */ - clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2); - clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("lvds0_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("lvds0_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("lvds0_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); + imx_clk_scu("mipi0_dsi_tx_esc_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS); + imx_clk_scu("mipi0_dsi_rx_esc_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS); + imx_clk_scu("mipi0_dsi_phy_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY); + imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi0_pwm_clk", IMX_SC_R_MIPI_0_PWM_0, IMX_SC_PM_CLK_PER); + + imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("lvds1_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("lvds1_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("lvds1_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); + imx_clk_scu("mipi1_dsi_tx_esc_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS); + imx_clk_scu("mipi1_dsi_rx_esc_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS); + imx_clk_scu("mipi1_dsi_phy_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PHY); + imx_clk_scu("mipi1_i2c0_clk", IMX_SC_R_MIPI_1_I2C_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi1_i2c1_clk", IMX_SC_R_MIPI_1_I2C_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi1_pwm_clk", IMX_SC_R_MIPI_1_PWM_0, IMX_SC_PM_CLK_PER); + + imx_clk_scu("lvds0_i2c0_clk", IMX_SC_R_LVDS_0_I2C_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("lvds0_pwm0_clk", IMX_SC_R_LVDS_0_PWM_0, IMX_SC_PM_CLK_PER); + + imx_clk_scu("lvds1_i2c0_clk", IMX_SC_R_LVDS_1_I2C_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("lvds1_pwm0_clk", IMX_SC_R_LVDS_1_PWM_0, IMX_SC_PM_CLK_PER); /* MIPI CSI SS */ - clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER); - clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC); - clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER); - clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC); + imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("mipi_csi1_core_clk", IMX_SC_R_CSI_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("mipi_csi1_esc_clk", IMX_SC_R_CSI_1, IMX_SC_PM_CLK_MISC); + imx_clk_scu("mipi_csi1_i2c0_clk", IMX_SC_R_CSI_1_I2C_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("mipi_csi1_pwm0_clk", IMX_SC_R_CSI_1_PWM_0, IMX_SC_PM_CLK_PER); + + /* Parallel Interface SS */ + imx_clk_scu("pi_dpll_clk", IMX_SC_R_PI_0_PLL, IMX_SC_PM_CLK_PLL); + imx_clk_scu2("pi_per_div_clk", pll0_sels, ARRAY_SIZE(pll0_sels), IMX_SC_R_PI_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("pi_mclk_div_clk", IMX_SC_R_PI_0, IMX_SC_PM_CLK_MISC0); /* GPU SS */ - clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER); - clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC); + imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER); + imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC); - for (i = 0; i < clk_data->num; i++) { - if (IS_ERR(clks[i])) - pr_warn("i.MX clk %u: register failed with %ld\n", - i, PTR_ERR(clks[i])); - } + imx_clk_scu("gpu_core1_clk", IMX_SC_R_GPU_1_PID0, IMX_SC_PM_CLK_PER); + imx_clk_scu("gpu_shader1_clk", IMX_SC_R_GPU_1_PID0, IMX_SC_PM_CLK_MISC); + /* CM40 SS */ + imx_clk_scu("cm40_i2c_div", IMX_SC_R_M4_0_I2C, IMX_SC_PM_CLK_PER); - return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data); -} + /* CM41 SS */ + imx_clk_scu("cm41_i2c_div", IMX_SC_R_M4_1_I2C, IMX_SC_PM_CLK_PER); -static const struct of_device_id imx8qxp_match[] = { - { .compatible = "fsl,scu-clk", }, - { .compatible = "fsl,imx8qxp-clk", }, - { /* sentinel */ } -}; + /* HDMI TX SS */ + imx_clk_scu("hdmi_dig_pll_clk", IMX_SC_R_HDMI_PLL_0, IMX_SC_PM_CLK_PLL); + imx_clk_scu("hdmi_av_pll_clk", IMX_SC_R_HDMI_PLL_1, IMX_SC_PM_CLK_PLL); + imx_clk_scu2("hdmi_pixel_mux_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC0); + imx_clk_scu2("hdmi_pixel_link_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("hdmi_ipg_clk", IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC4); + imx_clk_scu("hdmi_i2c0_clk", IMX_SC_R_HDMI_I2C_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("hdmi_hdp_core_clk", IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC2); + imx_clk_scu2("hdmi_pxl_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC3); + imx_clk_scu("hdmi_i2s_bypass_clk", IMX_SC_R_HDMI_I2S, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("hdmi_i2s_clk", IMX_SC_R_HDMI_I2S, IMX_SC_PM_CLK_MISC0); + + return of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks); +} static struct platform_driver imx8qxp_clk_driver = { .driver = { @@ -151,4 +256,8 @@ static struct platform_driver imx8qxp_clk_driver = { }, .probe = imx8qxp_clk_probe, }; -builtin_platform_driver(imx8qxp_clk_driver); +static int __init imx8qxp_clk_driver_init(void) +{ + return platform_driver_register(&imx8qxp_clk_driver); +} +subsys_initcall_sync(imx8qxp_clk_driver_init); diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index a73a799fb777..56b055e35db5 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -33,6 +33,9 @@ struct clk_lpcg_scu { void __iomem *reg; u8 bit_idx; bool hw_gate; + + /* for state save&restore */ + u32 state; }; #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) @@ -80,9 +83,9 @@ static const struct clk_ops clk_lpcg_scu_ops = { .disable = clk_lpcg_scu_disable, }; -struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, - unsigned long flags, void __iomem *reg, - u8 bit_idx, bool hw_gate) +struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, bool hw_gate) { struct clk_lpcg_scu *clk; struct clk_init_data init; @@ -106,11 +109,47 @@ struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, clk->hw.init = &init; hw = &clk->hw; - ret = clk_hw_register(NULL, hw); + ret = clk_hw_register(dev, hw); if (ret) { kfree(clk); hw = ERR_PTR(ret); } + if (dev) + dev_set_drvdata(dev, clk); + return hw; } + +int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) +{ + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + + if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg"))) + return 0; + + clk->state = readl_relaxed(clk->reg); + dev_dbg(dev, "save lpcg state 0x%x\n", clk->state); + + return 0; +} + +int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) +{ + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + + if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg"))) + return 0; + + /* FIXME: double write in case a failure */ + writel(clk->state, clk->reg); + writel(clk->state, clk->reg); + dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); + + return 0; +} + +const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend, + imx_clk_lpcg_scu_resume) +}; diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c index 50b7c30296f7..fc2e0fe03bdd 100644 --- a/drivers/clk/imx/clk-pfd.c +++ b/drivers/clk/imx/clk-pfd.c @@ -5,9 +5,11 @@ */ #include <linux/clk-provider.h> +#include <linux/imx_sema4.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/err.h> +#include <soc/imx/src.h> #include "clk.h" /** @@ -32,20 +34,57 @@ struct clk_pfd { #define CLR 0x8 #define OTG 0xc -static int clk_pfd_enable(struct clk_hw *hw) +static void clk_pfd_do_hardware(struct clk_pfd *pfd, bool enable) +{ + if (enable) + writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); + else + writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); +} + +static void clk_pfd_do_shared_clks(struct clk_hw *hw, bool enable) { struct clk_pfd *pfd = to_clk_pfd(hw); - writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); + if (imx_src_is_m4_enabled() && clk_on_imx6sx()) { +#ifdef CONFIG_SOC_IMX6SX + if (!amp_power_mutex || !shared_mem) { + if (enable) + clk_pfd_do_hardware(pfd, enable); + return; + } + + imx_sema4_mutex_lock(amp_power_mutex); + if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER || + shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) { + imx_sema4_mutex_unlock(amp_power_mutex); + return; + } + + if (!imx_update_shared_mem(hw, enable)) { + imx_sema4_mutex_unlock(amp_power_mutex); + return; + } + + clk_pfd_do_hardware(pfd, enable); + + imx_sema4_mutex_unlock(amp_power_mutex); +#endif + } else { + clk_pfd_do_hardware(pfd, enable); + } +} + +static int clk_pfd_enable(struct clk_hw *hw) +{ + clk_pfd_do_shared_clks(hw, true); return 0; } static void clk_pfd_disable(struct clk_hw *hw) { - struct clk_pfd *pfd = to_clk_pfd(hw); - - writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); + clk_pfd_do_shared_clks(hw, false); } static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw, diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c index a03bbed662c6..2a46b9b61b46 100644 --- a/drivers/clk/imx/clk-pfdv2.c +++ b/drivers/clk/imx/clk-pfdv2.c @@ -139,6 +139,12 @@ static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, u32 val; u8 frac; + if (!rate) + return -EINVAL; + + /* PFD can NOT change rate without gating */ + WARN_ON(clk_pfdv2_is_enabled(hw)); + tmp = tmp * 18 + rate / 2; do_div(tmp, rate); frac = tmp; diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 7a815ec76aa5..5660865baae0 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -92,9 +92,12 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1; short int kdiv; u64 fvco = parent_rate; + long rate = 0; + int i; pll_div_ctl0 = readl_relaxed(pll->base + 4); pll_div_ctl1 = readl_relaxed(pll->base + 8); @@ -103,13 +106,25 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw, sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT; kdiv = pll_div_ctl1 & KDIV_MASK; + /* + * Sometimes, the recalculated rate has deviation due to + * the frac part. So find the accurate pll rate from the table + * first, if no match rate in the table, use the rate calculated + * from the equation below. + */ + for (i = 0; i < pll->rate_count; i++) { + if (rate_table[i].pdiv == pdiv && rate_table[i].mdiv == mdiv && + rate_table[i].sdiv == sdiv && rate_table[i].kdiv == kdiv) + rate = rate_table[i].rate; + } + /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ fvco *= (mdiv * 65536 + kdiv); pdiv *= 65536; do_div(fvco, pdiv << sdiv); - return fvco; + return rate ? (unsigned long) rate : (unsigned long)fvco; } static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate, diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index df91a8244fb4..24684853c8b4 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -7,9 +7,11 @@ #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/imx_sema4.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/err.h> +#include <soc/imx/src.h> #include "clk.h" #define PLL_NUM_OFFSET 0x10 @@ -72,32 +74,74 @@ static int clk_pllv3_wait_lock(struct clk_pllv3 *pll) return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT; } -static int clk_pllv3_prepare(struct clk_hw *hw) +static int clk_pllv3_do_hardware(struct clk_hw *hw, bool enable) { struct clk_pllv3 *pll = to_clk_pllv3(hw); + int ret; u32 val; val = readl_relaxed(pll->base); - if (pll->powerup_set) - val |= pll->power_bit; - else - val &= ~pll->power_bit; - writel_relaxed(val, pll->base); + if (enable) { + if (pll->powerup_set) + val |= pll->power_bit; + else + val &= ~pll->power_bit; + writel_relaxed(val, pll->base); + + ret = clk_pllv3_wait_lock(pll); + if (ret) + return ret; + } else { + if (pll->powerup_set) + val &= ~pll->power_bit; + else + val |= pll->power_bit; + writel_relaxed(val, pll->base); + } - return clk_pllv3_wait_lock(pll); + return 0; } -static void clk_pllv3_unprepare(struct clk_hw *hw) +static void clk_pllv3_do_shared_clks(struct clk_hw *hw, bool enable) { - struct clk_pllv3 *pll = to_clk_pllv3(hw); - u32 val; + if (imx_src_is_m4_enabled() && clk_on_imx6sx()) { +#ifdef CONFIG_SOC_IMX6SX + if (!amp_power_mutex || !shared_mem) { + if (enable) + clk_pllv3_do_hardware(hw, enable); + return; + } + + imx_sema4_mutex_lock(amp_power_mutex); + if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER || + shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) { + imx_sema4_mutex_unlock(amp_power_mutex); + return; + } + + if (!imx_update_shared_mem(hw, enable)) { + imx_sema4_mutex_unlock(amp_power_mutex); + return; + } + clk_pllv3_do_hardware(hw, enable); + + imx_sema4_mutex_unlock(amp_power_mutex); +#endif + } else { + clk_pllv3_do_hardware(hw, enable); + } +} - val = readl_relaxed(pll->base); - if (pll->powerup_set) - val &= ~pll->power_bit; - else - val |= pll->power_bit; - writel_relaxed(val, pll->base); +static int clk_pllv3_prepare(struct clk_hw *hw) +{ + clk_pllv3_do_shared_clks(hw, true); + + return 0; +} + +static void clk_pllv3_unprepare(struct clk_hw *hw) +{ + clk_pllv3_do_shared_clks(hw, false); } static int clk_pllv3_is_prepared(struct clk_hw *hw) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index fbef740704d0..3334909a5f88 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -6,16 +6,42 @@ #include <dt-bindings/firmware/imx/rsrc.h> #include <linux/arm-smccc.h> +#include <linux/bsearch.h> #include <linux/clk-provider.h> #include <linux/err.h> +#include <linux/firmware/imx/svc/rm.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/syscalls.h> +#include <xen/xen.h> #include "clk-scu.h" #define IMX_SIP_CPUFREQ 0xC2000001 #define IMX_SIP_SET_CPUFREQ 0x00 +#define MAX_CLUSTER_NUM 2 static struct imx_sc_ipc *ccm_ipc_handle; +static const struct imx_clk_scu_rsrc_table *rsrc_table; +static struct delayed_work cpufreq_governor_daemon; +struct device_node *pd_np; +u32 clock_cells; + +struct imx_scu_clk_node { + const char *name; + u32 rsrc; + u8 clk_type; + const char * const *parents; + int num_parents; + + struct clk_hw *hw; + struct list_head node; +}; + +struct list_head imx_scu_clks[IMX_SC_R_LAST]; /* * struct clk_scu - Description of one SCU clock @@ -27,6 +53,26 @@ struct clk_scu { struct clk_hw hw; u16 rsrc_id; u8 clk_type; + + /* for state save&restore */ + struct clk_hw *parent; + u8 parent_index; + bool is_enabled; + u32 rate; +}; + +/* + * struct clk_gpr_scu - Description of one gate SCU clock + * @hw: the common clk_hw + * @rsrc_id: resource ID of this SCU clock + * @gpr_id: GPR ID index to control the divider + */ +struct clk_gpr_scu { + struct clk_hw hw; + u16 rsrc_id; + u8 gpr_id; + u8 flags; + bool gate_invert; }; /* @@ -54,6 +100,9 @@ struct resp_get_clock_rate { __le32 rate; }; +#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct clk_mux_gpr_scu, hw) +#define to_clk_gpr_scu(_hw) container_of(_hw, struct clk_gpr_scu, hw) + /* * struct imx_sc_msg_get_clock_rate - clock get rate protocol * @hdr: SCU protocol header @@ -128,9 +177,48 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw) return container_of(hw, struct clk_scu, hw); } -int imx_clk_scu_init(void) +static int imx_scu_clk_search_cmp(const void *rsrc, const void *rsrc_p) { - return imx_scu_get_handle(&ccm_ipc_handle); + return *(u32 *)rsrc - *(u32 *)rsrc_p; +} + +bool imx_scu_clk_is_valid(u32 rsrc_id) +{ + void *p; + + if (!rsrc_table) + return true; + + p = bsearch(&rsrc_id, rsrc_table->rsrc, rsrc_table->num, + sizeof(rsrc_table->rsrc[0]), imx_scu_clk_search_cmp); + return p != NULL; +} + +int imx_clk_scu_init(struct device_node *np, const void *data) +{ + struct platform_device *pd_dev; + int ret, i; + + ret = imx_scu_get_handle(&ccm_ipc_handle); + if (ret) + return ret; + + if (of_property_read_u32(np, "#clock-cells", &clock_cells)) + return -EINVAL; + + if (clock_cells == 2) { + for (i = 0; i < IMX_SC_R_LAST; i++) + INIT_LIST_HEAD(&imx_scu_clks[i]); + + pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd"); + pd_dev = of_find_device_by_node(pd_np); + if (!pd_dev || !device_is_bound(&pd_dev->dev)) + return -EPROBE_DEFER; + + rsrc_table = data; + } + + return 0; } /* @@ -192,8 +280,10 @@ static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate, struct arm_smccc_res res; unsigned long cluster_id; - if (clk->rsrc_id == IMX_SC_R_A35) + if (clk->rsrc_id == IMX_SC_R_A35 || clk->rsrc_id == IMX_SC_R_A53) cluster_id = 0; + else if (clk->rsrc_id == IMX_SC_R_A72) + cluster_id = 1; else return -EINVAL; @@ -254,6 +344,8 @@ static u8 clk_scu_get_parent(struct clk_hw *hw) return 0; } + clk->parent_index = msg.data.resp.parent; + return msg.data.resp.parent; } @@ -262,6 +354,7 @@ static int clk_scu_set_parent(struct clk_hw *hw, u8 index) struct clk_scu *clk = to_clk_scu(hw); struct imx_sc_msg_set_clock_parent msg; struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; hdr->ver = IMX_SC_RPC_VERSION; hdr->svc = IMX_SC_RPC_SVC_PM; @@ -272,7 +365,16 @@ static int clk_scu_set_parent(struct clk_hw *hw, u8 index) msg.clk = clk->clk_type; msg.parent = index; - return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); + ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true); + if (ret) { + pr_err("%s: failed to set clock parent %d\n", + clk_hw_get_name(hw), ret); + return ret; + } + + clk->parent_index = index; + + return 0; } static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource, @@ -344,8 +446,15 @@ static const struct clk_ops clk_scu_cpu_ops = { .unprepare = clk_scu_unprepare, }; -struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, - int num_parents, u32 rsrc_id, u8 clk_type) +static const struct clk_ops clk_scu_pi_ops = { + .recalc_rate = clk_scu_recalc_rate, + .round_rate = clk_scu_round_rate, + .set_rate = clk_scu_set_rate, +}; + +struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, + const char * const *parents, int num_parents, + u32 rsrc_id, u8 clk_type) { struct clk_init_data init; struct clk_scu *clk; @@ -361,8 +470,10 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, init.name = name; init.ops = &clk_scu_ops; - if (rsrc_id == IMX_SC_R_A35) + if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 || rsrc_id == IMX_SC_R_A72) init.ops = &clk_scu_cpu_ops; + else if (rsrc_id == IMX_SC_R_PI_0_PLL) + init.ops = &clk_scu_pi_ops; else init.ops = &clk_scu_ops; init.parent_names = parents; @@ -375,15 +486,468 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, * clock status from HW instead of using the possible invalid * cached rate. */ - init.flags = CLK_GET_RATE_NOCACHE; + init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_PARENT_NOCACHE; + clk->hw.init = &init; + + hw = &clk->hw; + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(clk); + hw = ERR_PTR(ret); + } + + if (dev) + dev_set_drvdata(dev, clk); + + return hw; +} + +struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec, + void *data) +{ + unsigned int rsrc = clkspec->args[0]; + unsigned int idx = clkspec->args[1]; + struct list_head *scu_clks = data; + struct imx_scu_clk_node *clk; + + list_for_each_entry(clk, &scu_clks[rsrc], node) { + if (clk->clk_type == idx) + return clk->hw; + } + + return ERR_PTR(-ENODEV); +} + +static int imx_clk_scu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx_scu_clk_node *clk = dev_get_platdata(dev); + struct clk_hw *hw; + int ret; + + pm_runtime_set_suspended(dev); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(dev); + + ret = pm_runtime_get_sync(dev); + if (ret) { + pm_genpd_remove_device(dev); + pm_runtime_disable(dev); + return ret; + } + + hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents, + clk->rsrc, clk->clk_type); + if (IS_ERR(hw)) { + pm_runtime_disable(dev); + return PTR_ERR(hw); + } + + clk->hw = hw; + list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]); + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc, + clk->clk_type); + + return 0; +} + +int __maybe_unused imx_clk_scu_suspend(struct device *dev) +{ + struct clk_scu *clk = dev_get_drvdata(dev); + u32 rsrc_id = clk->rsrc_id; + + if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) || + (rsrc_id == IMX_SC_R_A72)) + return 0; + + clk->parent = clk_hw_get_parent(&clk->hw); + + /* DC SS needs to handle bypass clock using non-cached clock rate */ + if (clk->rsrc_id == IMX_SC_R_DC_0_VIDEO0 || + clk->rsrc_id == IMX_SC_R_DC_0_VIDEO1 || + clk->rsrc_id == IMX_SC_R_DC_1_VIDEO0 || + clk->rsrc_id == IMX_SC_R_DC_1_VIDEO1) + clk->rate = clk_scu_recalc_rate(&clk->hw, 0); + else + clk->rate = clk_hw_get_rate(&clk->hw); + + clk->is_enabled = clk_hw_is_enabled(&clk->hw); + + if (clk->parent) + dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent), + clk->parent_index); + + if (clk->rate) + dev_dbg(dev, "save rate %d\n", clk->rate); + + if (clk->is_enabled) + dev_dbg(dev, "save enabled state\n"); + + return 0; +} + +int __maybe_unused imx_clk_scu_resume(struct device *dev) +{ + struct clk_scu *clk = dev_get_drvdata(dev); + u32 rsrc_id = clk->rsrc_id; + int ret = 0; + + if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) || + (rsrc_id == IMX_SC_R_A72)) + return 0; + + if (clk->parent) { + ret = clk_scu_set_parent(&clk->hw, clk->parent_index); + dev_dbg(dev, "restore parent %s idx %u %s\n", + clk_hw_get_name(clk->parent), + clk->parent_index, !ret ? "success" : "failed"); + } + + if (clk->rate) { + ret = clk_scu_set_rate(&clk->hw, clk->rate, 0); + dev_dbg(dev, "restore rate %d %s\n", clk->rate, + !ret ? "success" : "failed"); + } + + if (clk->is_enabled && rsrc_id != IMX_SC_R_PI_0_PLL) { + ret = clk_scu_prepare(&clk->hw); + dev_dbg(dev, "restore enabled state %s\n", + !ret ? "success" : "failed"); + } + + return ret; +} + +const struct dev_pm_ops imx_clk_scu_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_scu_suspend, + imx_clk_scu_resume) +}; + +static struct platform_driver imx_clk_scu_driver = { + .driver = { + .name = "imx-scu-clk", + .suppress_bind_attrs = true, + .pm = &imx_clk_scu_pm_ops, + }, + .probe = imx_clk_scu_probe, +}; + +static int __init imx_clk_scu_driver_init(void) +{ + return platform_driver_register(&imx_clk_scu_driver); +} +subsys_initcall_sync(imx_clk_scu_driver_init); + +static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id) +{ + struct of_phandle_args genpdspec = { + .np = pd_np, + .args_count = 1, + .args[0] = rsrc_id, + }; + + if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) || + (rsrc_id == IMX_SC_R_A72)) + return 0; + + return of_genpd_add_device(&genpdspec, dev); +} + +static bool imx_clk_is_resource_owned(u32 rsrc) +{ + /* + * A-core resources are special. SCFW reports they are not "owned" by + * current partition but linux can still adjust them for cpufreq. + * + * So force this to return false when running as a VM guest and always + * true otherwise. + */ + if (rsrc == IMX_SC_R_A53 || rsrc == IMX_SC_R_A72 || + rsrc == IMX_SC_R_A35) { + if (xen_domain() && !xen_initial_domain()) + return false; + return true; + } + + return imx_sc_rm_is_resource_owned(ccm_ipc_handle, rsrc); +} + +struct clk_hw *imx_clk_scu_alloc_dev(const char *name, + const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type) +{ + struct imx_scu_clk_node clk = { + .name = name, + .rsrc = rsrc_id, + .clk_type = clk_type, + .parents = parents, + .num_parents = num_parents, + }; + struct platform_device *pdev; + int ret; + + if (!imx_scu_clk_is_valid(rsrc_id)) + return NULL; + + if (!imx_clk_is_resource_owned(rsrc_id)) + return NULL; + + pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); + if (!pdev) { + pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n", + name, rsrc_id, clk_type); + return ERR_PTR(-ENOMEM); + } + + ret = platform_device_add_data(pdev, &clk, sizeof(clk)); + if (ret) { + platform_device_put(pdev); + return ERR_PTR(-ENOMEM); + } + + pdev->driver_override = "imx-scu-clk"; + + ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id); + if (ret) + pr_warn("%s: failed to attached the power domain %d\n", + name, ret); + + platform_device_add(pdev); + + /* For API backwards compatiblilty, simply return NULL for success */ + return NULL; +} + +static unsigned long clk_gpr_div_scu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_gpr_scu *clk = to_clk_gpr_scu(hw); + unsigned long rate = 0; + u32 val; + int err; + + err = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, &val); + + rate = val ? parent_rate / 2 : parent_rate; + + return err ? 0 : rate; +} + +static long clk_gpr_div_scu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + if (rate < *prate) + rate = *prate / 2; + else + rate = *prate; + + return rate; +} + +static int clk_gpr_div_scu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_gpr_scu *clk = to_clk_gpr_scu(hw); + uint32_t val; + int err; + + val = (rate < parent_rate) ? 1 : 0; + err = imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, val); + + return err ? -EINVAL : 0; +} + +static const struct clk_ops clk_gpr_div_scu_ops = { + .recalc_rate = clk_gpr_div_scu_recalc_rate, + .round_rate = clk_gpr_div_scu_round_rate, + .set_rate = clk_gpr_div_scu_set_rate, +}; + +static u8 clk_gpr_mux_scu_get_parent(struct clk_hw *hw) +{ + struct clk_gpr_scu *clk= to_clk_gpr_scu(hw); + u32 val = 0; + + imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, &val); + + return (u8)val; +} + +static int clk_gpr_mux_scu_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_gpr_scu *clk= to_clk_gpr_scu(hw); + + imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, index); + + return 0; +} + +static const struct clk_ops clk_gpr_mux_scu_ops = { + .get_parent = clk_gpr_mux_scu_get_parent, + .set_parent = clk_gpr_mux_scu_set_parent, +}; + +static int clk_gpr_gate_scu_prepare(struct clk_hw *hw) +{ + struct clk_gpr_scu *clk = to_clk_gpr_scu(hw); + + return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, !clk->gate_invert); +} + +static void clk_gpr_gate_scu_unprepare(struct clk_hw *hw) +{ + struct clk_gpr_scu *clk = to_clk_gpr_scu(hw); + int ret; + + ret = imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, clk->gate_invert); + if (ret) + pr_err("%s: clk unprepare failed %d\n", clk_hw_get_name(hw), + ret); +} + +static int clk_gpr_gate_scu_is_prepared(struct clk_hw *hw) +{ + struct clk_gpr_scu *clk= to_clk_gpr_scu(hw); + int ret; + u32 val; + + ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id, + clk->gpr_id, &val); + if (ret) + return ret; + + return clk->gate_invert ? !val : val; +} + +static struct clk_ops clk_gpr_gate_scu_ops = { + .prepare = clk_gpr_gate_scu_prepare, + .unprepare = clk_gpr_gate_scu_unprepare, + .is_prepared = clk_gpr_gate_scu_is_prepared, +}; + +struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_name, + int num_parents, u32 rsrc_id, u8 gpr_id, u8 flags, + bool invert) +{ + struct imx_scu_clk_node *clk_node; + struct clk_gpr_scu *clk; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + if (rsrc_id >= IMX_SC_R_LAST) + return NULL; + + if (gpr_id >= IMX_SC_C_LAST) + return NULL; + + if (!imx_scu_clk_is_valid(rsrc_id)) + return ERR_PTR(-EINVAL); + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + clk_node = kzalloc(sizeof(*clk_node), GFP_KERNEL); + if (!clk_node) { + kfree(clk); + return ERR_PTR(-ENOMEM); + }; + + /* struct clk_gate_scu assignments */ + clk->rsrc_id = rsrc_id; + clk->gpr_id = gpr_id; + clk->flags = flags; + clk->gate_invert = invert; + + if (flags & IMX_SCU_GPR_CLK_GATE) + init.ops = &clk_gpr_gate_scu_ops; + + if (flags & IMX_SCU_GPR_CLK_DIV) + init.ops = &clk_gpr_div_scu_ops; + + if (flags & IMX_SCU_GPR_CLK_MUX) + init.ops = &clk_gpr_mux_scu_ops; + + init.flags = 0; + init.name = name; + init.parent_names = parent_name; + init.num_parents = num_parents; + clk->hw.init = &init; hw = &clk->hw; ret = clk_hw_register(NULL, hw); if (ret) { kfree(clk); + kfree(clk_node); hw = ERR_PTR(ret); + } else { + clk_node->hw = hw; + clk_node->clk_type = gpr_id; + list_add_tail(&clk_node->node, &imx_scu_clks[rsrc_id]); } return hw; } + +static void cpufreq_governor_daemon_handler(struct work_struct *work) +{ + int fd, i; + unsigned char cluster_governor[MAX_CLUSTER_NUM][54] = { + "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", + "", + }; + + /* generate second cluster's cpufreq governor path */ + sprintf(cluster_governor[MAX_CLUSTER_NUM - 1], + "%s%d%s", "/sys/devices/system/cpu/cpu", num_online_cpus() - 1, + "/cpufreq/scaling_governor"); + + for (i = 0; i < MAX_CLUSTER_NUM; i++) { + fd = ksys_open((const char __user __force *)cluster_governor[i], + O_RDWR, 0700); + if (fd >= 0) { + ksys_write(fd, "schedutil", strlen("schedutil")); + ksys_close(fd); + pr_info("switch cluster %d cpu-freq governor to schedutil\n", + i); + } else { + /* re-schedule if sys write is NOT ready */ + schedule_delayed_work(&cpufreq_governor_daemon, + msecs_to_jiffies(3000)); + break; + } + } +} + +static int __init imx_scu_switch_cpufreq_governor(void) +{ + int i; + + INIT_DELAYED_WORK(&cpufreq_governor_daemon, + cpufreq_governor_daemon_handler); + + for (i = 1; i < num_online_cpus(); i++) { + if (topology_physical_package_id(i) == topology_physical_package_id(0)) + continue; + + schedule_delayed_work(&cpufreq_governor_daemon, + msecs_to_jiffies(3000)); + break; + } + + return 0; +} +late_initcall(imx_scu_switch_cpufreq_governor); diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index 2bcfaf06a458..ff60767c6251 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -8,25 +8,94 @@ #define __IMX_CLK_SCU_H #include <linux/firmware/imx/sci.h> +#include <linux/of.h> -int imx_clk_scu_init(void); +#define IMX_SCU_GPR_CLK_GATE BIT(0) +#define IMX_SCU_GPR_CLK_DIV BIT(1) +#define IMX_SCU_GPR_CLK_MUX BIT(2) -struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, - int num_parents, u32 rsrc_id, u8 clk_type); +struct imx_clk_scu_rsrc_table { + const u32 *rsrc; + u8 num; +}; + +extern u32 clock_cells; +extern struct list_head imx_scu_clks[]; +extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops; +extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp; +extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm; + +int imx_clk_scu_init(struct device_node *np, const void *data); +struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec, + void *data); +struct clk_hw *imx_clk_scu_alloc_dev(const char *name, + const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type); + +struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, + const char * const *parents, int num_parents, + u32 rsrc_id, u8 clk_type); + +struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, bool hw_gate); + +struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_name, + int num_parents, u32 rsrc_id, u8 gpr_id, u8 flags, + bool invert); static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type) { - return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type); + if (clock_cells == 2) + return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type); + else + return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type); } static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents, int num_parents, u32 rsrc_id, u8 clk_type) { - return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type); + if (clock_cells == 2) + return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type); + else + return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type); } -struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, - unsigned long flags, void __iomem *reg, - u8 bit_idx, bool hw_gate); +static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, bool hw_gate) +{ + return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg, + bit_idx, hw_gate); +} + +static inline struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, + u8 bit_idx, bool hw_gate) +{ + return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg, + bit_idx, hw_gate); +} + +static inline struct clk_hw *imx_clk_gate_gpr_scu(const char *name, const char *parent_name, + u32 rsrc_id, u8 gpr_id, bool invert) +{ + return __imx_clk_gpr_scu(name, &parent_name, 1, rsrc_id, gpr_id, + IMX_SCU_GPR_CLK_GATE, invert); +} + +static inline struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name, + u32 rsrc_id, u8 gpr_id) +{ + return __imx_clk_gpr_scu(name, &parent_name, 1, rsrc_id, gpr_id, + IMX_SCU_GPR_CLK_DIV, 0); +} + +static inline struct clk_hw *imx_clk_mux_gpr_scu(const char *name, const char * const *parent_names, + int num_parents, u32 rsrc_id, u8 gpr_id) +{ + return __imx_clk_gpr_scu(name, parent_names, num_parents, rsrc_id, + gpr_id, IMX_SCU_GPR_CLK_MUX, 0); +} #endif diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index cfc05e43c343..6c0029950d38 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -14,6 +14,8 @@ DEFINE_SPINLOCK(imx_ccm_lock); +bool uart_from_osc; + void imx_unregister_clocks(struct clk *clks[], unsigned int count) { unsigned int i; @@ -133,7 +135,7 @@ void imx_cscmr1_fixup(u32 *val) } static int imx_keep_uart_clocks; -static struct clk ** const *imx_uart_clocks; +static bool imx_uart_clks_on; static int __init imx_keep_uart_clocks_param(char *str) { @@ -146,26 +148,49 @@ __setup_param("earlycon", imx_keep_uart_earlycon, __setup_param("earlyprintk", imx_keep_uart_earlyprintk, imx_keep_uart_clocks_param, 0); -void imx_register_uart_clocks(struct clk ** const clks[]) +static void imx_earlycon_uart_clks_onoff(bool is_on) { - if (imx_keep_uart_clocks) { - int i; + struct clk *uart_clk; + int i = 0; - imx_uart_clocks = clks; - for (i = 0; imx_uart_clocks[i]; i++) - clk_prepare_enable(*imx_uart_clocks[i]); - } + if (!imx_keep_uart_clocks || (!is_on && !imx_uart_clks_on)) + return; + + /* only support dt */ + if (!of_stdout) + return; + + do { + uart_clk = of_clk_get(of_stdout, i++); + if (IS_ERR(uart_clk)) + break; + + if (is_on) + clk_prepare_enable(uart_clk); + else + clk_disable_unprepare(uart_clk); + } while (true); + + if (is_on) + imx_uart_clks_on = true; } -static int __init imx_clk_disable_uart(void) +void imx_register_uart_clocks(void) { - if (imx_keep_uart_clocks && imx_uart_clocks) { - int i; + imx_earlycon_uart_clks_onoff(true); +} - for (i = 0; imx_uart_clocks[i]; i++) - clk_disable_unprepare(*imx_uart_clocks[i]); - } +static int __init imx_clk_disable_uart(void) +{ + imx_earlycon_uart_clks_onoff(false); return 0; } late_initcall_sync(imx_clk_disable_uart); + +static int __init setup_uart_clk(char *uart_rate) +{ + uart_from_osc = true; + return 1; +} +__setup("uart_from_osc", setup_uart_clk); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index f7a389a50401..362cb9e60699 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -4,16 +4,20 @@ #include <linux/spinlock.h> #include <linux/clk-provider.h> +#include <soc/imx/src.h> extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); -void imx_register_uart_clocks(struct clk ** const clks[]); +void imx_register_uart_clocks(void); void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn); void imx_unregister_clocks(struct clk *clks[], unsigned int count); extern void imx_cscmr1_fixup(u32 *val); +extern struct imx_sema4_mutex *amp_power_mutex; +extern struct imx_shared_mem *shared_mem; +extern bool uart_from_osc; enum imx_pllv1_type { IMX_PLLV1_IMX1, @@ -126,6 +130,25 @@ enum imx_pllv3_type { IMX_PLLV3_AV_IMX7, }; +#define MAX_SHARED_CLK_NUMBER 100 +#define SHARED_MEM_MAGIC_NUMBER 0x12345678 +#define MCC_POWER_SHMEM_NUMBER (6) + +struct imx_shared_clk { + struct clk *self; + struct clk *parent; + void *m4_clk; + void *m4_clk_parent; + u8 ca9_enabled; + u8 cm4_enabled; +}; + +struct imx_shared_mem { + u32 ca9_valid; + u32 cm4_valid; + struct imx_shared_clk imx_clk[MAX_SHARED_CLK_NUMBER]; +}; + struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, const char *parent_name, void __iomem *base, u32 div_mask); @@ -181,6 +204,13 @@ struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift u8 width, void __iomem *busy_reg, u8 busy_shift, const char * const *parent_names, int num_parents); +int imx_update_shared_mem(struct clk_hw *hw, bool enable); + +static inline int clk_on_imx6sx(void) +{ + return of_machine_is_compatible("fsl,imx6sx"); +} + struct clk_hw *imx7ulp_clk_composite(const char *name, const char * const *parent_names, int num_parents, bool mux_present, @@ -347,7 +377,17 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name, static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent, void __iomem *reg, u8 shift) { - return clk_hw_register_gate(NULL, name, parent, + /* + * per design team's suggestion, clk root is NOT consuming + * much power, and clk root enable/disable does NOT have domain + * control, so they suggest to leave clk root always on when + * M4 is enabled. + */ + if (imx_src_is_m4_enabled()) + return clk_hw_register_fixed_factor(NULL, name, parent, + CLK_SET_RATE_PARENT, 1, 1); + else + return clk_hw_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, reg, shift, 0, &imx_ccm_lock); } diff --git a/drivers/clk/s32/Kconfig b/drivers/clk/s32/Kconfig new file mode 100644 index 000000000000..c28bdbbfaa3a --- /dev/null +++ b/drivers/clk/s32/Kconfig @@ -0,0 +1,4 @@ +config ARCH_S32_CLK + bool "Enable S32 CLK Framework" + help + Support for the Clock Framework on S32 SoCs. diff --git a/drivers/clk/s32/Makefile b/drivers/clk/s32/Makefile new file mode 100644 index 000000000000..169b8b5900f9 --- /dev/null +++ b/drivers/clk/s32/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARCH_S32_CLK) += clk-core.o +obj-$(CONFIG_ARCH_S32_CLK) += s32v234/ diff --git a/drivers/clk/s32/clk-core.c b/drivers/clk/s32/clk-core.c new file mode 100644 index 000000000000..a8cca66f7959 --- /dev/null +++ b/drivers/clk/s32/clk-core.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include "clk.h" + +void __init s32_check_clocks(struct clk *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("S32 clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + +static struct clk * __init s32_obtain_fixed_clock_from_dt(const char *name) +{ + struct of_phandle_args phandle; + struct clk *clk = ERR_PTR(-ENODEV); + char *path; + + path = kasprintf(GFP_KERNEL, "/clocks/%s", name); + if (!path) + return ERR_PTR(-ENOMEM); + + phandle.np = of_find_node_by_path(path); + kfree(path); + + if (phandle.np) { + clk = of_clk_get_from_provider(&phandle); + of_node_put(phandle.np); + } + return clk; +} + +struct clk * __init s32_obtain_fixed_clock( + const char *name, unsigned long rate) +{ + struct clk *clk; + + clk = s32_obtain_fixed_clock_from_dt(name); + if (IS_ERR(clk)) + clk = s32_clk_fixed(name, rate); + return clk; +} diff --git a/drivers/clk/s32/clk.h b/drivers/clk/s32/clk.h new file mode 100644 index 000000000000..83100641158f --- /dev/null +++ b/drivers/clk/s32/clk.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + */ + +#ifndef __MACH_S32_CLK_H +#define __MACH_S32_CLK_H + +#include <linux/spinlock.h> +#include <linux/clk-provider.h> + +#define PNAME(x) \ + static const char *x[] __initconst + +void s32_check_clocks(struct clk *clks[], unsigned int count); + +struct clk *s32_obtain_fixed_clock( + const char *name, unsigned long rate); + +static inline struct clk *s32_clk_fixed(const char *name, unsigned long rate) +{ + return clk_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk *s32_clk_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + spinlock_t *lock) +{ + struct clk *tmp_clk = clk_register_divider(NULL, name, parent, + CLK_SET_RATE_PARENT, + reg, shift, width, 0, lock); + + return tmp_clk; +} + +static inline struct clk *s32_clk_mux(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, + u8 num_parents, spinlock_t *lock) +{ + return clk_register_mux(NULL, name, parents, num_parents, + CLK_SET_RATE_NO_REPARENT, reg, shift, + width, 0, lock); +} + +static inline struct clk *s32_clk_fixed_factor(const char *name, + const char *parent, + unsigned int mult, + unsigned int div) +{ + return clk_register_fixed_factor(NULL, name, parent, + CLK_SET_RATE_PARENT, mult, div); +} + +#endif diff --git a/drivers/clk/s32/s32v234/Makefile b/drivers/clk/s32/s32v234/Makefile new file mode 100644 index 000000000000..7ddf9f4b5d81 --- /dev/null +++ b/drivers/clk/s32/s32v234/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_S32_CLK) += clk.o clk-plldig.o clk-dfs.o diff --git a/drivers/clk/s32/s32v234/clk-dfs.c b/drivers/clk/s32/s32v234/clk-dfs.c new file mode 100644 index 000000000000..2bd569e13a18 --- /dev/null +++ b/drivers/clk/s32/s32v234/clk-dfs.c @@ -0,0 +1,236 @@ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include "clk.h" + +/** + * struct clk_dfs - S32 DFS clock + * @clk_hw: clock source + * @reg: DFS register address + * @idx: the index of DFS encoded in the register + * + * DFS clock found on S32 series. Each register for DFS has 4 clk_dfs + * data encoded, and member idx is used to specify the one. + * Only ARMPLL(3 DFS), ENETPLL(4 DFS) and DDRPLL(3 DFS) has DFS outputs. + */ +struct clk_dfs { + struct clk_hw hw; + void __iomem *reg; + enum s32v234_plldig_type plltype; + u8 idx; + u32 mfn; +}; + +#define to_clk_dfs(_hw) container_of(_hw, struct clk_dfs, hw) + +static int get_pllx_dfs_nr(enum s32v234_plldig_type plltype) +{ + switch (plltype) { + case S32_PLLDIG_ARM: + return ARMPLL_DFS_NR; + case S32_PLLDIG_ENET: + return ENETPLL_DFS_NR; + case S32_PLLDIG_DDR: + return DDRPLL_DFS_NR; + case S32_PLLDIG_PERIPH: + case S32_PLLDIG_VIDEO: + pr_warn("Current selected PLL has no DFS\n"); + break; + } + + return -EINVAL; +} +static unsigned long get_pllx_dfsy_max_rate(enum s32v234_plldig_type plltype, + int dfsno) +{ + switch (plltype) { + case S32_PLLDIG_ARM: + switch (dfsno) { + case 0: + return ARMPLL_DFS0_MAX_RATE; + case 1: + return ARMPLL_DFS1_MAX_RATE; + case 2: + return ARMPLL_DFS2_MAX_RATE; + } + break; + case S32_PLLDIG_ENET: + switch (dfsno) { + case 0: + return ENETPLL_DFS0_MAX_RATE; + case 1: + return ENETPLL_DFS1_MAX_RATE; + case 2: + return ENETPLL_DFS2_MAX_RATE; + case 3: + return ENETPLL_DFS3_MAX_RATE; + } + break; + case S32_PLLDIG_DDR: + switch (dfsno) { + case 0: + return DDRPLL_DFS0_MAX_RATE; + case 1: + return DDRPLL_DFS1_MAX_RATE; + case 2: + return DDRPLL_DFS2_MAX_RATE; + } + break; + case S32_PLLDIG_PERIPH: + case S32_PLLDIG_VIDEO: + pr_warn("Current selected PLL has no DFS."); + break; + default: + pr_warn("Unsupported PLL. Use %d or %d\n", + S32_PLLDIG_ARM, S32_PLLDIG_VIDEO); + break; + } + + return -EINVAL; +} +static int clk_dfs_enable(struct clk_hw *hw) +{ + /* + * TODO: When SOC is available, this function + * should be tested and implemented for DFS + * if it is possible + */ + return 0; +} + +static void clk_dfs_disable(struct clk_hw *hw) +{ + /* + * TODO: When SOC is available, this function + * should be tested and implemented for DFS + * if it is possible + */ +} + +static unsigned long clk_dfs_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_dfs *dfs = to_clk_dfs(hw); + u32 mfn, mfi, rate; + u32 dvport = readl_relaxed(DFS_DVPORTn(dfs->reg, dfs->idx)); + + mfn = (dvport & DFS_DVPORTn_MFN_MASK) >> DFS_DVPORTn_MFN_OFFSET; + mfi = (dvport & DFS_DVPORTn_MFI_MASK) >> DFS_DVPORTn_MFI_OFFSET; + mfi <<= 8; + rate = parent_rate / (mfi + mfn); + rate <<= 8; + + return rate; +} + +static long clk_dfs_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_dfs *dfs = to_clk_dfs(hw); + unsigned long max_allowed_rate; + + max_allowed_rate = get_pllx_dfsy_max_rate(dfs->plltype, dfs->idx); + + if (rate > max_allowed_rate) + rate = max_allowed_rate; + + return rate; +} + +static int clk_dfs_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_dfs *dfs = to_clk_dfs(hw); + u32 mfi; + u32 portreset = readl_relaxed(DFS_PORTRESET(dfs->reg)); + + writel_relaxed(DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg)); + writel_relaxed(portreset | ~DFS_PORTRESET_PORTRESET_SET(dfs->idx), + DFS_PORTRESET(dfs->reg)); + + mfi = parent_rate/rate; + writel_relaxed(DFS_DVPORTn_MFI_SET(mfi) | + DFS_DVPORTn_MFN_SET(dfs->mfn), + DFS_DVPORTn(dfs->reg, dfs->idx)); + + writel_relaxed(~DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg)); + + while (readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx))) + ; + + return 0; +} + +static int clk_dfs_is_enabled(struct clk_hw *hw) +{ + struct clk_dfs *dfs = to_clk_dfs(hw); + + /* Check if current DFS output port is locked */ + if (readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx))) + return 0; + + return 1; +} + +static const struct clk_ops clk_dfs_ops = { + .enable = clk_dfs_enable, + .disable = clk_dfs_disable, + .recalc_rate = clk_dfs_recalc_rate, + .round_rate = clk_dfs_round_rate, + .set_rate = clk_dfs_set_rate, + .is_enabled = clk_dfs_is_enabled, +}; + +struct clk *s32v234_clk_dfs(enum s32v234_plldig_type type, const char *name, + const char *parent_name, void __iomem *reg, + u8 idx, u32 mfn) +{ + struct clk_dfs *dfs; + struct clk *clk; + struct clk_init_data init; + + /* PERIPH and VIDEO PLL do not have DFS */ + if (type == S32_PLLDIG_PERIPH || type == S32_PLLDIG_VIDEO) + return ERR_PTR(-EINVAL); + + /* check if DFS index is valid for current pll */ + if (idx >= get_pllx_dfs_nr(type)) + return ERR_PTR(-EINVAL); + + dfs = kzalloc(sizeof(*dfs), GFP_KERNEL); + if (!dfs) + return ERR_PTR(-ENOMEM); + + dfs->reg = reg; + dfs->idx = idx; + dfs->mfn = mfn; + dfs->plltype = type; + + init.name = name; + init.ops = &clk_dfs_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + dfs->hw.init = &init; + + clk = clk_register(NULL, &dfs->hw); + if (IS_ERR(clk)) + kfree(dfs); + + return clk; +} diff --git a/drivers/clk/s32/s32v234/clk-plldig.c b/drivers/clk/s32/s32v234/clk-plldig.c new file mode 100644 index 000000000000..6ed23974ee63 --- /dev/null +++ b/drivers/clk/s32/s32v234/clk-plldig.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/err.h> +#include "clk.h" + +/* + * struct clk_plldig - S32 PLLDIG clock + * @clk_hw: clock source + * @base: base address of PLL registers + * @plldv_mfd: multiplication loop factor divider + * @plldv_rfdphi: PHI reduced frequency divider + * @plldv_rfdphi1: PHI reduced frequency divider + * + * PLLDIG clock version 1, found on S32 series. + */ +struct clk_plldig { + struct clk_hw hw; + void __iomem *base; + enum s32v234_plldig_type type; + u32 plldv_mfd; + u32 pllfd_mfn; + u32 plldv_rfdphi; + u32 plldv_rfdphi1; +}; + +#define to_clk_plldig(_hw) container_of(_hw, struct clk_plldig, hw) + +static unsigned long get_pllx_max_vco_rate(enum s32v234_plldig_type plltype) +{ + switch (plltype) { + case S32_PLLDIG_PERIPH: + return PERIPHPLL_MAX_VCO_RATE; + default: + pr_warn("Unsupported PLL.\n"); + return -EINVAL; + } +} + +static unsigned long get_pllx_phiy_max_rate(enum s32v234_plldig_type plltype, + unsigned int phino) +{ + switch (plltype) { + case S32_PLLDIG_PERIPH: + switch (phino) { + case 0: + return PERIPHPLL_MAX_PHI0_MAX_RATE; + case 1: + return PERIPHPLL_MAX_PHI1_MAX_RATE; + default: + break; + } + break; + default: + pr_warn("Unsupported PLL.\n"); + break; + } + return -EINVAL; +} + +static int clk_plldig_prepare(struct clk_hw *hw) +{ + return 0; +} + +static void clk_plldig_unprepare(struct clk_hw *hw) +{ +} + +static unsigned long clk_plldig_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_plldig *pll = to_clk_plldig(hw); + u32 plldv = readl_relaxed(PLLDIG_PLLDV(pll->base)); + u32 pllfd = readl_relaxed(PLLDIG_PLLFD(pll->base)); + u32 prediv, mfd, mfn, vco; + + prediv = (plldv & PLLDIG_PLLDV_PREDIV_MASK) + >> PLLDIG_PLLDV_PREDIV_OFFSET; + mfd = (plldv & PLLDIG_PLLDV_MFD_MASK); + + mfn = (pllfd & PLLDIG_PLLFD_MFN_MASK); + + if (prediv == 0) + prediv = 1; + + /* + * This formula is from platform reference manual + * (Rev. 1, 6/2015), PLLDIG chapter. + */ + vco = (parent_rate / prediv) * (mfd + mfn / 20480); + + return vco; +} + +static long clk_plldig_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_plldig *pll = to_clk_plldig(hw); + unsigned long max_allowed_rate = get_pllx_max_vco_rate(pll->type); + + if (rate > max_allowed_rate) + rate = max_allowed_rate; + else if (rate < MIN_VCO_RATE) + rate = MIN_VCO_RATE; + + return rate; +} + +static int clk_plldig_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_plldig *pll = to_clk_plldig(hw); + u32 pllfd, prediv; + + unsigned long max_allowed_rate = get_pllx_max_vco_rate(pll->type); + unsigned long phi0_max_rate = get_pllx_phiy_max_rate(pll->type, 0); + unsigned long phi1_max_rate = get_pllx_phiy_max_rate(pll->type, 1); + + if (rate < MIN_VCO_RATE || rate > max_allowed_rate) + return -EINVAL; + + if (((rate / pll->plldv_rfdphi) > phi0_max_rate) || + ((rate / pll->plldv_rfdphi) > phi1_max_rate)) + return -EINVAL; + + pllfd = readl_relaxed(PLLDIG_PLLFD(pll->base)); + prediv = (parent_rate / rate) * + (pll->plldv_mfd + pll->pllfd_mfn / 20480); + + writel_relaxed(PLLDIG_PLLDV_RFDPHI1_SET(pll->plldv_rfdphi1) | + PLLDIG_PLLDV_RFDPHI_SET(pll->plldv_rfdphi) | + PLLDIG_PLLDV_PREDIV_SET(prediv) | + PLLDIG_PLLDV_MFD_SET(pll->plldv_mfd), + PLLDIG_PLLDV(pll->base)); + + writel_relaxed(pllfd | PLLDIG_PLLFD_MFN_SET(pll->pllfd_mfn), + PLLDIG_PLLFD(pll->base)); + + /* + * To be implemented the wait_lock or an equivalent state + * return clk_plldig_wait_lock(pll); + */ + return 0; +} + +static const struct clk_ops clk_plldig_ops = { + .prepare = clk_plldig_prepare, + .unprepare = clk_plldig_unprepare, + .recalc_rate = clk_plldig_recalc_rate, + .round_rate = clk_plldig_round_rate, + .set_rate = clk_plldig_set_rate, +}; + +struct clk *s32v234_clk_plldig_phi(enum s32v234_plldig_type type, + const char *name, const char *parent, + void __iomem *base, u32 phi) +{ + u32 plldv, rfd_phi; + + if (!base) + return ERR_PTR(-ENOMEM); + + plldv = readl_relaxed(PLLDIG_PLLDV(base)); + + switch (phi) { + /* PHI0 */ + case 0: + rfd_phi = (plldv & PLLDIG_PLLDV_RFDPHI_MASK) + >> PLLDIG_PLLDV_RFDPHI_OFFSET; + break; + /* PHI1 */ + case 1: + rfd_phi = (plldv & PLLDIG_PLLDV_RFDPHI1_MASK) + >> PLLDIG_PLLDV_RFDPHI1_OFFSET; + + if (rfd_phi == 0) + rfd_phi = 1; + + break; + default: + return ERR_PTR(-EINVAL); + } + + return clk_register_fixed_factor(NULL, name, parent, + CLK_SET_RATE_PARENT, 1, rfd_phi); +} + +struct clk *s32v234_clk_plldig(enum s32v234_plldig_type type, const char *name, + const char *parent_name, void __iomem *base, + u32 plldv_mfd, u32 pllfd_mfn, + u32 plldv_rfdphi, u32 plldv_rfdphi1) +{ + struct clk_plldig *pll; + const struct clk_ops *ops; + struct clk *clk; + struct clk_init_data init; + + if (plldv_rfdphi > PLLDIG_PLLDV_RFDPHI_MAXVALUE) + return ERR_PTR(-EINVAL); + + if (plldv_rfdphi1 > PLLDIG_PLLDV_RFDPHI1_MAXVALUE) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + ops = &clk_plldig_ops; + + pll->base = base; + pll->type = type; + pll->plldv_mfd = plldv_mfd; + pll->pllfd_mfn = pllfd_mfn; + pll->plldv_rfdphi = plldv_rfdphi; + pll->plldv_rfdphi1 = plldv_rfdphi1; + + init.name = name; + init.ops = ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/drivers/clk/s32/s32v234/clk.c b/drivers/clk/s32/s32v234/clk.c new file mode 100644 index 000000000000..cb5abd54fa2c --- /dev/null +++ b/drivers/clk/s32/s32v234/clk.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + */ + +#include <linux/of_address.h> +#include <linux/clk.h> +#include <dt-bindings/clock/s32v234-clock.h> + +#include "clk.h" + +static void __iomem *mc_cgm0_base; +static void __iomem *mc_cgm1_base; +static void __iomem *mc_cgm2_base; +static void __iomem *mc_cgm3_base; +static void __iomem *mc_me_base; +static void __iomem *src_base; + +DEFINE_SPINLOCK(s32v234_lock); + +/* sources for multiplexer clocks, this is used multiple times */ +PNAME(osc_sels) = {"firc", "fxosc", }; + +PNAME(sys_sels) = {"firc", "fxosc", "armpll_dfs0", }; + +PNAME(can_sels) = {"firc", "fxosc", "dummy", + "periphpll_phi0_div5", }; + +PNAME(lin_sels) = {"firc", "fxosc", "dummy", + "periphpll_phi0_div3", "dummy", "dummy", + "dummy", "dummy", "sys6",}; + +PNAME(sdhc_sels) = {"firc", "fxosc", "dummy", + "enetpll_dfs3",}; + +PNAME(enet_sels) = {"firc", "fxosc", "dummy", + "dummy", "enetpll_phi0",}; + +PNAME(enet_time_sels) = {"firc", "fxosc", "dummy", + "dummy", "enetpll_phi0",}; + +static struct clk *clk[S32V234_CLK_END]; +static struct clk_onecell_data clk_data; + +static void __init s32v234_clocks_init(struct device_node *mc_cgm0_node) +{ + struct device_node *np; + + clk[S32V234_CLK_DUMMY] = s32_clk_fixed("dummy", 0); + clk[S32V234_CLK_FXOSC] = s32_obtain_fixed_clock("fxosc", 0); + clk[S32V234_CLK_FIRC] = s32_obtain_fixed_clock("firc", 0); + + np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_me"); + mc_me_base = of_iomap(np, 0); + if (WARN_ON(!mc_me_base)) + return; + + np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-src"); + src_base = of_iomap(np, 0); + if (WARN_ON(!src_base)) + return; + + np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm1"); + mc_cgm1_base = of_iomap(np, 0); + if (WARN_ON(!mc_cgm1_base)) + return; + + np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm2"); + mc_cgm2_base = of_iomap(np, 0); + if (WARN_ON(!mc_cgm2_base)) + return; + + np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm3"); + mc_cgm3_base = of_iomap(np, 0); + if (WARN_ON(!mc_cgm3_base)) + return; + + np = mc_cgm0_node; + mc_cgm0_base = of_iomap(np, 0); + if (WARN_ON(!mc_cgm0_base)) + return; + + enable_cpumodes_onperipheralconfig(mc_me_base, MC_ME_RUN_PCn_DRUN | + MC_ME_RUN_PCn_RUN0 | + MC_ME_RUN_PCn_RUN1 | + MC_ME_RUN_PCn_RUN2 | + MC_ME_RUN_PCn_RUN3, + 0); + + /* turn on XOSC and FIRC */ + enable_clocks_sources(MC_ME_MODE_MC_MVRON, MC_ME_MODE_MC_XOSCON | + MC_ME_MODE_MC_FIRCON, + MC_ME_RUNn_MC(mc_me_base, 0)); + + /* transition the core to RUN0 mode */ + entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0); + + clk[S32V234_CLK_ARMPLL_SRC_SEL] = s32_clk_mux("armpll_sel", + SRC_GPR1, SRC_GPR1_ARMPLL_SRC_SEL_OFFSET, + SRC_GPR1_XPLL_SRC_SEL_SIZE, + osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock); + + clk[S32V234_CLK_PERIPHPLL_SRC_SEL] = s32_clk_mux("periphpll_sel", + SRC_GPR1, SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET, + SRC_GPR1_XPLL_SRC_SEL_SIZE, + osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock); + + clk[S32V234_CLK_ENETPLL_SRC_SEL] = s32_clk_mux("enetpll_sel", + SRC_GPR1, SRC_GPR1_ENETPLL_SRC_SEL_OFFSET, + SRC_GPR1_XPLL_SRC_SEL_SIZE, + osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock); + + /* ARM_PLL */ + clk[S32V234_CLK_ARMPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ARM, + "armpll_vco", "armpll_sel", ARMPLL_PLLDIG(mc_cgm0_base), + ARMPLL_PLLDIG_PLLDV_MFD, ARMPLL_PLLDIG_PLLDV_MFN, + ARMPLL_PLLDIG_PLLDV_RFDPHI0, ARMPLL_PLLDIG_PLLDV_RFDPHI1); + + clk[S32V234_CLK_ARMPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM, + "armpll_phi0", "armpll_vco", + ARMPLL_PLLDIG(mc_cgm0_base), 0); + + clk[S32V234_CLK_ARMPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM, + "armpll_phi1", "armpll_vco", + ARMPLL_PLLDIG(mc_cgm0_base), 1); + + clk[S32V234_CLK_ARMPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ARM, + "armpll_dfs0", "armpll_phi1", + ARMPLL_PLLDIG_DFS(mc_cgm0_base), 0, + ARMPLL_PLLDIG_DFS0_MFN); + + clk[S32V234_CLK_ARMPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ARM, + "armpll_dfs1", "armpll_phi1", + ARMPLL_PLLDIG_DFS(mc_cgm0_base), 1, + ARMPLL_PLLDIG_DFS1_MFN); + + clk[S32V234_CLK_ARMPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ARM, + "armpll_dfs2", "armpll_phi1", + ARMPLL_PLLDIG_DFS(mc_cgm0_base), 2, + ARMPLL_PLLDIG_DFS2_MFN); + + clk[S32V234_CLK_SYS_SEL] = s32_clk_mux("sys_sel", + MC_ME_RUNn_MC(mc_me_base, 0), + MC_ME_MODE_MC_SYSCLK_OFFSET, + MC_ME_MODE_MC_SYSCLK_SIZE, + sys_sels, ARRAY_SIZE(sys_sels), &s32v234_lock); + + clk[S32V234_CLK_SYS3] = s32_clk_divider("sys3", "sys_sel", + CGM_SC_DCn(mc_cgm0_base, 0), MC_CGM_SC_DCn_PREDIV_OFFSET, + MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock); + + clk[S32V234_CLK_SYS6] = s32_clk_divider("sys6", "sys_sel", + CGM_SC_DCn(mc_cgm0_base, 1), MC_CGM_SC_DCn_PREDIV_OFFSET, + MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock); + + clk[S32V234_CLK_SYS6_DIV2] = s32_clk_divider("sys6_div2", "sys_sel", + CGM_SC_DCn(mc_cgm0_base, 2), MC_CGM_SC_DCn_PREDIV_OFFSET, + MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock); + + /* PERIPH_PLL */ + clk[S32V234_CLK_PERIPHPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_PERIPH, + "periphpll_vco", "periphpll_sel", + PERIPHPLL_PLLDIG(mc_cgm0_base), + PERIPHPLL_PLLDIG_PLLDV_MFD, PERIPHPLL_PLLDIG_PLLDV_MFN, + PERIPHPLL_PLLDIG_PLLDV_RFDPHI0, + PERIPHPLL_PLLDIG_PLLDV_RFDPHI1); + + clk[S32V234_CLK_PERIPHPLL_PHI0] = + s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH, + "periphpll_phi0", "periphpll_vco", + PERIPHPLL_PLLDIG(mc_cgm0_base), 0); + + clk[S32V234_CLK_PERIPHPLL_PHI1] = + s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH, + "periphpll_phi1", "periphpll_vco", + PERIPHPLL_PLLDIG(mc_cgm0_base), 1); + + clk[S32V234_CLK_PERIPHPLL_PHI0_DIV3] = s32_clk_fixed_factor( + "periphpll_phi0_div3", "periphpll_phi0", 1, 3); + + clk[S32V234_CLK_PERIPHPLL_PHI0_DIV5] = s32_clk_fixed_factor( + "periphpll_phi0_div5", "periphpll_phi0", 1, 5); + + clk[S32V234_CLK_CAN_SEL] = s32_clk_mux("can_sel", + CGM_ACn_SC(mc_cgm0_base, 6), + MC_CGM_ACn_SEL_OFFSET, + MC_CGM_ACn_SEL_SIZE, + can_sels, ARRAY_SIZE(can_sels), &s32v234_lock); + + /* CAN Clock */ + clk[S32V234_CLK_CAN] = s32_clk_divider("can", "can_sel", + CGM_ACn_DCm(mc_cgm0_base, 6, 0), + MC_CGM_ACn_DCm_PREDIV_OFFSET, + MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock); + + /* Lin Clock */ + clk[S32V234_CLK_LIN_SEL] = s32_clk_mux("lin_sel", + CGM_ACn_SC(mc_cgm0_base, 3), + MC_CGM_ACn_SEL_OFFSET, + MC_CGM_ACn_SEL_SIZE, + lin_sels, ARRAY_SIZE(lin_sels), &s32v234_lock); + + clk[S32V234_CLK_LIN] = s32_clk_divider("lin", "lin_sel", + CGM_ACn_DCm(mc_cgm0_base, 3, 0), + MC_CGM_ACn_DCm_PREDIV_OFFSET, + MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock); + + clk[S32V234_CLK_LIN_IPG] = s32_clk_fixed_factor("lin_ipg", + "lin", 1, 2); + + /* enable PERIPHPLL */ + enable_clocks_sources(0, MC_ME_MODE_MC_PERIPHPLL, + MC_ME_RUNn_MC(mc_me_base, 0)); + + /* ENET_PLL */ + clk[S32V234_CLK_ENETPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ENET, + "enetpll_vco", "enetpll_sel", ENETPLL_PLLDIG(mc_cgm0_base), + ENETPLL_PLLDIG_PLLDV_MFD, ENETPLL_PLLDIG_PLLDV_MFN, + ENETPLL_PLLDIG_PLLDV_RFDPHI0, ENETPLL_PLLDIG_PLLDV_RFDPHI1); + + clk[S32V234_CLK_ENETPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET, + "enetpll_phi0", "enetpll_vco", + ENETPLL_PLLDIG(mc_cgm0_base), 0); + + clk[S32V234_CLK_ENETPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET, + "enetpll_phi1", "enetpll_vco", + ENETPLL_PLLDIG(mc_cgm0_base), 1); + + clk[S32V234_CLK_ENETPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ENET, + "enetpll_dfs0", "enetpll_phi1", + ENETPLL_PLLDIG_DFS(mc_cgm0_base), 0, + ENETPLL_PLLDIG_DFS0_MFN); + + clk[S32V234_CLK_ENETPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ENET, + "enetpll_dfs1", "enetpll_phi1", + ENETPLL_PLLDIG_DFS(mc_cgm0_base), 1, + ENETPLL_PLLDIG_DFS1_MFN); + + clk[S32V234_CLK_ENETPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ENET, + "enetpll_dfs2", "enetpll_phi1", + ENETPLL_PLLDIG_DFS(mc_cgm0_base), 2, + ENETPLL_PLLDIG_DFS2_MFN); + + clk[S32V234_CLK_ENETPLL_DFS3] = s32v234_clk_dfs(S32_PLLDIG_ENET, + "enetpll_dfs3", "enetpll_phi1", + ENETPLL_PLLDIG_DFS(mc_cgm0_base), 3, + ENETPLL_PLLDIG_DFS3_MFN); + + /* ENET Clock */ + clk[S32V234_CLK_ENET_SEL] = s32_clk_mux("enet_sel", + CGM_ACn_SC(mc_cgm2_base, 2), + MC_CGM_ACn_SEL_OFFSET, + MC_CGM_ACn_SEL_SIZE, + enet_sels, ARRAY_SIZE(enet_sels), &s32v234_lock); + + clk[S32V234_CLK_ENET_TIME_SEL] = s32_clk_mux("enet_time_sel", + CGM_ACn_SC(mc_cgm0_base, 7), + MC_CGM_ACn_SEL_OFFSET, + MC_CGM_ACn_SEL_SIZE, + enet_time_sels, ARRAY_SIZE(enet_time_sels), &s32v234_lock); + + clk[S32V234_CLK_ENET] = s32_clk_divider("enet", "enet_sel", + CGM_ACn_DCm(mc_cgm2_base, 2, 0), + MC_CGM_ACn_DCm_PREDIV_OFFSET, + MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock); + + clk[S32V234_CLK_ENET_TIME] = s32_clk_divider("enet_time", + "enet_time_sel", + CGM_ACn_DCm(mc_cgm0_base, 7, 1), + MC_CGM_ACn_DCm_PREDIV_OFFSET, + MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock); + + /* SDHC Clock */ + clk[S32V234_CLK_SDHC_SEL] = s32_clk_mux("sdhc_sel", + CGM_ACn_SC(mc_cgm0_base, 15), + MC_CGM_ACn_SEL_OFFSET, + MC_CGM_ACn_SEL_SIZE, + sdhc_sels, ARRAY_SIZE(sdhc_sels), &s32v234_lock); + + clk[S32V234_CLK_SDHC] = s32_clk_divider("sdhc", "sdhc_sel", + CGM_ACn_DCm(mc_cgm0_base, 15, 0), + MC_CGM_ACn_DCm_PREDIV_OFFSET, + MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock); + + /* set the system clock */ + enable_sysclock(MC_ME_MODE_MC_SYSCLK(0x2), + MC_ME_RUNn_MC(mc_me_base, 0)); + + /* transition the core to RUN0 mode */ + entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0); + + /* Add the clocks to provider list */ + clk_data.clks = clk; + clk_data.clk_num = ARRAY_SIZE(clk); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +CLK_OF_DECLARE(S32V234, "fsl,s32v234-mc_cgm0", s32v234_clocks_init); diff --git a/drivers/clk/s32/s32v234/clk.h b/drivers/clk/s32/s32v234/clk.h new file mode 100644 index 000000000000..82a222483394 --- /dev/null +++ b/drivers/clk/s32/s32v234/clk.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + */ + +#ifndef __MACH_S32V234_CLK_H +#define __MACH_S32V234_CLK_H + +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include "mc_cgm.h" +#include "mc_me.h" +#include "pll.h" +#include "src.h" +#include "dfs.h" +#include "../clk.h" + +struct clk *s32v234_clk_plldig(enum s32v234_plldig_type type, const char *name, + const char *parent_name, void __iomem *base, + u32 plldv_mfd, u32 plldv_mfn, + u32 plldv_rfdphi, u32 plldv_rfdphi1); + +struct clk *s32v234_clk_plldig_phi(enum s32v234_plldig_type type, + const char *name, const char *parent, + void __iomem *base, u32 phi); + +struct clk *s32v234_clk_dfs(enum s32v234_plldig_type type, const char *name, + const char *parent_name, + void __iomem *reg, u8 idx, u32 mfn); +#endif diff --git a/drivers/clk/s32/s32v234/dfs.h b/drivers/clk/s32/s32v234/dfs.h new file mode 100644 index 000000000000..be3104f7ae51 --- /dev/null +++ b/drivers/clk/s32/s32v234/dfs.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2018 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef _DFS_S32V234_H +#define _DFS_S32V234_H + +/* DFS Control Register (DFS_CTRL) */ +#define DFS_CTRL(base) ((base) + 0x00000018) +#define DFS_CTRL_DLL_LOLIE (1 << 0) +#define DFS_CTRL_DLL_RESET (1 << 1) + +/* DFS Port Status (DFS_PORTSR) */ +#define DFS_PORTSR(base) ((base) + 0x0000000C) +#define DFS_PORTSR_MASK (0x0000000F) +#define DFS_PORTSR_OFFSET (28) + +/* DFS Port Reset Register (DFS_PORTRESET) */ +#define DFS_PORTRESET(base) ((base) + 0x00000014) +#define DFS_PORTRESET_PORTRESET_SET(val) \ + (DFS_PORTRESET_PORTRESET_MASK | \ + (((val) & DFS_PORTRESET_PORTRESET_MAXVAL) \ + << DFS_PORTRESET_PORTRESET_OFFSET)) +#define DFS_PORTRESET_PORTRESET_MAXVAL (0xF) +#define DFS_PORTRESET_PORTRESET_MASK (0x0000000F) +#define DFS_PORTRESET_PORTRESET_OFFSET (28) + +/* DFS Divide Register Portn (DFS_DVPORTn) */ +#define DFS_DVPORTn(base, n) ((base) + (0x0000001C + \ + ((n) * sizeof(u32)))) +#define DFS_DVPORTn_MFI_SET(val) (DFS_DVPORTn_MFI_MASK & \ + (((val) & DFS_DVPORTn_MFI_MAXVAL) \ + << DFS_DVPORTn_MFI_OFFSET)) +#define DFS_DVPORTn_MFN_SET(val) (DFS_DVPORTn_MFN_MASK & \ + (((val) & DFS_DVPORTn_MFN_MAXVAL) \ + << DFS_DVPORTn_MFN_OFFSET)) +#define DFS_DVPORTn_MFI_MASK (0x0000FF00) +#define DFS_DVPORTn_MFN_MASK (0x000000FF) +#define DFS_DVPORTn_MFI_MAXVAL (0xFF) +#define DFS_DVPORTn_MFN_MAXVAL (0xFF) +#define DFS_DVPORTn_MFI_OFFSET (8) +#define DFS_DVPORTn_MFN_OFFSET (0) +#define DFS_MAXNUMBER (4) + +/* + * Naming convention for PLL: + * ARMPLL - PLL0 + * PERIPHPLL - PLL1 + * ENETPLL - PLL2 + * DDRPLL - PLL3 + * VIDEOPLL - PLL4 + */ + +/* The max values for PLL DFS is in Hz */ +/* ARMPLL */ +#define ARMPLL_DFS0_MAX_RATE (266000000) +#define ARMPLL_DFS1_MAX_RATE (600000000) +#define ARMPLL_DFS2_MAX_RATE (600000000) +/* ENETPLL */ +#define ENETPLL_DFS0_MAX_RATE (350000000) +#define ENETPLL_DFS1_MAX_RATE (350000000) +#define ENETPLL_DFS2_MAX_RATE (416000000) +#define ENETPLL_DFS3_MAX_RATE (104000000) +/* DDRPLL */ +#define DDRPLL_DFS0_MAX_RATE (500000000) +#define DDRPLL_DFS1_MAX_RATE (500000000) +#define DDRPLL_DFS2_MAX_RATE (350000000) + +#define ARMPLL_DFS_NR (3) +#define ENETPLL_DFS_NR (4) +#define DDRPLL_DFS_NR (3) + +#endif diff --git a/drivers/clk/s32/s32v234/mc_cgm.h b/drivers/clk/s32/s32v234/mc_cgm.h new file mode 100644 index 000000000000..aeac68771890 --- /dev/null +++ b/drivers/clk/s32/s32v234/mc_cgm.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright (C) 2017 NXP + */ +#ifndef _MC_CGM_H +#define _MC_CGM_H + +#define ARMPLL_PLLDIG(mc_cgm) (mc_cgm) +#define ARMPLL_PLLDIG_DFS(mc_cgm) ((mc_cgm) + 0x40) +#define ARMPLL_PLLDIG_PLLDV_MFD (50) +#define ARMPLL_PLLDIG_PLLDV_MFN (0) +#define ARMPLL_PLLDIG_PLLDV_RFDPHI0 (1) +#define ARMPLL_PLLDIG_PLLDV_RFDPHI1 (1) +#define ARMPLL_PLLDIG_DFS0_MFN (195) +#define ARMPLL_PLLDIG_DFS1_MFN (171) +#define ARMPLL_PLLDIG_DFS2_MFN (171) + +#define PERIPHPLL_PLLDIG(mc_cgm) ((mc_cgm) + 0x80) +#define PERIPHPLL_PLLDIG_PLLDV_MFD (30) +#define PERIPHPLL_PLLDIG_PLLDV_MFN (0) +#define PERIPHPLL_PLLDIG_PLLDV_RFDPHI0 (0x1) +#define PERIPHPLL_PLLDIG_PLLDV_RFDPHI1 (0x1) + +#define ENETPLL_PLLDIG(mc_cgm) ((mc_cgm) + 0x100) +#define ENETPLL_PLLDIG_DFS(mc_cgm) ((mc_cgm) + 0x100 + 0x40) +#define ENETPLL_PLLDIG_PLLDV_MFD (50) +#define ENETPLL_PLLDIG_PLLDV_MFN (0) +#define ENETPLL_PLLDIG_PLLDV_RFDPHI0 (0x1) +#define ENETPLL_PLLDIG_PLLDV_RFDPHI1 (0x1) +#define ENETPLL_PLLDIG_DFS0_MFN (220) +#define ENETPLL_PLLDIG_DFS1_MFN (220) +#define ENETPLL_PLLDIG_DFS2_MFN (33) +#define ENETPLL_PLLDIG_DFS3_MFN (1) + +/* MC_CGM_SC_SS */ +#define CGM_SC_SS(mc_cgm) (((mc_cgm) + 0x7E4)) + +/* MC_CGM_SC_DCn */ +#define CGM_SC_DCn(mc_cgm, dc) (((mc_cgm) + 0x7E8) + ((dc) * 0x4)) + +#define MC_CGM_SC_DCn_PREDIV_OFFSET (16) +#define MC_CGM_SC_DCn_PREDIV_SIZE (3) +#define MC_CGM_SC_DCn_DE (1 << 31) +#define MC_CGM_SC_SEL_OFFSET (24) +#define MC_CGM_SC_SEL_SIZE (4) + +/* MC_CGM_ACn_DCm */ +#define CGM_ACn_DCm(mc_cgm, ac, dc) (((mc_cgm) + 0x808) + ((ac) * 0x20)\ + + ((dc) * 0x4)) + +#define MC_CGM_ACn_DCm_PREDIV(val) (MC_CGM_ACn_DCm_PREDIV_MASK & \ + ((val) \ + << MC_CGM_ACn_DCm_PREDIV_OFFSET)) +#define MC_CGM_ACn_DCm_PREDIV_MASK (0x001F0000) +#define MC_CGM_ACn_DCm_PREDIV_OFFSET (16) +#define MC_CGM_ACn_DCm_PREDIV_SIZE (5) +#define MC_CGM_ACn_DCm_DE (1 << 31) + +/* MC_CGM_ACn_SC/MC_CGM_ACn_SS */ +#define CGM_ACn_SC(mc_cgm, ac) (((mc_cgm) + 0x800) + ((ac) * 0x20)) +#define CGM_ACn_SS(mc_cgm, ac) (((mc_cgm) + 0x804) + ((ac) * 0x24)) +#define MC_CGM_ACn_SEL_MASK (0x07000000) +#define MC_CGM_ACn_SEL_SET(source) (MC_CGM_ACn_SEL_MASK & \ + (((source) & 0x7) \ + << MC_CGM_ACn_SEL_OFFSET)) +#define MC_CGM_ACn_SEL_OFFSET (24) +#define MC_CGM_ACn_SEL_SIZE (4) + +#endif diff --git a/drivers/clk/s32/s32v234/mc_me.h b/drivers/clk/s32/s32v234/mc_me.h new file mode 100644 index 000000000000..718f1d1a0c30 --- /dev/null +++ b/drivers/clk/s32/s32v234/mc_me.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright (C) 2017 NXP + */ + +#ifndef _MC_ME_H +#define _MC_ME_H + +/* MC_ME registers definitions */ +/* MC_ME_GS */ + #define MC_ME_GS(mc_me) ((mc_me) + 0x00000000) + +/* MC_ME_MCTL */ +#define MC_ME_MCTL(mc_me) ((mc_me) + 0x00000004) +#define MC_ME_MCTL_RESET (0x0 << 28) +#define MC_ME_MCTL_TEST (0x1 << 28) +#define MC_ME_MCTL_DRUN (0x3 << 28) +#define MC_ME_MCTL_RUN0 (0x4 << 28) +#define MC_ME_MCTL_RUN1 (0x5 << 28) +#define MC_ME_MCTL_RUN2 (0x6 << 28) +#define MC_ME_MCTL_RUN3 (0x7 << 28) + +#define MC_ME_GS_S_MTRANS (1 << 27) + +#define MC_ME_MCTL_KEY (0x00005AF0) +#define MC_ME_MCTL_INVERTEDKEY (0x0000A50F) + +/* + * MC_ME_RESET_MC/MC_ME_TEST_MC + * MC_ME_DRUN_MC + * MC_ME_RUNn_MC + */ +#define MC_ME_RESET_MC(mc_me) ((mc_me) + 0x00000020) +#define MC_ME_TEST_MC(mc_me) ((mc_me) + 0x00000024) +#define MC_ME_DRUN_MC(mc_me) ((mc_me) + 0x0000002C) +#define MC_ME_RUNn_MC(mc_me, n) ((mc_me) + 0x00000030 + 0x4 * (n)) +#define MC_ME_MODE_MC_SYSCLK_OFFSET (0) +#define MC_ME_MODE_MC_SYSCLK_SIZE (0x3) +#define MC_ME_MODE_MC_SYSCLK(val) (MC_ME_MODE_MC_SYSCLK_MASK & (val)) +#define MC_ME_MODE_MC_SYSCLK_MASK (0x0000000F) +#define MC_ME_MODE_MC_FIRCON (1 << 4) +#define MC_ME_MODE_MC_XOSCON (1 << 5) +#define MC_ME_MODE_MC_ARMPLL (1 << 6) +#define MC_ME_MODE_MC_PERIPHPLL (1 << 7) +#define MC_ME_MODE_MC_ENETPLL (1 << 8) +#define MC_ME_MODE_MC_DDRPLL (1 << 9) +#define MC_ME_MODE_MC_VIDEOPLL (1 << 10) +#define MC_ME_MODE_MC_MVRON (1 << 20) + +/* MC_ME_DRUN_SEC_CC_I */ +#define MC_ME_DRUN_SEC_CC_I(mc_me) ((mc_me) + 0x260) +/* MC_ME_RUNn_SEC_CC_I */ +#define MC_ME_RUNn_SEC_CC_I(mc_me, n) ((mc_me) + 0x270 + (n) * 0x10) +#define MC_ME_MODE_SEC_CC_I_SYSCLK1_OFFSET (4) +#define MC_ME_MODE_SEC_CC_I_SYSCLK2_OFFSET (8) +#define MC_ME_MODE_SEC_CC_I_SYSCLK3_OFFSET (12) +/* Consider only the defined clocks */ +#define MC_ME_MODE_SEC_CC_I_SYSCLK1_SIZE (0x3) +#define MC_ME_MODE_SEC_CC_I_SYSCLK2_SIZE (0x3) +#define MC_ME_MODE_SEC_CC_I_SYSCLK3_SIZE (0x3) + +/* MC_ME_RUN_PCn */ +#define MC_ME_RUN_PCn(mc_me, n) (mc_me + 0x00000080 + 0x4 * (n)) + +#define MC_ME_RUN_PCn_MAX_IDX (7) +#define MC_ME_RUN_PCn_RESET (1 << 0) +#define MC_ME_RUN_PCn_TEST (1 << 1) +#define MC_ME_RUN_PCn_DRUN (1 << 3) +#define MC_ME_RUN_PCn_RUN0 (1 << 4) +#define MC_ME_RUN_PCn_RUN1 (1 << 5) +#define MC_ME_RUN_PCn_RUN2 (1 << 6) +#define MC_ME_RUN_PCn_RUN3 (1 << 7) + +#define MC_ME_PCTLn(mc_me, n) (mc_me + 0xC0 + 4 * (n >> 2) + \ + (3 - (n) % 4)) + +static inline void entry_to_target_mode(void __iomem *mc_me, u32 mode) +{ + writel_relaxed(mode | MC_ME_MCTL_KEY, MC_ME_MCTL(mc_me)); + writel_relaxed(mode | MC_ME_MCTL_INVERTEDKEY, MC_ME_MCTL(mc_me)); + while ((readl_relaxed(MC_ME_GS(mc_me)) & + MC_ME_GS_S_MTRANS) != 0x00000000) + ; +} + +static inline void enable_cpumodes_onperipheralconfig(void __iomem *mc_me, + u32 modes, u32 run_pc_idx) +{ + WARN_ON(run_pc_idx > MC_ME_RUN_PCn_MAX_IDX); + if (run_pc_idx > MC_ME_RUN_PCn_MAX_IDX) + return; + + writel_relaxed(modes, MC_ME_RUN_PCn(mc_me, run_pc_idx)); +} + +static inline void enable_clocks_sources(u32 flags, u32 clks, + void __iomem *xrun_mc_addr) +{ + writel_relaxed(readl_relaxed(xrun_mc_addr) | flags | clks, + xrun_mc_addr); +} + +static inline void enable_sysclock(u32 clk, void __iomem *xrun_mc_addr) +{ + writel_relaxed(readl_relaxed(xrun_mc_addr) & clk, + xrun_mc_addr); +} + +#endif diff --git a/drivers/clk/s32/s32v234/pll.h b/drivers/clk/s32/s32v234/pll.h new file mode 100644 index 000000000000..b7bcc50f0a22 --- /dev/null +++ b/drivers/clk/s32/s32v234/pll.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright (C) 2017-2018 NXP + */ +#ifndef _PLL_S32V234_H +#define _PLL_S32V234_H + +/* PLLDIG PLL Divider Register (PLLDIG_PLLDV) */ +#define PLLDIG_PLLDV(base) ((base) + 0x00000028) +#define PLLDIG_PLLDV_MFD_SET(val) (PLLDIG_PLLDV_MFD_MASK & (val)) +#define PLLDIG_PLLDV_MFD_MASK (0x000000FF) + +#define PLLDIG_PLLDV_RFDPHI_SET(val) (PLLDIG_PLLDV_RFDPHI_MASK & \ + (((val) & \ + PLLDIG_PLLDV_RFDPHI_MAXVALUE) \ + << PLLDIG_PLLDV_RFDPHI_OFFSET)) +#define PLLDIG_PLLDV_RFDPHI_MASK (0x003F0000) +#define PLLDIG_PLLDV_RFDPHI_MAXVALUE (0x3F) + +#define PLLDIG_PLLDV_RFDPHI_OFFSET (16) + +#define PLLDIG_PLLDV_RFDPHI1_SET(val) (PLLDIG_PLLDV_RFDPHI1_MASK & \ + (((val) & \ + PLLDIG_PLLDV_RFDPHI1_MAXVALUE) \ + << PLLDIG_PLLDV_RFDPHI1_OFFSET)) +#define PLLDIG_PLLDV_RFDPHI1_MASK (0x7E000000) +#define PLLDIG_PLLDV_RFDPHI1_MAXVALUE (0x3F) +#define PLLDIG_PLLDV_RFDPHI1_OFFSET (25) + +#define PLLDIG_PLLDV_PREDIV_SET(val) (PLLDIG_PLLDV_PREDIV_MASK & \ + (((val) & \ + PLLDIG_PLLDV_PREDIV_MAXVALUE) \ + << PLLDIG_PLLDV_PREDIV_OFFSET)) +#define PLLDIG_PLLDV_PREDIV_MASK (0x00007000) +#define PLLDIG_PLLDV_PREDIV_MAXVALUE (0x7) +#define PLLDIG_PLLDV_PREDIV_OFFSET (12) + +/* PLLDIG PLL Fractional Divide Register (PLLDIG_PLLFD) */ +#define PLLDIG_PLLFD(base) ((base) + 0x00000030) +#define PLLDIG_PLLFD_MFN_SET(val) (PLLDIG_PLLFD_MFN_MASK & (val)) +#define PLLDIG_PLLFD_MFN_MASK (0x00007FFF) + +/* PLL Calibration Register 1 (PLLDIG_PLLCAL1) */ +#define PLLDIG_PLLCAL1(base) ((base) + 0x00000038) +#define PLLDIG_PLLCAL1_NDAC1_SET(val) (PLLDIG_PLLCAL1_NDAC1_MASK & \ + ((val) \ + << PLLDIG_PLLCAL1_NDAC1_OFFSET)) +#define PLLDIG_PLLCAL1_NDAC1_OFFSET (24) +#define PLLDIG_PLLCAL1_NDAC1_MASK (0x7F000000) + +/* Naming convention for PLL: + * ARMPLL - PLL0 + * PERIPHPLL - PLL1 + * ENETPLL - PLL2 + * DDRPLL - PLL3 + * VIDEOPLL - PLL4 + */ +/* The min,max values for PLL VCO (Hz) */ +#define PERIPHPLL_MAX_VCO_RATE (1200000000) + +/* The min,max values for PLL PHI0 and PHI1 outputs (Hz) */ +#define PERIPHPLL_MAX_PHI0_MAX_RATE (400000000) +#define PERIPHPLL_MAX_PHI1_MAX_RATE (100000000) + +/* The maximum value for PLL VCO according to data sheet */ +#define MAX_VCO_RATE (1300000000) +#define MIN_VCO_RATE (650000000) + +enum s32v234_plldig_type { + S32_PLLDIG_ARM, + S32_PLLDIG_PERIPH, + S32_PLLDIG_ENET, + S32_PLLDIG_DDR, + S32_PLLDIG_VIDEO, +}; + +#endif diff --git a/drivers/clk/s32/s32v234/src.h b/drivers/clk/s32/s32v234/src.h new file mode 100644 index 000000000000..39fa973b7c3c --- /dev/null +++ b/drivers/clk/s32/s32v234/src.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + */ +#ifndef _SRC_H +#define _SRC_H + +/* Source Reset Control: General Purpose Register 1 */ +#define SRC_GPR1 (src_base + 0x100) +#define SRC_GPR1_ARMPLL_SRC_SEL_OFFSET (27) +#define SRC_GPR1_ENETPLL_SRC_SEL_OFFSET (28) +#define SRC_GPR1_DDRPLL_SRC_SEL_OFFSET (29) +#define SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET (30) +#define SRC_GPR1_VIDEOPLL_SRC_SEL_OFFSET (31) +#define SRC_GPR1_XPLL_SRC_SEL_SIZE (1) + +#endif diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h index e20c43cc36f6..15118e76e353 100644 --- a/include/dt-bindings/clock/imx6qdl-clock.h +++ b/include/dt-bindings/clock/imx6qdl-clock.h @@ -273,6 +273,11 @@ #define IMX6QDL_CLK_MMDC_P0_IPG 263 #define IMX6QDL_CLK_DCIC1 264 #define IMX6QDL_CLK_DCIC2 265 -#define IMX6QDL_CLK_END 266 +#define IMX6QDL_CLK_AXI_ALT_SEL 266 +#define IMX6QDL_CLK_LDB_DI0_DIV_7 267 +#define IMX6QDL_CLK_LDB_DI1_DIV_7 268 +#define IMX6QDL_CLK_LDB_DI0_DIV_SEL 269 +#define IMX6QDL_CLK_LDB_DI1_DIV_SEL 270 +#define IMX6QDL_CLK_END 271 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */ diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h index e6a670e1a3f8..8ee3b08a7c37 100644 --- a/include/dt-bindings/clock/imx7d-clock.h +++ b/include/dt-bindings/clock/imx7d-clock.h @@ -451,5 +451,8 @@ #define IMX7D_SNVS_CLK 442 #define IMX7D_CAAM_CLK 443 #define IMX7D_KPP_ROOT_CLK 444 -#define IMX7D_CLK_END 445 +#define IMX7D_PXP_IPG_CLK 445 +#define IMX7D_PXP_AXI_CLK 446 +#define IMX7D_CLK_END 447 + #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */ diff --git a/include/dt-bindings/clock/imx7ulp-clock.h b/include/dt-bindings/clock/imx7ulp-clock.h index 6f66f9005c81..f8d34fb4378f 100644 --- a/include/dt-bindings/clock/imx7ulp-clock.h +++ b/include/dt-bindings/clock/imx7ulp-clock.h @@ -49,15 +49,14 @@ #define IMX7ULP_CLK_NIC1_DIV 36 #define IMX7ULP_CLK_NIC1_BUS_DIV 37 #define IMX7ULP_CLK_NIC1_EXT_DIV 38 -#define IMX7ULP_CLK_MIPI_PLL 39 -#define IMX7ULP_CLK_SIRC 40 -#define IMX7ULP_CLK_SOSC_BUS_CLK 41 -#define IMX7ULP_CLK_FIRC_BUS_CLK 42 -#define IMX7ULP_CLK_SPLL_BUS_CLK 43 -#define IMX7ULP_CLK_HSRUN_SYS_SEL 44 -#define IMX7ULP_CLK_HSRUN_CORE_DIV 45 +#define IMX7ULP_CLK_SIRC 39 +#define IMX7ULP_CLK_SOSC_BUS_CLK 40 +#define IMX7ULP_CLK_FIRC_BUS_CLK 41 +#define IMX7ULP_CLK_SPLL_BUS_CLK 42 +#define IMX7ULP_CLK_HSRUN_SYS_SEL 43 +#define IMX7ULP_CLK_HSRUN_CORE_DIV 44 -#define IMX7ULP_CLK_SCG1_END 46 +#define IMX7ULP_CLK_SCG1_END 45 /* PCC2 */ #define IMX7ULP_CLK_DMA1 0 diff --git a/include/dt-bindings/clock/imx8-clock.h b/include/dt-bindings/clock/imx8-clock.h index 673a8c662340..d7d2a8f3d49e 100644 --- a/include/dt-bindings/clock/imx8-clock.h +++ b/include/dt-bindings/clock/imx8-clock.h @@ -7,287 +7,59 @@ #ifndef __DT_BINDINGS_CLOCK_IMX_H #define __DT_BINDINGS_CLOCK_IMX_H -/* SCU Clocks */ - -#define IMX_CLK_DUMMY 0 - -/* CPU */ -#define IMX_A35_CLK 1 - -/* LSIO SS */ -#define IMX_LSIO_MEM_CLK 2 -#define IMX_LSIO_BUS_CLK 3 -#define IMX_LSIO_PWM0_CLK 10 -#define IMX_LSIO_PWM1_CLK 11 -#define IMX_LSIO_PWM2_CLK 12 -#define IMX_LSIO_PWM3_CLK 13 -#define IMX_LSIO_PWM4_CLK 14 -#define IMX_LSIO_PWM5_CLK 15 -#define IMX_LSIO_PWM6_CLK 16 -#define IMX_LSIO_PWM7_CLK 17 -#define IMX_LSIO_GPT0_CLK 18 -#define IMX_LSIO_GPT1_CLK 19 -#define IMX_LSIO_GPT2_CLK 20 -#define IMX_LSIO_GPT3_CLK 21 -#define IMX_LSIO_GPT4_CLK 22 -#define IMX_LSIO_FSPI0_CLK 23 -#define IMX_LSIO_FSPI1_CLK 24 - -/* Connectivity SS */ -#define IMX_CONN_AXI_CLK_ROOT 30 -#define IMX_CONN_AHB_CLK_ROOT 31 -#define IMX_CONN_IPG_CLK_ROOT 32 -#define IMX_CONN_SDHC0_CLK 40 -#define IMX_CONN_SDHC1_CLK 41 -#define IMX_CONN_SDHC2_CLK 42 -#define IMX_CONN_ENET0_ROOT_CLK 43 -#define IMX_CONN_ENET0_BYPASS_CLK 44 -#define IMX_CONN_ENET0_RGMII_CLK 45 -#define IMX_CONN_ENET1_ROOT_CLK 46 -#define IMX_CONN_ENET1_BYPASS_CLK 47 -#define IMX_CONN_ENET1_RGMII_CLK 48 -#define IMX_CONN_GPMI_BCH_IO_CLK 49 -#define IMX_CONN_GPMI_BCH_CLK 50 -#define IMX_CONN_USB2_ACLK 51 -#define IMX_CONN_USB2_BUS_CLK 52 -#define IMX_CONN_USB2_LPM_CLK 53 - -/* HSIO SS */ -#define IMX_HSIO_AXI_CLK 60 -#define IMX_HSIO_PER_CLK 61 - -/* Display controller SS */ -#define IMX_DC_AXI_EXT_CLK 70 -#define IMX_DC_AXI_INT_CLK 71 -#define IMX_DC_CFG_CLK 72 -#define IMX_DC0_PLL0_CLK 80 -#define IMX_DC0_PLL1_CLK 81 -#define IMX_DC0_DISP0_CLK 82 -#define IMX_DC0_DISP1_CLK 83 - -/* MIPI-LVDS SS */ -#define IMX_MIPI_IPG_CLK 90 -#define IMX_MIPI0_PIXEL_CLK 100 -#define IMX_MIPI0_BYPASS_CLK 101 -#define IMX_MIPI0_LVDS_PIXEL_CLK 102 -#define IMX_MIPI0_LVDS_BYPASS_CLK 103 -#define IMX_MIPI0_LVDS_PHY_CLK 104 -#define IMX_MIPI0_I2C0_CLK 105 -#define IMX_MIPI0_I2C1_CLK 106 -#define IMX_MIPI0_PWM0_CLK 107 -#define IMX_MIPI1_PIXEL_CLK 108 -#define IMX_MIPI1_BYPASS_CLK 109 -#define IMX_MIPI1_LVDS_PIXEL_CLK 110 -#define IMX_MIPI1_LVDS_BYPASS_CLK 111 -#define IMX_MIPI1_LVDS_PHY_CLK 112 -#define IMX_MIPI1_I2C0_CLK 113 -#define IMX_MIPI1_I2C1_CLK 114 -#define IMX_MIPI1_PWM0_CLK 115 - -/* IMG SS */ -#define IMX_IMG_AXI_CLK 120 -#define IMX_IMG_IPG_CLK 121 -#define IMX_IMG_PXL_CLK 122 - -/* MIPI-CSI SS */ -#define IMX_CSI0_CORE_CLK 130 -#define IMX_CSI0_ESC_CLK 131 -#define IMX_CSI0_PWM0_CLK 132 -#define IMX_CSI0_I2C0_CLK 133 - -/* PARALLER CSI SS */ -#define IMX_PARALLEL_CSI_DPLL_CLK 140 -#define IMX_PARALLEL_CSI_PIXEL_CLK 141 -#define IMX_PARALLEL_CSI_MCLK_CLK 142 - -/* VPU SS */ -#define IMX_VPU_ENC_CLK 150 -#define IMX_VPU_DEC_CLK 151 - -/* GPU SS */ -#define IMX_GPU0_CORE_CLK 160 -#define IMX_GPU0_SHADER_CLK 161 - -/* ADMA SS */ -#define IMX_ADMA_IPG_CLK_ROOT 165 -#define IMX_ADMA_UART0_CLK 170 -#define IMX_ADMA_UART1_CLK 171 -#define IMX_ADMA_UART2_CLK 172 -#define IMX_ADMA_UART3_CLK 173 -#define IMX_ADMA_SPI0_CLK 174 -#define IMX_ADMA_SPI1_CLK 175 -#define IMX_ADMA_SPI2_CLK 176 -#define IMX_ADMA_SPI3_CLK 177 -#define IMX_ADMA_CAN0_CLK 178 -#define IMX_ADMA_CAN1_CLK 179 -#define IMX_ADMA_CAN2_CLK 180 -#define IMX_ADMA_I2C0_CLK 181 -#define IMX_ADMA_I2C1_CLK 182 -#define IMX_ADMA_I2C2_CLK 183 -#define IMX_ADMA_I2C3_CLK 184 -#define IMX_ADMA_FTM0_CLK 185 -#define IMX_ADMA_FTM1_CLK 186 -#define IMX_ADMA_ADC0_CLK 187 -#define IMX_ADMA_PWM_CLK 188 -#define IMX_ADMA_LCD_CLK 189 - -#define IMX_SCU_CLK_END 190 - -/* LPCG clocks */ - -/* LSIO SS LPCG */ -#define IMX_LSIO_LPCG_PWM0_IPG_CLK 0 -#define IMX_LSIO_LPCG_PWM0_IPG_S_CLK 1 -#define IMX_LSIO_LPCG_PWM0_IPG_HF_CLK 2 -#define IMX_LSIO_LPCG_PWM0_IPG_SLV_CLK 3 -#define IMX_LSIO_LPCG_PWM0_IPG_MSTR_CLK 4 -#define IMX_LSIO_LPCG_PWM1_IPG_CLK 5 -#define IMX_LSIO_LPCG_PWM1_IPG_S_CLK 6 -#define IMX_LSIO_LPCG_PWM1_IPG_HF_CLK 7 -#define IMX_LSIO_LPCG_PWM1_IPG_SLV_CLK 8 -#define IMX_LSIO_LPCG_PWM1_IPG_MSTR_CLK 9 -#define IMX_LSIO_LPCG_PWM2_IPG_CLK 10 -#define IMX_LSIO_LPCG_PWM2_IPG_S_CLK 11 -#define IMX_LSIO_LPCG_PWM2_IPG_HF_CLK 12 -#define IMX_LSIO_LPCG_PWM2_IPG_SLV_CLK 13 -#define IMX_LSIO_LPCG_PWM2_IPG_MSTR_CLK 14 -#define IMX_LSIO_LPCG_PWM3_IPG_CLK 15 -#define IMX_LSIO_LPCG_PWM3_IPG_S_CLK 16 -#define IMX_LSIO_LPCG_PWM3_IPG_HF_CLK 17 -#define IMX_LSIO_LPCG_PWM3_IPG_SLV_CLK 18 -#define IMX_LSIO_LPCG_PWM3_IPG_MSTR_CLK 19 -#define IMX_LSIO_LPCG_PWM4_IPG_CLK 20 -#define IMX_LSIO_LPCG_PWM4_IPG_S_CLK 21 -#define IMX_LSIO_LPCG_PWM4_IPG_HF_CLK 22 -#define IMX_LSIO_LPCG_PWM4_IPG_SLV_CLK 23 -#define IMX_LSIO_LPCG_PWM4_IPG_MSTR_CLK 24 -#define IMX_LSIO_LPCG_PWM5_IPG_CLK 25 -#define IMX_LSIO_LPCG_PWM5_IPG_S_CLK 26 -#define IMX_LSIO_LPCG_PWM5_IPG_HF_CLK 27 -#define IMX_LSIO_LPCG_PWM5_IPG_SLV_CLK 28 -#define IMX_LSIO_LPCG_PWM5_IPG_MSTR_CLK 29 -#define IMX_LSIO_LPCG_PWM6_IPG_CLK 30 -#define IMX_LSIO_LPCG_PWM6_IPG_S_CLK 31 -#define IMX_LSIO_LPCG_PWM6_IPG_HF_CLK 32 -#define IMX_LSIO_LPCG_PWM6_IPG_SLV_CLK 33 -#define IMX_LSIO_LPCG_PWM6_IPG_MSTR_CLK 34 -#define IMX_LSIO_LPCG_PWM7_IPG_CLK 35 -#define IMX_LSIO_LPCG_PWM7_IPG_S_CLK 36 -#define IMX_LSIO_LPCG_PWM7_IPG_HF_CLK 37 -#define IMX_LSIO_LPCG_PWM7_IPG_SLV_CLK 38 -#define IMX_LSIO_LPCG_PWM7_IPG_MSTR_CLK 39 -#define IMX_LSIO_LPCG_GPT0_IPG_CLK 40 -#define IMX_LSIO_LPCG_GPT0_IPG_S_CLK 41 -#define IMX_LSIO_LPCG_GPT0_IPG_HF_CLK 42 -#define IMX_LSIO_LPCG_GPT0_IPG_SLV_CLK 43 -#define IMX_LSIO_LPCG_GPT0_IPG_MSTR_CLK 44 -#define IMX_LSIO_LPCG_GPT1_IPG_CLK 45 -#define IMX_LSIO_LPCG_GPT1_IPG_S_CLK 46 -#define IMX_LSIO_LPCG_GPT1_IPG_HF_CLK 47 -#define IMX_LSIO_LPCG_GPT1_IPG_SLV_CLK 48 -#define IMX_LSIO_LPCG_GPT1_IPG_MSTR_CLK 49 -#define IMX_LSIO_LPCG_GPT2_IPG_CLK 50 -#define IMX_LSIO_LPCG_GPT2_IPG_S_CLK 51 -#define IMX_LSIO_LPCG_GPT2_IPG_HF_CLK 52 -#define IMX_LSIO_LPCG_GPT2_IPG_SLV_CLK 53 -#define IMX_LSIO_LPCG_GPT2_IPG_MSTR_CLK 54 -#define IMX_LSIO_LPCG_GPT3_IPG_CLK 55 -#define IMX_LSIO_LPCG_GPT3_IPG_S_CLK 56 -#define IMX_LSIO_LPCG_GPT3_IPG_HF_CLK 57 -#define IMX_LSIO_LPCG_GPT3_IPG_SLV_CLK 58 -#define IMX_LSIO_LPCG_GPT3_IPG_MSTR_CLK 59 -#define IMX_LSIO_LPCG_GPT4_IPG_CLK 60 -#define IMX_LSIO_LPCG_GPT4_IPG_S_CLK 61 -#define IMX_LSIO_LPCG_GPT4_IPG_HF_CLK 62 -#define IMX_LSIO_LPCG_GPT4_IPG_SLV_CLK 63 -#define IMX_LSIO_LPCG_GPT4_IPG_MSTR_CLK 64 -#define IMX_LSIO_LPCG_FSPI0_HCLK 65 -#define IMX_LSIO_LPCG_FSPI0_IPG_CLK 66 -#define IMX_LSIO_LPCG_FSPI0_IPG_S_CLK 67 -#define IMX_LSIO_LPCG_FSPI0_IPG_SFCK 68 -#define IMX_LSIO_LPCG_FSPI1_HCLK 69 -#define IMX_LSIO_LPCG_FSPI1_IPG_CLK 70 -#define IMX_LSIO_LPCG_FSPI1_IPG_S_CLK 71 -#define IMX_LSIO_LPCG_FSPI1_IPG_SFCK 72 - -#define IMX_LSIO_LPCG_CLK_END 73 - -/* Connectivity SS LPCG */ -#define IMX_CONN_LPCG_SDHC0_IPG_CLK 0 -#define IMX_CONN_LPCG_SDHC0_PER_CLK 1 -#define IMX_CONN_LPCG_SDHC0_HCLK 2 -#define IMX_CONN_LPCG_SDHC1_IPG_CLK 3 -#define IMX_CONN_LPCG_SDHC1_PER_CLK 4 -#define IMX_CONN_LPCG_SDHC1_HCLK 5 -#define IMX_CONN_LPCG_SDHC2_IPG_CLK 6 -#define IMX_CONN_LPCG_SDHC2_PER_CLK 7 -#define IMX_CONN_LPCG_SDHC2_HCLK 8 -#define IMX_CONN_LPCG_GPMI_APB_CLK 9 -#define IMX_CONN_LPCG_GPMI_BCH_APB_CLK 10 -#define IMX_CONN_LPCG_GPMI_BCH_IO_CLK 11 -#define IMX_CONN_LPCG_GPMI_BCH_CLK 12 -#define IMX_CONN_LPCG_APBHDMA_CLK 13 -#define IMX_CONN_LPCG_ENET0_ROOT_CLK 14 -#define IMX_CONN_LPCG_ENET0_TX_CLK 15 -#define IMX_CONN_LPCG_ENET0_AHB_CLK 16 -#define IMX_CONN_LPCG_ENET0_IPG_S_CLK 17 -#define IMX_CONN_LPCG_ENET0_IPG_CLK 18 - -#define IMX_CONN_LPCG_ENET1_ROOT_CLK 19 -#define IMX_CONN_LPCG_ENET1_TX_CLK 20 -#define IMX_CONN_LPCG_ENET1_AHB_CLK 21 -#define IMX_CONN_LPCG_ENET1_IPG_S_CLK 22 -#define IMX_CONN_LPCG_ENET1_IPG_CLK 23 - -#define IMX_CONN_LPCG_CLK_END 24 - -/* ADMA SS LPCG */ -#define IMX_ADMA_LPCG_UART0_IPG_CLK 0 -#define IMX_ADMA_LPCG_UART0_BAUD_CLK 1 -#define IMX_ADMA_LPCG_UART1_IPG_CLK 2 -#define IMX_ADMA_LPCG_UART1_BAUD_CLK 3 -#define IMX_ADMA_LPCG_UART2_IPG_CLK 4 -#define IMX_ADMA_LPCG_UART2_BAUD_CLK 5 -#define IMX_ADMA_LPCG_UART3_IPG_CLK 6 -#define IMX_ADMA_LPCG_UART3_BAUD_CLK 7 -#define IMX_ADMA_LPCG_SPI0_IPG_CLK 8 -#define IMX_ADMA_LPCG_SPI1_IPG_CLK 9 -#define IMX_ADMA_LPCG_SPI2_IPG_CLK 10 -#define IMX_ADMA_LPCG_SPI3_IPG_CLK 11 -#define IMX_ADMA_LPCG_SPI0_CLK 12 -#define IMX_ADMA_LPCG_SPI1_CLK 13 -#define IMX_ADMA_LPCG_SPI2_CLK 14 -#define IMX_ADMA_LPCG_SPI3_CLK 15 -#define IMX_ADMA_LPCG_CAN0_IPG_CLK 16 -#define IMX_ADMA_LPCG_CAN0_IPG_PE_CLK 17 -#define IMX_ADMA_LPCG_CAN0_IPG_CHI_CLK 18 -#define IMX_ADMA_LPCG_CAN1_IPG_CLK 19 -#define IMX_ADMA_LPCG_CAN1_IPG_PE_CLK 20 -#define IMX_ADMA_LPCG_CAN1_IPG_CHI_CLK 21 -#define IMX_ADMA_LPCG_CAN2_IPG_CLK 22 -#define IMX_ADMA_LPCG_CAN2_IPG_PE_CLK 23 -#define IMX_ADMA_LPCG_CAN2_IPG_CHI_CLK 24 -#define IMX_ADMA_LPCG_I2C0_CLK 25 -#define IMX_ADMA_LPCG_I2C1_CLK 26 -#define IMX_ADMA_LPCG_I2C2_CLK 27 -#define IMX_ADMA_LPCG_I2C3_CLK 28 -#define IMX_ADMA_LPCG_I2C0_IPG_CLK 29 -#define IMX_ADMA_LPCG_I2C1_IPG_CLK 30 -#define IMX_ADMA_LPCG_I2C2_IPG_CLK 31 -#define IMX_ADMA_LPCG_I2C3_IPG_CLK 32 -#define IMX_ADMA_LPCG_FTM0_CLK 33 -#define IMX_ADMA_LPCG_FTM1_CLK 34 -#define IMX_ADMA_LPCG_FTM0_IPG_CLK 35 -#define IMX_ADMA_LPCG_FTM1_IPG_CLK 36 -#define IMX_ADMA_LPCG_PWM_HI_CLK 37 -#define IMX_ADMA_LPCG_PWM_IPG_CLK 38 -#define IMX_ADMA_LPCG_LCD_PIX_CLK 39 -#define IMX_ADMA_LPCG_LCD_APB_CLK 40 -#define IMX_ADMA_LPCG_DSP_ADB_CLK 41 -#define IMX_ADMA_LPCG_DSP_IPG_CLK 42 -#define IMX_ADMA_LPCG_DSP_CORE_CLK 43 -#define IMX_ADMA_LPCG_OCRAM_IPG_CLK 44 - -#define IMX_ADMA_LPCG_CLK_END 45 +#define IMX_ADMA_ACM_AUD_CLK0_SEL 0 +#define IMX_ADMA_ACM_AUD_CLK0_CLK 1 +#define IMX_ADMA_ACM_AUD_CLK1_SEL 2 +#define IMX_ADMA_ACM_AUD_CLK1_CLK 3 +#define IMX_ADMA_ACM_MCLKOUT0_SEL 4 +#define IMX_ADMA_ACM_MCLKOUT1_SEL 5 +#define IMX_ADMA_ACM_ESAI0_MCLK_SEL 6 +#define IMX_ADMA_ACM_GPT0_MUX_CLK_SEL 7 +#define IMX_ADMA_ACM_GPT1_MUX_CLK_SEL 8 +#define IMX_ADMA_ACM_GPT2_MUX_CLK_SEL 9 +#define IMX_ADMA_ACM_GPT3_MUX_CLK_SEL 10 +#define IMX_ADMA_ACM_GPT4_MUX_CLK_SEL 11 +#define IMX_ADMA_ACM_GPT5_MUX_CLK_SEL 12 +#define IMX_ADMA_ACM_SAI0_MCLK_SEL 13 +#define IMX_ADMA_ACM_SAI1_MCLK_SEL 14 +#define IMX_ADMA_ACM_SAI2_MCLK_SEL 15 +#define IMX_ADMA_ACM_SAI3_MCLK_SEL 16 +#define IMX_ADMA_ACM_SAI4_MCLK_SEL 17 +#define IMX_ADMA_ACM_SAI5_MCLK_SEL 18 +#define IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL 19 +#define IMX_ADMA_ACM_MQS_TX_CLK_SEL 20 +#define IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL 21 +#define IMX_ADMA_ACM_ASRC1_MUX_CLK_SEL 22 + +#define IMX_ADMA_EXT_AUD_MCLK0 23 +#define IMX_ADMA_EXT_AUD_MCLK1 24 +#define IMX_ADMA_ESAI0_RX_CLK 25 +#define IMX_ADMA_ESAI0_RX_HF_CLK 26 +#define IMX_ADMA_ESAI0_TX_CLK 27 +#define IMX_ADMA_ESAI0_TX_HF_CLK 28 +#define IMX_ADMA_SPDIF0_RX 29 +#define IMX_ADMA_SAI0_RX_BCLK 30 +#define IMX_ADMA_SAI0_TX_BCLK 31 +#define IMX_ADMA_SAI1_RX_BCLK 32 +#define IMX_ADMA_SAI1_TX_BCLK 33 +#define IMX_ADMA_SAI2_RX_BCLK 34 +#define IMX_ADMA_SAI3_RX_BCLK 35 +#define IMX_ADMA_SAI4_RX_BCLK 36 +#define IMX_ADMA_SAI5_TX_BCLK 37 +#define IMX_ADMA_SAI6_RX_BCLK 38 +#define IMX_ADMA_HDMI_RX_MCLK 39 +#define IMX_ADMA_MLB_CLK 40 +#define IMX_ADMA_SPDIF1_RX 41 +#define IMX_ADMA_ESAI1_RX_CLK 42 +#define IMX_ADMA_ESAI1_RX_HF_CLK 43 +#define IMX_ADMA_ESAI1_TX_CLK 44 +#define IMX_ADMA_ESAI1_TX_HF_CLK 45 + +#define IMX_ADMA_ACM_ESAI1_MCLK_SEL 46 +#define IMX_ADMA_ACM_SAI6_MCLK_SEL 47 +#define IMX_ADMA_ACM_SAI7_MCLK_SEL 48 +#define IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL 49 + +#define IMX_ADMA_ACM_CLK_END 50 #endif /* __DT_BINDINGS_CLOCK_IMX_H */ diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index 65463673d25e..ee2eb2bef7c1 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -403,5 +403,9 @@ #define IMX8MQ_CLK_SNVS_ROOT 264 #define IMX8MQ_CLK_GIC 265 -#define IMX8MQ_CLK_END 266 +#define IMX8MQ_VIDEO2_PLL1_REF_SEL 266 + +#define IMX8MQ_CLK_PHY_27MHZ 267 + +#define IMX8MQ_CLK_END 268 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ diff --git a/include/dt-bindings/clock/s32v234-clock.h b/include/dt-bindings/clock/s32v234-clock.h new file mode 100644 index 000000000000..1ddfae5c1422 --- /dev/null +++ b/include/dt-bindings/clock/s32v234-clock.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * Copyright (C) 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_S32V234_H +#define __DT_BINDINGS_CLOCK_S32V234_H + +#define S32V234_CLK_DUMMY 0 +#define S32V234_CLK_FXOSC 1 +#define S32V234_CLK_FIRC 2 +/* PERIPH PLL */ +#define S32V234_CLK_PERIPHPLL_SRC_SEL 3 +#define S32V234_CLK_PERIPHPLL_VCO 4 +#define S32V234_CLK_PERIPHPLL_PHI0 5 +#define S32V234_CLK_PERIPHPLL_PHI0_DIV3 6 +#define S32V234_CLK_PERIPHPLL_PHI0_DIV5 7 +#define S32V234_CLK_PERIPHPLL_PHI1 8 +/* LINFlexD Clock */ +#define S32V234_CLK_LIN 9 +#define S32V234_CLK_LIN_SEL 10 +#define S32V234_CLK_LIN_IPG 11 +/* SDHC Clock */ +#define S32V234_CLK_SDHC 12 +#define S32V234_CLK_SDHC_SEL 13 +/* ENET PLL */ +#define S32V234_CLK_ENETPLL_SRC_SEL 14 +#define S32V234_CLK_ENETPLL_VCO 15 +#define S32V234_CLK_ENETPLL_PHI0 16 +#define S32V234_CLK_ENETPLL_PHI1 17 +#define S32V234_CLK_ENETPLL_DFS0 18 +#define S32V234_CLK_ENETPLL_DFS1 19 +#define S32V234_CLK_ENETPLL_DFS2 20 +#define S32V234_CLK_ENETPLL_DFS3 21 +/* System Clock */ +#define S32V234_CLK_SYS_SEL 22 +#define S32V234_CLK_SYS3 23 +#define S32V234_CLK_SYS6 24 +#define S32V234_CLK_SYS6_DIV2 25 +/* ENET Clock */ +#define S32V234_CLK_ENET_TIME_DIV 26 +#define S32V234_CLK_ENET_TIME_SEL 27 +#define S32V234_CLK_ENET_DIV 28 +#define S32V234_CLK_ENET_SEL 29 + +#define S32V234_CLK_ENET 30 +#define S32V234_CLK_ENET_TIME 31 + +/* ARM PLL */ +#define S32V234_CLK_ARMPLL_SRC_SEL 32 +#define S32V234_CLK_ARMPLL_VCO 33 +#define S32V234_CLK_ARMPLL_PHI0 34 +#define S32V234_CLK_ARMPLL_PHI1 35 +#define S32V234_CLK_ARMPLL_DFS0 35 +#define S32V234_CLK_ARMPLL_DFS1 36 +#define S32V234_CLK_ARMPLL_DFS2 37 + +/* CAN Clock */ +#define S32V234_CLK_CAN 38 +#define S32V234_CLK_CAN_SEL 39 + +#define S32V234_CLK_END 40 + +#endif /* __DT_BINDINGS_CLOCK_S32V234_H */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2fdfe8061363..30b61ec0e167 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -32,6 +32,7 @@ #define CLK_OPS_PARENT_ENABLE BIT(12) /* duty cycle call may be forwarded to the parent clock */ #define CLK_DUTY_CYCLE_PARENT BIT(13) +#define CLK_SET_PARENT_NOCACHE BIT(14) /* do not use the cached clk parent */ struct clk; struct clk_hw; diff --git a/include/soc/imx/gpc.h b/include/soc/imx/gpc.h new file mode 100644 index 000000000000..6a976e6aa3fe --- /dev/null +++ b/include/soc/imx/gpc.h @@ -0,0 +1,7 @@ +#ifndef __SOC_IMX_GPC_H +#define __SOC_IMX_GPC_H + +void imx_gpc_hold_m4_in_sleep(void); +void imx_gpc_release_m4_in_sleep(void); + +#endif /* __SOC_IMX_GPC_H */ diff --git a/include/soc/imx/src.h b/include/soc/imx/src.h new file mode 100644 index 000000000000..c55c34cd2366 --- /dev/null +++ b/include/soc/imx/src.h @@ -0,0 +1,6 @@ +#ifndef __SOC_IMX_SRC_H +#define __SOC_IMX_SRC_H + +bool imx_src_is_m4_enabled(void); + +#endif /* __SOC_IMX_SRC_H */ |