summaryrefslogtreecommitdiff
path: root/drivers/reset
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@blueri.se>2019-10-03 16:08:35 +0200
committerStefano Babic <sbabic@denx.de>2019-10-08 16:36:36 +0200
commit6300dc4c61c9eccc9960bd9cd9b163032992fb4a (patch)
tree5d8477a940a8f9166fecf6a9d1e6c7fe03c0fba2 /drivers/reset
parentd08a194871fdf91b2ccdbaf02e35ed9443e0e170 (diff)
downloadu-boot-6300dc4c61c9eccc9960bd9cd9b163032992fb4a.tar.gz
u-boot-6300dc4c61c9eccc9960bd9cd9b163032992fb4a.tar.bz2
u-boot-6300dc4c61c9eccc9960bd9cd9b163032992fb4a.zip
imx: add support for i.MX7/i.MX8MQ reset controller
Add support for the reset controller that's used on the i.MX7D and i.MX8MQ. This will be needed to be able to assert the PCIe reset pins. Bindings taken from Linux, driver implementation mostly taken from Linux and adjusted to U-Boot infrastructure. Signed-off-by: Patrick Wildt <patrick@blueri.se> Reviewed-by: Fabio Estevam <festevam@gmail.com>
Diffstat (limited to 'drivers/reset')
-rw-r--r--drivers/reset/Kconfig7
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-imx7.c312
3 files changed, 320 insertions, 0 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 6ec6f39c85..976f3a701c 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -127,4 +127,11 @@ config RESET_HISILICON
help
Support for reset controller on HiSilicon SoCs.
+config RESET_IMX7
+ bool "i.MX7/8 Reset Driver"
+ depends on DM_RESET && (ARCH_MX7 || ARCH_IMX8M)
+ default y
+ help
+ Support for reset controller on i.MX7/8 SoCs.
+
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 7fec75bb49..f5875fce09 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o
+obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
new file mode 100644
index 0000000000..f2ca5cf801
--- /dev/null
+++ b/drivers/reset/reset-imx7.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, Impinj, Inc.
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <dt-bindings/reset/imx7-reset.h>
+#include <dt-bindings/reset/imx8mq-reset.h>
+#include <reset-uclass.h>
+
+struct imx7_reset_priv {
+ void __iomem *base;
+ struct reset_ops ops;
+};
+
+struct imx7_src_signal {
+ unsigned int offset, bit;
+};
+
+enum imx7_src_registers {
+ SRC_A7RCR0 = 0x0004,
+ SRC_M4RCR = 0x000c,
+ SRC_ERCR = 0x0014,
+ SRC_HSICPHY_RCR = 0x001c,
+ SRC_USBOPHY1_RCR = 0x0020,
+ SRC_USBOPHY2_RCR = 0x0024,
+ SRC_MIPIPHY_RCR = 0x0028,
+ SRC_PCIEPHY_RCR = 0x002c,
+ SRC_DDRC_RCR = 0x1000,
+};
+
+static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = {
+ [IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) },
+ [IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) },
+ [IMX7_RESET_A7_CORE_RESET0] = { SRC_A7RCR0, BIT(4) },
+ [IMX7_RESET_A7_CORE_RESET1] = { SRC_A7RCR0, BIT(5) },
+ [IMX7_RESET_A7_DBG_RESET0] = { SRC_A7RCR0, BIT(8) },
+ [IMX7_RESET_A7_DBG_RESET1] = { SRC_A7RCR0, BIT(9) },
+ [IMX7_RESET_A7_ETM_RESET0] = { SRC_A7RCR0, BIT(12) },
+ [IMX7_RESET_A7_ETM_RESET1] = { SRC_A7RCR0, BIT(13) },
+ [IMX7_RESET_A7_SOC_DBG_RESET] = { SRC_A7RCR0, BIT(20) },
+ [IMX7_RESET_A7_L2RESET] = { SRC_A7RCR0, BIT(21) },
+ [IMX7_RESET_SW_M4C_RST] = { SRC_M4RCR, BIT(1) },
+ [IMX7_RESET_SW_M4P_RST] = { SRC_M4RCR, BIT(2) },
+ [IMX7_RESET_EIM_RST] = { SRC_ERCR, BIT(0) },
+ [IMX7_RESET_HSICPHY_PORT_RST] = { SRC_HSICPHY_RCR, BIT(1) },
+ [IMX7_RESET_USBPHY1_POR] = { SRC_USBOPHY1_RCR, BIT(0) },
+ [IMX7_RESET_USBPHY1_PORT_RST] = { SRC_USBOPHY1_RCR, BIT(1) },
+ [IMX7_RESET_USBPHY2_POR] = { SRC_USBOPHY2_RCR, BIT(0) },
+ [IMX7_RESET_USBPHY2_PORT_RST] = { SRC_USBOPHY2_RCR, BIT(1) },
+ [IMX7_RESET_MIPI_PHY_MRST] = { SRC_MIPIPHY_RCR, BIT(1) },
+ [IMX7_RESET_MIPI_PHY_SRST] = { SRC_MIPIPHY_RCR, BIT(2) },
+ [IMX7_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) },
+ [IMX7_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
+ [IMX7_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) },
+ [IMX7_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) },
+ [IMX7_RESET_DDRC_PRST] = { SRC_DDRC_RCR, BIT(0) },
+ [IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) },
+};
+
+static int imx7_reset_deassert_imx7(struct reset_ctl *rst)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
+ const struct imx7_src_signal *sig = imx7_src_signals;
+ u32 val;
+
+ if (rst->id >= IMX7_RESET_NUM)
+ return -EINVAL;
+
+ if (rst->id == IMX7_RESET_PCIEPHY) {
+ /*
+ * wait for more than 10us to release phy g_rst and
+ * btnrst
+ */
+ udelay(10);
+ }
+
+ val = readl(priv->base + sig[rst->id].offset);
+ switch (rst->id) {
+ case IMX7_RESET_PCIE_CTRL_APPS_EN:
+ val |= sig[rst->id].bit;
+ break;
+ default:
+ val &= ~sig[rst->id].bit;
+ break;
+ }
+ writel(val, priv->base + sig[rst->id].offset);
+
+ return 0;
+}
+
+static int imx7_reset_assert_imx7(struct reset_ctl *rst)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
+ const struct imx7_src_signal *sig = imx7_src_signals;
+ u32 val;
+
+ if (rst->id >= IMX7_RESET_NUM)
+ return -EINVAL;
+
+ val = readl(priv->base + sig[rst->id].offset);
+ switch (rst->id) {
+ case IMX7_RESET_PCIE_CTRL_APPS_EN:
+ val &= ~sig[rst->id].bit;
+ break;
+ default:
+ val |= sig[rst->id].bit;
+ break;
+ }
+ writel(val, priv->base + sig[rst->id].offset);
+
+ return 0;
+}
+
+enum imx8mq_src_registers {
+ SRC_A53RCR0 = 0x0004,
+ SRC_HDMI_RCR = 0x0030,
+ SRC_DISP_RCR = 0x0034,
+ SRC_GPU_RCR = 0x0040,
+ SRC_VPU_RCR = 0x0044,
+ SRC_PCIE2_RCR = 0x0048,
+ SRC_MIPIPHY1_RCR = 0x004c,
+ SRC_MIPIPHY2_RCR = 0x0050,
+ SRC_DDRC2_RCR = 0x1004,
+};
+
+static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
+ [IMX8MQ_RESET_A53_CORE_POR_RESET0] = { SRC_A53RCR0, BIT(0) },
+ [IMX8MQ_RESET_A53_CORE_POR_RESET1] = { SRC_A53RCR0, BIT(1) },
+ [IMX8MQ_RESET_A53_CORE_POR_RESET2] = { SRC_A53RCR0, BIT(2) },
+ [IMX8MQ_RESET_A53_CORE_POR_RESET3] = { SRC_A53RCR0, BIT(3) },
+ [IMX8MQ_RESET_A53_CORE_RESET0] = { SRC_A53RCR0, BIT(4) },
+ [IMX8MQ_RESET_A53_CORE_RESET1] = { SRC_A53RCR0, BIT(5) },
+ [IMX8MQ_RESET_A53_CORE_RESET2] = { SRC_A53RCR0, BIT(6) },
+ [IMX8MQ_RESET_A53_CORE_RESET3] = { SRC_A53RCR0, BIT(7) },
+ [IMX8MQ_RESET_A53_DBG_RESET0] = { SRC_A53RCR0, BIT(8) },
+ [IMX8MQ_RESET_A53_DBG_RESET1] = { SRC_A53RCR0, BIT(9) },
+ [IMX8MQ_RESET_A53_DBG_RESET2] = { SRC_A53RCR0, BIT(10) },
+ [IMX8MQ_RESET_A53_DBG_RESET3] = { SRC_A53RCR0, BIT(11) },
+ [IMX8MQ_RESET_A53_ETM_RESET0] = { SRC_A53RCR0, BIT(12) },
+ [IMX8MQ_RESET_A53_ETM_RESET1] = { SRC_A53RCR0, BIT(13) },
+ [IMX8MQ_RESET_A53_ETM_RESET2] = { SRC_A53RCR0, BIT(14) },
+ [IMX8MQ_RESET_A53_ETM_RESET3] = { SRC_A53RCR0, BIT(15) },
+ [IMX8MQ_RESET_A53_SOC_DBG_RESET] = { SRC_A53RCR0, BIT(20) },
+ [IMX8MQ_RESET_A53_L2RESET] = { SRC_A53RCR0, BIT(21) },
+ [IMX8MQ_RESET_SW_NON_SCLR_M4C_RST] = { SRC_M4RCR, BIT(0) },
+ [IMX8MQ_RESET_OTG1_PHY_RESET] = { SRC_USBOPHY1_RCR, BIT(0) },
+ [IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
+ [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
+ [IMX8MQ_RESET_MIPI_DSI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(2) },
+ [IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
+ [IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
+ [IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
+ [IMX8MQ_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR,
+ BIT(2) | BIT(1) },
+ [IMX8MQ_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
+ [IMX8MQ_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) },
+ [IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) },
+ [IMX8MQ_RESET_HDMI_PHY_APB_RESET] = { SRC_HDMI_RCR, BIT(0) },
+ [IMX8MQ_RESET_DISP_RESET] = { SRC_DISP_RCR, BIT(0) },
+ [IMX8MQ_RESET_GPU_RESET] = { SRC_GPU_RCR, BIT(0) },
+ [IMX8MQ_RESET_VPU_RESET] = { SRC_VPU_RCR, BIT(0) },
+ [IMX8MQ_RESET_PCIEPHY2] = { SRC_PCIE2_RCR,
+ BIT(2) | BIT(1) },
+ [IMX8MQ_RESET_PCIEPHY2_PERST] = { SRC_PCIE2_RCR, BIT(3) },
+ [IMX8MQ_RESET_PCIE2_CTRL_APPS_EN] = { SRC_PCIE2_RCR, BIT(6) },
+ [IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF] = { SRC_PCIE2_RCR, BIT(11) },
+ [IMX8MQ_RESET_MIPI_CSI1_CORE_RESET] = { SRC_MIPIPHY1_RCR, BIT(0) },
+ [IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET] = { SRC_MIPIPHY1_RCR, BIT(1) },
+ [IMX8MQ_RESET_MIPI_CSI1_ESC_RESET] = { SRC_MIPIPHY1_RCR, BIT(2) },
+ [IMX8MQ_RESET_MIPI_CSI2_CORE_RESET] = { SRC_MIPIPHY2_RCR, BIT(0) },
+ [IMX8MQ_RESET_MIPI_CSI2_PHY_REF_RESET] = { SRC_MIPIPHY2_RCR, BIT(1) },
+ [IMX8MQ_RESET_MIPI_CSI2_ESC_RESET] = { SRC_MIPIPHY2_RCR, BIT(2) },
+ [IMX8MQ_RESET_DDRC1_PRST] = { SRC_DDRC_RCR, BIT(0) },
+ [IMX8MQ_RESET_DDRC1_CORE_RESET] = { SRC_DDRC_RCR, BIT(1) },
+ [IMX8MQ_RESET_DDRC1_PHY_RESET] = { SRC_DDRC_RCR, BIT(2) },
+ [IMX8MQ_RESET_DDRC2_PHY_RESET] = { SRC_DDRC2_RCR, BIT(0) },
+ [IMX8MQ_RESET_DDRC2_CORE_RESET] = { SRC_DDRC2_RCR, BIT(1) },
+ [IMX8MQ_RESET_DDRC2_PRST] = { SRC_DDRC2_RCR, BIT(2) },
+};
+
+static int imx7_reset_deassert_imx8mq(struct reset_ctl *rst)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
+ const struct imx7_src_signal *sig = imx8mq_src_signals;
+ u32 val;
+
+ if (rst->id >= IMX8MQ_RESET_NUM)
+ return -EINVAL;
+
+ if (rst->id == IMX8MQ_RESET_PCIEPHY ||
+ rst->id == IMX8MQ_RESET_PCIEPHY2) {
+ /*
+ * wait for more than 10us to release phy g_rst and
+ * btnrst
+ */
+ udelay(10);
+ }
+
+ val = readl(priv->base + sig[rst->id].offset);
+ switch (rst->id) {
+ case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
+ case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
+ val |= sig[rst->id].bit;
+ break;
+ default:
+ val &= ~sig[rst->id].bit;
+ break;
+ }
+ writel(val, priv->base + sig[rst->id].offset);
+
+ return 0;
+}
+
+static int imx7_reset_assert_imx8mq(struct reset_ctl *rst)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
+ const struct imx7_src_signal *sig = imx8mq_src_signals;
+ u32 val;
+
+ if (rst->id >= IMX8MQ_RESET_NUM)
+ return -EINVAL;
+
+ val = readl(priv->base + sig[rst->id].offset);
+ switch (rst->id) {
+ case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
+ case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
+ val &= ~sig[rst->id].bit;
+ break;
+ default:
+ val |= sig[rst->id].bit;
+ break;
+ }
+ writel(val, priv->base + sig[rst->id].offset);
+
+ return 0;
+}
+
+static int imx7_reset_assert(struct reset_ctl *rst)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
+ return priv->ops.rst_assert(rst);
+}
+
+static int imx7_reset_deassert(struct reset_ctl *rst)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
+ return priv->ops.rst_deassert(rst);
+}
+
+static int imx7_reset_free(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static int imx7_reset_request(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static const struct reset_ops imx7_reset_reset_ops = {
+ .request = imx7_reset_request,
+ .free = imx7_reset_free,
+ .rst_assert = imx7_reset_assert,
+ .rst_deassert = imx7_reset_deassert,
+};
+
+static const struct udevice_id imx7_reset_ids[] = {
+ { .compatible = "fsl,imx7d-src" },
+ { .compatible = "fsl,imx8mq-src" },
+ { }
+};
+
+static int imx7_reset_probe(struct udevice *dev)
+{
+ struct imx7_reset_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr(dev);
+ if (!priv->base)
+ return -ENOMEM;
+
+ if (device_is_compatible(dev, "fsl,imx8mq-src")) {
+ priv->ops.rst_assert = imx7_reset_assert_imx8mq;
+ priv->ops.rst_deassert = imx7_reset_deassert_imx8mq;
+ } else if (device_is_compatible(dev, "fsl,imx7d-src")) {
+ priv->ops.rst_assert = imx7_reset_assert_imx7;
+ priv->ops.rst_deassert = imx7_reset_deassert_imx7;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(imx7_reset) = {
+ .name = "imx7_reset",
+ .id = UCLASS_RESET,
+ .of_match = imx7_reset_ids,
+ .ops = &imx7_reset_reset_ops,
+ .probe = imx7_reset_probe,
+ .priv_auto_alloc_size = sizeof(struct imx7_reset_priv),
+};