diff options
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 5 | ||||
-rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/boot.c | 435 | ||||
-rw-r--r-- | arch/arm/mach-imx/esdctl.c | 144 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx.c | 52 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx51.c | 20 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx53.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx6.c | 104 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx7.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/esdctl.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/generic.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/imx6-regs.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/imx6.h | 88 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/reset-reason.h | 37 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/vf610-ddrmc.h | 18 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/vf610-regs.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/vf610.h | 51 | ||||
-rw-r--r-- | arch/arm/mach-imx/vf610.c | 59 | ||||
-rw-r--r-- | arch/arm/mach-imx/xload.c | 2 |
19 files changed, 794 insertions, 259 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 9052a94ea0..e6956acbdb 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -393,6 +393,11 @@ config MACH_CM_FX6 bool "CM FX6" select ARCH_IMX6 +config MACH_ADVANTECH_ROM_742X + bool "Advantech ROM 742X" + select ARCH_IMX6 + select ARM_USE_COMPRESSED_DTB + config MACH_WARP7 bool "NXP i.MX7: element 14 WaRP7 Board" select ARCH_IMX7 diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 8ec846ccef..160ed4b084 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o CFLAGS_imx6.o := -march=armv7-a lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o obj-$(CONFIG_ARCH_IMX7) += imx7.o +obj-$(CONFIG_ARCH_VF610) += vf610.o obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o obj-$(CONFIG_IMX_IIM) += iim.o obj-$(CONFIG_IMX_OCOTP) += ocotp.o diff --git a/arch/arm/mach-imx/boot.c b/arch/arm/mach-imx/boot.c index 72597f5e2d..22cf08e6ad 100644 --- a/arch/arm/mach-imx/boot.c +++ b/arch/arm/mach-imx/boot.c @@ -15,6 +15,7 @@ #include <bootsource.h> #include <environment.h> #include <init.h> +#include <linux/bitfield.h> #include <magicvar.h> #include <io.h> @@ -26,6 +27,21 @@ #include <mach/imx53-regs.h> #include <mach/imx6-regs.h> #include <mach/imx7-regs.h> +#include <mach/vf610-regs.h> + + +static void +imx_boot_save_loc(void (*get_boot_source)(enum bootsource *, int *)) +{ + enum bootsource src = BOOTSOURCE_UNKNOWN; + int instance = BOOTSOURCE_INSTANCE_UNKNOWN; + + get_boot_source(&src, &instance); + + bootsource_set(src); + bootsource_set_instance(instance); +} + /* [CTRL][TYPE] */ static const enum bootsource locations[4][4] = { @@ -91,13 +107,7 @@ void imx25_get_boot_source(enum bootsource *src, int *instance) void imx25_boot_save_loc(void) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; - - imx25_get_boot_source(&src, &instance); - - bootsource_set(src); - bootsource_set_instance(instance); + imx_boot_save_loc(imx25_get_boot_source); } void imx35_get_boot_source(enum bootsource *src, int *instance) @@ -112,13 +122,7 @@ void imx35_get_boot_source(enum bootsource *src, int *instance) void imx35_boot_save_loc(void) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; - - imx35_get_boot_source(&src, &instance); - - bootsource_set(src); - bootsource_set_instance(instance); + imx_boot_save_loc(imx35_get_boot_source); } #define IMX27_SYSCTRL_GPCR 0x18 @@ -159,13 +163,7 @@ void imx27_get_boot_source(enum bootsource *src, int *instance) void imx27_boot_save_loc(void) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; - - imx27_get_boot_source(&src, &instance); - - bootsource_set(src); - bootsource_set_instance(instance); + imx_boot_save_loc(imx27_get_boot_source); } #define IMX51_SRC_SBMR 0x4 @@ -203,36 +201,82 @@ void imx51_get_boot_source(enum bootsource *src, int *instance) void imx51_boot_save_loc(void) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; + imx_boot_save_loc(imx51_get_boot_source); +} - imx51_get_boot_source(&src, &instance); +#define IMX53_SRC_SBMR 0x4 +#define SRC_SBMR_BMOD GENMASK(25, 24) +#define IMX53_BMOD_SERIAL 0b11 + +#define __BOOT_CFG(n, m, l) GENMASK((m) + ((n) - 1) * 8, \ + (l) + ((n) - 1) * 8) +#define BOOT_CFG1(m, l) __BOOT_CFG(1, m, l) +#define BOOT_CFG2(m, l) __BOOT_CFG(2, m, l) +#define BOOT_CFG3(m, l) __BOOT_CFG(3, m, l) +#define BOOT_CFG4(m, l) __BOOT_CFG(4, m, l) + +#define ___BOOT_CFG(n, i) __BOOT_CFG(n, i, i) +#define __MAKE_BOOT_CFG_BITS(idx) \ + enum { \ + BOOT_CFG##idx##_0 = ___BOOT_CFG(idx, 0), \ + BOOT_CFG##idx##_1 = ___BOOT_CFG(idx, 1), \ + BOOT_CFG##idx##_2 = ___BOOT_CFG(idx, 2), \ + BOOT_CFG##idx##_3 = ___BOOT_CFG(idx, 3), \ + BOOT_CFG##idx##_4 = ___BOOT_CFG(idx, 4), \ + BOOT_CFG##idx##_5 = ___BOOT_CFG(idx, 5), \ + BOOT_CFG##idx##_6 = ___BOOT_CFG(idx, 6), \ + BOOT_CFG##idx##_7 = ___BOOT_CFG(idx, 7), \ + }; - bootsource_set(src); - bootsource_set_instance(instance); +__MAKE_BOOT_CFG_BITS(1) +__MAKE_BOOT_CFG_BITS(2) +__MAKE_BOOT_CFG_BITS(4) +#undef __MAKE_BOOT_CFG +#undef ___BOOT_CFG + + +static unsigned int imx53_get_bmod(uint32_t r) +{ + return FIELD_GET(SRC_SBMR_BMOD, r); +} + +static int imx53_bootsource_internal(uint32_t r) +{ + return FIELD_GET(BOOT_CFG1(7, 4), r); +} + +static int imx53_port_select(uint32_t r) +{ + return FIELD_GET(BOOT_CFG3(5, 4), r); +} + +static bool imx53_bootsource_nand(uint32_t r) +{ + return FIELD_GET(BOOT_CFG1_7, r); +} + +static enum bootsource imx53_bootsource_serial_rom(uint32_t r) +{ + return BOOT_CFG1(r, 3) ? BOOTSOURCE_SPI : BOOTSOURCE_I2C; } -#define IMX53_SRC_SBMR 0x4 void imx53_get_boot_source(enum bootsource *src, int *instance) { void __iomem *src_base = IOMEM(MX53_SRC_BASE_ADDR); uint32_t cfg1 = readl(src_base + IMX53_SRC_SBMR); - if (((cfg1 >> 24) & 0x3) == 0x3) { + if (imx53_get_bmod(cfg1) == IMX53_BMOD_SERIAL) { *src = BOOTSOURCE_USB; *instance = 0; return; } - switch ((cfg1 & 0xff) >> 4) { + switch (imx53_bootsource_internal(cfg1)) { case 2: *src = BOOTSOURCE_HD; break; case 3: - if (cfg1 & (1 << 3)) - *src = BOOTSOURCE_SPI; - else - *src = BOOTSOURCE_I2C; + *src = imx53_bootsource_serial_rom(cfg1); break; case 4: case 5: @@ -241,18 +285,16 @@ void imx53_get_boot_source(enum bootsource *src, int *instance) *src = BOOTSOURCE_MMC; break; default: + if (imx53_bootsource_nand(cfg1)) + *src = BOOTSOURCE_NAND; break; } - if (cfg1 & (1 << 7)) - *src = BOOTSOURCE_NAND; - - switch (*src) { case BOOTSOURCE_MMC: case BOOTSOURCE_SPI: case BOOTSOURCE_I2C: - *instance = (cfg1 >> 20) & 0x3; + *instance = imx53_port_select(cfg1); break; default: *instance = 0; @@ -273,123 +315,206 @@ void imx53_boot_save_loc(void) #define IMX6_SRC_SBMR1 0x04 #define IMX6_SRC_SBMR2 0x1c +#define IMX6_BMOD_SERIAL 0b01 +#define IMX6_BMOD_RESERVED 0b11 +#define IMX6_BMOD_FUSES 0b00 +#define BT_FUSE_SEL BIT(4) + +static bool imx6_bootsource_reserved(uint32_t sbmr2) +{ + return imx53_get_bmod(sbmr2) == IMX6_BMOD_RESERVED; +} + +static bool imx6_bootsource_serial(uint32_t sbmr2) +{ + return imx53_get_bmod(sbmr2) == IMX6_BMOD_SERIAL || + /* + * If boot from fuses is selected and fuses are not + * programmed by setting BT_FUSE_SEL, ROM code will + * fallback to serial mode + */ + (imx53_get_bmod(sbmr2) == IMX6_BMOD_FUSES && + !(sbmr2 & BT_FUSE_SEL)); +} + +static int __imx6_bootsource_serial_rom(uint32_t r) +{ + return FIELD_GET(BOOT_CFG4(2, 0), r); +} + +/* + * Serial ROM bootsource on i.MX6 are as follows: + * + * 000 - ECSPI-1 + * 001 - ECSPI-2 + * 010 - ECSPI-3 + * 011 - ECSPI-4 + * 100 - ECSPI-5 + * 101 - I2C1 + * 110 - I2C2 + * 111 - I2C3 + * + * There's no single bit that would tell us we are booting from I2C or + * SPI, so we just have to compare the "source" agains the value for + * I2C1 for both: calculating bootsource and boot instance. + */ +#define IMX6_BOOTSOURCE_SERIAL_ROM_I2C1 0b101 + +static enum bootsource imx6_bootsource_serial_rom(uint32_t sbmr) +{ + const int source = __imx6_bootsource_serial_rom(sbmr); + + return source < IMX6_BOOTSOURCE_SERIAL_ROM_I2C1 ? + BOOTSOURCE_SPI_NOR : BOOTSOURCE_I2C; +} + +static int imx6_boot_instance_serial_rom(uint32_t sbmr) +{ + const int source = __imx6_bootsource_serial_rom(sbmr); + + if (source < IMX6_BOOTSOURCE_SERIAL_ROM_I2C1) + return source; + + return source - IMX6_BOOTSOURCE_SERIAL_ROM_I2C1; +} + +static int imx6_boot_instance_mmc(uint32_t r) +{ + return FIELD_GET(BOOT_CFG2(4, 3), r); +} void imx6_get_boot_source(enum bootsource *src, int *instance) { void __iomem *src_base = IOMEM(MX6_SRC_BASE_ADDR); uint32_t sbmr1 = readl(src_base + IMX6_SRC_SBMR1); uint32_t sbmr2 = readl(src_base + IMX6_SRC_SBMR2); - uint32_t boot_cfg_4_2_0; - int boot_mode; - /* BMOD[1:0] */ - boot_mode = (sbmr2 >> 24) & 0x3; + if (imx6_bootsource_reserved(sbmr2)) + return; - switch (boot_mode) { - case 0: /* Fuses, fall through */ - case 2: /* internal boot */ - goto internal_boot; - case 1: /* Serial Downloader */ + if (imx6_bootsource_serial(sbmr2)) { *src = BOOTSOURCE_SERIAL; - break; - case 3: /* reserved */ - break; - }; - - return; - -internal_boot: + return; + } - /* BOOT_CFG1[7:4] */ - switch ((sbmr1 >> 4) & 0xf) { + switch (imx53_bootsource_internal(sbmr1)) { case 2: *src = BOOTSOURCE_HD; break; case 3: - /* BOOT_CFG4[2:0] */ - boot_cfg_4_2_0 = (sbmr1 >> 24) & 0x7; - - if (boot_cfg_4_2_0 > 4) { - *src = BOOTSOURCE_I2C; - *instance = boot_cfg_4_2_0 - 5; - } else { - *src = BOOTSOURCE_SPI; - *instance = boot_cfg_4_2_0; - } + *src = imx6_bootsource_serial_rom(sbmr1); + *instance = imx6_boot_instance_serial_rom(sbmr1); break; case 4: case 5: case 6: case 7: *src = BOOTSOURCE_MMC; - - /* BOOT_CFG2[4:3] */ - *instance = (sbmr1 >> 11) & 0x3; + *instance = imx6_boot_instance_mmc(sbmr1); break; default: + if (imx53_bootsource_nand(sbmr1)) + *src = BOOTSOURCE_NAND; break; } - - /* BOOT_CFG1[7:0] */ - if (sbmr1 & (1 << 7)) - *src = BOOTSOURCE_NAND; - - return; } void imx6_boot_save_loc(void) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; - - imx6_get_boot_source(&src, &instance); - - bootsource_set(src); - bootsource_set_instance(instance); + imx_boot_save_loc(imx6_get_boot_source); } #define IMX7_SRC_SBMR1 0x58 #define IMX7_SRC_SBMR2 0x70 +/* + * Re-defined to match the naming in reference manual + */ +#define BOOT_CFG(m, l) BOOT_CFG1(m, l) + +#define IMX_BOOT_SW_INFO_POINTER_ADDR 0x000001E8 +#define IMX_BOOT_SW_INFO_BDT_SD 0x1 + +static unsigned int imx7_bootsource_internal(uint32_t r) +{ + return FIELD_GET(BOOT_CFG(15, 12), r); +} + +static int imx7_boot_instance_spi_nor(uint32_t r) +{ + return FIELD_GET(BOOT_CFG(11, 9), r); +} + +static int imx7_boot_instance_mmc(uint32_t r) +{ + return FIELD_GET(BOOT_CFG(11, 10), r); +} + +struct imx_boot_sw_info { + uint8_t reserved_1; + uint8_t boot_device_instance; + uint8_t boot_device_type; + uint8_t reserved_2; + uint32_t frequency_hz[4]; /* Various frequencies (ARM, AXI, + * DDR, etc.). Not used */ + uint32_t reserved_3[3]; +} __packed; + void imx7_get_boot_source(enum bootsource *src, int *instance) { void __iomem *src_base = IOMEM(MX7_SRC_BASE_ADDR); uint32_t sbmr1 = readl(src_base + IMX7_SRC_SBMR1); uint32_t sbmr2 = readl(src_base + IMX7_SRC_SBMR2); - int boot_mode; - /* BMOD[1:0] */ - boot_mode = (sbmr2 >> 24) & 0x3; - - switch (boot_mode) { - case 0: /* Fuses, fall through */ - case 2: /* internal boot */ - goto internal_boot; - case 1: /* Serial Downloader */ - *src = BOOTSOURCE_SERIAL; - break; - case 3: /* reserved */ - break; - }; + if (imx6_bootsource_reserved(sbmr2)) + return; - return; + if (imx6_bootsource_serial(sbmr2)) { + /* + * On i.MX7 ROM code will try to bood from uSDHC1 + * before entering serial mode. It doesn't seem to be + * reflected in the contents of SBMR1 in any way when + * that happens, so we check "Boot_SW_Info" structure + * (per 6.6.14 Boot information for software) to see + * if that really happened. + * + * FIXME: This behaviour can be inhibited by + * DISABLE_SDMMC_MFG, but location of that fuse + * doesn't seem to be documented anywhere. Once that + * is known it should be taken into account here. + */ + const struct imx_boot_sw_info *info; + + info = (const void *)readl(IMX_BOOT_SW_INFO_POINTER_ADDR); + + if (info->boot_device_type == IMX_BOOT_SW_INFO_BDT_SD) { + *src = BOOTSOURCE_MMC; + /* + * We are expecting to only ever boot from + * uSDHC1 here + */ + WARN_ON(*instance = info->boot_device_instance); + return; + } -internal_boot: + *src = BOOTSOURCE_SERIAL; + return; + } - switch ((sbmr1 >> 12) & 0xf) { + switch (imx7_bootsource_internal(sbmr1)) { case 1: case 2: *src = BOOTSOURCE_MMC; - *instance = (sbmr1 >> 10 & 0x3); + *instance = imx7_boot_instance_mmc(sbmr1); break; case 3: *src = BOOTSOURCE_NAND; break; - case 4: + case 6: *src = BOOTSOURCE_SPI_NOR, - *instance = (sbmr1 >> 9 & 0x7); + *instance = imx7_boot_instance_spi_nor(sbmr1); break; - case 6: + case 4: *src = BOOTSOURCE_SPI; /* Really: qspi */ break; case 5: @@ -398,21 +523,103 @@ internal_boot: default: break; } +} - /* BOOT_CFG1[7:0] */ - if (sbmr1 & (1 << 7)) - *src = BOOTSOURCE_NAND; +void imx7_boot_save_loc(void) +{ + imx_boot_save_loc(imx7_get_boot_source); +} - return; +static int vf610_boot_instance_spi(uint32_t r) +{ + return FIELD_GET(BOOT_CFG1_1, r); } -void imx7_boot_save_loc(void) +static int vf610_boot_instance_nor(uint32_t r) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; + return FIELD_GET(BOOT_CFG1_3, r); +} + +/* + * Vybrid's Serial ROM boot sources (BOOT_CFG4[2:0]) are as follows: + * + * 000 - SPI0 + * 001 - SPI1 + * 010 - SPI2 + * 011 - SPI3 + * 100 - I2C0 + * 101 - I2C1 + * 110 - I2C2 + * 111 - I2C3 + * + * Which we can neatly divide in two halves and use MSb to detect if + * bootsource is I2C or SPI EEPROM and 2 LSbs directly as boot + * insance. + */ +static enum bootsource vf610_bootsource_serial_rom(uint32_t r) +{ + return FIELD_GET(BOOT_CFG4_2, r) ? BOOTSOURCE_I2C : BOOTSOURCE_SPI_NOR; +} - imx7_get_boot_source(&src, &instance); +static int vf610_boot_instance_serial_rom(uint32_t r) +{ + return __imx6_bootsource_serial_rom(r) & 0b11; +} - bootsource_set(src); - bootsource_set_instance(instance); +static int vf610_boot_instance_can(uint32_t r) +{ + return FIELD_GET(BOOT_CFG1_0, r); +} + +static int vf610_boot_instance_mmc(uint32_t r) +{ + return FIELD_GET(BOOT_CFG2_3, r); +} + +void vf610_get_boot_source(enum bootsource *src, int *instance) +{ + void __iomem *src_base = IOMEM(VF610_SRC_BASE_ADDR); + uint32_t sbmr1 = readl(src_base + IMX6_SRC_SBMR1); + uint32_t sbmr2 = readl(src_base + IMX6_SRC_SBMR2); + + if (imx6_bootsource_reserved(sbmr2)) + return; + + if (imx6_bootsource_serial(sbmr2)) { + *src = BOOTSOURCE_SERIAL; + return; + } + + switch (imx53_bootsource_internal(sbmr1)) { + case 0: + *src = BOOTSOURCE_SPI; /* Really: qspi */ + *instance = vf610_boot_instance_spi(sbmr1); + break; + case 1: + *src = BOOTSOURCE_NOR; + *instance = vf610_boot_instance_nor(sbmr1); + break; + case 2: + *src = vf610_bootsource_serial_rom(sbmr1); + *instance = vf610_boot_instance_serial_rom(sbmr1); + break; + case 3: + *src = BOOTSOURCE_CAN; + *instance = vf610_boot_instance_can(sbmr1); + break; + case 6: + case 7: + *src = BOOTSOURCE_MMC; + *instance = vf610_boot_instance_mmc(sbmr1); + break; + default: + if (imx53_bootsource_nand(sbmr1)) + *src = BOOTSOURCE_NAND; + break; + } +} + +void vf610_boot_save_loc(void) +{ + imx_boot_save_loc(vf610_get_boot_source); } diff --git a/arch/arm/mach-imx/esdctl.c b/arch/arm/mach-imx/esdctl.c index 1eebc77b63..c1680d5ff8 100644 --- a/arch/arm/mach-imx/esdctl.c +++ b/arch/arm/mach-imx/esdctl.c @@ -37,6 +37,7 @@ #include <mach/imx51-regs.h> #include <mach/imx53-regs.h> #include <mach/imx6-regs.h> +#include <mach/vf610-ddrmc.h> struct imx_esdctl_data { unsigned long base0; @@ -75,12 +76,9 @@ static inline unsigned long imx_v1_sdram_size(void __iomem *esdctlbase, int num) if (ctlval & (1 << 17)) width = 4; - size = (1 << cols) * (1 << rows) * banks * width; + size = memory_sdram_size(cols, rows, banks, width); - if (size > SZ_64M) - size = SZ_64M; - - return size; + return min_t(unsigned long, size, SZ_64M); } /* @@ -103,12 +101,9 @@ static inline unsigned long imx_v2_sdram_size(void __iomem *esdctlbase, int num) if ((ctlval & ESDCTL0_DSIZ_MASK) == ESDCTL0_DSIZ_31_0) width = 4; - size = (1 << cols) * (1 << rows) * banks * width; - - if (size > SZ_256M) - size = SZ_256M; + size = memory_sdram_size(cols, rows, banks, width); - return size; + return min_t(unsigned long, size, SZ_256M); } /* @@ -120,13 +115,10 @@ static inline unsigned long imx_v3_sdram_size(void __iomem *esdctlbase, int num) size = imx_v2_sdram_size(esdctlbase, num); - if (readl(esdctlbase + IMX_ESDMISC) & (1 << 6)) + if (readl(esdctlbase + IMX_ESDMISC) & ESDMISC_DDR2_8_BANK) size *= 2; - if (size > SZ_256M) - size = SZ_256M; - - return size; + return min_t(unsigned long, size, SZ_256M); } /* @@ -136,7 +128,6 @@ static inline unsigned long imx_v4_sdram_size(void __iomem *esdctlbase, int cs) { u32 ctlval = readl(esdctlbase + ESDCTL_V4_ESDCTL0); u32 esdmisc = readl(esdctlbase + ESDCTL_V4_ESDMISC); - unsigned long size; int rows, cols, width = 2, banks = 8; if (cs == 0 && !(ctlval & ESDCTL_V4_ESDCTLx_SDE0)) @@ -162,20 +153,17 @@ static inline unsigned long imx_v4_sdram_size(void __iomem *esdctlbase, int cs) if (esdmisc & ESDCTL_V4_ESDMISC_BANKS_4) banks = 4; - size = (1 << cols) * (1 << rows) * banks * width; - - return size; + return memory_sdram_size(cols, rows, banks, width); } /* * MMDC - found on i.MX6 */ -static inline u64 imx6_mmdc_sdram_size(void __iomem *mmdcbase, int cs) +static inline u64 __imx6_mmdc_sdram_size(void __iomem *mmdcbase, int cs) { u32 ctlval = readl(mmdcbase + MDCTL); u32 mdmisc = readl(mmdcbase + MDMISC); - u64 size; int rows, cols, width = 2, banks = 8; if (cs == 0 && !(ctlval & MMDCx_MDCTL_SDE0)) @@ -201,9 +189,7 @@ static inline u64 imx6_mmdc_sdram_size(void __iomem *mmdcbase, int cs) if (mdmisc & MMDCx_MDMISC_DDR_4_BANKS) banks = 4; - size = (u64)(1 << cols) * (1 << rows) * banks * width; - - return size; + return memory_sdram_size(cols, rows, banks, width); } static void add_mem(unsigned long base0, unsigned long size0, @@ -286,7 +272,7 @@ static void imx_esdctl_v4_add_mem(void *esdctlbase, struct imx_esdctl_data *data */ #define IMX6_MAX_SDRAM_SIZE 0xF0000000 -static void imx6_mmdc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) +static inline resource_size_t imx6_mmdc_sdram_size(void __iomem *mmdcbase) { /* * It is possible to have a configuration in which both chip @@ -296,14 +282,41 @@ static void imx6_mmdc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) * IMX6_MAX_SDRAM_SIZE bytes of memory available. */ - u64 size_cs0 = imx6_mmdc_sdram_size(mmdcbase, 0); - u64 size_cs1 = imx6_mmdc_sdram_size(mmdcbase, 1); + u64 size_cs0 = __imx6_mmdc_sdram_size(mmdcbase, 0); + u64 size_cs1 = __imx6_mmdc_sdram_size(mmdcbase, 1); u64 total = size_cs0 + size_cs1; resource_size_t size = min(total, (u64)IMX6_MAX_SDRAM_SIZE); + return size; +} + +static void imx6_mmdc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) +{ + arm_add_mem_device("ram0", data->base0, + imx6_mmdc_sdram_size(mmdcbase)); +} + +static inline resource_size_t vf610_ddrmc_sdram_size(void __iomem *ddrmc) +{ + const u32 cr01 = readl(ddrmc + DDRMC_CR(1)); + const u32 cr73 = readl(ddrmc + DDRMC_CR(73)); + const u32 cr78 = readl(ddrmc + DDRMC_CR(78)); + + unsigned int rows, cols, width, banks; + + rows = DDRMC_CR01_MAX_ROW_REG(cr01) - DDRMC_CR73_ROW_DIFF(cr73); + cols = DDRMC_CR01_MAX_COL_REG(cr01) - DDRMC_CR73_COL_DIFF(cr73); + banks = 1 << (3 - DDRMC_CR73_BANK_DIFF(cr73)); + width = (cr78 & DDRMC_CR78_REDUC) ? sizeof(u8) : sizeof(u16); + + return memory_sdram_size(cols, rows, banks, width); +} + +static void vf610_ddrmc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) +{ arm_add_mem_device("ram0", data->base0, - size); + vf610_ddrmc_sdram_size(mmdcbase)); } static int imx_esdctl_probe(struct device_d *dev) @@ -373,15 +386,20 @@ static __maybe_unused struct imx_esdctl_data imx53_data = { }; static __maybe_unused struct imx_esdctl_data imx6q_data = { - .base0 = MX6_MMDC_PORT0_BASE_ADDR, + .base0 = MX6_MMDC_PORT01_BASE_ADDR, .add_mem = imx6_mmdc_add_mem, }; static __maybe_unused struct imx_esdctl_data imx6ul_data = { - .base0 = 0x80000000, + .base0 = MX6_MMDC_PORT0_BASE_ADDR, .add_mem = imx6_mmdc_add_mem, }; +static __maybe_unused struct imx_esdctl_data vf610_data = { + .base0 = VF610_RAM_BASE_ADDR, + .add_mem = vf610_ddrmc_add_mem, +}; + static struct platform_device_id imx_esdctl_ids[] = { #ifdef CONFIG_ARCH_IMX1 { @@ -441,6 +459,9 @@ static __maybe_unused struct of_device_id imx_esdctl_dt_ids[] = { .compatible = "fsl,imx6q-mmdc", .data = &imx6q_data }, { + .compatible = "fsl,vf610-ddrmc", + .data = &vf610_data + }, { /* sentinel */ } }; @@ -498,9 +519,9 @@ void __noreturn imx1_barebox_entry(void *boarddata) unsigned long base, size; upper_or_coalesced_range(MX1_CSD0_BASE_ADDR, - imx_v1_sdram_size((void *)MX1_SDRAMC_BASE_ADDR, 0), + imx_v1_sdram_size(IOMEM(MX1_SDRAMC_BASE_ADDR), 0), MX1_CSD1_BASE_ADDR, - imx_v1_sdram_size((void *)MX1_SDRAMC_BASE_ADDR, 1), + imx_v1_sdram_size(IOMEM(MX1_SDRAMC_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); @@ -511,9 +532,9 @@ void __noreturn imx25_barebox_entry(void *boarddata) unsigned long base, size; upper_or_coalesced_range(MX25_CSD0_BASE_ADDR, - imx_v2_sdram_size((void *)MX25_ESDCTL_BASE_ADDR, 0), + imx_v2_sdram_size(IOMEM(MX25_ESDCTL_BASE_ADDR), 0), MX25_CSD1_BASE_ADDR, - imx_v2_sdram_size((void *)MX25_ESDCTL_BASE_ADDR, 1), + imx_v2_sdram_size(IOMEM(MX25_ESDCTL_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); @@ -523,12 +544,12 @@ void __noreturn imx27_barebox_entry(void *boarddata) { unsigned long base, size; - imx_esdctl_v2_disable_default((void *)MX27_ESDCTL_BASE_ADDR); + imx_esdctl_v2_disable_default(IOMEM(MX27_ESDCTL_BASE_ADDR)); upper_or_coalesced_range(MX27_CSD0_BASE_ADDR, - imx_v2_sdram_size((void *)MX27_ESDCTL_BASE_ADDR, 0), + imx_v2_sdram_size(IOMEM(MX27_ESDCTL_BASE_ADDR), 0), MX27_CSD1_BASE_ADDR, - imx_v2_sdram_size((void *)MX27_ESDCTL_BASE_ADDR, 1), + imx_v2_sdram_size(IOMEM(MX27_ESDCTL_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); @@ -538,12 +559,12 @@ void __noreturn imx31_barebox_entry(void *boarddata) { unsigned long base, size; - imx_esdctl_v2_disable_default((void *)MX31_ESDCTL_BASE_ADDR); + imx_esdctl_v2_disable_default(IOMEM(MX31_ESDCTL_BASE_ADDR)); upper_or_coalesced_range(MX31_CSD0_BASE_ADDR, - imx_v2_sdram_size((void *)MX31_ESDCTL_BASE_ADDR, 0), + imx_v2_sdram_size(IOMEM(MX31_ESDCTL_BASE_ADDR), 0), MX31_CSD1_BASE_ADDR, - imx_v2_sdram_size((void *)MX31_ESDCTL_BASE_ADDR, 1), + imx_v2_sdram_size(IOMEM(MX31_ESDCTL_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); @@ -553,12 +574,12 @@ void __noreturn imx35_barebox_entry(void *boarddata) { unsigned long base, size; - imx_esdctl_v2_disable_default((void *)MX35_ESDCTL_BASE_ADDR); + imx_esdctl_v2_disable_default(IOMEM(MX35_ESDCTL_BASE_ADDR)); upper_or_coalesced_range(MX35_CSD0_BASE_ADDR, - imx_v2_sdram_size((void *)MX35_ESDCTL_BASE_ADDR, 0), + imx_v2_sdram_size(IOMEM(MX35_ESDCTL_BASE_ADDR), 0), MX35_CSD1_BASE_ADDR, - imx_v2_sdram_size((void *)MX35_ESDCTL_BASE_ADDR, 1), + imx_v2_sdram_size(IOMEM(MX35_ESDCTL_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); @@ -569,9 +590,9 @@ void __noreturn imx51_barebox_entry(void *boarddata) unsigned long base, size; upper_or_coalesced_range(MX51_CSD0_BASE_ADDR, - imx_v3_sdram_size((void *)MX51_ESDCTL_BASE_ADDR, 0), + imx_v3_sdram_size(IOMEM(MX51_ESDCTL_BASE_ADDR), 0), MX51_CSD1_BASE_ADDR, - imx_v3_sdram_size((void *)MX51_ESDCTL_BASE_ADDR, 1), + imx_v3_sdram_size(IOMEM(MX51_ESDCTL_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); @@ -582,32 +603,35 @@ void __noreturn imx53_barebox_entry(void *boarddata) unsigned long base, size; upper_or_coalesced_range(MX53_CSD0_BASE_ADDR, - imx_v4_sdram_size((void *)MX53_ESDCTL_BASE_ADDR, 0), + imx_v4_sdram_size(IOMEM(MX53_ESDCTL_BASE_ADDR), 0), MX53_CSD1_BASE_ADDR, - imx_v4_sdram_size((void *)MX53_ESDCTL_BASE_ADDR, 1), + imx_v4_sdram_size(IOMEM(MX53_ESDCTL_BASE_ADDR), 1), &base, &size); barebox_arm_entry(base, size, boarddata); } -void __noreturn imx6q_barebox_entry(void *boarddata) +static void __noreturn +imx6_barebox_entry(unsigned long membase, void *boarddata) { - u64 size_cs0 = imx6_mmdc_sdram_size((void *)MX6_MMDC_P0_BASE_ADDR, 0); - u64 size_cs1 = imx6_mmdc_sdram_size((void *)MX6_MMDC_P0_BASE_ADDR, 1); - u64 total = size_cs0 + size_cs1; - - resource_size_t size = min(total, (u64)IMX6_MAX_SDRAM_SIZE); + barebox_arm_entry(membase, + imx6_mmdc_sdram_size(IOMEM(MX6_MMDC_P0_BASE_ADDR)), + boarddata); +} - barebox_arm_entry(0x10000000, size, boarddata); +void __noreturn imx6q_barebox_entry(void *boarddata) +{ + imx6_barebox_entry(MX6_MMDC_PORT01_BASE_ADDR, boarddata); } void __noreturn imx6ul_barebox_entry(void *boarddata) { - u64 size_cs0 = imx6_mmdc_sdram_size((void *)MX6_MMDC_P0_BASE_ADDR, 0); - u64 size_cs1 = imx6_mmdc_sdram_size((void *)MX6_MMDC_P0_BASE_ADDR, 1); - u64 total = size_cs0 + size_cs1; - - resource_size_t size = min(total, (u64)IMX6_MAX_SDRAM_SIZE); + imx6_barebox_entry(MX6_MMDC_PORT0_BASE_ADDR, boarddata); +} - barebox_arm_entry(0x80000000, size, boarddata); +void __noreturn vf610_barebox_entry(void *boarddata) +{ + barebox_arm_entry(VF610_RAM_BASE_ADDR, + vf610_ddrmc_sdram_size(IOMEM(VF610_DDR_BASE_ADDR)), + boarddata); } diff --git a/arch/arm/mach-imx/imx.c b/arch/arm/mach-imx/imx.c index 9400105c66..1b4c1b3df1 100644 --- a/arch/arm/mach-imx/imx.c +++ b/arch/arm/mach-imx/imx.c @@ -14,8 +14,10 @@ #include <common.h> #include <of.h> #include <init.h> +#include <io.h> #include <mach/revision.h> #include <mach/generic.h> +#include <mach/reset-reason.h> static int __imx_silicon_revision = IMX_CHIP_REV_UNKNOWN; @@ -28,7 +30,10 @@ void imx_set_silicon_revision(const char *soc, int revision) { __imx_silicon_revision = revision; - pr_info("detected %s revision %d.%d\n", soc, + if (revision == IMX_CHIP_REV_UNKNOWN) + pr_info("detected %s revision unknown\n", soc); + else + pr_info("detected %s revision %d.%d\n", soc, (revision >> 4) & 0xf, revision & 0xf); } @@ -114,7 +119,7 @@ static int imx_init(void) else if (cpu_is_mx7()) ret = imx7_init(); else if (cpu_is_vf610()) - ret = 0; + ret = vf610_init(); else return -EINVAL; @@ -147,3 +152,46 @@ static int imx_init(void) return ret; } postcore_initcall(imx_init); + +const struct imx_reset_reason imx_reset_reasons[] = { + { IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 }, + { IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 }, + { IMX_SRC_SRSR_JTAG_RESET, RESET_JTAG, 0 }, + { IMX_SRC_SRSR_JTAG_SW_RESET, RESET_JTAG, 0 }, + { IMX_SRC_SRSR_WARM_BOOT, RESET_RST, 0 }, + { /* sentinel */ } +}; + +void imx_set_reset_reason(void __iomem *srsr, + const struct imx_reset_reason *reasons) +{ + enum reset_src_type type = RESET_UKWN; + const u32 reg = readl(srsr); + int i, instance = 0; + + /* + * SRSR register captures ALL reset event that occured since + * POR, so we need to clear it to make sure we only caputre + * the latest one. + */ + writel(reg, srsr); + + for (i = 0; reasons[i].mask; i++) { + if (reg & reasons[i].mask) { + type = reasons[i].type; + instance = reasons[i].instance; + break; + } + } + + /* + * Report this with above default priority in order to make + * sure we'll always override info from watchdog driver. + */ + reset_source_set_priority(type, + RESET_SOURCE_DEFAULT_PRIORITY + 1); + reset_source_set_instance(type, instance); + + pr_info("i.MX reset reason %s (SRSR: 0x%08x)\n", + reset_source_name(), reg); +} diff --git a/arch/arm/mach-imx/imx51.c b/arch/arm/mach-imx/imx51.c index ffe6a7c651..ec8cdd868b 100644 --- a/arch/arm/mach-imx/imx51.c +++ b/arch/arm/mach-imx/imx51.c @@ -21,6 +21,7 @@ #include <mach/revision.h> #include <mach/clock-imx51_53.h> #include <mach/generic.h> +#include <mach/reset-reason.h> #define IIM_SREV 0x24 @@ -43,7 +44,7 @@ static int imx51_silicon_revision(void) static void imx51_ipu_mipi_setup(void) { - void __iomem *hsc_addr = (void __iomem *)MX51_MIPI_HSC_BASE_ADDR; + void __iomem *hsc_addr = IOMEM(MX51_MIPI_HSC_BASE_ADDR); u32 val; /* setup MIPI module to legacy mode */ @@ -57,7 +58,10 @@ static void imx51_ipu_mipi_setup(void) int imx51_init(void) { + void __iomem *src = IOMEM(MX51_SRC_BASE_ADDR); + imx_set_silicon_revision("i.MX51", imx51_silicon_revision()); + imx_set_reset_reason(src + IMX_SRC_SRSR, imx_reset_reasons); imx51_boot_save_loc(); add_generic_device("imx51-esdctl", 0, NULL, MX51_ESDCTL_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL); imx51_ipu_mipi_setup(); @@ -97,7 +101,7 @@ int imx51_devices_init(void) */ static void imx51_setup_pll800_bug(void) { - void __iomem *base = (void *)MX51_PLL1_BASE_ADDR; + void __iomem *base = IOMEM(MX51_PLL1_BASE_ADDR); u32 dp_config; volatile int i; @@ -132,7 +136,7 @@ static void imx51_setup_pll800_bug(void) void imx51_init_lowlevel(unsigned int cpufreq_mhz) { - void __iomem *ccm = (void __iomem *)MX51_CCM_BASE_ADDR; + void __iomem *ccm = IOMEM(MX51_CCM_BASE_ADDR); u32 r; int rev = imx51_silicon_revision(); @@ -167,30 +171,30 @@ void imx51_init_lowlevel(unsigned int cpufreq_mhz) switch (cpufreq_mhz) { case 600: - imx5_setup_pll_600((void __iomem *)MX51_PLL1_BASE_ADDR); + imx5_setup_pll_600(IOMEM(MX51_PLL1_BASE_ADDR)); break; default: /* Default maximum 800MHz */ if (rev <= IMX_CHIP_REV_3_0) imx51_setup_pll800_bug(); else - imx5_setup_pll_800((void __iomem *)MX51_PLL1_BASE_ADDR); + imx5_setup_pll_800(IOMEM(MX51_PLL1_BASE_ADDR)); break; } - imx5_setup_pll_665((void __iomem *)MX51_PLL3_BASE_ADDR); + imx5_setup_pll_665(IOMEM(MX51_PLL3_BASE_ADDR)); /* Switch peripheral to PLL 3 */ writel(0x000010C0, ccm + MX5_CCM_CBCMR); writel(0x13239145, ccm + MX5_CCM_CBCDR); - imx5_setup_pll_665((void __iomem *)MX51_PLL2_BASE_ADDR); + imx5_setup_pll_665(IOMEM(MX51_PLL2_BASE_ADDR)); /* Switch peripheral to PLL2 */ writel(0x19239145, ccm + MX5_CCM_CBCDR); writel(0x000020C0, ccm + MX5_CCM_CBCMR); - imx5_setup_pll_216((void __iomem *)MX51_PLL3_BASE_ADDR); + imx5_setup_pll_216(IOMEM(MX51_PLL3_BASE_ADDR)); /* Set the platform clock dividers */ writel(0x00000125, MX51_ARM_BASE_ADDR + 0x14); diff --git a/arch/arm/mach-imx/imx53.c b/arch/arm/mach-imx/imx53.c index 2758f1bbcf..56f1bda75e 100644 --- a/arch/arm/mach-imx/imx53.c +++ b/arch/arm/mach-imx/imx53.c @@ -21,6 +21,7 @@ #include <mach/revision.h> #include <mach/clock-imx51_53.h> #include <mach/generic.h> +#include <mach/reset-reason.h> #define SI_REV 0x48 @@ -52,7 +53,10 @@ static int imx53_silicon_revision(void) int imx53_init(void) { + void __iomem *src = IOMEM(MX53_SRC_BASE_ADDR); + imx53_silicon_revision(); + imx_set_reset_reason(src + IMX_SRC_SRSR, imx_reset_reasons); imx53_boot_save_loc(); add_generic_device("imx53-esdctl", 0, NULL, MX53_ESDCTL_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL); diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c index 14a1cba5a4..eaf9f2e413 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -16,9 +16,11 @@ #include <io.h> #include <linux/sizes.h> #include <mfd/imx6q-iomuxc-gpr.h> +#include <mach/clock-imx6.h> #include <mach/imx6.h> #include <mach/generic.h> #include <mach/revision.h> +#include <mach/reset-reason.h> #include <mach/imx6-anadig.h> #include <mach/imx6-regs.h> #include <mach/generic.h> @@ -44,6 +46,11 @@ static void imx6_init_lowlevel(void) void __iomem *aips2 = (void *)MX6_AIPS2_ON_BASE_ADDR; bool is_imx6q = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6Q; bool is_imx6d = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6D; + uint32_t val_480; + uint32_t val_528; + uint32_t periph_sel_1; + uint32_t periph_sel_2; + uint32_t reg; /* * Set all MPROTx to be non-bufferable, trusted for R/W, @@ -68,32 +75,38 @@ static void imx6_init_lowlevel(void) /* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs * to make sure PFD is working right, otherwise, PFDs may * not output clock after reset, MX6DL and MX6SL have added 396M pfd - * workaround in ROM code, as bus clock need it + * workaround in ROM code, as bus clock need it. + * Don't reset PLL2 PFD0 / PLL2 PFD2 if is's used by periph_clk. */ if (is_imx6q || is_imx6d) { - writel(BM_ANADIG_PFD_480_PFD3_CLKGATE | - BM_ANADIG_PFD_480_PFD2_CLKGATE | - BM_ANADIG_PFD_480_PFD1_CLKGATE | - BM_ANADIG_PFD_480_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_SET); - writel(BM_ANADIG_PFD_528_PFD3_CLKGATE | - BM_ANADIG_PFD_528_PFD2_CLKGATE | - BM_ANADIG_PFD_528_PFD1_CLKGATE | - BM_ANADIG_PFD_528_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_SET); - - writel(BM_ANADIG_PFD_480_PFD3_CLKGATE | - BM_ANADIG_PFD_480_PFD2_CLKGATE | - BM_ANADIG_PFD_480_PFD1_CLKGATE | - BM_ANADIG_PFD_480_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_CLR); - writel(BM_ANADIG_PFD_528_PFD3_CLKGATE | - BM_ANADIG_PFD_528_PFD2_CLKGATE | - BM_ANADIG_PFD_528_PFD1_CLKGATE | - BM_ANADIG_PFD_528_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_CLR); - } + val_480 = BM_ANADIG_PFD_480_PFD3_CLKGATE | + BM_ANADIG_PFD_480_PFD2_CLKGATE | + BM_ANADIG_PFD_480_PFD1_CLKGATE | + BM_ANADIG_PFD_480_PFD0_CLKGATE; + + val_528 = BM_ANADIG_PFD_528_PFD3_CLKGATE | + BM_ANADIG_PFD_528_PFD1_CLKGATE; + + reg = readl(MXC_CCM_CBCMR); + periph_sel_1 = (reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) + >> MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET; + + periph_sel_2 = (reg & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) + >> MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET; + + if ((periph_sel_1 != 0x2) && (periph_sel_2 != 0x2)) + val_528 |= BM_ANADIG_PFD_528_PFD0_CLKGATE; + + if ((periph_sel_1 != 0x1) && (periph_sel_2 != 0x1) + && (periph_sel_1 != 0x3) && (periph_sel_2 != 0x3)) + val_528 |= BM_ANADIG_PFD_528_PFD2_CLKGATE; + + writel(val_480, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_SET); + writel(val_528, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_SET); + writel(val_480, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_CLR); + writel(val_528, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_CLR); + } } static void imx6_setup_ipu_qos(void) @@ -147,10 +160,37 @@ static void imx6ul_enet_clk_init(void) writel(val, gprbase + IOMUXC_GPR1); } +int imx6_cpu_type(void) +{ + static int cpu_type = -1; + + if (!cpu_is_mx6()) + return 0; + + if (cpu_type < 0) + cpu_type = __imx6_cpu_type(); + + return cpu_type; +} + +int imx6_cpu_revision(void) +{ + static int soc_revision = -1; + + if (!cpu_is_mx6()) + return 0; + + if (soc_revision < 0) + soc_revision = __imx6_cpu_revision(); + + return soc_revision; +} + int imx6_init(void) { const char *cputypestr; u32 mx6_silicon_revision; + void __iomem *src = IOMEM(MX6_SRC_BASE_ADDR); imx6_init_lowlevel(); @@ -160,16 +200,16 @@ int imx6_init(void) switch (imx6_cpu_type()) { case IMX6_CPUTYPE_IMX6Q: - if (mx6_silicon_revision >= IMX_CHIP_REV_2_0) - cputypestr = "i.MX6 Quad Plus"; - else - cputypestr = "i.MX6 Quad"; + cputypestr = "i.MX6 Quad"; + break; + case IMX6_CPUTYPE_IMX6QP: + cputypestr = "i.MX6 Quad Plus"; break; case IMX6_CPUTYPE_IMX6D: - if (mx6_silicon_revision >= IMX_CHIP_REV_2_0) - cputypestr = "i.MX6 Dual Plus"; - else - cputypestr = "i.MX6 Dual"; + cputypestr = "i.MX6 Dual"; + break; + case IMX6_CPUTYPE_IMX6DP: + cputypestr = "i.MX6 Dual Plus"; break; case IMX6_CPUTYPE_IMX6DL: cputypestr = "i.MX6 DualLite"; @@ -195,7 +235,7 @@ int imx6_init(void) } imx_set_silicon_revision(cputypestr, mx6_silicon_revision); - + imx_set_reset_reason(src + IMX_SRC_SRSR, imx_reset_reasons); imx6_setup_ipu_qos(); imx6ul_enet_clk_init(); diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c index 4eef99c872..e49baf6f77 100644 --- a/arch/arm/mach-imx/imx7.c +++ b/arch/arm/mach-imx/imx7.c @@ -19,6 +19,7 @@ #include <mach/imx7.h> #include <mach/generic.h> #include <mach/revision.h> +#include <mach/reset-reason.h> #include <mach/imx7-regs.h> void imx7_init_lowlevel(void) @@ -167,10 +168,21 @@ static struct psci_ops imx7_psci_ops = { .cpu_off = imx7_cpu_off, }; +static const struct imx_reset_reason imx7_reset_reasons[] = { + { IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 }, + { IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 }, + { IMX_SRC_SRSR_JTAG_RESET, RESET_JTAG, 0 }, + { IMX_SRC_SRSR_JTAG_SW_RESET, RESET_JTAG, 0 }, + { IMX_SRC_SRSR_WDOG3_RESET, RESET_WDG, 1 }, + { IMX_SRC_SRSR_WDOG4_RESET, RESET_WDG, 2 }, + { IMX_SRC_SRSR_TEMPSENSE_RESET, RESET_THERM, 0 }, + { /* sentinel */ } +}; + int imx7_init(void) { const char *cputypestr; - u32 imx7_silicon_revision; + void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR); imx7_init_lowlevel(); @@ -180,8 +192,6 @@ int imx7_init(void) imx7_boot_save_loc(); - imx7_silicon_revision = imx7_cpu_revision(); - psci_set_ops(&imx7_psci_ops); switch (imx7_cpu_type()) { @@ -196,7 +206,8 @@ int imx7_init(void) break; } - imx_set_silicon_revision(cputypestr, imx7_silicon_revision); + imx_set_silicon_revision(cputypestr, imx7_cpu_revision()); + imx_set_reset_reason(src + IMX7_SRC_SRSR, imx7_reset_reasons); return 0; } diff --git a/arch/arm/mach-imx/include/mach/esdctl.h b/arch/arm/mach-imx/include/mach/esdctl.h index 66dcc8974c..117e2bbad5 100644 --- a/arch/arm/mach-imx/include/mach/esdctl.h +++ b/arch/arm/mach-imx/include/mach/esdctl.h @@ -48,6 +48,7 @@ #define ESDMISC_MDDR_MDIS 0x00000010 #define ESDMISC_LHD 0x00000020 #define ESDMISC_SDRAMRDY 0x80000000 +#define ESDMISC_DDR2_8_BANK BIT(6) #define ESDCFGx_tXP_MASK 0x00600000 #define ESDCFGx_tXP_1 0x00000000 @@ -137,6 +138,7 @@ void __noreturn imx51_barebox_entry(void *boarddata); void __noreturn imx53_barebox_entry(void *boarddata); void __noreturn imx6q_barebox_entry(void *boarddata); void __noreturn imx6ul_barebox_entry(void *boarddata); +void __noreturn vf610_barebox_entry(void *boarddata); void imx_esdctl_disable(void); #endif diff --git a/arch/arm/mach-imx/include/mach/generic.h b/arch/arm/mach-imx/include/mach/generic.h index f68dc875b0..ad9d9cb022 100644 --- a/arch/arm/mach-imx/include/mach/generic.h +++ b/arch/arm/mach-imx/include/mach/generic.h @@ -15,6 +15,7 @@ void imx51_boot_save_loc(void); void imx53_boot_save_loc(void); void imx6_boot_save_loc(void); void imx7_boot_save_loc(void); +void vf610_boot_save_loc(void); void imx25_get_boot_source(enum bootsource *src, int *instance); void imx35_get_boot_source(enum bootsource *src, int *instance); @@ -22,6 +23,7 @@ void imx51_get_boot_source(enum bootsource *src, int *instance); void imx53_get_boot_source(enum bootsource *src, int *instance); void imx6_get_boot_source(enum bootsource *src, int *instance); void imx7_get_boot_source(enum bootsource *src, int *instance); +void vf610_get_boot_source(enum bootsource *src, int *instance); int imx1_init(void); int imx21_init(void); @@ -34,6 +36,7 @@ int imx51_init(void); int imx53_init(void); int imx6_init(void); int imx7_init(void); +int vf610_init(void); int imx1_devices_init(void); int imx21_devices_init(void); diff --git a/arch/arm/mach-imx/include/mach/imx6-regs.h b/arch/arm/mach-imx/include/mach/imx6-regs.h index ac2aa2109f..1ba22b5bc6 100644 --- a/arch/arm/mach-imx/include/mach/imx6-regs.h +++ b/arch/arm/mach-imx/include/mach/imx6-regs.h @@ -117,6 +117,8 @@ #define MX6_SATA_BASE_ADDR 0x02200000 -#define MX6_MMDC_PORT0_BASE_ADDR 0x10000000 +#define MX6_MMDC_PORT01_BASE_ADDR 0x10000000 +#define MX6_MMDC_PORT0_BASE_ADDR 0x80000000 + #endif /* __MACH_IMX6_REGS_H */ diff --git a/arch/arm/mach-imx/include/mach/imx6.h b/arch/arm/mach-imx/include/mach/imx6.h index 6b08e6a521..5701bd480c 100644 --- a/arch/arm/mach-imx/include/mach/imx6.h +++ b/arch/arm/mach-imx/include/mach/imx6.h @@ -16,7 +16,9 @@ void __noreturn imx6_pm_stby_poweroff(void); #define IMX6_CPUTYPE_IMX6DL 0x261 #define IMX6_CPUTYPE_IMX6SX 0x462 #define IMX6_CPUTYPE_IMX6D 0x263 +#define IMX6_CPUTYPE_IMX6DP 0x1263 #define IMX6_CPUTYPE_IMX6Q 0x463 +#define IMX6_CPUTYPE_IMX6QP 0x1463 #define IMX6_CPUTYPE_IMX6UL 0x164 #define IMX6_CPUTYPE_IMX6ULL 0x165 @@ -33,36 +35,51 @@ static inline int scu_get_core_count(void) return (ncores & 0x03) + 1; } -static inline int __imx6_cpu_type(void) +#define SI_REV_CPUTYPE(s) (((s) >> 16) & 0xff) +#define SI_REV_MAJOR(s) (((s) >> 8) & 0xf) +#define SI_REV_MINOR(s) ((s) & 0xf) + +static inline uint32_t __imx6_read_si_rev(void) { - uint32_t val; - - val = readl(MX6_ANATOP_BASE_ADDR + IMX6_ANATOP_SI_REV); - val = (val >> 16) & 0xff; - /* non-MX6-standard SI_REV reg offset for MX6SL */ - if (IS_ENABLED(CONFIG_ARCH_IMX6SL) && - val < (IMX6_CPUTYPE_IMX6S & 0xff)) { - uint32_t tmp; - tmp = readl(MX6_ANATOP_BASE_ADDR + IMX6SL_ANATOP_SI_REV); - tmp = (tmp >> 16) & 0xff; - if ((IMX6_CPUTYPE_IMX6SL & 0xff) == tmp) - /* intentionally skip scu_get_core_count() for MX6SL */ - return IMX6_CPUTYPE_IMX6SL; - } + uint32_t si_rev; + uint32_t cpu_type; + + si_rev = readl(MX6_ANATOP_BASE_ADDR + IMX6_ANATOP_SI_REV); + cpu_type = SI_REV_CPUTYPE(si_rev); - val |= scu_get_core_count() << 8; + if (cpu_type >= 0x61 && cpu_type <= 0x65) + return si_rev; - return val; + /* try non-MX6-standard SI_REV reg offset for MX6SL */ + si_rev = readl(MX6_ANATOP_BASE_ADDR + IMX6SL_ANATOP_SI_REV); + cpu_type = SI_REV_CPUTYPE(si_rev); + + if (si_rev == 0x60) + return si_rev; + + return 0; } -static inline int imx6_cpu_type(void) +static inline int __imx6_cpu_type(void) { - if (!cpu_is_mx6()) - return 0; + uint32_t si_rev = __imx6_read_si_rev(); + uint32_t cpu_type = SI_REV_CPUTYPE(si_rev); + + /* intentionally skip scu_get_core_count() for MX6SL */ + if (cpu_type == IMX6_CPUTYPE_IMX6SL) + return IMX6_CPUTYPE_IMX6SL; - return __imx6_cpu_type(); + cpu_type |= scu_get_core_count() << 8; + + if ((cpu_type == IMX6_CPUTYPE_IMX6D || cpu_type == IMX6_CPUTYPE_IMX6Q) && + SI_REV_MAJOR(si_rev) >= 1) + cpu_type |= 0x1000; + + return cpu_type; } +int imx6_cpu_type(void); + #define DEFINE_MX6_CPU_TYPE(str, type) \ static inline int cpu_mx6_is_##str(void) \ { \ @@ -76,10 +93,19 @@ static inline int imx6_cpu_type(void) return cpu_mx6_is_##str(); \ } +/* + * Below are defined: + * + * cpu_is_mx6s(), cpu_is_mx6dl(), cpu_is_mx6q(), cpu_is_mx6qp(), cpu_is_mx6d(), + * cpu_is_mx6dp(), cpu_is_mx6sx(), cpu_is_mx6sl(), cpu_is_mx6ul(), + * cpu_is_mx6ull() + */ DEFINE_MX6_CPU_TYPE(mx6s, IMX6_CPUTYPE_IMX6S); DEFINE_MX6_CPU_TYPE(mx6dl, IMX6_CPUTYPE_IMX6DL); DEFINE_MX6_CPU_TYPE(mx6q, IMX6_CPUTYPE_IMX6Q); +DEFINE_MX6_CPU_TYPE(mx6qp, IMX6_CPUTYPE_IMX6QP); DEFINE_MX6_CPU_TYPE(mx6d, IMX6_CPUTYPE_IMX6D); +DEFINE_MX6_CPU_TYPE(mx6dp, IMX6_CPUTYPE_IMX6DP); DEFINE_MX6_CPU_TYPE(mx6sx, IMX6_CPUTYPE_IMX6SX); DEFINE_MX6_CPU_TYPE(mx6sl, IMX6_CPUTYPE_IMX6SL); DEFINE_MX6_CPU_TYPE(mx6ul, IMX6_CPUTYPE_IMX6UL); @@ -87,27 +113,15 @@ DEFINE_MX6_CPU_TYPE(mx6ull, IMX6_CPUTYPE_IMX6ULL); static inline int __imx6_cpu_revision(void) { - uint32_t rev; - uint32_t si_rev_offset = IMX6_ANATOP_SI_REV; + uint32_t si_rev = __imx6_read_si_rev(); u8 major_part, minor_part; - if (IS_ENABLED(CONFIG_ARCH_IMX6SL) && cpu_mx6_is_mx6sl()) - si_rev_offset = IMX6SL_ANATOP_SI_REV; - - rev = readl(MX6_ANATOP_BASE_ADDR + si_rev_offset); - - major_part = (rev >> 8) & 0xf; - minor_part = rev & 0xf; + major_part = (si_rev >> 8) & 0xf; + minor_part = si_rev & 0xf; return ((major_part + 1) << 4) | minor_part; } -static inline int imx6_cpu_revision(void) -{ - if (!cpu_is_mx6()) - return 0; - - return __imx6_cpu_revision(); -} +int imx6_cpu_revision(void); #endif /* __MACH_IMX6_H */ diff --git a/arch/arm/mach-imx/include/mach/reset-reason.h b/arch/arm/mach-imx/include/mach/reset-reason.h new file mode 100644 index 0000000000..0f644a8c1d --- /dev/null +++ b/arch/arm/mach-imx/include/mach/reset-reason.h @@ -0,0 +1,37 @@ +#ifndef __MACH_RESET_REASON_H__ +#define __MACH_RESET_REASON_H__ + +#include <reset_source.h> + +#define IMX_SRC_SRSR_IPP_RESET BIT(0) +#define IMX_SRC_SRSR_CSU_RESET BIT(2) +#define IMX_SRC_SRSR_IPP_USER_RESET BIT(3) +#define IMX_SRC_SRSR_WDOG1_RESET BIT(4) +#define IMX_SRC_SRSR_JTAG_RESET BIT(5) +#define IMX_SRC_SRSR_JTAG_SW_RESET BIT(6) +#define IMX_SRC_SRSR_WDOG3_RESET BIT(7) +#define IMX_SRC_SRSR_WDOG4_RESET BIT(8) +#define IMX_SRC_SRSR_TEMPSENSE_RESET BIT(9) +#define IMX_SRC_SRSR_WARM_BOOT BIT(16) + +#define IMX_SRC_SRSR 0x008 +#define IMX7_SRC_SRSR 0x05c + +#define VF610_SRC_SRSR_SW_RST BIT(18) +#define VF610_SRC_SRSR_RESETB BIT(7) +#define VF610_SRC_SRSR_JTAG_RST BIT(5) +#define VF610_SRC_SRSR_WDOG_M4 BIT(4) +#define VF610_SRC_SRSR_WDOG_A5 BIT(3) +#define VF610_SRC_SRSR_POR_RST BIT(0) + +struct imx_reset_reason { + uint32_t mask; + enum reset_src_type type; + int instance; +}; + +void imx_set_reset_reason(void __iomem *, const struct imx_reset_reason *); + +extern const struct imx_reset_reason imx_reset_reasons[]; + +#endif /* __MACH_RESET_REASON_H__ */ diff --git a/arch/arm/mach-imx/include/mach/vf610-ddrmc.h b/arch/arm/mach-imx/include/mach/vf610-ddrmc.h new file mode 100644 index 0000000000..07feb036e5 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/vf610-ddrmc.h @@ -0,0 +1,18 @@ +#ifndef __MACH_DDRMC_H +#define __MACH_DDRMC_H + +#include <mach/vf610-regs.h> + + +#define DDRMC_CR(x) ((x) * 4) + +#define DDRMC_CR01_MAX_COL_REG(reg) (((reg) >> 8) & 0b01111) +#define DDRMC_CR01_MAX_ROW_REG(reg) (((reg) >> 0) & 0b11111) +#define DDRMC_CR73_COL_DIFF(reg) (((reg) >> 16) & 0b00111) +#define DDRMC_CR73_ROW_DIFF(reg) (((reg) >> 8) & 0b00011) +#define DDRMC_CR73_BANK_DIFF(reg) (((reg) >> 0) & 0b00011) + +#define DDRMC_CR78_REDUC BIT(8) + + +#endif /* __MACH_MMDC_H */ diff --git a/arch/arm/mach-imx/include/mach/vf610-regs.h b/arch/arm/mach-imx/include/mach/vf610-regs.h index 8be220b68c..416b457aff 100644 --- a/arch/arm/mach-imx/include/mach/vf610-regs.h +++ b/arch/arm/mach-imx/include/mach/vf610-regs.h @@ -13,6 +13,8 @@ #define VF610_AIPS0_BASE_ADDR 0x40000000 #define VF610_AIPS1_BASE_ADDR 0x40080000 +#define VF610_RAM_BASE_ADDR 0x80000000 + /* AIPS 0 */ #define VF610_MSCM_BASE_ADDR (VF610_AIPS0_BASE_ADDR + 0x00001000) #define VF610_MSCM_IR_BASE_ADDR (VF610_AIPS0_BASE_ADDR + 0x00001800) @@ -107,4 +109,7 @@ #define VF610_MSCM_IRSPRC_CP0_EN 1 #define VF610_MSCM_IRSPRC_NUM 112 +#define VF610_MSCM_CPxCOUNT 0x00c +#define VF610_MSCM_CPxCFG1 0x014 + #endif diff --git a/arch/arm/mach-imx/include/mach/vf610.h b/arch/arm/mach-imx/include/mach/vf610.h new file mode 100644 index 0000000000..6d00d2e457 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/vf610.h @@ -0,0 +1,51 @@ +#ifndef __MACH_VF610_H +#define __MACH_VF610_H + +#include <io.h> +#include <mach/generic.h> +#include <mach/vf610-regs.h> +#include <mach/revision.h> + +#define VF610_CPUTYPE_VFx10 0x010 + +#define VF610_CPUTYPE_VF610 0x610 +#define VF610_CPUTYPE_VF600 0x600 +#define VF610_CPUTYPE_VF510 0x510 +#define VF610_CPUTYPE_VF500 0x500 + +#define VF610_ROM_VERSION_OFFSET 0x80 + +static inline int __vf610_cpu_type(void) +{ + void __iomem *mscm = IOMEM(VF610_MSCM_BASE_ADDR); + const u32 cpxcount = readl(mscm + VF610_MSCM_CPxCOUNT); + const u32 cpxcfg1 = readl(mscm + VF610_MSCM_CPxCFG1); + int cpu_type; + + cpu_type = cpxcount ? VF610_CPUTYPE_VF600 : VF610_CPUTYPE_VF500; + + return cpxcfg1 ? cpu_type | VF610_CPUTYPE_VFx10 : cpu_type; +} + +static inline int vf610_cpu_type(void) +{ + if (!cpu_is_vf610()) + return 0; + + return __vf610_cpu_type(); +} + +static inline int vf610_cpu_revision(void) +{ + if (!cpu_is_vf610()) + return IMX_CHIP_REV_UNKNOWN; + + /* + * There doesn't seem to be a documented way of retreiving + * silicon revision on VFxxx cpus, so we just report Mask ROM + * version instead + */ + return readl(VF610_ROM_VERSION_OFFSET) & 0xff; +} + +#endif diff --git a/arch/arm/mach-imx/vf610.c b/arch/arm/mach-imx/vf610.c new file mode 100644 index 0000000000..c535716c10 --- /dev/null +++ b/arch/arm/mach-imx/vf610.c @@ -0,0 +1,59 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <init.h> +#include <common.h> +#include <io.h> +#include <linux/sizes.h> +#include <mach/generic.h> +#include <mach/revision.h> +#include <mach/vf610.h> +#include <mach/reset-reason.h> + +static const struct imx_reset_reason vf610_reset_reasons[] = { + { VF610_SRC_SRSR_POR_RST, RESET_POR, 0 }, + { VF610_SRC_SRSR_WDOG_A5, RESET_WDG, 0 }, + { VF610_SRC_SRSR_WDOG_M4, RESET_WDG, 1 }, + { VF610_SRC_SRSR_JTAG_RST, RESET_JTAG, 0 }, + { VF610_SRC_SRSR_RESETB, RESET_EXT, 0 }, + { VF610_SRC_SRSR_SW_RST, RESET_RST, 0 }, + { /* sentinel */ } +}; + +int vf610_init(void) +{ + const char *cputypestr; + void __iomem *src = IOMEM(VF610_SRC_BASE_ADDR); + + switch (vf610_cpu_type()) { + case VF610_CPUTYPE_VF610: + cputypestr = "VF610"; + break; + case VF610_CPUTYPE_VF600: + cputypestr = "VF600"; + break; + case VF610_CPUTYPE_VF510: + cputypestr = "VF510"; + break; + case VF610_CPUTYPE_VF500: + cputypestr = "VF500"; + break; + default: + cputypestr = "unknown VFxxx"; + break; + } + + imx_set_silicon_revision(cputypestr, vf610_cpu_revision()); + imx_set_reset_reason(src + IMX_SRC_SRSR, vf610_reset_reasons); + return 0; +} diff --git a/arch/arm/mach-imx/xload.c b/arch/arm/mach-imx/xload.c index 16d56ab288..921e9ade20 100644 --- a/arch/arm/mach-imx/xload.c +++ b/arch/arm/mach-imx/xload.c @@ -24,7 +24,7 @@ static __noreturn int imx_xload(void) pr_info("booting from MMC\n"); buf = bootstrap_read_disk("disk0.0", "fat"); break; - case BOOTSOURCE_SPI: + case BOOTSOURCE_SPI_NOR: pr_info("booting from SPI\n"); buf = bootstrap_read_devfs("dataflash0", false, SZ_256K, SZ_1M, SZ_1M); |