summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-10-07 08:51:10 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-10-07 08:51:10 +0200
commitc89e912efc4702e01bdf3bde140b5adc371d56b5 (patch)
treea188642f48be6a5baad56819a431112d0c36b34f /drivers
parent2da73f26645be6033840beec5611acfe241784b6 (diff)
parent35d4cf996034badd45b80c9fcd61e53036786421 (diff)
downloadbarebox-c89e912efc4702e01bdf3bde140b5adc371d56b5.tar.gz
barebox-c89e912efc4702e01bdf3bde140b5adc371d56b5.tar.xz
Merge branch 'for-next/imx'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/imx/Makefile2
-rw-r--r--drivers/clk/imx/clk-imx8mn.c558
-rw-r--r--drivers/ddr/imx8m/Kconfig2
-rw-r--r--drivers/ddr/imx8m/ddr_init.c8
-rw-r--r--drivers/ddr/imx8m/ddrphy_train.c26
-rw-r--r--drivers/ddr/imx8m/ddrphy_utils.c333
-rw-r--r--drivers/mci/imx-esdhc-pbl.c46
-rw-r--r--drivers/mci/imx-esdhc.c1
-rw-r--r--drivers/nvmem/ocotp.c3
-rw-r--r--drivers/pinctrl/imx-iomux-v3.c2
-rw-r--r--drivers/serial/serial_imx.c3
-rw-r--r--drivers/usb/imx/imx-usb-misc.c4
-rw-r--r--drivers/usb/imx/imx-usb-phy.c31
-rw-r--r--drivers/watchdog/imxwd.c16
14 files changed, 837 insertions, 198 deletions
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index bb6635d5e4..4a792422d5 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -28,8 +28,10 @@ obj-$(CONFIG_ARCH_IMX6SL) += clk-imx6sl.o
obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o
obj-$(CONFIG_ARCH_IMX7) += clk-imx7.o
pbl-$(CONFIG_ARCH_IMX8MM) += clk-pll14xx.o
+pbl-$(CONFIG_ARCH_IMX8MN) += clk-pll14xx.o
pbl-$(CONFIG_ARCH_IMX8MP) += clk-pll14xx.o
obj-$(CONFIG_ARCH_IMX8MM) += clk-imx8mm.o
+obj-$(CONFIG_ARCH_IMX8MN) += clk-imx8mn.o
obj-$(CONFIG_ARCH_IMX8MP) += clk-imx8mp.o
obj-$(CONFIG_ARCH_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_ARCH_VF610) += clk-vf610.o
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
new file mode 100644
index 0000000000..ffce907781
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018-2019 NXP.
+ */
+
+#include <dt-bindings/clock/imx8mn-clock.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <of_address.h>
+
+#include "clk.h"
+
+static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
+static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
+static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
+static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
+static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_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", };
+static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
+static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
+
+static const char * const imx8mn_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m",
+ "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
+ "audio_pll1_out", "sys_pll3_out", };
+
+static const char * const imx8mn_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
+
+static const char * const imx8mn_gpu_core_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mn_gpu_shader_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mn_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m",
+ "sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out",
+ "video_pll1_out", "sys_pll1_100m",};
+
+static const char * const imx8mn_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
+ "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out",
+ "video_pll1_out", "sys_pll3_out", };
+
+static const char * const imx8mn_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
+ "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
+ "sys_pll2_250m", "audio_pll1_out", };
+
+static const char * const imx8mn_disp_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
+ "clk_ext1", "clk_ext4", };
+
+static const char * const imx8mn_disp_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
+ "clk_ext1", "clk_ext3", };
+
+static const char * const imx8mn_usb_bus_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
+ "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+ "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mn_gpu_axi_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out",
+ "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mn_gpu_ahb_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out",
+ "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mn_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mn_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m",
+ "sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out",
+ "audio_pll1_out", "video_pll1_out", };
+
+static const char * const imx8mn_audio_ahb_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll2_166m", "sys_pll3_out",
+ "audio_pll1_out", "video_pll1_out", };
+
+static const char * const imx8mn_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m",
+ "sys_pll2_500m", "sys_pll2_1000m", "sys_pll3_out",
+ "audio_pll1_out", "sys_pll1_266m", };
+
+static const char * const imx8mn_dram_apb_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+ "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mn_disp_pixel_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out",
+ "audio_pll1_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll3_out", "clk_ext4", };
+
+static const char * const imx8mn_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+ "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+ "clk_ext3", "clk_ext4", };
+
+static const char * const imx8mn_sai3_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+ "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+ "clk_ext3", "clk_ext4", };
+
+static const char * const imx8mn_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+ "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+ "clk_ext2", "clk_ext3", };
+
+static const char * const imx8mn_sai6_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+ "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+ "clk_ext3", "clk_ext4", };
+
+static const char * const imx8mn_sai7_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+ "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+ "clk_ext3", "clk_ext4", };
+
+static const char * const imx8mn_spdif1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+ "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+ "clk_ext2", "clk_ext3", };
+
+static const char * const imx8mn_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
+ "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
+ "video_pll1_out", "clk_ext4", };
+
+static const char * const imx8mn_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
+ "clk_ext1", "clk_ext2", "clk_ext3",
+ "clk_ext4", "video_pll1_out", };
+
+static const char * const imx8mn_enet_phy_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m",
+ "sys_pll2_200m", "sys_pll2_500m", "video_pll1_out",
+ "audio_pll2_out", };
+
+static const char * const imx8mn_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out",
+ "sys_pll1_400m", "audio_pll2_out", "sys_pll3_out",
+ "sys_pll2_250m", "video_pll1_out", };
+
+static const char * const imx8mn_qspi_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll2_333m",
+ "sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m",
+ "sys_pll3_out", "sys_pll1_100m", };
+
+static const char * const imx8mn_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
+ "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
+ "audio_pll2_out", "sys_pll1_100m", };
+
+static const char * const imx8mn_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
+ "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
+ "audio_pll2_out", "sys_pll1_100m", };
+
+static const char * const imx8mn_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+ "sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+ "audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mn_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+ "sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+ "audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mn_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+ "sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+ "audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mn_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+ "sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+ "audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mn_uart1_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mn_uart2_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_uart3_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mn_uart4_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
+ "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
+ "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_gic_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+ "sys_pll2_100m", "sys_pll1_800m", "clk_ext2",
+ "clk_ext4", "audio_pll2_out" };
+
+static const char * const imx8mn_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+ "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mn_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+ "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mn_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+ "sys_pll1_40m", "sys_pll3_out", "clk_ext1",
+ "sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mn_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+ "sys_pll1_40m", "sys_pll3_out", "clk_ext1",
+ "sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mn_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+ "sys_pll1_40m", "sys_pll3_out", "clk_ext2",
+ "sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mn_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+ "sys_pll1_40m", "sys_pll3_out", "clk_ext2",
+ "sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mn_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m",
+ "vpu_pll_out", "sys_pll2_125m", "sys_pll3_out",
+ "sys_pll1_80m", "sys_pll2_166m", };
+
+static const char * const imx8mn_wrclk_sels[] = {"osc_24m", "sys_pll1_40m", "vpu_pll_out",
+ "sys_pll3_out", "sys_pll2_200m", "sys_pll1_266m",
+ "sys_pll2_500m", "sys_pll1_100m", };
+
+static const char * const imx8mn_dsi_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+ "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mn_dsi_phy_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_100m",
+ "sys_pll1_800m", "sys_pll2_1000m", "clk_ext2",
+ "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mn_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_100m",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+ "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mn_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
+ "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
+ "audio_pll2_out", "sys_pll1_100m", };
+
+static const char * const imx8mn_camera_pixel_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+ "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mn_csi1_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m",
+ "sys_pll1_800m", "sys_pll2_1000m", "clk_ext2",
+ "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mn_csi2_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m",
+ "sys_pll1_800m", "sys_pll2_1000m", "clk_ext2",
+ "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mn_csi2_esc_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+ "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mn_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
+
+static const char * const imx8mn_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m",
+ "sys_pll1_200m", "audio_pll2_out", "vpu_pll",
+ "sys_pll1_80m", };
+static const char * const imx8mn_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m",
+ "sys_pll2_166m", "sys_pll3_out", "audio_pll1_out",
+ "video_pll1_out", "osc_32k", };
+
+static const char * const clkout_sels[] = {"audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "dummy", "dummy", "gpu_pll_out", "dummy",
+ "arm_pll_out", "sys_pll1", "sys_pll2", "sys_pll3",
+ "dummy", "dummy", "osc_24m", "dummy", "osc_32k"};
+
+static struct clk *clks[IMX8MN_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static int imx8mn_clocks_init(struct device_node *ccm_np)
+{
+ struct device_node *anatop_np;
+ void __iomem *ccm, *ana;
+ int ret;
+
+ anatop_np = of_find_compatible_node(NULL, NULL, "fsl,imx8mn-anatop");
+ ana = of_iomap(anatop_np, 0);
+ if (WARN_ON(!ana))
+ return -ENOMEM;
+
+ ccm = of_iomap(ccm_np, 0);
+ if (WARN_ON(!ccm))
+ return -ENOMEM;
+
+ clks[IMX8MN_CLK_DUMMY] = clk_fixed("dummy", 0);
+ clks[IMX8MN_CLK_24M] = of_clk_get_by_name(ccm_np, "osc_24m");
+ clks[IMX8MN_CLK_32K] = of_clk_get_by_name(ccm_np, "osc_32k");
+ clks[IMX8MN_CLK_EXT1] = of_clk_get_by_name(ccm_np, "clk_ext1");
+ clks[IMX8MN_CLK_EXT2] = of_clk_get_by_name(ccm_np, "clk_ext2");
+ clks[IMX8MN_CLK_EXT3] = of_clk_get_by_name(ccm_np, "clk_ext3");
+ clks[IMX8MN_CLK_EXT4] = of_clk_get_by_name(ccm_np, "clk_ext4");
+
+ clks[IMX8MN_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", ana + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", ana + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", ana + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", ana + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", ana + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", ana + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", ana + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MN_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", ana + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+ clks[IMX8MN_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", ana, &imx_1443x_pll);
+ clks[IMX8MN_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", ana + 0x14, &imx_1443x_pll);
+ clks[IMX8MN_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", ana + 0x28, &imx_1443x_pll);
+ clks[IMX8MN_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", ana + 0x50, &imx_1443x_pll);
+ clks[IMX8MN_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", ana + 0x64, &imx_1416x_pll);
+ clks[IMX8MN_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", ana + 0x74, &imx_1416x_pll);
+ clks[IMX8MN_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", ana + 0x84, &imx_1416x_pll);
+ clks[IMX8MN_SYS_PLL1] = clk_fixed("sys_pll1", 800000000);
+ clks[IMX8MN_SYS_PLL2] = clk_fixed("sys_pll2", 1000000000);
+ clks[IMX8MN_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", ana + 0x114, &imx_1416x_pll);
+
+ /* PLL bypass out */
+ clks[IMX8MN_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", ana, 16, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_AUDIO_PLL2_BYPASS] = imx_clk_mux_flags("audio_pll2_bypass", ana + 0x14, 16, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_VIDEO_PLL1_BYPASS] = imx_clk_mux_flags("video_pll1_bypass", ana + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_DRAM_PLL_BYPASS] = imx_clk_mux_flags("dram_pll_bypass", ana + 0x50, 16, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_GPU_PLL_BYPASS] = imx_clk_mux_flags("gpu_pll_bypass", ana + 0x64, 28, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_VPU_PLL_BYPASS] = imx_clk_mux_flags("vpu_pll_bypass", ana + 0x74, 28, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", ana + 0x84, 28, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MN_SYS_PLL3_BYPASS] = imx_clk_mux_flags("sys_pll3_bypass", ana + 0x114, 28, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
+
+ /* PLL out gate */
+ clks[IMX8MN_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", ana, 13);
+ clks[IMX8MN_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", ana + 0x14, 13);
+ clks[IMX8MN_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", ana + 0x28, 13);
+ clks[IMX8MN_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", ana + 0x50, 13);
+ clks[IMX8MN_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", ana + 0x64, 11);
+ clks[IMX8MN_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", ana + 0x74, 11);
+ clks[IMX8MN_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", ana + 0x84, 11);
+ clks[IMX8MN_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", ana + 0x114, 11);
+
+ /* SYS PLL1 fixed output */
+ clks[IMX8MN_SYS_PLL1_40M_CG] = imx_clk_gate("sys_pll1_40m_cg", "sys_pll1", ana + 0x94, 27);
+ clks[IMX8MN_SYS_PLL1_80M_CG] = imx_clk_gate("sys_pll1_80m_cg", "sys_pll1", ana + 0x94, 25);
+ clks[IMX8MN_SYS_PLL1_100M_CG] = imx_clk_gate("sys_pll1_100m_cg", "sys_pll1", ana + 0x94, 23);
+ clks[IMX8MN_SYS_PLL1_133M_CG] = imx_clk_gate("sys_pll1_133m_cg", "sys_pll1", ana + 0x94, 21);
+ clks[IMX8MN_SYS_PLL1_160M_CG] = imx_clk_gate("sys_pll1_160m_cg", "sys_pll1", ana + 0x94, 19);
+ clks[IMX8MN_SYS_PLL1_200M_CG] = imx_clk_gate("sys_pll1_200m_cg", "sys_pll1", ana + 0x94, 17);
+ clks[IMX8MN_SYS_PLL1_266M_CG] = imx_clk_gate("sys_pll1_266m_cg", "sys_pll1", ana + 0x94, 15);
+ clks[IMX8MN_SYS_PLL1_400M_CG] = imx_clk_gate("sys_pll1_400m_cg", "sys_pll1", ana + 0x94, 13);
+ clks[IMX8MN_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1", ana + 0x94, 11);
+
+ clks[IMX8MN_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
+ clks[IMX8MN_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
+ clks[IMX8MN_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
+ clks[IMX8MN_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
+ clks[IMX8MN_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
+ clks[IMX8MN_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
+ clks[IMX8MN_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
+ clks[IMX8MN_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
+ clks[IMX8MN_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
+
+ /* SYS PLL2 fixed output */
+ clks[IMX8MN_SYS_PLL2_50M_CG] = imx_clk_gate("sys_pll2_50m_cg", "sys_pll2", ana + 0x104, 27);
+ clks[IMX8MN_SYS_PLL2_100M_CG] = imx_clk_gate("sys_pll2_100m_cg", "sys_pll2", ana + 0x104, 25);
+ clks[IMX8MN_SYS_PLL2_125M_CG] = imx_clk_gate("sys_pll2_125m_cg", "sys_pll2", ana + 0x104, 23);
+ clks[IMX8MN_SYS_PLL2_166M_CG] = imx_clk_gate("sys_pll2_166m_cg", "sys_pll2", ana + 0x104, 21);
+ clks[IMX8MN_SYS_PLL2_200M_CG] = imx_clk_gate("sys_pll2_200m_cg", "sys_pll2", ana + 0x104, 19);
+ clks[IMX8MN_SYS_PLL2_250M_CG] = imx_clk_gate("sys_pll2_250m_cg", "sys_pll2", ana + 0x104, 17);
+ clks[IMX8MN_SYS_PLL2_333M_CG] = imx_clk_gate("sys_pll2_333m_cg", "sys_pll2", ana + 0x104, 15);
+ clks[IMX8MN_SYS_PLL2_500M_CG] = imx_clk_gate("sys_pll2_500m_cg", "sys_pll2", ana + 0x104, 13);
+ clks[IMX8MN_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2", ana + 0x104, 11);
+
+ clks[IMX8MN_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
+ clks[IMX8MN_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
+ clks[IMX8MN_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
+ clks[IMX8MN_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
+ clks[IMX8MN_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
+ clks[IMX8MN_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
+ clks[IMX8MN_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
+ clks[IMX8MN_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
+ clks[IMX8MN_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+
+ clks[IMX8MN_CLK_CLKOUT1_SEL] = imx_clk_mux("clkout1_sel", ana + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
+ clks[IMX8MN_CLK_CLKOUT1_DIV] = imx_clk_divider("clkout1_div", "clkout1_sel", ana + 0x128, 0, 4);
+ clks[IMX8MN_CLK_CLKOUT1] = imx_clk_gate("clkout1", "clkout1_div", ana + 0x128, 8);
+ clks[IMX8MN_CLK_CLKOUT2_SEL] = imx_clk_mux("clkout2_sel", ana + 0x128, 20, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
+ clks[IMX8MN_CLK_CLKOUT2_DIV] = imx_clk_divider("clkout2_div", "clkout2_sel", ana + 0x128, 16, 4);
+ clks[IMX8MN_CLK_CLKOUT2] = imx_clk_gate("clkout2", "clkout2_div", ana + 0x128, 24);
+
+ /* CORE */
+ clks[IMX8MN_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", ccm + 0x8000, 24, 3, imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels));
+ clks[IMX8MN_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", ccm + 0x8180, 24, 3, imx8mn_gpu_core_sels, ARRAY_SIZE(imx8mn_gpu_core_sels));
+ clks[IMX8MN_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", ccm + 0x8200, 24, 3, imx8mn_gpu_shader_sels, ARRAY_SIZE(imx8mn_gpu_shader_sels));
+ clks[IMX8MN_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", ccm + 0x8000, 28);
+ clks[IMX8MN_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", ccm + 0x8180, 28);
+ clks[IMX8MN_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", ccm + 0x8200, 28);
+
+ clks[IMX8MN_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", ccm + 0x8000, 0, 3);
+ clks[IMX8MN_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", ccm + 0x8180, 0, 3);
+ clks[IMX8MN_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", ccm + 0x8200, 0, 3);
+
+ /* CORE SEL */
+ clks[IMX8MN_CLK_A53_CORE] = imx_clk_mux2("arm_a53_core", ccm + 0x9880, 24, 1, imx8mn_a53_core_sels, ARRAY_SIZE(imx8mn_a53_core_sels));
+
+ /* BUS */
+ clks[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mn_main_axi_sels, ccm + 0x8800);
+ clks[IMX8MN_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mn_enet_axi_sels, ccm + 0x8880);
+ clks[IMX8MN_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mn_nand_usdhc_sels, ccm + 0x8900);
+ clks[IMX8MN_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mn_disp_axi_sels, ccm + 0x8a00);
+ clks[IMX8MN_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mn_disp_apb_sels, ccm + 0x8a80);
+ clks[IMX8MN_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mn_usb_bus_sels, ccm + 0x8b80);
+ clks[IMX8MN_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mn_gpu_axi_sels, ccm + 0x8c00);
+ clks[IMX8MN_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mn_gpu_ahb_sels, ccm + 0x8c80);
+ clks[IMX8MN_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mn_noc_sels, ccm + 0x8d00);
+
+ clks[IMX8MN_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mn_ahb_sels, ccm + 0x9000);
+ clks[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mn_audio_ahb_sels, ccm + 0x9100);
+ clks[IMX8MN_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", ccm + 0x9080, 0, 1);
+ clks[IMX8MN_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", ccm + 0x9180, 0, 1);
+ clks[IMX8MN_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", ccm + 0x9800, 24, 1, imx8mn_dram_core_sels, ARRAY_SIZE(imx8mn_dram_core_sels), CLK_IS_CRITICAL);
+
+ /*
+ * DRAM clocks are manipulated from TF-A outside clock framework.
+ * Mark with GET_RATE_NOCACHE to always read div value from hardware
+ */
+ clks[IMX8MN_CLK_DRAM_ALT] = __imx8m_clk_composite("dram_alt", imx8mn_dram_alt_sels, ccm + 0xa000, CLK_GET_RATE_NOCACHE);
+ clks[IMX8MN_CLK_DRAM_APB] = __imx8m_clk_composite("dram_apb", imx8mn_dram_apb_sels, ccm + 0xa080, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
+
+ clks[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_composite("disp_pixel", imx8mn_disp_pixel_sels, ccm + 0xa500);
+ clks[IMX8MN_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mn_sai2_sels, ccm + 0xa600);
+ clks[IMX8MN_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mn_sai3_sels, ccm + 0xa680);
+ clks[IMX8MN_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mn_sai5_sels, ccm + 0xa780);
+ clks[IMX8MN_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mn_sai6_sels, ccm + 0xa800);
+ clks[IMX8MN_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mn_spdif1_sels, ccm + 0xa880);
+ clks[IMX8MN_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels, ccm + 0xa980);
+ clks[IMX8MN_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mn_enet_timer_sels, ccm + 0xaa00);
+ clks[IMX8MN_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mn_enet_phy_sels, ccm + 0xaa80);
+ clks[IMX8MN_CLK_NAND] = imx8m_clk_composite("nand", imx8mn_nand_sels, ccm + 0xab00);
+ clks[IMX8MN_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mn_qspi_sels, ccm + 0xab80);
+ clks[IMX8MN_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mn_usdhc1_sels, ccm + 0xac00);
+ clks[IMX8MN_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mn_usdhc2_sels, ccm + 0xac80);
+ clks[IMX8MN_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mn_i2c1_sels, ccm + 0xad00);
+ clks[IMX8MN_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mn_i2c2_sels, ccm + 0xad80);
+ clks[IMX8MN_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mn_i2c3_sels, ccm + 0xae00);
+ clks[IMX8MN_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mn_i2c4_sels, ccm + 0xae80);
+ clks[IMX8MN_CLK_UART1] = imx8m_clk_composite("uart1", imx8mn_uart1_sels, ccm + 0xaf00);
+ clks[IMX8MN_CLK_UART2] = imx8m_clk_composite("uart2", imx8mn_uart2_sels, ccm + 0xaf80);
+ clks[IMX8MN_CLK_UART3] = imx8m_clk_composite("uart3", imx8mn_uart3_sels, ccm + 0xb000);
+ clks[IMX8MN_CLK_UART4] = imx8m_clk_composite("uart4", imx8mn_uart4_sels, ccm + 0xb080);
+ clks[IMX8MN_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mn_usb_core_sels, ccm + 0xb100);
+ clks[IMX8MN_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mn_usb_phy_sels, ccm + 0xb180);
+ clks[IMX8MN_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mn_gic_sels, ccm + 0xb200);
+ clks[IMX8MN_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mn_ecspi1_sels, ccm + 0xb280);
+ clks[IMX8MN_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mn_ecspi2_sels, ccm + 0xb300);
+ clks[IMX8MN_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mn_pwm1_sels, ccm + 0xb380);
+ clks[IMX8MN_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mn_pwm2_sels, ccm + 0xb400);
+ clks[IMX8MN_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mn_pwm3_sels, ccm + 0xb480);
+ clks[IMX8MN_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mn_pwm4_sels, ccm + 0xb500);
+ clks[IMX8MN_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mn_wdog_sels, ccm + 0xb900);
+ clks[IMX8MN_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mn_wrclk_sels, ccm + 0xb980);
+ clks[IMX8MN_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mn_clko1_sels, ccm + 0xba00);
+ clks[IMX8MN_CLK_CLKO2] = imx8m_clk_composite("clko2", imx8mn_clko2_sels, ccm + 0xba80);
+ clks[IMX8MN_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mn_dsi_core_sels, ccm + 0xbb00);
+ clks[IMX8MN_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mn_dsi_phy_sels, ccm + 0xbb80);
+ clks[IMX8MN_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mn_dsi_dbi_sels, ccm + 0xbc00);
+ clks[IMX8MN_CLK_USDHC3] = imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels, ccm + 0xbc80);
+ clks[IMX8MN_CLK_CAMERA_PIXEL] = imx8m_clk_composite("camera_pixel", imx8mn_camera_pixel_sels, ccm + 0xbd00);
+ clks[IMX8MN_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mn_csi1_phy_sels, ccm + 0xbd80);
+ clks[IMX8MN_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mn_csi2_phy_sels, ccm + 0xbf00);
+ clks[IMX8MN_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mn_csi2_esc_sels, ccm + 0xbf80);
+ clks[IMX8MN_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mn_ecspi3_sels, ccm + 0xc180);
+ clks[IMX8MN_CLK_PDM] = imx8m_clk_composite("pdm", imx8mn_pdm_sels, ccm + 0xc200);
+ clks[IMX8MN_CLK_SAI7] = imx8m_clk_composite("sai7", imx8mn_sai7_sels, ccm + 0xc300);
+
+ clks[IMX8MN_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", ccm + 0x4070, 0);
+ clks[IMX8MN_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", ccm + 0x4080, 0);
+ clks[IMX8MN_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", ccm + 0x4090, 0);
+ clks[IMX8MN_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", ccm + 0x40a0, 0);
+ clks[IMX8MN_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", ccm + 0x40b0, 0);
+ clks[IMX8MN_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", ccm + 0x40c0, 0);
+ clks[IMX8MN_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", ccm + 0x40d0, 0);
+ clks[IMX8MN_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", ccm + 0x40e0, 0);
+ clks[IMX8MN_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", ccm + 0x40f0, 0);
+ clks[IMX8MN_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", ccm + 0x4170, 0);
+ clks[IMX8MN_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", ccm + 0x4180, 0);
+ clks[IMX8MN_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", ccm + 0x4190, 0);
+ clks[IMX8MN_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", ccm + 0x41a0, 0);
+ clks[IMX8MN_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", ccm + 0x4210, 0);
+ clks[IMX8MN_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", ccm + 0x4220, 0);
+ clks[IMX8MN_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", ccm + 0x4280, 0);
+ clks[IMX8MN_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", ccm + 0x4290, 0);
+ clks[IMX8MN_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", ccm + 0x42a0, 0);
+ clks[IMX8MN_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", ccm + 0x42b0, 0);
+ clks[IMX8MN_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", ccm + 0x42f0, 0);
+ clks[IMX8MN_CLK_NAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", ccm + 0x4300, 0);
+ clks[IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", ccm + 0x4300, 0);
+ clks[IMX8MN_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", ccm + 0x4340, 0);
+ clks[IMX8MN_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", ccm + 0x4340, 0);
+ clks[IMX8MN_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", ccm + 0x4350, 0);
+ clks[IMX8MN_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", ccm + 0x4350, 0);
+ clks[IMX8MN_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", ccm + 0x4370, 0);
+ clks[IMX8MN_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", ccm + 0x4370, 0);
+ clks[IMX8MN_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", ccm + 0x4380, 0);
+ clks[IMX8MN_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", ccm + 0x4380, 0);
+ clks[IMX8MN_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", ccm + 0x4470, 0);
+ clks[IMX8MN_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", ccm + 0x4490, 0);
+ clks[IMX8MN_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", ccm + 0x44a0, 0);
+ clks[IMX8MN_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", ccm + 0x44b0, 0);
+ clks[IMX8MN_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", ccm + 0x44c0, 0);
+ clks[IMX8MN_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", ccm + 0x44d0, 0);
+ clks[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_gate4("gpu_core_root_clk", "gpu_core_div", ccm + 0x44f0, 0);
+ clks[IMX8MN_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", ccm + 0x4510, 0);
+ clks[IMX8MN_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", ccm + 0x4520, 0);
+ clks[IMX8MN_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", ccm + 0x4530, 0);
+ clks[IMX8MN_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", ccm + 0x4540, 0);
+ clks[IMX8MN_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", ccm + 0x4550, 0);
+ clks[IMX8MN_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi", ccm + 0x4570, 0);
+ clks[IMX8MN_CLK_ASRC_ROOT] = imx_clk_gate4("asrc_root_clk", "audio_ahb", ccm + 0x4580, 0);
+ clks[IMX8MN_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm", ccm + 0x45b0, 0);
+ clks[IMX8MN_CLK_PDM_IPG] = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", ccm + 0x45b0, 0);
+ clks[IMX8MN_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", ccm + 0x45d0, 0);
+ clks[IMX8MN_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", ccm + 0x45d0, 0);
+ clks[IMX8MN_CLK_CAMERA_PIXEL_ROOT] = imx_clk_gate2_shared2("camera_pixel_clk", "camera_pixel", ccm + 0x45d0, 0);
+ clks[IMX8MN_CLK_DISP_PIXEL_ROOT] = imx_clk_gate2_shared2("disp_pixel_clk", "disp_pixel", ccm + 0x45d0, 0);
+ clks[IMX8MN_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3", ccm + 0x45e0, 0);
+ clks[IMX8MN_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", ccm + 0x4620, 0);
+ clks[IMX8MN_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", ccm + 0x43a0, 0);
+ clks[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", ccm + 0x43b0, 0);
+ clks[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", ccm + 0x45f0, 0);
+ clks[IMX8MN_CLK_SAI7_ROOT] = imx_clk_gate2_shared2("sai7_root_clk", "sai7", ccm + 0x4650, 0);
+
+ clks[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
+
+ clks[IMX8MN_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_core",
+ clks[IMX8MN_CLK_A53_CORE],
+ clks[IMX8MN_CLK_A53_CORE],
+ clks[IMX8MN_ARM_PLL_OUT],
+ clks[IMX8MN_CLK_A53_DIV]);
+
+ imx_check_clocks(clks, ARRAY_SIZE(clks));
+
+ clk_enable(clks[IMX8MN_SYS_PLL3_OUT]);
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+
+ ret = of_clk_add_provider(ccm_np, of_clk_src_onecell_get, &clk_data);
+ if (ret < 0)
+ pr_err("failed to register clks for i.MX8MN\n");
+
+ return ret;
+}
+CLK_OF_DECLARE(imx8mn, "fsl,imx8mn-ccm", imx8mn_clocks_init);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8MN clock driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ddr/imx8m/Kconfig b/drivers/ddr/imx8m/Kconfig
index 7673ab5b4c..efc50c21d4 100644
--- a/drivers/ddr/imx8m/Kconfig
+++ b/drivers/ddr/imx8m/Kconfig
@@ -1,5 +1,5 @@
menu "i.MX8M DDR controllers"
- depends on ARCH_IMX8MQ || ARCH_IMX8MM || ARCH_IMX8MP
+ depends on ARCH_IMX8MQ || ARCH_IMX8MM || ARCH_IMX8MN || ARCH_IMX8MP
config IMX8M_DRAM
bool "imx8m dram controller support"
diff --git a/drivers/ddr/imx8m/ddr_init.c b/drivers/ddr/imx8m/ddr_init.c
index 34da44af64..95ac76efcd 100644
--- a/drivers/ddr/imx8m/ddr_init.c
+++ b/drivers/ddr/imx8m/ddr_init.c
@@ -48,6 +48,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing,
reg32_write(src_ddrc_rcr + 0x04, 0x8f000000);
break;
case DDRC_TYPE_MM:
+ case DDRC_TYPE_MN:
case DDRC_TYPE_MP:
reg32_write(src_ddrc_rcr, 0x8f00001f);
reg32_write(src_ddrc_rcr, 0x8f00000f);
@@ -88,7 +89,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing,
/* if ddr type is LPDDR4, do it */
tmp = reg32_read(DDRC_MSTR(0));
- if (tmp & (0x1 << 5))
+ if (tmp & (0x1 << 5) && type != DDRC_TYPE_MN)
reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
/* determine the initial boot frequency */
@@ -197,6 +198,11 @@ int imx8mm_ddr_init(struct dram_timing_info *dram_timing)
return imx8m_ddr_init(dram_timing, DDRC_TYPE_MM);
}
+int imx8mn_ddr_init(struct dram_timing_info *dram_timing)
+{
+ return imx8m_ddr_init(dram_timing, DDRC_TYPE_MN);
+}
+
int imx8mq_ddr_init(struct dram_timing_info *dram_timing)
{
return imx8m_ddr_init(dram_timing, DDRC_TYPE_MQ);
diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx8m/ddrphy_train.c
index a4677f903c..d930a2fffe 100644
--- a/drivers/ddr/imx8m/ddrphy_train.c
+++ b/drivers/ddr/imx8m/ddrphy_train.c
@@ -11,17 +11,29 @@
#include <firmware.h>
#include <mach/imx8m-regs.h>
-void ddr_load_train_code(enum fw_type type)
+void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type)
{
const u16 *imem, *dmem;
size_t isize, dsize;
- if (type == FW_1D_IMAGE) {
- get_builtin_firmware(lpddr4_pmu_train_1d_imem_bin, &imem, &isize);
- get_builtin_firmware(lpddr4_pmu_train_1d_dmem_bin, &dmem, &dsize);
+ if (dram_is_lpddr4(dram_type)) {
+ if (fw_type == FW_1D_IMAGE) {
+ get_builtin_firmware(lpddr4_pmu_train_1d_imem_bin, &imem, &isize);
+ get_builtin_firmware(lpddr4_pmu_train_1d_dmem_bin, &dmem, &dsize);
+ } else {
+ get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &imem, &isize);
+ get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &dmem, &dsize);
+ }
+ } else if (dram_is_ddr4(dram_type)) {
+ if (fw_type == FW_1D_IMAGE) {
+ get_builtin_firmware(ddr4_imem_1d_bin, &imem, &isize);
+ get_builtin_firmware(ddr4_dmem_1d_bin, &dmem, &dsize);
+ } else {
+ get_builtin_firmware(ddr4_imem_2d_bin, &imem, &isize);
+ get_builtin_firmware(ddr4_dmem_2d_bin, &dmem, &dsize);
+ }
} else {
- get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &imem, &isize);
- get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &dmem, &dsize);
+ panic("No matching DDR PHY firmware found");
}
ddrc_phy_load_firmware(IOMEM(MX8M_DDRC_PHY_BASE_ADDR),
@@ -58,7 +70,7 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing, enum ddrc_type type)
/* load the dram training firmware image */
dwc_ddrphy_apb_wr(0xd0000, 0x0);
- ddr_load_train_code(fsp_msg->fw_type);
+ ddr_load_train_code(dram_timing->dram_type, fsp_msg->fw_type);
/* load the frequency set point message block parameter */
dram_cfg = fsp_msg->fsp_cfg;
diff --git a/drivers/ddr/imx8m/ddrphy_utils.c b/drivers/ddr/imx8m/ddrphy_utils.c
index 9a4e1a22ee..79bb76c35a 100644
--- a/drivers/ddr/imx8m/ddrphy_utils.c
+++ b/drivers/ddr/imx8m/ddrphy_utils.c
@@ -13,6 +13,109 @@
#include <mach/imx8m-regs.h>
#include <mach/imx8m-ccm-regs.h>
+/* DDR Transfer rate, bus clock is transfer rate / 2, and the DDRC runs at bus
+ * clock / 2, which is therefor transfer rate / 4. */
+enum ddr_rate {
+ DDR_4000,
+ DDR_3200,
+ DDR_3000,
+ DDR_2600, /* Unused */
+ DDR_2400,
+ DDR_2376, /* Unused */
+ DDR_1600,
+ DDR_1000, /* Unused */
+ DDR_1066,
+ DDR_667,
+ DDR_400,
+ DDR_250, /* Unused */
+ DDR_100,
+ DDR_NUM_RATES
+};
+
+/* PLL config for IMX8MM type DRAM PLL. This PLL type isn't documented, but
+ * it looks like it is a basically a fractional PLL:
+ * Frequency = Ref (24 MHz) / P * M / 2^S
+ * Note: Divider is equal to register value
+ */
+#define MDIV(x) ((x) << 12)
+#define PDIV(x) ((x) << 4)
+#define SDIV(x) ((x) << 0)
+
+#define LOCK_STATUS BIT(31)
+#define LOCK_SEL_MASK BIT(29)
+#define CLKE_MASK BIT(11)
+#define RST_MASK BIT(9)
+#define BYPASS_MASK BIT(4)
+
+static const struct imx8mm_fracpll_config {
+ uint32_t r1, r2;
+ bool valid;
+} imx8mm_fracpll_table[DDR_NUM_RATES] = {
+ [DDR_4000] = { .valid = true, .r1 = MDIV(250) | PDIV(3) | SDIV(1), .r2 = 0 },
+ [DDR_3200] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(0), .r2 = 0 },
+ [DDR_3000] = { .valid = true, .r1 = MDIV(250) | PDIV(8) | SDIV(0), .r2 = 0 },
+ [DDR_2600] = { .valid = true, .r1 = MDIV(325) | PDIV(3) | SDIV(2), .r2 = 0 },
+ [DDR_2400] = { .valid = true, .r1 = MDIV(300) | PDIV(3) | SDIV(2), .r2 = 0 },
+ [DDR_2376] = { .valid = true, .r1 = MDIV( 99) | PDIV(1) | SDIV(2), .r2 = 0 },
+ [DDR_1600] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(1), .r2 = 0 },
+ [DDR_1066] = { .valid = true, .r1 = MDIV(400) | PDIV(9) | SDIV(2), .r2 = 0 },
+ [DDR_667] = { .valid = true, .r1 = MDIV(334) | PDIV(3) | SDIV(4), .r2 = 0 },
+ [DDR_400] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(3), .r2 = 0 },
+};
+
+/* PLL config for IMX8MQ type DRAM PLL. This is SSCG_PLL:
+ * Frequency = Ref (25 MHz) / divr1 * (2*divf1) / divr2 * divf2 / divq
+ * Note: IMX8MQ RM, §5.1.5.4.4 Fig. 5-8 shows ÷2 on divf2, but this is not true.
+ * Note: divider is register value + 1
+ */
+#define SSCG_PLL_LOCK BIT(31)
+#define SSCG_PLL_DRAM_PLL_CLKE BIT(9)
+#define SSCG_PLL_PD BIT(7)
+#define SSCG_PLL_BYPASS1 BIT(5)
+#define SSCG_PLL_BYPASS2 BIT(4)
+
+#define SSCG_PLL_REF_DIVR2_MASK (0x3f << 19)
+#define SSCG_PLL_REF_DIVR2_VAL(n) (((n) << 19) & SSCG_PLL_REF_DIVR2_MASK)
+#define SSCG_PLL_FEEDBACK_DIV_F1_MASK (0x3f << 13)
+#define SSCG_PLL_FEEDBACK_DIV_F1_VAL(n) (((n) << 13) & SSCG_PLL_FEEDBACK_DIV_F1_MASK)
+#define SSCG_PLL_FEEDBACK_DIV_F2_MASK (0x3f << 7)
+#define SSCG_PLL_FEEDBACK_DIV_F2_VAL(n) (((n) << 7) & SSCG_PLL_FEEDBACK_DIV_F2_MASK)
+#define SSCG_PLL_OUTPUT_DIV_VAL_MASK (0x3f << 1)
+#define SSCG_PLL_OUTPUT_DIV_VAL(n) (((n) << 1) & SSCG_PLL_OUTPUT_DIV_VAL_MASK)
+
+#define SSCG_PLL_CFG2(divf1, divr2, divf2, divq) \
+ (SSCG_PLL_FEEDBACK_DIV_F1_VAL(divf1) | SSCG_PLL_FEEDBACK_DIV_F2_VAL(divf2) | \
+ SSCG_PLL_REF_DIVR2_VAL(divr2) | SSCG_PLL_OUTPUT_DIV_VAL(divq))
+
+static const struct imx8mq_ssgcpll_config {
+ uint32_t val;
+ bool valid;
+} imx8mq_ssgcpll_table[DDR_NUM_RATES] = {
+ [DDR_3200] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 11, 0) },
+ [DDR_2400] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 17, 1) },
+ [DDR_1600] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 11, 1) },
+ [DDR_667] = { .valid = true, .val = SSCG_PLL_CFG2(45, 30, 8, 3) }, /* ~166.935 MHz = 667.74 */
+};
+
+/* IMX8M Bypass clock config. These configure dram_alt1_clk and the dram apb
+ * clock. For the bypass config, clock rate = DRAM tranfer rate, rather than
+ * clock = dram / 4
+ */
+
+/* prediv is actual divider, register will be set to divider - 1 */
+#define CCM_ROOT_CFG(mux, prediv) (IMX8M_CCM_TARGET_ROOTn_ENABLE | \
+ IMX8M_CCM_TARGET_ROOTn_MUX(mux) | IMX8M_CCM_TARGET_ROOTn_PRE_DIV(prediv-1))
+
+static const struct imx8m_bypass_config {
+ uint32_t alt_clk;
+ uint32_t apb_clk;
+ bool valid;
+} imx8m_bypass_table[DDR_NUM_RATES] = {
+ [DDR_400] = { .valid = true, .alt_clk = CCM_ROOT_CFG(1, 2), .apb_clk = CCM_ROOT_CFG(3, 2) },
+ [DDR_250] = { .valid = true, .alt_clk = CCM_ROOT_CFG(3, 2), .apb_clk = CCM_ROOT_CFG(2, 2) },
+ [DDR_100] = { .valid = true, .alt_clk = CCM_ROOT_CFG(2, 1), .apb_clk = CCM_ROOT_CFG(2, 2) },
+};
+
void ddrc_phy_load_firmware(void __iomem *phy,
enum ddrc_phy_firmware_offset offset,
const u16 *blob, size_t size)
@@ -102,64 +205,18 @@ int wait_ddrphy_training_complete(void)
}
}
-struct dram_bypass_clk_setting {
- ulong clk;
- int alt_root_sel;
- int alt_pre_div;
- int apb_root_sel;
- int apb_pre_div;
-};
-
-#define MHZ(x) (1000000UL * (x))
-
-static struct dram_bypass_clk_setting imx8mq_dram_bypass_tbl[] = {
- {
- .clk = MHZ(100),
- .alt_root_sel = 2,
- .alt_pre_div = 1 - 1,
- .apb_root_sel = 2,
- .apb_pre_div = 2 - 1,
- } , {
- .clk = MHZ(250),
- .alt_root_sel = 3,
- .alt_pre_div = 2 - 1,
- .apb_root_sel = 2,
- .apb_pre_div = 2 - 1,
- }, {
- .clk = MHZ(400),
- .alt_root_sel = 1,
- .alt_pre_div = 2 - 1,
- .apb_root_sel = 3,
- .apb_pre_div = 2 - 1,
- },
-};
-
-static void dram_enable_bypass(ulong clk_val)
+static void dram_enable_bypass(enum ddr_rate drate)
{
- int i;
- struct dram_bypass_clk_setting *config;
+ const struct imx8m_bypass_config *config = &imx8m_bypass_table[drate];
- for (i = 0; i < ARRAY_SIZE(imx8mq_dram_bypass_tbl); i++) {
- if (clk_val == imx8mq_dram_bypass_tbl[i].clk)
- break;
- }
-
- if (i == ARRAY_SIZE(imx8mq_dram_bypass_tbl)) {
- printf("No matched freq table %lu\n", clk_val);
+ if (!config->valid) {
+ printf("No matched freq table entry %u\n", drate);
return;
}
- config = &imx8mq_dram_bypass_tbl[i];
-
- imx8m_clock_set_target_val(IMX8M_DRAM_ALT_CLK_ROOT,
- IMX8M_CCM_TARGET_ROOTn_ENABLE |
- IMX8M_CCM_TARGET_ROOTn_MUX(config->alt_root_sel) |
- IMX8M_CCM_TARGET_ROOTn_PRE_DIV(config->alt_pre_div));
- imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT,
- IMX8M_CCM_TARGET_ROOTn_ENABLE |
- IMX8M_CCM_TARGET_ROOTn_MUX(config->apb_root_sel) |
- IMX8M_CCM_TARGET_ROOTn_PRE_DIV(config->apb_pre_div));
- imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG, IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ imx8m_clock_set_target_val(IMX8M_DRAM_ALT_CLK_ROOT, config->alt_clk);
+ imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT, config->apb_clk);
+ imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG, IMX8M_CCM_TARGET_ROOTn_ENABLE |
IMX8M_CCM_TARGET_ROOTn_MUX(1));
}
@@ -174,56 +231,15 @@ static void dram_disable_bypass(void)
IMX8M_CCM_TARGET_ROOTn_PRE_DIV(5 - 1));
}
-struct imx_int_pll_rate_table {
- u32 rate;
- u32 r1;
- u32 r2;
-};
-
-#define MDIV(x) ((x) << 12)
-#define PDIV(x) ((x) << 4)
-#define SDIV(x) ((x) << 0)
-
-#define LOCK_STATUS BIT(31)
-#define LOCK_SEL_MASK BIT(29)
-#define CLKE_MASK BIT(11)
-#define RST_MASK BIT(9)
-#define BYPASS_MASK BIT(4)
-
-static struct imx_int_pll_rate_table imx8mm_fracpll_tbl[] = {
- { .rate = 1000000000U, .r1 = MDIV(250) | PDIV(3) | SDIV(1), .r2 = 0 },
- { .rate = 800000000U, .r1 = MDIV(300) | PDIV(9) | SDIV(0), .r2 = 0 },
- { .rate = 750000000U, .r1 = MDIV(250) | PDIV(8) | SDIV(0), .r2 = 0 },
- { .rate = 650000000U, .r1 = MDIV(325) | PDIV(3) | SDIV(2), .r2 = 0 },
- { .rate = 600000000U, .r1 = MDIV(300) | PDIV(3) | SDIV(2), .r2 = 0 },
- { .rate = 594000000U, .r1 = MDIV( 99) | PDIV(1) | SDIV(2), .r2 = 0 },
- { .rate = 400000000U, .r1 = MDIV(300) | PDIV(9) | SDIV(1), .r2 = 0 },
- { .rate = 266666667U, .r1 = MDIV(400) | PDIV(9) | SDIV(2), .r2 = 0 },
- { .rate = 167000000U, .r1 = MDIV(334) | PDIV(3) | SDIV(4), .r2 = 0 },
- { .rate = 100000000U, .r1 = MDIV(300) | PDIV(9) | SDIV(3), .r2 = 0 },
-};
-
-static struct imx_int_pll_rate_table *fracpll(u32 freq)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(imx8mm_fracpll_tbl); i++)
- if (freq == imx8mm_fracpll_tbl[i].rate)
- return &imx8mm_fracpll_tbl[i];
-
- return NULL;
-}
-
-static int dram_frac_pll_init(u32 freq)
+static int dram_frac_pll_init(enum ddr_rate drate)
{
volatile int i;
u32 tmp;
void *pll_base;
- struct imx_int_pll_rate_table *rate;
+ const struct imx8mm_fracpll_config *config = &imx8mm_fracpll_table[drate];
- rate = fracpll(freq);
- if (!rate) {
- printf("No matched freq table %u\n", freq);
+ if (!config->valid) {
+ printf("No matched freq table entry %u\n", drate);
return -EINVAL;
}
@@ -242,8 +258,8 @@ static int dram_frac_pll_init(u32 freq)
tmp &= ~RST_MASK;
writel(tmp, pll_base);
- writel(rate->r1, pll_base + 4);
- writel(rate->r2, pll_base + 8);
+ writel(config->r1, pll_base + 4);
+ writel(config->r2, pll_base + 8);
for (i = 0; i < 1000; i++);
@@ -261,25 +277,16 @@ static int dram_frac_pll_init(u32 freq)
return 0;
}
-#define SSCG_PLL_LOCK BIT(31)
-#define SSCG_PLL_DRAM_PLL_CLKE BIT(9)
-#define SSCG_PLL_PD BIT(7)
-#define SSCG_PLL_BYPASS1 BIT(5)
-#define SSCG_PLL_BYPASS2 BIT(4)
-
-#define SSCG_PLL_REF_DIVR2_MASK (0x3f << 19)
-#define SSCG_PLL_REF_DIVR2_VAL(n) (((n) << 19) & SSCG_PLL_REF_DIVR2_MASK)
-#define SSCG_PLL_FEEDBACK_DIV_F1_MASK (0x3f << 13)
-#define SSCG_PLL_FEEDBACK_DIV_F1_VAL(n) (((n) << 13) & SSCG_PLL_FEEDBACK_DIV_F1_MASK)
-#define SSCG_PLL_FEEDBACK_DIV_F2_MASK (0x3f << 7)
-#define SSCG_PLL_FEEDBACK_DIV_F2_VAL(n) (((n) << 7) & SSCG_PLL_FEEDBACK_DIV_F2_MASK)
-#define SSCG_PLL_OUTPUT_DIV_VAL_MASK (0x3f << 1)
-#define SSCG_PLL_OUTPUT_DIV_VAL(n) (((n) << 1) & SSCG_PLL_OUTPUT_DIV_VAL_MASK)
-
-static int dram_sscg_pll_init(u32 freq)
+static int dram_sscg_pll_init(enum ddr_rate drate)
{
u32 val;
void __iomem *pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x60;
+ const struct imx8mq_ssgcpll_config *config = &imx8mq_ssgcpll_table[drate];
+
+ if (!config->valid) {
+ printf("No matched freq table entry %u\n", drate);
+ return -EINVAL;
+ }
/* Bypass */
setbits_le32(pll_base, SSCG_PLL_BYPASS1 | SSCG_PLL_BYPASS2);
@@ -289,36 +296,7 @@ static int dram_sscg_pll_init(u32 freq)
SSCG_PLL_FEEDBACK_DIV_F2_MASK |
SSCG_PLL_FEEDBACK_DIV_F1_MASK |
SSCG_PLL_REF_DIVR2_MASK);
-
- switch (freq) {
- case MHZ(800):
- val |= SSCG_PLL_OUTPUT_DIV_VAL(0);
- val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(11);
- val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39);
- val |= SSCG_PLL_REF_DIVR2_VAL(29);
- break;
- case MHZ(600):
- val |= SSCG_PLL_OUTPUT_DIV_VAL(1);
- val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(17);
- val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39);
- val |= SSCG_PLL_REF_DIVR2_VAL(29);
- break;
- case MHZ(400):
- val |= SSCG_PLL_OUTPUT_DIV_VAL(1);
- val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(11);
- val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39);
- val |= SSCG_PLL_REF_DIVR2_VAL(29);
- break;
- case MHZ(167):
- val |= SSCG_PLL_OUTPUT_DIV_VAL(3);
- val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(8);
- val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(45);
- val |= SSCG_PLL_REF_DIVR2_VAL(30);
- break;
- default:
- break;
- }
-
+ val |= config->val;
writel(val, pll_base + 0x8);
/* Clear power down bit */
@@ -337,59 +315,44 @@ static int dram_sscg_pll_init(u32 freq)
return 0;
}
-static int dram_pll_init(u32 freq, enum ddrc_type type)
+static int dram_pll_init(enum ddr_rate drate, enum ddrc_type type)
{
switch (type) {
case DDRC_TYPE_MQ:
- return dram_sscg_pll_init(freq);
+ return dram_sscg_pll_init(drate);
case DDRC_TYPE_MM:
+ case DDRC_TYPE_MN:
case DDRC_TYPE_MP:
- return dram_frac_pll_init(freq);
+ return dram_frac_pll_init(drate);
default:
return -ENODEV;
}
}
-void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type type)
+void ddrphy_init_set_dfi_clk(unsigned int drate_mhz, enum ddrc_type type)
{
- switch (drate) {
- case 4000:
- dram_pll_init(MHZ(1000), type);
- dram_disable_bypass();
- break;
- case 3200:
- dram_pll_init(MHZ(800), type);
- dram_disable_bypass();
- break;
- case 3000:
- dram_pll_init(MHZ(750), type);
- dram_disable_bypass();
- break;
- case 2400:
- dram_pll_init(MHZ(600), type);
- dram_disable_bypass();
- break;
- case 1600:
- dram_pll_init(MHZ(400), type);
- dram_disable_bypass();
- break;
- case 1066:
- dram_pll_init(MHZ(266),type);
- dram_disable_bypass();
- break;
- case 667:
- dram_pll_init(MHZ(167), type);
- dram_disable_bypass();
- break;
- case 400:
- dram_enable_bypass(MHZ(400));
- break;
- case 100:
- dram_enable_bypass(MHZ(100));
- break;
+ enum ddr_rate drate;
+
+ switch (drate_mhz) {
+ case 4000: drate = DDR_4000; break;
+ case 3200: drate = DDR_3200; break;
+ case 3000: drate = DDR_3000; break;
+ case 2400: drate = DDR_2400; break;
+ case 1600: drate = DDR_1600; break;
+ case 1066: drate = DDR_1066; break;
+ case 667: drate = DDR_667; break;
+ case 400: drate = DDR_400; break;
+ case 100: drate = DDR_100; break;
default:
return;
}
+
+ if (drate_mhz > 400) {
+ dram_pll_init(drate, type);
+ dram_disable_bypass();
+ } else {
+ dram_enable_bypass(drate);
+ }
}
void ddrphy_init_read_msg_block(enum fw_type type)
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index c9a31b5548..5a76e7a663 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -25,6 +25,40 @@
#define esdhc_send_cmd __esdhc_send_cmd
+static u8 ext_csd[512] __aligned(64);
+
+static int esdhc_send_ext_csd(struct fsl_esdhc_host *host)
+{
+ struct mci_cmd cmd;
+ struct mci_data data;
+
+ cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+
+ data.dest = ext_csd;
+ data.blocks = 1;
+ data.blocksize = sizeof(ext_csd);
+ data.flags = MMC_DATA_READ;
+
+ return esdhc_send_cmd(host, &cmd, &data);
+}
+
+static bool esdhc_bootpart_active(struct fsl_esdhc_host *host)
+{
+ unsigned bootpart;
+
+ int ret = esdhc_send_ext_csd(host);
+ if (ret)
+ return false;
+
+ bootpart = (ext_csd[EXT_CSD_PARTITION_CONFIG] >> 3) & 0x7;
+ if (bootpart == 1 || bootpart == 2)
+ return true;
+
+ return false;
+}
+
static int esdhc_read_blocks(struct fsl_esdhc_host *host, void *dst, size_t len)
{
struct mci_cmd cmd;
@@ -143,8 +177,8 @@ esdhc_load_image(struct fsl_esdhc_host *host, ptrdiff_t address,
*
* buf + ofs = entry
*
- * solving the above for 'buf' gvies us the
- * adjustement that needs to be made:
+ * solving the above for 'buf' gives us the
+ * adjustment that needs to be made:
*
* buf = entry - ofs
*
@@ -338,15 +372,21 @@ int imx8mp_esdhc_load_image(int instance, bool start)
{
struct esdhc_soc_data data;
struct fsl_esdhc_host host = { 0 };
+ u32 offset;
int ret;
ret = imx8m_esdhc_init(&host, &data, instance);
if (ret)
return ret;
+ offset = esdhc_bootpart_active(&host)? 0 : SZ_32K;
+
return esdhc_load_image(&host, MX8M_DDR_CSD1_BASE_ADDR,
- MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K, 0, start);
+ MX8MQ_ATF_BL33_BASE_ADDR, offset, 0, start);
}
+
+int imx8mn_esdhc_load_image(int instance, bool start)
+ __alias(imx8mp_esdhc_load_image);
#endif
#ifdef CONFIG_ARCH_LS1046
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 5a664ce4c3..9dcad3bb5d 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -357,6 +357,7 @@ static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = {
{ .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data },
{ .compatible = "fsl,imx8mq-usdhc", .data = &usdhc_imx6sx_data },
{ .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx6sx_data },
+ { .compatible = "fsl,imx8mn-usdhc", .data = &usdhc_imx6sx_data },
{ .compatible = "fsl,imx8mp-usdhc", .data = &usdhc_imx6sx_data },
{ .compatible = "fsl,ls1046a-esdhc",.data = &esdhc_ls_data },
{ /* sentinel */ }
diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index b2fad3c687..7d27a4fe44 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -938,6 +938,9 @@ static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
.compatible = "fsl,imx8mm-ocotp",
.data = &imx8mq_ocotp_data,
}, {
+ .compatible = "fsl,imx8mn-ocotp",
+ .data = &imx8mq_ocotp_data,
+ }, {
.compatible = "fsl,vf610-ocotp",
.data = &vf610_ocotp_data,
}, {
diff --git a/drivers/pinctrl/imx-iomux-v3.c b/drivers/pinctrl/imx-iomux-v3.c
index cec2414a03..fb2b348883 100644
--- a/drivers/pinctrl/imx-iomux-v3.c
+++ b/drivers/pinctrl/imx-iomux-v3.c
@@ -251,6 +251,8 @@ static __maybe_unused struct of_device_id imx_iomux_v3_dt_ids[] = {
}, {
.compatible = "fsl,imx8mm-iomuxc",
}, {
+ .compatible = "fsl,imx8mn-iomuxc",
+ }, {
.compatible = "fsl,imx8mp-iomuxc",
}, {
.compatible = "fsl,imx8mq-iomuxc",
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index 056fa14c2a..d1329ca1eb 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -299,6 +299,9 @@ static __maybe_unused struct of_device_id imx_serial_dt_ids[] = {
.compatible = "fsl,imx8mm-uart",
.data = &imx21_data,
}, {
+ .compatible = "fsl,imx8mn-uart",
+ .data = &imx21_data,
+ }, {
.compatible = "fsl,imx8mp-uart",
.data = &imx21_data,
}, {
diff --git a/drivers/usb/imx/imx-usb-misc.c b/drivers/usb/imx/imx-usb-misc.c
index c16b4cf0ab..013f139a8a 100644
--- a/drivers/usb/imx/imx-usb-misc.c
+++ b/drivers/usb/imx/imx-usb-misc.c
@@ -616,6 +616,10 @@ static __maybe_unused struct of_device_id imx_usbmisc_dt_ids[] = {
.compatible = "fsl,imx8mm-usbmisc",
.data = &mx7_data,
},
+ {
+ .compatible = "fsl,imx8mn-usbmisc",
+ .data = &mx7_data,
+ },
#endif
#ifdef CONFIG_ARCH_VF610
{
diff --git a/drivers/usb/imx/imx-usb-phy.c b/drivers/usb/imx/imx-usb-phy.c
index 32098ef248..6a58e71ba2 100644
--- a/drivers/usb/imx/imx-usb-phy.c
+++ b/drivers/usb/imx/imx-usb-phy.c
@@ -37,9 +37,12 @@
#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1)
#define ANADIG_USB1_CHRG_DETECT_SET 0x1b4
-#define ANADIG_USB2_CHRG_DETECT_SET 0x214
#define ANADIG_USB1_CHRG_DETECT_EN_B BIT(20)
#define ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B BIT(19)
+#define ANADIG_USB1_VBUS_DETECT_STAT 0x1c0
+#define ANADIG_USB1_VBUS_DETECT_STAT_VBUS_VALID BIT(3)
+#define ANADIG_USB2_CHRG_DETECT_SET 0x214
+#define ANADIG_USB2_VBUS_DETECT_STAT 0x220
struct imx_usbphy {
struct usb_phy usb_phy;
@@ -49,6 +52,8 @@ struct imx_usbphy {
struct clk *clk;
struct phy_provider *provider;
int port_id;
+
+ unsigned int vbus_valid;
};
static int imx_usbphy_phy_init(struct phy *phy)
@@ -132,6 +137,21 @@ static const struct phy_ops imx_phy_ops = {
.to_usbphy = imx_usbphy_to_usbphy,
};
+static int imx_usbphy_get_vbus_state(struct param_d *p, void *priv)
+{
+ struct imx_usbphy *imxphy = priv;
+ unsigned int reg, val;
+
+ reg = imxphy->port_id ?
+ ANADIG_USB1_VBUS_DETECT_STAT :
+ ANADIG_USB2_VBUS_DETECT_STAT;
+ val = readl(imxphy->anatop + reg);
+
+ imxphy->vbus_valid = !!(val & ANADIG_USB1_VBUS_DETECT_STAT_VBUS_VALID);
+
+ return 0;
+}
+
static int imx_usbphy_probe(struct device_d *dev)
{
struct resource *iores;
@@ -154,6 +174,15 @@ static int imx_usbphy_probe(struct device_d *dev)
ret = PTR_ERR_OR_ZERO(imxphy->anatop);
if (ret)
goto err_free;
+
+ /*
+ * This is useful in case of usb-otg = device. In host case
+ * it isn't that useful since we are the supplier of the vbus
+ * signal.
+ */
+ dev_add_param_bool(dev, "vbus_valid", param_set_readonly,
+ imx_usbphy_get_vbus_state,
+ &imxphy->vbus_valid, imxphy);
}
iores = dev_request_mem_resource(dev, 0);
diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
index 26c62b7bcb..a109f6fee7 100644
--- a/drivers/watchdog/imxwd.c
+++ b/drivers/watchdog/imxwd.c
@@ -39,6 +39,7 @@ struct imx_wd {
struct device_d *dev;
const struct imx_wd_ops *ops;
struct restart_handler restart;
+ struct restart_handler restart_warm;
bool ext_reset;
bool bigendian;
};
@@ -183,6 +184,14 @@ static void __noreturn imxwd_force_soc_reset(struct restart_handler *rst)
hang();
}
+static void __noreturn imxwd_force_soc_reset_internal(struct restart_handler *rst)
+{
+ struct imx_wd *priv = container_of(rst, struct imx_wd, restart_warm);
+
+ priv->ext_reset = false;
+ imxwd_force_soc_reset(&priv->restart);
+}
+
static void imx_watchdog_detect_reset_source(struct imx_wd *priv)
{
u16 val = imxwd_read(priv, IMX21_WDOG_WSTR);
@@ -284,9 +293,16 @@ static int imx_wd_probe(struct device_d *dev)
priv->restart.name = "imxwd";
priv->restart.restart = imxwd_force_soc_reset;
+ priv->restart.priority = RESTART_DEFAULT_PRIORITY;
restart_handler_register(&priv->restart);
+ priv->restart_warm.name = "imxwd-warm";
+ priv->restart_warm.restart = imxwd_force_soc_reset_internal;
+ priv->restart_warm.priority = RESTART_DEFAULT_PRIORITY - 10;
+
+ restart_handler_register(&priv->restart_warm);
+
return 0;
error_unregister: