diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2018-05-09 14:17:05 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2018-05-09 14:17:05 +0200 |
commit | 93c5d36b6520b8caed7cedcc5e4f18c8c68dc25c (patch) | |
tree | df6d59438d7f035202e90cbd15fee2f21962c4a2 | |
parent | afc0bedfd779e0b6e110427290312da5b0021e22 (diff) | |
parent | 8c489973200dfd9df9e918453f6de0f6a3b14bf7 (diff) | |
download | barebox-93c5d36b6520b8caed7cedcc5e4f18c8c68dc25c.tar.gz barebox-93c5d36b6520b8caed7cedcc5e4f18c8c68dc25c.tar.xz |
Merge branch 'for-next/imx-bootsource'
-rw-r--r-- | arch/arm/boards/datamodul-edm-qmx6/board.c | 2 | ||||
-rw-r--r-- | arch/arm/boards/dfi-fs700-m60/board.c | 2 | ||||
-rw-r--r-- | arch/arm/boards/phytec-som-imx6/board.c | 2 | ||||
-rw-r--r-- | arch/arm/boards/zii-imx6q-rdu2/lowlevel.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/boot.c | 435 | ||||
-rw-r--r-- | arch/arm/mach-imx/include/mach/generic.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/xload.c | 2 | ||||
-rw-r--r-- | common/bootsource.c | 1 | ||||
-rw-r--r-- | include/bootsource.h | 1 | ||||
-rw-r--r-- | include/linux/bitfield.h | 152 | ||||
-rw-r--r-- | include/linux/bug.h | 25 | ||||
-rw-r--r-- | include/linux/build_bug.h | 83 |
12 files changed, 566 insertions, 143 deletions
diff --git a/arch/arm/boards/datamodul-edm-qmx6/board.c b/arch/arm/boards/datamodul-edm-qmx6/board.c index 043a93461b..d93c940e3d 100644 --- a/arch/arm/boards/datamodul-edm-qmx6/board.c +++ b/arch/arm/boards/datamodul-edm-qmx6/board.c @@ -132,7 +132,7 @@ static int realq7_device_init(void) } break; default: - case BOOTSOURCE_SPI: + case BOOTSOURCE_SPI_NOR: of_device_enable_path("/chosen/environment-spi"); break; } diff --git a/arch/arm/boards/dfi-fs700-m60/board.c b/arch/arm/boards/dfi-fs700-m60/board.c index bef4612d9e..2cb8e3106f 100644 --- a/arch/arm/boards/dfi-fs700-m60/board.c +++ b/arch/arm/boards/dfi-fs700-m60/board.c @@ -105,7 +105,7 @@ static int dfi_fs700_m60_init(void) phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK, ar8031_phy_fixup); - if (bootsource_get() == BOOTSOURCE_SPI) + if (bootsource_get() == BOOTSOURCE_SPI_NOR) flag_spi |= BBU_HANDLER_FLAG_DEFAULT; else flag_mmc |= BBU_HANDLER_FLAG_DEFAULT; diff --git a/arch/arm/boards/phytec-som-imx6/board.c b/arch/arm/boards/phytec-som-imx6/board.c index 1a2d45ec92..34a0fe4183 100644 --- a/arch/arm/boards/phytec-som-imx6/board.c +++ b/arch/arm/boards/phytec-som-imx6/board.c @@ -204,7 +204,7 @@ static int physom_imx6_devices_init(void) environment_path = basprintf("/chosen/environment-nand"); envdev = "NAND flash"; break; - case BOOTSOURCE_SPI: + case BOOTSOURCE_SPI_NOR: environment_path = basprintf("/chosen/environment-spinor"); envdev = "SPI NOR flash"; break; diff --git a/arch/arm/boards/zii-imx6q-rdu2/lowlevel.c b/arch/arm/boards/zii-imx6q-rdu2/lowlevel.c index 48d02ce645..6b9c719c6d 100644 --- a/arch/arm/boards/zii-imx6q-rdu2/lowlevel.c +++ b/arch/arm/boards/zii-imx6q-rdu2/lowlevel.c @@ -290,7 +290,7 @@ static noinline void rdu2_sram_setup(void) write_regs(imx6q_dcd, ARRAY_SIZE(imx6q_dcd)); imx6_get_boot_source(&bootsrc, &instance); - if (bootsrc == BOOTSOURCE_SPI) + if (bootsrc == BOOTSOURCE_SPI_NOR) imx6_spi_start_image(0); else imx6_esdhc_start_image(instance); 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/include/mach/generic.h b/arch/arm/mach-imx/include/mach/generic.h index f68dc875b0..dedb4bbf06 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); 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); diff --git a/common/bootsource.c b/common/bootsource.c index 707b07924c..78ecd82676 100644 --- a/common/bootsource.c +++ b/common/bootsource.c @@ -36,6 +36,7 @@ static const char *bootsource_str[] = { [BOOTSOURCE_HD] = "harddisk", [BOOTSOURCE_USB] = "usb", [BOOTSOURCE_NET] = "net", + [BOOTSOURCE_CAN] = "can", }; static enum bootsource bootsource = BOOTSOURCE_UNKNOWN; diff --git a/include/bootsource.h b/include/bootsource.h index c6d3b3a98b..064f6b9a28 100644 --- a/include/bootsource.h +++ b/include/bootsource.h @@ -16,6 +16,7 @@ enum bootsource { BOOTSOURCE_HD, BOOTSOURCE_USB, BOOTSOURCE_NET, + BOOTSOURCE_CAN, }; #define BOOTSOURCE_INSTANCE_UNKNOWN -1 diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h new file mode 100644 index 0000000000..cf2588d811 --- /dev/null +++ b/include/linux/bitfield.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name> + * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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. + */ + +#ifndef _LINUX_BITFIELD_H +#define _LINUX_BITFIELD_H + +#include <linux/build_bug.h> +#include <asm/byteorder.h> + +/* + * Bitfield access macros + * + * FIELD_{GET,PREP} macros take as first parameter shifted mask + * from which they extract the base mask and shift amount. + * Mask must be a compilation time constant. + * + * Example: + * + * #define REG_FIELD_A GENMASK(6, 0) + * #define REG_FIELD_B BIT(7) + * #define REG_FIELD_C GENMASK(15, 8) + * #define REG_FIELD_D GENMASK(31, 16) + * + * Get: + * a = FIELD_GET(REG_FIELD_A, reg); + * b = FIELD_GET(REG_FIELD_B, reg); + * + * Set: + * reg = FIELD_PREP(REG_FIELD_A, 1) | + * FIELD_PREP(REG_FIELD_B, 0) | + * FIELD_PREP(REG_FIELD_C, c) | + * FIELD_PREP(REG_FIELD_D, 0x40); + * + * Modify: + * reg &= ~REG_FIELD_C; + * reg |= FIELD_PREP(REG_FIELD_C, c); + */ + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ + ({ \ + BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ + _pfx "mask is not constant"); \ + BUILD_BUG_ON_MSG(!(_mask), _pfx "mask is zero"); \ + BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ + ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ + _pfx "value too large for the field"); \ + BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ + _pfx "type of reg too small for mask"); \ + __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ + (1ULL << __bf_shf(_mask))); \ + }) + +/** + * FIELD_FIT() - check if value fits in the field + * @_mask: shifted mask defining the field's length and position + * @_val: value to test against the field + * + * Return: true if @_val can fit inside @_mask, false if @_val is too big. + */ +#define FIELD_FIT(_mask, _val) \ + ({ \ + __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ + !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ + }) + +/** + * FIELD_PREP() - prepare a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val: value to put in the field + * + * FIELD_PREP() masks and shifts up the value. The result should + * be combined with other fields of the bitfield using logical OR. + */ +#define FIELD_PREP(_mask, _val) \ + ({ \ + __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ + ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + }) + +/** + * FIELD_GET() - extract a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_reg: value of entire bitfield + * + * FIELD_GET() extracts the field specified by @_mask from the + * bitfield passed in as @_reg by masking and shifting it down. + */ +#define FIELD_GET(_mask, _reg) \ + ({ \ + __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ + (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + }) + +extern void __compiletime_warning("value doesn't fit into mask") +__field_overflow(void); +extern void __compiletime_error("bad bitfield mask") +__bad_mask(void); +static __always_inline u64 field_multiplier(u64 field) +{ + if ((field | (field - 1)) & ((field | (field - 1)) + 1)) + __bad_mask(); + return field & -field; +} +static __always_inline u64 field_mask(u64 field) +{ + return field / field_multiplier(field); +} +#define ____MAKE_OP(type,base,to,from) \ +static __always_inline __##type type##_encode_bits(base v, base field) \ +{ \ + if (__builtin_constant_p(v) && (v & ~field_multiplier(field))) \ + __field_overflow(); \ + return to((v & field_mask(field)) * field_multiplier(field)); \ +} \ +static __always_inline __##type type##_replace_bits(__##type old, \ + base val, base field) \ +{ \ + return (old & ~to(field)) | type##_encode_bits(val, field); \ +} \ +static __always_inline void type##p_replace_bits(__##type *p, \ + base val, base field) \ +{ \ + *p = (*p & ~to(field)) | type##_encode_bits(val, field); \ +} \ +static __always_inline base type##_get_bits(__##type v, base field) \ +{ \ + return (from(v) & field)/field_multiplier(field); \ +} +#define __MAKE_OP(size) \ + ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ + ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ + ____MAKE_OP(u##size,u##size,,) +__MAKE_OP(16) +__MAKE_OP(32) +__MAKE_OP(64) +#undef __MAKE_OP +#undef ____MAKE_OP + +#endif diff --git a/include/linux/bug.h b/include/linux/bug.h index 7295618c98..8367a11ec2 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -2,29 +2,6 @@ #define _LINUX_BUG_H #include <asm-generic/bug.h> - -#ifdef __CHECKER__ -#define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) -#define BUILD_BUG_ON_ZERO(e) (0) -#define BUILD_BUG_ON_NULL(e) ((void*)0) -#define BUILD_BUG_ON(condition) (0) -#else /* __CHECKER__ */ - -/* Force a compilation error if a constant expression is not a power of 2 */ -#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ - BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0)) - -/* Force a compilation error if condition is true, but also produce a - result (of value 0 and type size_t), so the expression can be used - e.g. in a structure initializer (or where-ever else comma expressions - aren't permitted). */ -#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) -#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) - -/* Force a compilation error if condition is true */ -#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) - -#endif - +#include <linux/build_bug.h> #endif /* _LINUX_BUG_H */ diff --git a/include/linux/build_bug.h b/include/linux/build_bug.h new file mode 100644 index 0000000000..43d1fd50d4 --- /dev/null +++ b/include/linux/build_bug.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_BUILD_BUG_H +#define _LINUX_BUILD_BUG_H + +#include <linux/compiler.h> + +#ifdef __CHECKER__ +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) +#define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) +#define BUILD_BUG_ON_ZERO(e) (0) +#define BUILD_BUG_ON_INVALID(e) (0) +#define BUILD_BUG_ON_MSG(cond, msg) (0) +#define BUILD_BUG_ON(condition) (0) +#define BUILD_BUG() (0) +#else /* __CHECKER__ */ + +/* Force a compilation error if a constant expression is not a power of 2 */ +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \ + BUILD_BUG_ON(((n) & ((n) - 1)) != 0) +#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ + BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0)) + +/* + * Force a compilation error if condition is true, but also produce a + * result (of value 0 and type size_t), so the expression can be used + * e.g. in a structure initializer (or where-ever else comma expressions + * aren't permitted). + */ +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); })) + +/* + * BUILD_BUG_ON_INVALID() permits the compiler to check the validity of the + * expression but avoids the generation of any code, even if that expression + * has side-effects. + */ +#define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e)))) + +/** + * BUILD_BUG_ON_MSG - break compile if a condition is true & emit supplied + * error message. + * @condition: the condition which the compiler should know is false. + * + * See BUILD_BUG_ON for description. + */ +#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) + +/** + * BUILD_BUG_ON - break compile if a condition is true. + * @condition: the condition which the compiler should know is false. + * + * If you have some code which relies on certain constants being equal, or + * some other compile-time-evaluated condition, you should use BUILD_BUG_ON to + * detect if someone changes it. + * + * The implementation uses gcc's reluctance to create a negative array, but gcc + * (as of 4.4) only emits that error for obvious cases (e.g. not arguments to + * inline functions). Luckily, in 4.3 they added the "error" function + * attribute just for this type of case. Thus, we use a negative sized array + * (should always create an error on gcc versions older than 4.4) and then call + * an undefined function with the error attribute (should always create an + * error on gcc 4.3 and later). If for some reason, neither creates a + * compile-time error, we'll still have a link-time error, which is harder to + * track down. + */ +#ifndef __OPTIMIZE__ +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +#else +#define BUILD_BUG_ON(condition) \ + BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) +#endif + +/** + * BUILD_BUG - break compile if used. + * + * If you have some code that you expect the compiler to eliminate at + * build time, you should use BUILD_BUG to detect if it is + * unexpectedly used. + */ +#define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed") + +#endif /* __CHECKER__ */ + +#endif /* _LINUX_BUILD_BUG_H */ |