diff options
113 files changed, 3279 insertions, 454 deletions
diff --git a/Documentation/boards/imx/embest-i.mx6s-riotboard.rst b/Documentation/boards/imx/embest-i.mx6s-riotboard.rst new file mode 100644 index 0000000000..9157f53c2a --- /dev/null +++ b/Documentation/boards/imx/embest-i.mx6s-riotboard.rst @@ -0,0 +1,133 @@ +Embest RIoTboard +================ + +RIoTboard Standard kit +---------------------- + +http://www.embest-tech.com/prod_view.aspx?TypeId=74&Id=345&FId=t3:74:3 + +General Features: + * Product Dimensions: 75mm x 120mm + * Operating Temperature: 0 ~ 50℃ + * Operating Humidity: 20% ~ 90% (non-condensing) + * DC-in:5V/4A + +Processor: + * i.MX 6Solo based on ARM Cortex™-A9 + * 32 Kbyte L1 instruction buffer + * 32 Kbyte L1 data buffer + * Private counter and watchdog + * Cortex-A9 NEON MPE (media processing engine) coprocessor + +On-Board Memories: + * 4GByte eMMC + * 2*512MB DDR3 SDRAM + +One-Board Interfaces/Buttons: + + * Audio input/output interfaces + * A LVDS interface + * A HDMI interface + * A LCD display interface (expansion interface) + * A digital camera interface + * A MIPI interface + * 4 TTL-level serial interfaces (one for debugging, the rest for expansion) + * 4 high-speed USB2.0 host interfaces (480Mbps) + * A high-speed USB2.0 OTG interface (480Mbps) + * A SD card slot + * A TF card slot + * A 10/100M/1Gbps RJ45 interface + * 2 I2C interfaces (expansion interfaces) + * 2 SPI interfaces (expansion interfaces) + * 3 PWM interfaces (expansion interfaces) + * A GPIO interface (expansion interfaces) + * A JTAG interface + * A boot-mode switch + * 4 LEDs (1 system LED, 2 custom LED, 1 open SDA LED) + * A reset button + +How to build barebox for Embest RIoTboard +----------------------------------------- + +Using the default configuration: + +.. code-block:: sh + + make ARCH=arm imx_v7_defconfig + +Build the binary image: + +.. code-block:: sh + + make ARCH=arm CROSS_COMPILE=armv7compiler + +.. note:: replace ``armv7compiler`` with your ARM v7 cross compiler prefix, + e.g.: ``arm-linux-gnueabihf-`` + +The resulting binary image to be flashed will be ``images/barebox-embest-imx6s-riotboard.img``. + +Replacing U-Boot with barebox +----------------------------- + + 1. Connect to the boards's UART (115200 8N1); + + 2. Turn board's power on; + + 3. Wait ``Hit any key to stop autoboot: 2`` prompt and press any key; + + 4. Upload barebox image to the board via tftp and start it + +.. code-block:: none + + MX6Solo RIoTboard U-Boot > setenv ethaddr d2:2d:ce:88:f4:f1 + MX6Solo RIoTboard U-Boot > tftpboot 0x20800000 192.168.23.4:ore-barebox-riotboard + ----phy_addr=0x4, id= 0x4dd072 + FEC: Link is Up 796d + Using FEC0 device + TFTP from server 192.168.23.4; our IP address is 192.168.1.103 + Filename 'ore-barebox-riotboard'. + Load address: 0x20800000 + Loading: ## Warning: gatewayip needed but not set + ## Warning: gatewayip needed but not set + ############################################ + done + Bytes transferred = 637947 (9bbfb hex) + MX6Solo RIoTboard U-Boot > go 0x20800000 + + ## Starting application at 0x20800000 ... + + barebox 2019.04.0-00151-g86762248de #391 Mon Apr 29 14:41:58 CEST 2019 + + Board: RIoTboard i.MX6S + detected i.MX6 Solo revision 1.1 + i.MX reset reason POR (SRSR: 0x00000001) + mdio_bus: miibus0: probed + imx-usb 2184200.usb@2184200.of: USB EHCI 1.00 + imx-esdhc 2194000.usdhc@2194000.of: registered as mmc1 + imx-esdhc 2198000.usdhc@2198000.of: registered as mmc2 + imx-esdhc 219c000.usdhc@219c000.of: registered as mmc3 + imx-ipuv3 2400000.ipu@2400000.of: IPUv3H probed + imx-hdmi 120000.hdmi@120000.of: Detected HDMI controller 0x13:0x1a:0xa0:0xc1 + netconsole: registered as netconsole-1 + malloc space: 0x2fefb5e0 -> 0x4fdf6bbf (size 511 MiB) + mmc3: detected MMC card version 4.41 + mmc3: registered mmc3.boot0 + mmc3: registered mmc3.boot1 + mmc3: registered mmc3 + partition mmc3.3 not completely inside device mmc3 + mmc3: Failed to register partition 3 on mmc3 (-22) + envfs: no envfs (magic mismatch) - envfs never written? + running /env/bin/init... + + Hit m for menu or any key to stop autoboot: 2 + + type exit to get to the menu + barebox@RIoTboard i.MX6S:/ +.. + + 5. Install barebox to the eMMC + +.. code-block:: none + + barebox@RIoTboard i.MX6S:/ cp /mnt/tftp/ore-barebox-riotboard /dev/mmc3.barebox +.. @@ -1,5 +1,5 @@ VERSION = 2019 -PATCHLEVEL = 04 +PATCHLEVEL = 05 SUBLEVEL = 0 EXTRAVERSION = NAME = None diff --git a/arch/arm/boards/ls1046ardb/lowlevel.c b/arch/arm/boards/ls1046ardb/lowlevel.c index 6de16063a7..0c95fbb035 100644 --- a/arch/arm/boards/ls1046ardb/lowlevel.c +++ b/arch/arm/boards/ls1046ardb/lowlevel.c @@ -3,6 +3,7 @@ #include <common.h> #include <debug_ll.h> #include <ddr_spd.h> +#include <image-metadata.h> #include <platform_data/mmc-esdhc-imx.h> #include <i2c/i2c-early.h> #include <soc/fsl/fsl_ddr_sdram.h> @@ -201,6 +202,8 @@ static noinline __noreturn void ls1046ardb_r_entry(unsigned long memsize) debug_ll_init(); ls1046a_init_lowlevel(); + IMD_USED_OF(fsl_ls1046a_rdb); + i2c = ls1046_i2c_init(IOMEM(LSCH2_I2C1_BASE_ADDR)); ret = spd_read_eeprom(i2c, i2c_fsl_xfer, 0x51, &spd_eeprom); if (ret) { diff --git a/arch/arm/boards/tqmls1046a/board.c b/arch/arm/boards/tqmls1046a/board.c index 5d6d5ad62c..8cc4d73de5 100644 --- a/arch/arm/boards/tqmls1046a/board.c +++ b/arch/arm/boards/tqmls1046a/board.c @@ -3,10 +3,15 @@ #include <common.h> #include <init.h> #include <envfs.h> +#include <bbu.h> +#include <bootsource.h> #include <asm/memory.h> #include <linux/sizes.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <soc/fsl/immap_lsch2.h> +#include <mach/bbu.h> +#include <mach/layerscape.h> static int tqmls1046a_mem_init(void) { @@ -21,11 +26,39 @@ mem_initcall(tqmls1046a_mem_init); static int tqmls1046a_postcore_init(void) { + struct ccsr_scfg *scfg = IOMEM(LSCH2_SCFG_ADDR); + enum bootsource bootsource; + unsigned long sd_bbu_flags = 0, qspi_bbu_flags = 0; + if (!of_machine_is_compatible("tqc,tqmls1046a")) return 0; defaultenv_append_directory(defaultenv_tqmls1046a); + /* Configure iomux for i2c4 */ + out_be32(&scfg->rcwpmuxcr0, 0x3300); + + /* divide CGA1/CGA2 PLL by 24 to get QSPI interface clock */ + out_be32(&scfg->qspi_cfg, 0x30100000); + + bootsource = ls1046_bootsource_get(); + + switch (bootsource) { + case BOOTSOURCE_MMC: + of_device_enable_path("/chosen/environment-sd"); + sd_bbu_flags = BBU_HANDLER_FLAG_DEFAULT; + break; + case BOOTSOURCE_SPI_NOR: + of_device_enable_path("/chosen/environment-qspi"); + qspi_bbu_flags = BBU_HANDLER_FLAG_DEFAULT; + break; + default: + break; + } + + ls1046a_bbu_mmc_register_handler("sd", "/dev/mmc0.barebox", sd_bbu_flags); + ls1046a_bbu_qspi_register_handler("qspi", "/dev/qspiflash0.barebox", qspi_bbu_flags); + return 0; } diff --git a/arch/arm/boards/tqmls1046a/lowlevel.c b/arch/arm/boards/tqmls1046a/lowlevel.c index 044d6a418d..dc0e179694 100644 --- a/arch/arm/boards/tqmls1046a/lowlevel.c +++ b/arch/arm/boards/tqmls1046a/lowlevel.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include <common.h> #include <debug_ll.h> +#include <image-metadata.h> #include <platform_data/mmc-esdhc-imx.h> #include <soc/fsl/fsl_ddr_sdram.h> #include <soc/fsl/immap_lsch2.h> @@ -116,7 +117,7 @@ found: DDR_CDR2_VREF_TRAIN_EN | DDR_CDR2_VREF_RANGE_2; /* optimize cpo for erratum A-009942 */ - popts->cpo_sample = 0x61; + popts->cpo_sample = 0x48; } static struct dimm_params dimm_params[] = { @@ -169,37 +170,97 @@ static struct fsl_ddr_controller ddrc[] = { .erratum_A009942 = 1, .chip_selects_per_ctrl = 4, .board_options = ddr_board_options, + .fsl_ddr_config_reg = { + .cs[0].bnds = 0x0000007F, + .cs[0].config = 0x80010312, + .cs[0].config_2 = 0x00000000, + .cs[1].bnds = 0x00000000, + .cs[1].config = 0x00000000, + .cs[1].config_2 = 0x00000000, + .cs[2].bnds = 0x00000000, + .cs[2].config = 0x00000000, + .cs[2].config_2 = 0x00000000, + .cs[3].bnds = 0x00000000, + .cs[3].config = 0x00000000, + .cs[3].config_2 = 0x00000000, + .timing_cfg_3 = 0x020F1100, + .timing_cfg_0 = 0x77660008, + .timing_cfg_1 = 0xF1FCC265, + .timing_cfg_2 = 0x0059415E, + .ddr_sdram_cfg = 0x65000000, + .ddr_sdram_cfg_2 = 0x00401150, + .ddr_sdram_cfg_3 = 0x00000000, + .ddr_sdram_mode = 0x03010625, + .ddr_sdram_mode_2 = 0x00100200, + .ddr_sdram_mode_3 = 0x00010625, + .ddr_sdram_mode_4 = 0x00100200, + .ddr_sdram_mode_5 = 0x00010625, + .ddr_sdram_mode_6 = 0x00100200, + .ddr_sdram_mode_7 = 0x00010625, + .ddr_sdram_mode_8 = 0x00100200, + .ddr_sdram_mode_9 = 0x00000500, + .ddr_sdram_mode_10 = 0x04400000, + .ddr_sdram_mode_11 = 0x00000400, + .ddr_sdram_mode_12 = 0x04400000, + .ddr_sdram_mode_13 = 0x00000400, + .ddr_sdram_mode_14 = 0x04400000, + .ddr_sdram_mode_15 = 0x00000400, + .ddr_sdram_mode_16 = 0x04400000, + .ddr_sdram_interval = 0x0F3C0000, + .ddr_data_init = 0xDEADBEEF, + .ddr_sdram_clk_cntl = 0x02000000, + .ddr_init_addr = 0x00000000, + .ddr_init_ext_addr = 0x00000000, + .timing_cfg_4 = 0x00224002, + .timing_cfg_5 = 0x04401400, + .timing_cfg_6 = 0x00000000, + .timing_cfg_7 = 0x25500000, + .timing_cfg_8 = 0x03335A00, + .timing_cfg_9 = 0x00000000, + .ddr_zq_cntl = 0x8A090705, + .ddr_wrlvl_cntl = 0x86550609, + .ddr_wrlvl_cntl_2 = 0x09080806, + .ddr_wrlvl_cntl_3 = 0x06040409, + .ddr_sr_cntr = 0x00000000, + .ddr_sdram_rcw_1 = 0x00000000, + .ddr_sdram_rcw_2 = 0x00000000, + .ddr_sdram_rcw_3 = 0x00000000, + .ddr_cdr1 = 0x80080000, + .ddr_cdr2 = 0x000000C0, + .dq_map_0 = 0x00000000, + .dq_map_1 = 0x00000000, + .dq_map_2 = 0x00000000, + .dq_map_3 = 0x00000000, + .debug[28] = 0x00700046, + }, }, }; -static struct fsl_ddr_info ls1046a_info = { - .num_ctrls = ARRAY_SIZE(ddrc), - .c = ddrc, -}; - extern char __dtb_fsl_tqmls1046a_mbls10xxa_start[]; -static noinline __noreturn void tqmls1046a_r_entry(unsigned long memsize) +static noinline __noreturn void tqmls1046a_r_entry(void) { unsigned long membase = LS1046A_DDR_SDRAM_BASE; - if (get_pc() >= membase) { - if (memsize + membase >= 0x100000000) - memsize = 0x100000000 - membase; - + if (get_pc() >= membase) barebox_arm_entry(membase, 0x80000000, __dtb_fsl_tqmls1046a_mbls10xxa_start); - } arm_cpu_lowlevel_init(); - debug_ll_init(); ls1046a_init_lowlevel(); - memsize = fsl_ddr_sdram(&ls1046a_info); + debug_ll_init(); + + udelay(500); + putc_ll('>'); + + IMD_USED_OF(fsl_tqmls1046a_mbls10xxa); + + fsl_ddr_set_memctl_regs(&ddrc[0], 0); ls1046a_errata_post_ddr(); - ls1046a_esdhc_start_image(memsize, 0, 0); + ls1046a_xload_start_image(0, 0, 0); pr_err("Booting failed\n"); @@ -213,5 +274,5 @@ __noreturn void tqmls1046a_entry(unsigned long r0, unsigned long r1, unsigned lo relocate_to_current_adr(); setup_c(); - tqmls1046a_r_entry(r0); + tqmls1046a_r_entry(); } diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_pbi_sd.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg index 7ac1398123..0a04afa770 100644 --- a/arch/arm/boards/tqmls1046a/tqmls1046a_pbi_sd.cfg +++ b/arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg @@ -1,3 +1,5 @@ +#Configure QSPI clock +0957015c 40100000 #Configure Scratch register 09570600 00000000 09570604 10000000 diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_pbi_qspi.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_pbi_qspi.cfg deleted file mode 100644 index 32865ca2d0..0000000000 --- a/arch/arm/boards/tqmls1046a/tqmls1046a_pbi_qspi.cfg +++ /dev/null @@ -1,33 +0,0 @@ -#Configure QSPI clock -0957015c 40100000 -#Configure Scratch register -09570600 00000000 -09570604 40010000 -#Disable CCI barrier tranaction -09570178 0000e010 -09180000 00000008 -#USB PHY frequency sel -09570418 0000009c -0957041c 0000009c -09570420 0000009c -#Serdes SATA -09eb1300 80104e20 -09eb08dc 00502880 -#PEX gen3 link (errata A-010477) -09570158 00000300 -89400890 01048000 -89500890 01048000 -89600890 01048000 -#PEX gen3 equalization preset values (errata A-008851) -894008bc 01000000 -89400154 47474747 -89400158 47474747 -894008bc 00000000 -895008bc 01000000 -89500154 47474747 -89500158 47474747 -895008bc 00000000 -896008bc 01000000 -89600154 47474747 -89600158 47474747 -896008bc 00000000 diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_emmc_3333_5559.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_emmc_3333_5559.cfg deleted file mode 100644 index 6c72d001c3..0000000000 --- a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_emmc_3333_5559.cfg +++ /dev/null @@ -1,84 +0,0 @@ -# RCW values -# 0: 1 - SYS_PLL_CFG : 0 [0x0 / 0b00] -# 2: 6 - SYS_PLL_RAT : 6 [0x6 / 0b00110] -# 8: 9 - MEM_PLL_CFG : 0 [0x0 / 0b00] -# 10: 15 - MEM_PLL_RAT : 20 [0x14 / 0b010100] -# 24: 25 - CGA_PLL1_CFG : 0 [0x0 / 0b00] -# 26: 31 - CGA_PLL1_RAT : 16 [0x10 / 0b010000] -# 32: 33 - CGA_PLL2_CFG : 0 [0x0 / 0b00] -# 34: 39 - CGA_PLL2_RAT : 14 [0xe / 0b001110] -# 96: 99 - C1_PLL_SEL : 0 [0x0 / 0b0000] -# 128:143 - SRDS_PRTCL_S1 : 13107 [0x3333 / 0b0011001100110011] -# 144:159 - SRDS_PRTCL_S2 : 21849 [0x5559 / 0b0101010101011001] -# 160:161 - SRDS_PLL_REF_CLK_SEL_S1 : 3 [0x3 / 0b11] -# 162:163 - SRDS_PLL_REF_CLK_SEL_S2 : 3 [0x3 / 0b11] -# 168:169 - SRDS_PLL_PD_S1 : 0 [0x0 / 0b00] -# 170:171 - SRDS_PLL_PD_S2 : 0 [0x0 / 0b00] -# 176:177 - SRDS_DIV_PEX_S1 : 1 [0x1 / 0b01] -# 178:179 - SRDS_DIV_PEX_S2 : 1 [0x1 / 0b01] -# 186:187 - DDR_REFCLK_SEL : 0 [0x0 / 0b00] -# 188:188 - SRDS_REFCLK_SEL_S1 : 0 [0x0 / 0b0] -# 189:189 - SRDS_REFCLK_SEL_S2 : 0 [0x0 / 0b0] -# 190:191 - DDR_FDBK_MULT : 2 [0x2 / 0b10] -# 192:195 - PBI_SRC : 6 [0x6 / 0b0110] -# 201:201 - BOOT_HO : 0 [0x0 / 0b0] -# 202:202 - SB_EN : 0 [0x0 / 0b0] -# 203:211 - IFC_MODE : 64 [0x40 / 0b001000000] -# 224:226 - HWA_CGA_M1_CLK_SEL : 6 [0x6 / 0b110] -# 230:231 - DRAM_LAT : 1 [0x1 / 0b01] -# 232:232 - DDR_RATE : 0 [0x0 / 0b0] -# 234:234 - DDR_RSV0 : 0 [0x0 / 0b0] -# 242:242 - SYS_PLL_SPD : 0 [0x0 / 0b0] -# 243:243 - MEM_PLL_SPD : 0 [0x0 / 0b0] -# 244:244 - CGA_PLL1_SPD : 0 [0x0 / 0b0] -# 245:245 - CGA_PLL2_SPD : 0 [0x0 / 0b0] -# 264:266 - HOST_AGT_PEX : 0 [0x0 / 0b000] -# 288:295 - GP_INFO1 : 0 [0x00 / 0b00000000] -# 299:319 - GP_INFO2 : 0 [0x00000 / 0b000000000000000000000] -# 354:356 - UART_EXT : 0 [0x0 / 0b000] -# 357:359 - IRQ_EXT : 0 [0x0 / 0b000] -# 360:362 - SPI_EXT : 0 [0x0 / 0b000] -# 363:365 - SDHC_EXT : 0 [0x0 / 0b000] -# 366:368 - UART_BASE : 5 [0x5 / 0b101] -# 369:369 - ASLEEP : 0 [0x0 / 0b0] -# 370:370 - RTC : 0 [0x0 / 0b0] -# 371:371 - SDHC_BASE : 0 [0x0 / 0b0] -# 372:372 - IRQ_OUT : 1 [0x1 / 0b1] -# 373:381 - IRQ_BASE : 0 [0x00 / 0b000000000] -# 382:383 - SPI_BASE : 0 [0x0 / 0b00] -# 384:386 - IFC_GRP_A_EXT : 1 [0x1 / 0b001] -# 393:395 - IFC_GRP_D_EXT : 0 [0x0 / 0b000] -# 396:398 - IFC_GRP_E1_EXT : 0 [0x0 / 0b000] -# 399:401 - IFC_GRP_F_EXT : 1 [0x1 / 0b001] -# 405:405 - IFC_GRP_E1_BASE : 0 [0x0 / 0b0] -# 407:407 - IFC_GRP_D_BASE : 0 [0x0 / 0b0] -# 412:413 - IFC_GRP_A_BASE : 0 [0x0 / 0b00] -# 415:415 - IFC_A_22_24 : 0 [0x0 / 0b0] -# 416:418 - EC1 : 0 [0x0 / 0b000] -# 419:421 - EC2 : 0 [0x0 / 0b000] -# 422:423 - LVDD_VSEL : 1 [0x1 / 0b01] -# 424:424 - I2C_IPGCLK_SEL : 0 [0x0 / 0b0] -# 425:425 - EM1 : 0 [0x0 / 0b0] -# 426:426 - EM2 : 0 [0x0 / 0b0] -# 427:427 - EMI2_DMODE : 1 [0x1 / 0b1] -# 428:428 - EMI2_CMODE : 0 [0x0 / 0b0] -# 429:429 - USB_DRVVBUS : 0 [0x0 / 0b0] -# 430:430 - USB_PWRFAULT : 0 [0x0 / 0b0] -# 433:434 - TVDD_VSEL : 1 [0x1 / 0b01] -# 435:436 - DVDD_VSEL : 2 [0x2 / 0b10] -# 438:438 - EMI1_DMODE : 1 [0x1 / 0b1] -# 439:440 - EVDD_VSEL : 0 [0x0 / 0b00] -# 441:443 - IIC2_BASE : 0 [0x0 / 0b000] -# 444:444 - EMI1_CMODE : 0 [0x0 / 0b0] -# 445:447 - IIC2_EXT : 2 [0x2 / 0b010] -# 472:481 - SYSCLK_FREQ : 600 [0x258 / 0b1001011000] -# 509:511 - HWA_CGA_M2_CLK_SEL : 1 [0x1 / 0b001] - - -#PBL preamble and RCW header -aa55aa55 01ee0100 -# RCW -0c140010 0e000000 00000000 00000000 -33335559 f0005002 60040000 c1000000 -00000000 00000000 00000000 00028800 -20004000 01103202 00000096 00000001 diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg index 395c75c7d0..2df229c56c 100644 --- a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg +++ b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg @@ -8,7 +8,7 @@ # 32: 33 - CGA_PLL2_CFG : 0 [0x0 / 0b00] # 34: 39 - CGA_PLL2_RAT : 14 [0xe / 0b001110] # 96: 99 - C1_PLL_SEL : 0 [0x0 / 0b0000] -# 128:143 - SRDS_PRTCL_S1 : 13107 [0x3333 / 0b0011001100110011] +# 128:143 - SRDS_PRTCL_S1 : 4403 [0x1133 / 0b0001000100110011] # 144:159 - SRDS_PRTCL_S2 : 21849 [0x5559 / 0b0101010101011001] # 160:161 - SRDS_PLL_REF_CLK_SEL_S1 : 3 [0x3 / 0b11] # 162:163 - SRDS_PLL_REF_CLK_SEL_S2 : 3 [0x3 / 0b11] @@ -39,7 +39,7 @@ # 357:359 - IRQ_EXT : 0 [0x0 / 0b000] # 360:362 - SPI_EXT : 0 [0x0 / 0b000] # 363:365 - SDHC_EXT : 0 [0x0 / 0b000] -# 366:368 - UART_BASE : 5 [0x5 / 0b101] +# 366:368 - UART_BASE : 6 [0x6 / 0b110] # 369:369 - ASLEEP : 0 [0x0 / 0b0] # 370:370 - RTC : 0 [0x0 / 0b0] # 371:371 - SDHC_BASE : 0 [0x0 / 0b0] @@ -79,6 +79,6 @@ aa55aa55 01ee0100 # RCW 0c140010 0e000000 00000000 00000000 -33335559 f0005002 40025000 c1000000 -00000000 00000000 00000000 00028800 +11335559 f0005002 40025000 c1000000 +00000000 00000000 00000000 00030800 20004000 01103202 00000096 00000001 diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg index 4ef6d576ed..72ab1cd7d7 100644 --- a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg +++ b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg @@ -8,7 +8,7 @@ # 32: 33 - CGA_PLL2_CFG : 0 [0x0 / 0b00] # 34: 39 - CGA_PLL2_RAT : 14 [0xe / 0b001110] # 96: 99 - C1_PLL_SEL : 0 [0x0 / 0b0000] -# 128:143 - SRDS_PRTCL_S1 : 13107 [0x3333 / 0b0011001100110011] +# 128:143 - SRDS_PRTCL_S1 : 4403 [0x1133 / 0b0001000100110011] # 144:159 - SRDS_PRTCL_S2 : 21849 [0x5559 / 0b0101010101011001] # 160:161 - SRDS_PLL_REF_CLK_SEL_S1 : 3 [0x3 / 0b11] # 162:163 - SRDS_PLL_REF_CLK_SEL_S2 : 3 [0x3 / 0b11] @@ -39,7 +39,7 @@ # 357:359 - IRQ_EXT : 0 [0x0 / 0b000] # 360:362 - SPI_EXT : 0 [0x0 / 0b000] # 363:365 - SDHC_EXT : 0 [0x0 / 0b000] -# 366:368 - UART_BASE : 5 [0x5 / 0b101] +# 366:368 - UART_BASE : 6 [0x6 / 0b110] # 369:369 - ASLEEP : 0 [0x0 / 0b0] # 370:370 - RTC : 0 [0x0 / 0b0] # 371:371 - SDHC_BASE : 0 [0x0 / 0b0] @@ -67,10 +67,10 @@ # 433:434 - TVDD_VSEL : 1 [0x1 / 0b01] # 435:436 - DVDD_VSEL : 2 [0x2 / 0b10] # 438:438 - EMI1_DMODE : 1 [0x1 / 0b1] -# 439:440 - EVDD_VSEL : 2 [0x2 / 0b10] +# 439:440 - EVDD_VSEL : 0 [0x0 / 0b00] # 441:443 - IIC2_BASE : 0 [0x0 / 0b000] # 444:444 - EMI1_CMODE : 0 [0x0 / 0b0] -# 445:447 - IIC2_EXT : 1 [0x1 / 0b001] +# 445:447 - IIC2_EXT : 2 [0x2 / 0b010] # 472:481 - SYSCLK_FREQ : 600 [0x258 / 0b1001011000] # 509:511 - HWA_CGA_M2_CLK_SEL : 1 [0x1 / 0b001] @@ -79,6 +79,6 @@ aa55aa55 01ee0100 # RCW 0c140010 0e000000 00000000 00000000 -33335559 f0005002 60040000 c1000000 -00000000 00000000 00000000 00028800 -20004000 01103301 00000096 00000001 +11335559 f0005002 60040000 c1000000 +00000000 00000000 00000000 00030800 +20004000 01103202 00000096 00000001 diff --git a/arch/arm/boards/zii-imx51-rdu1/Makefile b/arch/arm/boards/zii-imx51-rdu1/Makefile index 01c7a259e9..604b3621be 100644 --- a/arch/arm/boards/zii-imx51-rdu1/Makefile +++ b/arch/arm/boards/zii-imx51-rdu1/Makefile @@ -1,2 +1,3 @@ obj-y += board.o +CFLAGS_pbl-lowlevel.o := -fno-tree-switch-conversion -fno-jump-tables lwl-y += lowlevel.o diff --git a/arch/arm/boards/zii-imx51-rdu1/lowlevel.c b/arch/arm/boards/zii-imx51-rdu1/lowlevel.c index 849c5624c5..da05b0564c 100644 --- a/arch/arm/boards/zii-imx51-rdu1/lowlevel.c +++ b/arch/arm/boards/zii-imx51-rdu1/lowlevel.c @@ -84,13 +84,6 @@ ENTRY_FUNCTION(start_imx51_zii_rdu1, r0, r1, r2) switch (system_type) { default: - /* - * see similar code in - * arch/arm/boards/zii-vf610-dev/lowlevel.c for - * reasoning for placing barrier() below. - */ - barrier(); - if (IS_ENABLED(CONFIG_DEBUG_LL)) { relocate_to_current_adr(); setup_c(); diff --git a/arch/arm/boards/zii-imx8mq-dev/lowlevel.c b/arch/arm/boards/zii-imx8mq-dev/lowlevel.c index 0fd2ddfca5..33c007e05d 100644 --- a/arch/arm/boards/zii-imx8mq-dev/lowlevel.c +++ b/arch/arm/boards/zii-imx8mq-dev/lowlevel.c @@ -179,13 +179,6 @@ ENTRY_FUNCTION(start_zii_imx8mq_dev, r0, r1, r2) switch (system_type) { default: - /* - * see similar code in - * arch/arm/boards/zii-vf610-dev/lowlevel.c for - * reasoning for placing barrier() below. - */ - barrier(); - if (IS_ENABLED(CONFIG_DEBUG_LL)) { relocate_to_current_adr(); setup_c(); diff --git a/arch/arm/boards/zii-vf610-dev/Makefile b/arch/arm/boards/zii-vf610-dev/Makefile index 1297d815e3..3c3a3f2387 100644 --- a/arch/arm/boards/zii-vf610-dev/Makefile +++ b/arch/arm/boards/zii-vf610-dev/Makefile @@ -1,3 +1,4 @@ obj-y += board.o +CFLAGS_pbl-lowlevel.o := -fno-tree-switch-conversion -fno-jump-tables lwl-y += lowlevel.o bbenv-y += defaultenv-zii-vf610-dev diff --git a/arch/arm/boards/zii-vf610-dev/board.c b/arch/arm/boards/zii-vf610-dev/board.c index 1296f70317..90d4535684 100644 --- a/arch/arm/boards/zii-vf610-dev/board.c +++ b/arch/arm/boards/zii-vf610-dev/board.c @@ -122,6 +122,7 @@ static int zii_vf610_dev_set_hostname(void) const char *compatible; const char *hostname; } boards[] = { + { "zii,vf610dtu", "dtu" }, { "zii,vf610spu3", "spu3" }, { "zii,vf610spb4", "spb4" }, { "zii,vf610cfu1", "cfu1" }, @@ -170,7 +171,8 @@ static int zii_vf610_register_emmc_bbu(void) if (!of_machine_is_compatible("zii,vf610spu3") && !of_machine_is_compatible("zii,vf610cfu1") && - !of_machine_is_compatible("zii,vf610spb4")) + !of_machine_is_compatible("zii,vf610spb4") && + !of_machine_is_compatible("zii,vf610dtu")) return 0; ret = vf610_bbu_internal_mmcboot_register_handler("eMMC", diff --git a/arch/arm/boards/zii-vf610-dev/lowlevel.c b/arch/arm/boards/zii-vf610-dev/lowlevel.c index 79588ac381..b320fbc0cf 100644 --- a/arch/arm/boards/zii-vf610-dev/lowlevel.c +++ b/arch/arm/boards/zii-vf610-dev/lowlevel.c @@ -42,6 +42,7 @@ enum zii_platform_vf610_type { ZII_PLATFORM_VF610_CFU1 = 0x04, ZII_PLATFORM_VF610_DEV_REV_C = 0x05, ZII_PLATFORM_VF610_SPB4 = 0x06, + ZII_PLATFORM_VF610_SSMB_DTU = 0x07, }; static unsigned int get_system_type(void) @@ -79,6 +80,7 @@ extern char __dtb_vf610_zii_dev_rev_c_start[]; extern char __dtb_vf610_zii_cfu1_start[]; extern char __dtb_vf610_zii_ssmb_spu3_start[]; extern char __dtb_vf610_zii_scu4_aib_start[]; +extern char __dtb_vf610_zii_ssmb_dtu_start[]; extern char __dtb_vf610_zii_spb4_start[]; ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2) @@ -93,23 +95,6 @@ ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2) switch (system_type) { default: - /* - * GCC can be smart enough to, when DEBUG_LL is - * disabled, reduce this switch statement to a LUT - * fetch. Unfortunately here, this early in the boot - * process before any relocation/address fixups could - * happen, the address of that LUT used by the code is - * incorrect and any access to it would result in - * bogus values. - * - * Adding the following barrier() statement seem to - * force the compiler to always translate this block - * to a sequence of consecutive checks and jumps with - * relative fetches, which should work with or without - * relocation/fixups. - */ - barrier(); - if (IS_ENABLED(CONFIG_DEBUG_LL)) { relocate_to_current_adr(); setup_c(); @@ -137,6 +122,9 @@ ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2) case ZII_PLATFORM_VF610_SPB4: fdt = __dtb_vf610_zii_spb4_start; break; + case ZII_PLATFORM_VF610_SSMB_DTU: + fdt = __dtb_vf610_zii_ssmb_dtu_start; + break; } vf610_barebox_entry(fdt + get_runtime_offset()); diff --git a/arch/arm/configs/layerscape_defconfig b/arch/arm/configs/layerscape_defconfig index dadbcc214c..b81f375415 100644 --- a/arch/arm/configs/layerscape_defconfig +++ b/arch/arm/configs/layerscape_defconfig @@ -22,7 +22,6 @@ CONFIG_PBL_CONSOLE=y CONFIG_PARTITION_DISK_EFI=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y CONFIG_RESET_SOURCE=y -CONFIG_DEBUG_LL=y CONFIG_CMD_DMESG=y CONFIG_LONGHELP=y CONFIG_CMD_IOMEM=y @@ -85,8 +84,13 @@ CONFIG_DRIVER_NET_FSL_FMAN=y CONFIG_DP83867_PHY=y CONFIG_REALTEK_PHY=y CONFIG_NET_DSA_MV88E6XXX=y +CONFIG_DRIVER_SPI_FSL_QUADSPI=y CONFIG_I2C=y CONFIG_I2C_IMX=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_MTD=y +CONFIG_MTD_M25P80=y CONFIG_MCI=y CONFIG_MCI_MMC_BOOT_PARTITIONS=y CONFIG_MCI_IMX_ESDHC=y @@ -94,10 +98,12 @@ CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_LED_GPIO_OF=y CONFIG_LED_TRIGGERS=y +CONFIG_LED_PCA955X=y CONFIG_EEPROM_AT25=y CONFIG_EEPROM_AT24=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_IMX=y +CONFIG_GPIO_PCA953X=y CONFIG_NVMEM=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED=y diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig index 2577103293..f8abbccfca 100644 --- a/arch/arm/cpu/Kconfig +++ b/arch/arm/cpu/Kconfig @@ -86,6 +86,7 @@ config CPU_V8 select CPU_64v8 select CPU_SUPPORTS_64BIT_KERNEL select ARM_EXCEPTIONS + select GENERIC_FIND_NEXT_BIT config CPU_XSC3 bool diff --git a/arch/arm/cpu/cache-armv7.S b/arch/arm/cpu/cache-armv7.S index 7a1c5c0189..6a8aff8bb1 100644 --- a/arch/arm/cpu/cache-armv7.S +++ b/arch/arm/cpu/cache-armv7.S @@ -83,7 +83,10 @@ hierarchical: ands r3, r0, #0x7000000 @ extract loc from clidr mov r3, r3, lsr #23 @ left align loc bit field beq finished @ if loc is 0, then no need to clean - mov r12, #0 @ start clean at cache level 0 + cmp r8, #0 +THUMB( ite eq ) + moveq r12, #0 + subne r12, r3, #2 @ start invalidate at outmost cache level loop1: add r2, r12, r12, lsr #1 @ work out 3x current cache level mov r1, r0, lsr r2 @ extract cache type bits from clidr @@ -118,8 +121,16 @@ THUMB( ite eq ) subs r7, r7, #1 @ decrement the index bge loop2 skip: + cmp r8, #0 + bne inval_check add r12, r12, #2 @ increment cache number cmp r3, r12 + b loop_end_check +inval_check: + cmp r12, #0 + sub r12, r12, #2 @ decrement cache number +loop_end_check: + dsb @ work-around Cortex-A7 erratum 814220 bgt loop1 finished: ldmfd sp!, {r4-r11} diff --git a/arch/arm/cpu/lowlevel_64.S b/arch/arm/cpu/lowlevel_64.S index af1cd8b5bc..6a23132ed1 100644 --- a/arch/arm/cpu/lowlevel_64.S +++ b/arch/arm/cpu/lowlevel_64.S @@ -12,6 +12,13 @@ ENTRY(arm_cpu_lowlevel_init) orr x0, x0, #(1 << 10) /* 64-bit EL2 */ msr scr_el3, x0 msr cptr_el3, xzr + + mrs x0, sctlr_el3 + ldr x1, =SCTLR_ELx_FLAGS + bic x0, x0, x1 + msr sctlr_el3, x0 + isb + b done 2: diff --git a/arch/arm/cpu/mmu-early.c b/arch/arm/cpu/mmu-early.c index d39a03ed95..2f5876fc46 100644 --- a/arch/arm/cpu/mmu-early.c +++ b/arch/arm/cpu/mmu-early.c @@ -5,17 +5,20 @@ #include <asm/memory.h> #include <asm/system.h> #include <asm/cache.h> +#include <asm-generic/sections.h> #include "mmu.h" static uint32_t *ttb; -static void map_cachable(unsigned long start, unsigned long size) +static inline void map_region(unsigned long start, unsigned long size, + uint64_t flags) + { start = ALIGN_DOWN(start, SZ_1M); size = ALIGN(size, SZ_1M); - create_sections(ttb, start, start + size - 1, PMD_SECT_DEF_CACHED); + create_sections(ttb, start, start + size - 1, flags); } void mmu_early_enable(unsigned long membase, unsigned long memsize, @@ -28,9 +31,27 @@ void mmu_early_enable(unsigned long membase, unsigned long memsize, set_ttbr(ttb); set_domain(DOMAIN_MANAGER); + /* + * This marks the whole address space as uncachable as well as + * unexecutable if possible + */ create_flat_mapping(ttb); - map_cachable(membase, memsize); + /* + * There can be SoCs that have a section shared between device memory + * and the on-chip RAM hosting the PBL. Thus mark this section + * uncachable, but executable. + * On such SoCs, executing from OCRAM could cause the instruction + * prefetcher to speculatively access that device memory, triggering + * potential errant behavior. + * + * If your SoC has such a memory layout, you should rewrite the code + * here to map the OCRAM page-wise. + */ + map_region((unsigned long)_stext, _etext - _stext, PMD_SECT_DEF_UNCACHED); + + /* maps main memory as cachable */ + map_region(membase, memsize, PMD_SECT_DEF_CACHED); __mmu_cache_on(); } diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c index 29816ad563..123e19e9e5 100644 --- a/arch/arm/cpu/mmu.c +++ b/arch/arm/cpu/mmu.c @@ -34,7 +34,6 @@ #include "mmu.h" -#define PMD_SECT_DEF_CACHED (PMD_SECT_WB | PMD_SECT_DEF_UNCACHED) #define PTRS_PER_PTE (PGDIR_SIZE / PAGE_SIZE) #define ARCH_MAP_WRITECOMBINE ((unsigned)-1) @@ -58,11 +57,13 @@ static inline void tlb_invalidate(void) } #define PTE_FLAGS_CACHED_V7 (PTE_EXT_TEX(1) | PTE_BUFFERABLE | PTE_CACHEABLE) -#define PTE_FLAGS_WC_V7 PTE_EXT_TEX(1) -#define PTE_FLAGS_UNCACHED_V7 (0) +#define PTE_FLAGS_WC_V7 (PTE_EXT_TEX(1) | PTE_EXT_XN) +#define PTE_FLAGS_UNCACHED_V7 PTE_EXT_XN #define PTE_FLAGS_CACHED_V4 (PTE_SMALL_AP_UNO_SRW | PTE_BUFFERABLE | PTE_CACHEABLE) #define PTE_FLAGS_UNCACHED_V4 PTE_SMALL_AP_UNO_SRW -#define PGD_FLAGS_WC_V7 (PMD_SECT_TEX(1) | PMD_TYPE_SECT | PMD_SECT_BUFFERABLE) +#define PGD_FLAGS_WC_V7 (PMD_SECT_TEX(1) | PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \ + PMD_SECT_XN) +#define PGD_FLAGS_UNCACHED_V7 (PMD_SECT_DEF_UNCACHED | PMD_SECT_XN) /* * PTE flags to set cached and uncached areas. @@ -72,6 +73,7 @@ static uint32_t pte_flags_cached; static uint32_t pte_flags_wc; static uint32_t pte_flags_uncached; static uint32_t pgd_flags_wc; +static uint32_t pgd_flags_uncached; #define PTE_MASK ((1 << 12) - 1) @@ -164,7 +166,7 @@ int arch_remap_range(void *start, size_t size, unsigned flags) break; case MAP_UNCACHED: pte_flags = pte_flags_uncached; - pgd_flags = PMD_SECT_DEF_UNCACHED; + pgd_flags = pgd_flags_uncached; break; case ARCH_MAP_WRITECOMBINE: pte_flags = pte_flags_wc; @@ -247,7 +249,7 @@ void *map_io_sections(unsigned long phys, void *_start, size_t size) unsigned long start = (unsigned long)_start, sec; for (sec = start; sec < start + size; sec += PGDIR_SIZE, phys += PGDIR_SIZE) - ttb[pgd_index(sec)] = phys | PMD_SECT_DEF_UNCACHED; + ttb[pgd_index(sec)] = phys | pgd_flags_uncached; dma_flush_range(ttb, 0x4000); tlb_invalidate(); @@ -411,11 +413,13 @@ void __mmu_init(bool mmu_on) pte_flags_cached = PTE_FLAGS_CACHED_V7; pte_flags_wc = PTE_FLAGS_WC_V7; pgd_flags_wc = PGD_FLAGS_WC_V7; + pgd_flags_uncached = PGD_FLAGS_UNCACHED_V7; pte_flags_uncached = PTE_FLAGS_UNCACHED_V7; } else { pte_flags_cached = PTE_FLAGS_CACHED_V4; pte_flags_wc = PTE_FLAGS_UNCACHED_V4; pgd_flags_wc = PMD_SECT_DEF_UNCACHED; + pgd_flags_uncached = PMD_SECT_DEF_UNCACHED; pte_flags_uncached = PTE_FLAGS_UNCACHED_V4; } diff --git a/arch/arm/cpu/mmu.h b/arch/arm/cpu/mmu.h index 338728aacd..c911ee209f 100644 --- a/arch/arm/cpu/mmu.h +++ b/arch/arm/cpu/mmu.h @@ -3,6 +3,7 @@ #include <asm/pgtable.h> #include <linux/sizes.h> +#include <asm/system_info.h> #include "mmu-common.h" @@ -62,8 +63,13 @@ create_sections(uint32_t *ttb, unsigned long first, static inline void create_flat_mapping(uint32_t *ttb) { + unsigned int flags = PMD_SECT_DEF_UNCACHED; + + if (cpu_architecture() >= CPU_ARCH_ARMv7) + flags |= PMD_SECT_XN; + /* create a flat mapping using 1MiB sections */ - create_sections(ttb, 0, 0xffffffff, PMD_SECT_DEF_UNCACHED); + create_sections(ttb, 0, 0xffffffff, flags); } #endif /* __ARM_MMU_H */ diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 1c6129816d..be3edbb0cc 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -125,7 +125,8 @@ pbl-dtb-$(CONFIG_MACH_ZII_VF610_DEV) += \ vf610-zii-cfu1.dtb.o \ vf610-zii-ssmb-spu3.dtb.o \ vf610-zii-scu4-aib.dtb.o \ - vf610-zii-spb4.dtb.o + vf610-zii-spb4.dtb.o \ + vf610-zii-ssmb-dtu.dtb.o pbl-dtb-$(CONFIG_MACH_AT91SAM9263EK_DT) += at91sam9263ek.dtb.o pbl-dtb-$(CONFIG_MACH_MICROCHIP_KSZ9477_EVB) += at91-microchip-ksz9477-evb.dtb.o pbl-dtb-$(CONFIG_MACH_AT91SAM9X5EK) += at91sam9x5ek.dtb.o diff --git a/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts b/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts index f21479eef8..f0332e3999 100644 --- a/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts +++ b/arch/arm/dts/fsl-tqmls1046a-mbls10xxa.dts @@ -20,10 +20,30 @@ serial0 = &duart0; serial1 = &duart1; mmc0 = &esdhc; + qspiflash0 = &qflash0; + qspiflash1 = &qflash1; + qsgmii_s1_p1 = &qsgmii1_phy1; + qsgmii_s1_p2 = &qsgmii1_phy2; + qsgmii_s2_p1 = &qsgmii2_phy1; + qsgmii_s2_p2 = &qsgmii2_phy2; + qsgmii_s2_p3 = &qsgmii2_phy3; + qsgmii_s2_p4 = &qsgmii2_phy4; }; chosen { stdout-path = "serial1:115200n8"; + + environment-sd { + compatible = "barebox,environment"; + device-path = &environment_sd; + status = "disabled"; + }; + + environment-qspi { + compatible = "barebox,environment"; + device-path = &environment_qspi; + status = "disabled"; + }; }; gpio-keys-polled { @@ -57,6 +77,24 @@ }; +&esdhc { + partitions { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "fixed-partitions"; + + partition@0 { + label = "barebox"; + reg = <0x1000 0xdf000>; + }; + + environment_sd: partition@e0000 { + label = "barebox-environment"; + reg = <0xe0000 0x20000>; + }; + }; +}; &duart0 { status = "okay"; @@ -66,6 +104,14 @@ status = "okay"; }; +&esdhc { + mmc-hs200-1_8v; + sd-uhs-sdr104; + sd-uhs-sdr50; + sd-uhs-sdr25; + sd-uhs-sdr12; +}; + &i2c3 { status = "okay"; @@ -132,43 +178,40 @@ &fman0 { status = "okay"; - ethernet@e0000 { - status = "disabled"; + ethernet@e0000 { /* EMAC.1 */ + phy-connection-type = "sgmii"; + }; - ethernet@e2000 { - phy-handle = <&qsgmii1_phy2>; + ethernet@e2000 { /* EMAC.2 */ phy-connection-type = "sgmii"; }; - ethernet@e4000 { + ethernet@e4000 { /* EMAC.3 */ phy-handle = <&rgmii_phy1>; phy-connection-type = "rgmii"; phy-mode = "rgmii-id"; }; - ethernet@e6000 { + ethernet@e6000 { /* EMAC.4 */ phy-handle = <&rgmii_phy2>; phy-connection-type = "rgmii"; phy-mode = "rgmii-id"; }; - ethernet@e8000 { - status = "disabled"; + ethernet@e8000 { /* EMAC.5 */ + phy-connection-type = "sgmii"; }; - ethernet@ea000 { - phy-handle = <&qsgmii2_phy2>; + ethernet@ea000 { /* EMAC.6 */ phy-connection-type = "sgmii"; }; - ethernet@f0000 { - phy-handle = <&qsgmii1_phy1>; + ethernet@f0000 { /* EMAC.9 */ phy-connection-type = "sgmii"; }; - ethernet@f2000 { - phy-handle = <&qsgmii2_phy1>; + ethernet@f2000 { /* EMAC.10 */ phy-connection-type = "sgmii"; }; @@ -212,6 +255,13 @@ ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>; }; + rgmii_phy2: ethernet-phy@0c { + reg = <0x0c>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_1_50_NS>; + ti,tx-internal-delay = <DP83867_RGMIIDCTL_1_50_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>; + }; + qsgmii1_phy1: ethernet-phy@1c { reg = <0x1c>; }; @@ -219,15 +269,6 @@ qsgmii1_phy2: ethernet-phy@1d { reg = <0x1d>; }; - }; - - mdio@fd000 { - rgmii_phy2: ethernet-phy@0c { - reg = <0x0c>; - ti,rx-internal-delay = <DP83867_RGMIIDCTL_1_50_NS>; - ti,tx-internal-delay = <DP83867_RGMIIDCTL_1_50_NS>; - ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>; - }; qsgmii2_phy1: ethernet-phy@00 { reg = <0x00>; @@ -236,5 +277,41 @@ qsgmii2_phy2: ethernet-phy@01 { reg = <0x01>; }; + + qsgmii2_phy3: ethernet-phy@02 { + reg = <0x02>; + }; + + qsgmii2_phy4: ethernet-phy@03 { + reg = <0x03>; + }; + }; + + mdio@fd000 { + status = "disabled"; + }; +}; + +&qflash0 { + partitions { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "fixed-partitions"; + + partition@0 { + label = "barebox"; + reg = <0x0 0x200000>; + }; + + environment_qspi: partition@200000 { + label = "barebox-environment"; + reg = <0x200000 0x80000>; + }; + + partition@280000 { + label = "data"; + reg = <0x280000 0x0>; + }; }; }; diff --git a/arch/arm/dts/fsl-tqmls1046a.dtsi b/arch/arm/dts/fsl-tqmls1046a.dtsi index 4717e66857..0ea2612cbf 100644 --- a/arch/arm/dts/fsl-tqmls1046a.dtsi +++ b/arch/arm/dts/fsl-tqmls1046a.dtsi @@ -40,15 +40,15 @@ #address-cells = <1>; #size-cells = <1>; compatible = "jedec,spi-nor"; - spi-max-frequency = <108000000>; + spi-max-frequency = <62500000>; reg = <0>; }; qflash1: mx66u51235f@1 { #address-cells = <1>; #size-cells = <1>; - spi-max-frequency = <108000000>; compatible = "jedec,spi-nor"; + spi-max-frequency = <62500000>; reg = <1>; }; }; diff --git a/arch/arm/dts/imx8mq.dtsi b/arch/arm/dts/imx8mq.dtsi index d1d8bdaa0e..1d59615238 100644 --- a/arch/arm/dts/imx8mq.dtsi +++ b/arch/arm/dts/imx8mq.dtsi @@ -198,3 +198,7 @@ <25000000>, <125000000>; }; + +&pgc_pcie1 { + power-domains = <&pgc_pcie2>; +}; diff --git a/arch/arm/dts/vf610-zii-ssmb-dtu.dts b/arch/arm/dts/vf610-zii-ssmb-dtu.dts new file mode 100644 index 0000000000..6ffb7aa62d --- /dev/null +++ b/arch/arm/dts/vf610-zii-ssmb-dtu.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +#include <arm/vf610-zii-ssmb-dtu.dts> + +#include "vf610-zii-dev.dtsi" + +/ { + aliases { + /* + * NVMEM device corresponding to EEPROM attached to + * the switch shared DT node with it, so we use that + * fact to create a desirable naming + */ + switch-eeprom = &switch0; + }; +};
\ No newline at end of file diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index 348a76b2c1..d8a4d9b667 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -82,6 +82,12 @@ static inline int test_bit(int nr, const void * addr) #define test_and_clear_bit(x, y) __test_and_clear_bit(x, y) #define test_and_change_bit(x, y) __test_and_change_bit(x, y) +#ifdef CONFIG_CPU_V8 + +#include <asm-generic/bitops/find.h> + +#else /* CONFIG_CPU_V8 */ + #ifndef __ARMEB__ /* * These are the little endian definitions. @@ -115,6 +121,8 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset); #endif /* __ARMEB__ */ +#endif /* CONFIG_CPU_V8 */ + #if defined (CONFIG_CPU_32) && defined(__LINUX_ARM_ARCH__) && (__LINUX_ARM_ARCH__ >= 5) static inline int constant_fls(int x) { diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index ef9cb98bf0..a0180f2df8 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -1,6 +1,26 @@ #ifndef __ASM_ARM_SYSTEM_H #define __ASM_ARM_SYSTEM_H +#include <linux/const.h> + +/* Common SCTLR_ELx flags. */ +#define SCTLR_ELx_DSSBS (_BITUL(44)) +#define SCTLR_ELx_ENIA (_BITUL(31)) +#define SCTLR_ELx_ENIB (_BITUL(30)) +#define SCTLR_ELx_ENDA (_BITUL(27)) +#define SCTLR_ELx_EE (_BITUL(25)) +#define SCTLR_ELx_IESB (_BITUL(21)) +#define SCTLR_ELx_WXN (_BITUL(19)) +#define SCTLR_ELx_ENDB (_BITUL(13)) +#define SCTLR_ELx_I (_BITUL(12)) +#define SCTLR_ELx_SA (_BITUL(3)) +#define SCTLR_ELx_C (_BITUL(2)) +#define SCTLR_ELx_A (_BITUL(1)) +#define SCTLR_ELx_M (_BITUL(0)) + +#define SCTLR_ELx_FLAGS (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | \ + SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_IESB) + #if __LINUX_ARM_ARCH__ >= 7 #define isb() __asm__ __volatile__ ("isb" : : : "memory") #ifdef CONFIG_CPU_64v8 diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c4e7500e8f..71d37cee90 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -454,6 +454,7 @@ config MACH_ZII_IMX8MQ_DEV select FIRMWARE_IMX8MQ_ATF select ARM_SMCCC select MCI_IMX_ESDHC_PBL + select MACH_ZII_COMMON config MACH_ZII_VF610_DEV bool "ZII VF610 Dev Family" diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c index 01b4274ed3..e898be9ab5 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -117,7 +117,7 @@ static void imx6_setup_ipu_qos(void) uint32_t val; if (!cpu_mx6_is_mx6q() && !cpu_mx6_is_mx6d() && - !cpu_mx6_is_mx6dl() && cpu_mx6_is_mx6s()) + !cpu_mx6_is_mx6dl() && !cpu_mx6_is_mx6s()) return; val = readl(iomux + IOMUXC_GPR4); diff --git a/arch/arm/mach-imx/include/mach/imx25-regs.h b/arch/arm/mach-imx/include/mach/imx25-regs.h index 71812764c9..5974897a16 100644 --- a/arch/arm/mach-imx/include/mach/imx25-regs.h +++ b/arch/arm/mach-imx/include/mach/imx25-regs.h @@ -62,12 +62,14 @@ #define MX25_SSI2_BASE_ADDR 0x50014000 #define MX25_SSI1_BASE_ADDR 0x50034000 #define MX25_NFC_BASE_ADDR 0xbb000000 +#define MX25_SCC_BASE_ADDR 0x53fac000 #define MX25_IIM_BASE_ADDR 0x53ff0000 #define MX25_DRYICE_BASE_ADDR 0x53ffc000 #define MX25_ESDHC1_BASE_ADDR 0x53fb4000 #define MX25_ESDHC2_BASE_ADDR 0x53fb8000 #define MX25_LCDC_BASE_ADDR 0x53fbc000 #define MX25_KPP_BASE_ADDR 0x43fa8000 +#define MX25_RNGB_BASE_ADDR 0x53fb0000 #define MX25_SDMA_BASE_ADDR 0x53fd4000 #define MX25_USB_BASE_ADDR 0x53ff4000 #define MX25_USB_OTG_BASE_ADDR (MX25_USB_BASE_ADDR + 0x0000) diff --git a/arch/arm/mach-layerscape/Makefile b/arch/arm/mach-layerscape/Makefile index 269839254b..73cd61a7cf 100644 --- a/arch/arm/mach-layerscape/Makefile +++ b/arch/arm/mach-layerscape/Makefile @@ -2,3 +2,5 @@ obj- := __dummy__.o lwl-y += lowlevel.o errata.o lwl-$(CONFIG_ARCH_LS1046) += lowlevel-ls1046a.o obj-y += icid.o +obj-pbl-y += boot.o +pbl-y += xload-qspi.o xload.o diff --git a/arch/arm/mach-layerscape/boot.c b/arch/arm/mach-layerscape/boot.c new file mode 100644 index 0000000000..c804977d22 --- /dev/null +++ b/arch/arm/mach-layerscape/boot.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <common.h> +#include <init.h> +#include <bootsource.h> +#include <mach/layerscape.h> +#include <soc/fsl/immap_lsch2.h> + +enum bootsource ls1046_bootsource_get(void) +{ + void __iomem *dcfg = IOMEM(LSCH2_DCFG_ADDR); + uint32_t rcw_src; + + rcw_src = in_be32(dcfg) >> 23; + + if (rcw_src == 0x40) + return BOOTSOURCE_MMC; + if ((rcw_src & 0x1fe) == 0x44) + return BOOTSOURCE_SPI_NOR; + if ((rcw_src & 0x1f0) == 0x10) + /* 8bit NOR Flash */ + return BOOTSOURCE_NOR; + if ((rcw_src & 0x1f0) == 0x20) + /* 16bit NOR Flash */ + return BOOTSOURCE_NOR; + + return BOOTSOURCE_UNKNOWN; +} + +static int ls1046a_bootsource_init(void) +{ + if (!of_machine_is_compatible("fsl,ls1046a")) + return 0; + + bootsource_set(ls1046_bootsource_get()); + + return 0; +} +coredevice_initcall(ls1046a_bootsource_init);
\ No newline at end of file diff --git a/arch/arm/mach-layerscape/include/mach/bbu.h b/arch/arm/mach-layerscape/include/mach/bbu.h new file mode 100644 index 0000000000..1ea0cbb11f --- /dev/null +++ b/arch/arm/mach-layerscape/include/mach/bbu.h @@ -0,0 +1,22 @@ +#ifndef __MACH_LAYERSCAPE_BBU_H +#define __MACH_LAYERSCAPE_BBU_H + +#include <bbu.h> + +static inline int ls1046a_bbu_mmc_register_handler(const char *name, + const char *devicefile, + unsigned long flags) +{ + return bbu_register_std_file_update(name, flags, devicefile, + filetype_layerscape_image); +} + +static inline int ls1046a_bbu_qspi_register_handler(const char *name, + const char *devicefile, + unsigned long flags) +{ + return bbu_register_std_file_update(name, flags, devicefile, + filetype_layerscape_qspi_image); +} + +#endif /* __MACH_LAYERSCAPE_BBU_H */
\ No newline at end of file diff --git a/arch/arm/mach-layerscape/include/mach/layerscape.h b/arch/arm/mach-layerscape/include/mach/layerscape.h index 55e0b7bc96..3366e7f258 100644 --- a/arch/arm/mach-layerscape/include/mach/layerscape.h +++ b/arch/arm/mach-layerscape/include/mach/layerscape.h @@ -4,4 +4,6 @@ #define LS1046A_DDR_SDRAM_BASE 0x80000000 #define LS1046A_DDR_FREQ 2100000000 +enum bootsource ls1046_bootsource_get(void); + #endif /* __MACH_LAYERSCAPE_H */ diff --git a/arch/arm/mach-layerscape/include/mach/xload.h b/arch/arm/mach-layerscape/include/mach/xload.h index fedd36e020..eb2d998865 100644 --- a/arch/arm/mach-layerscape/include/mach/xload.h +++ b/arch/arm/mach-layerscape/include/mach/xload.h @@ -2,5 +2,9 @@ #define __MACH_XLOAD_H int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long r2); +int ls1046a_qspi_start_image(unsigned long r0, unsigned long r1, + unsigned long r2); +int ls1046a_xload_start_image(unsigned long r0, unsigned long r1, + unsigned long r2); #endif /* __MACH_XLOAD_H */ diff --git a/arch/arm/mach-layerscape/xload-qspi.c b/arch/arm/mach-layerscape/xload-qspi.c new file mode 100644 index 0000000000..c76780a0e8 --- /dev/null +++ b/arch/arm/mach-layerscape/xload-qspi.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <common.h> +#include <soc/fsl/immap_lsch2.h> +#include <asm-generic/sections.h> +#include <asm/cache.h> +#include <mach/xload.h> +#include <mach/layerscape.h> + +/* + * The offset of the 2nd stage image in the output file. This must match with the + * offset the pblimage tool puts barebox to. + */ +#define BAREBOX_START (128 * 1024) + +int ls1046a_qspi_start_image(unsigned long r0, unsigned long r1, + unsigned long r2) +{ + void *qspi_reg_base = IOMEM(LSCH2_QSPI0_BASE_ADDR); + void *membase = (void *)LS1046A_DDR_SDRAM_BASE; + void *qspi_mem_base = IOMEM(0x40000000); + void (*barebox)(unsigned long, unsigned long, unsigned long) = membase; + + /* Switch controller into little endian mode */ + out_be32(qspi_reg_base, 0x000f400c); + + memcpy(membase, qspi_mem_base + BAREBOX_START, barebox_image_size); + icache_invalidate(); + + printf("Starting barebox\n"); + + barebox(r0, r1, r2); + + printf("failed\n"); + + return -EIO; +} diff --git a/arch/arm/mach-layerscape/xload.c b/arch/arm/mach-layerscape/xload.c new file mode 100644 index 0000000000..54495d7f97 --- /dev/null +++ b/arch/arm/mach-layerscape/xload.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <common.h> +#include <bootsource.h> +#include <mach/layerscape.h> +#include <mach/xload.h> + +int ls1046a_xload_start_image(unsigned long r0, unsigned long r1, + unsigned long r2) +{ + enum bootsource src; + + src = ls1046_bootsource_get(); + + switch (src) { + case BOOTSOURCE_SPI_NOR: + return ls1046a_qspi_start_image(r0, r1, r2); + case BOOTSOURCE_MMC: + return ls1046a_esdhc_start_image(r0, r1, r2); + default: + pr_err("Unknown bootsource\n"); + return -EINVAL; + } +} diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index 665e8194ef..a7ea8f2d3b 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -94,7 +94,7 @@ int linux_tstc(int fd) return 0; } -int ctrlc(void) +int arch_ctrlc(void) { char chr; diff --git a/commands/Kconfig b/commands/Kconfig index 4f5d84ac18..039fd7d1ac 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1964,6 +1964,16 @@ config CMD_BAREBOX_UPDATE -y autom. use 'yes' when asking confirmations -f LEVEL set force level +config CMD_BLOBGEN + bool + select BLOBGEN + prompt "blobgen" + help + Provides the "blobgen" command. This command encrypts and decrypts + plaintext to/from blobs. This is done with hardware crypto engines, + so this command is only useful when you also enable a blobgen capable + driver. + config CMD_FIRMWARELOAD bool select FIRMWARE diff --git a/commands/Makefile b/commands/Makefile index 358671bb5b..e69fb5046f 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o obj-$(CONFIG_CMD_AUTOMOUNT) += automount.o obj-$(CONFIG_CMD_GLOBAL) += global.o obj-$(CONFIG_CMD_DMESG) += dmesg.o +obj-$(CONFIG_CMD_BLOBGEN) += blobgen.o obj-$(CONFIG_CMD_BASENAME) += basename.o obj-$(CONFIG_CMD_HAB) += hab.o obj-$(CONFIG_CMD_DIRNAME) += dirname.o diff --git a/commands/blobgen.c b/commands/blobgen.c new file mode 100644 index 0000000000..49107d037c --- /dev/null +++ b/commands/blobgen.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <common.h> +#include <command.h> +#include <getopt.h> +#include <blobgen.h> +#include <environment.h> + +static int do_blobgen(int argc, char *argv[]) +{ + bool do_encrypt = false, do_decrypt = false; + int opt; + const char *varname = NULL; + const char *modifier = NULL; + const char *blobdev = NULL; + struct blobgen *bg; + int plainsize; + int ret; + const char *message = NULL; + + while ((opt = getopt(argc, argv, "edm:V:b:")) > 0) { + switch (opt) { + case 'e': + do_encrypt = true; + break; + case 'd': + do_decrypt = true; + break; + case 'm': + modifier = optarg; + break; + case 'V': + varname = optarg; + break; + case 'b': + blobdev = optarg; + break; + } + } + + if (!varname) { + printf("varname not specified\n"); + return -EINVAL; + } + + if (!modifier) { + printf("Modifier not specified\n"); + return -EINVAL; + } + + bg = blobgen_get(blobdev); + if (!bg) { + printf("blobdev \"%s\" not found\n", blobdev); + return -ENOENT; + } + + if (do_encrypt && do_decrypt) { + printf("Both encrypt and decrypt given\n"); + return -EINVAL; + } + + if (!do_encrypt && !do_decrypt) { + printf("Specify either -e or -d option\n"); + return -EINVAL; + } + + if (argc > optind) { + message = argv[optind]; + } else { + printf("No message to %scrypt provided\n", + do_encrypt ? "en" : "de"); + return -EINVAL; + } + + if (do_encrypt) { + ret = blob_encrypt_to_env(bg, modifier, message, strlen(message), + varname); + if (ret) + return ret; + } + + if (do_decrypt) { + void *plain; + char *str; + + ret = blob_decrypt_from_base64(bg, modifier, message, &plain, + &plainsize); + if (ret) + return ret; + + str = malloc(plainsize + 1); + if (!str) + return -ENOMEM; + + memcpy(str, plain, plainsize); + str[plainsize] = 0; + + setenv(varname, str); + free(plain); + free(str); + } + + return 0; +} + +BAREBOX_CMD_HELP_START(blobgen) +BAREBOX_CMD_HELP_TEXT("This command utilizes hardware crypto engines to en/decrypt") +BAREBOX_CMD_HELP_TEXT("data blobs.") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-e\t", "encrypt") +BAREBOX_CMD_HELP_OPT("-d\t", "decrypt") +BAREBOX_CMD_HELP_OPT("-m <modifier>", "Set modifier") +BAREBOX_CMD_HELP_OPT("-V <varname>", "specify variable name to set with the result") +BAREBOX_CMD_HELP_OPT("-b <blobdev>", "specify blob device to use") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(blobgen) + .cmd = do_blobgen, + BAREBOX_CMD_DESC("en/decrypt blobs") + BAREBOX_CMD_OPTS("[-edmVb] <plaintext/ciphertext>") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_blobgen_help) +BAREBOX_CMD_END diff --git a/commands/timeout.c b/commands/timeout.c index d197cedd8b..db88900287 100644 --- a/commands/timeout.c +++ b/commands/timeout.c @@ -61,7 +61,7 @@ static int do_timeout(int argc, char *argv[]) return COMMAND_ERROR_USAGE; timeout = simple_strtoul(argv[optind], NULL, 0); - ret = console_countdown(timeout, flags, str); + ret = console_countdown(timeout, flags, NULL, str); if (varname && str[0]) setenv(varname, str); diff --git a/common/bbu.c b/common/bbu.c index 5cb09e4eb0..00bec32a86 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -299,6 +299,8 @@ static int bbu_std_file_handler(struct bbu_handler *handler, return -EINVAL; } + device_detect_by_name(devpath_to_name(data->devicefile)); + ret = stat(data->devicefile, &s); if (ret) { oflags |= O_CREAT; @@ -361,7 +363,7 @@ err_close: * Return: 0 if successful, negative error code otherwise */ int bbu_register_std_file_update(const char *name, unsigned long flags, - char *devicefile, enum filetype imagetype) + const char *devicefile, enum filetype imagetype) { struct bbu_std *std; struct bbu_handler *handler; diff --git a/common/console.c b/common/console.c index 47ccf2e54d..406722a1da 100644 --- a/common/console.c +++ b/common/console.c @@ -574,18 +574,60 @@ void console_flush(void) } EXPORT_SYMBOL(console_flush); -#ifndef ARCH_HAS_CTRLC +static int ctrlc_abort; +static int ctrlc_allowed; + +void ctrlc_handled(void) +{ + ctrlc_abort = 0; +} + /* test if ctrl-c was pressed */ -int ctrlc (void) +int ctrlc(void) { + int ret = 0; + + if (!ctrlc_allowed) + return 0; + + if (ctrlc_abort) + return 1; + poller_call(); +#ifdef ARCH_HAS_CTRLC + ret = arch_ctrlc(); +#else if (tstc() && getchar() == 3) - return 1; - return 0; + ret = 1; +#endif + + if (ret) + ctrlc_abort = 1; + + return ret; } EXPORT_SYMBOL(ctrlc); -#endif /* ARCH_HAS_CTRC */ + +static int console_ctrlc_init(void) +{ + globalvar_add_simple_bool("console.ctrlc_allowed", &ctrlc_allowed); + return 0; +} +device_initcall(console_ctrlc_init); + +void console_ctrlc_allow(void) +{ + ctrlc_allowed = 1; +} + +void console_ctrlc_forbid(void) +{ + ctrlc_allowed = 0; +} + +BAREBOX_MAGICVAR_NAMED(global_console_ctrlc_allowed, global.console.ctrlc_allowed, + "If true, scripts can be aborted with ctrl-c"); BAREBOX_MAGICVAR_NAMED(global_linux_bootargs_console, global.linux.bootargs.console, "console= argument for Linux from the stdout-path property in /chosen node"); diff --git a/common/console_countdown.c b/common/console_countdown.c index 36da1ce577..8d09894c30 100644 --- a/common/console_countdown.c +++ b/common/console_countdown.c @@ -30,7 +30,22 @@ void console_countdown_abort(void) console_countdown_timeout_abort = true; } -int console_countdown(int timeout_s, unsigned flags, char *out_key) +static int key_in_list(char key, const char *keys) +{ + if (!keys) + return false; + + while (*keys) { + if (key == *keys) + return true; + keys++; + } + + return false; +} + +int console_countdown(int timeout_s, unsigned flags, const char *keys, + char *out_key) { uint64_t start, second; int countdown, ret = -EINTR; @@ -48,6 +63,8 @@ int console_countdown(int timeout_s, unsigned flags, char *out_key) if (tstc()) { key = getchar(); if (key >= 0) { + if (key_in_list(key, keys)) + goto out; if (flags & CONSOLE_COUNTDOWN_ANYKEY) goto out; if (flags & CONSOLE_COUNTDOWN_RETURN && key == '\n') diff --git a/common/filetype.c b/common/filetype.c index fb029a7739..e2d707b156 100644 --- a/common/filetype.c +++ b/common/filetype.c @@ -75,6 +75,8 @@ static const struct filetype_str filetype_str[] = { [filetype_elf] = { "ELF", "elf" }, [filetype_imx_image_v1] = { "i.MX image (v1)", "imx-image-v1" }, [filetype_imx_image_v2] = { "i.MX image (v2)", "imx-image-v2" }, + [filetype_layerscape_image] = { "Layerscape image", "layerscape-PBL" }, + [filetype_layerscape_qspi_image] = { "Layerscape QSPI image", "layerscape-qspi-PBL" }, }; const char *file_type_to_string(enum filetype f) @@ -329,6 +331,11 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize) if (is_sparse_image(_buf)) return filetype_android_sparse; + if (buf[0] == 0x55aa55aa && buf[1] == 0x0001ee01) + return filetype_layerscape_image; + if (buf[0] == 0x01ee0100 && buf[1] == 0xaa55aa55) + return filetype_layerscape_qspi_image; + if (bufsize < 64) return filetype_unknown; diff --git a/common/hush.c b/common/hush.c index d2f9cc70f5..dab9b04081 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1734,7 +1734,7 @@ static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int fla return 1; } b_free(&temp); - } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ + } while (!ctrlc() && rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ return code; } @@ -1932,6 +1932,7 @@ int run_shell(void) login(); do { + ctrlc_handled(); setup_file_in_str(&input); rcode = parse_stream_outer(&ctx, &input, FLAG_PARSE_SEMICOLON); if (rcode < -1) { diff --git a/common/parser.c b/common/parser.c index 397d268da1..fb9ef42e7f 100644 --- a/common/parser.c +++ b/common/parser.c @@ -283,6 +283,7 @@ int run_shell(void) /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } + ctrlc_handled(); } } return 0; diff --git a/common/startup.c b/common/startup.c index 28edee4fce..9fac0eabbd 100644 --- a/common/startup.c +++ b/common/startup.c @@ -42,6 +42,9 @@ #include <asm/sections.h> #include <uncompress.h> #include <globalvar.h> +#include <console_countdown.h> +#include <environment.h> +#include <linux/ctype.h> extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], __barebox_initcalls_end[]; @@ -143,16 +146,172 @@ static int load_environment(void) environment_initcall(load_environment); #endif +static int global_autoboot_abort_key; +static const char * const global_autoboot_abort_keys[] = { + "any", + "ctrl-c", +}; +static int global_autoboot_timeout = 3; +static char *global_boot_default; +static char *global_editcmd; +static char *global_linux_bootargs_base; +static char *global_linux_bootargs_console; +static char *global_linux_bootargs_dyn_ip; +static char *global_linux_bootargs_dyn_root; +static char *global_user; + +static bool test_abort(void) +{ + bool do_abort = false; + int c, ret; + char key; + + while (tstc()) { + c = getchar(); + if (tolower(c) == 'q' || c == 3) + do_abort = true; + } + + if (!do_abort) + return false; + + printf("Abort init sequence? (y/n)\n" + "Will continue with init sequence in:"); + + ret = console_countdown(5, CONSOLE_COUNTDOWN_EXTERN, "yYnN", &key); + if (!ret) + return false; + + if (tolower(key) == 'y') + return true; + + return false; +} + +static int run_init(void) +{ + DIR *dir; + struct dirent *d; + const char *initfile = "/env/bin/init"; + const char *initdir = "/env/init"; + const char *menufile = "/env/menu/mainmenu"; + struct stat s; + unsigned flags = CONSOLE_COUNTDOWN_EXTERN; + unsigned char outkey; + int ret; + bool menu_exists; + bool env_bin_init_exists; + char *abortkeys = NULL; + + setenv("PATH", "/env/bin"); + + /* Run legacy /env/bin/init if it exists */ + env_bin_init_exists = stat(initfile, &s) == 0; + if (env_bin_init_exists) { + pr_info("running %s...\n", initfile); + run_command(initfile); + return 0; + } + + global_editcmd = xstrdup("sedit"); + global_user = xstrdup("none"); + globalvar_add_simple_string("user", &global_user); + global_boot_default = xstrdup("net"); + + globalvar_add_simple_enum("autoboot_abort_key", + &global_autoboot_abort_key, + global_autoboot_abort_keys, + ARRAY_SIZE(global_autoboot_abort_keys)); + globalvar_add_simple_int("autoboot_timeout", + &global_autoboot_timeout, "%u"); + globalvar_add_simple_string("boot.default", &global_boot_default); + globalvar_add_simple_string("editcmd", &global_editcmd); + globalvar_add_simple_string("linux.bootargs.base", + &global_linux_bootargs_base); + globalvar_add_simple_string("linux.bootargs.console", + &global_linux_bootargs_console); + globalvar_add_simple_string("linux.bootargs.dyn.ip", + &global_linux_bootargs_dyn_ip); + globalvar_add_simple_string("linux.bootargs.dyn.root", + &global_linux_bootargs_dyn_root); + + /* Unblank console cursor */ + printf("\e[?25h"); + + if (test_abort()) { + pr_info("Init sequence aborted\n"); + return -EINTR; + } + + /* Run scripts in /env/init/ */ + dir = opendir(initdir); + if (dir) { + char *scr; + + while ((d = readdir(dir))) { + if (*d->d_name == '.') + continue; + + pr_debug("Executing '%s/%s'...\n", initdir, d->d_name); + scr = basprintf("source %s/%s", initdir, d->d_name); + run_command(scr); + free(scr); + } + + closedir(dir); + } + + menu_exists = stat(menufile, &s) == 0; + + if (menu_exists) { + printf("\nHit m for menu or %s to stop autoboot: ", + global_autoboot_abort_keys[global_autoboot_abort_key]); + abortkeys = "m"; + } else { + printf("\nHit %s to stop autoboot: ", + global_autoboot_abort_keys[global_autoboot_abort_key]); + } + + switch (global_autoboot_abort_key) { + case 0: + flags |= CONSOLE_COUNTDOWN_ANYKEY; + break; + case 1: + flags |= CONSOLE_COUNTDOWN_CTRLC; + break; + default: + break; + } + + ret = console_countdown(global_autoboot_timeout, flags, abortkeys, + &outkey); + + if (ret == 0) + run_command("boot"); + + console_ctrlc_allow(); + + if (menu_exists) { + if (outkey == 'm') + run_command(menufile); + + printf("Enter 'exit' to get back to the menu\n"); + run_shell(); + run_command(menufile); + } + + return 0; +} + int (*barebox_main)(void); void __noreturn start_barebox(void) { initcall_t *initcall; int result; - struct stat s; - if (!IS_ENABLED(CONFIG_SHELL_NONE)) - barebox_main = run_shell; + if (!IS_ENABLED(CONFIG_SHELL_NONE) && IS_ENABLED(CONFIG_COMMAND_SUPPORT)) + barebox_main = run_init; for (initcall = __barebox_initcalls_start; initcall < __barebox_initcalls_end; initcall++) { @@ -165,25 +324,16 @@ void __noreturn start_barebox(void) pr_debug("initcalls done\n"); - if (IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { - pr_info("running /env/bin/init...\n"); - - if (!stat("/env/bin/init", &s)) - run_command("source /env/bin/init"); - else - pr_err("/env/bin/init not found\n"); - } + if (barebox_main) + barebox_main(); - if (!barebox_main) { - pr_err("No main function! aborting.\n"); + if (IS_ENABLED(CONFIG_SHELL_NONE)) { + pr_err("Nothing left to do\n"); hang(); + } else { + while (1) + run_shell(); } - - /* main_loop() can return to retry autoboot, if so just run it again. */ - for (;;) - barebox_main(); - - /* NOTREACHED - no way out of command loop except booting */ } void __noreturn hang (void) diff --git a/defaultenv/defaultenv-2-base/bin/init b/defaultenv/defaultenv-2-base/bin/init deleted file mode 100644 index 8d02e3d3ab..0000000000 --- a/defaultenv/defaultenv-2-base/bin/init +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh - -export PATH=/env/bin - -global hostname -global user -global autoboot_timeout -global autoboot_abort_key -global boot.default -global linux.bootargs.base -global linux.bootargs.console -#linux.bootargs.dyn.* will be cleared at the beginning of boot -global linux.bootargs.dyn.ip -global linux.bootargs.dyn.root -global editcmd - -[ -z "${global.hostname}" ] && global.hostname=generic -[ -z "${global.user}" ] && global.user=none -magicvar -a global.user "username (used in network filenames)" -[ -z "${global.autoboot_timeout}" ] && global.autoboot_timeout=3 -magicvar -a global.autoboot_timeout "timeout in seconds before automatic booting" -[ -z "${global.autoboot_abort_key}" ] && global.autoboot_abort_key=any -magicvar -a global.autoboot_abort_key "key to abort automatic booting (valid options: any, ctrl-c)" -[ -z "${global.boot.default}" ] && global.boot.default=net -[ -z "${global.editcmd}" ] && global.editcmd=sedit - -[ -e /env/config-board ] && /env/config-board -/env/config - -# allow to stop the boot before execute the /env/init/* -# but without waiting -timeout -s -a -v key 0 -autoboot="$?" - -echo -e -n "\e[?25h" -if [ "${key}" = "q" ]; then - exit -fi - -for i in /env/init/*; do - . $i -done - -if [ "${global.autoboot_abort_key}" = "ctrl-c" ]; then - abort_string="ctrl-c" - abort_args="-c" -else - abort_string="any key" - abort_args="-a" -fi - -if [ -e /env/menu ]; then - echo -e -n "\nHit m for menu or $abort_string to stop autoboot: " -else - echo -e -n "\nHit $abort_string to stop autoboot: " -fi - -if [ "$autoboot" = 0 ]; then - timeout $abort_args $global.autoboot_timeout -v key - autoboot="$?" -fi - -if [ "${key}" = "q" ]; then - exit -fi - -if [ "$autoboot" = 0 ]; then - boot -fi - -if [ -e /env/menu ]; then - if [ "${key}" != "m" ]; then - echo -e "\ntype exit to get to the menu" - sh - fi - /env/menu/mainmenu -fi diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c index baa42e14f4..ce4fbed68c 100644 --- a/drivers/clk/imx/clk-imx25.c +++ b/drivers/clk/imx/clk-imx25.c @@ -95,7 +95,7 @@ static int imx25_ccm_probe(struct device_d *dev) writel((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 15) | (1 << 19) | (1 << 21) | (1 << 22) | - (1 << 23) | (1 << 24) | (1 << 28), + (1 << 23) | (1 << 24) | (1 << 25) | (1 << 28), base + CCM_CGCR0); writel((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 13) | (1 << 14) | @@ -152,7 +152,9 @@ static int imx25_ccm_probe(struct device_d *dev) clks[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", base + CCM_CGCR0, 24); clks[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", base + CCM_CGCR1, 29); clks[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", base + CCM_CGCR0, 7); + clks[scc_ipg] = imx_clk_gate("scc_ipg", "ipg", base + CCM_CGCR2, 5); clks[rngb_ipg] = imx_clk_gate("rngb_ipg", "ipg", base + CCM_CGCR2, 3); + clks[dryice_ipg] = imx_clk_gate("dryice_ipg", "ipg", base + CCM_CGCR1, 8); clkdev_add_physbase(clks[per15], MX25_UART1_BASE_ADDR, NULL); clkdev_add_physbase(clks[per15], MX25_UART2_BASE_ADDR, NULL); @@ -176,6 +178,9 @@ static int imx25_ccm_probe(struct device_d *dev) clkdev_add_physbase(clks[lcdc_ipg_per], MX25_LCDC_BASE_ADDR, "per"); clkdev_add_physbase(clks[lcdc_ipg], MX25_LCDC_BASE_ADDR, "ipg"); clkdev_add_physbase(clks[lcdc_ahb], MX25_LCDC_BASE_ADDR, "ahb"); + clkdev_add_physbase(clks[scc_ipg], MX25_SCC_BASE_ADDR, "ipg"); + clkdev_add_physbase(clks[rngb_ipg], MX25_RNGB_BASE_ADDR, "ipg"); + clkdev_add_physbase(clks[dryice_ipg], MX25_DRYICE_BASE_ADDR, NULL); return 0; } diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 1b1b881052..d70f4416cb 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -459,26 +459,30 @@ enum { DDRMC_CR117_AXI0_FITYPEREG_SYNC = 0b01 << 16, }; -static int vf610_switch_cpu_clock_to_500mhz(void) +static bool vf610_cpu_clk_changeable(void) { - int ret; - /* * When switching A5 CPU to 500Mhz we expect DDRC to be * clocked by PLL2_PFD2 and the system to be configured in * asynchronous mode. - * - * We also can't just use default PFD1 output of PLL1 due to - * Errata e6235, so we have to re-clock the PLL itself and use - * its output to clock the CPU directly. */ - if (clk_get_parent(clk[VF610_CLK_DDR_SEL]) != clk[VF610_CLK_PLL2_PFD2]) { - pr_warn("DDRC is clocked by PLL1, can't switch CPU clock"); - return -EINVAL; + pr_warn("DDRC is clocked by PLL1, can't switch CPU clock\n"); + return false; } + return true; +} + +static int vf610_switch_cpu_clock_to_500mhz(void) +{ + int ret; + /* + * We can't just use default PFD1 output of PLL1 due to + * Errata e6235, so we have to re-clock the PLL itself and use + * its output to clock the CPU directly. + * * Code below alters the frequency of PLL1, and doing so would * require us to wait for PLL1 lock before proceeding to * select it as a clock source again. @@ -533,11 +537,6 @@ static int vf610_switch_cpu_clock_to_400mhz(void) uint32_t cr117; void * __iomem ddrmc = IOMEM(VF610_DDR_BASE_ADDR); - if (clk_get_parent(clk[VF610_CLK_DDR_SEL]) != clk[VF610_CLK_PLL2_PFD2]) { - pr_warn("DDRC is clocked by PLL1, can't switch CPU clock"); - return -EINVAL; - } - ret = clk_set_parent(clk[VF610_CLK_PLL2_PFD_SEL], clk[VF610_CLK_PLL2_PFD2]); if (ret < 0) { pr_crit("Unable to re-parent '%s'\n", @@ -595,10 +594,14 @@ static int vf610_switch_cpu_clock(void) return 0; case VF610_SPEED_500: + if (!vf610_cpu_clk_changeable()) + return 0; ret = vf610_switch_cpu_clock_to_500mhz(); break; case VF610_SPEED_400: + if (!vf610_cpu_clk_changeable()) + return 0; ret = vf610_switch_cpu_clock_to_400mhz(); break; } diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index b2709f00f8..77d3782bde 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -5,5 +5,6 @@ menuconfig CRYPTO_HW if CRYPTO_HW source "drivers/crypto/caam/Kconfig" +source "drivers/crypto/imx-scc/Kconfig" endif diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 67f968f76c..1999929bc2 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ +obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += imx-scc/ diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 7bd6f3e23c..933b9c0592 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += ctrl.o error.o jr.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG) += caamrng.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_SELF_TEST) += rng_self_test.o +obj-$(CONFIG_BLOBGEN) += caam-blobgen.o diff --git a/drivers/crypto/caam/caam-blobgen.c b/drivers/crypto/caam/caam-blobgen.c new file mode 100644 index 0000000000..acbe5a110d --- /dev/null +++ b/drivers/crypto/caam/caam-blobgen.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * 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 <common.h> +#include <asm/io.h> +#include <base64.h> +#include <blobgen.h> +#include <crypto.h> +#include <dma.h> +#include <driver.h> +#include <init.h> +#include <fs.h> +#include <fcntl.h> +#include "intern.h" +#include "desc.h" +#include "desc_constr.h" +#include "error.h" +#include "jr.h" + +/* + * Upon completion, desc points to a buffer containing a CAAM job + * descriptor which encapsulates data into an externally-storable + * blob. + */ +#define INITIAL_DESCSZ 16 +/* 32 bytes key blob + 16 bytes HMAC identifier */ +#define BLOB_OVERHEAD (32 + 16) +#define KEYMOD_LENGTH 16 +#define RED_BLOB_LENGTH 64 +#define MAX_BLOB_LEN 4096 +#define DESC_LEN 64 + +struct blob_job_result { + int err; +}; + +struct blob_priv { + struct blobgen bg; + u32 desc[DESC_LEN]; + dma_addr_t dma_modifier; + dma_addr_t dma_plaintext; + dma_addr_t dma_ciphertext; +}; + +static struct blob_priv *to_blob_priv(struct blobgen *bg) +{ + return container_of(bg, struct blob_priv, bg); +} + +static void jr_jobdesc_blob_decap(struct blob_priv *ctx, u8 modlen, u16 input_size) +{ + u32 *desc = ctx->desc; + u16 in_sz; + u16 out_sz; + + in_sz = input_size; + out_sz = input_size - BLOB_OVERHEAD; + + init_job_desc(desc, 0); + /* + * The key modifier can be used to differentiate specific data. + * Or to prevent replay attacks. + */ + append_key(desc, ctx->dma_modifier, modlen, CLASS_2); + append_seq_in_ptr(desc, ctx->dma_ciphertext, in_sz, 0); + append_seq_out_ptr(desc, ctx->dma_plaintext, out_sz, 0); + append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB); +} + +static void jr_jobdesc_blob_encap(struct blob_priv *ctx, u8 modlen, u16 input_size) +{ + u32 *desc = ctx->desc; + u16 in_sz; + u16 out_sz; + + in_sz = input_size; + out_sz = input_size + BLOB_OVERHEAD; + + init_job_desc(desc, 0); + /* + * The key modifier can be used to differentiate specific data. + * Or to prevent replay attacks. + */ + append_key(desc, ctx->dma_modifier, modlen, CLASS_2); + append_seq_in_ptr(desc, ctx->dma_plaintext, in_sz, 0); + append_seq_out_ptr(desc, ctx->dma_ciphertext, out_sz, 0); + append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB); +} + +static void blob_job_done(struct device_d *dev, u32 *desc, u32 err, void *arg) +{ + struct blob_job_result *res = arg; + + if (!res) + return; + + if (err) + caam_jr_strstatus(dev, err); + + res->err = err; +} + +static int caam_blob_decrypt(struct blobgen *bg, const char *modifier, + const void *blob, int blobsize, void **plain, + int *plainsize) +{ + struct blob_priv *ctx = to_blob_priv(bg); + struct device_d *jrdev = bg->dev.parent; + struct blob_job_result testres; + int modifier_len = strlen(modifier); + u32 *desc = ctx->desc; + int ret; + + if (blobsize <= BLOB_OVERHEAD) + return -EINVAL; + + *plainsize = blobsize - BLOB_OVERHEAD; + + *plain = dma_alloc(*plainsize); + if (!*plain) + return -ENOMEM; + + memset(desc, 0, DESC_LEN); + + ctx->dma_modifier = (dma_addr_t)modifier; + ctx->dma_plaintext = (dma_addr_t)*plain; + ctx->dma_ciphertext = (dma_addr_t)blob; + + jr_jobdesc_blob_decap(ctx, modifier_len, blobsize); + + dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc), + DMA_TO_DEVICE); + + dma_sync_single_for_device((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)*plain, *plainsize, + DMA_FROM_DEVICE); + dma_sync_single_for_device((unsigned long)blob, blobsize, + DMA_TO_DEVICE); + + testres.err = 0; + + ret = caam_jr_enqueue(jrdev, desc, blob_job_done, &testres); + if (ret) + dev_err(jrdev, "decryption error\n"); + + ret = testres.err; + + dma_sync_single_for_cpu((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_cpu((unsigned long)*plain, *plainsize, + DMA_FROM_DEVICE); + dma_sync_single_for_cpu((unsigned long)blob, blobsize, + DMA_TO_DEVICE); + + return ret; +} + +static int caam_blob_encrypt(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, void *blob, + int *blobsize) +{ + struct blob_priv *ctx = to_blob_priv(bg); + struct device_d *jrdev = bg->dev.parent; + struct blob_job_result testres; + int modifier_len = strlen(modifier); + u32 *desc = ctx->desc; + int ret; + + *blobsize = plainsize + BLOB_OVERHEAD; + + memset(desc, 0, DESC_LEN); + + ctx->dma_modifier = (dma_addr_t)modifier; + ctx->dma_plaintext = (dma_addr_t)plain; + ctx->dma_ciphertext = (dma_addr_t)blob; + + jr_jobdesc_blob_encap(ctx, modifier_len, plainsize); + + dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc), + DMA_TO_DEVICE); + + dma_sync_single_for_device((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)plain, plainsize, + DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)blob, *blobsize, + DMA_FROM_DEVICE); + + testres.err = 0; + + ret = caam_jr_enqueue(jrdev, desc, blob_job_done, &testres); + if (ret) + dev_err(jrdev, "encryption error\n"); + + ret = testres.err; + + dma_sync_single_for_cpu((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_cpu((unsigned long)plain, plainsize, + DMA_TO_DEVICE); + dma_sync_single_for_cpu((unsigned long)blob, *blobsize, + DMA_FROM_DEVICE); + + return ret; +} + +int caam_blob_gen_probe(struct device_d *dev, struct device_d *jrdev) +{ + struct blob_priv *ctx; + struct blobgen *bg; + int ret; + + ctx = xzalloc(sizeof(*ctx)); + bg = &ctx->bg; + bg->max_payload_size = MAX_BLOB_LEN - BLOB_OVERHEAD; + bg->encrypt = caam_blob_encrypt; + bg->decrypt = caam_blob_decrypt; + + ret = blob_gen_register(jrdev, bg); + if (ret) + free(ctx); + + return ret; +} diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 4fe3eea3e6..06b075e74a 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -654,6 +654,15 @@ static int caam_probe(struct device_d *dev) } } + if (IS_ENABLED(CONFIG_BLOBGEN)) { + ret = caam_blob_gen_probe(dev, ctrlpriv->jrpdev[0]); + if (ret) { + dev_err(dev, "failed to instantiate blobgen device"); + caam_remove(dev); + return ret; + } + } + /* NOTE: RTIC detection ought to go here, around Si time */ caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 | (u64)rd_reg32(&ctrl->perfmon.caam_id_ls); diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index fe19a2c8d2..6dfcea26ac 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -93,5 +93,6 @@ void caam_jr_algapi_init(struct device *dev); void caam_jr_algapi_remove(struct device *dev); int caam_rng_probe(struct device_d *dev, struct device_d *jrdev); +int caam_blob_gen_probe(struct device_d *dev, struct device_d *jrdev); int caam_jr_probe(struct device_d *dev); #endif /* INTERN_H */ diff --git a/drivers/crypto/caam/rng_self_test.c b/drivers/crypto/caam/rng_self_test.c index aab4fa2e47..7816cd152c 100644 --- a/drivers/crypto/caam/rng_self_test.c +++ b/drivers/crypto/caam/rng_self_test.c @@ -51,6 +51,7 @@ #include "error.h" #include "regs.h" #include "jr.h" +#include "rng_self_test.h" static const u32 rng_dsc1[] = { 0xb0800036, 0x04800010, 0x3c85a15b, 0x50a9d0b1, diff --git a/drivers/crypto/imx-scc/Kconfig b/drivers/crypto/imx-scc/Kconfig new file mode 100644 index 0000000000..531304f432 --- /dev/null +++ b/drivers/crypto/imx-scc/Kconfig @@ -0,0 +1,14 @@ +config CRYPTO_DEV_MXC_SCC + tristate "Support for Freescale Security Controller (SCC)" + depends on ARCH_IMX25 && OFTREE + select CRYPTO_BLKCIPHER + select CRYPTO_DES + help + This option enables support for the Security Controller (SCC) + found in Freescale i.MX25 chips. + +config CRYPTO_DEV_MXC_SCC_BLOB_GEN + tristate "Support for SCC blob gen" + depends on ARCH_IMX25 + select BLOBGEN + select CRYPTO_DEV_MXC_SCC diff --git a/drivers/crypto/imx-scc/Makefile b/drivers/crypto/imx-scc/Makefile new file mode 100644 index 0000000000..c30fd1e12d --- /dev/null +++ b/drivers/crypto/imx-scc/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += scc.o +obj-$(CONFIG_CRYPTO_DEV_MXC_SCC_BLOB_GEN) += scc-blobgen.o diff --git a/drivers/crypto/imx-scc/scc-blobgen.c b/drivers/crypto/imx-scc/scc-blobgen.c new file mode 100644 index 0000000000..e1a1372420 --- /dev/null +++ b/drivers/crypto/imx-scc/scc-blobgen.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * 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 <common.h> +#include <dma.h> +#include <digest.h> +#include <driver.h> +#include <init.h> +#include <blobgen.h> +#include <stdlib.h> +#include <crypto.h> +#include <crypto/sha.h> + +#include "scc.h" + +#define MAX_IVLEN BLOCKSIZE_BYTES + +static struct digest *sha256; + +static int sha256sum(uint8_t *src, uint8_t *dst, unsigned int size) +{ + if (!sha256) + sha256 = digest_alloc("sha256"); + + if (!sha256) { + pr_err("Unable to allocate sha256 digest\n"); + return -EINVAL; + } + + return digest_digest(sha256, src, size, dst); +} + +static int imx_scc_blob_encrypt(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, void *blob, + int *blobsize) +{ + char *s; + int bufsiz; + struct ablkcipher_request req = {}; + uint8_t iv[MAX_IVLEN]; + uint8_t hash[SHA256_DIGEST_SIZE]; + int ret; + + bufsiz = ALIGN(plainsize + KEYMOD_LENGTH, 8); + + s = malloc(bufsiz + SHA256_DIGEST_SIZE); + if (!s) + return -ENOMEM; + + memset(s, 0, bufsiz); + + strncpy(s, modifier, KEYMOD_LENGTH); + memcpy(s + KEYMOD_LENGTH, plain, plainsize); + + ret = sha256sum(s, hash, bufsiz); + if (ret) + goto out; + + memcpy(s + bufsiz, hash, SHA256_DIGEST_SIZE); + + bufsiz += SHA256_DIGEST_SIZE; + + req.info = iv; + req.src = s; + req.dst = blob; + req.nbytes = bufsiz; + + get_random_bytes(req.info, MAX_IVLEN); + + ret = imx_scc_cbc_des_encrypt(&req); + if (ret) + goto out; + + memcpy(blob + bufsiz, req.info, MAX_IVLEN); + *blobsize = bufsiz + MAX_IVLEN; + +out: + free(s); + + return ret; +} + +static int imx_scc_blob_decrypt(struct blobgen *bg, const char *modifier, + const void *blob, int blobsize, void **plain, + int *plainsize) +{ + struct ablkcipher_request req = {}; + uint8_t iv[MAX_IVLEN]; + uint8_t hash[SHA256_DIGEST_SIZE]; + int ret; + uint8_t *data; + int ciphersize = blobsize - MAX_IVLEN; + + if (blobsize <= MAX_IVLEN + SHA256_DIGEST_SIZE + KEYMOD_LENGTH) + return -EINVAL; + + data = malloc(ciphersize); + if (!data) + return -ENOMEM; + + req.info = iv; + req.nbytes = ciphersize; + req.src = (void *)blob; + req.dst = data; + + memcpy(req.info, blob + req.nbytes, MAX_IVLEN); + + ret = imx_scc_cbc_des_decrypt(&req); + if (ret) + goto out; + + ret = sha256sum(data, hash, ciphersize - SHA256_DIGEST_SIZE); + if (ret) + goto out; + + if (memcmp(data + ciphersize - SHA256_DIGEST_SIZE, hash, + SHA256_DIGEST_SIZE)) { + pr_err("%s: Corrupted SHA256 digest. Can't continue.\n", + bg->dev.name); + pr_err("%s: Calculated hash:\n", bg->dev.name); + memory_display(hash, 0, SHA256_DIGEST_SIZE, 1, 0); + pr_err("%s: Received hash:\n", bg->dev.name); + memory_display(data + ciphersize - SHA256_DIGEST_SIZE, + 0, SHA256_DIGEST_SIZE, 1, 0); + + ret = -EILSEQ; + goto out; + } + + *plainsize = ciphersize - SHA256_DIGEST_SIZE - KEYMOD_LENGTH; + *plain = xmemdup(data + KEYMOD_LENGTH, *plainsize); +out: + free(data); + + return ret; +} + +int imx_scc_blob_gen_probe(struct device_d *dev) +{ + struct blobgen *bg; + int ret; + + bg = xzalloc(sizeof(*bg)); + + bg->max_payload_size = MAX_BLOB_LEN - MAX_IVLEN - + SHA256_DIGEST_SIZE - KEYMOD_LENGTH; + bg->encrypt = imx_scc_blob_encrypt; + bg->decrypt = imx_scc_blob_decrypt; + + ret = blob_gen_register(dev, bg); + if (ret) + free(bg); + + return ret; +} diff --git a/drivers/crypto/imx-scc/scc.c b/drivers/crypto/imx-scc/scc.c new file mode 100644 index 0000000000..5a35c3506d --- /dev/null +++ b/drivers/crypto/imx-scc/scc.c @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * The driver is based on information gathered from + * drivers/mxc/security/imx_scc.c which can be found in + * the Freescale linux-2.6-imx.git in the imx_2.6.35_maintain branch. + * + * 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. + * + */ +#include <common.h> +#include <clock.h> +#include <driver.h> +#include <init.h> +#include <io.h> +#include <crypto.h> +#include <linux/barebox-wrapper.h> +#include <linux/clk.h> +#include <crypto/des.h> + +#include "scc.h" + +/* Secure Memory (SCM) registers */ +#define SCC_SCM_RED_START 0x0000 +#define SCC_SCM_BLACK_START 0x0004 +#define SCC_SCM_LENGTH 0x0008 +#define SCC_SCM_CTRL 0x000C +#define SCC_SCM_STATUS 0x0010 +#define SCC_SCM_ERROR_STATUS 0x0014 +#define SCC_SCM_INTR_CTRL 0x0018 +#define SCC_SCM_CFG 0x001C +#define SCC_SCM_INIT_VECTOR_0 0x0020 +#define SCC_SCM_INIT_VECTOR_1 0x0024 +#define SCC_SCM_RED_MEMORY 0x0400 +#define SCC_SCM_BLACK_MEMORY 0x0800 + +/* Security Monitor (SMN) Registers */ +#define SCC_SMN_STATUS 0x1000 +#define SCC_SMN_COMMAND 0x1004 +#define SCC_SMN_SEQ_START 0x1008 +#define SCC_SMN_SEQ_END 0x100C +#define SCC_SMN_SEQ_CHECK 0x1010 +#define SCC_SMN_BIT_COUNT 0x1014 +#define SCC_SMN_BITBANK_INC_SIZE 0x1018 +#define SCC_SMN_BITBANK_DECREMENT 0x101C +#define SCC_SMN_COMPARE_SIZE 0x1020 +#define SCC_SMN_PLAINTEXT_CHECK 0x1024 +#define SCC_SMN_CIPHERTEXT_CHECK 0x1028 +#define SCC_SMN_TIMER_IV 0x102C +#define SCC_SMN_TIMER_CONTROL 0x1030 +#define SCC_SMN_DEBUG_DETECT_STAT 0x1034 +#define SCC_SMN_TIMER 0x1038 + +#define SCC_SCM_CTRL_START_CIPHER BIT(2) +#define SCC_SCM_CTRL_CBC_MODE BIT(1) +#define SCC_SCM_CTRL_DECRYPT_MODE BIT(0) + +#define SCC_SCM_STATUS_LEN_ERR BIT(12) +#define SCC_SCM_STATUS_SMN_UNBLOCKED BIT(11) +#define SCC_SCM_STATUS_CIPHERING_DONE BIT(10) +#define SCC_SCM_STATUS_ZEROIZING_DONE BIT(9) +#define SCC_SCM_STATUS_INTR_STATUS BIT(8) +#define SCC_SCM_STATUS_SEC_KEY BIT(7) +#define SCC_SCM_STATUS_INTERNAL_ERR BIT(6) +#define SCC_SCM_STATUS_BAD_SEC_KEY BIT(5) +#define SCC_SCM_STATUS_ZEROIZE_FAIL BIT(4) +#define SCC_SCM_STATUS_SMN_BLOCKED BIT(3) +#define SCC_SCM_STATUS_CIPHERING BIT(2) +#define SCC_SCM_STATUS_ZEROIZING BIT(1) +#define SCC_SCM_STATUS_BUSY BIT(0) + +#define SCC_SMN_STATUS_STATE_MASK 0x0000001F +#define SCC_SMN_STATE_START 0x0 +/* The SMN is zeroizing its RAM during reset */ +#define SCC_SMN_STATE_ZEROIZE_RAM 0x5 +/* SMN has passed internal checks */ +#define SCC_SMN_STATE_HEALTH_CHECK 0x6 +/* Fatal Security Violation. SMN is locked, SCM is inoperative. */ +#define SCC_SMN_STATE_FAIL 0x9 +/* SCC is in secure state. SCM is using secret key. */ +#define SCC_SMN_STATE_SECURE 0xA +/* SCC is not secure. SCM is using default key. */ +#define SCC_SMN_STATE_NON_SECURE 0xC + +#define SCC_SCM_INTR_CTRL_ZEROIZE_MEM BIT(2) +#define SCC_SCM_INTR_CTRL_CLR_INTR BIT(1) +#define SCC_SCM_INTR_CTRL_MASK_INTR BIT(0) + +/* Size, in blocks, of Red memory. */ +#define SCC_SCM_CFG_BLACK_SIZE_MASK 0x07fe0000 +#define SCC_SCM_CFG_BLACK_SIZE_SHIFT 17 +/* Size, in blocks, of Black memory. */ +#define SCC_SCM_CFG_RED_SIZE_MASK 0x0001ff80 +#define SCC_SCM_CFG_RED_SIZE_SHIFT 7 +/* Number of bytes per block. */ +#define SCC_SCM_CFG_BLOCK_SIZE_MASK 0x0000007f + +#define SCC_SMN_COMMAND_TAMPER_LOCK BIT(4) +#define SCC_SMN_COMMAND_CLR_INTR BIT(3) +#define SCC_SMN_COMMAND_CLR_BIT_BANK BIT(2) +#define SCC_SMN_COMMAND_EN_INTR BIT(1) +#define SCC_SMN_COMMAND_SET_SOFTWARE_ALARM BIT(0) + +#define SCC_KEY_SLOTS 20 +#define SCC_MAX_KEY_SIZE 32 +#define SCC_KEY_SLOT_SIZE 32 + +#define SCC_CRC_CCITT_START 0xFFFF + +/* + * Offset into each RAM of the base of the area which is not + * used for Stored Keys. + */ +#define SCC_NON_RESERVED_OFFSET (SCC_KEY_SLOTS * SCC_KEY_SLOT_SIZE) + +/* Fixed padding for appending to plaintext to fill out a block */ +static char scc_block_padding[8] = { 0x80, 0, 0, 0, 0, 0, 0, 0 }; + +struct imx_scc { + struct device_d *dev; + void __iomem *base; + struct clk *clk; + struct ablkcipher_request *req; + unsigned int block_size_bytes; + unsigned int black_ram_size_blocks; + unsigned int memory_size_bytes; + unsigned int bytes_remaining; + + void __iomem *red_memory; + void __iomem *black_memory; +}; + +struct imx_scc_ctx { + struct imx_scc *scc; + unsigned int offset; + unsigned int size; + unsigned int ctrl; +}; + +static struct imx_scc *scc_dev; + +static int imx_scc_get_data(struct imx_scc_ctx *ctx, + struct ablkcipher_request *ablkreq) +{ + struct imx_scc *scc = ctx->scc; + void __iomem *from; + + if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) + from = scc->red_memory; + else + from = scc->black_memory; + + memcpy(ablkreq->dst, from + ctx->offset, ctx->size); + + pr_debug("GET_DATA:\n"); + pr_memory_display(MSG_DEBUG, from, 0, ctx->size, 0x40 >> 3, 0); + + ctx->offset += ctx->size; + + if (ctx->offset < ablkreq->nbytes) + return -EINPROGRESS; + + return 0; +} + +static int imx_scc_ablkcipher_req_init(struct ablkcipher_request *req, + struct imx_scc_ctx *ctx) +{ + ctx->size = 0; + ctx->offset = 0; + + return 0; +} + +static int imx_scc_put_data(struct imx_scc_ctx *ctx, + struct ablkcipher_request *req) +{ + u8 padding_buffer[sizeof(u16) + sizeof(scc_block_padding)]; + size_t len = min(req->nbytes - ctx->offset, ctx->scc->bytes_remaining); + unsigned int padding_byte_count = 0; + struct imx_scc *scc = ctx->scc; + void __iomem *to; + + if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) + to = scc->black_memory; + else + to = scc->red_memory; + + if (ctx->ctrl & SCC_SCM_CTRL_CBC_MODE) { + dev_dbg(scc->dev, "set IV@0x%p\n", scc->base + SCC_SCM_INIT_VECTOR_0); + memcpy(scc->base + SCC_SCM_INIT_VECTOR_0, req->info, + scc->block_size_bytes); + } + + memcpy(to, req->src + ctx->offset, len); + + ctx->size = len; + + scc->bytes_remaining -= len; + + padding_byte_count = ((len + scc->block_size_bytes - 1) & + ~(scc->block_size_bytes-1)) - len; + + if (padding_byte_count) { + memcpy(padding_buffer, scc_block_padding, padding_byte_count); + memcpy(to + len, padding_buffer, padding_byte_count); + ctx->size += padding_byte_count; + } + + dev_dbg(scc->dev, "copied %d bytes to 0x%p\n", ctx->size, to); + pr_debug("IV:\n"); + pr_memory_display(MSG_DEBUG, scc->base + SCC_SCM_INIT_VECTOR_0, 0, + scc->block_size_bytes, + 0x40 >> 3, 0); + pr_debug("DATA:\n"); + pr_memory_display(MSG_DEBUG, to, 0, ctx->size, 0x40 >> 3, 0); + + return 0; +} + +static int imx_scc_ablkcipher_next(struct imx_scc_ctx *ctx, + struct ablkcipher_request *ablkreq) +{ + struct imx_scc *scc = ctx->scc; + int err; + + writel(0, scc->base + SCC_SCM_ERROR_STATUS); + + err = imx_scc_put_data(ctx, ablkreq); + if (err) + return err; + + dev_dbg(scc->dev, "Start encryption (0x%p/0x%p)\n", + (void *)readl(scc->base + SCC_SCM_RED_START), + (void *)readl(scc->base + SCC_SCM_BLACK_START)); + + /* clear interrupt control registers */ + writel(SCC_SCM_INTR_CTRL_CLR_INTR, + scc->base + SCC_SCM_INTR_CTRL); + + writel((ctx->size / ctx->scc->block_size_bytes) - 1, + scc->base + SCC_SCM_LENGTH); + + dev_dbg(scc->dev, "Process %d block(s) in 0x%p\n", + ctx->size / ctx->scc->block_size_bytes, + (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) ? scc->black_memory : + scc->red_memory); + + writel(ctx->ctrl, scc->base + SCC_SCM_CTRL); + + return 0; +} + +static int imx_scc_int(struct imx_scc_ctx *ctx) +{ + struct ablkcipher_request *ablkreq; + struct imx_scc *scc = ctx->scc; + uint64_t start; + + start = get_time_ns(); + while (readl(scc->base + SCC_SCM_STATUS) & SCC_SCM_STATUS_BUSY) { + if (is_timeout(start, 100 * MSECOND)) { + dev_err(scc->dev, "timeout waiting for interrupt\n"); + return -ETIMEDOUT; + } + } + + /* clear interrupt control registers */ + writel(SCC_SCM_INTR_CTRL_CLR_INTR, scc->base + SCC_SCM_INTR_CTRL); + + ablkreq = scc->req; + + if (ablkreq) + return imx_scc_get_data(ctx, ablkreq); + + return 0; +} + +static int imx_scc_process_req(struct imx_scc_ctx *ctx, + struct ablkcipher_request *ablkreq) +{ + int ret = -EINPROGRESS; + + ctx->scc->req = ablkreq; + + while (ret == -EINPROGRESS) { + ret = imx_scc_ablkcipher_next(ctx, ablkreq); + if (ret) + break; + ret = imx_scc_int(ctx); + } + + ctx->scc->req = NULL; + ctx->scc->bytes_remaining = ctx->scc->memory_size_bytes; + + return 0; +} + +static int imx_scc_des3_op(struct imx_scc_ctx *ctx, + struct ablkcipher_request *req) +{ + int err; + + err = imx_scc_ablkcipher_req_init(req, ctx); + if (err) + return err; + + return imx_scc_process_req(ctx, req); +} + +int imx_scc_cbc_des_encrypt(struct ablkcipher_request *req) +{ + struct imx_scc_ctx *ctx; + + ctx = xzalloc(sizeof(*ctx)); + ctx->scc = scc_dev; + + ctx->ctrl = SCC_SCM_CTRL_START_CIPHER; + ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE; + + return imx_scc_des3_op(ctx, req); +} + +int imx_scc_cbc_des_decrypt(struct ablkcipher_request *req) +{ + struct imx_scc_ctx *ctx; + + ctx = xzalloc(sizeof(*ctx)); + ctx->scc = scc_dev; + + ctx->ctrl = SCC_SCM_CTRL_START_CIPHER; + ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE; + ctx->ctrl |= SCC_SCM_CTRL_DECRYPT_MODE; + + return imx_scc_des3_op(ctx, req); +} + +static void imx_scc_hw_init(struct imx_scc *scc) +{ + int offset; + + offset = SCC_NON_RESERVED_OFFSET / scc->block_size_bytes; + + /* Fill the RED_START register */ + writel(offset, scc->base + SCC_SCM_RED_START); + + /* Fill the BLACK_START register */ + writel(offset, scc->base + SCC_SCM_BLACK_START); + + scc->red_memory = scc->base + SCC_SCM_RED_MEMORY + + SCC_NON_RESERVED_OFFSET; + + scc->black_memory = scc->base + SCC_SCM_BLACK_MEMORY + + SCC_NON_RESERVED_OFFSET; + + scc->bytes_remaining = scc->memory_size_bytes; +} + +static int imx_scc_get_config(struct imx_scc *scc) +{ + int config; + + config = readl(scc->base + SCC_SCM_CFG); + + scc->block_size_bytes = config & SCC_SCM_CFG_BLOCK_SIZE_MASK; + + scc->black_ram_size_blocks = config & SCC_SCM_CFG_BLACK_SIZE_MASK; + + scc->memory_size_bytes = (scc->block_size_bytes * + scc->black_ram_size_blocks) - + SCC_NON_RESERVED_OFFSET; + + return 0; +} + +static int imx_scc_get_state(struct imx_scc *scc) +{ + int status, ret; + const char *statestr; + + status = readl(scc->base + SCC_SMN_STATUS) & + SCC_SMN_STATUS_STATE_MASK; + + /* If in Health Check, try to bringup to secure state */ + if (status & SCC_SMN_STATE_HEALTH_CHECK) { + /* + * Write a simple algorithm to the Algorithm Sequence + * Checker (ASC) + */ + writel(0xaaaa, scc->base + SCC_SMN_SEQ_START); + writel(0x5555, scc->base + SCC_SMN_SEQ_END); + writel(0x5555, scc->base + SCC_SMN_SEQ_CHECK); + + status = readl(scc->base + SCC_SMN_STATUS) & + SCC_SMN_STATUS_STATE_MASK; + } + + switch (status) { + case SCC_SMN_STATE_NON_SECURE: + statestr = "non-secure"; + ret = 0; + break; + case SCC_SMN_STATE_SECURE: + statestr = "secure"; + ret = 0; + break; + case SCC_SMN_STATE_FAIL: + statestr = "fail"; + ret = -EIO; + break; + default: + statestr = "unknown"; + ret = -EINVAL; + break; + } + + dev_info(scc->dev, "starting in %s mode\n", statestr); + + return ret; +} + +static int imx_scc_probe(struct device_d *dev) +{ + struct imx_scc *scc; + int ret; + + scc = xzalloc(sizeof(*scc)); + + scc->base = dev_request_mem_region(dev, 0); + if (IS_ERR(scc->base)) + return PTR_ERR(scc->base); + + scc->clk = clk_get(dev, "ipg"); + if (IS_ERR(scc->clk)) { + dev_err(dev, "Could not get ipg clock\n"); + return PTR_ERR(scc->clk); + } + + clk_enable(scc->clk); + + /* clear error status register */ + + writel(0x0, scc->base + SCC_SCM_ERROR_STATUS); + + /* clear interrupt control registers */ + writel(SCC_SCM_INTR_CTRL_CLR_INTR | + SCC_SCM_INTR_CTRL_MASK_INTR, + scc->base + SCC_SCM_INTR_CTRL); + + writel(SCC_SMN_COMMAND_CLR_INTR | + SCC_SMN_COMMAND_EN_INTR, + scc->base + SCC_SMN_COMMAND); + + scc->dev = dev; + + ret = imx_scc_get_config(scc); + if (ret) + goto err_out; + + ret = imx_scc_get_state(scc); + + if (ret) { + dev_err(dev, "SCC in unusable state\n"); + goto err_out; + } + + imx_scc_hw_init(scc); + + scc_dev = scc; + + if (IS_ENABLED(CONFIG_BLOBGEN)) { + ret = imx_scc_blob_gen_probe(dev); + if (ret) + goto err_out; + } + + return 0; + +err_out: + clk_disable(scc->clk); + clk_put(scc->clk); + free(scc); + + return ret; +} + +static __maybe_unused struct of_device_id imx_scc_dt_ids[] = { + { .compatible = "fsl,imx25-scc", }, + { /* sentinel */ } +}; + +static struct driver_d imx_scc_driver = { + .name = "mxc-scc", + .probe = imx_scc_probe, + .of_compatible = imx_scc_dt_ids, +}; +device_platform_driver(imx_scc_driver); diff --git a/drivers/crypto/imx-scc/scc.h b/drivers/crypto/imx-scc/scc.h new file mode 100644 index 0000000000..5c5c25c4a0 --- /dev/null +++ b/drivers/crypto/imx-scc/scc.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * 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. + */ + +struct ablkcipher_request; + +int imx_scc_cbc_des_encrypt(struct ablkcipher_request *req); +int imx_scc_cbc_des_decrypt(struct ablkcipher_request *req); +int imx_scc_blob_gen_probe(struct device_d *dev); diff --git a/drivers/ddr/fsl/fsl_ddr.h b/drivers/ddr/fsl/fsl_ddr.h index ee6069d812..ab991a5bf4 100644 --- a/drivers/ddr/fsl/fsl_ddr.h +++ b/drivers/ddr/fsl/fsl_ddr.h @@ -227,8 +227,6 @@ unsigned int mclk_to_picos(struct fsl_ddr_controller *c, unsigned int mclk); unsigned int get_memory_clk_period_ps(struct fsl_ddr_controller *c); unsigned int picos_to_mclk(struct fsl_ddr_controller *c, unsigned int picos); -void fsl_ddr_set_memctl_regs(struct fsl_ddr_controller *c, int step); - void erratum_a009942_check_cpo(void); #endif diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c index f7f8c3348d..0251757a2a 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -16,6 +16,7 @@ #include <mci.h> #include <linux/sizes.h> #include <asm-generic/sections.h> +#include <asm/cache.h> #include <mach/xload.h> #ifdef CONFIG_ARCH_IMX #include <mach/atf.h> @@ -445,7 +446,7 @@ int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long */ val = esdhc_read32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET); val &= ~0x0000fff0; - val |= (2 << 8) | (6 << 4); + val |= (8 << 8) | (3 << 4); esdhc_write32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val); esdhc_write32(&esdhc, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP); @@ -457,6 +458,8 @@ int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long return ret; } + icache_invalidate(); + printf("Starting barebox\n"); barebox(r0, r1, r2); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 85b55c6982..1595349c4c 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -646,6 +646,7 @@ static const struct spi_device_id spi_nor_ids[] = { { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25q40bw", INFO(0xef5013, 0, 64 * 1024, 8, SECT_4K) }, { "w25q16dw", INFO(0xef6015, 0, 64 * 1024, 32, SECT_4K) }, { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, diff --git a/drivers/net/fsl-fman.c b/drivers/net/fsl-fman.c index 1a11ca4926..4e6bb2ecfd 100644 --- a/drivers/net/fsl-fman.c +++ b/drivers/net/fsl-fman.c @@ -640,6 +640,8 @@ static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth) i * MAX_RXBUF_LEN)); buf_lo = lower_32_bits(virt_to_phys(rx_buf_pool + i * MAX_RXBUF_LEN)); + dma_sync_single_for_device((unsigned long)rx_buf_pool + i * MAX_RXBUF_LEN, + MAX_RXBUF_LEN, DMA_FROM_DEVICE); muram_writew(&rxbd->buf_ptr_hi, (u16)buf_hi); out_be32(&rxbd->buf_ptr_lo, buf_lo); rxbd++; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7d181949ee..9d2c6e614b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -38,6 +38,12 @@ config RTC_DRV_ABRACON endif # I2C +config RTC_DRV_IMXDI + tristate "Freescale IMX DryIce Real Time Clock" + depends on ARCH_IMX + help + Support for Freescale IMX DryIce RTC + config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 RTC" depends on MACH_MIPS_XBURST diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 68741c26a1..1308beff38 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_RTC_CLASS) += class.o obj-$(CONFIG_RTC_DRV_ABRACON) += rtc-abracon.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o +obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c new file mode 100644 index 0000000000..8fcaf631ff --- /dev/null +++ b/drivers/rtc/rtc-imxdi.c @@ -0,0 +1,623 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2010 Orex Computed Radiography + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* based on rtc-mc13892.c */ + +/* + * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block + * to implement a Linux RTC. Times and alarms are truncated to seconds. + * Since the RTC framework performs API locking via rtc->ops_lock the + * only simultaneous accesses we need to deal with is updating DryIce + * registers while servicing an alarm. + * + * Note that reading the DSR (DryIce Status Register) automatically clears + * the WCF (Write Complete Flag). All DryIce writes are synchronized to the + * LP (Low Power) domain and set the WCF upon completion. Writes to the + * DIER (DryIce Interrupt Enable Register) are the only exception. These + * occur at normal bus speeds and do not set WCF. Periodic interrupts are + * not supported by the hardware. + */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <rtc.h> +#include <io.h> +#include <linux/clk.h> +#include <linux/rtc.h> +#include <linux/nvmem-provider.h> + +/* DryIce Register Definitions */ + +#define DTCMR 0x00 /* Time Counter MSB Reg */ +#define DTCLR 0x04 /* Time Counter LSB Reg */ + +#define DCAMR 0x08 /* Clock Alarm MSB Reg */ +#define DCALR 0x0c /* Clock Alarm LSB Reg */ +#define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */ + +#define DCR 0x10 /* Control Reg */ +#define DCR_TDCHL (1 << 30) /* Tamper-detect configuration hard lock */ +#define DCR_TDCSL (1 << 29) /* Tamper-detect configuration soft lock */ +#define DCR_KSSL (1 << 27) /* Key-select soft lock */ +#define DCR_MCHL (1 << 20) /* Monotonic-counter hard lock */ +#define DCR_MCSL (1 << 19) /* Monotonic-counter soft lock */ +#define DCR_TCHL (1 << 18) /* Timer-counter hard lock */ +#define DCR_TCSL (1 << 17) /* Timer-counter soft lock */ +#define DCR_FSHL (1 << 16) /* Failure state hard lock */ +#define DCR_TCE (1 << 3) /* Time Counter Enable */ +#define DCR_MCE (1 << 2) /* Monotonic Counter Enable */ + +#define DSR 0x14 /* Status Reg */ +#define DSR_WTD (1 << 23) /* Wire-mesh tamper detected */ +#define DSR_ETBD (1 << 22) /* External tamper B detected */ +#define DSR_ETAD (1 << 21) /* External tamper A detected */ +#define DSR_EBD (1 << 20) /* External boot detected */ +#define DSR_SAD (1 << 19) /* SCC alarm detected */ +#define DSR_TTD (1 << 18) /* Temperature tamper detected */ +#define DSR_CTD (1 << 17) /* Clock tamper detected */ +#define DSR_VTD (1 << 16) /* Voltage tamper detected */ +#define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */ +#define DSR_WNF (1 << 9) /* Write Next Flag (synchronous) */ +#define DSR_WCF (1 << 8) /* Write Complete Flag (synchronous)*/ +#define DSR_WEF (1 << 7) /* Write Error Flag */ +#define DSR_CAF (1 << 4) /* Clock Alarm Flag */ +#define DSR_MCO (1 << 3) /* monotonic counter overflow */ +#define DSR_TCO (1 << 2) /* time counter overflow */ +#define DSR_NVF (1 << 1) /* Non-Valid Flag */ +#define DSR_SVF (1 << 0) /* Security Violation Flag */ + +#define DIER 0x18 /* Interrupt Enable Reg (synchronous) */ +#define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */ +#define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */ +#define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */ +#define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */ +#define DIER_SVIE (1 << 0) /* Security-violation Interrupt Enable */ + +#define DMCR 0x1c /* DryIce Monotonic Counter Reg */ + +#define DTCR 0x28 /* DryIce Tamper Configuration Reg */ +#define DTCR_MOE (1 << 9) /* monotonic overflow enabled */ +#define DTCR_TOE (1 << 8) /* time overflow enabled */ +#define DTCR_WTE (1 << 7) /* wire-mesh tamper enabled */ +#define DTCR_ETBE (1 << 6) /* external B tamper enabled */ +#define DTCR_ETAE (1 << 5) /* external A tamper enabled */ +#define DTCR_EBE (1 << 4) /* external boot tamper enabled */ +#define DTCR_SAIE (1 << 3) /* SCC enabled */ +#define DTCR_TTE (1 << 2) /* temperature tamper enabled */ +#define DTCR_CTE (1 << 1) /* clock tamper enabled */ +#define DTCR_VTE (1 << 0) /* voltage tamper enabled */ + +#define DGPR 0x3c /* DryIce General Purpose Reg */ + +/** + * struct imxdi_dev - private imxdi rtc data + * @dev: pionter to dev + * @rtc: pointer to rtc struct + * @ioaddr: IO registers pointer + * @clk: input reference clock + * @dsr: copy of the DSR register + */ +struct imxdi_dev { + struct device_d *dev; + struct rtc_device rtc; + void __iomem *ioaddr; + struct clk *clk; + u32 dsr; + struct nvmem_device *nvmem; +}; + +/* Some background: + * + * The DryIce unit is a complex security/tamper monitor device. To be able do + * its job in a useful manner it runs a bigger statemachine to bring it into + * security/tamper failure state and once again to bring it out of this state. + * + * This unit can be in one of three states: + * + * - "NON-VALID STATE" + * always after the battery power was removed + * - "FAILURE STATE" + * if one of the enabled security events has happened + * - "VALID STATE" + * if the unit works as expected + * + * Everything stops when the unit enters the failure state including the RTC + * counter (to be able to detect the time the security event happened). + * + * The following events (when enabled) let the DryIce unit enter the failure + * state: + * + * - wire-mesh-tamper detect + * - external tamper B detect + * - external tamper A detect + * - temperature tamper detect + * - clock tamper detect + * - voltage tamper detect + * - RTC counter overflow + * - monotonic counter overflow + * - external boot + * + * If we find the DryIce unit in "FAILURE STATE" and the TDCHL cleared, we + * can only detect this state. In this case the unit is completely locked and + * must force a second "SYSTEM POR" to bring the DryIce into the + * "NON-VALID STATE" + "FAILURE STATE" where a recovery is possible. + * If the TDCHL is set in the "FAILURE STATE" we are out of luck. In this case + * a battery power cycle is required. + * + * In the "NON-VALID STATE" + "FAILURE STATE" we can clear the "FAILURE STATE" + * and recover the DryIce unit. By clearing the "NON-VALID STATE" as the last + * task, we bring back this unit into life. + */ + +/* + * Do a write into the unit without interrupt support. + * We do not need to check the WEF here, because the only reason this kind of + * write error can happen is if we write to the unit twice within the 122 us + * interval. This cannot happen, since we are using this function only while + * setting up the unit. + */ +static void di_write_busy_wait(const struct imxdi_dev *imxdi, u32 val, + unsigned reg) +{ + /* do the register write */ + writel(val, imxdi->ioaddr + reg); + + /* + * now it takes four 32,768 kHz clock cycles to take + * the change into effect = 122 us + */ + udelay(130); +} + +static void di_what_is_to_be_done(struct imxdi_dev *imxdi, + const char *power_supply) +{ + dev_emerg(imxdi->dev, "Please cycle the %s power supply in order to get the DryIce/RTC unit working again\n", + power_supply); +} + +static int di_handle_failure_state(struct imxdi_dev *imxdi, u32 dsr) +{ + u32 dcr; + + dev_dbg(imxdi->dev, "DSR register reports: %08X\n", dsr); + + dcr = readl(imxdi->ioaddr + DCR); + + if (dcr & DCR_FSHL) { + /* we are out of luck */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + /* + * with the next SYSTEM POR we will transit from the "FAILURE STATE" + * into the "NON-VALID STATE" + "FAILURE STATE" + */ + di_what_is_to_be_done(imxdi, "main"); + + return -ENODEV; +} + +static int di_handle_valid_state(struct imxdi_dev *imxdi, u32 dsr) +{ + /* initialize alarm */ + di_write_busy_wait(imxdi, DCAMR_UNSET, DCAMR); + di_write_busy_wait(imxdi, 0, DCALR); + + /* clear alarm flag */ + if (dsr & DSR_CAF) + di_write_busy_wait(imxdi, DSR_CAF, DSR); + + return 0; +} + +static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr) +{ + u32 dcr, sec; + + /* + * lets disable all sources which can force the DryIce unit into + * the "FAILURE STATE" for now + */ + di_write_busy_wait(imxdi, 0x00000000, DTCR); + /* and lets protect them at runtime from any change */ + di_write_busy_wait(imxdi, DCR_TDCSL, DCR); + + sec = readl(imxdi->ioaddr + DTCMR); + if (sec != 0) + dev_warn(imxdi->dev, + "The security violation has happened at %u seconds\n", + sec); + /* + * the timer cannot be set/modified if + * - the TCHL or TCSL bit is set in DCR + */ + dcr = readl(imxdi->ioaddr + DCR); + if (!(dcr & DCR_TCE)) { + if (dcr & DCR_TCHL) { + /* we are out of luck */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + if (dcr & DCR_TCSL) { + di_what_is_to_be_done(imxdi, "main"); + return -ENODEV; + } + } + /* + * - the timer counter stops/is stopped if + * - its overflow flag is set (TCO in DSR) + * -> clear overflow bit to make it count again + * - NVF is set in DSR + * -> clear non-valid bit to make it count again + * - its TCE (DCR) is cleared + * -> set TCE to make it count + * - it was never set before + * -> write a time into it (required again if the NVF was set) + */ + /* state handled */ + di_write_busy_wait(imxdi, DSR_NVF, DSR); + /* clear overflow flag */ + di_write_busy_wait(imxdi, DSR_TCO, DSR); + /* enable the counter */ + di_write_busy_wait(imxdi, dcr | DCR_TCE, DCR); + /* set and trigger it to make it count */ + di_write_busy_wait(imxdi, sec, DTCMR); + + /* now prepare for the valid state */ + return di_handle_valid_state(imxdi, __raw_readl(imxdi->ioaddr + DSR)); +} + +static int di_handle_invalid_and_failure_state(struct imxdi_dev *imxdi, u32 dsr) +{ + u32 dcr; + + /* + * now we must first remove the tamper sources in order to get the + * device out of the "FAILURE STATE" + * To disable any of the following sources we need to modify the DTCR + */ + if (dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD | DSR_EBD | DSR_SAD | + DSR_TTD | DSR_CTD | DSR_VTD | DSR_MCO | DSR_TCO)) { + dcr = __raw_readl(imxdi->ioaddr + DCR); + if (dcr & DCR_TDCHL) { + /* + * the tamper register is locked. We cannot disable the + * tamper detection. The TDCHL can only be reset by a + * DRYICE POR, but we cannot force a DRYICE POR in + * softwere because we are still in "FAILURE STATE". + * We need a DRYICE POR via battery power cycling.... + */ + /* + * out of luck! + * we cannot disable them without a DRYICE POR + */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + if (dcr & DCR_TDCSL) { + /* a soft lock can be removed by a SYSTEM POR */ + di_what_is_to_be_done(imxdi, "main"); + return -ENODEV; + } + } + + /* disable all sources */ + di_write_busy_wait(imxdi, 0x00000000, DTCR); + + /* clear the status bits now */ + di_write_busy_wait(imxdi, dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD | + DSR_EBD | DSR_SAD | DSR_TTD | DSR_CTD | DSR_VTD | + DSR_MCO | DSR_TCO), DSR); + + dsr = readl(imxdi->ioaddr + DSR); + if ((dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF | + DSR_WCF | DSR_WEF)) != 0) + dev_warn(imxdi->dev, + "There are still some sources of pain in DSR: %08x!\n", + dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF | + DSR_WCF | DSR_WEF)); + + /* + * now we are trying to clear the "Security-violation flag" to + * get the DryIce out of this state + */ + di_write_busy_wait(imxdi, DSR_SVF, DSR); + + /* success? */ + dsr = readl(imxdi->ioaddr + DSR); + if (dsr & DSR_SVF) { + dev_crit(imxdi->dev, + "Cannot clear the security violation flag. We are ending up in an endless loop!\n"); + /* last resort */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + + /* + * now we have left the "FAILURE STATE" and ending up in the + * "NON-VALID STATE" time to recover everything + */ + return di_handle_invalid_state(imxdi, dsr); +} + +static int di_handle_state(struct imxdi_dev *imxdi) +{ + int rc; + u32 dsr; + + dsr = readl(imxdi->ioaddr + DSR); + + switch (dsr & (DSR_NVF | DSR_SVF)) { + case DSR_NVF: + dev_warn(imxdi->dev, "Invalid stated unit detected\n"); + rc = di_handle_invalid_state(imxdi, dsr); + break; + case DSR_SVF: + dev_warn(imxdi->dev, "Failure stated unit detected\n"); + rc = di_handle_failure_state(imxdi, dsr); + break; + case DSR_NVF | DSR_SVF: + dev_warn(imxdi->dev, + "Failure+Invalid stated unit detected\n"); + rc = di_handle_invalid_and_failure_state(imxdi, dsr); + break; + default: + dev_notice(imxdi->dev, "Unlocked unit detected\n"); + rc = di_handle_valid_state(imxdi, dsr); + } + + return rc; +} + +/* + * This function attempts to clear the dryice write-error flag. + * + * A dryice write error is similar to a bus fault and should not occur in + * normal operation. Clearing the flag requires another write, so the root + * cause of the problem may need to be fixed before the flag can be cleared. + */ +static void clear_write_error(struct imxdi_dev *imxdi) +{ + int cnt; + + dev_warn(imxdi->dev, "WARNING: Register write error!\n"); + + /* clear the write error flag */ + writel(DSR_WEF, imxdi->ioaddr + DSR); + + /* wait for it to take effect */ + for (cnt = 0; cnt < 1000; cnt++) { + if ((readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0) + return; + udelay(10); + } + dev_err(imxdi->dev, + "ERROR: Cannot clear write-error flag!\n"); +} + +/* + * Write a dryice register and wait until it completes. + * + * This function uses interrupts to determine when the + * write has completed. + */ +static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg) +{ + int rc = 0; + uint32_t dsr; + uint64_t start; + + /* do the register write */ + writel(val, imxdi->ioaddr + reg); + + start = get_time_ns(); + + /* wait for the write to finish */ + while (1) { + dsr = readl(imxdi->ioaddr + DSR); + + if (dsr & (DSR_WCF | DSR_WEF)) + break; + if (is_timeout(start, MSECOND)) + return -EIO; + } + + /* check for write error */ + if (dsr & DSR_WEF) { + clear_write_error(imxdi); + rc = -EIO; + } + + return rc; +} + +static struct imxdi_dev *to_imxdi_dev(struct rtc_device *rtc) +{ + return container_of(rtc, struct imxdi_dev, rtc); +} + +/* + * read the seconds portion of the current time from the dryice time counter + */ +static int dryice_rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + struct imxdi_dev *imxdi = to_imxdi_dev(rtc); + unsigned long now; + + now = readl(imxdi->ioaddr + DTCMR); + rtc_time_to_tm(now, tm); + + return 0; +} + +/* + * set the seconds portion of dryice time counter and clear the + * fractional part. + */ +static int dryice_rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + struct imxdi_dev *imxdi = to_imxdi_dev(rtc); + u32 dcr, dsr; + int ret; + unsigned long secs; + + ret = rtc_tm_to_time(tm, &secs); + if (ret) + return ret; + + dcr = readl(imxdi->ioaddr + DCR); + dsr = readl(imxdi->ioaddr + DSR); + + if (!(dcr & DCR_TCE) || (dsr & DSR_SVF)) { + if (dcr & DCR_TCHL) { + /* we are even more out of luck */ + di_what_is_to_be_done(imxdi, "battery"); + return -EPERM; + } + if ((dcr & DCR_TCSL) || (dsr & DSR_SVF)) { + /* we are out of luck for now */ + di_what_is_to_be_done(imxdi, "main"); + return -EPERM; + } + } + + /* zero the fractional part first */ + ret = di_write_wait(imxdi, 0, DTCLR); + if (ret) + return ret; + + ret = di_write_wait(imxdi, secs, DTCMR); + if (ret) + return ret; + + return di_write_wait(imxdi, readl(imxdi->ioaddr + DCR) | DCR_TCE, DCR); +} + +static const struct rtc_class_ops dryice_rtc_ops = { + .read_time = dryice_rtc_read_time, + .set_time = dryice_rtc_set_time, +}; + +static int nvstore_write(struct device_d *dev, const int reg, const void *val, + int bytes) +{ + struct imxdi_dev *imxdi = dev->parent->priv; + const u32 *val32 = val; + + if (bytes != 4) + return 0; + + writel(*val32, imxdi->ioaddr + DGPR); + + return 0; +} + +static int nvstore_read(struct device_d *dev, const int reg, void *val, + int bytes) +{ + struct imxdi_dev *imxdi = dev->parent->priv; + u32 *val32 = val; + + if (bytes != 4) + return 0; + + *val32 = readl(imxdi->ioaddr + DGPR); + + return 0; +} + +static struct nvmem_bus nvstore_nvmem_bus = { + .write = nvstore_write, + .read = nvstore_read, +}; + +static struct nvmem_config nvstore_nvmem_config = { + .name = "nvstore", + .stride = 4, + .word_size = 4, + .size = 4, + .bus = &nvstore_nvmem_bus, +}; + +static int __init dryice_rtc_probe(struct device_d *dev) +{ + struct resource *res; + struct imxdi_dev *imxdi; + int ret; + + imxdi = xzalloc(sizeof(*imxdi)); + + imxdi->dev = dev; + imxdi->rtc.ops = &dryice_rtc_ops; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + imxdi->ioaddr = IOMEM(res->start); + + imxdi->clk = clk_get(dev, NULL); + if (IS_ERR(imxdi->clk)) + return PTR_ERR(imxdi->clk); + + ret = clk_enable(imxdi->clk); + if (ret) + return ret; + + /* + * Initialize dryice hardware + */ + + /* mask all interrupts */ + writel(0, imxdi->ioaddr + DIER); + + ret = di_handle_state(imxdi); + if (ret) + goto err; + + dev->priv = imxdi; + + nvstore_nvmem_config.dev = dev; + + imxdi->nvmem = nvmem_register(&nvstore_nvmem_config); + if (IS_ENABLED(CONFIG_NVMEM) && IS_ERR(imxdi->nvmem)) { + ret = PTR_ERR(imxdi->nvmem); + goto err; + } + + ret = rtc_register(&imxdi->rtc); + if (ret) + goto err; + + return 0; + +err: + clk_disable(imxdi->clk); + + return ret; +} + +static __maybe_unused const struct of_device_id dryice_dt_ids[] = { + { .compatible = "fsl,imx25-rtc" }, + { /* sentinel */ } +}; + +static struct driver_d dryice_rtc_driver = { + .name = "imx-di-rtc", + .probe = dryice_rtc_probe, + .of_compatible = DRV_OF_COMPAT(dryice_dt_ids), +}; +device_platform_driver(dryice_rtc_driver); diff --git a/dts/Bindings/arm/cpus.yaml b/dts/Bindings/arm/cpus.yaml index 365dcf384d..82dd7582e9 100644 --- a/dts/Bindings/arm/cpus.yaml +++ b/dts/Bindings/arm/cpus.yaml @@ -228,7 +228,7 @@ patternProperties: - renesas,r9a06g032-smp - rockchip,rk3036-smp - rockchip,rk3066-smp - - socionext,milbeaut-m10v-smp + - socionext,milbeaut-m10v-smp - ste,dbx500-smp cpu-release-addr: diff --git a/dts/Bindings/hwmon/adc128d818.txt b/dts/Bindings/hwmon/adc128d818.txt index 08bab0e94d..d0ae46d7ba 100644 --- a/dts/Bindings/hwmon/adc128d818.txt +++ b/dts/Bindings/hwmon/adc128d818.txt @@ -26,7 +26,7 @@ Required node properties: Optional node properties: - - ti,mode: Operation mode (see above). + - ti,mode: Operation mode (u8) (see above). Example (operation mode 2): @@ -34,5 +34,5 @@ Example (operation mode 2): adc128d818@1d { compatible = "ti,adc128d818"; reg = <0x1d>; - ti,mode = <2>; + ti,mode = /bits/ 8 <2>; }; diff --git a/dts/Bindings/net/davinci_emac.txt b/dts/Bindings/net/davinci_emac.txt index 24c5cdaba8..ca83dcc84f 100644 --- a/dts/Bindings/net/davinci_emac.txt +++ b/dts/Bindings/net/davinci_emac.txt @@ -20,6 +20,8 @@ Required properties: Optional properties: - phy-handle: See ethernet.txt file in the same directory. If absent, davinci_emac driver defaults to 100/FULL. +- nvmem-cells: phandle, reference to an nvmem node for the MAC address +- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used - ti,davinci-rmii-en: 1 byte, 1 means use RMII - ti,davinci-no-bd-ram: boolean, does EMAC have BD RAM? diff --git a/dts/Bindings/net/ethernet.txt b/dts/Bindings/net/ethernet.txt index cfc376bc97..a686215805 100644 --- a/dts/Bindings/net/ethernet.txt +++ b/dts/Bindings/net/ethernet.txt @@ -10,15 +10,14 @@ Documentation/devicetree/bindings/phy/phy-bindings.txt. the boot program; should be used in cases where the MAC address assigned to the device by the boot program is different from the "local-mac-address" property; -- nvmem-cells: phandle, reference to an nvmem node for the MAC address; -- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used; - max-speed: number, specifies maximum speed in Mbit/s supported by the device; - max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than the maximum frame size (there's contradiction in the Devicetree Specification). - phy-mode: string, operation mode of the PHY interface. This is now a de-facto standard property; supported values are: - * "internal" + * "internal" (Internal means there is not a standard bus between the MAC and + the PHY, something proprietary is being used to embed the PHY in the MAC.) * "mii" * "gmii" * "sgmii" diff --git a/dts/Bindings/net/macb.txt b/dts/Bindings/net/macb.txt index 174f292d8a..8b80515729 100644 --- a/dts/Bindings/net/macb.txt +++ b/dts/Bindings/net/macb.txt @@ -26,6 +26,10 @@ Required properties: Optional elements: 'tsu_clk' - clocks: Phandles to input clocks. +Optional properties: +- nvmem-cells: phandle, reference to an nvmem node for the MAC address +- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used + Optional properties for PHY child node: - reset-gpios : Should specify the gpio for phy reset - magic-packet : If present, indicates that the hardware supports waking diff --git a/dts/include/dt-bindings/clock/sifive-fu540-prci.h b/dts/include/dt-bindings/clock/sifive-fu540-prci.h new file mode 100644 index 0000000000..6a0b70a37d --- /dev/null +++ b/dts/include/dt-bindings/clock/sifive-fu540-prci.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018-2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + */ + +#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H +#define __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H + +/* Clock indexes for use by Device Tree data and the PRCI driver */ + +#define PRCI_CLK_COREPLL 0 +#define PRCI_CLK_DDRPLL 1 +#define PRCI_CLK_GEMGXLPLL 2 +#define PRCI_CLK_TLCLK 3 + +#endif diff --git a/dts/include/dt-bindings/input/linux-event-codes.h b/dts/include/dt-bindings/input/linux-event-codes.h index 7f14d4a66c..64cee11692 100644 --- a/dts/include/dt-bindings/input/linux-event-codes.h +++ b/dts/include/dt-bindings/input/linux-event-codes.h @@ -439,10 +439,12 @@ #define KEY_TITLE 0x171 #define KEY_SUBTITLE 0x172 #define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 +#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */ +#define KEY_ZOOM KEY_FULL_SCREEN #define KEY_MODE 0x175 #define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 +#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */ +#define KEY_SCREEN KEY_ASPECT_RATIO #define KEY_PC 0x178 /* Media Select Computer */ #define KEY_TV 0x179 /* Media Select TV */ #define KEY_TV2 0x17a /* Media Select Cable */ diff --git a/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h b/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h index 8063e8314e..6d487c5eba 100644 --- a/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h +++ b/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h @@ -51,7 +51,10 @@ #define RESET_SD_EMMC_A 44 #define RESET_SD_EMMC_B 45 #define RESET_SD_EMMC_C 46 -/* 47-60 */ +/* 47 */ +#define RESET_USB_PHY20 48 +#define RESET_USB_PHY21 49 +/* 50-60 */ #define RESET_AUDIO_CODEC 61 /* 62-63 */ /* RESET2 */ diff --git a/dts/src/arc/hsdk.dts b/dts/src/arc/hsdk.dts index 69bc1c9e8e..7425bb0f2d 100644 --- a/dts/src/arc/hsdk.dts +++ b/dts/src/arc/hsdk.dts @@ -18,8 +18,8 @@ model = "snps,hsdk"; compatible = "snps,hsdk"; - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; chosen { bootargs = "earlycon=uart8250,mmio32,0xf0005000,115200n8 console=ttyS0,115200n8 debug print-fatal-signals=1"; @@ -105,7 +105,7 @@ #size-cells = <1>; interrupt-parent = <&idu_intc>; - ranges = <0x00000000 0xf0000000 0x10000000>; + ranges = <0x00000000 0x0 0xf0000000 0x10000000>; cgu_rst: reset-controller@8a0 { compatible = "snps,hsdk-reset"; @@ -269,9 +269,10 @@ }; memory@80000000 { - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; device_type = "memory"; - reg = <0x80000000 0x40000000>; /* 1 GiB */ + reg = <0x0 0x80000000 0x0 0x40000000>; /* 1 GB lowmem */ + /* 0x1 0x00000000 0x0 0x40000000>; 1 GB highmem */ }; }; diff --git a/dts/src/arm/am335x-evm.dts b/dts/src/arm/am335x-evm.dts index dce5be5df9..edcff79879 100644 --- a/dts/src/arm/am335x-evm.dts +++ b/dts/src/arm/am335x-evm.dts @@ -57,6 +57,24 @@ enable-active-high; }; + /* TPS79501 */ + v1_8d_reg: fixedregulator-v1_8d { + compatible = "regulator-fixed"; + regulator-name = "v1_8d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* TPS79501 */ + v3_3d_reg: fixedregulator-v3_3d { + compatible = "regulator-fixed"; + regulator-name = "v3_3d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + matrix_keypad: matrix_keypad0 { compatible = "gpio-matrix-keypad"; debounce-delay-ms = <5>; @@ -499,10 +517,10 @@ status = "okay"; /* Regulators */ - AVDD-supply = <&vaux2_reg>; - IOVDD-supply = <&vaux2_reg>; - DRVDD-supply = <&vaux2_reg>; - DVDD-supply = <&vbat>; + AVDD-supply = <&v3_3d_reg>; + IOVDD-supply = <&v3_3d_reg>; + DRVDD-supply = <&v3_3d_reg>; + DVDD-supply = <&v1_8d_reg>; }; }; diff --git a/dts/src/arm/am335x-evmsk.dts b/dts/src/arm/am335x-evmsk.dts index b128998097..2c2d8b5b8c 100644 --- a/dts/src/arm/am335x-evmsk.dts +++ b/dts/src/arm/am335x-evmsk.dts @@ -73,6 +73,24 @@ enable-active-high; }; + /* TPS79518 */ + v1_8d_reg: fixedregulator-v1_8d { + compatible = "regulator-fixed"; + regulator-name = "v1_8d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* TPS78633 */ + v3_3d_reg: fixedregulator-v3_3d { + compatible = "regulator-fixed"; + regulator-name = "v3_3d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + leds { pinctrl-names = "default"; pinctrl-0 = <&user_leds_s0>; @@ -501,10 +519,10 @@ status = "okay"; /* Regulators */ - AVDD-supply = <&vaux2_reg>; - IOVDD-supply = <&vaux2_reg>; - DRVDD-supply = <&vaux2_reg>; - DVDD-supply = <&vbat>; + AVDD-supply = <&v3_3d_reg>; + IOVDD-supply = <&v3_3d_reg>; + DRVDD-supply = <&v3_3d_reg>; + DVDD-supply = <&v1_8d_reg>; }; }; diff --git a/dts/src/arm/am33xx-l4.dtsi b/dts/src/arm/am33xx-l4.dtsi index f459ec316a..ca6d9f02a8 100644 --- a/dts/src/arm/am33xx-l4.dtsi +++ b/dts/src/arm/am33xx-l4.dtsi @@ -1762,7 +1762,7 @@ reg = <0xcc000 0x4>; reg-names = "rev"; /* Domains (P, C): per_pwrdm, l4ls_clkdm */ - clocks = <&l4ls_clkctrl AM3_D_CAN0_CLKCTRL 0>; + clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN0_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; @@ -1785,7 +1785,7 @@ reg = <0xd0000 0x4>; reg-names = "rev"; /* Domains (P, C): per_pwrdm, l4ls_clkdm */ - clocks = <&l4ls_clkctrl AM3_D_CAN1_CLKCTRL 0>; + clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN1_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; diff --git a/dts/src/arm/rk3288-tinker.dtsi b/dts/src/arm/rk3288-tinker.dtsi index aa107ee41b..ef653c3209 100644 --- a/dts/src/arm/rk3288-tinker.dtsi +++ b/dts/src/arm/rk3288-tinker.dtsi @@ -254,6 +254,7 @@ }; vccio_sd: LDO_REG5 { + regulator-boot-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; regulator-name = "vccio_sd"; @@ -430,7 +431,7 @@ bus-width = <4>; cap-mmc-highspeed; cap-sd-highspeed; - card-detect-delay = <200>; + broken-cd; disable-wp; /* wp not hooked up */ pinctrl-names = "default"; pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; diff --git a/dts/src/arm/rk3288-veyron.dtsi b/dts/src/arm/rk3288-veyron.dtsi index 0bc2409f69..192dbc089a 100644 --- a/dts/src/arm/rk3288-veyron.dtsi +++ b/dts/src/arm/rk3288-veyron.dtsi @@ -25,8 +25,6 @@ gpio_keys: gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&pwr_key_l>; diff --git a/dts/src/arm/rk3288.dtsi b/dts/src/arm/rk3288.dtsi index ca7d52daa8..a024d1e7e7 100644 --- a/dts/src/arm/rk3288.dtsi +++ b/dts/src/arm/rk3288.dtsi @@ -70,7 +70,7 @@ compatible = "arm,cortex-a12"; reg = <0x501>; resets = <&cru SRST_CORE1>; - operating-points = <&cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; /* min followed by max */ clock-latency = <40000>; clocks = <&cru ARMCLK>; @@ -80,7 +80,7 @@ compatible = "arm,cortex-a12"; reg = <0x502>; resets = <&cru SRST_CORE2>; - operating-points = <&cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; /* min followed by max */ clock-latency = <40000>; clocks = <&cru ARMCLK>; @@ -90,7 +90,7 @@ compatible = "arm,cortex-a12"; reg = <0x503>; resets = <&cru SRST_CORE3>; - operating-points = <&cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; /* min followed by max */ clock-latency = <40000>; clocks = <&cru ARMCLK>; @@ -1119,8 +1119,6 @@ clock-names = "ref", "pclk"; power-domains = <&power RK3288_PD_VIO>; rockchip,grf = <&grf>; - #address-cells = <1>; - #size-cells = <0>; status = "disabled"; ports { @@ -1282,27 +1280,27 @@ gpu_opp_table: gpu-opp-table { compatible = "operating-points-v2"; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <950000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <950000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <1000000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1100000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <1200000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <1250000>; }; diff --git a/dts/src/arm/sama5d2-pinfunc.h b/dts/src/arm/sama5d2-pinfunc.h index 1c01a6f843..28a2e45752 100644 --- a/dts/src/arm/sama5d2-pinfunc.h +++ b/dts/src/arm/sama5d2-pinfunc.h @@ -518,7 +518,7 @@ #define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0) #define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 1, 3) #define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 2, 1) -#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 2, 1) +#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 3, 1) #define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 4, 2) #define PIN_PC10 74 #define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0) diff --git a/dts/src/arm/ste-nomadik-nhk15.dts b/dts/src/arm/ste-nomadik-nhk15.dts index f2f6558a00..04066f9cb8 100644 --- a/dts/src/arm/ste-nomadik-nhk15.dts +++ b/dts/src/arm/ste-nomadik-nhk15.dts @@ -213,13 +213,12 @@ gpio-sck = <&gpio0 5 GPIO_ACTIVE_HIGH>; gpio-mosi = <&gpio0 4 GPIO_ACTIVE_HIGH>; /* - * This chipselect is active high. Just setting the flags - * to GPIO_ACTIVE_HIGH is not enough for the SPI DT bindings, - * it will be ignored, only the special "spi-cs-high" flag - * really counts. + * It's not actually active high, but the frameworks assume + * the polarity of the passed-in GPIO is "normal" (active + * high) then actively drives the line low to select the + * chip. */ cs-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; - spi-cs-high; num-chipselects = <1>; /* diff --git a/dts/src/arm64/altera/socfpga_stratix10.dtsi b/dts/src/arm64/altera/socfpga_stratix10.dtsi index 7c649f6b14..cd7c76e58b 100644 --- a/dts/src/arm64/altera/socfpga_stratix10.dtsi +++ b/dts/src/arm64/altera/socfpga_stratix10.dtsi @@ -162,6 +162,7 @@ rx-fifo-depth = <16384>; snps,multicast-filter-bins = <256>; iommus = <&smmu 1>; + altr,sysmgr-syscon = <&sysmgr 0x44 0>; status = "disabled"; }; @@ -179,6 +180,7 @@ rx-fifo-depth = <16384>; snps,multicast-filter-bins = <256>; iommus = <&smmu 2>; + altr,sysmgr-syscon = <&sysmgr 0x48 0>; status = "disabled"; }; @@ -196,6 +198,7 @@ rx-fifo-depth = <16384>; snps,multicast-filter-bins = <256>; iommus = <&smmu 3>; + altr,sysmgr-syscon = <&sysmgr 0x4c 0>; status = "disabled"; }; diff --git a/dts/src/arm64/rockchip/rk3328-roc-cc.dts b/dts/src/arm64/rockchip/rk3328-roc-cc.dts index 33c44e8572..0e34354b20 100644 --- a/dts/src/arm64/rockchip/rk3328-roc-cc.dts +++ b/dts/src/arm64/rockchip/rk3328-roc-cc.dts @@ -108,8 +108,8 @@ snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 50000>; - tx_delay = <0x25>; - rx_delay = <0x11>; + tx_delay = <0x24>; + rx_delay = <0x18>; status = "okay"; }; diff --git a/dts/src/arm64/rockchip/rk3328-rock64.dts b/dts/src/arm64/rockchip/rk3328-rock64.dts index 2157a52827..79b4d1d4b5 100644 --- a/dts/src/arm64/rockchip/rk3328-rock64.dts +++ b/dts/src/arm64/rockchip/rk3328-rock64.dts @@ -46,8 +46,7 @@ vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; + gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&usb20_host_drv>; regulator-name = "vcc_host1_5v"; diff --git a/dts/src/arm64/rockchip/rk3328.dtsi b/dts/src/arm64/rockchip/rk3328.dtsi index 84f14b132e..dabef1a216 100644 --- a/dts/src/arm64/rockchip/rk3328.dtsi +++ b/dts/src/arm64/rockchip/rk3328.dtsi @@ -1445,11 +1445,11 @@ sdmmc0 { sdmmc0_clk: sdmmc0-clk { - rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_4ma>; + rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_8ma>; }; sdmmc0_cmd: sdmmc0-cmd { - rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_8ma>; }; sdmmc0_dectn: sdmmc0-dectn { @@ -1461,14 +1461,14 @@ }; sdmmc0_bus1: sdmmc0-bus1 { - rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_8ma>; }; sdmmc0_bus4: sdmmc0-bus4 { - rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>, - <1 RK_PA1 1 &pcfg_pull_up_4ma>, - <1 RK_PA2 1 &pcfg_pull_up_4ma>, - <1 RK_PA3 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_8ma>, + <1 RK_PA1 1 &pcfg_pull_up_8ma>, + <1 RK_PA2 1 &pcfg_pull_up_8ma>, + <1 RK_PA3 1 &pcfg_pull_up_8ma>; }; sdmmc0_gpio: sdmmc0-gpio { @@ -1642,50 +1642,50 @@ rgmiim1_pins: rgmiim1-pins { rockchip,pins = /* mac_txclk */ - <1 RK_PB4 2 &pcfg_pull_none_12ma>, + <1 RK_PB4 2 &pcfg_pull_none_8ma>, /* mac_rxclk */ - <1 RK_PB5 2 &pcfg_pull_none_2ma>, + <1 RK_PB5 2 &pcfg_pull_none_4ma>, /* mac_mdio */ - <1 RK_PC3 2 &pcfg_pull_none_2ma>, + <1 RK_PC3 2 &pcfg_pull_none_4ma>, /* mac_txen */ - <1 RK_PD1 2 &pcfg_pull_none_12ma>, + <1 RK_PD1 2 &pcfg_pull_none_8ma>, /* mac_clk */ - <1 RK_PC5 2 &pcfg_pull_none_2ma>, + <1 RK_PC5 2 &pcfg_pull_none_4ma>, /* mac_rxdv */ - <1 RK_PC6 2 &pcfg_pull_none_2ma>, + <1 RK_PC6 2 &pcfg_pull_none_4ma>, /* mac_mdc */ - <1 RK_PC7 2 &pcfg_pull_none_2ma>, + <1 RK_PC7 2 &pcfg_pull_none_4ma>, /* mac_rxd1 */ - <1 RK_PB2 2 &pcfg_pull_none_2ma>, + <1 RK_PB2 2 &pcfg_pull_none_4ma>, /* mac_rxd0 */ - <1 RK_PB3 2 &pcfg_pull_none_2ma>, + <1 RK_PB3 2 &pcfg_pull_none_4ma>, /* mac_txd1 */ - <1 RK_PB0 2 &pcfg_pull_none_12ma>, + <1 RK_PB0 2 &pcfg_pull_none_8ma>, /* mac_txd0 */ - <1 RK_PB1 2 &pcfg_pull_none_12ma>, + <1 RK_PB1 2 &pcfg_pull_none_8ma>, /* mac_rxd3 */ - <1 RK_PB6 2 &pcfg_pull_none_2ma>, + <1 RK_PB6 2 &pcfg_pull_none_4ma>, /* mac_rxd2 */ - <1 RK_PB7 2 &pcfg_pull_none_2ma>, + <1 RK_PB7 2 &pcfg_pull_none_4ma>, /* mac_txd3 */ - <1 RK_PC0 2 &pcfg_pull_none_12ma>, + <1 RK_PC0 2 &pcfg_pull_none_8ma>, /* mac_txd2 */ - <1 RK_PC1 2 &pcfg_pull_none_12ma>, + <1 RK_PC1 2 &pcfg_pull_none_8ma>, /* mac_txclk */ - <0 RK_PB0 1 &pcfg_pull_none>, + <0 RK_PB0 1 &pcfg_pull_none_8ma>, /* mac_txen */ - <0 RK_PB4 1 &pcfg_pull_none>, + <0 RK_PB4 1 &pcfg_pull_none_8ma>, /* mac_clk */ - <0 RK_PD0 1 &pcfg_pull_none>, + <0 RK_PD0 1 &pcfg_pull_none_4ma>, /* mac_txd1 */ - <0 RK_PC0 1 &pcfg_pull_none>, + <0 RK_PC0 1 &pcfg_pull_none_8ma>, /* mac_txd0 */ - <0 RK_PC1 1 &pcfg_pull_none>, + <0 RK_PC1 1 &pcfg_pull_none_8ma>, /* mac_txd3 */ - <0 RK_PC7 1 &pcfg_pull_none>, + <0 RK_PC7 1 &pcfg_pull_none_8ma>, /* mac_txd2 */ - <0 RK_PC6 1 &pcfg_pull_none>; + <0 RK_PC6 1 &pcfg_pull_none_8ma>; }; rmiim1_pins: rmiim1-pins { diff --git a/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts b/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts index 4a543f2117..844eac939a 100644 --- a/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts +++ b/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts @@ -158,6 +158,7 @@ }; &hdmi { + ddc-i2c-bus = <&i2c3>; pinctrl-names = "default"; pinctrl-0 = <&hdmi_cec>; status = "okay"; diff --git a/images/Makefile.layerscape b/images/Makefile.layerscape index 47df3777f0..d20cc6a37e 100644 --- a/images/Makefile.layerscape +++ b/images/Makefile.layerscape @@ -14,6 +14,12 @@ quiet_cmd_lspbl_image = LSPBL-IMG $@ $(objtree)/scripts/pblimage -o $@ -r $(lspbl-rcw-tmp) \ -m $($(patsubst $(obj)/%.pblb,PBL_CODE_SIZE_%,$<)) -p $(lspbl-pbi-tmp) -i $< +quiet_cmd_lspbl_spi_image = LSPBL-SPI-IMG $@ + cmd_lspbl_spi_image = $(CPP) $(lspbl_cfg_cpp_flags) -o $(lspbl-rcw-tmp) $(word 2,$^) ; \ + $(CPP) $(lspbl_cfg_cpp_flags) -o $(lspbl-pbi-tmp) $(word 3,$^) ; \ + $(objtree)/scripts/pblimage -o $@ -r $(lspbl-rcw-tmp) -s \ + -m $($(patsubst $(obj)/%.pblb,PBL_CODE_SIZE_%,$<)) -p $(lspbl-pbi-tmp) -i $< + pbl-$(CONFIG_MACH_LS1046ARDB) += start_ls1046ardb.pbl $(obj)/barebox-ls1046ardb-2nd.image: $(obj)/start_ls1046ardb.pblb $(call if_changed,shipped) @@ -31,7 +37,7 @@ $(obj)/barebox-ls1046ardb-emmc.image: $(obj)/start_ls1046ardb.pblb \ $(obj)/barebox-ls1046ardb-qspi.image: $(obj)/start_ls1046ardb.pblb \ $(board)/ls1046ardb/ls1046ardb_rcw_qspi.cfg \ $(board)/ls1046ardb/ls1046ardb_pbi.cfg - $(call if_changed,lspbl_image) + $(call if_changed,lspbl_spi_image) image-$(CONFIG_MACH_LS1046ARDB) += barebox-ls1046ardb-sd.image barebox-ls1046ardb-qspi.image \ barebox-ls1046ardb-emmc.image barebox-ls1046ardb-2nd.image @@ -42,18 +48,13 @@ $(obj)/barebox-tqmls1046a-2nd.image: $(obj)/start_tqmls1046a.pblb $(obj)/barebox-tqmls1046a-sd.image: $(obj)/start_tqmls1046a.pblb \ $(board)/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg \ - $(board)/tqmls1046a/tqmls1046a_pbi_sd.cfg - $(call if_changed,lspbl_image) - -$(obj)/barebox-tqmls1046a-emmc.image: $(obj)/start_tqmls1046a.pblb \ - $(board)/tqmls1046a/tqmls1046a_rcw_emmc_3333_5559.cfg \ - $(board)/tqmls1046a/tqmls1046a_pbi_sd.cfg + $(board)/tqmls1046a/tqmls1046a_pbi.cfg $(call if_changed,lspbl_image) $(obj)/barebox-tqmls1046a-qspi.image: $(obj)/start_tqmls1046a.pblb \ $(board)/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg \ - $(board)/tqmls1046a/tqmls1046a_pbi_qspi.cfg - $(call if_changed,lspbl_image) + $(board)/tqmls1046a/tqmls1046a_pbi.cfg + $(call if_changed,lspbl_spi_image) -image-$(CONFIG_MACH_TQMLS1046A) += barebox-tqmls1046a-sd.image barebox-tqmls1046a-emmc.image \ +image-$(CONFIG_MACH_TQMLS1046A) += barebox-tqmls1046a-sd.image \ barebox-tqmls1046a-qspi.image barebox-tqmls1046a-2nd.image diff --git a/include/base64.h b/include/base64.h new file mode 100644 index 0000000000..0df510281d --- /dev/null +++ b/include/base64.h @@ -0,0 +1,9 @@ +#ifndef __BASE64_H +#define __BASE64_H + +void uuencode(char *p, const char *src, int length); +int decode_base64(char *dst, int dst_len, const char *src); + +#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3)) + +#endif /* __BASE64_H */ diff --git a/include/bbu.h b/include/bbu.h index 0ed355b539..9da6785d2e 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -54,7 +54,7 @@ int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *); int bbu_register_handler(struct bbu_handler *); int bbu_register_std_file_update(const char *name, unsigned long flags, - char *devicefile, enum filetype imagetype); + const char *devicefile, enum filetype imagetype); #else @@ -64,7 +64,7 @@ static inline int bbu_register_handler(struct bbu_handler *unused) } static inline int bbu_register_std_file_update(const char *name, unsigned long flags, - char *devicefile, enum filetype imagetype) + const char *devicefile, enum filetype imagetype) { return -ENOSYS; } diff --git a/include/blobgen.h b/include/blobgen.h new file mode 100644 index 0000000000..09a6637b77 --- /dev/null +++ b/include/blobgen.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * 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 __BLOBGEN_H__ +#define __BLOBGEN_H__ + +#include <common.h> + +enum access_rights { + KERNEL, + KERNEL_EVM, + USERSPACE, +}; + +#define KEYMOD_LENGTH 16 +#define MAX_BLOB_LEN 4096 +#define BLOCKSIZE_BYTES 8 + +struct blobgen { + struct device_d dev; + int (*encrypt)(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, void *blob, + int *blobsize); + int (*decrypt)(struct blobgen *bg, const char *modifier, + const void *blob, int blobsize, void **plain, + int *plainsize); + + enum access_rights access; + unsigned int max_payload_size; + + struct list_head list; +}; + +int blob_gen_register(struct device_d *dev, struct blobgen *bg); + +struct blobgen *blobgen_get(const char *name); + +int blob_encrypt(struct blobgen *blg, const char *modifier, const void *plain, + int plainsize, void **blob, int *blobsize); +int blob_encrypt_to_env(struct blobgen *blg, const char *modifier, + const void *plain, int plainsize, const char *varname); +int blob_decrypt(struct blobgen *bg, const char *modifier, const void *blob, + int blobsize, void **plain, int *plainsize); +int blob_decrypt_from_base64(struct blobgen *blg, const char *modifier, + const char *encrypted, void **plain, int *plainsize); + +#endif diff --git a/include/common.h b/include/common.h index 11d26cb3db..723b9c706c 100644 --- a/include/common.h +++ b/include/common.h @@ -68,7 +68,9 @@ int readline (const char *prompt, char *buf, int len); long get_ram_size (volatile long *, long); /* common/console.c */ -int ctrlc (void); +int ctrlc(void); +int arch_ctrlc(void); +void ctrlc_handled(void); #ifdef ARCH_HAS_STACK_DUMP void dump_stack(void); diff --git a/include/console.h b/include/console.h index 673921331d..4062e5abf6 100644 --- a/include/console.h +++ b/include/console.h @@ -207,4 +207,7 @@ static inline void pbl_set_putc(void (*putcf)(void *ctx, int c), void *ctx) {} bool console_allow_color(void); +void console_ctrlc_allow(void); +void console_ctrlc_forbid(void); + #endif diff --git a/include/console_countdown.h b/include/console_countdown.h index c6c2d5c00e..88cadf11ec 100644 --- a/include/console_countdown.h +++ b/include/console_countdown.h @@ -7,7 +7,7 @@ #define CONSOLE_COUNTDOWN_CTRLC (1 << 4) #define CONSOLE_COUNTDOWN_EXTERN (1 << 5) -int console_countdown(int timeout_s, unsigned flags, char *out_key); +int console_countdown(int timeout_s, unsigned flags, const char *keys, char *out_key); void console_countdown_abort(void); #endif /* __CONSOLE_COUNTDOWN_H */ diff --git a/include/crypto.h b/include/crypto.h new file mode 100644 index 0000000000..ac70111cab --- /dev/null +++ b/include/crypto.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * 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 __CRYPTO_H__ +#define __CRYPTO_H__ + +struct ablkcipher_request { + unsigned int nbytes; + + void __iomem *info; + + void __iomem *dst; + void __iomem *src; +}; + +#endif diff --git a/include/crypto/des.h b/include/crypto/des.h new file mode 100644 index 0000000000..58fdaaa99d --- /dev/null +++ b/include/crypto/des.h @@ -0,0 +1,16 @@ +/* + * DES & Triple DES EDE Cipher Algorithms. + */ + +#ifndef __CRYPTO_DES_H +#define __CRYPTO_DES_H + +#define DES_KEY_SIZE 8 +#define DES_EXPKEY_WORDS 32 +#define DES_BLOCK_SIZE 8 + +#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) +#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE + +#endif /* __CRYPTO_DES_H */ diff --git a/include/filetype.h b/include/filetype.h index 395053dd59..dcb331a6c9 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -45,6 +45,8 @@ enum filetype { filetype_elf, filetype_imx_image_v1, filetype_imx_image_v2, + filetype_layerscape_image, + filetype_layerscape_qspi_image, filetype_max, }; diff --git a/include/soc/fsl/fsl_ddr_sdram.h b/include/soc/fsl/fsl_ddr_sdram.h index 07d0af96fc..80508ef5d5 100644 --- a/include/soc/fsl/fsl_ddr_sdram.h +++ b/include/soc/fsl/fsl_ddr_sdram.h @@ -540,6 +540,7 @@ struct fsl_ddr_info { }; phys_size_t fsl_ddr_sdram(struct fsl_ddr_info *pinfo); +void fsl_ddr_set_memctl_regs(struct fsl_ddr_controller *c, int step); #ifdef CONFIG_SYS_FSL_DDR_LE #define ddr_in32(a) in_le32(a) diff --git a/lib/Kconfig b/lib/Kconfig index 27f62461f0..7cf6975bcc 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -57,6 +57,9 @@ config XZ_DEC_SPARC config REED_SOLOMON bool +config BASE64 + bool "include base64 encode/decode support" + config GENERIC_FIND_NEXT_BIT def_bool n @@ -155,4 +158,7 @@ config GENERIC_LIB_MULDI3 config NLS bool "Native language support" +config BLOBGEN + bool "include blob encode/decode support" + endmenu diff --git a/lib/Makefile b/lib/Makefile index 8dabf4ae77..161d3a756e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -18,6 +18,7 @@ obj-y += readkey.o obj-y += kfifo.o obj-y += libbb.o obj-y += libgen.o +obj-$(CONFIG_BLOBGEN) += blobgen.o obj-y += stringlist.o obj-y += cmdlinepart.o obj-y += recursive_action.o @@ -44,6 +45,7 @@ obj-$(CONFIG_LZ4_DECOMPRESS) += decompress_unlz4.o obj-$(CONFIG_PROCESS_ESCAPE_SEQUENCE) += process_escape_sequence.o obj-$(CONFIG_UNCOMPRESS) += uncompress.o obj-$(CONFIG_BCH) += bch.o +obj-$(CONFIG_BASE64) += base64.o obj-$(CONFIG_BITREV) += bitrev.o obj-$(CONFIG_QSORT) += qsort.o obj-$(CONFIG_LIBSCAN) += libscan.o diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 0000000000..ac165ab168 --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,154 @@ +/* + * Code based on busybox-1.23.2 + * + * Copyright 2003, Glenn McGrath + * Copyright 2006, Rob Landley <rob@landley.net> + * Copyright 2010, Denys Vlasenko + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include <common.h> +#include <base64.h> + +/* Conversion table. for base 64 */ +static const char uuenc_tbl_base64[65 + 1] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', + '=' /* termination character */, + '\0' /* needed for uudecode.c only */ +}; + +/* + * Encode bytes at S of length LENGTH to uuencode or base64 format and place it + * to STORE. STORE will be 0-terminated, and must point to a writable + * buffer of at least 1+BASE64_LENGTH(length) bytes. + * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3)) + */ +void uuencode(char *p, const char *src, int length) +{ + const unsigned char *s = src; + const char *tbl = uuenc_tbl_base64; + + /* Transform the 3x8 bits to 4x6 bits */ + while (length > 0) { + unsigned s1, s2; + + /* Are s[1], s[2] valid or should be assumed 0? */ + s1 = s2 = 0; + length -= 3; /* can be >=0, -1, -2 */ + if (length >= -1) { + s1 = s[1]; + if (length >= 0) + s2 = s[2]; + } + *p++ = tbl[s[0] >> 2]; + *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)]; + *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)]; + *p++ = tbl[s2 & 0x3f]; + s += 3; + } + /* Zero-terminate */ + *p = '\0'; + /* If length is -2 or -1, pad last char or two */ + while (length) { + *--p = tbl[64]; + length++; + } +} +EXPORT_SYMBOL(uuencode); + +/* + * Decode base64 encoded string. Stops on '\0'. + * + */ +int decode_base64(char *p_dst, int dst_len, const char *src) +{ + const char *src_tail; + char *dst = p_dst; + int length = 0; + + while (dst_len > 0) { + unsigned char six_bit[4]; + int count = 0; + + /* Fetch up to four 6-bit values */ + src_tail = src; + while (count < 4) { + const char *table_ptr; + int ch; + + /* + * Get next _valid_ character. + * uuenc_tbl_base64[] contains this string: + * 0 1 2 3 4 5 6 + * 01234567890123456789012345678901234567890123456789012345678901234 + * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + */ + do { + ch = *src; + if (ch == '\0') { + /* + * Example: + * If we decode "QUJD <NUL>", we want + * to return ptr to NUL, not to ' ', + * because we did fully decode + * the string (to "ABC"). + */ + if (count == 0) + src_tail = src; + goto ret; + } + src++; + table_ptr = strchr(uuenc_tbl_base64, ch); + } while (!table_ptr); + + /* Convert encoded character to decimal */ + ch = table_ptr - uuenc_tbl_base64; + + /* ch is 64 if char was '=', otherwise 0..63 */ + if (ch == 64) + break; + + six_bit[count] = ch; + count++; + } + + /* + * Transform 6-bit values to 8-bit ones. + * count can be < 4 when we decode the tail: + * "eQ==" -> "y", not "y NUL NUL". + * Note that (count > 1) is always true, + * "x===" encoding is not valid: + * even a single zero byte encodes as "AA==". + * However, with current logic we come here with count == 1 + * when we decode "==" tail. + */ + if (count > 1) + *dst++ = six_bit[0] << 2 | six_bit[1] >> 4; + if (count > 2) + *dst++ = six_bit[1] << 4 | six_bit[2] >> 2; + if (count > 3) + *dst++ = six_bit[2] << 6 | six_bit[3]; + /* + * Note that if we decode "AA==" and ate first '=', + * we just decoded one char (count == 2) and now we'll + * do the loop once more to decode second '='. + */ + dst_len -= count-1; + /* last character was "=" */ + if (count != 0) + length += count - 1; + } +ret: + p_dst = dst; + + return length; +} +EXPORT_SYMBOL(decode_base64); diff --git a/lib/blobgen.c b/lib/blobgen.c new file mode 100644 index 0000000000..5a556a68ce --- /dev/null +++ b/lib/blobgen.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * 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. + * + */ +#include <blobgen.h> +#include <base64.h> +#include <malloc.h> +#include <crypto.h> +#include <dma.h> +#include <environment.h> + +static LIST_HEAD(blobs); +static struct blobgen *bg_default; + +/** + * blob_gen_register - register a blob device + * @dev: The parent device + * @bg: The blobgen device + * + * This registers a blob device. Returns 0 for success or a negative error + * code otherwise. + */ +int blob_gen_register(struct device_d *dev, struct blobgen *bg) +{ + int ret; + + dev_set_name(&bg->dev, "blob"); + bg->dev.parent = dev; + + ret = register_device(&bg->dev); + if (ret) + return ret; + + list_add_tail(&bg->list, &blobs); + + if (!bg_default) + bg_default = bg; + + return 0; +} + +/** + * blobgen_get - get a blob generator of given name + * @name: The name of the blob generator to look for + * + * Finds a blob generator by name and returns it. Returns NULL if none is found. + */ +struct blobgen *blobgen_get(const char *name) +{ + struct device_d *dev; + struct blobgen *bg; + + if (!name) + return bg_default; + + dev = get_device_by_name(name); + if (!dev) + return NULL; + + list_for_each_entry(bg, &blobs, list) { + if (dev == &bg->dev) + return bg; + } + + return NULL; +} + +/** + * blob_encrypt - encrypt a data blob + * @bg: The blob generator to use + * @modifier: Modifier string + * @plain: The plaintext input + * @plainsize: Length of the plain data in bytes + * @retblob: The encrypted blob is returned here + * @blobsize: The returned length of the encrypted blob + * + * This encrypts a blob passed in @plain to an allocated buffer returned in + * @retblob. Returns 0 for success or a negative error code otherwise. @retblob + * is valid when the function returns successfully. The caller must free the + * buffer after use. + */ +int blob_encrypt(struct blobgen *bg, const char *modifier, const void *plain, + int plainsize, void **retblob, int *blobsize) +{ + void *blob; + int ret; + + if (plainsize > bg->max_payload_size) + return -EINVAL; + + pr_debug("%s plain:\n", __func__); + pr_memory_display(MSG_DEBUG, plain, 0, plainsize, 1, 0); + + blob = dma_alloc(MAX_BLOB_LEN); + if (!blob) + return -ENOMEM; + + ret = bg->encrypt(bg, modifier, plain, plainsize, blob, blobsize); + + if (ret) { + free(blob); + } else { + pr_debug("%s encrypted:\n", __func__); + pr_memory_display(MSG_DEBUG, blob, 0, *blobsize, 1, 0); + *retblob = blob; + } + + return ret; +} + +/** + * blob_encrypt_to_env - encrypt blob to environment variable + * @bg: The blob generator to use + * @modifier: Modifier string + * @plain: The plaintext input + * @plainsize: Length of the plain data in bytes + * @varname: Name of the variable to set with the output blob + * + * This uses blob_encrypt to encrypt a blob. The result is base64 encoded and + * written to the environment variable @varname. Returns 0 for success or a + * negative error code otherwise. + */ +int blob_encrypt_to_env(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, const char *varname) +{ + int ret; + int blobsize; + void *blob; + char *value; + + ret = blob_encrypt(bg, modifier, plain, plainsize, &blob, &blobsize); + if (ret) + return ret; + + value = malloc(BASE64_LENGTH(blobsize) + 1); + if (!value) + return -ENOMEM; + + uuencode(value, blob, blobsize); + + pr_debug("%s encrypted base64: \"%s\"\n", __func__, value); + + ret = setenv(varname, value); + + free(value); + free(blob); + + return ret; +} + +/** + * blob_decrypt - decrypt a blob + * @bg: The blob generator to use + * @modifier: Modifier string + * @blob: The encrypted blob + * @blobsize: Size of the encrypted blob + * @plain: Plaintext is returned here + * @plainsize: Size of the data returned in bytes + * + * This function decrypts a blob generated with blob_encrypt. @modifier must match + * the modifier used to encrypt the data. Returns 0 when the data could be + * decrypted successfully or a negative error code otherwise. + */ +int blob_decrypt(struct blobgen *bg, const char *modifier, const void *blob, + int blobsize, void **plain, int *plainsize) +{ + int ret; + + pr_debug("%s encrypted:\n", __func__); + pr_memory_display(MSG_DEBUG, blob, 0, blobsize, 1, 0); + + ret = bg->decrypt(bg, modifier, blob, blobsize, plain, plainsize); + + if (!ret) { + pr_debug("%s decrypted:\n", __func__); + pr_memory_display(MSG_DEBUG, *plain, 0, *plainsize, 1, 0); + } + + return ret; +} + +/** + * blob_decrypt_from_base64 - decrypt a base64 encoded blob + * @bg: The blob generator to use + * @modifier: Modifier string + * @encrypted: base64 encoded encrypted data + * @plain: Plaintext is returned here + * @plainsize: Size of the data returned in bytes + * + * like blob_decrypt, but takes the encrypted data as a base64 encoded string. + * Returns 0 when the data could be decrypted successfully or a negative error + * code otherwise. + */ +int blob_decrypt_from_base64(struct blobgen *bg, const char *modifier, + const char *encrypted, void **plain, + int *plainsize) +{ + char *data; + int ret, len; + + data = dma_alloc(MAX_BLOB_LEN); + if (!data) + return -ENOMEM; + + pr_debug("encrypted base64: \"%s\"\n", encrypted); + + len = decode_base64(data, MAX_BLOB_LEN, encrypted); + + ret = blob_decrypt(bg, modifier, data, len, plain, plainsize); + + free(data); + + return ret; +} diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 8c07a54d05..95eaf522ab 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -470,7 +470,7 @@ cmd_imximage_S_dcd= \ overwrite-hab-env = $(shell set -e; \ test -n "$(CONFIG_HAB_CERTS_ENV)"; \ test -n "$$$(1)"; \ - echo -D$(1)=\"$(shell echo $$$(1))\") + echo -D$(1)=\\\"$(shell echo $$$(1))\\\") imxcfg_cpp_flags = -Wp,-MD,$(depfile) -nostdinc -x assembler-with-cpp \ -I $(srctree)/include -I $(srctree)/arch/arm/mach-imx/include \ diff --git a/scripts/pblimage.c b/scripts/pblimage.c index 6e83c523e5..73c0169ac1 100644 --- a/scripts/pblimage.c +++ b/scripts/pblimage.c @@ -13,6 +13,7 @@ #include <stdint.h> #include <getopt.h> #include <endian.h> +#include <byteswap.h> #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define PBL_ACS_CONT_CMD 0x81000000 @@ -49,11 +50,11 @@ static int pbl_end; static int image_size; static int out_fd; static int in_fd; +static int spiimage; static uint32_t pbl_cmd_initaddr; static uint32_t pbi_crc_cmd1; static uint32_t pbi_crc_cmd2; -static uint32_t pbl_end_cmd[4]; enum arch { ARCH_ARM, @@ -210,16 +211,6 @@ static void pbl_parser(char *name) static void add_end_cmd(void) { uint32_t crc32_pbl; - int i; - unsigned char *p = (unsigned char *)&pbl_end_cmd; - - for (i = 0; i < 4; i++) - pbl_end_cmd[i] = htobe32(pbl_end_cmd[i]); - - for (i = 0; i < 16; i++) { - *pmem_buf++ = *p++; - pbl_size++; - } /* Add PBI CRC command. */ *pmem_buf++ = 0x08; @@ -240,6 +231,7 @@ static void add_end_cmd(void) static void pbl_load_image(void) { int size; + uint64_t *buf64 = (void *)mem_buf; /* parse the rcw.cfg file. */ pbl_parser(rcwfile); @@ -256,6 +248,15 @@ static void pbl_load_image(void) add_end_cmd(); + if (spiimage) { + int i; + + pbl_size = roundup(pbl_size, 8); + + for (i = 0; i < pbl_size / 8; i++) + buf64[i] = bswap_64(buf64[i]); + } + size = pbl_size; if (write(out_fd, (const void *)&mem_buf, size) != size) { @@ -297,18 +298,10 @@ static int pblimage_check_params(void) pbl_cmd_initaddr = loadaddr & PBL_ADDR_24BIT_MASK; pbl_cmd_initaddr |= PBL_ACS_CONT_CMD; pbl_cmd_initaddr += image_size; - pbl_end_cmd[0] = 0x09610000; - pbl_end_cmd[1] = 0x00000000; - pbl_end_cmd[2] = 0x096100c0; - pbl_end_cmd[3] = 0x00000000; } else { pbi_crc_cmd1 = 0x13; pbi_crc_cmd2 = 0x80; pbl_cmd_initaddr = 0x82000000; - pbl_end_cmd[0] = 0x091380c0; - pbl_end_cmd[1] = 0x00000000; - pbl_end_cmd[2] = 0x091380c0; - pbl_end_cmd[3] = 0x00000000; } next_pbl_cmd = pbl_cmd_initaddr; @@ -357,7 +350,7 @@ int main(int argc, char *argv[]) int opt, ret; off_t pos; - while ((opt = getopt(argc, argv, "i:r:p:o:m:")) != -1) { + while ((opt = getopt(argc, argv, "i:r:p:o:m:s")) != -1) { switch (opt) { case 'i': infile = optarg; @@ -374,6 +367,9 @@ int main(int argc, char *argv[]) case 'm': pbl_end = atoi(optarg); break; + case 's': + spiimage = 1; + break; default: exit(EXIT_FAILURE); } |