diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile index c183b89..3bf176b 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_MACH_GK802) += gk802/ obj-$(CONFIG_MACH_GLOBALSCALE_GURUPLUG) += globalscale-guruplug/ obj-$(CONFIG_MACH_GLOBALSCALE_MIRABOX) += globalscale-mirabox/ +obj-$(CONFIG_MACH_GRINN_LITEBOARD) += grinn-liteboard/ obj-$(CONFIG_MACH_GUF_CUPID) += guf-cupid/ obj-$(CONFIG_MACH_GUF_SANTARO) += guf-santaro/ obj-$(CONFIG_MACH_GUF_VINCELL) += guf-vincell/ diff --git a/arch/arm/boards/grinn-liteboard/Makefile b/arch/arm/boards/grinn-liteboard/Makefile new file mode 100644 index 0000000..01c7a25 --- /dev/null +++ b/arch/arm/boards/grinn-liteboard/Makefile @@ -0,0 +1,2 @@ +obj-y += board.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/grinn-liteboard/board.c b/arch/arm/boards/grinn-liteboard/board.c new file mode 100644 index 0000000..8e5a91e --- /dev/null +++ b/arch/arm/boards/grinn-liteboard/board.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 Grinn + * + * Author: Marcin Niestroj + * + * 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; version 2. + * + * 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. + */ + +#define pr_fmt(fmt) "liteboard: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void bbu_register_handler_sd(bool is_boot_source) +{ + imx6_bbu_internal_mmc_register_handler("sd", "/dev/mmc0.barebox", + is_boot_source ? BBU_HANDLER_FLAG_DEFAULT : 0); +} + +static void bbu_register_handler_emmc(bool is_boot_source) +{ + int emmc_boot_flag = 0, emmc_flag = 0; + const char *bootpart; + struct device_d *dev; + int ret; + + if (!is_boot_source) + goto bbu_register; + + dev = get_device_by_name("mmc1"); + if (!dev) { + pr_warn("Failed to get eMMC device\n"); + goto bbu_register; + } + + ret = device_detect(dev); + if (ret) { + pr_warn("Failed to probe eMMC\n"); + goto bbu_register; + } + + bootpart = dev_get_param(dev, "boot"); + if (!bootpart) { + pr_warn("Failed to get eMMC boot configuration\n"); + goto bbu_register; + } + + if (!strncmp(bootpart, "boot", 4)) + emmc_boot_flag |= BBU_HANDLER_FLAG_DEFAULT; + else + emmc_flag |= BBU_HANDLER_FLAG_DEFAULT; + +bbu_register: + imx6_bbu_internal_mmc_register_handler("emmc", "/dev/mmc1.barebox", + emmc_flag); + imx6_bbu_internal_mmcboot_register_handler("emmc-boot", "mmc1", + emmc_boot_flag); +} + +static const struct { + const char *name; + const char *env; + void (*bbu_register_handler)(bool); +} boot_sources[] = { + {"SD", "/chosen/environment-sd", bbu_register_handler_sd}, + {"eMMC", "/chosen/environment-emmc", bbu_register_handler_emmc}, +}; + +static int liteboard_devices_init(void) +{ + int boot_source_idx = 0; + int ret; + int i; + + if (!of_machine_is_compatible("grinn,imx6ul-liteboard")) + return 0; + + barebox_set_hostname("liteboard"); + + if (bootsource_get() == BOOTSOURCE_MMC) { + int mmc_idx = bootsource_get_instance(); + + if (0 <= mmc_idx && mmc_idx < ARRAY_SIZE(boot_sources)) + boot_source_idx = mmc_idx; + } + + ret = of_device_enable_path(boot_sources[boot_source_idx].env); + if (ret < 0) + pr_warn("Failed to enable environment partition '%s' (%d)\n", + boot_sources[boot_source_idx].env, ret); + + pr_notice("Using environment in %s\n", + boot_sources[boot_source_idx].name); + + for (i = 0; i < ARRAY_SIZE(boot_sources); i++) + boot_sources[i].bbu_register_handler(boot_source_idx == i); + + return 0; +} +device_initcall(liteboard_devices_init); diff --git a/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg new file mode 100644 index 0000000..1b980c7 --- /dev/null +++ b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg @@ -0,0 +1,6 @@ + +#define SETUP_MDASP_MDCTL \ + wm 32 0x021B0040 0x00000047; \ + wm 32 0x021B0000 0x83180000 + +#include "flash-header-liteboard.h" diff --git a/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg new file mode 100644 index 0000000..c93a2cc --- /dev/null +++ b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg @@ -0,0 +1,6 @@ + +#define SETUP_MDASP_MDCTL \ + wm 32 0x021B0040 0x0000004F; \ + wm 32 0x021B0000 0x84180000 + +#include "flash-header-liteboard.h" diff --git a/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h b/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h new file mode 100644 index 0000000..60a39f5 --- /dev/null +++ b/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h @@ -0,0 +1,68 @@ + +loadaddr 0x80000000 +soc imx6 +dcdofs 0x400 + +wm 32 0x020c4068 0xffffffff +wm 32 0x020c406c 0xffffffff +wm 32 0x020c4070 0xffffffff +wm 32 0x020c4074 0xffffffff +wm 32 0x020c4078 0xffffffff +wm 32 0x020c407c 0xffffffff +wm 32 0x020c4080 0xffffffff + +wm 32 0x020E04B4 0x000C0000 +wm 32 0x020E04AC 0x00000000 +wm 32 0x020E027C 0x00000030 +wm 32 0x020E0250 0x00000030 +wm 32 0x020E024C 0x00000030 +wm 32 0x020E0490 0x00000030 +wm 32 0x020E0288 0x00000030 +wm 32 0x020E0270 0x00000000 +wm 32 0x020E0260 0x00000030 +wm 32 0x020E0264 0x00000030 +wm 32 0x020E04A0 0x00000030 +wm 32 0x020E0494 0x00020000 +wm 32 0x020E0280 0x00000030 +wm 32 0x020E0284 0x00000030 +wm 32 0x020E04B0 0x00020000 +wm 32 0x020E0498 0x00000030 +wm 32 0x020E04A4 0x00000030 +wm 32 0x020E0244 0x00000030 +wm 32 0x020E0248 0x00000030 +wm 32 0x021B001C 0x00008000 +wm 32 0x021B0800 0xA1390003 +wm 32 0x021B080C 0x00000000 +wm 32 0x021B083C 0x41480148 +wm 32 0x021B0848 0x40403E42 +wm 32 0x021B0850 0x40405852 +wm 32 0x021B081C 0x33333333 +wm 32 0x021B0820 0x33333333 +wm 32 0x021B082C 0xf3333333 +wm 32 0x021B0830 0xf3333333 +wm 32 0x021B08C0 0x00922012 +wm 32 0x021B0858 0x00000F00 +wm 32 0x021B08b8 0x00000800 +wm 32 0x021B0004 0x0002002D +wm 32 0x021B0008 0x1B333030 +wm 32 0x021B000C 0x676B52F3 +wm 32 0x021B0010 0xB66D0B63 +wm 32 0x021B0014 0x01FF00DB +wm 32 0x021B0018 0x00211740 +wm 32 0x021B001C 0x00008000 +wm 32 0x021B002C 0x000026D2 +wm 32 0x021B0030 0x006B1023 + +SETUP_MDASP_MDCTL + +wm 32 0x021b0890 0x00400A38 +wm 32 0x021B001C 0x02008032 +wm 32 0x021B001C 0x00008033 +wm 32 0x021B001C 0x00048031 +wm 32 0x021B001C 0x15208030 +wm 32 0x021B001C 0x04008040 +wm 32 0x021B0020 0x00007800 +wm 32 0x021B0818 0x00000227 +wm 32 0x021B0004 0x0002556D +wm 32 0x021B0404 0x00011006 +wm 32 0x021B001C 0x00000000 diff --git a/arch/arm/boards/grinn-liteboard/lowlevel.c b/arch/arm/boards/grinn-liteboard/lowlevel.c new file mode 100644 index 0000000..331ccc2 --- /dev/null +++ b/arch/arm/boards/grinn-liteboard/lowlevel.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 Grinn + * + * Author: Marcin Niestroj + * + * 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; version 2. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void setup_uart(void) +{ + void __iomem *iomuxbase = IOMEM(MX6_IOMUXC_BASE_ADDR); + void __iomem *uart = IOMEM(MX6_UART1_BASE_ADDR); + + relocate_to_current_adr(); + setup_c(); + barrier(); + + imx6_ungate_all_peripherals(); + + writel(0x0, iomuxbase + 0x84); + writel(0x1b0b1, iomuxbase + 0x0310); + + imx6_uart_setup(uart); + + pbl_set_putc(imx_uart_putc, uart); + + putchar('>'); +} + +BAREBOX_IMD_TAG_STRING(liteboard_memsize_SZ_256M, IMD_TYPE_PARAMETER, + "memsize=256", 0); +BAREBOX_IMD_TAG_STRING(liteboard_memsize_SZ_512M, IMD_TYPE_PARAMETER, + "memsize=512", 0); + +extern char __dtb_imx6ul_liteboard_start[]; + +static void __noreturn start_imx6_liteboard(void) +{ + imx6ul_cpu_lowlevel_init(); + + arm_setup_stack(0x00910000 - 8); + + arm_early_mmu_cache_invalidate(); + + if (IS_ENABLED(CONFIG_PBL_CONSOLE)) + setup_uart(); + + imx6ul_barebox_entry(__dtb_imx6ul_liteboard_start + + get_runtime_offset()); +} + +#define LITEBOARD_ENTRY(name, memory_size) \ + ENTRY_FUNCTION(name, r0, r1, r2) \ + { \ + IMD_USED(liteboard_memsize_##memory_size); \ + \ + start_imx6_liteboard(); \ + } + + +LITEBOARD_ENTRY(start_imx6ul_liteboard_256mb, SZ_256M); +LITEBOARD_ENTRY(start_imx6ul_liteboard_512mb, SZ_512M); diff --git a/arch/arm/boards/nxp-imx8mq-evk/board.c b/arch/arm/boards/nxp-imx8mq-evk/board.c index 764eadb..299d056 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/board.c +++ b/arch/arm/boards/nxp-imx8mq-evk/board.c @@ -17,11 +17,12 @@ * */ +#include +#include #include #include -#include -#include #include +#include #include #include @@ -45,25 +46,27 @@ return 0; } -static int imx8mq_evk_mem_init(void) -{ - if (!of_machine_is_compatible("fsl,imx8mq-evk")) - return 0; - - request_sdram_region("ATF", 0x40000000, SZ_128K); - - return 0; -} -mem_initcall(imx8mq_evk_mem_init); - static int nxp_imx8mq_evk_init(void) { + int flags; + if (!of_machine_is_compatible("fsl,imx8mq-evk")) return 0; barebox_set_hostname("imx8mq-evk"); - imx8mq_bbu_internal_mmc_register_handler("eMMC", "/dev/mmc0", 0); + flags = bootsource_get_instance() == 0 ? BBU_HANDLER_FLAG_DEFAULT : 0; + imx8mq_bbu_internal_mmc_register_handler("eMMC", + "/dev/mmc0.barebox", flags); + + flags = bootsource_get_instance() == 1 ? BBU_HANDLER_FLAG_DEFAULT : 0; + imx8mq_bbu_internal_mmc_register_handler("SD", + "/dev/mmc1.barebox", flags); + + if (bootsource_get_instance() == 0) + of_device_enable_path("/chosen/environment-emmc"); + else + of_device_enable_path("/chosen/environment-sd"); phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK, ar8031_phy_fixup); diff --git a/arch/arm/boards/zii-imx51-rdu1/board.c b/arch/arm/boards/zii-imx51-rdu1/board.c index 46368cc..f739f3b 100644 --- a/arch/arm/boards/zii-imx51-rdu1/board.c +++ b/arch/arm/boards/zii-imx51-rdu1/board.c @@ -17,9 +17,16 @@ #include #include +#include #include #include #include +#include +#include +#include +#include + +#include static int zii_rdu1_init(void) { @@ -45,3 +52,175 @@ return 0; } coredevice_initcall(zii_rdu1_init); + +#define KEY 0 +#define VALUE 1 +#define STRINGS_NUM 2 + +static int zii_rdu1_load_config(void) +{ + struct device_node *np, *root; + size_t len, remaining_space; + const uint8_t crc8_polynomial = 0x8c; + DECLARE_CRC8_TABLE(crc8_table); + const char *cursor, *end; + const char *file = "/dev/dataflash0.config"; + uint8_t *config; + int ret = 0; + enum { + BLOB_SPINOR, + BLOB_RAVE_SP_EEPROM, + BLOB_MICROWIRE, + } blob; + + if (!of_machine_is_compatible("zii,imx51-rdu1")) + return 0; + + crc8_populate_lsb(crc8_table, crc8_polynomial); + + for (blob = BLOB_SPINOR; blob <= BLOB_MICROWIRE; blob++) { + switch (blob) { + case BLOB_MICROWIRE: + file = "/dev/microwire-eeprom"; + /* FALLTHROUGH */ + case BLOB_SPINOR: + config = read_file(file, &remaining_space); + if (!config) { + pr_err("Failed to read %s\n", file); + return -EIO; + } + break; + case BLOB_RAVE_SP_EEPROM: + /* Needed for error logging below */ + file = "shadow copy in RAVE SP EEPROM"; + + root = of_get_root_node(); + np = of_find_node_by_name(root, "eeprom@a4"); + if (!np) + return -ENODEV; + + pr_info("Loading %s, this may take a while\n", file); + + remaining_space = SZ_1K; + config = nvmem_cell_get_and_read(np, "shadow-config", + remaining_space); + if (IS_ERR(config)) + return PTR_ERR(config); + + break; + } + + /* + * The environment blob has its CRC8 stored as the + * last byte of the blob, so calculating CRC8 over the + * whole things should return 0 + */ + if (crc8(crc8_table, config, remaining_space, 0)) { + pr_err("CRC mismatch for %s\n", file); + free(config); + config = NULL; + } else { + /* + * We are done if there's a blob with a valid + * CRC8 + */ + break; + } + } + + if (!config) { + pr_err("No valid config blobs were found\n"); + ret = -EINVAL; + goto free_config; + } + + /* + * Last byte is CRC8, so it is of no use for our parsing + * algorithm + */ + remaining_space--; + + cursor = config; + end = cursor + remaining_space; + + /* + * The environemnt is stored a a bunch of zero-terminated + * ASCII strings in "key":"value" pairs + */ + while (cursor < end) { + const char *strings[STRINGS_NUM] = { NULL, NULL }; + char *key; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(strings); i++) { + if (!*cursor) { + /* We assume that last key:value pair + * will be terminated by an extra '\0' + * at the end */ + goto free_config; + } + + len = strnlen(cursor, remaining_space); + if (len >= remaining_space) { + ret = -EOVERFLOW; + goto free_config; + } + + strings[i] = cursor; + + len++; /* Account for '\0' at the end of the string */ + cursor += len; + remaining_space -= len; + + if (cursor > end) { + ret = -EOVERFLOW; + goto free_config; + } + } + + key = basprintf("config_%s", strings[KEY]); + ret = setenv(key, strings[VALUE]); + free(key); + + if (ret) + goto free_config; + } + +free_config: + free(config); + return ret; +} +late_initcall(zii_rdu1_load_config); + +static int zii_rdu1_ethernet_init(void) +{ + const char *mac_string; + struct device_node *np, *root; + uint8_t mac[ETH_ALEN]; + int ret; + + if (!of_machine_is_compatible("zii,imx51-rdu1")) + return 0; + + root = of_get_root_node(); + + np = of_find_node_by_alias(root, "ethernet0"); + if (!np) { + pr_warn("Failed to find ethernet0\n"); + return -ENOENT; + } + + mac_string = getenv("config_mac"); + if (!mac_string) + return -ENOENT; + + ret = string_to_ethaddr(mac_string, mac); + if (ret < 0) + return ret; + + of_eth_register_ethaddr(np, mac); + return 0; +} +/* This needs to happen only after zii_rdu1_load_config was + * executed */ +environment_initcall(zii_rdu1_ethernet_init); diff --git a/arch/arm/boards/zii-imx6q-rdu2/board.c b/arch/arm/boards/zii-imx6q-rdu2/board.c index e174032..6352f49 100644 --- a/arch/arm/boards/zii-imx6q-rdu2/board.c +++ b/arch/arm/boards/zii-imx6q-rdu2/board.c @@ -15,7 +15,9 @@ #include #include +#include #include +#include #include #include #include @@ -99,10 +101,27 @@ static int rdu2_devices_init(void) { + struct i2c_client client; + if (!of_machine_is_compatible("zii,imx6q-zii-rdu2") && !of_machine_is_compatible("zii,imx6qp-zii-rdu2")) return 0; + client.adapter = i2c_get_adapter(1); + if (client.adapter) { + u8 reg; + + /* + * Reset PMIC SW1AB and SW1C rails to 1.375V. If an event + * caused only the i.MX6 SoC reset, the PMIC might still be + * stuck on the low voltage for the slow operating point. + */ + client.addr = 0x08; /* PMIC i2c address */ + reg = 0x2b; /* 1.375V, valid for both rails */ + i2c_write_reg(&client, 0x20, ®, 1); + i2c_write_reg(&client, 0x2e, ®, 1); + } + barebox_set_hostname("rdu2"); imx6_bbu_internal_spi_i2c_register_handler("SPI", "/dev/m25p0.barebox", @@ -170,3 +189,32 @@ return 0; } late_initcall(rdu2_ethernet_init); + +#define I210_CFGWORD_PCIID_157B 0x157b1a11 +static int rdu2_i210_invm(void) +{ + int fd; + u32 val; + + if (!of_machine_is_compatible("zii,imx6q-zii-rdu2") && + !of_machine_is_compatible("zii,imx6qp-zii-rdu2")) + return 0; + + fd = open("/dev/e1000-invm0", O_RDWR); + if (fd < 0) { + pr_err("could not open e1000 iNVM device!\n"); + return fd; + } + + pread(fd, &val, sizeof(val), 0); + if (val == I210_CFGWORD_PCIID_157B) { + pr_debug("i210 already programmed correctly\n"); + return 0; + } + + val = I210_CFGWORD_PCIID_157B; + pwrite(fd, &val, sizeof(val), 0); + + return 0; +} +late_initcall(rdu2_i210_invm); diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 0fc3c9c..bf84dfa 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -41,6 +41,7 @@ CONFIG_MACH_PHYTEC_PHYCORE_IMX7=y CONFIG_MACH_FREESCALE_MX7_SABRESD=y CONFIG_MACH_NXP_IMX6ULL_EVK=y +CONFIG_MACH_GRINN_LITEBOARD=y CONFIG_IMX_IIM=y CONFIG_IMX_IIM_FUSE_BLOW=y CONFIG_THUMB2_BAREBOX=y diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 809ecf6..4ecb3c2 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -27,6 +27,7 @@ pbl-dtb-$(CONFIG_MACH_GK802) += imx6q-gk802.dtb.o pbl-dtb-$(CONFIG_MACH_GLOBALSCALE_GURUPLUG) += kirkwood-guruplug-server-plus-bb.dtb.o pbl-dtb-$(CONFIG_MACH_GLOBALSCALE_MIRABOX) += armada-370-mirabox-bb.dtb.o +pbl-dtb-$(CONFIG_MACH_GRINN_LITEBOARD) += imx6ul-liteboard.dtb.o pbl-dtb-$(CONFIG_MACH_GUF_SANTARO) += imx6q-guf-santaro.dtb.o pbl-dtb-$(CONFIG_MACH_GUF_VINCELL) += imx53-guf-vincell.dtb.o imx53-guf-vincell-lt.dtb.o pbl-dtb-$(CONFIG_MACH_GW_VENTANA) += imx6q-gw54xx.dtb.o diff --git a/arch/arm/dts/imx51-zii-rdu1.dts b/arch/arm/dts/imx51-zii-rdu1.dts index c649db4..01e46ba 100644 --- a/arch/arm/dts/imx51-zii-rdu1.dts +++ b/arch/arm/dts/imx51-zii-rdu1.dts @@ -32,6 +32,7 @@ * fact to create a desirable naming */ switch-eeprom = &switch; + microwire-eeprom = µwire_eeprom; }; }; @@ -64,6 +65,10 @@ switch: switch@0 {}; }; +&spi_gpio { + microwire_eeprom: eeprom@0 {}; +}; + &uart3 { rave-sp { watchdog { @@ -72,9 +77,16 @@ }; eeprom@a4 { + nvmem-cells = <&shadow_config>; + nvmem-cell-names = "shadow-config"; + boot_source: boot-source@83 { reg = <0x83 1>; }; + + shadow_config: shadow-config@1000 { + reg = <0x1000 0x400>; + }; }; }; }; diff --git a/arch/arm/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/dts/imx6qdl-zii-rdu2.dtsi index a3f6dbd..fea219f 100644 --- a/arch/arm/dts/imx6qdl-zii-rdu2.dtsi +++ b/arch/arm/dts/imx6qdl-zii-rdu2.dtsi @@ -116,19 +116,13 @@ }; }; -&pcie { - host@0 { - #address-cells = <3>; - #size-cells = <2>; - reg = <0 0 0 0 0>; - device_type = "pci"; +&i210 { + nvmem-cells = <&mac_address_1>; + nvmem-cell-names = "mac-address"; +}; - i210: i210@0 { - reg = <0 0 0 0 0>; - nvmem-cells = <&mac_address_1>; - nvmem-cell-names = "mac-address"; - }; - }; +&usbotg { + dr_mode = "otg"; }; &gpio3 { diff --git a/arch/arm/dts/imx6ul-liteboard.dts b/arch/arm/dts/imx6ul-liteboard.dts new file mode 100644 index 0000000..03a4bfc --- /dev/null +++ b/arch/arm/dts/imx6ul-liteboard.dts @@ -0,0 +1,96 @@ +/* + * Copyright 2018 Grinn + * + * Author: Marcin Niestroj + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +/ { + chosen { + environment-sd { + compatible = "barebox,environment"; + device-path = &environment_sd; + status = "disabled"; + }; + + environment-emmc { + compatible = "barebox,environment"; + device-path = &environment_emmc; + status = "disabled"; + }; + }; +}; + +&usdhc1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0xe0000>; + }; + + environment_sd: partition@e0000 { + label = "barebox-environment"; + reg = <0xe0000 0x20000>; + }; + }; +}; + +&usdhc2 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0xe0000>; + }; + + environment_emmc: partition@e0000 { + label = "barebox-environment"; + reg = <0xe0000 0x20000>; + }; + }; +}; diff --git a/arch/arm/dts/imx8mq-evk.dts b/arch/arm/dts/imx8mq-evk.dts index a6e724e..56a3517 100644 --- a/arch/arm/dts/imx8mq-evk.dts +++ b/arch/arm/dts/imx8mq-evk.dts @@ -15,6 +15,17 @@ chosen { stdout-path = &uart1; + + environment-emmc { + compatible = "barebox,environment"; + device-path = &usdhc1, "partname:barebox-environment"; + status = "disabled"; + }; + environment-sd { + compatible = "barebox,environment"; + device-path = &usdhc2, "partname:barebox-environment"; + status = "disabled"; + }; }; reg_usdhc2_vmmc: regulator-vsd-3v3 { @@ -177,6 +188,19 @@ no-sd; no-sdio; status = "okay"; + + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0xe0000>; + }; + + partition@e0000 { + label = "barebox-environment"; + reg = <0xe0000 0x20000>; + }; }; &usdhc2 { @@ -190,6 +214,19 @@ cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; vmmc-supply = <®_usdhc2_vmmc>; status = "okay"; + + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0xe0000>; + }; + + partition@e0000 { + label = "barebox-environment"; + reg = <0xe0000 0x20000>; + }; }; &wdog1 { diff --git a/arch/arm/dts/vf610-zii-cfu1.dts b/arch/arm/dts/vf610-zii-cfu1.dts index 1493335..1de9ee9 100644 --- a/arch/arm/dts/vf610-zii-cfu1.dts +++ b/arch/arm/dts/vf610-zii-cfu1.dts @@ -18,4 +18,3 @@ switch-eeprom = &switch0; }; }; - diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 63a92bd..b2b250f 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -413,6 +413,7 @@ bool "ZII i.MX51 RDU1" select ARCH_IMX51 select MACH_FREESCALE_MX51_PDK_POWER + select CRC8 config MACH_ZII_RDU2 bool "ZII i.MX6Q(+) RDU2" @@ -454,6 +455,10 @@ select FIRMWARE_IMX8MQ_ATF select ARM_SMCCC +config MACH_GRINN_LITEBOARD + bool "Grinn liteboard" + select ARCH_IMX6UL + endif # ---------------------------------------------------------- diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 38b6f42..c28a6d4 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -43,4 +43,12 @@ help Say y here to enable Rave SP EEPROM support. +config EEPROM_93XX46 + bool "Microwire EEPROM 93XX46 support" + depends on SPI + help + Driver for the microwire EEPROM chipsets 93xx46x. The driver + supports both read and write commands and also the command to + erase the whole EEPROM. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 716e5db..abf9dae 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -13,4 +13,7 @@ nvmem_ocotp-y := ocotp.o obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o -nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o \ No newline at end of file +nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o + +obj-$(CONFIG_EEPROM_93XX46) += nvmem_eeprom_93xx46.o +nvmem_eeprom_93xx46-y := eeprom_93xx46.o \ No newline at end of file diff --git a/drivers/nvmem/eeprom_93xx46.c b/drivers/nvmem/eeprom_93xx46.c new file mode 100644 index 0000000..d96ba32 --- /dev/null +++ b/drivers/nvmem/eeprom_93xx46.c @@ -0,0 +1,446 @@ +/* + * Driver for 93xx46 EEPROMs + * + * (C) 2011 DENX Software Engineering, Anatolij Gustschin + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define OP_START 0x4 +#define OP_WRITE (OP_START | 0x1) +#define OP_READ (OP_START | 0x2) +#define ADDR_EWDS 0x00 +#define ADDR_ERAL 0x20 +#define ADDR_EWEN 0x30 + +struct eeprom_93xx46_platform_data { + unsigned char flags; +#define EE_ADDR8 0x01 /* 8 bit addr. cfg */ +#define EE_ADDR16 0x02 /* 16 bit addr. cfg */ +#define EE_READONLY 0x08 /* forbid writing */ + + unsigned int quirks; +/* Single word read transfers only; no sequential read. */ +#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0) +/* Instructions such as EWEN are (addrlen + 2) in length. */ +#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH (1 << 1) + + /* + * optional hooks to control additional logic + * before and after spi transfer. + */ + void (*prepare)(void *); + void (*finish)(void *); + int select; +}; + +struct eeprom_93xx46_devtype_data { + unsigned int quirks; +}; + +static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = { + .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ | + EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH, +}; + +struct eeprom_93xx46_dev { + struct spi_device *spi; + struct eeprom_93xx46_platform_data *pdata; + struct nvmem_config nvmem_config; + struct nvmem_device *nvmem; + int addrlen; + int size; +}; + +static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev) +{ + return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ; +} + +static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev) +{ + return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH; +} + +static int eeprom_93xx46_read(struct device_d *dev, int off, + void *val, int count) +{ + struct eeprom_93xx46_dev *edev = dev->parent->priv; + char *buf = val; + int err = 0; + + if (unlikely(off >= edev->size)) + return 0; + if ((off + count) > edev->size) + count = edev->size - off; + if (unlikely(!count)) + return count; + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + while (count) { + struct spi_message m; + struct spi_transfer t[2] = { { 0 } }; + u16 cmd_addr = OP_READ << edev->addrlen; + size_t nbytes = count; + int bits; + + if (edev->addrlen == 7) { + cmd_addr |= off & 0x7f; + bits = 10; + if (has_quirk_single_word_read(edev)) + nbytes = 1; + } else { + cmd_addr |= (off >> 1) & 0x3f; + bits = 9; + if (has_quirk_single_word_read(edev)) + nbytes = 2; + } + + dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n", + cmd_addr, edev->spi->max_speed_hz); + + spi_message_init(&m); + + t[0].tx_buf = (char *)&cmd_addr; + t[0].len = 2; + t[0].bits_per_word = bits; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = count; + t[1].bits_per_word = 8; + spi_message_add_tail(&t[1], &m); + + err = spi_sync(edev->spi, &m); + /* have to wait at least Tcsl ns */ + ndelay(250); + + if (err) { + dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", + nbytes, (int)off, err); + break; + } + + buf += nbytes; + off += nbytes; + count -= nbytes; + } + + if (edev->pdata->finish) + edev->pdata->finish(edev); + + return err; +} + +static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) +{ + struct spi_message m; + struct spi_transfer t; + int bits, ret; + u16 cmd_addr; + + cmd_addr = OP_START << edev->addrlen; + if (edev->addrlen == 7) { + cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; + bits = 10; + } else { + cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); + bits = 9; + } + + if (has_quirk_instruction_length(edev)) { + cmd_addr <<= 2; + bits += 2; + } + + dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n", + is_on ? "en" : "ds", cmd_addr, bits); + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + t.tx_buf = &cmd_addr; + t.len = 2; + t.bits_per_word = bits; + spi_message_add_tail(&t, &m); + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + ret = spi_sync(edev->spi, &m); + /* have to wait at least Tcsl ns */ + ndelay(250); + if (ret) + dev_err(&edev->spi->dev, "erase/write %sable error %d\n", + is_on ? "en" : "dis", ret); + + if (edev->pdata->finish) + edev->pdata->finish(edev); + + return ret; +} + +static ssize_t +eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, + const char *buf, unsigned off) +{ + struct spi_message m; + struct spi_transfer t[2]; + int bits, data_len, ret; + u16 cmd_addr; + + cmd_addr = OP_WRITE << edev->addrlen; + + if (edev->addrlen == 7) { + cmd_addr |= off & 0x7f; + bits = 10; + data_len = 1; + } else { + cmd_addr |= (off >> 1) & 0x3f; + bits = 9; + data_len = 2; + } + + dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = (char *)&cmd_addr; + t[0].len = 2; + t[0].bits_per_word = bits; + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = data_len; + t[1].bits_per_word = 8; + spi_message_add_tail(&t[1], &m); + + ret = spi_sync(edev->spi, &m); + /* have to wait program cycle time Twc ms */ + mdelay(6); + return ret; +} + +static int eeprom_93xx46_write(struct device_d *dev, const int off, + const void *val, int count) +{ + struct eeprom_93xx46_dev *edev = dev->parent->priv; + const char *buf = val; + int i, ret, step = 1; + + if (unlikely(off >= edev->size)) + return -EFBIG; + if ((off + count) > edev->size) + count = edev->size - off; + if (unlikely(!count)) + return count; + + /* only write even number of bytes on 16-bit devices */ + if (edev->addrlen == 6) { + step = 2; + count &= ~1; + } + + /* erase/write enable */ + ret = eeprom_93xx46_ew(edev, 1); + if (ret) + return ret; + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + for (i = 0; i < count; i += step) { + ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); + if (ret) { + dev_err(&edev->spi->dev, "write failed at %d: %d\n", + (int)off + i, ret); + break; + } + } + + if (edev->pdata->finish) + edev->pdata->finish(edev); + + /* erase/write disable */ + eeprom_93xx46_ew(edev, 0); + return ret; +} + +static void select_assert(void *context) +{ + struct eeprom_93xx46_dev *edev = context; + + if (gpio_is_valid(edev->pdata->select)) + gpio_set_active(edev->pdata->select, true); +} + +static void select_deassert(void *context) +{ + struct eeprom_93xx46_dev *edev = context; + + if (gpio_is_valid(edev->pdata->select)) + gpio_set_active(edev->pdata->select, false); +} + +static const struct of_device_id eeprom_93xx46_of_table[] = { + { .compatible = "eeprom-93xx46", }, + { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, }, + {} +}; + +static int eeprom_93xx46_probe_dt(struct spi_device *spi) +{ + const struct of_device_id *of_id = + of_match_device(eeprom_93xx46_of_table, &spi->dev); + struct device_node *np = spi->dev.device_node; + struct eeprom_93xx46_platform_data *pd; + enum of_gpio_flags of_flags; + unsigned long flags = GPIOF_OUT_INIT_INACTIVE; + u32 tmp; + int ret; + + pd = xzalloc(sizeof(*pd)); + + ret = of_property_read_u32(np, "data-size", &tmp); + if (ret < 0) { + dev_err(&spi->dev, "data-size property not found\n"); + return ret; + } + + if (tmp == 8) { + pd->flags |= EE_ADDR8; + } else if (tmp == 16) { + pd->flags |= EE_ADDR16; + } else { + dev_err(&spi->dev, "invalid data-size (%d)\n", tmp); + return -EINVAL; + } + + if (of_property_read_bool(np, "read-only")) + pd->flags |= EE_READONLY; + + pd->select =of_get_named_gpio_flags(np, "select", 0, &of_flags); + if (gpio_is_valid(pd->select)) { + char *name; + + if (of_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + + name = basprintf("%s select", dev_name(&spi->dev)); + ret = gpio_request_one(pd->select, flags, name); + if (ret < 0) + return ret; + } + + pd->prepare = select_assert; + pd->finish = select_deassert; + + if (gpio_is_valid(pd->select)) + gpio_set_active(pd->select, false); + + if (of_id->data) { + const struct eeprom_93xx46_devtype_data *data = of_id->data; + + pd->quirks = data->quirks; + } + + spi->dev.platform_data = pd; + + return 0; +} + +static const struct nvmem_bus eeprom_93xx46_nvmem_bus = { + .write = eeprom_93xx46_write, + .read = eeprom_93xx46_read, +}; + +static int eeprom_93xx46_probe(struct device_d *dev) +{ + struct spi_device *spi = (struct spi_device *)dev->type_data; + struct eeprom_93xx46_platform_data *pd; + struct eeprom_93xx46_dev *edev; + int err; + + if (dev->device_node) { + err = eeprom_93xx46_probe_dt(spi); + if (err < 0) + return err; + } + + pd = spi->dev.platform_data; + if (!pd) { + dev_err(&spi->dev, "missing platform data\n"); + return -ENODEV; + } + + edev = xzalloc(sizeof(*edev)); + + if (pd->flags & EE_ADDR8) + edev->addrlen = 7; + else if (pd->flags & EE_ADDR16) + edev->addrlen = 6; + else { + dev_err(&spi->dev, "unspecified address type\n"); + err = -EINVAL; + goto fail; + } + + edev->spi = spi; + edev->pdata = pd; + + edev->size = 128; + edev->nvmem_config.name = dev_name(&spi->dev); + edev->nvmem_config.dev = &spi->dev; + edev->nvmem_config.read_only = pd->flags & EE_READONLY; + edev->nvmem_config.bus = &eeprom_93xx46_nvmem_bus; + edev->nvmem_config.stride = 4; + edev->nvmem_config.word_size = 1; + edev->nvmem_config.size = edev->size; + + dev->priv = edev; + + edev->nvmem = nvmem_register(&edev->nvmem_config); + if (IS_ERR(edev->nvmem)) { + err = PTR_ERR(edev->nvmem); + goto fail; + } + + dev_info(&spi->dev, "%d-bit eeprom %s\n", + (pd->flags & EE_ADDR8) ? 8 : 16, + (pd->flags & EE_READONLY) ? "(readonly)" : ""); + + return 0; +fail: + kfree(edev); + return err; +} + +static struct driver_d eeprom_93xx46_driver = { + .name = "93xx46", + .probe = eeprom_93xx46_probe, + .of_compatible = DRV_OF_COMPAT(eeprom_93xx46_of_table), +}; +device_spi_driver(eeprom_93xx46_driver); + + + diff --git a/images/Makefile.imx b/images/Makefile.imx index 341ce85..9b5cd57 100644 --- a/images/Makefile.imx +++ b/images/Makefile.imx @@ -486,6 +486,16 @@ FILE_barebox-imx6dl-samx6i.img = start_imx6dl_samx6i.pblx.imximg image-$(CONFIG_MACH_KONTRON_SAMX6I) += barebox-imx6dl-samx6i.img +pblx-$(CONFIG_MACH_GRINN_LITEBOARD) += start_imx6ul_liteboard_256mb +CFG_start_imx6ul_liteboard_256mb.pblx.imximg = $(board)/grinn-liteboard/flash-header-liteboard-256mb.imxcfg +FILE_barebox-grinn-liteboard-256mb.img = start_imx6ul_liteboard_256mb.pblx.imximg +image-$(CONFIG_MACH_GRINN_LITEBOARD) += barebox-grinn-liteboard-256mb.img + +pblx-$(CONFIG_MACH_GRINN_LITEBOARD) += start_imx6ul_liteboard_512mb +CFG_start_imx6ul_liteboard_512mb.pblx.imximg = $(board)/grinn-liteboard/flash-header-liteboard-512mb.imxcfg +FILE_barebox-grinn-liteboard-512mb.img = start_imx6ul_liteboard_512mb.pblx.imximg +image-$(CONFIG_MACH_GRINN_LITEBOARD) += barebox-grinn-liteboard-512mb.img + pblx-$(CONFIG_MACH_GW_VENTANA) += start_imx6q_gw54xx_1gx64 CFG_start_imx6q_gw54xx_1gx64.pblx.imximg = $(board)/gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg FILE_barebox-gateworks-imx6q-ventana-1gx64.img = start_imx6q_gw54xx_1gx64.pblx.imximg diff --git a/include/linux/crc8.h b/include/linux/crc8.h new file mode 100644 index 0000000..13c8dab --- /dev/null +++ b/include/linux/crc8.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __CRC8_H_ +#define __CRC8_H_ + +#include + +/* see usage of this value in crc8() description */ +#define CRC8_INIT_VALUE 0xFF + +/* + * Return value of crc8() indicating valid message+crc. This is true + * if a CRC is inverted before transmission. The CRC computed over the + * whole received bitstream is _table[x], where x is the bit pattern + * of the modification (almost always 0xff). + */ +#define CRC8_GOOD_VALUE(_table) (_table[0xFF]) + +/* required table size for crc8 algorithm */ +#define CRC8_TABLE_SIZE 256 + +/* helper macro assuring right table size is used */ +#define DECLARE_CRC8_TABLE(_table) \ + static u8 _table[CRC8_TABLE_SIZE] + +/** + * crc8_populate_lsb - fill crc table for given polynomial in regular bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + * + * This function fills the provided table according the polynomial provided for + * regular bit order (lsb first). Polynomials in CRC algorithms are typically + * represented as shown below. + * + * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1 + * + * For lsb first direction x^7 maps to the lsb. So the polynomial is as below. + * + * - lsb first: poly = 10101011(1) = 0xAB + */ +void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial); + +/** + * crc8_populate_msb - fill crc table for given polynomial in reverse bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + * + * This function fills the provided table according the polynomial provided for + * reverse bit order (msb first). Polynomials in CRC algorithms are typically + * represented as shown below. + * + * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1 + * + * For msb first direction x^7 maps to the msb. So the polynomial is as below. + * + * - msb first: poly = (1)11010101 = 0xD5 + */ +void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial); + +/** + * crc8() - calculate a crc8 over the given input data. + * + * @table: crc table used for calculation. + * @pdata: pointer to data buffer. + * @nbytes: number of bytes in data buffer. + * @crc: previous returned crc8 value. + * + * The CRC8 is calculated using the polynomial given in crc8_populate_msb() + * or crc8_populate_lsb(). + * + * The caller provides the initial value (either %CRC8_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When validating a byte + * stream (including CRC8), a final return value of %CRC8_GOOD_VALUE + * indicates the byte stream data can be considered valid. + * + * Reference: + * "A Painless Guide to CRC Error Detection Algorithms", ver 3, Aug 1993 + * Williams, Ross N., rossross.net + * (see URL http://www.ross.net/crc/download/crc_v3.txt). + */ +u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc); + +#endif /* __CRC8_H_ */ diff --git a/lib/Kconfig b/lib/Kconfig index 860d471..67680ad 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -118,6 +118,13 @@ the kernel tree does. Such modules that use library CRC-CCITT functions require M here. +config CRC8 + bool "CRC8 function" + help + This option provides CRC8 function. Drivers may select this + when they need to do cyclic redundancy check according CRC8 + algorithm. Module will be called crc8. + source lib/gui/Kconfig source lib/fonts/Kconfig diff --git a/lib/Makefile b/lib/Makefile index 24dc3d9..8ece2c2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -66,6 +66,7 @@ obj-y += parseopt.o obj-y += clz_ctz.o obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o +obj-$(CONFIG_CRC8) += crc8.o # GCC library routines obj-$(CONFIG_GENERIC_LIB_ASHLDI3) += ashldi3.o diff --git a/lib/crc8.c b/lib/crc8.c new file mode 100644 index 0000000..a89160b --- /dev/null +++ b/lib/crc8.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include + +/** + * crc8_populate_msb - fill crc table for given polynomial in reverse bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + */ +void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial) +{ + int i, j; + const u8 msbit = 0x80; + u8 t = msbit; + + table[0] = 0; + + for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) { + t = (t << 1) ^ (t & msbit ? polynomial : 0); + for (j = 0; j < i; j++) + table[i+j] = table[j] ^ t; + } +} +EXPORT_SYMBOL(crc8_populate_msb); + +/** + * crc8_populate_lsb - fill crc table for given polynomial in regular bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + */ +void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial) +{ + int i, j; + u8 t = 1; + + table[0] = 0; + + for (i = (CRC8_TABLE_SIZE >> 1); i; i >>= 1) { + t = (t >> 1) ^ (t & 1 ? polynomial : 0); + for (j = 0; j < CRC8_TABLE_SIZE; j += 2*i) + table[i+j] = table[j] ^ t; + } +} +EXPORT_SYMBOL(crc8_populate_lsb); + +/** + * crc8 - calculate a crc8 over the given input data. + * + * @table: crc table used for calculation. + * @pdata: pointer to data buffer. + * @nbytes: number of bytes in data buffer. + * @crc: previous returned crc8 value. + */ +u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc) +{ + /* loop over the buffer data */ + while (nbytes-- > 0) + crc = table[(crc ^ *pdata++) & 0xff]; + + return crc; +} +EXPORT_SYMBOL(crc8); + +MODULE_DESCRIPTION("CRC8 (by Williams, Ross N.) function"); +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index 88e2cb9..fa93e47 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -894,6 +894,12 @@ if (cpu_is_aarch64(&data)) { bb_header = bb_header_aarch64; sizeof_bb_header = sizeof(bb_header_aarch64); + /* + * Compute jump offset, must be done dynamically as the code + * location changes depending on the presence of a signed HDMI + * firmware. + */ + data.first_opcode |= (data.header_gap + header_len) >> 2; } else { bb_header = bb_header_aarch32; sizeof_bb_header = sizeof(bb_header_aarch32); diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index 2341732..43f67da 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -243,7 +243,7 @@ { .name = "imx53", .header_version = 2, .cpu_type = IMX_CPU_IMX53, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, { .name = "imx6", .header_version = 2, .cpu_type = IMX_CPU_IMX6, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, { .name = "imx7", .header_version = 2, .cpu_type = IMX_CPU_IMX7, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, - { .name = "imx8mq", .header_version = 2, .cpu_type = IMX_CPU_IMX8MQ, .header_gap = SZ_32K, .first_opcode = 0x14009000 /* b 0x9000 */}, + { .name = "imx8mq", .header_version = 2, .cpu_type = IMX_CPU_IMX8MQ, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, { .name = "vf610", .header_version = 2, .cpu_type = IMX_CPU_VF610, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, };