summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/clk.c43
-rw-r--r--drivers/clk/imx/Makefile3
-rw-r--r--drivers/clk/imx/clk-imx8mm.c577
-rw-r--r--drivers/clk/imx/clk-pll14xx.c446
-rw-r--r--drivers/clk/imx/clk.h47
-rw-r--r--drivers/ddr/Kconfig1
-rw-r--r--drivers/ddr/Makefile1
-rw-r--r--drivers/ddr/imx8m/Kconfig7
-rw-r--r--drivers/ddr/imx8m/Makefile7
-rw-r--r--drivers/ddr/imx8m/ddr_init.c211
-rw-r--r--drivers/ddr/imx8m/ddrphy_csr.c732
-rw-r--r--drivers/ddr/imx8m/ddrphy_train.c112
-rw-r--r--drivers/ddr/imx8m/ddrphy_utils.c306
-rw-r--r--drivers/ddr/imx8m/helper.c86
-rw-r--r--drivers/hab/habv4.c12
-rw-r--r--drivers/i2c/busses/i2c-imx-early.c12
-rw-r--r--drivers/mci/imx-esdhc-pbl.c23
-rw-r--r--drivers/mci/imx-esdhc.c1
-rw-r--r--drivers/net/designware_eqos.c33
-rw-r--r--drivers/net/designware_eqos.h1
-rw-r--r--drivers/net/designware_stm32.c1
-rw-r--r--drivers/net/designware_tegra186.c1
-rw-r--r--drivers/of/overlay.c20
-rw-r--r--drivers/pinctrl/imx-iomux-v3.c2
-rw-r--r--drivers/pinctrl/pinctrl-single.c2
-rw-r--r--drivers/serial/serial_imx.c3
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/core/hub.c3
-rw-r--r--drivers/usb/gadget/Kconfig14
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/f_fastboot.c6
-rw-r--r--drivers/usb/gadget/fsl_udc.c394
-rw-r--r--drivers/usb/gadget/fsl_udc_pbl.c210
-rw-r--r--drivers/usb/host/ehci-hcd.c101
-rw-r--r--drivers/usb/imx/chipidea-imx.c2
-rw-r--r--drivers/usb/imx/imx-usb-misc.c6
-rw-r--r--drivers/usb/musb/musb_core.c5
-rw-r--r--drivers/usb/musb/musb_dsps.c55
-rw-r--r--drivers/usb/musb/phy-am335x-control.c25
-rw-r--r--drivers/usb/musb/phy-am335x.c22
-rw-r--r--drivers/usb/musb/phy-am335x.h6
-rw-r--r--drivers/video/ssd1307fb.c63
42 files changed, 3058 insertions, 547 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index ea3304bc7c..b27ad6d249 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -84,12 +84,14 @@ void clk_disable(struct clk *clk)
if (!clk->enable_count)
return;
+ if (clk->enable_count == 1 && clk->flags & CLK_IS_CRITICAL) {
+ pr_warn("Disabling critical clock %s\n", clk->name);
+ return;
+ }
+
clk->enable_count--;
if (!clk->enable_count) {
- if (clk->flags & CLK_IS_CRITICAL)
- return;
-
if (clk->ops->disable)
clk->ops->disable(clk);
@@ -282,6 +284,9 @@ int clk_register(struct clk *clk)
list_add_tail(&clk->list, &clks);
+ if (clk->flags & CLK_IS_CRITICAL)
+ clk_enable(clk);
+
return 0;
}
@@ -627,12 +632,40 @@ int of_clk_init(struct device_node *root, const struct of_device_id *matches)
}
#endif
+static const char *clk_hw_stat(struct clk *clk)
+{
+ if (clk->ops->is_enabled) {
+ if (clk->ops->is_enabled(clk))
+ return "enabled";
+ else
+ return "disabled";
+ }
+
+ if (!clk->ops->enable)
+ return "always enabled";
+
+ return "unknown";
+}
+
static void dump_one(struct clk *clk, int verbose, int indent)
{
struct clk *c;
+ int enabled = clk_is_enabled(clk);
+ const char *hwstat, *stat;
+
+ hwstat = clk_hw_stat(clk);
+
+ if (enabled == 0)
+ stat = "disabled";
+ else
+ stat = "enabled";
+
+ printf("%*s%s (rate %lu, enable_count: %d, %s)\n", indent * 4, "",
+ clk->name,
+ clk_get_rate(clk),
+ clk->enable_count,
+ hwstat);
- printf("%*s%s (rate %lu, %sabled)\n", indent * 4, "", clk->name, clk_get_rate(clk),
- clk_is_enabled(clk) ? "en" : "dis");
if (verbose) {
if (clk->num_parents > 1) {
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 97ae97a2a9..e627ef4a09 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_COMMON_CLK) += \
clk-pllv1.o \
clk-pllv2.o \
clk-pllv3.o \
+ clk-pll14xx.o \
clk-pfd.o \
clk-gate2.o \
clk-gate-exclusive.o \
@@ -25,5 +26,7 @@ obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o
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
+obj-$(CONFIG_ARCH_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_ARCH_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_ARCH_VF610) += clk-vf610.o
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
new file mode 100644
index 0000000000..a31741af88
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017-2018 NXP.
+ */
+
+#include <dt-bindings/clock/imx8mm-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 *pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
+static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
+static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
+static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
+static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
+static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
+static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
+static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
+static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
+
+/* CCM ROOT */
+static const char *imx8mm_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 *imx8mm_m4_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "sys_pll1_266m",
+ "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
+
+static const char *imx8mm_vpu_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
+ "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "vpu_pll_out", };
+
+static const char *imx8mm_gpu3d_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 *imx8mm_gpu2d_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_vpu_bus_sels[] = {"osc_24m", "sys_pll1_800m", "vpu_pll_out", "audio_pll2_out",
+ "sys_pll3_out", "sys_pll2_1000m", "sys_pll2_200m", "sys_pll1_100m", };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_disp_rtrm_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll2_1000m",
+ "audio_pll1_out", "video_pll1_out", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_noc_apb_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll3_out", "sys_pll2_333m", "sys_pll2_200m",
+ "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_vpu_g1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_100m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", };
+
+static const char *imx8mm_vpu_g2_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_100m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", };
+
+static const char *imx8mm_disp_dtrc_sels[] = {"osc_24m", "dummy", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_160m", "video_pll1_out", "sys_pll3_out", "audio_pll2_out", };
+
+static const char *imx8mm_disp_dc8000_sels[] = {"osc_24m", "dummy", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_160m", "video_pll1_out", "sys_pll3_out", "audio_pll2_out", };
+
+static const char *imx8mm_pcie1_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m", "sys_pll1_266m",
+ "sys_pll1_800m", "sys_pll2_500m", "sys_pll2_333m", "sys_pll3_out", };
+
+static const char *imx8mm_pcie1_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m", "clk_ext1", "clk_ext2",
+ "clk_ext3", "clk_ext4", "sys_pll1_400m", };
+
+static const char *imx8mm_pcie1_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m", "sys_pll3_out",
+ "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_160m", "sys_pll1_200m", };
+
+static const char *imx8mm_dc_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 *imx8mm_lcdif_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 *imx8mm_sai1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mm_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mm_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 *imx8mm_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_spdif2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_gpt1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m", "sys_pll1_40m",
+ "video_pll1_out", "sys_pll1_80m", "audio_pll1_out", "clk_ext1" };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_csi1_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 *imx8mm_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 *imx8mm_csi1_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 *imx8mm_csi2_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 *imx8mm_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 *imx8mm_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 *imx8mm_pcie2_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m", "sys_pll1_266m",
+ "sys_pll1_800m", "sys_pll2_500m", "sys_pll2_333m", "sys_pll3_out", };
+
+static const char *imx8mm_pcie2_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m", "clk_ext1",
+ "clk_ext2", "clk_ext3", "clk_ext4", "sys_pll1_400m", };
+
+static const char *imx8mm_pcie2_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m", "sys_pll3_out",
+ "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_160m", "sys_pll1_200m", };
+
+static const char *imx8mm_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 *imx8mm_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 *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "audio_pll2_out", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", };
+
+static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
+
+static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out",
+ "vpu_pll", "sys_pll1_80m", };
+
+static struct clk *clks[IMX8MM_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static int imx8mm_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,imx8mm-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[IMX8MM_CLK_DUMMY] = clk_fixed("dummy", 0);
+ clks[IMX8MM_CLK_24M] = of_clk_get_by_name(ccm_np, "osc_24m");
+ clks[IMX8MM_CLK_32K] = of_clk_get_by_name(ccm_np, "osc_32k");
+ clks[IMX8MM_CLK_EXT1] = of_clk_get_by_name(ccm_np, "clk_ext1");
+ clks[IMX8MM_CLK_EXT2] = of_clk_get_by_name(ccm_np, "clk_ext2");
+ clks[IMX8MM_CLK_EXT3] = of_clk_get_by_name(ccm_np, "clk_ext3");
+ clks[IMX8MM_CLK_EXT4] = of_clk_get_by_name(ccm_np, "clk_ext4");
+
+ clks[IMX8MM_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", ana + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", ana + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", ana + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", ana + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", ana + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", ana + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", ana + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", ana + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+ clks[IMX8MM_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", ana, &imx_1443x_pll);
+ clks[IMX8MM_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", ana + 0x14, &imx_1443x_pll);
+ clks[IMX8MM_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", ana + 0x28, &imx_1443x_pll);
+ clks[IMX8MM_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", ana + 0x50, &imx_1443x_pll);
+ clks[IMX8MM_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", ana + 0x64, &imx_1416x_pll);
+ clks[IMX8MM_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", ana + 0x74, &imx_1416x_pll);
+ clks[IMX8MM_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", ana + 0x84, &imx_1416x_pll);
+ clks[IMX8MM_SYS_PLL1] = clk_fixed("sys_pll1", 800000000);
+ clks[IMX8MM_SYS_PLL2] = clk_fixed("sys_pll2", 1000000000);
+ clks[IMX8MM_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", ana + 0x114, &imx_1416x_pll);
+
+ /* PLL bypass out */
+ clks[IMX8MM_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[IMX8MM_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[IMX8MM_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[IMX8MM_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[IMX8MM_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[IMX8MM_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[IMX8MM_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[IMX8MM_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[IMX8MM_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", ana, 13);
+ clks[IMX8MM_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", ana + 0x14, 13);
+ clks[IMX8MM_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", ana + 0x28, 13);
+ clks[IMX8MM_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", ana + 0x50, 13);
+ clks[IMX8MM_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", ana + 0x64, 11);
+ clks[IMX8MM_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", ana + 0x74, 11);
+ clks[IMX8MM_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", ana + 0x84, 11);
+ clks[IMX8MM_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", ana + 0x114, 11);
+
+ /* SYS PLL1 fixed output */
+ clks[IMX8MM_SYS_PLL1_40M_CG] = imx_clk_gate("sys_pll1_40m_cg", "sys_pll1", ana + 0x94, 27);
+ clks[IMX8MM_SYS_PLL1_80M_CG] = imx_clk_gate("sys_pll1_80m_cg", "sys_pll1", ana + 0x94, 25);
+ clks[IMX8MM_SYS_PLL1_100M_CG] = imx_clk_gate("sys_pll1_100m_cg", "sys_pll1", ana + 0x94, 23);
+ clks[IMX8MM_SYS_PLL1_133M_CG] = imx_clk_gate("sys_pll1_133m_cg", "sys_pll1", ana + 0x94, 21);
+ clks[IMX8MM_SYS_PLL1_160M_CG] = imx_clk_gate("sys_pll1_160m_cg", "sys_pll1", ana + 0x94, 19);
+ clks[IMX8MM_SYS_PLL1_200M_CG] = imx_clk_gate("sys_pll1_200m_cg", "sys_pll1", ana + 0x94, 17);
+ clks[IMX8MM_SYS_PLL1_266M_CG] = imx_clk_gate("sys_pll1_266m_cg", "sys_pll1", ana + 0x94, 15);
+ clks[IMX8MM_SYS_PLL1_400M_CG] = imx_clk_gate("sys_pll1_400m_cg", "sys_pll1", ana + 0x94, 13);
+ clks[IMX8MM_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1", ana + 0x94, 11);
+
+ clks[IMX8MM_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
+ clks[IMX8MM_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
+ clks[IMX8MM_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
+ clks[IMX8MM_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
+ clks[IMX8MM_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
+ clks[IMX8MM_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
+ clks[IMX8MM_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
+ clks[IMX8MM_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
+ clks[IMX8MM_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
+
+ /* SYS PLL2 fixed output */
+ clks[IMX8MM_SYS_PLL2_50M_CG] = imx_clk_gate("sys_pll2_50m_cg", "sys_pll2", ana + 0x104, 27);
+ clks[IMX8MM_SYS_PLL2_100M_CG] = imx_clk_gate("sys_pll2_100m_cg", "sys_pll2", ana + 0x104, 25);
+ clks[IMX8MM_SYS_PLL2_125M_CG] = imx_clk_gate("sys_pll2_125m_cg", "sys_pll2", ana + 0x104, 23);
+ clks[IMX8MM_SYS_PLL2_166M_CG] = imx_clk_gate("sys_pll2_166m_cg", "sys_pll2", ana + 0x104, 21);
+ clks[IMX8MM_SYS_PLL2_200M_CG] = imx_clk_gate("sys_pll2_200m_cg", "sys_pll2", ana + 0x104, 19);
+ clks[IMX8MM_SYS_PLL2_250M_CG] = imx_clk_gate("sys_pll2_250m_cg", "sys_pll2", ana + 0x104, 17);
+ clks[IMX8MM_SYS_PLL2_333M_CG] = imx_clk_gate("sys_pll2_333m_cg", "sys_pll2", ana + 0x104, 15);
+ clks[IMX8MM_SYS_PLL2_500M_CG] = imx_clk_gate("sys_pll2_500m_cg", "sys_pll2", ana + 0x104, 13);
+ clks[IMX8MM_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2", ana + 0x104, 11);
+
+ clks[IMX8MM_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
+ clks[IMX8MM_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
+ clks[IMX8MM_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
+ clks[IMX8MM_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
+ clks[IMX8MM_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
+ clks[IMX8MM_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
+ clks[IMX8MM_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
+ clks[IMX8MM_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
+ clks[IMX8MM_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+
+ /* Core Slice */
+ clks[IMX8MM_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", ccm + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels));
+ clks[IMX8MM_CLK_M4_SRC] = imx_clk_mux2("arm_m4_src", ccm + 0x8080, 24, 3, imx8mm_m4_sels, ARRAY_SIZE(imx8mm_m4_sels));
+ clks[IMX8MM_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", ccm + 0x8100, 24, 3, imx8mm_vpu_sels, ARRAY_SIZE(imx8mm_vpu_sels));
+ clks[IMX8MM_CLK_GPU3D_SRC] = imx_clk_mux2("gpu3d_src", ccm + 0x8180, 24, 3, imx8mm_gpu3d_sels, ARRAY_SIZE(imx8mm_gpu3d_sels));
+ clks[IMX8MM_CLK_GPU2D_SRC] = imx_clk_mux2("gpu2d_src", ccm + 0x8200, 24, 3, imx8mm_gpu2d_sels, ARRAY_SIZE(imx8mm_gpu2d_sels));
+ clks[IMX8MM_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", ccm + 0x8000, 28);
+ clks[IMX8MM_CLK_M4_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", ccm + 0x8080, 28);
+ clks[IMX8MM_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", ccm + 0x8100, 28);
+ clks[IMX8MM_CLK_GPU3D_CG] = imx_clk_gate3("gpu3d_cg", "gpu3d_src", ccm + 0x8180, 28);
+ clks[IMX8MM_CLK_GPU2D_CG] = imx_clk_gate3("gpu2d_cg", "gpu2d_src", ccm + 0x8200, 28);
+ clks[IMX8MM_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", ccm + 0x8000, 0, 3);
+ clks[IMX8MM_CLK_M4_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", ccm + 0x8080, 0, 3);
+ clks[IMX8MM_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", ccm + 0x8100, 0, 3);
+ clks[IMX8MM_CLK_GPU3D_DIV] = imx_clk_divider2("gpu3d_div", "gpu3d_cg", ccm + 0x8180, 0, 3);
+ clks[IMX8MM_CLK_GPU2D_DIV] = imx_clk_divider2("gpu2d_div", "gpu2d_cg", ccm + 0x8200, 0, 3);
+
+ /* BUS */
+ clks[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mm_main_axi_sels, ccm + 0x8800);
+ clks[IMX8MM_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, ccm + 0x8880);
+ clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, ccm + 0x8900);
+ clks[IMX8MM_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mm_vpu_bus_sels, ccm + 0x8980);
+ clks[IMX8MM_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mm_disp_axi_sels, ccm + 0x8a00);
+ clks[IMX8MM_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mm_disp_apb_sels, ccm + 0x8a80);
+ clks[IMX8MM_CLK_DISP_RTRM] = imx8m_clk_composite("disp_rtrm", imx8mm_disp_rtrm_sels, ccm + 0x8b00);
+ clks[IMX8MM_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mm_usb_bus_sels, ccm + 0x8b80);
+ clks[IMX8MM_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mm_gpu_axi_sels, ccm + 0x8c00);
+ clks[IMX8MM_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mm_gpu_ahb_sels, ccm + 0x8c80);
+ clks[IMX8MM_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mm_noc_sels, ccm + 0x8d00);
+ clks[IMX8MM_CLK_NOC_APB] = imx8m_clk_composite_critical("noc_apb", imx8mm_noc_apb_sels, ccm + 0x8d80);
+
+ /* AHB */
+ clks[IMX8MM_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mm_ahb_sels, ccm + 0x9000);
+ clks[IMX8MM_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mm_audio_ahb_sels, ccm + 0x9100);
+
+ /* IPG */
+ clks[IMX8MM_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", ccm + 0x9080, 0, 1);
+ clks[IMX8MM_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", ccm + 0x9180, 0, 1);
+
+ /* IP */
+ clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, ccm + 0xa000);
+ clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mm_dram_apb_sels, ccm + 0xa080);
+ clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, ccm + 0xa100);
+ clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, ccm + 0xa180);
+ clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, ccm + 0xa200);
+ clks[IMX8MM_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mm_disp_dc8000_sels, ccm + 0xa280);
+ clks[IMX8MM_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mm_pcie1_ctrl_sels, ccm + 0xa300);
+ clks[IMX8MM_CLK_PCIE1_PHY] = imx8m_clk_composite("pcie1_phy", imx8mm_pcie1_phy_sels, ccm + 0xa380);
+ clks[IMX8MM_CLK_PCIE1_AUX] = imx8m_clk_composite("pcie1_aux", imx8mm_pcie1_aux_sels, ccm + 0xa400);
+ clks[IMX8MM_CLK_DC_PIXEL] = imx8m_clk_composite("dc_pixel", imx8mm_dc_pixel_sels, ccm + 0xa480);
+ clks[IMX8MM_CLK_LCDIF_PIXEL] = imx8m_clk_composite("lcdif_pixel", imx8mm_lcdif_pixel_sels, ccm + 0xa500);
+ clks[IMX8MM_CLK_SAI1] = imx8m_clk_composite("sai1", imx8mm_sai1_sels, ccm + 0xa580);
+ clks[IMX8MM_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mm_sai2_sels, ccm + 0xa600);
+ clks[IMX8MM_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mm_sai3_sels, ccm + 0xa680);
+ clks[IMX8MM_CLK_SAI4] = imx8m_clk_composite("sai4", imx8mm_sai4_sels, ccm + 0xa700);
+ clks[IMX8MM_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mm_sai5_sels, ccm + 0xa780);
+ clks[IMX8MM_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mm_sai6_sels, ccm + 0xa800);
+ clks[IMX8MM_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mm_spdif1_sels, ccm + 0xa880);
+ clks[IMX8MM_CLK_SPDIF2] = imx8m_clk_composite("spdif2", imx8mm_spdif2_sels, ccm + 0xa900);
+ clks[IMX8MM_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mm_enet_ref_sels, ccm + 0xa980);
+ clks[IMX8MM_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mm_enet_timer_sels, ccm + 0xaa00);
+ clks[IMX8MM_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mm_enet_phy_sels, ccm + 0xaa80);
+ clks[IMX8MM_CLK_NAND] = imx8m_clk_composite("nand", imx8mm_nand_sels, ccm + 0xab00);
+ clks[IMX8MM_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mm_qspi_sels, ccm + 0xab80);
+ clks[IMX8MM_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mm_usdhc1_sels, ccm + 0xac00);
+ clks[IMX8MM_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mm_usdhc2_sels, ccm + 0xac80);
+ clks[IMX8MM_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mm_i2c1_sels, ccm + 0xad00);
+ clks[IMX8MM_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mm_i2c2_sels, ccm + 0xad80);
+ clks[IMX8MM_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, ccm + 0xae00);
+ clks[IMX8MM_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, ccm + 0xae80);
+ clks[IMX8MM_CLK_UART1] = imx8m_clk_composite("uart1", imx8mm_uart1_sels, ccm + 0xaf00);
+ clks[IMX8MM_CLK_UART2] = imx8m_clk_composite("uart2", imx8mm_uart2_sels, ccm + 0xaf80);
+ clks[IMX8MM_CLK_UART3] = imx8m_clk_composite("uart3", imx8mm_uart3_sels, ccm + 0xb000);
+ clks[IMX8MM_CLK_UART4] = imx8m_clk_composite("uart4", imx8mm_uart4_sels, ccm + 0xb080);
+ clks[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, ccm + 0xb100);
+ clks[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, ccm + 0xb180);
+ clks[IMX8MM_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mm_gic_sels, ccm + 0xb200);
+ clks[IMX8MM_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, ccm + 0xb280);
+ clks[IMX8MM_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, ccm + 0xb300);
+ clks[IMX8MM_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, ccm + 0xb380);
+ clks[IMX8MM_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mm_pwm2_sels, ccm + 0xb400);
+ clks[IMX8MM_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mm_pwm3_sels, ccm + 0xb480);
+ clks[IMX8MM_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mm_pwm4_sels, ccm + 0xb500);
+ clks[IMX8MM_CLK_GPT1] = imx8m_clk_composite("gpt1", imx8mm_gpt1_sels, ccm + 0xb580);
+ clks[IMX8MM_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mm_wdog_sels, ccm + 0xb900);
+ clks[IMX8MM_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mm_wrclk_sels, ccm + 0xb980);
+ clks[IMX8MM_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mm_clko1_sels, ccm + 0xba00);
+ clks[IMX8MM_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mm_dsi_core_sels, ccm + 0xbb00);
+ clks[IMX8MM_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mm_dsi_phy_sels, ccm + 0xbb80);
+ clks[IMX8MM_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mm_dsi_dbi_sels, ccm + 0xbc00);
+ clks[IMX8MM_CLK_USDHC3] = imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels, ccm + 0xbc80);
+ clks[IMX8MM_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mm_csi1_core_sels, ccm + 0xbd00);
+ clks[IMX8MM_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mm_csi1_phy_sels, ccm + 0xbd80);
+ clks[IMX8MM_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mm_csi1_esc_sels, ccm + 0xbe00);
+ clks[IMX8MM_CLK_CSI2_CORE] = imx8m_clk_composite("csi2_core", imx8mm_csi2_core_sels, ccm + 0xbe80);
+ clks[IMX8MM_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mm_csi2_phy_sels, ccm + 0xbf00);
+ clks[IMX8MM_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mm_csi2_esc_sels, ccm + 0xbf80);
+ clks[IMX8MM_CLK_PCIE2_CTRL] = imx8m_clk_composite("pcie2_ctrl", imx8mm_pcie2_ctrl_sels, ccm + 0xc000);
+ clks[IMX8MM_CLK_PCIE2_PHY] = imx8m_clk_composite("pcie2_phy", imx8mm_pcie2_phy_sels, ccm + 0xc080);
+ clks[IMX8MM_CLK_PCIE2_AUX] = imx8m_clk_composite("pcie2_aux", imx8mm_pcie2_aux_sels, ccm + 0xc100);
+ clks[IMX8MM_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mm_ecspi3_sels, ccm + 0xc180);
+ clks[IMX8MM_CLK_PDM] = imx8m_clk_composite("pdm", imx8mm_pdm_sels, ccm + 0xc200);
+ clks[IMX8MM_CLK_VPU_H1] = imx8m_clk_composite("vpu_h1", imx8mm_vpu_h1_sels, ccm + 0xc280);
+
+ /* CCGR */
+ clks[IMX8MM_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", ccm + 0x4070, 0);
+ clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", ccm + 0x4080, 0);
+ clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", ccm + 0x4090, 0);
+ clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", ccm + 0x40a0, 0);
+ clks[IMX8MM_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", ccm + 0x40b0, 0);
+ clks[IMX8MM_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", ccm + 0x40c0, 0);
+ clks[IMX8MM_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", ccm + 0x40d0, 0);
+ clks[IMX8MM_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", ccm + 0x40e0, 0);
+ clks[IMX8MM_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", ccm + 0x40f0, 0);
+ clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", ccm + 0x4100, 0);
+ clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", ccm + 0x4170, 0);
+ clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", ccm + 0x4180, 0);
+ clks[IMX8MM_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", ccm + 0x4190, 0);
+ clks[IMX8MM_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", ccm + 0x41a0, 0);
+ clks[IMX8MM_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", ccm + 0x4210, 0);
+ clks[IMX8MM_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", ccm + 0x4220, 0);
+ clks[IMX8MM_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", ccm + 0x4250, 0);
+ clks[IMX8MM_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", ccm + 0x4280, 0);
+ clks[IMX8MM_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", ccm + 0x4290, 0);
+ clks[IMX8MM_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", ccm + 0x42a0, 0);
+ clks[IMX8MM_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", ccm + 0x42b0, 0);
+ clks[IMX8MM_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", ccm + 0x42f0, 0);
+ clks[IMX8MM_CLK_NAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", ccm + 0x4300, 0);
+ clks[IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", ccm + 0x4300, 0);
+ clks[IMX8MM_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1", ccm + 0x4330, 0);
+ clks[IMX8MM_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", ccm + 0x4330, 0);
+ clks[IMX8MM_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", ccm + 0x4340, 0);
+ clks[IMX8MM_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", ccm + 0x4340, 0);
+ clks[IMX8MM_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", ccm + 0x4350, 0);
+ clks[IMX8MM_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", ccm + 0x4350, 0);
+ clks[IMX8MM_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4", ccm + 0x4360, 0);
+ clks[IMX8MM_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", ccm + 0x4360, 0);
+ clks[IMX8MM_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", ccm + 0x4370, 0);
+ clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", ccm + 0x4370, 0);
+ clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", ccm + 0x4380, 0);
+ clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", ccm + 0x4380, 0);
+ clks[IMX8MM_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", ccm + 0x4470, 0);
+ clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", ccm + 0x4490, 0);
+ clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", ccm + 0x44a0, 0);
+ clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", ccm + 0x44b0, 0);
+ clks[IMX8MM_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", ccm + 0x44c0, 0);
+ clks[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", ccm + 0x44d0, 0);
+ clks[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_gate4("gpu3d_root_clk", "gpu3d_div", ccm + 0x44f0, 0);
+ clks[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", ccm + 0x4510, 0);
+ clks[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", ccm + 0x4520, 0);
+ clks[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", ccm + 0x4530, 0);
+ clks[IMX8MM_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", ccm + 0x4540, 0);
+ clks[IMX8MM_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", ccm + 0x4550, 0);
+ clks[IMX8MM_CLK_VPU_G1_ROOT] = imx_clk_gate4("vpu_g1_root_clk", "vpu_g1", ccm + 0x4560, 0);
+ clks[IMX8MM_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi", ccm + 0x4570, 0);
+ clks[IMX8MM_CLK_VPU_H1_ROOT] = imx_clk_gate4("vpu_h1_root_clk", "vpu_h1", ccm + 0x4590, 0);
+ clks[IMX8MM_CLK_VPU_G2_ROOT] = imx_clk_gate4("vpu_g2_root_clk", "vpu_g2", ccm + 0x45a0, 0);
+ clks[IMX8MM_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm", ccm + 0x45b0, 0);
+ clks[IMX8MM_CLK_PDM_IPG] = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", ccm + 0x45b0, 0);
+ clks[IMX8MM_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000", ccm + 0x45d0, 0);
+ clks[IMX8MM_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", ccm + 0x45d0, 0);
+ clks[IMX8MM_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", ccm + 0x45d0, 0);
+ clks[IMX8MM_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", ccm + 0x45d0, 0);
+ clks[IMX8MM_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3", ccm + 0x45e0, 0);
+ clks[IMX8MM_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", ccm + 0x4620, 0);
+ clks[IMX8MM_CLK_VPU_DEC_ROOT] = imx_clk_gate4("vpu_dec_root_clk", "vpu_bus", ccm + 0x4630, 0);
+ clks[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", ccm + 0x43a0, 0);
+ clks[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", ccm + 0x43b0, 0);
+ clks[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", ccm + 0x45f0, 0);
+ clks[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_gate4("gpu2d_root_clk", "gpu2d_div", ccm + 0x4660, 0);
+ clks[IMX8MM_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", ccm + 0x4650, 0);
+
+ clks[IMX8MM_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc_24m", 1, 8);
+
+ clks[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
+ clks[IMX8MM_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", ccm + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL);
+
+ clks[IMX8MM_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div",
+ clks[IMX8MM_CLK_A53_DIV],
+ clks[IMX8MM_CLK_A53_SRC],
+ clks[IMX8MM_ARM_PLL_OUT],
+ clks[IMX8MM_SYS_PLL1_800M]);
+
+ imx_check_clocks(clks, ARRAY_SIZE(clks));
+
+ clk_enable(clks[IMX8MM_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.MX8MM\n");
+
+ return ret;
+}
+CLK_OF_DECLARE(imx8mm, "fsl,imx8mm-ccm", imx8mm_clocks_init);
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
new file mode 100644
index 0000000000..91e9624a60
--- /dev/null
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017-2018 NXP.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <malloc.h>
+#include <clock.h>
+#include <soc/imx8m/clk-early.h>
+#include <asm-generic/div64.h>
+
+#include "clk.h"
+
+#define GNRL_CTL 0x0
+#define DIV_CTL 0x4
+#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)
+#define MDIV_SHIFT 12
+#define MDIV_MASK GENMASK(21, 12)
+#define PDIV_SHIFT 4
+#define PDIV_MASK GENMASK(9, 4)
+#define SDIV_SHIFT 0
+#define SDIV_MASK GENMASK(2, 0)
+#define KDIV_SHIFT 0
+#define KDIV_MASK GENMASK(15, 0)
+
+#define LOCK_TIMEOUT_US 10000
+
+struct clk_pll14xx {
+ struct clk clk;
+ void __iomem *base;
+ enum imx_pll14xx_type type;
+ const struct imx_pll14xx_rate_table *rate_table;
+ int rate_count;
+ const char *parent;
+};
+
+#define to_clk_pll14xx(clk) container_of(clk, struct clk_pll14xx, clk)
+
+static const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
+ PLL_1416X_RATE(1800000000U, 225, 3, 0),
+ PLL_1416X_RATE(1600000000U, 200, 3, 0),
+ PLL_1416X_RATE(1500000000U, 375, 3, 1),
+ PLL_1416X_RATE(1400000000U, 350, 3, 1),
+ PLL_1416X_RATE(1200000000U, 300, 3, 1),
+ PLL_1416X_RATE(1000000000U, 250, 3, 1),
+ PLL_1416X_RATE(800000000U, 200, 3, 1),
+ PLL_1416X_RATE(750000000U, 250, 2, 2),
+ PLL_1416X_RATE(700000000U, 350, 3, 2),
+ PLL_1416X_RATE(600000000U, 300, 3, 2),
+};
+
+static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
+ PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
+ PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
+ PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
+ PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
+};
+
+struct imx_pll14xx_clk imx_1443x_pll = {
+ .type = PLL_1443X,
+ .rate_table = imx_pll1443x_tbl,
+ .rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
+};
+
+struct imx_pll14xx_clk imx_1416x_pll = {
+ .type = PLL_1416X,
+ .rate_table = imx_pll1416x_tbl,
+ .rate_count = ARRAY_SIZE(imx_pll1416x_tbl),
+};
+
+static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
+ struct clk_pll14xx *pll, unsigned long rate)
+{
+ const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ for (i = 0; i < pll->rate_count; i++)
+ if (rate == rate_table[i].rate)
+ return &rate_table[i];
+
+ return NULL;
+}
+
+static long clk_pll14xx_round_rate(struct clk *clk, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ /* Assumming rate_table is in descending order */
+ for (i = 0; i < pll->rate_count; i++)
+ if (rate >= rate_table[i].rate)
+ return rate_table[i].rate;
+
+ /* return minimum supported value */
+ return rate_table[i - 1].rate;
+}
+
+static unsigned long clk_pll1416x_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ u32 mdiv, pdiv, sdiv, pll_div;
+ u64 fvco = parent_rate;
+
+ pll_div = readl(pll->base + 4);
+ mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
+ pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
+ sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
+
+ fvco *= mdiv;
+ do_div(fvco, pdiv << sdiv);
+
+ return fvco;
+}
+
+static unsigned long clk_pll1443x_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
+ short int kdiv;
+ u64 fvco = parent_rate;
+
+ pll_div_ctl0 = readl(pll->base + 4);
+ pll_div_ctl1 = readl(pll->base + 8);
+ mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
+ pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
+ sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
+ kdiv = pll_div_ctl1 & KDIV_MASK;
+
+ /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
+ fvco *= (mdiv * 65536 + kdiv);
+ pdiv *= 65536;
+
+ do_div(fvco, pdiv << sdiv);
+
+ return fvco;
+}
+
+static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
+ u32 pll_div)
+{
+ u32 old_mdiv, old_pdiv;
+
+ old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
+ old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
+
+ return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
+}
+
+static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
+{
+ u32 val;
+
+ return readl_poll_timeout(pll->base, val, val & LOCK_STATUS,
+ LOCK_TIMEOUT_US);
+}
+
+static int clk_pll1416x_set_rate(struct clk *clk, unsigned long drate,
+ unsigned long prate)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ const struct imx_pll14xx_rate_table *rate;
+ u32 tmp, div_val;
+ int ret;
+
+ rate = imx_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, clk->name);
+ return -EINVAL;
+ }
+
+ tmp = readl(pll->base + 4);
+
+ if (!clk_pll14xx_mp_change(rate, tmp)) {
+ tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
+ tmp |= rate->sdiv << SDIV_SHIFT;
+ writel(tmp, pll->base + 4);
+
+ return 0;
+ }
+
+ /* Bypass clock and set lock to pll output lock */
+ tmp = readl(pll->base);
+ tmp |= LOCK_SEL_MASK;
+ writel(tmp, pll->base);
+
+ /* Enable RST */
+ tmp &= ~RST_MASK;
+ writel(tmp, pll->base);
+
+ /* Enable BYPASS */
+ tmp |= BYPASS_MASK;
+ writel(tmp, pll->base);
+
+ div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+ (rate->sdiv << SDIV_SHIFT);
+ writel(div_val, pll->base + 0x4);
+
+ /*
+ * According to SPEC, t3 - t2 need to be greater than
+ * 1us and 1/FREF, respectively.
+ * FREF is FIN / Prediv, the prediv is [1, 63], so choose
+ * 3us.
+ */
+ udelay(3);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel(tmp, pll->base);
+
+ /* Wait Lock */
+ ret = clk_pll14xx_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel(tmp, pll->base);
+
+ return 0;
+}
+
+int clk_pll1416x_early_set_rate(void __iomem *base, unsigned long drate,
+ unsigned long prate)
+{
+ struct clk_pll14xx pll = {
+ .clk = {
+ .name = "pll1416x",
+ },
+ .base = base,
+ .rate_table = imx_pll1416x_tbl,
+ .rate_count = ARRAY_SIZE(imx_pll1416x_tbl),
+ };
+
+ return clk_pll1416x_set_rate(&pll.clk, drate, prate);
+}
+
+static int clk_pll1443x_set_rate(struct clk *clk, unsigned long drate,
+ unsigned long prate)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ const struct imx_pll14xx_rate_table *rate;
+ u32 tmp, div_val;
+ int ret;
+
+ rate = imx_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, clk->name);
+ return -EINVAL;
+ }
+
+ tmp = readl(pll->base + 4);
+
+ if (!clk_pll14xx_mp_change(rate, tmp)) {
+ tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
+ tmp |= rate->sdiv << SDIV_SHIFT;
+ writel(tmp, pll->base + 4);
+
+ tmp = rate->kdiv << KDIV_SHIFT;
+ writel(tmp, pll->base + 8);
+
+ return 0;
+ }
+
+ /* Enable RST */
+ tmp = readl(pll->base);
+ tmp &= ~RST_MASK;
+ writel(tmp, pll->base);
+
+ /* Enable BYPASS */
+ tmp |= BYPASS_MASK;
+ writel(tmp, pll->base);
+
+ div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+ (rate->sdiv << SDIV_SHIFT);
+ writel(div_val, pll->base + 0x4);
+ writel(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
+
+ /*
+ * According to SPEC, t3 - t2 need to be greater than
+ * 1us and 1/FREF, respectively.
+ * FREF is FIN / Prediv, the prediv is [1, 63], so choose
+ * 3us.
+ */
+ udelay(3);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel(tmp, pll->base);
+
+ /* Wait Lock*/
+ ret = clk_pll14xx_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel(tmp, pll->base);
+
+ return 0;
+}
+
+static int clk_pll14xx_prepare(struct clk *clk)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ u32 val;
+ int ret;
+
+ /*
+ * RESETB = 1 from 0, PLL starts its normal
+ * operation after lock time
+ */
+ val = readl(pll->base + GNRL_CTL);
+ if (val & RST_MASK)
+ return 0;
+ val |= BYPASS_MASK;
+ writel(val, pll->base + GNRL_CTL);
+ val |= RST_MASK;
+ writel(val, pll->base + GNRL_CTL);
+
+ ret = clk_pll14xx_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ val &= ~BYPASS_MASK;
+ writel(val, pll->base + GNRL_CTL);
+
+ return 0;
+}
+
+static int clk_pll14xx_is_prepared(struct clk *clk)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ u32 val;
+
+ val = readl(pll->base + GNRL_CTL);
+
+ return (val & RST_MASK) ? 1 : 0;
+}
+
+static void clk_pll14xx_unprepare(struct clk *clk)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(clk);
+ u32 val;
+printf("%s %p\n", __func__, pll);
+printf("%s %p\n", __func__, pll->base);
+ /*
+ * Set RST to 0, power down mode is enabled and
+ * every digital block is reset
+ */
+ val = readl(pll->base + GNRL_CTL);
+ val &= ~RST_MASK;
+ writel(val, pll->base + GNRL_CTL);
+}
+
+static const struct clk_ops clk_pll1416x_ops = {
+ .enable = clk_pll14xx_prepare,
+ .disable = clk_pll14xx_unprepare,
+ .is_enabled = clk_pll14xx_is_prepared,
+ .recalc_rate = clk_pll1416x_recalc_rate,
+ .round_rate = clk_pll14xx_round_rate,
+ .set_rate = clk_pll1416x_set_rate,
+};
+
+static const struct clk_ops clk_pll1416x_min_ops = {
+ .recalc_rate = clk_pll1416x_recalc_rate,
+};
+
+static const struct clk_ops clk_pll1443x_ops = {
+ .enable = clk_pll14xx_prepare,
+ .disable = clk_pll14xx_unprepare,
+ .is_enabled = clk_pll14xx_is_prepared,
+ .recalc_rate = clk_pll1443x_recalc_rate,
+ .round_rate = clk_pll14xx_round_rate,
+ .set_rate = clk_pll1443x_set_rate,
+};
+
+struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
+ void __iomem *base,
+ const struct imx_pll14xx_clk *pll_clk)
+{
+ struct clk_pll14xx *pll;
+ struct clk *clk;
+ u32 val;
+ int ret;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ clk = &pll->clk;
+
+ pll->parent = parent_name;
+ clk->name = name;
+ clk->flags = pll_clk->flags;
+ clk->parent_names = &pll->parent;
+ clk->num_parents = 1;
+
+ switch (pll_clk->type) {
+ case PLL_1416X:
+ if (!pll_clk->rate_table)
+ clk->ops = &clk_pll1416x_min_ops;
+ else
+ clk->ops = &clk_pll1416x_ops;
+ break;
+ case PLL_1443X:
+ clk->ops = &clk_pll1443x_ops;
+ break;
+ default:
+ pr_err("%s: Unknown pll type for pll clk %s\n",
+ __func__, name);
+ };
+
+ pll->base = base;
+ pll->type = pll_clk->type;
+ pll->rate_table = pll_clk->rate_table;
+ pll->rate_count = pll_clk->rate_count;
+
+ val = readl(pll->base + GNRL_CTL);
+ val &= ~BYPASS_MASK;
+ writel(val, pll->base + GNRL_CTL);
+
+ ret = clk_register(clk);
+ if (ret) {
+ free(pll);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 04286f03f7..39eff9ee74 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -168,6 +168,50 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent, void __iomem *base,
u32 div_mask);
+enum imx_pll14xx_type {
+ PLL_1416X,
+ PLL_1443X,
+};
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+struct imx_pll14xx_rate_table {
+ unsigned int rate;
+ unsigned int pdiv;
+ unsigned int mdiv;
+ unsigned int sdiv;
+ unsigned int kdiv;
+};
+
+#define PLL_1416X_RATE(_rate, _m, _p, _s) \
+ { \
+ .rate = (_rate), \
+ .mdiv = (_m), \
+ .pdiv = (_p), \
+ .sdiv = (_s), \
+ }
+
+#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \
+ { \
+ .rate = (_rate), \
+ .mdiv = (_m), \
+ .pdiv = (_p), \
+ .sdiv = (_s), \
+ .kdiv = (_k), \
+ }
+
+struct imx_pll14xx_clk {
+ enum imx_pll14xx_type type;
+ const struct imx_pll14xx_rate_table *rate_table;
+ int rate_count;
+ int flags;
+};
+
+extern struct imx_pll14xx_clk imx_1443x_pll;
+extern struct imx_pll14xx_clk imx_1416x_pll;
+
+struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
+ void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
+
struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
void __iomem *base);
@@ -226,4 +270,7 @@ struct clk *imx8m_clk_composite_flags(const char *name,
#define imx8m_clk_composite(name, parent_names, reg) \
__imx8m_clk_composite(name, parent_names, reg, 0)
+#define imx8m_clk_composite_critical(name, parent_names, reg) \
+ __imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
+
#endif /* __IMX_CLK_H */
diff --git a/drivers/ddr/Kconfig b/drivers/ddr/Kconfig
index 4ea71598af..d92c272b58 100644
--- a/drivers/ddr/Kconfig
+++ b/drivers/ddr/Kconfig
@@ -1 +1,2 @@
source "drivers/ddr/fsl/Kconfig"
+source "drivers/ddr/imx8m/Kconfig"
diff --git a/drivers/ddr/Makefile b/drivers/ddr/Makefile
index faf2f9e1d6..7e33182cbc 100644
--- a/drivers/ddr/Makefile
+++ b/drivers/ddr/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_DDR_FSL) += fsl/
+obj-$(CONFIG_IMX8M_DRAM) += imx8m/
diff --git a/drivers/ddr/imx8m/Kconfig b/drivers/ddr/imx8m/Kconfig
new file mode 100644
index 0000000000..e8bce8c49d
--- /dev/null
+++ b/drivers/ddr/imx8m/Kconfig
@@ -0,0 +1,7 @@
+menu "i.MX8M DDR controllers"
+ depends on ARCH_IMX8MQ || ARCH_IMX8MM
+
+config IMX8M_DRAM
+ bool "imx8m dram controller support"
+
+endmenu
diff --git a/drivers/ddr/imx8m/Makefile b/drivers/ddr/imx8m/Makefile
new file mode 100644
index 0000000000..2be313900f
--- /dev/null
+++ b/drivers/ddr/imx8m/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2018 NXP
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+pbl-$(CONFIG_IMX8M_DRAM) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o ddr_init.o
diff --git a/drivers/ddr/imx8m/ddr_init.c b/drivers/ddr/imx8m/ddr_init.c
new file mode 100644
index 0000000000..374601b786
--- /dev/null
+++ b/drivers/ddr/imx8m/ddr_init.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018-2019 NXP
+ */
+#define DEBUG
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <soc/imx8m/ddr.h>
+#include <mach/generic.h>
+#include <mach/imx8m-regs.h>
+#include <mach/imx8m-ccm-regs.h>
+
+#define SRC_DDRC_RCR_ADDR MX8MQ_SRC_DDRC_RCR_ADDR
+
+static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
+{
+ int i = 0;
+
+ for (i = 0; i < num; i++) {
+ reg32_write((unsigned long)ddrc_cfg->reg, ddrc_cfg->val);
+ ddrc_cfg++;
+ }
+}
+
+static int imx8m_ddr_init(unsigned long src_ddrc_rcr,
+ struct dram_timing_info *dram_timing)
+{
+ unsigned int tmp, initial_drate, target_freq;
+ int ret;
+
+ debug("DDRINFO: start DRAM init\n");
+
+ debug("DDRINFO: cfg clk\n");
+
+ /* disable iso */
+ reg32_write(0x303A00EC, 0x0000ffff); /* PGC_CPU_MAPPING */
+ reg32setbit(0x303A00F8, 5); /* PU_PGC_SW_PUP_REQ */
+
+ initial_drate = dram_timing->fsp_msg[0].drate;
+ /* default to the frequency point 0 clock */
+ ddrphy_init_set_dfi_clk(initial_drate);
+
+ /* D-aasert the presetn */
+ reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000006);
+
+ /* Step2: Program the dwc_ddr_umctl2 registers */
+ debug("DDRINFO: ddrc config start\n");
+ ddr_cfg_umctl2(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num);
+ debug("DDRINFO: ddrc config done\n");
+
+ /* Step3: De-assert reset signal(core_ddrc_rstn & aresetn_n) */
+ reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000004);
+ reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000000);
+
+ /*
+ * Step4: Disable auto-refreshes, self-refresh, powerdown, and
+ * assertion of dfi_dram_clk_disable by setting RFSHCTL3.dis_auto_refresh = 1,
+ * PWRCTL.powerdown_en = 0, and PWRCTL.selfref_en = 0,
+ * PWRCTL.en_dfi_dram_clk_disable = 0
+ */
+ reg32_write(DDRC_DBG1(0), 0x00000000);
+ reg32_write(DDRC_RFSHCTL3(0), 0x0000001);
+ reg32_write(DDRC_PWRCTL(0), 0xa0);
+
+ /* if ddr type is LPDDR4, do it */
+ tmp = reg32_read(DDRC_MSTR(0));
+ if (tmp & (0x1 << 5))
+ reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
+
+ /* determine the initial boot frequency */
+ target_freq = reg32_read(DDRC_MSTR2(0)) & 0x3;
+ target_freq = (tmp & (0x1 << 29)) ? target_freq : 0x0;
+
+ /* Step5: Set SWCT.sw_done to 0 */
+ reg32_write(DDRC_SWCTL(0), 0x00000000);
+
+ /* Set the default boot frequency point */
+ clrsetbits_le32(DDRC_DFIMISC(0), (0x1f << 8), target_freq << 8);
+ /* Step6: Set DFIMISC.dfi_init_complete_en to 0 */
+ clrbits_le32(DDRC_DFIMISC(0), 0x1);
+
+ /* Step7: Set SWCTL.sw_done to 1; need to polling SWSTAT.sw_done_ack */
+ reg32_write(DDRC_SWCTL(0), 0x00000001);
+ do {
+ tmp = reg32_read(DDRC_SWSTAT(0));
+ } while ((tmp & 0x1) == 0x0);
+
+ /*
+ * Step8 ~ Step13: Start PHY initialization and training by
+ * accessing relevant PUB registers
+ */
+ debug("DDRINFO:ddrphy config start\n");
+
+ ret = ddr_cfg_phy(dram_timing);
+ if (ret)
+ return ret;
+
+ debug("DDRINFO: ddrphy config done\n");
+
+ /*
+ * step14 CalBusy.0 =1, indicates the calibrator is actively
+ * calibrating. Wait Calibrating done.
+ */
+ do {
+ tmp = reg32_read(DDRPHY_CalBusy(0));
+ } while ((tmp & 0x1));
+
+ debug("DDRINFO:ddrphy calibration done\n");
+
+ /* Step15: Set SWCTL.sw_done to 0 */
+ reg32_write(DDRC_SWCTL(0), 0x00000000);
+
+ /* Step16: Set DFIMISC.dfi_init_start to 1 */
+ setbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
+
+ /* Step17: Set SWCTL.sw_done to 1; need to polling SWSTAT.sw_done_ack */
+ reg32_write(DDRC_SWCTL(0), 0x00000001);
+ do {
+ tmp = reg32_read(DDRC_SWSTAT(0));
+ } while ((tmp & 0x1) == 0x0);
+
+ /* Step18: Polling DFISTAT.dfi_init_complete = 1 */
+ do {
+ tmp = reg32_read(DDRC_DFISTAT(0));
+ } while ((tmp & 0x1) == 0x0);
+
+ /* Step19: Set SWCTL.sw_done to 0 */
+ reg32_write(DDRC_SWCTL(0), 0x00000000);
+
+ /* Step20: Set DFIMISC.dfi_init_start to 0 */
+ clrbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
+
+ /* Step21: optional */
+
+ /* Step22: Set DFIMISC.dfi_init_complete_en to 1 */
+ setbits_le32(DDRC_DFIMISC(0), 0x1);
+
+ /* Step23: Set PWRCTL.selfref_sw to 0 */
+ clrbits_le32(DDRC_PWRCTL(0), (0x1 << 5));
+
+ /* Step24: Set SWCTL.sw_done to 1; need polling SWSTAT.sw_done_ack */
+ reg32_write(DDRC_SWCTL(0), 0x00000001);
+ do {
+ tmp = reg32_read(DDRC_SWSTAT(0));
+ } while ((tmp & 0x1) == 0x0);
+
+ /* Step25: Wait for dwc_ddr_umctl2 to move to normal operating mode by monitoring
+ * STAT.operating_mode signal */
+ do {
+ tmp = reg32_read(DDRC_STAT(0));
+ } while ((tmp & 0x3) != 0x1);
+
+ /* Step26: Set back register in Step4 to the original values if desired */
+ reg32_write(DDRC_RFSHCTL3(0), 0x0000000);
+ /* enable selfref_en by default */
+ setbits_le32(DDRC_PWRCTL(0), 0x1 << 3);
+
+ /* enable port 0 */
+ reg32_write(DDRC_PCTRL_0(0), 0x00000001);
+ debug("DDRINFO: ddrmix config done\n");
+
+ return 0;
+}
+
+/*
+ * We store the timing parameters here. the TF-A will pick these up.
+ * Note that the timing used we leave the driver with is a PLL bypass 25MHz
+ * mode. So if your board runs horribly slow you'll likely have to provide a
+ * TF-A binary.
+ */
+#define IMX8M_SAVED_DRAM_TIMING_BASE 0x180000
+
+int imx8mm_ddr_init(struct dram_timing_info *dram_timing)
+{
+ unsigned long src_ddrc_rcr = MX8M_SRC_DDRC_RCR_ADDR;
+ int ret;
+
+ /* Step1: Follow the power up procedure */
+ reg32_write(src_ddrc_rcr, 0x8f00001f);
+ reg32_write(src_ddrc_rcr, 0x8f00000f);
+
+ ret = imx8m_ddr_init(src_ddrc_rcr, dram_timing);
+ if (ret)
+ return ret;
+
+ /* save the dram timing config into memory */
+ dram_config_save(dram_timing, IMX8M_SAVED_DRAM_TIMING_BASE);
+
+ return 0;
+}
+
+int imx8mq_ddr_init(struct dram_timing_info *dram_timing)
+{
+ unsigned long src_ddrc_rcr = MX8MQ_SRC_DDRC_RCR_ADDR;
+ int ret;
+
+ /* Step1: Follow the power up procedure */
+ reg32_write(src_ddrc_rcr + 0x04, 0x8f00000f);
+ reg32_write(src_ddrc_rcr, 0x8f00000f);
+ reg32_write(src_ddrc_rcr + 0x04, 0x8f000000);
+
+ ret = imx8m_ddr_init(src_ddrc_rcr, dram_timing);
+ if (ret)
+ return ret;
+
+ /* save the dram timing config into memory */
+ dram_config_save(dram_timing, IMX8M_SAVED_DRAM_TIMING_BASE);
+
+ return 0;
+}
diff --git a/drivers/ddr/imx8m/ddrphy_csr.c b/drivers/ddr/imx8m/ddrphy_csr.c
new file mode 100644
index 0000000000..98ac5db3c0
--- /dev/null
+++ b/drivers/ddr/imx8m/ddrphy_csr.c
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <linux/kernel.h>
+#include <soc/imx8m/ddr.h>
+
+/* ddr phy trained csr */
+struct dram_cfg_param ddrphy_trained_csr[] = {
+ { 0x200b2, 0x0 },
+ { 0x1200b2, 0x0 },
+ { 0x2200b2, 0x0 },
+ { 0x200cb, 0x0 },
+ { 0x10043, 0x0 },
+ { 0x110043, 0x0 },
+ { 0x210043, 0x0 },
+ { 0x10143, 0x0 },
+ { 0x110143, 0x0 },
+ { 0x210143, 0x0 },
+ { 0x11043, 0x0 },
+ { 0x111043, 0x0 },
+ { 0x211043, 0x0 },
+ { 0x11143, 0x0 },
+ { 0x111143, 0x0 },
+ { 0x211143, 0x0 },
+ { 0x12043, 0x0 },
+ { 0x112043, 0x0 },
+ { 0x212043, 0x0 },
+ { 0x12143, 0x0 },
+ { 0x112143, 0x0 },
+ { 0x212143, 0x0 },
+ { 0x13043, 0x0 },
+ { 0x113043, 0x0 },
+ { 0x213043, 0x0 },
+ { 0x13143, 0x0 },
+ { 0x113143, 0x0 },
+ { 0x213143, 0x0 },
+ { 0x80, 0x0 },
+ { 0x100080, 0x0 },
+ { 0x200080, 0x0 },
+ { 0x1080, 0x0 },
+ { 0x101080, 0x0 },
+ { 0x201080, 0x0 },
+ { 0x2080, 0x0 },
+ { 0x102080, 0x0 },
+ { 0x202080, 0x0 },
+ { 0x3080, 0x0 },
+ { 0x103080, 0x0 },
+ { 0x203080, 0x0 },
+ { 0x4080, 0x0 },
+ { 0x104080, 0x0 },
+ { 0x204080, 0x0 },
+ { 0x5080, 0x0 },
+ { 0x105080, 0x0 },
+ { 0x205080, 0x0 },
+ { 0x6080, 0x0 },
+ { 0x106080, 0x0 },
+ { 0x206080, 0x0 },
+ { 0x7080, 0x0 },
+ { 0x107080, 0x0 },
+ { 0x207080, 0x0 },
+ { 0x8080, 0x0 },
+ { 0x108080, 0x0 },
+ { 0x208080, 0x0 },
+ { 0x9080, 0x0 },
+ { 0x109080, 0x0 },
+ { 0x209080, 0x0 },
+ { 0x10080, 0x0 },
+ { 0x110080, 0x0 },
+ { 0x210080, 0x0 },
+ { 0x10180, 0x0 },
+ { 0x110180, 0x0 },
+ { 0x210180, 0x0 },
+ { 0x11080, 0x0 },
+ { 0x111080, 0x0 },
+ { 0x211080, 0x0 },
+ { 0x11180, 0x0 },
+ { 0x111180, 0x0 },
+ { 0x211180, 0x0 },
+ { 0x12080, 0x0 },
+ { 0x112080, 0x0 },
+ { 0x212080, 0x0 },
+ { 0x12180, 0x0 },
+ { 0x112180, 0x0 },
+ { 0x212180, 0x0 },
+ { 0x13080, 0x0 },
+ { 0x113080, 0x0 },
+ { 0x213080, 0x0 },
+ { 0x13180, 0x0 },
+ { 0x113180, 0x0 },
+ { 0x213180, 0x0 },
+ { 0x10081, 0x0 },
+ { 0x110081, 0x0 },
+ { 0x210081, 0x0 },
+ { 0x10181, 0x0 },
+ { 0x110181, 0x0 },
+ { 0x210181, 0x0 },
+ { 0x11081, 0x0 },
+ { 0x111081, 0x0 },
+ { 0x211081, 0x0 },
+ { 0x11181, 0x0 },
+ { 0x111181, 0x0 },
+ { 0x211181, 0x0 },
+ { 0x12081, 0x0 },
+ { 0x112081, 0x0 },
+ { 0x212081, 0x0 },
+ { 0x12181, 0x0 },
+ { 0x112181, 0x0 },
+ { 0x212181, 0x0 },
+ { 0x13081, 0x0 },
+ { 0x113081, 0x0 },
+ { 0x213081, 0x0 },
+ { 0x13181, 0x0 },
+ { 0x113181, 0x0 },
+ { 0x213181, 0x0 },
+ { 0x100d0, 0x0 },
+ { 0x1100d0, 0x0 },
+ { 0x2100d0, 0x0 },
+ { 0x101d0, 0x0 },
+ { 0x1101d0, 0x0 },
+ { 0x2101d0, 0x0 },
+ { 0x110d0, 0x0 },
+ { 0x1110d0, 0x0 },
+ { 0x2110d0, 0x0 },
+ { 0x111d0, 0x0 },
+ { 0x1111d0, 0x0 },
+ { 0x2111d0, 0x0 },
+ { 0x120d0, 0x0 },
+ { 0x1120d0, 0x0 },
+ { 0x2120d0, 0x0 },
+ { 0x121d0, 0x0 },
+ { 0x1121d0, 0x0 },
+ { 0x2121d0, 0x0 },
+ { 0x130d0, 0x0 },
+ { 0x1130d0, 0x0 },
+ { 0x2130d0, 0x0 },
+ { 0x131d0, 0x0 },
+ { 0x1131d0, 0x0 },
+ { 0x2131d0, 0x0 },
+ { 0x100d1, 0x0 },
+ { 0x1100d1, 0x0 },
+ { 0x2100d1, 0x0 },
+ { 0x101d1, 0x0 },
+ { 0x1101d1, 0x0 },
+ { 0x2101d1, 0x0 },
+ { 0x110d1, 0x0 },
+ { 0x1110d1, 0x0 },
+ { 0x2110d1, 0x0 },
+ { 0x111d1, 0x0 },
+ { 0x1111d1, 0x0 },
+ { 0x2111d1, 0x0 },
+ { 0x120d1, 0x0 },
+ { 0x1120d1, 0x0 },
+ { 0x2120d1, 0x0 },
+ { 0x121d1, 0x0 },
+ { 0x1121d1, 0x0 },
+ { 0x2121d1, 0x0 },
+ { 0x130d1, 0x0 },
+ { 0x1130d1, 0x0 },
+ { 0x2130d1, 0x0 },
+ { 0x131d1, 0x0 },
+ { 0x1131d1, 0x0 },
+ { 0x2131d1, 0x0 },
+ { 0x10068, 0x0 },
+ { 0x10168, 0x0 },
+ { 0x10268, 0x0 },
+ { 0x10368, 0x0 },
+ { 0x10468, 0x0 },
+ { 0x10568, 0x0 },
+ { 0x10668, 0x0 },
+ { 0x10768, 0x0 },
+ { 0x10868, 0x0 },
+ { 0x11068, 0x0 },
+ { 0x11168, 0x0 },
+ { 0x11268, 0x0 },
+ { 0x11368, 0x0 },
+ { 0x11468, 0x0 },
+ { 0x11568, 0x0 },
+ { 0x11668, 0x0 },
+ { 0x11768, 0x0 },
+ { 0x11868, 0x0 },
+ { 0x12068, 0x0 },
+ { 0x12168, 0x0 },
+ { 0x12268, 0x0 },
+ { 0x12368, 0x0 },
+ { 0x12468, 0x0 },
+ { 0x12568, 0x0 },
+ { 0x12668, 0x0 },
+ { 0x12768, 0x0 },
+ { 0x12868, 0x0 },
+ { 0x13068, 0x0 },
+ { 0x13168, 0x0 },
+ { 0x13268, 0x0 },
+ { 0x13368, 0x0 },
+ { 0x13468, 0x0 },
+ { 0x13568, 0x0 },
+ { 0x13668, 0x0 },
+ { 0x13768, 0x0 },
+ { 0x13868, 0x0 },
+ { 0x10069, 0x0 },
+ { 0x10169, 0x0 },
+ { 0x10269, 0x0 },
+ { 0x10369, 0x0 },
+ { 0x10469, 0x0 },
+ { 0x10569, 0x0 },
+ { 0x10669, 0x0 },
+ { 0x10769, 0x0 },
+ { 0x10869, 0x0 },
+ { 0x11069, 0x0 },
+ { 0x11169, 0x0 },
+ { 0x11269, 0x0 },
+ { 0x11369, 0x0 },
+ { 0x11469, 0x0 },
+ { 0x11569, 0x0 },
+ { 0x11669, 0x0 },
+ { 0x11769, 0x0 },
+ { 0x11869, 0x0 },
+ { 0x12069, 0x0 },
+ { 0x12169, 0x0 },
+ { 0x12269, 0x0 },
+ { 0x12369, 0x0 },
+ { 0x12469, 0x0 },
+ { 0x12569, 0x0 },
+ { 0x12669, 0x0 },
+ { 0x12769, 0x0 },
+ { 0x12869, 0x0 },
+ { 0x13069, 0x0 },
+ { 0x13169, 0x0 },
+ { 0x13269, 0x0 },
+ { 0x13369, 0x0 },
+ { 0x13469, 0x0 },
+ { 0x13569, 0x0 },
+ { 0x13669, 0x0 },
+ { 0x13769, 0x0 },
+ { 0x13869, 0x0 },
+ { 0x1008c, 0x0 },
+ { 0x11008c, 0x0 },
+ { 0x21008c, 0x0 },
+ { 0x1018c, 0x0 },
+ { 0x11018c, 0x0 },
+ { 0x21018c, 0x0 },
+ { 0x1108c, 0x0 },
+ { 0x11108c, 0x0 },
+ { 0x21108c, 0x0 },
+ { 0x1118c, 0x0 },
+ { 0x11118c, 0x0 },
+ { 0x21118c, 0x0 },
+ { 0x1208c, 0x0 },
+ { 0x11208c, 0x0 },
+ { 0x21208c, 0x0 },
+ { 0x1218c, 0x0 },
+ { 0x11218c, 0x0 },
+ { 0x21218c, 0x0 },
+ { 0x1308c, 0x0 },
+ { 0x11308c, 0x0 },
+ { 0x21308c, 0x0 },
+ { 0x1318c, 0x0 },
+ { 0x11318c, 0x0 },
+ { 0x21318c, 0x0 },
+ { 0x1008d, 0x0 },
+ { 0x11008d, 0x0 },
+ { 0x21008d, 0x0 },
+ { 0x1018d, 0x0 },
+ { 0x11018d, 0x0 },
+ { 0x21018d, 0x0 },
+ { 0x1108d, 0x0 },
+ { 0x11108d, 0x0 },
+ { 0x21108d, 0x0 },
+ { 0x1118d, 0x0 },
+ { 0x11118d, 0x0 },
+ { 0x21118d, 0x0 },
+ { 0x1208d, 0x0 },
+ { 0x11208d, 0x0 },
+ { 0x21208d, 0x0 },
+ { 0x1218d, 0x0 },
+ { 0x11218d, 0x0 },
+ { 0x21218d, 0x0 },
+ { 0x1308d, 0x0 },
+ { 0x11308d, 0x0 },
+ { 0x21308d, 0x0 },
+ { 0x1318d, 0x0 },
+ { 0x11318d, 0x0 },
+ { 0x21318d, 0x0 },
+ { 0x100c0, 0x0 },
+ { 0x1100c0, 0x0 },
+ { 0x2100c0, 0x0 },
+ { 0x101c0, 0x0 },
+ { 0x1101c0, 0x0 },
+ { 0x2101c0, 0x0 },
+ { 0x102c0, 0x0 },
+ { 0x1102c0, 0x0 },
+ { 0x2102c0, 0x0 },
+ { 0x103c0, 0x0 },
+ { 0x1103c0, 0x0 },
+ { 0x2103c0, 0x0 },
+ { 0x104c0, 0x0 },
+ { 0x1104c0, 0x0 },
+ { 0x2104c0, 0x0 },
+ { 0x105c0, 0x0 },
+ { 0x1105c0, 0x0 },
+ { 0x2105c0, 0x0 },
+ { 0x106c0, 0x0 },
+ { 0x1106c0, 0x0 },
+ { 0x2106c0, 0x0 },
+ { 0x107c0, 0x0 },
+ { 0x1107c0, 0x0 },
+ { 0x2107c0, 0x0 },
+ { 0x108c0, 0x0 },
+ { 0x1108c0, 0x0 },
+ { 0x2108c0, 0x0 },
+ { 0x110c0, 0x0 },
+ { 0x1110c0, 0x0 },
+ { 0x2110c0, 0x0 },
+ { 0x111c0, 0x0 },
+ { 0x1111c0, 0x0 },
+ { 0x2111c0, 0x0 },
+ { 0x112c0, 0x0 },
+ { 0x1112c0, 0x0 },
+ { 0x2112c0, 0x0 },
+ { 0x113c0, 0x0 },
+ { 0x1113c0, 0x0 },
+ { 0x2113c0, 0x0 },
+ { 0x114c0, 0x0 },
+ { 0x1114c0, 0x0 },
+ { 0x2114c0, 0x0 },
+ { 0x115c0, 0x0 },
+ { 0x1115c0, 0x0 },
+ { 0x2115c0, 0x0 },
+ { 0x116c0, 0x0 },
+ { 0x1116c0, 0x0 },
+ { 0x2116c0, 0x0 },
+ { 0x117c0, 0x0 },
+ { 0x1117c0, 0x0 },
+ { 0x2117c0, 0x0 },
+ { 0x118c0, 0x0 },
+ { 0x1118c0, 0x0 },
+ { 0x2118c0, 0x0 },
+ { 0x120c0, 0x0 },
+ { 0x1120c0, 0x0 },
+ { 0x2120c0, 0x0 },
+ { 0x121c0, 0x0 },
+ { 0x1121c0, 0x0 },
+ { 0x2121c0, 0x0 },
+ { 0x122c0, 0x0 },
+ { 0x1122c0, 0x0 },
+ { 0x2122c0, 0x0 },
+ { 0x123c0, 0x0 },
+ { 0x1123c0, 0x0 },
+ { 0x2123c0, 0x0 },
+ { 0x124c0, 0x0 },
+ { 0x1124c0, 0x0 },
+ { 0x2124c0, 0x0 },
+ { 0x125c0, 0x0 },
+ { 0x1125c0, 0x0 },
+ { 0x2125c0, 0x0 },
+ { 0x126c0, 0x0 },
+ { 0x1126c0, 0x0 },
+ { 0x2126c0, 0x0 },
+ { 0x127c0, 0x0 },
+ { 0x1127c0, 0x0 },
+ { 0x2127c0, 0x0 },
+ { 0x128c0, 0x0 },
+ { 0x1128c0, 0x0 },
+ { 0x2128c0, 0x0 },
+ { 0x130c0, 0x0 },
+ { 0x1130c0, 0x0 },
+ { 0x2130c0, 0x0 },
+ { 0x131c0, 0x0 },
+ { 0x1131c0, 0x0 },
+ { 0x2131c0, 0x0 },
+ { 0x132c0, 0x0 },
+ { 0x1132c0, 0x0 },
+ { 0x2132c0, 0x0 },
+ { 0x133c0, 0x0 },
+ { 0x1133c0, 0x0 },
+ { 0x2133c0, 0x0 },
+ { 0x134c0, 0x0 },
+ { 0x1134c0, 0x0 },
+ { 0x2134c0, 0x0 },
+ { 0x135c0, 0x0 },
+ { 0x1135c0, 0x0 },
+ { 0x2135c0, 0x0 },
+ { 0x136c0, 0x0 },
+ { 0x1136c0, 0x0 },
+ { 0x2136c0, 0x0 },
+ { 0x137c0, 0x0 },
+ { 0x1137c0, 0x0 },
+ { 0x2137c0, 0x0 },
+ { 0x138c0, 0x0 },
+ { 0x1138c0, 0x0 },
+ { 0x2138c0, 0x0 },
+ { 0x100c1, 0x0 },
+ { 0x1100c1, 0x0 },
+ { 0x2100c1, 0x0 },
+ { 0x101c1, 0x0 },
+ { 0x1101c1, 0x0 },
+ { 0x2101c1, 0x0 },
+ { 0x102c1, 0x0 },
+ { 0x1102c1, 0x0 },
+ { 0x2102c1, 0x0 },
+ { 0x103c1, 0x0 },
+ { 0x1103c1, 0x0 },
+ { 0x2103c1, 0x0 },
+ { 0x104c1, 0x0 },
+ { 0x1104c1, 0x0 },
+ { 0x2104c1, 0x0 },
+ { 0x105c1, 0x0 },
+ { 0x1105c1, 0x0 },
+ { 0x2105c1, 0x0 },
+ { 0x106c1, 0x0 },
+ { 0x1106c1, 0x0 },
+ { 0x2106c1, 0x0 },
+ { 0x107c1, 0x0 },
+ { 0x1107c1, 0x0 },
+ { 0x2107c1, 0x0 },
+ { 0x108c1, 0x0 },
+ { 0x1108c1, 0x0 },
+ { 0x2108c1, 0x0 },
+ { 0x110c1, 0x0 },
+ { 0x1110c1, 0x0 },
+ { 0x2110c1, 0x0 },
+ { 0x111c1, 0x0 },
+ { 0x1111c1, 0x0 },
+ { 0x2111c1, 0x0 },
+ { 0x112c1, 0x0 },
+ { 0x1112c1, 0x0 },
+ { 0x2112c1, 0x0 },
+ { 0x113c1, 0x0 },
+ { 0x1113c1, 0x0 },
+ { 0x2113c1, 0x0 },
+ { 0x114c1, 0x0 },
+ { 0x1114c1, 0x0 },
+ { 0x2114c1, 0x0 },
+ { 0x115c1, 0x0 },
+ { 0x1115c1, 0x0 },
+ { 0x2115c1, 0x0 },
+ { 0x116c1, 0x0 },
+ { 0x1116c1, 0x0 },
+ { 0x2116c1, 0x0 },
+ { 0x117c1, 0x0 },
+ { 0x1117c1, 0x0 },
+ { 0x2117c1, 0x0 },
+ { 0x118c1, 0x0 },
+ { 0x1118c1, 0x0 },
+ { 0x2118c1, 0x0 },
+ { 0x120c1, 0x0 },
+ { 0x1120c1, 0x0 },
+ { 0x2120c1, 0x0 },
+ { 0x121c1, 0x0 },
+ { 0x1121c1, 0x0 },
+ { 0x2121c1, 0x0 },
+ { 0x122c1, 0x0 },
+ { 0x1122c1, 0x0 },
+ { 0x2122c1, 0x0 },
+ { 0x123c1, 0x0 },
+ { 0x1123c1, 0x0 },
+ { 0x2123c1, 0x0 },
+ { 0x124c1, 0x0 },
+ { 0x1124c1, 0x0 },
+ { 0x2124c1, 0x0 },
+ { 0x125c1, 0x0 },
+ { 0x1125c1, 0x0 },
+ { 0x2125c1, 0x0 },
+ { 0x126c1, 0x0 },
+ { 0x1126c1, 0x0 },
+ { 0x2126c1, 0x0 },
+ { 0x127c1, 0x0 },
+ { 0x1127c1, 0x0 },
+ { 0x2127c1, 0x0 },
+ { 0x128c1, 0x0 },
+ { 0x1128c1, 0x0 },
+ { 0x2128c1, 0x0 },
+ { 0x130c1, 0x0 },
+ { 0x1130c1, 0x0 },
+ { 0x2130c1, 0x0 },
+ { 0x131c1, 0x0 },
+ { 0x1131c1, 0x0 },
+ { 0x2131c1, 0x0 },
+ { 0x132c1, 0x0 },
+ { 0x1132c1, 0x0 },
+ { 0x2132c1, 0x0 },
+ { 0x133c1, 0x0 },
+ { 0x1133c1, 0x0 },
+ { 0x2133c1, 0x0 },
+ { 0x134c1, 0x0 },
+ { 0x1134c1, 0x0 },
+ { 0x2134c1, 0x0 },
+ { 0x135c1, 0x0 },
+ { 0x1135c1, 0x0 },
+ { 0x2135c1, 0x0 },
+ { 0x136c1, 0x0 },
+ { 0x1136c1, 0x0 },
+ { 0x2136c1, 0x0 },
+ { 0x137c1, 0x0 },
+ { 0x1137c1, 0x0 },
+ { 0x2137c1, 0x0 },
+ { 0x138c1, 0x0 },
+ { 0x1138c1, 0x0 },
+ { 0x2138c1, 0x0 },
+ { 0x10020, 0x0 },
+ { 0x110020, 0x0 },
+ { 0x210020, 0x0 },
+ { 0x11020, 0x0 },
+ { 0x111020, 0x0 },
+ { 0x211020, 0x0 },
+ { 0x12020, 0x0 },
+ { 0x112020, 0x0 },
+ { 0x212020, 0x0 },
+ { 0x13020, 0x0 },
+ { 0x113020, 0x0 },
+ { 0x213020, 0x0 },
+ { 0x20072, 0x0 },
+ { 0x20073, 0x0 },
+ { 0x20074, 0x0 },
+ { 0x100aa, 0x0 },
+ { 0x110aa, 0x0 },
+ { 0x120aa, 0x0 },
+ { 0x130aa, 0x0 },
+ { 0x20010, 0x0 },
+ { 0x120010, 0x0 },
+ { 0x220010, 0x0 },
+ { 0x20011, 0x0 },
+ { 0x120011, 0x0 },
+ { 0x220011, 0x0 },
+ { 0x100ae, 0x0 },
+ { 0x1100ae, 0x0 },
+ { 0x2100ae, 0x0 },
+ { 0x100af, 0x0 },
+ { 0x1100af, 0x0 },
+ { 0x2100af, 0x0 },
+ { 0x110ae, 0x0 },
+ { 0x1110ae, 0x0 },
+ { 0x2110ae, 0x0 },
+ { 0x110af, 0x0 },
+ { 0x1110af, 0x0 },
+ { 0x2110af, 0x0 },
+ { 0x120ae, 0x0 },
+ { 0x1120ae, 0x0 },
+ { 0x2120ae, 0x0 },
+ { 0x120af, 0x0 },
+ { 0x1120af, 0x0 },
+ { 0x2120af, 0x0 },
+ { 0x130ae, 0x0 },
+ { 0x1130ae, 0x0 },
+ { 0x2130ae, 0x0 },
+ { 0x130af, 0x0 },
+ { 0x1130af, 0x0 },
+ { 0x2130af, 0x0 },
+ { 0x20020, 0x0 },
+ { 0x120020, 0x0 },
+ { 0x220020, 0x0 },
+ { 0x100a0, 0x0 },
+ { 0x100a1, 0x0 },
+ { 0x100a2, 0x0 },
+ { 0x100a3, 0x0 },
+ { 0x100a4, 0x0 },
+ { 0x100a5, 0x0 },
+ { 0x100a6, 0x0 },
+ { 0x100a7, 0x0 },
+ { 0x110a0, 0x0 },
+ { 0x110a1, 0x0 },
+ { 0x110a2, 0x0 },
+ { 0x110a3, 0x0 },
+ { 0x110a4, 0x0 },
+ { 0x110a5, 0x0 },
+ { 0x110a6, 0x0 },
+ { 0x110a7, 0x0 },
+ { 0x120a0, 0x0 },
+ { 0x120a1, 0x0 },
+ { 0x120a2, 0x0 },
+ { 0x120a3, 0x0 },
+ { 0x120a4, 0x0 },
+ { 0x120a5, 0x0 },
+ { 0x120a6, 0x0 },
+ { 0x120a7, 0x0 },
+ { 0x130a0, 0x0 },
+ { 0x130a1, 0x0 },
+ { 0x130a2, 0x0 },
+ { 0x130a3, 0x0 },
+ { 0x130a4, 0x0 },
+ { 0x130a5, 0x0 },
+ { 0x130a6, 0x0 },
+ { 0x130a7, 0x0 },
+ { 0x2007c, 0x0 },
+ { 0x12007c, 0x0 },
+ { 0x22007c, 0x0 },
+ { 0x2007d, 0x0 },
+ { 0x12007d, 0x0 },
+ { 0x22007d, 0x0 },
+ { 0x400fd, 0x0 },
+ { 0x400c0, 0x0 },
+ { 0x90201, 0x0 },
+ { 0x190201, 0x0 },
+ { 0x290201, 0x0 },
+ { 0x90202, 0x0 },
+ { 0x190202, 0x0 },
+ { 0x290202, 0x0 },
+ { 0x90203, 0x0 },
+ { 0x190203, 0x0 },
+ { 0x290203, 0x0 },
+ { 0x90204, 0x0 },
+ { 0x190204, 0x0 },
+ { 0x290204, 0x0 },
+ { 0x90205, 0x0 },
+ { 0x190205, 0x0 },
+ { 0x290205, 0x0 },
+ { 0x90206, 0x0 },
+ { 0x190206, 0x0 },
+ { 0x290206, 0x0 },
+ { 0x90207, 0x0 },
+ { 0x190207, 0x0 },
+ { 0x290207, 0x0 },
+ { 0x90208, 0x0 },
+ { 0x190208, 0x0 },
+ { 0x290208, 0x0 },
+ { 0x10062, 0x0 },
+ { 0x10162, 0x0 },
+ { 0x10262, 0x0 },
+ { 0x10362, 0x0 },
+ { 0x10462, 0x0 },
+ { 0x10562, 0x0 },
+ { 0x10662, 0x0 },
+ { 0x10762, 0x0 },
+ { 0x10862, 0x0 },
+ { 0x11062, 0x0 },
+ { 0x11162, 0x0 },
+ { 0x11262, 0x0 },
+ { 0x11362, 0x0 },
+ { 0x11462, 0x0 },
+ { 0x11562, 0x0 },
+ { 0x11662, 0x0 },
+ { 0x11762, 0x0 },
+ { 0x11862, 0x0 },
+ { 0x12062, 0x0 },
+ { 0x12162, 0x0 },
+ { 0x12262, 0x0 },
+ { 0x12362, 0x0 },
+ { 0x12462, 0x0 },
+ { 0x12562, 0x0 },
+ { 0x12662, 0x0 },
+ { 0x12762, 0x0 },
+ { 0x12862, 0x0 },
+ { 0x13062, 0x0 },
+ { 0x13162, 0x0 },
+ { 0x13262, 0x0 },
+ { 0x13362, 0x0 },
+ { 0x13462, 0x0 },
+ { 0x13562, 0x0 },
+ { 0x13662, 0x0 },
+ { 0x13762, 0x0 },
+ { 0x13862, 0x0 },
+ { 0x20077, 0x0 },
+ { 0x10001, 0x0 },
+ { 0x11001, 0x0 },
+ { 0x12001, 0x0 },
+ { 0x13001, 0x0 },
+ { 0x10040, 0x0 },
+ { 0x10140, 0x0 },
+ { 0x10240, 0x0 },
+ { 0x10340, 0x0 },
+ { 0x10440, 0x0 },
+ { 0x10540, 0x0 },
+ { 0x10640, 0x0 },
+ { 0x10740, 0x0 },
+ { 0x10840, 0x0 },
+ { 0x10030, 0x0 },
+ { 0x10130, 0x0 },
+ { 0x10230, 0x0 },
+ { 0x10330, 0x0 },
+ { 0x10430, 0x0 },
+ { 0x10530, 0x0 },
+ { 0x10630, 0x0 },
+ { 0x10730, 0x0 },
+ { 0x10830, 0x0 },
+ { 0x11040, 0x0 },
+ { 0x11140, 0x0 },
+ { 0x11240, 0x0 },
+ { 0x11340, 0x0 },
+ { 0x11440, 0x0 },
+ { 0x11540, 0x0 },
+ { 0x11640, 0x0 },
+ { 0x11740, 0x0 },
+ { 0x11840, 0x0 },
+ { 0x11030, 0x0 },
+ { 0x11130, 0x0 },
+ { 0x11230, 0x0 },
+ { 0x11330, 0x0 },
+ { 0x11430, 0x0 },
+ { 0x11530, 0x0 },
+ { 0x11630, 0x0 },
+ { 0x11730, 0x0 },
+ { 0x11830, 0x0 },
+ { 0x12040, 0x0 },
+ { 0x12140, 0x0 },
+ { 0x12240, 0x0 },
+ { 0x12340, 0x0 },
+ { 0x12440, 0x0 },
+ { 0x12540, 0x0 },
+ { 0x12640, 0x0 },
+ { 0x12740, 0x0 },
+ { 0x12840, 0x0 },
+ { 0x12030, 0x0 },
+ { 0x12130, 0x0 },
+ { 0x12230, 0x0 },
+ { 0x12330, 0x0 },
+ { 0x12430, 0x0 },
+ { 0x12530, 0x0 },
+ { 0x12630, 0x0 },
+ { 0x12730, 0x0 },
+ { 0x12830, 0x0 },
+ { 0x13040, 0x0 },
+ { 0x13140, 0x0 },
+ { 0x13240, 0x0 },
+ { 0x13340, 0x0 },
+ { 0x13440, 0x0 },
+ { 0x13540, 0x0 },
+ { 0x13640, 0x0 },
+ { 0x13740, 0x0 },
+ { 0x13840, 0x0 },
+ { 0x13030, 0x0 },
+ { 0x13130, 0x0 },
+ { 0x13230, 0x0 },
+ { 0x13330, 0x0 },
+ { 0x13430, 0x0 },
+ { 0x13530, 0x0 },
+ { 0x13630, 0x0 },
+ { 0x13730, 0x0 },
+ { 0x13830, 0x0 },
+};
+
+uint32_t ddrphy_trained_csr_num = ARRAY_SIZE(ddrphy_trained_csr);
diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx8m/ddrphy_train.c
new file mode 100644
index 0000000000..c2238cc66b
--- /dev/null
+++ b/drivers/ddr/imx8m/ddrphy_train.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+#define DEBUG
+#include <common.h>
+#include <linux/kernel.h>
+#include <soc/imx8m/ddr.h>
+#include <firmware.h>
+#include <mach/imx8m-regs.h>
+
+void ddr_load_train_code(enum fw_type 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);
+ } else {
+ get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &imem, &isize);
+ get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &dmem, &dsize);
+ }
+
+ ddrc_phy_load_firmware(IOMEM(MX8M_DDRC_PHY_BASE_ADDR),
+ DDRC_PHY_IMEM, imem, isize);
+
+ ddrc_phy_load_firmware(IOMEM(MX8M_DDRC_PHY_BASE_ADDR),
+ DDRC_PHY_DMEM, dmem, dsize);
+}
+
+int ddr_cfg_phy(struct dram_timing_info *dram_timing)
+{
+ struct dram_cfg_param *dram_cfg;
+ struct dram_fsp_msg *fsp_msg;
+ unsigned int num;
+ int i = 0;
+ int j = 0;
+ int ret;
+
+ /* initialize PHY configuration */
+ dram_cfg = dram_timing->ddrphy_cfg;
+ num = dram_timing->ddrphy_cfg_num;
+ for (i = 0; i < num; i++) {
+ /* config phy reg */
+ dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+ dram_cfg++;
+ }
+
+ /* load the frequency setpoint message block config */
+ fsp_msg = dram_timing->fsp_msg;
+ for (i = 0; i < dram_timing->fsp_msg_num; i++) {
+ debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
+ /* set dram PHY input clocks to desired frequency */
+ ddrphy_init_set_dfi_clk(fsp_msg->drate);
+
+ /* load the dram training firmware image */
+ dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ ddr_load_train_code(fsp_msg->fw_type);
+
+ /* load the frequency set point message block parameter */
+ dram_cfg = fsp_msg->fsp_cfg;
+ num = fsp_msg->fsp_cfg_num;
+ for (j = 0; j < num; j++) {
+ dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+ dram_cfg++;
+ }
+
+ /*
+ * -------------------- excute the firmware --------------------
+ * Running the firmware is a simply process to taking the
+ * PMU out of reset and stall, then the firwmare will be run
+ * 1. reset the PMU;
+ * 2. begin the excution;
+ * 3. wait for the training done;
+ * 4. read the message block result.
+ * -------------------------------------------------------------
+ */
+ dwc_ddrphy_apb_wr(0xd0000, 0x1);
+ dwc_ddrphy_apb_wr(0xd0099, 0x9);
+ dwc_ddrphy_apb_wr(0xd0099, 0x1);
+ dwc_ddrphy_apb_wr(0xd0099, 0x0);
+
+ /* Wait for the training firmware to complete */
+ ret = wait_ddrphy_training_complete();
+ if (ret)
+ return ret;
+
+ /* Halt the microcontroller. */
+ dwc_ddrphy_apb_wr(0xd0099, 0x1);
+
+ /* Read the Message Block results */
+ dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ ddrphy_init_read_msg_block(fsp_msg->fw_type);
+ dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
+ fsp_msg++;
+ }
+
+ /* Load PHY Init Engine Image */
+ dram_cfg = dram_timing->ddrphy_pie;
+ num = dram_timing->ddrphy_pie_num;
+ for (i = 0; i < num; i++) {
+ dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+ dram_cfg++;
+ }
+
+ /* save the ddr PHY trained CSR in memory for low power use */
+ ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num);
+
+ return 0;
+}
diff --git a/drivers/ddr/imx8m/ddrphy_utils.c b/drivers/ddr/imx8m/ddrphy_utils.c
new file mode 100644
index 0000000000..651bb4b698
--- /dev/null
+++ b/drivers/ddr/imx8m/ddrphy_utils.c
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+* Copyright 2018 NXP
+*/
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <linux/iopoll.h>
+#include <soc/imx8m/ddr.h>
+#include <mach/imx8m-regs.h>
+#include <mach/imx8m-ccm-regs.h>
+
+void ddrc_phy_load_firmware(void __iomem *phy,
+ enum ddrc_phy_firmware_offset offset,
+ const u16 *blob, size_t size)
+{
+ while (size) {
+ writew(*blob++, phy + DDRC_PHY_REG(offset));
+ offset++;
+ size -= sizeof(*blob);
+ }
+}
+
+enum pmc_constants {
+ PMC_MESSAGE_ID,
+ PMC_MESSAGE_STREAM,
+
+ PMC_TRAIN_SUCCESS = 0x07,
+ PMC_TRAIN_STREAM_START = 0x08,
+ PMC_TRAIN_FAIL = 0xff,
+};
+
+static u32 ddrc_phy_get_message(void __iomem *phy, int type)
+{
+ u32 r, message;
+
+ /*
+ * When BIT0 set to 0, the PMU has a message for the user
+ * Wait for it indefinitely.
+ */
+ readl_poll_timeout(phy + DDRC_PHY_REG(0xd0004),
+ r, !(r & BIT(0)), 0);
+
+ switch (type) {
+ case PMC_MESSAGE_ID:
+ /*
+ * Get the major message ID
+ */
+ message = readl(phy + DDRC_PHY_REG(0xd0032));
+ break;
+ case PMC_MESSAGE_STREAM:
+ message = readl(phy + DDRC_PHY_REG(0xd0034));
+ message <<= 16;
+ message |= readl(phy + DDRC_PHY_REG(0xd0032));
+ break;
+ }
+
+ /*
+ * By setting this register to 0, the user acknowledges the
+ * receipt of the message.
+ */
+ writel(0x00000000, phy + DDRC_PHY_REG(0xd0031));
+ /*
+ * When BIT0 set to 0, the PMU has a message for the user
+ */
+ readl_poll_timeout(phy + DDRC_PHY_REG(0xd0004),
+ r, r & BIT(0), 0);
+
+ writel(0x00000001, phy + DDRC_PHY_REG(0xd0031));
+
+ return message;
+}
+
+static void ddrc_phy_fetch_streaming_message(void __iomem *phy)
+{
+ const u16 index = ddrc_phy_get_message(phy, PMC_MESSAGE_STREAM);
+ u16 i;
+
+ for (i = 0; i < index; i++)
+ ddrc_phy_get_message(phy, PMC_MESSAGE_STREAM);
+}
+
+int wait_ddrphy_training_complete(void)
+{
+ void __iomem *phy = IOMEM(MX8M_DDRC_PHY_BASE_ADDR);
+
+ for (;;) {
+ const u32 m = ddrc_phy_get_message(phy, PMC_MESSAGE_ID);
+
+ switch (m) {
+ case PMC_TRAIN_STREAM_START:
+ ddrc_phy_fetch_streaming_message(phy);
+ break;
+ case PMC_TRAIN_SUCCESS:
+ return 0;
+ case PMC_TRAIN_FAIL:
+ hang();
+ }
+ }
+}
+
+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)
+{
+ int i;
+ struct dram_bypass_clk_setting *config;
+
+ 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);
+ 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_CCM_TARGET_ROOTn_MUX(1));
+}
+
+static void dram_disable_bypass(void)
+{
+ imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(0));
+ imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(4) |
+ 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_pll_init(u32 freq)
+{
+ volatile int i;
+ u32 tmp;
+ void *pll_base;
+ struct imx_int_pll_rate_table *rate;
+
+ rate = fracpll(freq);
+ if (!rate) {
+ printf("No matched freq table %u\n", freq);
+ return -EINVAL;
+ }
+
+ setbits_le32(MX8M_GPC_BASE_ADDR + 0xec, 1 << 7);
+ setbits_le32(MX8M_GPC_BASE_ADDR + 0xf8, 1 << 5);
+ writel(0x8F000000UL, MX8M_SRC_BASE_ADDR + 0x1004);
+
+ pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x50;
+
+ /* Bypass clock and set lock to pll output lock */
+ tmp = readl(pll_base);
+ tmp |= BYPASS_MASK;
+ writel(tmp, pll_base);
+
+ /* Enable RST */
+ tmp &= ~RST_MASK;
+ writel(tmp, pll_base);
+
+ writel(rate->r1, pll_base + 4);
+ writel(rate->r2, pll_base + 8);
+
+ for (i = 0; i < 1000; i++);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel(tmp, pll_base);
+
+ /* Wait Lock*/
+ while (!(readl(pll_base) & LOCK_STATUS));
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel(tmp, pll_base);
+
+ return 0;
+}
+
+void ddrphy_init_set_dfi_clk(unsigned int drate)
+{
+ switch (drate) {
+ case 4000:
+ dram_pll_init(MHZ(1000));
+ dram_disable_bypass();
+ break;
+ case 3200:
+ dram_pll_init(MHZ(800));
+ dram_disable_bypass();
+ break;
+ case 3000:
+ dram_pll_init(MHZ(750));
+ dram_disable_bypass();
+ break;
+ case 2400:
+ dram_pll_init(MHZ(600));
+ dram_disable_bypass();
+ break;
+ case 1600:
+ dram_pll_init(MHZ(400));
+ dram_disable_bypass();
+ break;
+ case 1066:
+ dram_pll_init(MHZ(266));
+ dram_disable_bypass();
+ break;
+ case 667:
+ dram_pll_init(MHZ(167));
+ dram_disable_bypass();
+ break;
+ case 400:
+ dram_enable_bypass(MHZ(400));
+ break;
+ case 100:
+ dram_enable_bypass(MHZ(100));
+ break;
+ default:
+ return;
+ }
+}
+
+void ddrphy_init_read_msg_block(enum fw_type type)
+{
+}
diff --git a/drivers/ddr/imx8m/helper.c b/drivers/ddr/imx8m/helper.c
new file mode 100644
index 0000000000..9e32ef9376
--- /dev/null
+++ b/drivers/ddr/imx8m/helper.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <io.h>
+#include <errno.h>
+#include <soc/imx8m/ddr.h>
+
+#define IMEM_LEN 32768 /* byte */
+#define DMEM_LEN 16384 /* byte */
+#define IMEM_2D_OFFSET 49152
+
+#define IMEM_OFFSET_ADDR 0x00050000
+#define DMEM_OFFSET_ADDR 0x00054000
+#define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0)
+
+void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr,
+ unsigned int num)
+{
+ int i = 0;
+
+ /* enable the ddrphy apb */
+ dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ dwc_ddrphy_apb_wr(0xc0080, 0x3);
+ for (i = 0; i < num; i++) {
+ ddrphy_csr->val = dwc_ddrphy_apb_rd(ddrphy_csr->reg);
+ ddrphy_csr++;
+ }
+ /* disable the ddrphy apb */
+ dwc_ddrphy_apb_wr(0xc0080, 0x2);
+ dwc_ddrphy_apb_wr(0xd0000, 0x1);
+}
+
+void dram_config_save(struct dram_timing_info *timing_info,
+ unsigned long saved_timing_base)
+{
+ int i = 0;
+ struct dram_timing_info *saved_timing = (void *)saved_timing_base;
+ struct dram_cfg_param *cfg;
+
+ saved_timing->ddrc_cfg_num = timing_info->ddrc_cfg_num;
+ saved_timing->ddrphy_cfg_num = timing_info->ddrphy_cfg_num;
+ saved_timing->ddrphy_trained_csr_num = ddrphy_trained_csr_num;
+ saved_timing->ddrphy_pie_num = timing_info->ddrphy_pie_num;
+
+ /* save the fsp table */
+ for (i = 0; i < 4; i++)
+ saved_timing->fsp_table[i] = timing_info->fsp_table[i];
+
+ cfg = (struct dram_cfg_param *)(saved_timing_base +
+ sizeof(*timing_info));
+
+ /* save ddrc config */
+ saved_timing->ddrc_cfg = cfg;
+ for (i = 0; i < timing_info->ddrc_cfg_num; i++) {
+ cfg->reg = timing_info->ddrc_cfg[i].reg;
+ cfg->val = timing_info->ddrc_cfg[i].val;
+ cfg++;
+ }
+
+ /* save ddrphy config */
+ saved_timing->ddrphy_cfg = cfg;
+ for (i = 0; i < timing_info->ddrphy_cfg_num; i++) {
+ cfg->reg = timing_info->ddrphy_cfg[i].reg;
+ cfg->val = timing_info->ddrphy_cfg[i].val;
+ cfg++;
+ }
+
+ /* save the ddrphy csr */
+ saved_timing->ddrphy_trained_csr = cfg;
+ for (i = 0; i < ddrphy_trained_csr_num; i++) {
+ cfg->reg = ddrphy_trained_csr[i].reg;
+ cfg->val = ddrphy_trained_csr[i].val;
+ cfg++;
+ }
+
+ /* save the ddrphy pie */
+ saved_timing->ddrphy_pie = cfg;
+ for (i = 0; i < timing_info->ddrphy_pie_num; i++) {
+ cfg->reg = timing_info->ddrphy_pie[i].reg;
+ cfg->val = timing_info->ddrphy_pie[i].val;
+ cfg++;
+ }
+}
diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c
index e3c1de1a4d..f0a087d1a8 100644
--- a/drivers/hab/habv4.c
+++ b/drivers/hab/habv4.c
@@ -213,7 +213,7 @@ static enum hab_status hab_sip_report_status(enum hab_config *config,
return (enum hab_status)res.a0;
}
-static enum hab_status imx8_read_sram_events(enum hab_status status,
+static enum hab_status imx8m_read_sram_events(enum hab_status status,
uint32_t index, void *event,
uint32_t *bytes)
{
@@ -262,7 +262,7 @@ static enum hab_status imx8_read_sram_events(enum hab_status status,
struct habv4_rvt hab_smc_ops = {
.header = { .tag = 0xdd },
- .report_event = imx8_read_sram_events,
+ .report_event = imx8m_read_sram_events,
.report_status = hab_sip_report_status,
};
@@ -585,12 +585,12 @@ int imx6_hab_get_status(void)
return -EINVAL;
}
-static int imx8_hab_get_status(void)
+static int imx8m_hab_get_status(void)
{
return habv4_get_status(&hab_smc_ops);
}
-static int init_imx8_hab_get_status(void)
+static int init_imx8m_hab_get_status(void)
{
if (!cpu_is_mx8mq())
/* can happen in multi-image builds and is not an error */
@@ -600,7 +600,7 @@ static int init_imx8_hab_get_status(void)
* Nobody will check the return value if there were HAB errors, but the
* initcall will fail spectaculously with a strange error message.
*/
- imx8_hab_get_status();
+ imx8m_hab_get_status();
return 0;
}
@@ -610,7 +610,7 @@ static int init_imx8_hab_get_status(void)
*
*
*/
-postmmu_initcall(init_imx8_hab_get_status);
+postmmu_initcall(init_imx8m_hab_get_status);
static int init_imx6_hab_get_status(void)
{
diff --git a/drivers/i2c/busses/i2c-imx-early.c b/drivers/i2c/busses/i2c-imx-early.c
index d67226441e..26922c1044 100644
--- a/drivers/i2c/busses/i2c-imx-early.c
+++ b/drivers/i2c/busses/i2c-imx-early.c
@@ -308,3 +308,15 @@ void *ls1046_i2c_init(void __iomem *regs)
return &fsl_i2c;
}
+
+void *imx8m_i2c_early_init(void __iomem *regs)
+{
+ fsl_i2c.regs = regs;
+ fsl_i2c.regshift = 2;
+ fsl_i2c.i2cr_ien_opcode = I2CR_IEN_OPCODE_1;
+ fsl_i2c.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C;
+ /* Divider for ~100kHz when coming from the ROM */
+ fsl_i2c.ifdr = 0x0f;
+
+ return &fsl_i2c;
+}
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index 2579cfd9d1..caaf1ac9b5 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -22,6 +22,7 @@
#include <mach/atf.h>
#include <mach/imx6-regs.h>
#include <mach/imx8mq-regs.h>
+#include <mach/imx8mm-regs.h>
#include <mach/imx-header.h>
#endif
#include "sdhci.h"
@@ -201,16 +202,20 @@ static void imx_esdhc_init(struct fsl_esdhc_host *host,
FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML));
}
-static int imx8_esdhc_init(struct fsl_esdhc_host *host,
- struct esdhc_soc_data *data,
- int instance)
+static int imx8m_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data,
+ int instance)
{
switch (instance) {
case 0:
- host->regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
+ host->regs = IOMEM(MX8M_USDHC1_BASE_ADDR);
break;
case 1:
- host->regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
+ host->regs = IOMEM(MX8M_USDHC2_BASE_ADDR);
+ break;
+ case 2:
+ /* Only exists on i.MX8MM, not on i.MX8MQ */
+ host->regs = IOMEM(MX8MM_USDHC3_BASE_ADDR);
break;
default:
return -EINVAL;
@@ -261,7 +266,7 @@ int imx6_esdhc_start_image(int instance)
}
/**
- * imx8_esdhc_load_image - Load and optionally start an image from USDHC controller
+ * imx8m_esdhc_load_image - Load and optionally start an image from USDHC controller
* @instance: The USDHC controller instance (0..2)
* @start: Whether to directly start the loaded image
*
@@ -273,17 +278,17 @@ int imx6_esdhc_start_image(int instance)
* Return: If successful, this function does not return (if directly started)
* or 0. A negative error code is returned when this function fails.
*/
-int imx8_esdhc_load_image(int instance, bool start)
+int imx8m_esdhc_load_image(int instance, bool start)
{
struct esdhc_soc_data data;
struct fsl_esdhc_host host;
int ret;
- ret = imx8_esdhc_init(&host, &data, instance);
+ ret = imx8m_esdhc_init(&host, &data, instance);
if (ret)
return ret;
- return esdhc_load_image(&host, MX8MQ_DDR_CSD1_BASE_ADDR,
+ return esdhc_load_image(&host, MX8M_DDR_CSD1_BASE_ADDR,
MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K, start);
}
#endif
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 6a9f1196cb..dc8fab73d3 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -389,6 +389,7 @@ static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = {
{ .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data },
{ .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,ls1046a-esdhc",.data = &esdhc_ls_data },
{ /* sentinel */ }
};
diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c
index 4ae07fe059..cb52f3942d 100644
--- a/drivers/net/designware_eqos.c
+++ b/drivers/net/designware_eqos.c
@@ -199,7 +199,7 @@ static int eqos_mdio_wait_idle(struct eqos *eqos)
static int eqos_mdio_read(struct mii_bus *bus, int addr, int reg)
{
struct eqos *eqos = bus->priv;
- u32 miiaddr;
+ u32 miiaddr = MII_BUSY;
int ret;
ret = eqos_mdio_wait_idle(eqos);
@@ -208,18 +208,13 @@ static int eqos_mdio_read(struct mii_bus *bus, int addr, int reg)
return ret;
}
- miiaddr = readl(&eqos->mac_regs->mdio_address);
- miiaddr &= EQOS_MDIO_ADDR_SKAP | EQOS_MDIO_ADDR_C45E;
- miiaddr |= EQOS_MDIO_ADDR_GOC_READ << EQOS_MDIO_ADDR_GOC_SHIFT;
-
- miiaddr |= EQOS_MDIO_CLK_CSR(eqos->ops->clk_csr);
miiaddr |= EQOS_MDIO_ADDR(addr) | EQOS_MDIO_REG(reg);
- miiaddr |= MII_BUSY;
+ miiaddr |= EQOS_MDIO_CLK_CSR(eqos->ops->clk_csr);
+ miiaddr |= EQOS_MDIO_ADDR_GOC_READ << EQOS_MDIO_ADDR_GOC_SHIFT;
+ writel(0, &eqos->mac_regs->mdio_data);
writel(miiaddr, &eqos->mac_regs->mdio_address);
- udelay(eqos->ops->mdio_wait_us);
-
ret = eqos_mdio_wait_idle(eqos);
if (ret) {
dev_err(&bus->dev, "MDIO read didn't complete\n");
@@ -232,7 +227,7 @@ static int eqos_mdio_read(struct mii_bus *bus, int addr, int reg)
static int eqos_mdio_write(struct mii_bus *bus, int addr, int reg, u16 data)
{
struct eqos *eqos = bus->priv;
- u32 miiaddr = 0;
+ u32 miiaddr = MII_BUSY;
int ret;
ret = eqos_mdio_wait_idle(eqos);
@@ -241,28 +236,18 @@ static int eqos_mdio_write(struct mii_bus *bus, int addr, int reg, u16 data)
return ret;
}
- miiaddr = readl(&eqos->mac_regs->mdio_address);
- miiaddr &= EQOS_MDIO_ADDR_SKAP | EQOS_MDIO_ADDR_C45E;
- miiaddr |= EQOS_MDIO_ADDR_GOC_WRITE << EQOS_MDIO_ADDR_GOC_SHIFT;
-
- miiaddr |= EQOS_MDIO_CLK_CSR(eqos->ops->clk_csr);
miiaddr |= EQOS_MDIO_ADDR(addr) | EQOS_MDIO_REG(reg);
- miiaddr |= MII_BUSY;
+ miiaddr |= EQOS_MDIO_CLK_CSR(eqos->ops->clk_csr);
+ miiaddr |= EQOS_MDIO_ADDR_GOC_WRITE << EQOS_MDIO_ADDR_GOC_SHIFT;
writel(data, &eqos->mac_regs->mdio_data);
writel(miiaddr, &eqos->mac_regs->mdio_address);
- udelay(eqos->ops->mdio_wait_us);
-
ret = eqos_mdio_wait_idle(eqos);
- if (ret) {
+ if (ret)
dev_err(&bus->dev, "MDIO read didn't complete\n");
- return ret;
- }
- /* Needed as a fix for ST-Phy */
- eqos_mdio_read(bus, addr, reg);
- return 0;
+ return ret;
}
diff --git a/drivers/net/designware_eqos.h b/drivers/net/designware_eqos.h
index f794195db4..30f4f02579 100644
--- a/drivers/net/designware_eqos.h
+++ b/drivers/net/designware_eqos.h
@@ -17,7 +17,6 @@ struct eqos_ops {
unsigned long (*get_csr_clk_rate)(struct eqos *);
bool enh_desc;
- int mdio_wait_us;
#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT 0
#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3
diff --git a/drivers/net/designware_stm32.c b/drivers/net/designware_stm32.c
index 1e0cdfa695..2e2af8942d 100644
--- a/drivers/net/designware_stm32.c
+++ b/drivers/net/designware_stm32.c
@@ -180,7 +180,6 @@ static struct eqos_ops stm32_ops = {
.adjust_link = eqos_adjust_link,
.get_csr_clk_rate = eqos_get_csr_clk_rate_stm32,
- .mdio_wait_us = 10 * USEC_PER_MSEC,
.clk_csr = EQOS_MDIO_ADDR_CR_250_300,
.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV,
};
diff --git a/drivers/net/designware_tegra186.c b/drivers/net/designware_tegra186.c
index 20521db1c7..5348f65c41 100644
--- a/drivers/net/designware_tegra186.c
+++ b/drivers/net/designware_tegra186.c
@@ -280,7 +280,6 @@ static const struct eqos_ops tegra186_ops = {
.adjust_link = eqos_adjust_link_tegra186,
.get_csr_clk_rate = eqos_get_csr_clk_rate_tegra186,
- .mdio_wait_us = 10,
.clk_csr = EQOS_MDIO_ADDR_CR_20_35,
.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
};
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index de79e05cbc..a35eddfa08 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -105,7 +105,7 @@ static char *of_overlay_fix_path(struct device_node *root,
return basprintf("%s%s", target->full_name, path_tail);
}
-static int of_overlay_apply_symbols(struct device_node *root,
+static void of_overlay_apply_symbols(struct device_node *root,
struct device_node *overlay)
{
const char *old_path;
@@ -115,12 +115,12 @@ static int of_overlay_apply_symbols(struct device_node *root,
struct device_node *overlay_symbols;
root_symbols = of_get_child_by_name(root, "__symbols__");
- if (!root_symbols)
- return -EINVAL;
-
overlay_symbols = of_get_child_by_name(overlay, "__symbols__");
- if (!overlay_symbols)
- return -EINVAL;
+
+ if (!overlay_symbols || !root_symbols) {
+ pr_info("overlay/root doesn't have a __symbols__ node\n");
+ return;
+ }
list_for_each_entry(prop, &overlay_symbols->properties, list) {
if (of_prop_cmp(prop->name, "name") == 0)
@@ -133,8 +133,6 @@ static int of_overlay_apply_symbols(struct device_node *root,
prop->name, new_path);
of_property_write_string(root_symbols, prop->name, new_path);
}
-
- return 0;
}
static int of_overlay_apply_fragment(struct device_node *root,
@@ -171,15 +169,13 @@ int of_overlay_apply_tree(struct device_node *root,
return -EINVAL;
/* Copy symbols from resolved overlay to base device tree */
- err = of_overlay_apply_symbols(root, resolved);
- if (err)
- pr_warn("failed to copy symbols from overlay");
+ of_overlay_apply_symbols(root, resolved);
/* Copy nodes and properties from resolved overlay to root */
for_each_child_of_node(resolved, fragment) {
err = of_overlay_apply_fragment(root, fragment);
if (err)
- pr_warn("failed to apply %s", fragment->name);
+ pr_warn("failed to apply %s\n", fragment->name);
}
of_delete_node(resolved);
diff --git a/drivers/pinctrl/imx-iomux-v3.c b/drivers/pinctrl/imx-iomux-v3.c
index 1d2b76d632..dccf7d10df 100644
--- a/drivers/pinctrl/imx-iomux-v3.c
+++ b/drivers/pinctrl/imx-iomux-v3.c
@@ -252,6 +252,8 @@ static __maybe_unused struct of_device_id imx_iomux_v3_dt_ids[] = {
.compatible = "fsl,imx7d-iomuxc-lpsr",
.data = &imx_iomux_imx7_lpsr_data,
}, {
+ .compatible = "fsl,imx8mm-iomuxc",
+ }, {
.compatible = "fsl,imx8mq-iomuxc",
}, {
/* sentinel */
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index d4f411b4ad..2cd58df931 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -87,8 +87,8 @@ static int pcs_set_state(struct pinctrl_device *pdev, struct device_node *np)
for (i = 0; i < rows; i++) {
offset = be32_to_cpup(mux + index++);
- mask = be32_to_cpup(mux + index++);
val = be32_to_cpup(mux + index++);
+ mask = be32_to_cpup(mux + index++);
reg = pcs->read(pcs->base + offset);
reg &= ~mask;
reg |= val;
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index 09341af874..e5280ac3e9 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -288,6 +288,9 @@ static __maybe_unused struct of_device_id imx_serial_dt_ids[] = {
.compatible = "fsl,imx8mq-uart",
.data = &imx21_data,
}, {
+ .compatible = "fsl,imx8mm-uart",
+ .data = &imx21_data,
+ }, {
/* sentinel */
}
};
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 9e98099502..64d4bddad4 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -2,9 +2,9 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_IMX_CHIPIDEA) += imx/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MUSB) += musb/
-obj-$(CONFIG_USB_GADGET) += gadget/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-y += host/
obj-y += otg/
+obj-y += gadget/
obj-$(CONFIG_USB) += misc/
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 8874775f17..466bbe527b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -406,6 +406,9 @@ static int usb_device_list_scan(void)
if (ret)
goto out;
}
+
+ /* Avoid hammering the HUB with port scans */
+ mdelay(25);
}
out:
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 9d6a262038..6e60c7aee8 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -15,6 +15,9 @@ config USB_GADGET_DRIVER_ARC
default y
select USB_GADGET_DUALSPEED
+config USB_GADGET_DRIVER_ARC_PBL
+ bool
+
config USB_GADGET_DRIVER_AT91
bool
prompt "at91 gadget driver"
@@ -58,6 +61,7 @@ config USB_GADGET_FASTBOOT
config USB_GADGET_FASTBOOT_SPARSE
bool
+ depends on USB_GADGET_FASTBOOT
select IMAGE_SPARSE
prompt "Enable Fastboot sparse image support"
help
@@ -77,4 +81,14 @@ config USB_GADGET_FASTBOOT_BUF
a buffer, then using a buffer might be better.
Say no here unless you know what you are doing.
+
+config USB_GADGET_FASTBOOT_CMD_OEM
+ bool
+ depends on USB_GADGET_FASTBOOT
+ prompt "Enable OEM commands"
+ help
+ This option enables the fastboot "oem" group of commands. They allow to
+ executing arbitrary barebox commands and may be disabled in secure
+ environments.
+
endif
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 9ef594575b..27673fcf0e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_USB_GADGET_SERIAL) += u_serial.o serial.o f_serial.o f_acm.o
obj-$(CONFIG_USB_GADGET_DFU) += dfu.o
obj-$(CONFIG_USB_GADGET_FASTBOOT) += f_fastboot.o
obj-$(CONFIG_USB_GADGET_DRIVER_ARC) += fsl_udc.o
+pbl-$(CONFIG_USB_GADGET_DRIVER_ARC_PBL) += fsl_udc_pbl.o
obj-$(CONFIG_USB_GADGET_DRIVER_AT91) += at91_udc.o
obj-$(CONFIG_USB_GADGET_DRIVER_PXA27X) += pxa27x_udc.o
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 0a3aff3cf0..cf3cc6dac7 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -957,6 +957,8 @@ static int fastboot_handle_sparse(struct f_fastboot *f_fb,
if (ret)
goto out;
} else {
+ discard_range(fd, retlen, pos);
+
pos = lseek(fd, pos, SEEK_SET);
if (pos == -1) {
ret = -errno;
@@ -1251,7 +1253,7 @@ static const struct cmd_dispatch_info cmd_oem_dispatch_info[] = {
},
};
-static void cb_oem(struct f_fastboot *f_fb, const char *cmd)
+static void __maybe_unused cb_oem(struct f_fastboot *f_fb, const char *cmd)
{
pr_debug("%s: \"%s\"\n", __func__, cmd);
@@ -1279,9 +1281,11 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
}, {
.cmd = "erase:",
.cb = cb_erase,
+#if defined(CONFIG_USB_GADGET_FASTBOOT_CMD_OEM)
}, {
.cmd = "oem ",
.cb = cb_oem,
+#endif
},
};
diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c
index c7160cdbc7..cffe9bdab7 100644
--- a/drivers/usb/gadget/fsl_udc.c
+++ b/drivers/usb/gadget/fsl_udc.c
@@ -10,384 +10,9 @@
#include <io.h>
#include <asm/byteorder.h>
#include <linux/err.h>
-
+#include <soc/fsl/fsl_udc.h>
#include <asm/mmu.h>
-/* ### define USB registers here
- */
-#define USB_MAX_CTRL_PAYLOAD 64
-#define USB_DR_SYS_OFFSET 0x400
-
- /* USB DR device mode registers (Little Endian) */
-struct usb_dr_device {
- /* Capability register */
- u8 res1[256];
- u16 caplength; /* Capability Register Length */
- u16 hciversion; /* Host Controller Interface Version */
- u32 hcsparams; /* Host Controller Structual Parameters */
- u32 hccparams; /* Host Controller Capability Parameters */
- u8 res2[20];
- u32 dciversion; /* Device Controller Interface Version */
- u32 dccparams; /* Device Controller Capability Parameters */
- u8 res3[24];
- /* Operation register */
- u32 usbcmd; /* USB Command Register */
- u32 usbsts; /* USB Status Register */
- u32 usbintr; /* USB Interrupt Enable Register */
- u32 frindex; /* Frame Index Register */
- u8 res4[4];
- u32 deviceaddr; /* Device Address */
- u32 endpointlistaddr; /* Endpoint List Address Register */
- u8 res5[4];
- u32 burstsize; /* Master Interface Data Burst Size Register */
- u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
- u8 res6[24];
- u32 configflag; /* Configure Flag Register */
- u32 portsc1; /* Port 1 Status and Control Register */
- u8 res7[28];
- u32 otgsc; /* On-The-Go Status and Control */
- u32 usbmode; /* USB Mode Register */
- u32 endptsetupstat; /* Endpoint Setup Status Register */
- u32 endpointprime; /* Endpoint Initialization Register */
- u32 endptflush; /* Endpoint Flush Register */
- u32 endptstatus; /* Endpoint Status Register */
- u32 endptcomplete; /* Endpoint Complete Register */
- u32 endptctrl[6]; /* Endpoint Control Registers */
-};
-
-/* ep0 transfer state */
-#define WAIT_FOR_SETUP 0
-#define DATA_STATE_XMIT 1
-#define DATA_STATE_NEED_ZLP 2
-#define WAIT_FOR_OUT_STATUS 3
-#define DATA_STATE_RECV 4
-
-/* Device Controller Capability Parameter register */
-#define DCCPARAMS_DC 0x00000080
-#define DCCPARAMS_DEN_MASK 0x0000001f
-
-/* Frame Index Register Bit Masks */
-#define USB_FRINDEX_MASKS 0x3fff
-/* USB CMD Register Bit Masks */
-#define USB_CMD_RUN_STOP 0x00000001
-#define USB_CMD_CTRL_RESET 0x00000002
-#define USB_CMD_PERIODIC_SCHEDULE_EN 0x00000010
-#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020
-#define USB_CMD_INT_AA_DOORBELL 0x00000040
-#define USB_CMD_ASP 0x00000300
-#define USB_CMD_ASYNC_SCH_PARK_EN 0x00000800
-#define USB_CMD_SUTW 0x00002000
-#define USB_CMD_ATDTW 0x00004000
-#define USB_CMD_ITC 0x00FF0000
-
-/* bit 15,3,2 are frame list size */
-#define USB_CMD_FRAME_SIZE_1024 0x00000000
-#define USB_CMD_FRAME_SIZE_512 0x00000004
-#define USB_CMD_FRAME_SIZE_256 0x00000008
-#define USB_CMD_FRAME_SIZE_128 0x0000000C
-#define USB_CMD_FRAME_SIZE_64 0x00008000
-#define USB_CMD_FRAME_SIZE_32 0x00008004
-#define USB_CMD_FRAME_SIZE_16 0x00008008
-#define USB_CMD_FRAME_SIZE_8 0x0000800C
-
-/* bit 9-8 are async schedule park mode count */
-#define USB_CMD_ASP_00 0x00000000
-#define USB_CMD_ASP_01 0x00000100
-#define USB_CMD_ASP_10 0x00000200
-#define USB_CMD_ASP_11 0x00000300
-#define USB_CMD_ASP_BIT_POS 8
-
-/* bit 23-16 are interrupt threshold control */
-#define USB_CMD_ITC_NO_THRESHOLD 0x00000000
-#define USB_CMD_ITC_1_MICRO_FRM 0x00010000
-#define USB_CMD_ITC_2_MICRO_FRM 0x00020000
-#define USB_CMD_ITC_4_MICRO_FRM 0x00040000
-#define USB_CMD_ITC_8_MICRO_FRM 0x00080000
-#define USB_CMD_ITC_16_MICRO_FRM 0x00100000
-#define USB_CMD_ITC_32_MICRO_FRM 0x00200000
-#define USB_CMD_ITC_64_MICRO_FRM 0x00400000
-#define USB_CMD_ITC_BIT_POS 16
-
-/* USB STS Register Bit Masks */
-#define USB_STS_INT 0x00000001
-#define USB_STS_ERR 0x00000002
-#define USB_STS_PORT_CHANGE 0x00000004
-#define USB_STS_FRM_LST_ROLL 0x00000008
-#define USB_STS_SYS_ERR 0x00000010
-#define USB_STS_IAA 0x00000020
-#define USB_STS_RESET 0x00000040
-#define USB_STS_SOF 0x00000080
-#define USB_STS_SUSPEND 0x00000100
-#define USB_STS_HC_HALTED 0x00001000
-#define USB_STS_RCL 0x00002000
-#define USB_STS_PERIODIC_SCHEDULE 0x00004000
-#define USB_STS_ASYNC_SCHEDULE 0x00008000
-
-/* USB INTR Register Bit Masks */
-#define USB_INTR_INT_EN 0x00000001
-#define USB_INTR_ERR_INT_EN 0x00000002
-#define USB_INTR_PTC_DETECT_EN 0x00000004
-#define USB_INTR_FRM_LST_ROLL_EN 0x00000008
-#define USB_INTR_SYS_ERR_EN 0x00000010
-#define USB_INTR_ASYN_ADV_EN 0x00000020
-#define USB_INTR_RESET_EN 0x00000040
-#define USB_INTR_SOF_EN 0x00000080
-#define USB_INTR_DEVICE_SUSPEND 0x00000100
-
-/* Device Address bit masks */
-#define USB_DEVICE_ADDRESS_MASK 0xFE000000
-#define USB_DEVICE_ADDRESS_BIT_POS 25
-
-/* endpoint list address bit masks */
-#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
-
-/* PORTSCX Register Bit Masks */
-#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001
-#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002
-#define PORTSCX_PORT_ENABLE 0x00000004
-#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008
-#define PORTSCX_OVER_CURRENT_ACT 0x00000010
-#define PORTSCX_OVER_CURRENT_CHG 0x00000020
-#define PORTSCX_PORT_FORCE_RESUME 0x00000040
-#define PORTSCX_PORT_SUSPEND 0x00000080
-#define PORTSCX_PORT_RESET 0x00000100
-#define PORTSCX_LINE_STATUS_BITS 0x00000C00
-#define PORTSCX_PORT_POWER 0x00001000
-#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000
-#define PORTSCX_PORT_TEST_CTRL 0x000F0000
-#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000
-#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000
-#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000
-#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000
-#define PORTSCX_PORT_FORCE_FULL_SPEED 0x01000000
-#define PORTSCX_PORT_SPEED_MASK 0x0C000000
-#define PORTSCX_PORT_WIDTH 0x10000000
-#define PORTSCX_PHY_TYPE_SEL 0xC0000000
-
-/* bit 11-10 are line status */
-#define PORTSCX_LINE_STATUS_SE0 0x00000000
-#define PORTSCX_LINE_STATUS_JSTATE 0x00000400
-#define PORTSCX_LINE_STATUS_KSTATE 0x00000800
-#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00
-#define PORTSCX_LINE_STATUS_BIT_POS 10
-
-/* bit 15-14 are port indicator control */
-#define PORTSCX_PIC_OFF 0x00000000
-#define PORTSCX_PIC_AMBER 0x00004000
-#define PORTSCX_PIC_GREEN 0x00008000
-#define PORTSCX_PIC_UNDEF 0x0000C000
-#define PORTSCX_PIC_BIT_POS 14
-
-/* bit 19-16 are port test control */
-#define PORTSCX_PTC_DISABLE 0x00000000
-#define PORTSCX_PTC_JSTATE 0x00010000
-#define PORTSCX_PTC_KSTATE 0x00020000
-#define PORTSCX_PTC_SEQNAK 0x00030000
-#define PORTSCX_PTC_PACKET 0x00040000
-#define PORTSCX_PTC_FORCE_EN 0x00050000
-#define PORTSCX_PTC_BIT_POS 16
-
-/* bit 27-26 are port speed */
-#define PORTSCX_PORT_SPEED_FULL 0x00000000
-#define PORTSCX_PORT_SPEED_LOW 0x04000000
-#define PORTSCX_PORT_SPEED_HIGH 0x08000000
-#define PORTSCX_PORT_SPEED_UNDEF 0x0C000000
-#define PORTSCX_SPEED_BIT_POS 26
-
-/* bit 28 is parallel transceiver width for UTMI interface */
-#define PORTSCX_PTW 0x10000000
-#define PORTSCX_PTW_8BIT 0x00000000
-#define PORTSCX_PTW_16BIT 0x10000000
-
-/* bit 31-30 are port transceiver select */
-#define PORTSCX_PTS_UTMI 0x00000000
-#define PORTSCX_PTS_ULPI 0x80000000
-#define PORTSCX_PTS_FSLS 0xC0000000
-#define PORTSCX_PTS_BIT_POS 30
-
-/* otgsc Register Bit Masks */
-#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001
-#define OTGSC_CTRL_VUSB_CHARGE 0x00000002
-#define OTGSC_CTRL_OTG_TERM 0x00000008
-#define OTGSC_CTRL_DATA_PULSING 0x00000010
-#define OTGSC_STS_USB_ID 0x00000100
-#define OTGSC_STS_A_VBUS_VALID 0x00000200
-#define OTGSC_STS_A_SESSION_VALID 0x00000400
-#define OTGSC_STS_B_SESSION_VALID 0x00000800
-#define OTGSC_STS_B_SESSION_END 0x00001000
-#define OTGSC_STS_1MS_TOGGLE 0x00002000
-#define OTGSC_STS_DATA_PULSING 0x00004000
-#define OTGSC_INTSTS_USB_ID 0x00010000
-#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000
-#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000
-#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000
-#define OTGSC_INTSTS_B_SESSION_END 0x00100000
-#define OTGSC_INTSTS_1MS 0x00200000
-#define OTGSC_INTSTS_DATA_PULSING 0x00400000
-#define OTGSC_INTR_USB_ID 0x01000000
-#define OTGSC_INTR_A_VBUS_VALID 0x02000000
-#define OTGSC_INTR_A_SESSION_VALID 0x04000000
-#define OTGSC_INTR_B_SESSION_VALID 0x08000000
-#define OTGSC_INTR_B_SESSION_END 0x10000000
-#define OTGSC_INTR_1MS_TIMER 0x20000000
-#define OTGSC_INTR_DATA_PULSING 0x40000000
-
-/* USB MODE Register Bit Masks */
-#define USB_MODE_CTRL_MODE_IDLE 0x00000000
-#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
-#define USB_MODE_CTRL_MODE_HOST 0x00000003
-#define USB_MODE_CTRL_MODE_RSV 0x00000001
-#define USB_MODE_CTRL_MODE_MASK 0x00000003
-#define USB_MODE_SETUP_LOCK_OFF 0x00000008
-#define USB_MODE_STREAM_DISABLE 0x00000010
-/* Endpoint Flush Register */
-#define EPFLUSH_TX_OFFSET 0x00010000
-#define EPFLUSH_RX_OFFSET 0x00000000
-
-/* Endpoint Setup Status bit masks */
-#define EP_SETUP_STATUS_MASK 0x0000003F
-#define EP_SETUP_STATUS_EP0 0x00000001
-
-/* ENDPOINTCTRLx Register Bit Masks */
-#define EPCTRL_TX_ENABLE 0x00800000
-#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */
-#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */
-#define EPCTRL_TX_TYPE 0x000C0000
-#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */
-#define EPCTRL_TX_EP_STALL 0x00010000
-#define EPCTRL_RX_ENABLE 0x00000080
-#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */
-#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */
-#define EPCTRL_RX_TYPE 0x0000000C
-#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */
-#define EPCTRL_RX_EP_STALL 0x00000001
-
-/* bit 19-18 and 3-2 are endpoint type */
-#define EPCTRL_EP_TYPE_CONTROL 0
-#define EPCTRL_EP_TYPE_ISO 1
-#define EPCTRL_EP_TYPE_BULK 2
-#define EPCTRL_EP_TYPE_INTERRUPT 3
-#define EPCTRL_TX_EP_TYPE_SHIFT 18
-#define EPCTRL_RX_EP_TYPE_SHIFT 2
-
-/* SNOOPn Register Bit Masks */
-#define SNOOP_ADDRESS_MASK 0xFFFFF000
-#define SNOOP_SIZE_ZERO 0x00 /* snooping disable */
-#define SNOOP_SIZE_4KB 0x0B /* 4KB snoop size */
-#define SNOOP_SIZE_8KB 0x0C
-#define SNOOP_SIZE_16KB 0x0D
-#define SNOOP_SIZE_32KB 0x0E
-#define SNOOP_SIZE_64KB 0x0F
-#define SNOOP_SIZE_128KB 0x10
-#define SNOOP_SIZE_256KB 0x11
-#define SNOOP_SIZE_512KB 0x12
-#define SNOOP_SIZE_1MB 0x13
-#define SNOOP_SIZE_2MB 0x14
-#define SNOOP_SIZE_4MB 0x15
-#define SNOOP_SIZE_8MB 0x16
-#define SNOOP_SIZE_16MB 0x17
-#define SNOOP_SIZE_32MB 0x18
-#define SNOOP_SIZE_64MB 0x19
-#define SNOOP_SIZE_128MB 0x1A
-#define SNOOP_SIZE_256MB 0x1B
-#define SNOOP_SIZE_512MB 0x1C
-#define SNOOP_SIZE_1GB 0x1D
-#define SNOOP_SIZE_2GB 0x1E /* 2GB snoop size */
-
-/* pri_ctrl Register Bit Masks */
-#define PRI_CTRL_PRI_LVL1 0x0000000C
-#define PRI_CTRL_PRI_LVL0 0x00000003
-
-/* si_ctrl Register Bit Masks */
-#define SI_CTRL_ERR_DISABLE 0x00000010
-#define SI_CTRL_IDRC_DISABLE 0x00000008
-#define SI_CTRL_RD_SAFE_EN 0x00000004
-#define SI_CTRL_RD_PREFETCH_DISABLE 0x00000002
-#define SI_CTRL_RD_PREFEFETCH_VAL 0x00000001
-
-/* control Register Bit Masks */
-#define USB_CTRL_IOENB 0x00000004
-#define USB_CTRL_ULPI_INT0EN 0x00000001
-
-/* Endpoint Queue Head data struct
- * Rem: all the variables of qh are LittleEndian Mode
- * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
- */
-struct ep_queue_head {
- u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len
- and IOS(15) */
- u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */
- u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */
- u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15),
- MultO(11-10), STS (7-0) */
- u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */
- u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */
- u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */
- u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */
- u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */
- u32 res1;
- u8 setup_buffer[8]; /* Setup data 8 bytes */
- u32 res2[4];
-};
-
-/* Endpoint Queue Head Bit Masks */
-#define EP_QUEUE_HEAD_MULT_POS 30
-#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
-#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
-#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
-#define EP_QUEUE_HEAD_IOS 0x00008000
-#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
-#define EP_QUEUE_HEAD_IOC 0x00008000
-#define EP_QUEUE_HEAD_MULTO 0x00000C00
-#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
-#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
-#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
-#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
-#define EP_QUEUE_FRINDEX_MASK 0x000007FF
-#define EP_MAX_LENGTH_TRANSFER 0x4000
-
-/* Endpoint Transfer Descriptor data struct */
-/* Rem: all the variables of td are LittleEndian Mode */
-struct ep_td_struct {
- u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set
- indicate invalid */
- u32 size_ioc_sts; /* Total bytes (30-16), IOC (15),
- MultO(11-10), STS (7-0) */
- u32 buff_ptr0; /* Buffer pointer Page 0 */
- u32 buff_ptr1; /* Buffer pointer Page 1 */
- u32 buff_ptr2; /* Buffer pointer Page 2 */
- u32 buff_ptr3; /* Buffer pointer Page 3 */
- u32 buff_ptr4; /* Buffer pointer Page 4 */
- u32 res;
- /* 32 bytes */
- dma_addr_t td_dma; /* dma address for this td */
- /* virtual address of next td specified in next_td_ptr */
- struct ep_td_struct *next_td_virt;
-};
-
-/* Endpoint Transfer Descriptor bit Masks */
-#define DTD_NEXT_TERMINATE 0x00000001
-#define DTD_IOC 0x00008000
-#define DTD_STATUS_ACTIVE 0x00000080
-#define DTD_STATUS_HALTED 0x00000040
-#define DTD_STATUS_DATA_BUFF_ERR 0x00000020
-#define DTD_STATUS_TRANSACTION_ERR 0x00000008
-#define DTD_RESERVED_FIELDS 0x80007300
-#define DTD_ADDR_MASK 0xFFFFFFE0
-#define DTD_PACKET_SIZE 0x7FFF0000
-#define DTD_LENGTH_BIT_POS 16
-#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
- DTD_STATUS_DATA_BUFF_ERR | \
- DTD_STATUS_TRANSACTION_ERR)
-/* Alignment requirements; must be a power of two */
-#define DTD_ALIGNMENT 0x20
-#define QH_ALIGNMENT 2048
-
-/* Controller dma boundary */
-#define UDC_DMA_BOUNDARY 0x1000
-
-/*-------------------------------------------------------------------------*/
-
/* ### driver private data
*/
struct fsl_req {
@@ -1137,6 +762,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req,
unsigned length;
u32 swap_temp;
struct ep_td_struct *dtd;
+ unsigned long buf;
/* how big will this transfer be? */
length = min(req->req.length - req->req.actual,
@@ -1154,7 +780,13 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req,
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
/* Init all of buffer page pointers */
- swap_temp = (u32) (req->req.buf + req->req.actual);
+ buf = (unsigned long)req->req.buf;
+ if (buf > 0xffffffff) {
+ pr_err("Only 32bit supported\n");
+ return NULL;
+ }
+
+ swap_temp = (u32)(buf + req->req.actual);
dtd->buff_ptr0 = cpu_to_le32(swap_temp);
dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
@@ -1320,13 +952,19 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
if (req->queue.next != &ep->queue) {
struct ep_queue_head *qh;
struct fsl_req *next_req;
+ unsigned long next_req_head;
qh = ep->qh;
next_req = list_entry(req->queue.next, struct fsl_req,
queue);
/* Point the QH to the first TD of next request */
- writel((u32) next_req->head, &qh->curr_dtd_ptr);
+ next_req_head = (unsigned long)next_req->head;
+ if (next_req_head > 0xffffffff) {
+ pr_err("Only 32bit supported\n");
+ goto out;
+ }
+ writel((u32)next_req_head, &qh->curr_dtd_ptr);
}
/* The request hasn't been processed, patch up the TD chain */
diff --git a/drivers/usb/gadget/fsl_udc_pbl.c b/drivers/usb/gadget/fsl_udc_pbl.c
new file mode 100644
index 0000000000..978adf0667
--- /dev/null
+++ b/drivers/usb/gadget/fsl_udc_pbl.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <usb/ch9.h>
+#include <soc/fsl/fsl_udc.h>
+#include <mach/imx8mm-regs.h>
+
+static void fsl_queue_td(struct usb_dr_device *dr, struct ep_td_struct *dtd,
+ int ep_is_in)
+{
+ int ep_index = 0;
+ int i = ep_index * 2 + ep_is_in;
+ u32 bitmask;
+ volatile struct ep_queue_head *dQH =
+ (void *)(unsigned long)readl(&dr->endpointlistaddr);
+ unsigned long td_dma = (unsigned long)dtd;
+
+ dQH = &dQH[i];
+
+ bitmask = ep_is_in ? (1 << (ep_index + 16)) : (1 << (ep_index));
+
+ dQH->next_dtd_ptr = cpu_to_le32(td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK);
+
+ dQH->size_ioc_int_sts &= cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+ | EP_QUEUE_HEAD_STATUS_HALT));
+
+ writel(bitmask, &dr->endpointprime);
+}
+
+static struct ep_td_struct dtd_data __attribute__((aligned(64)));
+static struct ep_td_struct dtd_status __attribute__((aligned(64)));
+
+static int fsl_ep_queue(struct usb_dr_device *dr, struct ep_td_struct *dtd,
+ void *buf, int len)
+{
+ u32 swap_temp;
+
+ memset(dtd, 0, sizeof(*dtd));
+
+ /* Clear reserved field */
+ swap_temp = cpu_to_le32(dtd->size_ioc_sts);
+ swap_temp &= ~DTD_RESERVED_FIELDS;
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ swap_temp = (unsigned long)buf;
+ dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+ dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+ dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+ dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+ dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
+
+ /* Fill in the transfer size; set active bit */
+ swap_temp = ((len << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE) | DTD_IOC;
+
+ writel(cpu_to_le32(swap_temp), &dtd->size_ioc_sts);
+
+ dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
+
+ fsl_queue_td(dr, dtd, len ? 0 : 1);
+
+ return 0;
+}
+
+enum state {
+ state_init = 0,
+ state_expect_command,
+ state_transfer_data,
+ state_complete,
+};
+
+#define MAX_TRANSFER_SIZE 2048
+
+static enum state state;
+static uint8_t databuf[MAX_TRANSFER_SIZE] __attribute__((aligned(64)));
+static int actual;
+static int to_transfer;
+static void *image;
+
+static void tripwire_handler(struct usb_dr_device *dr, u8 ep_num)
+{
+ uint32_t val;
+ struct ep_queue_head *qh;
+ struct ep_queue_head *dQH = (void *)(unsigned long)readl(&dr->endpointlistaddr);
+ struct usb_ctrlrequest *ctrl;
+
+ qh = &dQH[ep_num * 2];
+
+ val = readl(&dr->endptsetupstat);
+ val |= 1 << ep_num;
+ writel(val, &dr->endptsetupstat);
+
+ do {
+ val = readl(&dr->usbcmd);
+ val |= USB_CMD_SUTW;
+ writel(val, &dr->usbcmd);
+
+ ctrl = (void *)qh->setup_buffer;
+ if ((ctrl->wValue & 0xff) == 1)
+ state = state_expect_command;
+
+ } while (!(readl(&dr->usbcmd) & USB_CMD_SUTW));
+
+ val = readl(&dr->usbcmd);
+ val &= ~USB_CMD_SUTW;
+ writel(val, &dr->usbcmd);
+
+ fsl_ep_queue(dr, &dtd_data, databuf, MAX_TRANSFER_SIZE);
+}
+
+static void dtd_complete_irq(struct usb_dr_device *dr)
+{
+ struct ep_td_struct *dtd = &dtd_data;
+ u32 bit_pos;
+ int len;
+
+ /* Clear the bits in the register */
+ bit_pos = readl(&dr->endptcomplete);
+ writel(bit_pos, &dr->endptcomplete);
+
+ if (!(bit_pos & 1))
+ return;
+
+ len = MAX_TRANSFER_SIZE -
+ (le32_to_cpu(dtd->size_ioc_sts) >> DTD_LENGTH_BIT_POS);
+
+ if (state == state_expect_command) {
+ state = state_transfer_data;
+ to_transfer = databuf[8] << 24 |
+ databuf[9] << 16 |
+ databuf[10] << 8 |
+ databuf[11];
+ } else {
+ memcpy(image + actual, &databuf[1], len - 1);
+ actual += len - 1;
+ to_transfer -= len - 1;
+
+ if (to_transfer == 0)
+ state = state_complete;
+ }
+
+ fsl_ep_queue(dr, &dtd_status, NULL, 0);
+}
+
+static int usb_irq(struct usb_dr_device *dr)
+{
+ uint32_t irq_src = readl(&dr->usbsts);
+
+ irq_src &= ~0x80;
+
+ if (!irq_src)
+ return -EAGAIN;
+
+ /* Clear notification bits */
+ writel(irq_src, &dr->usbsts);
+
+ /* USB Interrupt */
+ if (irq_src & USB_STS_INT) {
+ /* Setup package, we only support ep0 as control ep */
+ if (readl(&dr->endptsetupstat) & EP_SETUP_STATUS_EP0)
+ tripwire_handler(dr, 0);
+
+ /* completion of dtd */
+ if (readl(&dr->endptcomplete))
+ dtd_complete_irq(dr);
+ }
+
+ if (state == state_complete)
+ return 0;
+ else
+ return -EAGAIN;
+}
+
+int imx_barebox_load_usb(void __iomem *dr, void *dest)
+{
+ int ret;
+
+ image = dest;
+
+ while (1) {
+ ret = usb_irq(dr);
+ if (!ret)
+ break;
+ }
+
+ return 0;
+}
+
+int imx_barebox_start_usb(void __iomem *dr, void *dest)
+{
+ void __noreturn (*bb)(void);
+ int ret;
+
+ ret = imx_barebox_load_usb(dr, dest);
+ if (ret)
+ return ret;
+
+ printf("Downloading complete, start barebox\n");
+ bb = dest;
+ bb();
+}
+
+int imx8mm_barebox_load_usb(void *dest)
+{
+ return imx_barebox_load_usb(IOMEM(MX8MM_USB1_BASE_ADDR), dest);
+}
+
+int imx8mm_barebox_start_usb(void *dest)
+{
+ return imx_barebox_start_usb(IOMEM(MX8MM_USB1_BASE_ADDR), dest);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 417ae5df75..ead63b2c9f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -42,7 +42,9 @@ struct ehci_host {
struct ehci_hcor *hcor;
struct usb_host host;
struct QH *qh_list;
+ dma_addr_t qh_list_dma;
struct qTD *td;
+ dma_addr_t td_dma;
int portreset;
unsigned long flags;
@@ -51,7 +53,9 @@ struct ehci_host {
void *drvdata;
int periodic_schedules;
struct QH *periodic_queue;
+ dma_addr_t periodic_queue_dma;
uint32_t *periodic_list;
+ dma_addr_t periodic_list_dma;
};
struct int_queue {
@@ -59,9 +63,11 @@ struct int_queue {
int queuesize;
unsigned long pipe;
struct QH *first;
+ dma_addr_t first_dma;
struct QH *current;
struct QH *last;
struct qTD *tds;
+ dma_addr_t tds_dma;
};
#define to_ehci(ptr) container_of(ptr, struct ehci_host, host)
@@ -137,6 +143,29 @@ static struct descriptor {
#define ehci_is_TDI() (ehci->flags & EHCI_HAS_TT)
+#define EHCI_DMA(dma0, ptr0, ptr) \
+ ((dma0) + ((ptr) - (ptr0)) * sizeof(*(ptr)))
+
+static inline uint32_t ehci_qh_dma(struct ehci_host *ehci, struct QH *qh)
+{
+ return EHCI_DMA(ehci->qh_list_dma, ehci->qh_list, qh);
+}
+
+static inline uint32_t ehci_td_dma(struct ehci_host *ehci, struct qTD *td)
+{
+ return EHCI_DMA(ehci->td_dma, ehci->td, td);
+}
+
+static inline uint32_t ehci_int_qh_dma(struct int_queue *intq, struct QH *qh)
+{
+ return EHCI_DMA(intq->first_dma, intq->first, qh);
+}
+
+static inline uint32_t ehci_int_td_dma(struct int_queue *intq, struct qTD *td)
+{
+ return EHCI_DMA(intq->tds_dma, intq->tds, td);
+}
+
static void memzero32(void *ptr, size_t size)
{
uint32_t *ptr32 = ptr;
@@ -346,7 +375,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
dev_dbg(ehci->dev, "unable construct SETUP td\n");
return ret;
}
- *tdp = cpu_to_hc32((uint32_t) td);
+ *tdp = cpu_to_hc32(ehci_td_dma(ehci, td));
tdp = &td->qt_next;
toggle = 1;
@@ -385,7 +414,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
dev_err(ehci->dev, "unable construct DATA td\n");
return ret;
}
- *tdp = cpu_to_hc32((uint32_t) td);
+ *tdp = cpu_to_hc32(ehci_td_dma(ehci, td));
tdp = &td->qt_next;
}
@@ -399,7 +428,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
QT_TOKEN_PID_IN),
NULL, 0,
NULL, DMA_NONE);
- *tdp = cpu_to_hc32((uint32_t)td);
+ *tdp = cpu_to_hc32(ehci_td_dma(ehci, td));
tdp = &td->qt_next;
}
@@ -841,7 +870,7 @@ static int ehci_init(struct usb_host *host)
return ret;
}
- ehci->qh_list[0].qh_link = cpu_to_hc32((uint32_t)&ehci->qh_list[1] |
+ ehci->qh_list[0].qh_link = cpu_to_hc32(ehci_qh_dma(ehci, &ehci->qh_list[1]) |
QH_LINK_TYPE_QH);
ehci->qh_list[0].qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) |
QH_ENDPT1_EPS(USB_SPEED_HIGH));
@@ -850,12 +879,13 @@ static int ehci_init(struct usb_host *host)
ehci->qh_list[0].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
ehci->qh_list[0].qt_token = cpu_to_hc32(QT_TOKEN_STATUS_HALTED);
- ehci->qh_list[1].qh_link = cpu_to_hc32((uint32_t)&ehci->qh_list[0] |
+ ehci->qh_list[1].qh_link = cpu_to_hc32(ehci_qh_dma(ehci,
+ &ehci->qh_list[0]) |
QH_LINK_TYPE_QH);
ehci->qh_list[1].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
/* Set async. queue head pointer. */
- ehci_writel(&ehci->hcor->or_asynclistaddr, (uint32_t)ehci->qh_list);
+ ehci_writel(&ehci->hcor->or_asynclistaddr, (uint32_t)ehci->qh_list_dma);
/*
* Set up periodic list
@@ -885,15 +915,15 @@ static int ehci_init(struct usb_host *host)
* PAGE_SIZE less then 4k will break this code.
*/
ehci->periodic_list = dma_alloc_coherent(1024 * 4,
- DMA_ADDRESS_BROKEN);
+ &ehci->periodic_list_dma);
for (i = 0; i < 1024; i++) {
- ehci->periodic_list[i] = cpu_to_hc32((unsigned long)periodic
+ ehci->periodic_list[i] = cpu_to_hc32((unsigned long)ehci->periodic_queue_dma
| QH_LINK_TYPE_QH);
}
/* Set periodic list base address */
ehci_writel(&ehci->hcor->or_periodiclistbase,
- (unsigned long)ehci->periodic_list);
+ (uint32_t)ehci->periodic_list_dma);
reg = ehci_readl(&ehci->hccr->cr_hcsparams);
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
@@ -986,7 +1016,10 @@ disable_periodic(struct ehci_host *ehci)
return 0;
}
-#define NEXT_QH(qh) (struct QH *)((unsigned long)hc32_to_cpu((qh)->qh_link) & ~0x1f)
+#define NEXT_QH(queue, qh) (struct QH *)( \
+ ((unsigned long)hc32_to_cpu((qh)->qh_link) & ~0x1f) - \
+ (queue)->first_dma + \
+ (unsigned long)(queue)->first)
static int
enable_periodic(struct ehci_host *ehci)
@@ -1051,7 +1084,7 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
static struct int_queue *ehci_create_int_queue(struct usb_device *dev,
unsigned long pipe, int queuesize, int elementsize,
- void *buffer, int interval)
+ void *buffer, dma_addr_t buffer_dma, int interval)
{
struct usb_host *host = dev->host;
struct ehci_host *ehci = to_ehci(host);
@@ -1100,22 +1133,23 @@ static struct int_queue *ehci_create_int_queue(struct usb_device *dev,
result->queuesize = queuesize;
result->pipe = pipe;
result->first = dma_alloc_coherent(sizeof(struct QH) * queuesize,
- DMA_ADDRESS_BROKEN);
+ &result->first_dma);
result->current = result->first;
result->last = result->first + queuesize - 1;
result->tds = dma_alloc_coherent(sizeof(struct qTD) * queuesize,
- DMA_ADDRESS_BROKEN);
+ &result->tds_dma);
for (i = 0; i < queuesize; i++) {
struct QH *qh = result->first + i;
struct qTD *td = result->tds + i;
void **buf = &qh->buffer;
- qh->qh_link = cpu_to_hc32((unsigned long)(qh+1) | QH_LINK_TYPE_QH);
+ qh->qh_link = cpu_to_hc32(ehci_int_qh_dma(result, qh + 1) |
+ QH_LINK_TYPE_QH);
if (i == queuesize - 1)
qh->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
- qh->qt_next = cpu_to_hc32((unsigned long)td);
+ qh->qt_next = cpu_to_hc32(ehci_int_td_dma(result, td));
qh->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
qh->qh_endpt1 =
cpu_to_hc32((0 << 28) | /* No NAK reload (ehci 4.9) */
@@ -1142,15 +1176,15 @@ static struct int_queue *ehci_create_int_queue(struct usb_device *dev,
((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
0x80); /* active */
td->qt_buffer[0] =
- cpu_to_hc32((unsigned long)buffer + i * elementsize);
+ cpu_to_hc32(buffer_dma + i * elementsize);
td->qt_buffer[1] =
- cpu_to_hc32((td->qt_buffer[0] + 0x1000) & ~0xfff);
+ cpu_to_hc32((buffer_dma + i * elementsize + 0x1000) & ~0xfff);
td->qt_buffer[2] =
- cpu_to_hc32((td->qt_buffer[0] + 0x2000) & ~0xfff);
+ cpu_to_hc32((buffer_dma + i * elementsize + 0x2000) & ~0xfff);
td->qt_buffer[3] =
- cpu_to_hc32((td->qt_buffer[0] + 0x3000) & ~0xfff);
+ cpu_to_hc32((buffer_dma + i * elementsize + 0x3000) & ~0xfff);
td->qt_buffer[4] =
- cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff);
+ cpu_to_hc32((buffer_dma + i * elementsize + 0x4000) & ~0xfff);
*buf = buffer + i * elementsize;
}
@@ -1165,7 +1199,7 @@ static struct int_queue *ehci_create_int_queue(struct usb_device *dev,
/* hook up to periodic list */
result->last->qh_link = list->qh_link;
- list->qh_link = cpu_to_hc32((unsigned long)result->first | QH_LINK_TYPE_QH);
+ list->qh_link = cpu_to_hc32(result->first_dma | QH_LINK_TYPE_QH);
if (enable_periodic(ehci) < 0) {
dev_err(&dev->dev,
@@ -1177,8 +1211,10 @@ static struct int_queue *ehci_create_int_queue(struct usb_device *dev,
dev_dbg(&dev->dev, "Exit create_int_queue\n");
return result;
fail3:
- dma_free_coherent(result->tds, 0, sizeof(struct qTD) * queuesize);
- dma_free_coherent(result->first, 0, sizeof(struct QH) * queuesize);
+ dma_free_coherent(result->tds, result->tds_dma,
+ sizeof(struct qTD) * queuesize);
+ dma_free_coherent(result->first, result->first_dma,
+ sizeof(struct QH) * queuesize);
free(result);
return NULL;
}
@@ -1235,14 +1271,14 @@ static int ehci_destroy_int_queue(struct usb_device *dev,
dev_dbg(&dev->dev,
"considering %p, with qh_link %x\n",
cur, cur->qh_link);
- if (NEXT_QH(cur) == queue->first) {
+ if (NEXT_QH(queue, cur) == queue->first) {
dev_dbg(&dev->dev,
"found candidate. removing from chain\n");
cur->qh_link = queue->last->qh_link;
result = 0;
break;
}
- cur = NEXT_QH(cur);
+ cur = NEXT_QH(queue, cur);
}
if (ehci->periodic_schedules > 0) {
@@ -1269,14 +1305,14 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
uint64_t start;
void *backbuffer;
int result = 0, ret;
+ dma_addr_t buffer_dma;
dev_dbg(ehci->dev, "dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
- dma_sync_single_for_device((unsigned long)buffer, length,
- DMA_BIDIRECTIONAL);
+ buffer_dma = dma_map_single(ehci->dev, buffer, length, DMA_BIDIRECTIONAL);
- queue = ehci_create_int_queue(dev, pipe, 1, length, buffer, interval);
+ queue = ehci_create_int_queue(dev, pipe, 1, length, buffer, buffer_dma, interval);
if (!queue)
return -EINVAL;
@@ -1298,8 +1334,7 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
result = -EINVAL;
}
- dma_sync_single_for_cpu((unsigned long)buffer, length,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(ehci->dev, buffer_dma, length, DMA_BIDIRECTIONAL);
ret = ehci_destroy_int_queue(dev, queue);
if (!result)
@@ -1335,11 +1370,11 @@ struct ehci_host *ehci_register(struct device_d *dev, struct ehci_data *data)
ehci->post_init = data->post_init;
ehci->qh_list = dma_alloc_coherent(sizeof(struct QH) * NUM_QH,
- DMA_ADDRESS_BROKEN);
+ &ehci->qh_list_dma);
ehci->periodic_queue = dma_alloc_coherent(sizeof(struct QH),
- DMA_ADDRESS_BROKEN);
+ &ehci->periodic_queue_dma);
ehci->td = dma_alloc_coherent(sizeof(struct qTD) * NUM_TD,
- DMA_ADDRESS_BROKEN);
+ &ehci->td_dma);
host->hw_dev = dev;
host->init = ehci_init;
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index 3cf5d26dcd..03301d9c3e 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -323,6 +323,8 @@ static __maybe_unused struct of_device_id imx_chipidea_dt_ids[] = {
{
.compatible = "fsl,imx27-usb",
}, {
+ .compatible = "fsl,imx7d-usb",
+ }, {
/* sentinel */
},
};
diff --git a/drivers/usb/imx/imx-usb-misc.c b/drivers/usb/imx/imx-usb-misc.c
index ef3892c220..aa4485ccba 100644
--- a/drivers/usb/imx/imx-usb-misc.c
+++ b/drivers/usb/imx/imx-usb-misc.c
@@ -599,6 +599,12 @@ static __maybe_unused struct of_device_id imx_usbmisc_dt_ids[] = {
.data = &mx7_data,
},
#endif
+#ifdef CONFIG_ARCH_IMX8M
+ {
+ .compatible = "fsl,imx8mm-usbmisc",
+ .data = &mx7_data,
+ },
+#endif
#ifdef CONFIG_ARCH_VF610
{
.compatible = "fsl,vf610-usbmisc",
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 4c11e6580c..b84da5516c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1136,8 +1136,9 @@ fail2:
musb_platform_exit(musb);
fail1:
- dev_err(musb->controller,
- "musb_init_controller failed with status %d\n", status);
+ if (status != -EPROBE_DEFER)
+ dev_err(musb->controller,
+ "musb_init_controller failed with status %d\n", status);
musb_free(musb);
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 3b76b6cc61..d54a663e9d 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -39,7 +39,6 @@
#include <linux/barebox-wrapper.h>
#include "musb_core.h"
-#include "phy-am335x.h"
static __maybe_unused struct of_device_id musb_dsps_dt_ids[];
@@ -217,10 +216,6 @@ static int dsps_musb_init(struct musb *musb)
const struct dsps_musb_wrapper *wrp = glue->wrp;
u32 rev, val, mode;
- musb->xceiv = am335x_get_usb_phy();
- if (IS_ERR(musb->xceiv))
- return PTR_ERR(musb->xceiv);
-
/* Returns zero if e.g. not clocked */
rev = dsps_readl(musb->ctrl_base, wrp->revision);
if (!rev)
@@ -319,11 +314,13 @@ static int dsps_set_mode(void *ctx, enum usb_dr_mode mode)
static int dsps_probe(struct device_d *dev)
{
- struct resource *iores;
+ struct resource *iores[2];
struct musb_hdrc_platform_data *pdata;
struct musb_hdrc_config *config;
struct device_node *dn = dev->device_node;
const struct dsps_musb_wrapper *wrp;
+ struct device_node *phy_node;
+ struct device_d *phy_dev;
struct dsps_glue *glue;
int ret;
@@ -337,6 +334,14 @@ static int dsps_probe(struct device_d *dev)
return -ENODEV;
}
+ phy_node = of_parse_phandle(dn, "phys", 0);
+ if (!phy_node)
+ return -ENODEV;
+
+ phy_dev = of_find_device_by_node(phy_node);
+ if (!phy_dev || !phy_dev->priv)
+ return -EPROBE_DEFER;
+
/* allocate glue */
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
@@ -349,17 +354,22 @@ static int dsps_probe(struct device_d *dev)
pdata = &glue->pdata;
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- glue->musb.mregs = IOMEM(iores->start);
+ iores[0] = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores[0])) {
+ ret = PTR_ERR(iores[0]);
+ goto free_glue;
+ }
+ glue->musb.mregs = IOMEM(iores[0]->start);
- iores = dev_request_mem_resource(dev, 1);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- glue->musb.ctrl_base = IOMEM(iores->start);
+ iores[1] = dev_request_mem_resource(dev, 1);
+ if (IS_ERR(iores[1])) {
+ ret = PTR_ERR(iores[1]);
+ goto release_iores0;
+ }
+ glue->musb.ctrl_base = IOMEM(iores[1]->start);
glue->musb.controller = dev;
+ glue->musb.xceiv = phy_dev->priv;
config = &glue->config;
@@ -377,11 +387,24 @@ static int dsps_probe(struct device_d *dev)
if (pdata->mode == MUSB_PORT_MODE_DUAL_ROLE) {
ret = usb_register_otg_device(dev, dsps_set_mode, glue);
if (ret)
- return ret;
+ goto release_iores1;
return 0;
}
- return musb_init_controller(&glue->musb, pdata);
+ ret = musb_init_controller(&glue->musb, pdata);
+ if (ret)
+ goto release_iores1;
+
+ return 0;
+
+release_iores1:
+ release_region(iores[1]);
+release_iores0:
+ release_region(iores[0]);
+free_glue:
+ free(glue);
+
+ return ret;
}
static const struct dsps_musb_wrapper am33xx_driver_data = {
diff --git a/drivers/usb/musb/phy-am335x-control.c b/drivers/usb/musb/phy-am335x-control.c
index c84525ec7e..41a3689ed3 100644
--- a/drivers/usb/musb/phy-am335x-control.c
+++ b/drivers/usb/musb/phy-am335x-control.c
@@ -109,15 +109,15 @@ struct phy_control *am335x_get_phy_control(struct device_d *dev)
node = of_parse_phandle(dev->device_node, "ti,ctrl_mod", 0);
if (!node)
- return NULL;
+ return ERR_PTR(-ENOENT);
dev = of_find_device_by_node(node);
if (!dev)
- return NULL;
+ return ERR_PTR(-EPROBE_DEFER);
ctrl_usb = dev->priv;
if (!ctrl_usb)
- return NULL;
+ return ERR_PTR(-EPROBE_DEFER);
return &ctrl_usb->phy_ctrl;
}
@@ -141,13 +141,17 @@ static int am335x_control_usb_probe(struct device_d *dev)
ctrl_usb->dev = dev;
iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ goto free_ctrl;
+ }
ctrl_usb->phy_reg = IOMEM(iores->start);
iores = dev_request_mem_resource(dev, 1);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ goto release_resource;
+ }
ctrl_usb->wkup = IOMEM(iores->start);
spin_lock_init(&ctrl_usb->lock);
@@ -155,6 +159,13 @@ static int am335x_control_usb_probe(struct device_d *dev)
dev->priv = ctrl_usb;
return 0;
+
+release_resource:
+ release_region(iores);
+free_ctrl:
+ free(ctrl_usb);
+
+ return 0;
};
static struct driver_d am335x_control_driver = {
diff --git a/drivers/usb/musb/phy-am335x.c b/drivers/usb/musb/phy-am335x.c
index df31255d89..f2e870d7ee 100644
--- a/drivers/usb/musb/phy-am335x.c
+++ b/drivers/usb/musb/phy-am335x.c
@@ -5,7 +5,6 @@
#include <linux/err.h>
#include "am35x-phy-control.h"
#include "musb_core.h"
-#include "phy-am335x.h"
struct am335x_usbphy {
void __iomem *base;
@@ -14,13 +13,6 @@ struct am335x_usbphy {
struct usb_phy phy;
};
-static struct am335x_usbphy *am_usbphy;
-
-struct usb_phy *am335x_get_usb_phy(void)
-{
- return &am_usbphy->phy;
-}
-
static int am335x_init(struct usb_phy *phy)
{
struct am335x_usbphy *am_usbphy = container_of(phy, struct am335x_usbphy, phy);
@@ -31,6 +23,7 @@ static int am335x_init(struct usb_phy *phy)
static int am335x_phy_probe(struct device_d *dev)
{
+ struct am335x_usbphy *am_usbphy;
struct resource *iores;
int ret;
@@ -44,22 +37,27 @@ static int am335x_phy_probe(struct device_d *dev)
am_usbphy->base = IOMEM(iores->start);
am_usbphy->phy_ctrl = am335x_get_phy_control(dev);
- if (!am_usbphy->phy_ctrl)
- return -ENODEV;
+ if (IS_ERR(am_usbphy->phy_ctrl)) {
+ ret = PTR_ERR(am_usbphy->phy_ctrl);
+ goto err_release;
+ }
am_usbphy->id = of_alias_get_id(dev->device_node, "phy");
if (am_usbphy->id < 0) {
dev_err(dev, "Missing PHY id: %d\n", am_usbphy->id);
- return am_usbphy->id;
+ ret = am_usbphy->id;
+ goto err_release;
}
am_usbphy->phy.init = am335x_init;
- dev->priv = am_usbphy;
+ dev->priv = &am_usbphy->phy;
dev_info(dev, "am_usbphy %p enabled\n", &am_usbphy->phy);
return 0;
+err_release:
+ release_region(iores);
err_free:
free(am_usbphy);
diff --git a/drivers/usb/musb/phy-am335x.h b/drivers/usb/musb/phy-am335x.h
deleted file mode 100644
index 27da2e3b10..0000000000
--- a/drivers/usb/musb/phy-am335x.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PHY_AM335x_H_
-#define _PHY_AM335x_H_
-
-struct usb_phy *am335x_get_usb_phy(void);
-
-#endif
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
index 70077e43a8..835814bf53 100644
--- a/drivers/video/ssd1307fb.c
+++ b/drivers/video/ssd1307fb.c
@@ -405,8 +405,9 @@ static int ssd1307fb_probe(struct device_d *dev)
}
info = xzalloc(sizeof(struct fb_info));
+ par = xzalloc(sizeof(*par));
- par = info->priv;
+ info->priv = par;
par->info = info;
par->client = client;
@@ -414,12 +415,8 @@ static int ssd1307fb_probe(struct device_d *dev)
par->reset = of_get_named_gpio(node,
"reset-gpios", 0);
- if (!gpio_is_valid(par->reset)) {
- ret = par->reset;
- if (ret != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Couldn't get named gpio 'reset-gpios': %s.\n",
- strerror(-ret));
+ if (!gpio_is_valid(par->reset) && par->reset == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
goto fb_alloc_error;
}
@@ -502,38 +499,41 @@ static int ssd1307fb_probe(struct device_d *dev)
info->screen_base = (u8 __force __iomem *)vmem;
- ret = gpio_request_one(par->reset,
- GPIOF_OUT_INIT_HIGH,
- "oled-reset");
- if (ret) {
- dev_err(&client->dev,
- "failed to request gpio %d: %d\n",
- par->reset, ret);
- goto reset_oled_error;
- }
-
- if (par->vbat) {
- ret = regulator_disable(par->vbat);
- if (ret < 0)
+ if (par->reset >= 0) {
+ ret = gpio_request_one(par->reset,
+ GPIOF_OUT_INIT_HIGH,
+ "oled-reset");
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to request gpio %d: %d\n",
+ par->reset, ret);
goto reset_oled_error;
+ }
}
- i2c_set_clientdata(client, info);
+ ret = regulator_disable(par->vbat);
+ if (ret < 0)
+ goto reset_oled_error;
- /* Reset the screen */
- gpio_set_value(par->reset, 0);
- udelay(4);
+ i2c_set_clientdata(client, info);
- if (par->vbat) {
- ret = regulator_enable(par->vbat);
- if (ret < 0)
- goto reset_oled_error;
+ if (par->reset > 0) {
+ /* Reset the screen */
+ gpio_set_value(par->reset, 0);
+ udelay(4);
}
- mdelay(100);
+ ret = regulator_enable(par->vbat);
+ if (ret < 0)
+ goto reset_oled_error;
- gpio_set_value(par->reset, 1);
- udelay(4);
+ if (par->vbat)
+ mdelay(100);
+
+ if (par->reset > 0) {
+ gpio_set_value(par->reset, 1);
+ udelay(4);
+ }
ret = ssd1307fb_init(par);
if (ret)
@@ -574,6 +574,7 @@ reset_oled_error:
free(vmem);
fb_alloc_error:
regulator_disable(par->vbat);
+ free(par);
free(info);
return ret;
}