summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-04-15 14:01:50 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-04-15 14:01:50 +0200
commite61c75c259af8601a671e14237b464e0d49fd0df (patch)
tree3d827b3500fc00dbe8f5ec164c0aee6aabe99519 /arch
parenta9450309bb51ff3d7159db85b6b40be20eaba962 (diff)
parent4539ad7832f761f5af579d1f53f82ee9845615bc (diff)
downloadbarebox-e61c75c259af8601a671e14237b464e0d49fd0df.tar.gz
barebox-e61c75c259af8601a671e14237b464e0d49fd0df.tar.xz
Merge branch 'for-next/imx'
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/boards/Makefile2
-rw-r--r--arch/arm/boards/kamstrup-mx7-concentrator/Makefile1
-rw-r--r--arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg79
-rw-r--r--arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c35
-rw-r--r--arch/arm/boards/skov-imx6/Makefile3
-rw-r--r--arch/arm/boards/skov-imx6/board.c528
-rw-r--r--arch/arm/boards/skov-imx6/env/init/automount14
-rw-r--r--arch/arm/boards/skov-imx6/env/nv/boot.default1
-rw-r--r--arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg4
-rw-r--r--arch/arm/boards/skov-imx6/lowlevel.c664
-rw-r--r--arch/arm/configs/imx_v7_defconfig1
-rw-r--r--arch/arm/dts/Makefile2
-rw-r--r--arch/arm/dts/imx6dl-skov-imx6.dts24
-rw-r--r--arch/arm/dts/imx6q-skov-imx6.dts28
-rw-r--r--arch/arm/dts/imx6qdl-skov-imx6.dtsi546
-rw-r--r--arch/arm/dts/imx7d-flex-concentrator-mfg.dts108
-rw-r--r--arch/arm/mach-imx/Kconfig11
-rw-r--r--arch/arm/mach-imx/boot.c3
-rw-r--r--arch/arm/mach-imx/include/mach/imx-gpio.h21
19 files changed, 2068 insertions, 7 deletions
diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index 9ccb75e27b..0c1c077f00 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_MACH_HABA_KNX_LITE) += haba-knx/
obj-$(CONFIG_MACH_IMX21ADS) += freescale-mx21-ads/
obj-$(CONFIG_MACH_IMX233_OLINUXINO) += imx233-olinuxino/
obj-$(CONFIG_MACH_IMX27ADS) += freescale-mx27-ads/
+obj-$(CONFIG_MACH_KAMSTRUP_MX7_CONCENTRATOR) += kamstrup-mx7-concentrator/
obj-$(CONFIG_MACH_KINDLE3) += kindle3/
obj-$(CONFIG_MACH_KONTRON_SAMX6I) += kontron-samx6i/
obj-$(CONFIG_MACH_LENOVO_IX4_300D) += lenovo-ix4-300d/
@@ -114,6 +115,7 @@ obj-$(CONFIG_MACH_RPI_COMMON) += raspberry-pi/
obj-$(CONFIG_MACH_SABRELITE) += freescale-mx6-sabrelite/
obj-$(CONFIG_MACH_SABRESD) += freescale-mx6-sabresd/
obj-$(CONFIG_MACH_AC_SXB) += ac-sxb/
+obj-$(CONFIG_MACH_SKOV_IMX6) += skov-imx6/
obj-$(CONFIG_MACH_FREESCALE_IMX6SX_SABRESDB) += freescale-mx6sx-sabresdb/
obj-$(CONFIG_MACH_SAMA5D27_GIANTBOARD) += sama5d27-giantboard/
obj-$(CONFIG_MACH_SAMA5D27_SOM1) += sama5d27-som1/
diff --git a/arch/arm/boards/kamstrup-mx7-concentrator/Makefile b/arch/arm/boards/kamstrup-mx7-concentrator/Makefile
new file mode 100644
index 0000000000..7ab9f52747
--- /dev/null
+++ b/arch/arm/boards/kamstrup-mx7-concentrator/Makefile
@@ -0,0 +1 @@
+lwl-y += lowlevel.o \ No newline at end of file
diff --git a/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg b/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg
new file mode 100644
index 0000000000..4b36324110
--- /dev/null
+++ b/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg
@@ -0,0 +1,79 @@
+soc imx7
+loadaddr 0xbfbff000
+ivtofs 0x400
+
+#include <mach/imx7-ddr-regs.h>
+
+wm 32 0x30340004 0x4F400005 /* IOMUXC_GPR_GPR1 */
+/* Clear then set bit30 to ensure exit from DDR retention */
+wm 32 0x30360388 0x40000000
+wm 32 0x30360384 0x40000000
+
+/* TQMa7x DRAM Timing REV0100 */
+/* DCD Code i.MX7D/S 528 MHz 1 GByte Samsung K4B4G1646D */
+wm 32 0x30360070 0x0070302C /* CCM_ANALOG_PLL_DDRx */
+wm 32 0x30360090 0x00000000 /* CCM_ANALOG_PLL_NUM */
+wm 32 0x30360070 0x0060302C /* CCM_ANALOG_PLL_DDRx */
+check 32 until_all_bits_set 0x30360070 0x80000000
+wm 32 0x30391000 0x00000002 /* SRC_DDRC_RCR */
+
+wm 32 MX7_DDRC_MSTR 0x01040001
+wm 32 MX7_DDRC_DFIUPD0 0x80400003
+wm 32 MX7_DDRC_DFIUPD1 0x00100020
+wm 32 MX7_DDRC_DFIUPD2 0x80100004
+wm 32 MX7_DDRC_RFSHTMG 0x00200045
+wm 32 MX7_DDRC_MP_PCTRL_0 0x00000001
+wm 32 MX7_DDRC_INIT0 0x00020081
+wm 32 MX7_DDRC_INIT1 0x00680000
+wm 32 MX7_DDRC_INIT3 0x09300004
+wm 32 MX7_DDRC_INIT4 0x00480000
+wm 32 MX7_DDRC_INIT5 0x00100004
+wm 32 MX7_DDRC_RANKCTL 0x0000033F
+wm 32 MX7_DDRC_DRAMTMG0 0x090E0809
+wm 32 MX7_DDRC_DRAMTMG1 0x0007020E
+wm 32 MX7_DDRC_DRAMTMG2 0x03040407
+wm 32 MX7_DDRC_DRAMTMG3 0x00002006
+wm 32 MX7_DDRC_DRAMTMG4 0x04020304
+wm 32 MX7_DDRC_DRAMTMG5 0x03030202
+wm 32 MX7_DDRC_DRAMTMG8 0x00000803
+wm 32 MX7_DDRC_ZQCTL0 0x00800020
+wm 32 MX7_DDRC_DFITMG0 0x02098204
+wm 32 MX7_DDRC_DFITMG1 0x00030303
+wm 32 MX7_DDRC_ADDRMAP0 0x00000016
+wm 32 MX7_DDRC_ADDRMAP1 0x00171717
+wm 32 MX7_DDRC_ADDRMAP4 0x00000F0F
+wm 32 MX7_DDRC_ADDRMAP5 0x04040404
+wm 32 MX7_DDRC_ADDRMAP6 0x0F040404
+wm 32 MX7_DDRC_ODTCFG 0x06000604
+wm 32 MX7_DDRC_ODTMAP 0x00000001
+wm 32 0x30391000 0x00000000 /* SRC_DDRC_RCR */
+wm 32 MX7_DDR_PHY_PHY_CON0 0x17420F40
+wm 32 MX7_DDR_PHY_PHY_CON1 0x10210100
+wm 32 MX7_DDR_PHY_PHY_CON4 0x00060807
+wm 32 MX7_DDR_PHY_MDLL_CON0 0x1010007E
+wm 32 MX7_DDR_PHY_DRVDS_CON0 0x00000924
+/* DDR_PHY_CMD_DESKEW_CON0 not set */
+/* DDR_PHY_CMD_DESKEW_CON1 not set */
+/* DDR_PHY_CMD_DESKEW_CON2 not set */
+/* DDR_PHY_CMD_DESKEW_CON3 not set */
+/* DDR_PHY_LVL_CON0 not set */
+wm 32 MX7_DDR_PHY_OFFSET_RD_CON0 0x0B0B0B0B
+wm 32 MX7_DDR_PHY_OFFSET_WR_CON0 0x06060606
+wm 32 MX7_DDR_PHY_CMD_SDLL_CON0 0x01000010
+wm 32 MX7_DDR_PHY_CMD_SDLL_CON0 0x00000010
+
+wm 32 MX7_DDR_PHY_ZQ_CON0 0x0C407304
+wm 32 MX7_DDR_PHY_ZQ_CON0 0x0C447304
+wm 32 MX7_DDR_PHY_ZQ_CON0 0x0C447306
+check 32 until_all_bits_set MX7_DDR_PHY_ZQ_CON1 0x1 /* ZQ Calibration is finished */
+wm 32 MX7_DDR_PHY_ZQ_CON0 0x0C447304
+wm 32 MX7_DDR_PHY_ZQ_CON0 0x0C407304
+
+wm 32 0x30384130 0x00000000 /* CCM_CCGRn */
+wm 32 0x30340020 0x00000178 /* IOMUXC_GPR_GPR8 */
+wm 32 0x30384130 0x00000002 /* CCM_CCGRn */
+wm 32 0x30790018 0x0000000f /* DDR_PHY_LP_CON0 */
+
+/* DDRC_STAT */
+check 32 until_all_bits_set 0x307a0004 0x1
+
diff --git a/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c b/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c
new file mode 100644
index 0000000000..8cd6d67f7e
--- /dev/null
+++ b/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c
@@ -0,0 +1,35 @@
+#include <debug_ll.h>
+#include <io.h>
+#include <common.h>
+#include <linux/sizes.h>
+#include <mach/generic.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <mach/imx7-ccm-regs.h>
+#include <mach/iomux-mx7.h>
+#include <mach/debug_ll.h>
+#include <asm/cache.h>
+#include <mach/esdctl.h>
+
+extern char __dtb_z_imx7d_flex_concentrator_mfg_start[];
+
+static inline void setup_uart(void)
+{
+ imx7_early_setup_uart_clock();
+
+ imx7_setup_pad(MX7D_PAD_SAI2_TX_BCLK__UART4_DCE_TX);
+
+ imx7_uart_setup_ll();
+
+ putc_ll('>');
+}
+
+ENTRY_FUNCTION(start_kamstrup_mx7_concentrator, r0, r1, r2)
+{
+ imx7_cpu_lowlevel_init();
+
+ if (IS_ENABLED(CONFIG_DEBUG_LL))
+ setup_uart();
+
+ imx7d_barebox_entry(__dtb_z_imx7d_flex_concentrator_mfg_start + get_runtime_offset());
+}
diff --git a/arch/arm/boards/skov-imx6/Makefile b/arch/arm/boards/skov-imx6/Makefile
new file mode 100644
index 0000000000..a5e85bc1e1
--- /dev/null
+++ b/arch/arm/boards/skov-imx6/Makefile
@@ -0,0 +1,3 @@
+obj-y += board.o
+lwl-y += lowlevel.o
+obj-pbl-y += version.o
diff --git a/arch/arm/boards/skov-imx6/board.c b/arch/arm/boards/skov-imx6/board.c
new file mode 100644
index 0000000000..a58172b2b1
--- /dev/null
+++ b/arch/arm/boards/skov-imx6/board.c
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "skov-imx6: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <mach/bbu.h>
+#include <environment.h>
+#include <bootsource.h>
+#include <globalvar.h>
+#include <net.h>
+#include <of_gpio.h>
+#include <gpio.h>
+
+#include "version.h"
+
+static int eth_of_fixup_node(struct device_node *root, const char *node_path,
+ const u8 *ethaddr)
+{
+ struct device_node *node;
+ int ret;
+
+ if (!is_valid_ether_addr(ethaddr)) {
+ unsigned char ethaddr_str[sizeof("xx:xx:xx:xx:xx:xx")];
+
+ ethaddr_to_string(ethaddr, ethaddr_str);
+ pr_err("The mac-address %s is invalid.\n", ethaddr_str);
+ return -EINVAL;
+ }
+
+ node = of_find_node_by_path_from(root, node_path);
+ if (!node) {
+ pr_err("Did not find node %s to fix up with stored mac-address.\n",
+ node_path);
+ return -ENOENT;
+ }
+
+ ret = of_set_property(node, "mac-address", ethaddr, ETH_ALEN, 1);
+ if (ret)
+ pr_err("Setting mac-address property of %s failed with: %s.\n",
+ node->full_name, strerror(-ret));
+
+ return ret;
+}
+
+static int eth_of_fixup_node_from_eth_device(struct device_node *root,
+ const char *node_path,
+ const char *ethname)
+{
+ struct eth_device *edev;
+
+ edev = eth_get_byname(ethname);
+ if (!edev) {
+ pr_err("Did not find eth device \"%s\" to copy mac-address from.\n", ethname);
+ return -ENOENT;
+ }
+
+ return eth_of_fixup_node(root, node_path, edev->ethaddr);
+}
+
+static int get_mac_address_from_env_variable(const char *env, u8 ethaddr[ETH_ALEN])
+{
+ const char *ethaddr_str;
+ int ret;
+
+ ethaddr_str = getenv(env);
+ if (!ethaddr_str) {
+ pr_err("State variable %s storing the mac-address not found.\n", env);
+ return -ENOENT;
+ }
+
+ ret = string_to_ethaddr(ethaddr_str, ethaddr);
+ if (ret < 0) {
+ pr_err("Could not convert \"%s\" in state variable %s into mac-address.\n",
+ ethaddr_str, env);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_default_mac_address_from_state_node(const char *state_node_path,
+ u8 ethaddr[ETH_ALEN])
+{
+ struct device_node *node;
+ int ret;
+
+ node = of_find_node_by_path(state_node_path);
+ if (!node) {
+ pr_err("Node %s defining the state variable not found.\n", state_node_path);
+ return -ENOENT;
+ }
+
+ ret = of_property_read_u8_array(node, "default", ethaddr, ETH_ALEN);
+ if (ret) {
+ pr_err("Node %s has no property \"default\" of proper type.\n", state_node_path);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int eth2_of_fixup_node_individually(struct device_node *root,
+ const char *node_path,
+ const char *ethname,
+ const char *env,
+ const char *state_node_path)
+{
+ u8 env_ethaddr[ETH_ALEN], default_ethaddr[ETH_ALEN];
+ int ret;
+
+ ret = get_mac_address_from_env_variable(env, env_ethaddr);
+ if (ret)
+ goto copy_mac_from_eth0;
+
+ ret = get_default_mac_address_from_state_node(state_node_path, default_ethaddr);
+ if (ret)
+ goto copy_mac_from_eth0;
+
+ /*
+ * As the default is bogus copy the MAC address from eth0 if
+ * the state variable has not been set to a different variant
+ */
+ if (memcmp(env_ethaddr, default_ethaddr, ETH_ALEN) == 0)
+ goto copy_mac_from_eth0;
+
+ return eth_of_fixup_node(root, node_path, env_ethaddr);
+
+copy_mac_from_eth0:
+ return eth_of_fixup_node_from_eth_device(root, node_path, ethname);
+}
+
+#define MAX_V_GPIO 8
+
+struct board_description {
+ const char *variant;
+ const char *revision;
+ const char *soc;
+ const char *dts_compatible;
+ const char *display;
+ unsigned flags;
+};
+
+#define SKOV_NEED_ENABLE_RMII BIT(0)
+#define SKOV_DISPLAY_PARALLEL BIT(1)
+#define SKOV_ENABLE_MMC_POWER BIT(2)
+#define SKOV_DISPLAY_LVDS BIT(3)
+
+static const struct board_description imx6_variants[] = {
+ [0] = {
+ .variant = "high performance",
+ .revision = "A",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6-imxq-revA",
+ .flags = SKOV_NEED_ENABLE_RMII | SKOV_DISPLAY_PARALLEL,
+ },
+ [1] = {
+ .variant = "low cost",
+ .revision = "A",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6-imxdl-revA",
+ .flags = SKOV_NEED_ENABLE_RMII | SKOV_DISPLAY_PARALLEL,
+ },
+ [2] = {
+ .variant = "high performance",
+ .revision = "A",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6-imxq-revA",
+ .flags = SKOV_NEED_ENABLE_RMII | SKOV_DISPLAY_PARALLEL,
+ },
+ [4] = {
+ .variant = "low cost",
+ .revision = "A",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6-imxdl-revA",
+ .flags = SKOV_NEED_ENABLE_RMII | SKOV_DISPLAY_PARALLEL,
+ },
+ [8] = {
+ .variant = "high performance",
+ .revision = "A",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6-imxq-revA",
+ .flags = SKOV_NEED_ENABLE_RMII | SKOV_DISPLAY_PARALLEL,
+ },
+ [9] = {
+ .variant = "minimum cost",
+ .revision = "B",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6-imxdl-revB",
+ .flags = SKOV_DISPLAY_PARALLEL,
+ },
+ [10] = {
+ .variant = "low cost",
+ .revision = "B",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6-imxdl-revB",
+ .flags = SKOV_DISPLAY_PARALLEL,
+ },
+ [11] = {
+ .variant = "high performance",
+ .revision = "B",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6-imxq-revB",
+ .flags = SKOV_DISPLAY_PARALLEL,
+ },
+ [12] = {
+ /* FIXME this one is a revision 'C' according to the schematics */
+ .variant = "max performance",
+ .revision = "B",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6q-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_DISPLAY_PARALLEL,
+ },
+ [13] = {
+ .variant = "low cost",
+ .revision = "C",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6dl-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [14] = {
+ .variant = "high performance",
+ .revision = "C",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6q-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [15] = {
+ .variant = "middle performance",
+ .revision = "C",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6dl-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [16] = {
+ .variant = "Solo_R512M_F4G",
+ .revision = "C",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6dl-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [17] = {
+ .variant = "Quad_R2G_F8G",
+ .revision = "C",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6q-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [18] = {
+ .variant = "QuadPlus_R4G_F16G",
+ .revision = "C",
+ .soc = "i.MX6Q+",
+ .dts_compatible = "skov,imx6q-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [19] = {
+ .variant = "Solo_R512M_F2G",
+ .revision = "C",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6dl-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [20] = {
+ .variant = "Quad_R1G_F4G",
+ .revision = "C",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6q-skov-revc-lt2",
+ .display = "l2rt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [21] = {
+ .variant = "Solo_R512M_F2G",
+ .revision = "C",
+ .soc = "i.MX6S",
+ .dts_compatible = "skov,imx6dl-skov-revc-lt6",
+ .display = "l6whrt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [22] = {
+ .variant = "Quad_R1G_F4G",
+ .revision = "C",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6q-skov-revc-lt6",
+ .display = "l6whrt",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_PARALLEL,
+ },
+ [24] = {
+ .variant = "Quad_R1G_F4G",
+ .revision = "E",
+ .soc = "i.MX6Q",
+ .dts_compatible = "skov,imx6q-skov-reve-mi1010ait-1cp1",
+ .display = "mi1010ait-1cp1",
+ .flags = SKOV_ENABLE_MMC_POWER | SKOV_DISPLAY_LVDS,
+ },
+};
+
+static int skov_board_no = -1;
+
+static int skov_imx6_fixup(struct device_node *root, void *unused)
+{
+ int ret;
+ const char *val;
+ uint32_t brightness;
+ struct device_node *node;
+ struct device_node *chosen = of_create_node(root, "/chosen");
+
+ eth_of_fixup_node_from_eth_device(root,
+ "/mdio-gpio/ksz8873@3/ports/ports@0", "eth0");
+ eth2_of_fixup_node_individually(root,
+ "/mdio-gpio/ksz8873@3/ports/ports@1", "eth0",
+ "state.ethaddr.eth2", "/state/ethaddr/eth2");
+
+ switch (bootsource_get()) {
+ case BOOTSOURCE_MMC:
+ /* use default variant of state variable defined in devicetree */
+ brightness = 8;
+ break;
+ default:
+ val = getenv("state.display.brightness");
+ if (!val) {
+ pr_err("could not get default display brightness\n");
+ return 0;
+ }
+
+ brightness = simple_strtoul(val, NULL, 0);
+ break;
+ }
+
+ for_each_compatible_node_from(node, root, NULL, "pwm-backlight") {
+ ret = of_property_write_u32(node, "default-brightness-level", brightness);
+ if (ret)
+ pr_err("error %d while setting default-brightness-level property on node %s to %d\n",
+ ret, node->name, brightness);
+ }
+
+ of_property_write_u32(chosen, "skov,imx6-board-version", skov_board_no);
+ of_property_write_string(chosen, "skov,imx6-board-variant",
+ imx6_variants[skov_board_no].variant);
+
+ return 0;
+}
+
+/*
+ * Some variants need tweaks to make them work
+ *
+ * Revision A has no backlight control, since revision B it is present (GPIO6/23)
+ * Revision A needs GPIO1/24 to be low to make network working
+ * Revision C can control the SD main power supply
+ */
+static void skov_init_board(const struct board_description *variant)
+{
+ struct device_node *np;
+ char *environment_path, *envdev;
+ int ret;
+
+ imx6_bbu_internal_spi_i2c_register_handler("spiflash", "/dev/m25p0.barebox",
+ BBU_HANDLER_FLAG_DEFAULT);
+
+ of_register_fixup(skov_imx6_fixup, NULL);
+
+ switch (bootsource_get()) {
+ case BOOTSOURCE_MMC:
+ environment_path = "/chosen/environment-sd";
+ envdev = "MMC";
+ break;
+ default:
+ environment_path = "/chosen/environment-spinor";
+ envdev = "SPI NOR flash";
+ break;
+ }
+
+ pr_notice("Using environment in %s\n", envdev);
+
+ ret = of_device_enable_path(environment_path);
+ if (ret < 0)
+ pr_warn("Failed to enable environment partition '%s' (%d)\n",
+ environment_path, ret);
+
+ if (variant->flags & SKOV_NEED_ENABLE_RMII) {
+ /*
+ * MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 is a gpio which must be
+ * low to enable the RMII from the switch point of view
+ */
+ gpio_request(24, "must_be_low");
+ gpio_direction_output(24, 0);
+ }
+
+ /* SD card handling */
+ gpio_request(205, "mmc io supply");
+ gpio_direction_output(205, 0); /* select 3.3 V IO voltage */
+
+ if (variant->flags & SKOV_ENABLE_MMC_POWER) {
+ /*
+ * keep in sync with devicetree's 'regulator-boot-on' setting for
+ * this regulator
+ */
+ gpio_request(200, "mmc power supply");
+ gpio_direction_output(200, 0); /* switch on */
+ mdelay(1);
+ gpio_direction_output(200, 1); /* switch on */
+ }
+
+ if (variant->flags & SKOV_DISPLAY_PARALLEL) {
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx-parallel-display");
+ if (np)
+ of_device_enable_and_register(np);
+ else
+ pr_err("Cannot find \"fsl,imx-parallel-display\" node\n");
+ }
+
+ if (variant->flags & SKOV_DISPLAY_LVDS) {
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ldb");
+ if (np)
+ of_device_enable_and_register(np);
+ else
+ pr_err("Cannot find \"fsl,imx6q-ldb\" node\n");
+
+ /* ... as well as its channel 0 */
+ np = of_find_node_by_name(np, "lvds-channel@0");
+ if (np)
+ of_device_enable(np);
+ else
+ pr_err("Cannot find \"lvds-channel@0\" node\n");
+ }
+}
+
+static void fixup_machine_compatible(const char *compat)
+{
+ const char *curcompat;
+ struct device_node *root;
+ int cclen = 0, clen = strlen(compat) + 1;
+ void *buf;
+
+ root = of_get_root_node();
+ if (!root)
+ return;
+
+ curcompat = of_get_property(root, "compatible", &cclen);
+
+ buf = xzalloc(cclen + clen);
+
+ memcpy(buf, compat, clen);
+ memcpy(buf + clen, curcompat, cclen);
+
+ /*
+ * Prepend the compatible from board entry to the machine compatible.
+ * Used to match bootspec entries against it.
+ */
+ of_set_property(root, "compatible", buf, cclen + clen, true);
+
+ free(buf);
+}
+
+static int skov_imx6_probe(struct device_d *dev)
+{
+ unsigned v = 0;
+ const struct board_description *variant;
+
+ v = skov_imx6_get_version();
+
+ if (v >= ARRAY_SIZE(imx6_variants)) {
+ dev_err(dev, "Invalid variant %u\n", v);
+ return -EINVAL;
+ }
+
+ variant = &imx6_variants[v];
+
+ if (!variant->variant) {
+ dev_err(dev, "Invalid variant %u\n", v);
+ return -EINVAL;
+ }
+
+ skov_board_no = v;
+
+ globalvar_add_simple_int("board.no", &skov_board_no, "%u");
+ globalvar_add_simple("board.variant", variant->variant);
+ globalvar_add_simple("board.revision",variant->revision);
+ globalvar_add_simple("board.soc", variant->soc);
+ globalvar_add_simple("board.dts", variant->dts_compatible);
+ globalvar_add_simple("board.display", variant->display ?: NULL);
+
+ fixup_machine_compatible(variant->dts_compatible);
+
+ skov_init_board(variant);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id skov_version_ids[] = {
+ {
+ .compatible = "skov,imx6",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d skov_version_driver = {
+ .name = "skov-imx6",
+ .probe = skov_imx6_probe,
+ .of_compatible = DRV_OF_COMPAT(skov_version_ids),
+};
+coredevice_platform_driver(skov_version_driver);
+
+static void skov_imx6_devices_shutdown(void)
+{
+ const char *external;
+
+ if (skov_board_no < 0)
+ return;
+
+ external = getenv("state.display.external");
+ if (!external) {
+ pr_err("could not get state variable display.external\n");
+ return;
+ }
+
+ if (!strcmp(external, "0"))
+ setenv("backlight0.brightness", "0");
+}
+predevshutdown_exitcall(skov_imx6_devices_shutdown);
diff --git a/arch/arm/boards/skov-imx6/env/init/automount b/arch/arm/boards/skov-imx6/env/init/automount
new file mode 100644
index 0000000000..bc9ff48a0a
--- /dev/null
+++ b/arch/arm/boards/skov-imx6/env/init/automount
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if [ "$1" = menu ]; then
+ init-menu-add-entry "$0" "Automountpoints"
+ exit
+fi
+
+# development support
+mkdir -p /mnt/tftp
+automount /mnt/tftp 'ifup eth0 && mount -t tftp $eth0.serverip /mnt/tftp'
+
+# regular SD card based boot procedure
+mkdir -p /mnt/sd
+automount -d /mnt/sd 'mmc2.probe=1 && mount -t ext4 /dev/mmc2.0 /mnt/sd'
diff --git a/arch/arm/boards/skov-imx6/env/nv/boot.default b/arch/arm/boards/skov-imx6/env/nv/boot.default
new file mode 100644
index 0000000000..fe1a363da1
--- /dev/null
+++ b/arch/arm/boards/skov-imx6/env/nv/boot.default
@@ -0,0 +1 @@
+bootchooser
diff --git a/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg b/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg
new file mode 100644
index 0000000000..4bb615ebb0
--- /dev/null
+++ b/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg
@@ -0,0 +1,4 @@
+soc imx6
+loadaddr 0x00907000
+max_load_size 0x11000
+ivtofs 0x400
diff --git a/arch/arm/boards/skov-imx6/lowlevel.c b/arch/arm/boards/skov-imx6/lowlevel.c
new file mode 100644
index 0000000000..eab797faa1
--- /dev/null
+++ b/arch/arm/boards/skov-imx6/lowlevel.c
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "skov-imx6: " fmt
+
+#include <common.h>
+#include <mach/generic.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <debug_ll.h>
+#include <io.h>
+#include <mach/imx6-mmdc.h>
+#include <mach/imx6-ddr-regs.h>
+#include <mach/imx6.h>
+#include <mach/xload.h>
+#include <mach/esdctl.h>
+#include <serial/imx-uart.h>
+#include <mach/iomux-mx6.h>
+#include <mach/imx-gpio.h>
+#include "version.h"
+
+static void __udelay(int us)
+{
+ volatile int i;
+
+ for (i = 0; i < us * 4; i++);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Micron MT41K512M16HA-125 IT:E -> 8 GBit = 64 Meg x 16 x 8 banks
+ *
+ * Speed Grade Data Rate (MT/s) tRCD-tRP-CL tRCD(ns) tRP(ns) CL(ns)
+ * -125 1600 11-11-11 13.75 13.75 13.75
+ * (=800 MHz)
+ *
+ * Memory configuration used by variant:
+ * - "Max Performance", 64 bit data bus, 1066 MHz, 4 GiB memory
+ */
+static const struct mx6_ddr3_cfg skov_imx6_cfg_4x512Mb_1066MHz = {
+ .mem_speed = 1066,
+ .density = 8, /* GiBit */
+ .width = 16, /* 16 bit data per device */
+ .banks = 8,
+ .rowaddr = 16, /* 64 k */
+ .coladdr = 10, /* 1 k */
+ .pagesz = 2, /* [kiB] */
+ .trcd = 1375, /* 13.75 ns = 11 clocks @ 1.6 GHz */
+ .trcmin = 4875, /* 48.75 ns = 39 clocks @ 1.6 GHz */
+ .trasmin = 3500, /* 35 ns = 28 clocks @ 1.6 GHz */
+ .SRT = 0,
+};
+
+static const struct mx6_ddr_sysinfo skov_imx6_sysinfo_4x512Mb_1066MHz = {
+ .dsize = 2, /* 64 bit wide = 4 devices, 16 bit each */
+ .cs_density = 32, /* four 8 GBit devices connected */
+ .ncs = 1, /* one CS line for all devices */
+ .cs1_mirror = 1, /* TODO */
+ .bi_on = 1, /* TODO */
+ .rtt_nom = 1, /* MX6_MMDC_P0_MPODTCTRL -> 0x00022227 */
+ .rtt_wr = 0, /* is LW_EN is 0 in their code */
+ .ralat = 5, /* TODO */
+ .walat = 1, /* TODO */
+ .mif3_mode = 3, /* TODO */
+ .rst_to_cke = 0x23, /* used in their code as well */
+ .sde_to_rst = 0x10, /* used in their code as well */
+ .pd_fast_exit = 0, /* TODO */
+};
+
+static const struct mx6_mmdc_calibration skov_imx6_calib_4x512Mb_1066MHz = {
+ .p0_mpwldectrl0 = 0x001a0017,
+ .p0_mpwldectrl1 = 0x001F001F,
+ .p0_mpdgctrl0 = 0x43040319,
+ .p0_mpdgctrl1 = 0x03040279,
+ .p0_mprddlctl = 0x4d434248,
+ .p0_mpwrdlctl = 0x34424543,
+
+ .p1_mpwldectrl0 = 0x00170027,
+ .p1_mpwldectrl1 = 0x000a001f,
+ .p1_mpdgctrl0 = 0x43040321,
+ .p1_mpdgctrl1 = 0x03030251,
+ .p1_mprddlctl = 0x42413c4d,
+ .p1_mpwrdlctl = 0x49324933,
+};
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Micron MT41K256M16HA-125 IT:E -> 4 GBit = 32 Meg x 16 x 8 banks
+ *
+ * Speed Grade Data Rate (MT/s) tRCD-tRP-CL tRCD(ns) tRP(ns) CL(ns)
+ * -125 1600 11-11-11 13.75 13.75 13.75
+ * (=800 MHz)
+ *
+ * Memory configuration used by variant:
+ * - "Max Performance", 64 bit data bus, 1066 MHz, 2 GiB memory
+ */
+static const struct mx6_ddr3_cfg skov_imx6_cfg_4x256Mb_1066MHz = {
+ .mem_speed = 1066,
+ .density = 4, /* GiBit */
+ .width = 16, /* 16 bit data per device */
+ .banks = 8,
+ .rowaddr = 15, /* 32 k */
+ .coladdr = 10, /* 1 k */
+ .pagesz = 2, /* [kiB] */
+ .trcd = 1375, /* 13.75 ns = 11 clocks @ 1.6 GHz */
+ .trcmin = 4875, /* 48.75 ns = 39 clocks @ 1.6 GHz */
+ .trasmin = 3500, /* 35 ns = 28 clocks @ 1.6 GHz */
+ .SRT = 0,
+};
+
+static const struct mx6_ddr_sysinfo skov_imx6_sysinfo_4x256Mb_1066MHz = {
+ .dsize = 2, /* 64 bit wide = 4 devices, 16 bit each */
+ .cs_density = 16, /* four 4 GBit devices connected */
+ .ncs = 1, /* one CS line for all devices */
+ .cs1_mirror = 1, /* TODO */
+ .bi_on = 1, /* TODO */
+ .rtt_nom = 1, /* MX6_MMDC_P0_MPODTCTRL -> 0x00022227 */
+ .rtt_wr = 0, /* is LW_EN is 0 in their code */
+ .ralat = 5, /* TODO */
+ .walat = 1, /* TODO */
+ .mif3_mode = 3, /* TODO */
+ .rst_to_cke = 0x23, /* used in their code as well */
+ .sde_to_rst = 0x10, /* used in their code as well */
+ .pd_fast_exit = 0, /* TODO */
+};
+
+static const struct mx6_mmdc_calibration skov_imx6_calib_4x256Mb_1066MHz = {
+ .p0_mpwldectrl0 = 0x001a0017,
+ .p0_mpwldectrl1 = 0x001F001F,
+ .p0_mpdgctrl0 = 0x43040319,
+ .p0_mpdgctrl1 = 0x03040279,
+ .p0_mprddlctl = 0x4d434248,
+ .p0_mpwrdlctl = 0x34424543,
+
+ .p1_mpwldectrl0 = 0x00170027,
+ .p1_mpwldectrl1 = 0x000a001f,
+ .p1_mpdgctrl0 = 0x43040321,
+ .p1_mpdgctrl1 = 0x03030251,
+ .p1_mprddlctl = 0x42413c4d,
+ .p1_mpwrdlctl = 0x49324933,
+};
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Micron MT41K128M16JT-125 IT:K -> 2 GBit = 16 Meg x 16 x 8 banks
+ *
+ * Speed Grade Data Rate (MT/s) tRCD-tRP-CL tRCD(ns) tRP(ns) CL(ns)
+ * -125 ¹² 1600 11-11-11 13.75 13.75 13.75
+ * (=800 MHz)
+ *
+ * ¹ Backward compatible to 1066 (=533 MHz), CL = 7
+ * ² Backward compatible to 1333 (=667 MHz), CL = 9
+ *
+ * Memory configuration used by variant
+ * - "High Performance", 64 bit data bus, 1066 MHz, 1 GiB memory
+ */
+static const struct mx6_ddr3_cfg skov_imx6_cfg_4x128Mb_1066MHz = {
+ .mem_speed = 1066,
+ .density = 2, /* GiBit */
+ .width = 16, /* 16 bit data per device */
+ .banks = 8,
+ .rowaddr = 14, /* 16 k */
+ .coladdr = 10, /* 1 k */
+ .pagesz = 2, /* [kiB] */
+ .trcd = 1375, /* 13.75 ns = 11 clocks @ 1.6 GHz */
+ .trcmin = 4875, /* 48.75 ns = 39 clocks @ 1.6 GHz */
+ .trasmin = 3500, /* 35 ns = 28 clocks @ 1.6 GHz */
+ .SRT = 0,
+};
+
+static const struct mx6_ddr_sysinfo skov_imx6_sysinfo_4x128Mb_1066MHz = {
+ .dsize = 2, /* 64 bit wide = 4 devices, 16 bit each */
+ .cs_density = 8, /* four 2 GBit devices connected */
+ .ncs = 1, /* one CS line for all devices */
+ .cs1_mirror = 1, /* TODO */
+ .bi_on = 1, /* TODO */
+ .rtt_nom = 1, /* MX6_MMDC_P0_MPODTCTRL -> 0x00022227 */
+ .rtt_wr = 0, /* is LW_EN is 0 in their code */
+ .ralat = 5, /* TODO */
+ .walat = 1, /* TODO */
+ .mif3_mode = 3, /* TODO */
+ .rst_to_cke = 0x23, /* used in their code as well */
+ .sde_to_rst = 0x10, /* used in their code as well */
+ .pd_fast_exit = 0, /* TODO */
+};
+
+/* calibration info for the "max performance" and "high performance" */
+static const struct mx6_mmdc_calibration skov_imx6_calib_4x128Mb_1066MHz = {
+ .p0_mpwldectrl0 = 0x0011000E,
+ .p0_mpwldectrl1 = 0x000E001B,
+ .p0_mpdgctrl0 = 0x42720306,
+ .p0_mpdgctrl1 = 0x026F0266,
+ .p0_mprddlctl = 0x45393B3E,
+ .p0_mpwrdlctl = 0x40434541,
+
+ .p1_mpwldectrl0 = 0x00190015,
+ .p1_mpwldectrl1 = 0x00070018,
+ .p1_mpdgctrl0 = 0x4273030A,
+ .p1_mpdgctrl1 = 0x02740240,
+ .p1_mprddlctl = 0x403A3747,
+ .p1_mpwrdlctl = 0x473E4A3B,
+};
+
+/* ------------------------------------------------------------------------ */
+
+static struct mx6dq_iomux_ddr_regs ddr_iomux_q = {
+ .dram_sdqs0 = 0x00000030,
+ .dram_sdqs1 = 0x00000030,
+ .dram_sdqs2 = 0x00000030,
+ .dram_sdqs3 = 0x00000030,
+ .dram_sdqs4 = 0x00000030,
+ .dram_sdqs5 = 0x00000030,
+ .dram_sdqs6 = 0x00000030,
+ .dram_sdqs7 = 0x00000030,
+ .dram_dqm0 = 0x00020030,
+ .dram_dqm1 = 0x00020030,
+ .dram_dqm2 = 0x00020030,
+ .dram_dqm3 = 0x00020030,
+ .dram_dqm4 = 0x00020030,
+ .dram_dqm5 = 0x00020030,
+ .dram_dqm6 = 0x00020030,
+ .dram_dqm7 = 0x00020030,
+ .dram_cas = 0x00020030,
+ .dram_ras = 0x00020030,
+ .dram_sdclk_0 = 0x00020030,
+ .dram_sdclk_1 = 0x00020030,
+ .dram_sdcke0 = 0x00003000,
+ .dram_sdcke1 = 0x00003000,
+ .dram_reset = 0x00020030,
+ .dram_sdba2 = 0x00000000,
+ .dram_sdodt0 = 0x00003030,
+ .dram_sdodt1 = 0x00003030,
+};
+
+static struct mx6dq_iomux_grp_regs grp_iomux_q = {
+ .grp_b0ds = 0x00000030,
+ .grp_b1ds = 0x00000030,
+ .grp_b2ds = 0x00000030,
+ .grp_b3ds = 0x00000030,
+ .grp_b4ds = 0x00000030,
+ .grp_b5ds = 0x00000030,
+ .grp_b6ds = 0x00000030,
+ .grp_b7ds = 0x00000030,
+ .grp_addds = 0x00000030,
+ .grp_ddrmode_ctl = 0x00020000,
+ .grp_ddrpke = 0x00000000,
+ .grp_ddrmode = 0x00020000,
+ .grp_ctlds = 0x00000030,
+ .grp_ddr_type = 0x000C0000,
+};
+
+static void spl_imx6q_dram_init(const struct mx6_ddr_sysinfo *si,
+ const struct mx6_mmdc_calibration *cb,
+ const struct mx6_ddr3_cfg *cfg)
+{
+ mx6dq_dram_iocfg(64, &ddr_iomux_q, &grp_iomux_q);
+ mx6_dram_cfg(si, cb, cfg);
+ __udelay(100);
+}
+
+/* ------------------------------------------------------------------------ */
+/*
+ * Device Information: Varies per DDR3 part number and speed grade
+ * Note: this SDRAM type is used on the "Low Cost" variant
+ *
+ * Micron MT41K128M16JT-125 IT:K -> 2 GBit = 16 Meg x 16 x 8 banks
+ *
+ * Speed Grade Data Rate (MT/s) tRCD-tRP-CL tRCD(ns) tRP(ns) CL(ns)
+ * -125 ¹² 1600 11-11-11 13.75 13.75 13.75
+ * (=800 MHz)
+ *
+ * ¹ Backward compatible to 1066 (=533 MHz), CL = 7
+ * ² Backward compatible to 1333 (=667 MHz), CL = 9
+ *
+ * Memory configuration used by variant
+ * - "Low Cost", 32 bit data bus, 800 MHz, 512 MiB memory
+ */
+static const struct mx6_ddr3_cfg skov_imx6_cfg_2x128Mb_800MHz = {
+ .mem_speed = 800,
+ .density = 2, /* GiBit */
+ .width = 16, /* 16 bit data per device */
+ .banks = 8,
+ .rowaddr = 14, /* 16 k */
+ .coladdr = 10, /* 1 k */
+ .pagesz = 2, /* [kiB] */
+ .trcd = 1375, /* 13.75 ns = 11 clocks @ 1.6 GHz */
+ .trcmin = 4875, /* 48.75 ns = 39 clocks @ 1.6 GHz */
+ .trasmin = 3500, /* 35 ns = 28 clocks @ 1.6 GHz */
+ .SRT = 0,
+};
+
+static const struct mx6_ddr_sysinfo skov_imx6_sysinfo_2x128Mb_800MHz = {
+ .dsize = 1, /* 32 bit wide = 2 devices, 16 bit each */
+ .cs_density = 4, /* two 2 GBit devices connected */
+ .ncs = 1, /* one CS line for all devices */
+ .cs1_mirror = 1, /* TODO */
+ .bi_on = 1, /* TODO */
+ .rtt_nom = 1, /* MX6_MMDC_P0_MPODTCTRL -> 0x00022227 */
+ .rtt_wr = 0, /* is LW_EN is 0 in their code */
+ .ralat = 5, /* TODO */
+ .walat = 1, /* TODO */
+ .mif3_mode = 3, /* TODO */
+ .rst_to_cke = 0x23, /* used in their code as well */
+ .sde_to_rst = 0x10, /* used in their code as well */
+ .pd_fast_exit = 0, /* TODO */
+};
+
+static const struct mx6_mmdc_calibration skov_imx6_calib_2x128Mb_800MHz = {
+ .p0_mpwldectrl0 = 0x0040003C,
+ .p0_mpwldectrl1 = 0x0032003E,
+ .p0_mpdgctrl0 = 0x42350231,
+ .p0_mpdgctrl1 = 0x021A0218,
+ .p0_mprddlctl = 0x4B4B4E49,
+ .p0_mpwrdlctl = 0x3F3F3035,
+};
+
+/* ------------------------------------------------------------------------ */
+
+static const struct mx6sdl_iomux_ddr_regs ddr_iomux_s = {
+ .dram_sdqs0 = 0x00000030,
+ .dram_sdqs1 = 0x00000030,
+ .dram_sdqs2 = 0x00000030,
+ .dram_sdqs3 = 0x00000030,
+ .dram_sdqs4 = 0x00000030,
+ .dram_sdqs5 = 0x00000030,
+ .dram_sdqs6 = 0x00000030,
+ .dram_sdqs7 = 0x00000030,
+ .dram_dqm0 = 0x00020030,
+ .dram_dqm1 = 0x00020030,
+ .dram_dqm2 = 0x00020030,
+ .dram_dqm3 = 0x00020030,
+ .dram_dqm4 = 0x00020030,
+ .dram_dqm5 = 0x00020030,
+ .dram_dqm6 = 0x00020030,
+ .dram_dqm7 = 0x00020030,
+ .dram_cas = 0x00020030,
+ .dram_ras = 0x00020030,
+ .dram_sdclk_0 = 0x00020030,
+ .dram_sdclk_1 = 0x00020030,
+ .dram_sdcke0 = 0x00003000,
+ .dram_sdcke1 = 0x00003000,
+ .dram_reset = 0x00020030,
+ .dram_sdba2 = 0x00000000,
+ .dram_sdodt0 = 0x00003030,
+ .dram_sdodt1 = 0x00003030,
+};
+
+static const struct mx6sdl_iomux_grp_regs grp_iomux_s = { /* TODO */
+ .grp_b0ds = 0x00000030,
+ .grp_b1ds = 0x00000030,
+ .grp_b2ds = 0x00000030,
+ .grp_b3ds = 0x00000030,
+ .grp_b4ds = 0x00000030,
+ .grp_b5ds = 0x00000030,
+ .grp_b6ds = 0x00000030,
+ .grp_b7ds = 0x00000030,
+ .grp_addds = 0x00000030,
+ .grp_ddrmode_ctl = 0x00020000,
+ .grp_ddrpke = 0x00000000,
+ .grp_ddrmode = 0x00020000,
+ .grp_ctlds = 0x00000030,
+ .grp_ddr_type = 0x000C0000,
+};
+
+static void spl_imx6sdl_dram_init(const struct mx6_ddr_sysinfo *si,
+ const struct mx6_mmdc_calibration *cb,
+ const struct mx6_ddr3_cfg *cfg)
+{
+ mx6sdl_dram_iocfg(64, &ddr_iomux_s, &grp_iomux_s);
+ mx6_dram_cfg(si, cb, cfg);
+ __udelay(100);
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define BKLGT_PWR_PAD_CTRL MX6_PAD_CTL_SPEED_LOW | MX6_PAD_CTL_DSE_80ohm | MX6_PAD_CTL_SRE_SLOW
+
+static inline void init_backlight_gpios(int cpu_type, unsigned board_variant)
+{
+ void __iomem *iomuxbase = IOMEM(MX6_IOMUXC_BASE_ADDR);
+ void __iomem *gpio6base = IOMEM(MX6_GPIO6_BASE_ADDR);
+ void __iomem *gpio1base = IOMEM(MX6_GPIO1_BASE_ADDR);
+
+ /*
+ * since revision B a backlight switch is present which can help to
+ * prevent any kind of flicker when switching on the board. Use it.
+ * GPIO6/23 controls the backlight. High switches off the backlight.
+ */
+ switch (board_variant) {
+ case 0 ... 8:
+ break;
+ default:
+ imx6_gpio_direction_output(gpio6base, 23, 1);
+
+ switch (cpu_type) {
+ case IMX6_CPUTYPE_IMX6S:
+ case IMX6_CPUTYPE_IMX6DL:
+ writel(IOMUX_CONFIG_SION | 0x05, iomuxbase + 0x2D0);
+ writel(BKLGT_PWR_PAD_CTRL, iomuxbase + 0x6B8);
+ break;
+ case IMX6_CPUTYPE_IMX6D:
+ case IMX6_CPUTYPE_IMX6Q:
+ writel(IOMUX_CONFIG_SION | 0x05, iomuxbase + 0x068);
+ writel(BKLGT_PWR_PAD_CTRL, iomuxbase + 0x37C);
+ break;
+ }
+ }
+
+ /*
+ * switch brightness to the lowest available value. This is what we
+ * can do for revision A boards
+ * GPIO1/1 controls (via PWM) the brightness. A static low means
+ * a very dark backlight
+ */
+ imx6_gpio_direction_output(gpio1base, 1, 0);
+
+ switch (cpu_type) {
+ case IMX6_CPUTYPE_IMX6S:
+ case IMX6_CPUTYPE_IMX6DL:
+ writel(IOMUX_CONFIG_SION | 0x05, iomuxbase + 0x210);
+ writel(BKLGT_PWR_PAD_CTRL, iomuxbase + 0x5E0);
+ break;
+ case IMX6_CPUTYPE_IMX6D:
+ case IMX6_CPUTYPE_IMX6Q:
+ writel(IOMUX_CONFIG_SION | 0x05, iomuxbase + 0x224);
+ writel(BKLGT_PWR_PAD_CTRL, iomuxbase + 0x5F4);
+ break;
+ }
+}
+
+#define LED_PAD_CTRL MX6_PAD_CTL_SPEED_LOW | MX6_PAD_CTL_DSE_240ohm | MX6_PAD_CTL_SRE_SLOW
+
+static inline void setup_leds(int cpu_type)
+{
+ void __iomem *iomuxbase = IOMEM(MX6_IOMUXC_BASE_ADDR);
+ void __iomem *gpiobase = IOMEM(MX6_GPIO1_BASE_ADDR);
+
+ switch (cpu_type) {
+ case IMX6_CPUTYPE_IMX6S:
+ case IMX6_CPUTYPE_IMX6DL:
+ writel(0x05, iomuxbase + 0x20C); /* LED1 (GPIO0) */
+ writel(LED_PAD_CTRL, iomuxbase + 0x5DC);
+ writel(0x05, iomuxbase + 0x224); /* LED2 (GPIO2) */
+ writel(LED_PAD_CTRL, iomuxbase + 0x5F4);
+ writel(0x05, iomuxbase + 0x22C); /* LED3 (GPIO4) */
+ writel(LED_PAD_CTRL, iomuxbase + 0x5FC);
+ break;
+ case IMX6_CPUTYPE_IMX6D:
+ case IMX6_CPUTYPE_IMX6Q:
+ writel(0x05, iomuxbase + 0x220); /* LED1 (GPIO0) */
+ writel(LED_PAD_CTRL, iomuxbase + 0x5f0);
+ writel(0x05, iomuxbase + 0x234); /* LED2 (GPIO2) */
+ writel(LED_PAD_CTRL, iomuxbase + 0x604);
+ writel(0x05, iomuxbase + 0x238); /* LED3 (GPIO4) */
+ writel(LED_PAD_CTRL, iomuxbase + 0x608);
+ break;
+ }
+
+ /* Turn off all LEDS */
+ imx6_gpio_direction_output(gpiobase, 1, 0);
+ imx6_gpio_direction_output(gpiobase, 4, 0);
+ imx6_gpio_direction_output(gpiobase, 16, 0);
+}
+
+static inline void setup_uart(int cpu_type)
+{
+ void __iomem *iomuxbase = IOMEM(MX6_IOMUXC_BASE_ADDR);
+
+ /* UART TxD output is pin EIM/D26, e.g. UART is in DTE mode */
+ switch (cpu_type) {
+ case IMX6_CPUTYPE_IMX6S:
+ case IMX6_CPUTYPE_IMX6DL:
+ writel(0x0, iomuxbase + 0x904); /* IOMUXC_UART2_UART_RX_DATA_SELECT_INPUT */
+ writel(0x4, iomuxbase + 0x16c); /* IOMUXC_SW_MUX_CTL_PAD_EIM_DATA26 */
+ break;
+ case IMX6_CPUTYPE_IMX6D:
+ case IMX6_CPUTYPE_IMX6Q:
+ writel(0x0, iomuxbase + 0x928); /* IOMUXC_UART2_UART_RX_DATA_SELECT_INPUT */
+ writel(0x4, iomuxbase + 0x0bc); /* IOMUXC_SW_MUX_CTL_PAD_EIM_DATA26 */
+ break;
+ }
+
+ imx6_ungate_all_peripherals();
+ imx6_uart_setup(IOMEM(MX6_UART2_BASE_ADDR));
+ pbl_set_putc(imx_uart_putc, IOMEM(MX6_UART2_BASE_ADDR));
+
+ pr_debug("\n");
+}
+
+/*
+ * Hardware marked board revisions and deployments
+ *
+ * count board ram flash CPU
+ * rev.
+ * 00000000 A 1024 MiB 1024 MiB i.MX6Q
+ * 00000001 A 512 MiB 256 MiB i.MX6S
+ * 00000010 A 1024 MiB 512 MiB i.MX6Q
+ * 00000011 ---- not defined ----
+ * 00000100 A 512 MiB 256 MiB i.MX6S
+ * 00000101 ---- not defined ----
+ * 00000110 ---- not defined ----
+ * 00000111 ---- not defined ----
+ * 00001000 A 1024 MiB 512 MiB i.MX6Q
+ * 00001001 B 256 MiB 16 MiB i.MX6S
+ * 00001010 B 256 MiB 256 MiB i.MX6S
+ * 00001011 B 1024 MiB 256 MiB i.MX6Q
+ * 00001100 B 2048 MiB 8 GiB i.MX6Q
+ * 00001101 C 256 MiB 256 MiB i.MX6S
+ * 00001110 C 1024 MiB 256 MiB i.MX6Q
+ * 00001111 C 512 MiB 256 MiB i.MX6S
+ * 00010000 C 512 MiB 4 GiB i.MX6S
+ * 00010001 C 2048 MiB 8 GiB i.MX6Q
+ * 00010010 C 4096 MiB 16 GiB i.MX6Q+
+ * 00010011 C 512 MiB 2 GiB i.MX6S
+ * 00010100 C 1024 MiB 4 GiB i.MX6Q
+ * 00010101 D 512 MiB 2 GIB i.MX6S
+ * 00010110 D 1024 MiB 4 GIB i.MX6Q
+ * 00010111 ---- not defined ----
+ * 00011000 E 1024 MiB 4 GIB i.MX6Q
+ *
+ * This routine does not return if starting the image from SD card or NOR
+ * was successful. It restarts skov_imx6_start() instead
+ */
+static void skov_imx6_init(int cpu_type, unsigned board_variant)
+{
+ enum bootsource bootsrc;
+ int instance;
+
+ switch (board_variant) {
+ case 12: /* P2 i.MX6Q, max performance */
+ if (cpu_type != IMX6_CPUTYPE_IMX6Q) {
+ pr_err("Invalid SoC! i.MX6Q expected\n");
+ return;
+ }
+ pr_debug("Initializing a P2 max performance system...\n");
+ spl_imx6q_dram_init(&skov_imx6_sysinfo_4x256Mb_1066MHz,
+ &skov_imx6_calib_4x256Mb_1066MHz,
+ &skov_imx6_cfg_4x256Mb_1066MHz);
+ break;
+ case 18: /* i.MX6Q+ */
+ if (cpu_type != IMX6_CPUTYPE_IMX6Q) {
+ pr_err("Invalid SoC! i.MX6Q expected\n");
+ return;
+ }
+ pr_debug("Initializing board variant 18\n");
+ spl_imx6q_dram_init(&skov_imx6_sysinfo_4x512Mb_1066MHz,
+ &skov_imx6_calib_4x512Mb_1066MHz,
+ &skov_imx6_cfg_4x512Mb_1066MHz);
+ break;
+ case 19: /* i.MX6S "Solo_R512M_F2G" */
+ if (cpu_type != IMX6_CPUTYPE_IMX6S) {
+ pr_err("Invalid SoC! i.MX6S expected\n");
+ return;
+ }
+ pr_debug("Initializing board variant 19\n");
+ spl_imx6sdl_dram_init(&skov_imx6_sysinfo_2x128Mb_800MHz,
+ &skov_imx6_calib_2x128Mb_800MHz,
+ &skov_imx6_cfg_2x128Mb_800MHz);
+ break;
+ case 20: /* i.MX6Q, "Quad_R1G_F2G" */
+ if (cpu_type != IMX6_CPUTYPE_IMX6Q) {
+ pr_err("Invalid SoC! i.MX6Q expected\n");
+ return;
+ }
+ pr_debug("Initializing board variant 20\n");
+ spl_imx6q_dram_init(&skov_imx6_sysinfo_4x128Mb_1066MHz,
+ &skov_imx6_calib_4x128Mb_1066MHz,
+ &skov_imx6_cfg_4x128Mb_1066MHz);
+ break;
+ case 21: /* i.MX6S "Solo_R512M_F2G" */
+ if (cpu_type != IMX6_CPUTYPE_IMX6S) {
+ pr_err("Invalid SoC! i.MX6S expected\n");
+ return;
+ }
+ pr_debug("Initializing board variant 21\n");
+ spl_imx6sdl_dram_init(&skov_imx6_sysinfo_2x128Mb_800MHz,
+ &skov_imx6_calib_2x128Mb_800MHz,
+ &skov_imx6_cfg_2x128Mb_800MHz);
+ break;
+ case 22: /* i.MX6Q, "Quad_R1G_F4G" */
+ if (cpu_type != IMX6_CPUTYPE_IMX6Q) {
+ pr_err("Invalid SoC! i.MX6Q expected\n");
+ return;
+ }
+ pr_debug("Initializing board variant 22\n");
+ spl_imx6q_dram_init(&skov_imx6_sysinfo_4x128Mb_1066MHz,
+ &skov_imx6_calib_4x128Mb_1066MHz,
+ &skov_imx6_cfg_4x128Mb_1066MHz);
+ break;
+ case 24: /* i.MX6Q, "Quad_R1G_F4G" */
+ if (cpu_type != IMX6_CPUTYPE_IMX6Q) {
+ pr_err("Invalid SoC! i.MX6Q expected\n");
+ return;
+ }
+ pr_debug("Initializing board variant 24\n");
+ spl_imx6q_dram_init(&skov_imx6_sysinfo_4x128Mb_1066MHz,
+ &skov_imx6_calib_4x128Mb_1066MHz,
+ &skov_imx6_cfg_4x128Mb_1066MHz);
+ break;
+ default:
+ pr_err("Unsupported board variant: 0x%x\n", board_variant);
+ /* don't continue */
+ while(1);
+ break;
+ }
+
+ imx6_get_boot_source(&bootsrc, &instance);
+ if (bootsrc == BOOTSOURCE_SPI_NOR) {
+ pr_info("Loading bootloader image from SPI flash...");
+ imx6_spi_start_image(0);
+ } else {
+ pr_info("Loading bootloader image from SD card...");
+ imx6_esdhc_start_image(instance);
+ }
+}
+
+extern char __dtb_z_imx6q_skov_imx6_start[];
+extern char __dtb_z_imx6dl_skov_imx6_start[];
+
+/* called twice: once for SDRAM setup only, second for devicetree setup */
+static noinline void skov_imx6_start(void)
+{
+ int cpu_type = __imx6_cpu_type();
+ unsigned board_variant = skov_imx6_get_version();
+
+ setup_uart(cpu_type);
+
+ if (get_pc() <= MX6_MMDC_PORT01_BASE_ADDR) {
+ /* first call: do the lowlevel things first */
+ init_backlight_gpios(cpu_type, board_variant);
+ setup_leds(cpu_type);
+ pr_info("Starting to init IMX6 system...\n");
+ skov_imx6_init(cpu_type, board_variant);
+ pr_err("Unable to start bootloader\n");
+ while (1);
+ }
+
+ /* boot this platform (second call) */
+ switch (cpu_type) {
+ case IMX6_CPUTYPE_IMX6S:
+ case IMX6_CPUTYPE_IMX6DL:
+ pr_debug("Startup i.MX6S/DL based system...\n");
+ imx6q_barebox_entry(__dtb_z_imx6dl_skov_imx6_start);
+ break;
+ case IMX6_CPUTYPE_IMX6D:
+ case IMX6_CPUTYPE_IMX6Q:
+ pr_debug("Startup i.MX6Q based system...\n");
+ imx6q_barebox_entry(__dtb_z_imx6q_skov_imx6_start);
+ break;
+ }
+}
+
+ENTRY_FUNCTION(start_imx6_skov_imx6, r0, r1, r2)
+{
+ arm_cpu_lowlevel_init();
+
+ relocate_to_current_adr();
+ setup_c();
+ barrier();
+
+ skov_imx6_start();
+}
diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig
index 16e109464b..624698ae3c 100644
--- a/arch/arm/configs/imx_v7_defconfig
+++ b/arch/arm/configs/imx_v7_defconfig
@@ -13,6 +13,7 @@ CONFIG_MACH_FREESCALE_MX53_VMX53=y
CONFIG_MACH_TX53=y
CONFIG_MACH_PHYTEC_SOM_IMX6=y
CONFIG_MACH_PROTONIC_IMX6=y
+CONFIG_MACH_KAMSTRUP_MX7_CONCENTRATOR=y
CONFIG_MACH_KONTRON_SAMX6I=y
CONFIG_MACH_DFI_FS700_M60=y
CONFIG_MACH_GUF_SANTARO=y
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index d5f61768a5..c032f0391f 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -30,6 +30,7 @@ lwl-$(CONFIG_MACH_GRINN_LITEBOARD) += imx6ul-liteboard.dtb.o
lwl-$(CONFIG_MACH_GUF_SANTARO) += imx6q-guf-santaro.dtb.o
lwl-$(CONFIG_MACH_GUF_VINCELL) += imx53-guf-vincell.dtb.o imx53-guf-vincell-lt.dtb.o
lwl-$(CONFIG_MACH_GW_VENTANA) += imx6q-gw54xx.dtb.o
+lwl-$(CONFIG_MACH_KAMSTRUP_MX7_CONCENTRATOR) += imx7d-flex-concentrator-mfg.dtb.o
lwl-$(CONFIG_MACH_KONTRON_SAMX6I) += imx6q-samx6i.dtb.o \
imx6dl-samx6i.dtb.o
lwl-$(CONFIG_MACH_LENOVO_IX4_300D) += armada-xp-lenovo-ix4-300d-bb.dtb.o
@@ -110,6 +111,7 @@ lwl-$(CONFIG_MACH_SOLIDRUN_CUBOX) += dove-cubox-bb.dtb.o
lwl-$(CONFIG_MACH_SOLIDRUN_MICROSOM) += imx6dl-hummingboard.dtb.o imx6q-hummingboard.dtb.o \
imx6dl-hummingboard2.dtb.o imx6q-hummingboard2.dtb.o \
imx6q-h100.dtb.o
+lwl-$(CONFIG_MACH_SKOV_IMX6) += imx6dl-skov-imx6.dtb.o imx6q-skov-imx6.dtb.o
lwl-$(CONFIG_MACH_SEEED_ODYSSEY) += stm32mp157c-odyssey.dtb.o
lwl-$(CONFIG_MACH_STM32MP15XX_DKX) += stm32mp157c-dk2.dtb.o stm32mp157a-dk1.dtb.o
lwl-$(CONFIG_MACH_LXA_MC1) += stm32mp157c-lxa-mc1.dtb.o
diff --git a/arch/arm/dts/imx6dl-skov-imx6.dts b/arch/arm/dts/imx6dl-skov-imx6.dts
new file mode 100644
index 0000000000..c2dac68204
--- /dev/null
+++ b/arch/arm/dts/imx6dl-skov-imx6.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Juergen Borleis, Pengutronix <kernel@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include <arm/imx6dl.dtsi>
+#include "imx6dl.dtsi"
+#include "imx6qdl-skov-imx6.dtsi"
+
+/ {
+ model = "Skov IMX6";
+ compatible = "skov,imx6", "fsl,imx6dl";
+
+ chosen {
+ stdout-path = &uart2;
+ };
+};
diff --git a/arch/arm/dts/imx6q-skov-imx6.dts b/arch/arm/dts/imx6q-skov-imx6.dts
new file mode 100644
index 0000000000..fea84cb498
--- /dev/null
+++ b/arch/arm/dts/imx6q-skov-imx6.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 Juergen Borleis, Pengutronix <kernel@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include <arm/imx6q.dtsi>
+#include "imx6q.dtsi"
+#include "imx6qdl-skov-imx6.dtsi"
+
+/ {
+ model = "Skov IMX6";
+ compatible = "skov,imx6", "fsl,imx6q";
+
+ chosen {
+ stdout-path = &uart2;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+};
diff --git a/arch/arm/dts/imx6qdl-skov-imx6.dtsi b/arch/arm/dts/imx6qdl-skov-imx6.dtsi
new file mode 100644
index 0000000000..03f3cb02fc
--- /dev/null
+++ b/arch/arm/dts/imx6qdl-skov-imx6.dtsi
@@ -0,0 +1,546 @@
+/*
+ * Copyright 2015 Juergen Borleis, Pengutronix <kernel@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ aliases {
+ state = &state;
+ };
+
+ chosen {
+ environment-sd {
+ compatible = "barebox,environment";
+ device-path = &usdhc3, "partname:2";
+ status = "disabled";
+ };
+
+ environment-spinor {
+ compatible = "barebox,environment";
+ device-path = &barebox_env;
+ status = "disabled";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led0: D1 {
+ label = "D1";
+ gpios = <&gpio1 2 0>;
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+
+ led1: D2 {
+ label = "D2";
+ gpios = <&gpio1 0 0>;
+ default-state = "off";
+ };
+
+ led2: D3 {
+ label = "D3";
+ gpios = <&gpio1 4 0>;
+ default-state = "on";
+ };
+ };
+
+ /* State: mutable part */
+ state: state {
+ magic = <0x34a0fc27>;
+ compatible = "barebox,state";
+ backend-type = "raw";
+ backend = <&state_storage>;
+ backend-stridesize = <0x40>;
+
+ bootstate {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ system0 { /* the node's name here must match the subnode's name in the 'bootstate' node */
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@0 {
+ reg = <0x0 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+ priority@4 {
+ reg = <0x4 0x4>;
+ type = "uint32";
+ default = <30>;
+ };
+ };
+
+ system1 { /* the node's name here must match the subnode's name in the 'bootstate' node */
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@8 {
+ reg = <0x8 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+ priority@C {
+ reg = <0xC 0x4>;
+ type = "uint32";
+ default = <20>;
+ };
+ };
+
+ last_chosen@10 {
+ reg = <0x10 0x4>;
+ type = "uint32";
+ };
+ };
+
+ display {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ xres@14 {
+ reg = <0x14 0x4>;
+ type = "uint32";
+ default = <0>;
+ };
+
+ yres@18 {
+ reg = <0x18 0x4>;
+ type = "uint32";
+ default = <0>;
+ };
+
+ brightness@1C {
+ reg = <0x1C 0x1>;
+ type = "uint8";
+ default = <8>;
+ };
+
+ external@1D {
+ reg = <0x1D 0x1>;
+ type = "uint8";
+ default = <0>;
+ };
+ };
+
+ ethaddr {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ eth2 {
+ reg = <0x1E 0x6>;
+ type = "mac";
+ default = [00 11 22 33 44 55];
+ };
+ };
+ };
+
+ backlight_lcd: backlight_lcd {
+ compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_backlight>;
+ pwms = <&pwm2 0 20000 0>;
+ brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>;
+ default-brightness-level = <8>;
+ enable-gpios = <&gpio6 23 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ };
+
+ display {
+ status = "disabled";
+ compatible = "fsl,imx-parallel-display";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ipu1_4>;
+ interface-pix-fmt = "rgb24";
+
+ port {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+
+ display-timings {
+ native-mode = &l2rt;
+
+ l2rt: l2rt {
+ native-mode;
+ clock-frequency = <33000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <85>;
+ hfront-porch = <112>;
+ vback-porch = <29>;
+ vfront-porch = <38>;
+ hsync-len = <3>;
+ vsync-len = <3>;
+ pixelclk-active = <1>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ };
+
+ l6whrt: l6whrt {
+ native-mode;
+ clock-frequency = <33000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <43>;
+ hfront-porch = <154>;
+ vback-porch = <20>;
+ vfront-porch = <47>;
+ hsync-len = <3>;
+ vsync-len = <3>;
+ pixelclk-active = <1>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ };
+ };
+ };
+
+ panel {
+ compatible = "simple-panel";
+ backlight = <&backlight_lcd>;
+ /* power-supply = <&reg_3p3v>; */
+
+ display-timings {
+ native-mode = &mi1010ait_1cp1;
+
+ mi1010ait_1cp1: mi1010ait-1cp1 {
+ native-mode;
+ clock-frequency = <70000000>;
+ hactive = <1280>;
+ vactive = <800>;
+ hback-porch = <60>;
+ hfront-porch = <60>;
+ vback-porch = <10>;
+ vfront-porch = <10>;
+ hsync-len = <10>;
+ vsync-len = <6>;
+ /* pixelclk-active = <>; */
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ };
+ };
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+};
+
+&pwm2 {
+ /* used for backlight brightness */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2_2>;
+ status = "okay";
+};
+
+&pwm3 {
+ /* used for LCD contrast control */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3_2>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2_2>;
+};
+
+&hdmi {
+ status = "okay";
+ ddc-i2c-bus = <&i2c2>;
+};
+
+/delete-node/&ipu1_di0_hdmi;
+/delete-node/&hdmi_mux_0;
+
+&ipu1_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hog>;
+
+ pinctrl_hog: hoggrp {
+ /* we need a few pins as GPIOs */
+ fsl,pins = <
+ /* MMC IO voltage select */
+ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x40000058
+ /* MMC Power Supply Switch (since revision C)
+ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x40000058
+ /* Backlight Power Supply Switch (since revision B)
+ MX6QDL_PAD_RGMII_TD3__GPIO6_IO23 0x40000058
+ /* Backlight Brightness */
+ MX6QDL_PAD_GPIO_1__GPIO1_IO01 0x40000058
+ /* must be high */
+ MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x40000058
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x40000058 /* CS# signal */
+ >;
+ };
+
+ /* pins for eth0 */
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
+ MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN 0x100b0
+ MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x100b0
+ MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x100b0
+ MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1 0x100b0
+ MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0 0x100b0
+ MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1 0x100b0
+ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x400000c0
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1b040 /* WP */
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b040 /* CD */
+ >;
+ };
+
+ pinctrl_gpmi_nand: gpminandgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
+ MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1
+ MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000
+ MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1
+ MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1
+ MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1
+ MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1
+ MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1
+ MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1
+ MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1
+ MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1
+ MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1
+ MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1
+ MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1
+ MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1
+ >;
+ };
+
+ pinctrl_i2c2_2: i2c2grp-2 {
+ fsl,pins = <
+ /* internal 22 k pull up required */
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001F878
+ /* internal 22 k pull up required */
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001F878
+ >;
+ };
+
+ pinctrl_ipu1_4: ipu1grp-4 {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10
+ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10
+ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10
+ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10
+ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10
+ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10
+ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10
+ >;
+ };
+
+ pinctrl_backlight: backlight_grp {
+ fsl,pins = <
+ MX6QDL_PAD_RGMII_TD3__GPIO6_IO23 0x40000058
+ >;
+ };
+
+ pinctrl_pwm2_2: pwm2grp-2 {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__PWM2_OUT 0x00058
+ >;
+ };
+
+ pinctrl_pwm3_2: pwm3grp-2 {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x00058
+ >;
+ };
+};
+
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>,
+ <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>;
+};
+
+/* console */
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+/* spi */
+&ecspi1 {
+ fsl,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio3 24 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ norflash: m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <54000000>;
+ reg = <0>;
+ };
+};
+
+/* eth0 */
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rmii";
+ status = "okay";
+ phy-reset-gpios = <&gpio1 5 0>;
+ phy-reset-duration = <100>;
+ #address-cells = <0>;
+ #size-cells = <1>;
+ fixed-link {
+ speed = <100>;
+ full-duplex;
+ };
+};
+
+&ldb {
+ status = "disabled";
+
+ lvds0: lvds-channel@0 {
+ status = "disabled";
+ fsl,data-width = <24>;
+ fsl,data-mapping = "spwg";
+
+ port@4 {
+ reg = <4>;
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+};
+
+&wdog1 {
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ wp-gpios = <&gpio7 1 0>;
+ cd-gpios = <&gpio7 0 0>;
+ status = "okay";
+ fsl,delay-line;
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ nand-on-flash-bbt;
+ status = "okay";
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "firmware";
+ reg = <0x00000000 0x000000000>; /* keep zero sized to enable autodetection */
+ };
+ };
+};
+
+/* define the SPI based 8 MiB NOR flash layout */
+&norflash {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0x100000>;
+ };
+
+ /* space left to let barebox grow */
+
+ /* placed near the end of the NOR memory */
+ barebox_env: partition@780000 {
+ label = "barebox-environment";
+ reg = <0x780000 0x40000>;
+ };
+
+ /* placed at the end of the NOR memory */
+ state_storage: partition@7C0000 {
+ label = "barebox-state";
+ reg = <0x7C0000 0x40000>; /* four times mirrored */
+ };
+ };
+};
+
+&ocotp {
+ barebox,provide-mac-address = <&fec 0x620>;
+};
diff --git a/arch/arm/dts/imx7d-flex-concentrator-mfg.dts b/arch/arm/dts/imx7d-flex-concentrator-mfg.dts
new file mode 100644
index 0000000000..d174ef7250
--- /dev/null
+++ b/arch/arm/dts/imx7d-flex-concentrator-mfg.dts
@@ -0,0 +1,108 @@
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <arm/imx7d-flex-concentrator-mfg.dts>
+
+/ {
+ chosen {
+ environment {
+ compatible = "barebox,environment";
+ device-path = &environment_emmc;
+ };
+ };
+
+ aliases {
+ state = &state_emmc;
+ };
+
+ state_emmc: state {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "barebox,state";
+ magic = <0x4b414d31>;
+ backend-type = "raw";
+ backend = <&backend_state_emmc>;
+ backend-stridesize = <0x200>;
+
+ bootstate {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ system0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@0 {
+ reg = <0x0 0x4>;
+ type = "uint32";
+ default = <10>;
+ };
+
+ priority@4 {
+ reg = <0x4 0x4>;
+ type = "uint32";
+ default = <21>;
+ };
+ };
+
+ system1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@8 {
+ reg = <0x8 0x4>;
+ type = "uint32";
+ default = <0>;
+ };
+
+ priority@c {
+ reg = <0xc 0x4>;
+ type = "uint32";
+ default = <20>;
+ };
+ };
+
+ last_chosen@10 {
+ reg = <0x10 0x4>;
+ type = "uint32";
+ };
+ };
+ };
+};
+
+/* eMMC */
+&usdhc3 {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0x100000>;
+ };
+
+ environment_emmc: partition@100000 {
+ label = "barebox-environment";
+ reg = <0x100000 0x100000>;
+ };
+
+ backend_state_emmc: partition@200000 {
+ label = "barebox-state";
+ reg = <0x200000 0x100000>;
+ };
+ };
+};
+
+/* FIXME: barebox serial is broken when barebox applies requested reparenting */
+&uart4 {
+ /delete-property/ assigned-clocks;
+ /delete-property/ assigned-clock-parents;
+};
+
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 3f8012c732..38aee42bf2 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -526,6 +526,11 @@ config MACH_FREESCALE_MX7_SABRESD
https://goo.gl/6EKGdk
+config MACH_KAMSTRUP_MX7_CONCENTRATOR
+ bool "Kamstrup i.MX7 Concentrator"
+ select ARCH_IMX7
+ select ARM_USE_COMPRESSED_DTB
+
config MACH_NXP_IMX6ULL_EVK
bool "NXP i.MX6ull EVK Board"
select ARCH_IMX6UL
@@ -592,6 +597,12 @@ config MACH_MNT_REFORM
select MCI_IMX_ESDHC_PBL
select I2C_IMX_EARLY
+config MACH_SKOV_IMX6
+ bool "Skov IMX6"
+ select ARCH_IMX6
+ select ARM_USE_COMPRESSED_DTB
+ select MCI_IMX_ESDHC_PBL
+
endif
# ----------------------------------------------------------
diff --git a/arch/arm/mach-imx/boot.c b/arch/arm/mach-imx/boot.c
index c3cf4b85ff..e9b5a49443 100644
--- a/arch/arm/mach-imx/boot.c
+++ b/arch/arm/mach-imx/boot.c
@@ -506,6 +506,9 @@ static void __imx7_get_boot_source(enum bootsource *src, int *instance,
case 5:
*src = BOOTSOURCE_NOR;
break;
+ case 15:
+ *src = BOOTSOURCE_SERIAL;
+ break;
default:
break;
}
diff --git a/arch/arm/mach-imx/include/mach/imx-gpio.h b/arch/arm/mach-imx/include/mach/imx-gpio.h
index 0cfd16f4fa..64ac278d61 100644
--- a/arch/arm/mach-imx/include/mach/imx-gpio.h
+++ b/arch/arm/mach-imx/include/mach/imx-gpio.h
@@ -32,7 +32,7 @@ static inline void imx_gpio_direction(void __iomem *gdir, void __iomem *dr,
writel(val, dr);
}
-static inline void imx1_gpio_direction_output(void *base, int gpio, int value)
+static inline void imx1_gpio_direction_output(void __iomem *base, int gpio, int value)
{
imx_gpio_direction(base + 0x0, base + 0x1c, gpio, 1, value);
}
@@ -40,7 +40,7 @@ static inline void imx1_gpio_direction_output(void *base, int gpio, int value)
#define imx21_gpio_direction_output(base, gpio, value) imx1_gpio_direction_output(base, gpio,value)
#define imx27_gpio_direction_output(base, gpio, value) imx1_gpio_direction_output(base, gpio,value)
-static inline void imx31_gpio_direction_output(void *base, int gpio, int value)
+static inline void imx31_gpio_direction_output(void __iomem *base, int gpio, int value)
{
imx_gpio_direction(base + 0x4, base + 0x0, gpio, 1, value);
}
@@ -52,7 +52,7 @@ static inline void imx31_gpio_direction_output(void *base, int gpio, int value)
#define imx6_gpio_direction_output(base, gpio, value) imx31_gpio_direction_output(base, gpio,value)
#define imx8m_gpio_direction_output(base, gpio, value) imx31_gpio_direction_output(base, gpio,value)
-static inline void imx1_gpio_direction_input(void *base, int gpio, int value)
+static inline void imx1_gpio_direction_input(void __iomem *base, int gpio, int value)
{
imx_gpio_direction(base + 0x0, base + 0x1c, gpio, 0, 0);
}
@@ -60,7 +60,7 @@ static inline void imx1_gpio_direction_input(void *base, int gpio, int value)
#define imx21_gpio_direction_input(base, gpio, value) imx1_gpio_direction_input(base, gpio)
#define imx27_gpio_direction_input(base, gpio, value) imx1_gpio_direction_input(base, gpio)
-static inline void imx31_gpio_direction_input(void *base, int gpio)
+static inline void imx31_gpio_direction_input(void __iomem *base, int gpio)
{
imx_gpio_direction(base + 0x4, base + 0x0, gpio, 0, 0);
}
@@ -72,11 +72,18 @@ static inline void imx31_gpio_direction_input(void *base, int gpio)
#define imx6_gpio_direction_input(base, gpio) imx31_gpio_direction_input(base, gpio)
#define imx8m_gpio_direction_input(base, gpio) imx31_gpio_direction_input(base, gpio)
-#define imx1_gpio_val(base, gpio) readl(base + 0x1c) & (1 << gpio) ? 1 : 0
+static inline int imx1_gpio_val(void __iomem *base, int gpio)
+{
+ return readl(base + 0x1c) & (1 << gpio) ? 1 : 0;
+}
+
+static inline int imx31_gpio_val(void __iomem *base, int gpio)
+{
+ return readl(base) & (1 << gpio) ? 1 : 0;
+}
+
#define imx21_gpio_val(base, gpio) imx1_gpio_val(base, gpio)
#define imx27_gpio_val(base, gpio) imx1_gpio_val(base, gpio)
-
-#define imx31_gpio_val(base, gpio) readl(base) & (1 << gpio) ? 1 : 0
#define imx25_gpio_val(base, gpio) imx31_gpio_val(base, gpio)
#define imx35_gpio_val(base, gpio) imx31_gpio_val(base, gpio)
#define imx51_gpio_val(base, gpio) imx31_gpio_val(base, gpio)