diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2021-04-15 14:01:50 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-04-15 14:01:50 +0200 |
commit | e61c75c259af8601a671e14237b464e0d49fd0df (patch) | |
tree | 3d827b3500fc00dbe8f5ec164c0aee6aabe99519 /arch | |
parent | a9450309bb51ff3d7159db85b6b40be20eaba962 (diff) | |
parent | 4539ad7832f761f5af579d1f53f82ee9845615bc (diff) | |
download | barebox-e61c75c259af8601a671e14237b464e0d49fd0df.tar.gz barebox-e61c75c259af8601a671e14237b464e0d49fd0df.tar.xz |
Merge branch 'for-next/imx'
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/boards/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/boards/kamstrup-mx7-concentrator/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg | 79 | ||||
-rw-r--r-- | arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c | 35 | ||||
-rw-r--r-- | arch/arm/boards/skov-imx6/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/boards/skov-imx6/board.c | 528 | ||||
-rw-r--r-- | arch/arm/boards/skov-imx6/env/init/automount | 14 | ||||
-rw-r--r-- | arch/arm/boards/skov-imx6/env/nv/boot.default | 1 | ||||
-rw-r--r-- | arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg | 4 | ||||
-rw-r--r-- | arch/arm/boards/skov-imx6/lowlevel.c | 664 | ||||
-rw-r--r-- | arch/arm/configs/imx_v7_defconfig | 1 | ||||
-rw-r--r-- | arch/arm/dts/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/dts/imx6dl-skov-imx6.dts | 24 | ||||
-rw-r--r-- | arch/arm/dts/imx6q-skov-imx6.dts | 28 | ||||
-rw-r--r-- | arch/arm/dts/imx6qdl-skov-imx6.dtsi | 546 | ||||
-rw-r--r-- | arch/arm/dts/imx7d-flex-concentrator-mfg.dts | 108 | ||||
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 11 | ||||
-rw-r--r-- | arch/arm/mach-imx/boot.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/imx-gpio.h | 21 |
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 = <®_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) |