diff options
263 files changed, 13142 insertions, 1861 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 64fb41ece7..ea21d59f1e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -383,12 +383,16 @@ T: git git://github.com/agraf/u-boot.git F: doc/README.uefi F: doc/README.iscsi F: Documentation/efi.rst +F: include/capitalization.h +F: include/cp1250.h +F: include/cp437.h F: include/efi* F: include/pe.h F: include/asm-generic/pe.h F: lib/charset.c F: lib/efi*/ F: test/py/tests/test_efi* +F: test/unicode_ut.c F: cmd/bootefi.c F: tools/file2include.c @@ -372,7 +372,7 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__ KBUILD_CFLAGS := -Wall -Wstrict-prototypes \ -Wno-format-security \ -fno-builtin -ffreestanding $(CSTD_FLAG) -KBUILD_CFLAGS += -fshort-wchar +KBUILD_CFLAGS += -fshort-wchar -fno-strict-aliasing KBUILD_AFLAGS := -D__ASSEMBLY__ # Don't generate position independent code @@ -528,25 +528,6 @@ The following options need to be configured: pointer. This is needed for the temporary stack before relocation. - CONFIG_SYS_MIPS_CACHE_MODE - - Cache operation mode for the MIPS CPU. - See also arch/mips/include/asm/mipsregs.h. - Possible values are: - CONF_CM_CACHABLE_NO_WA - CONF_CM_CACHABLE_WA - CONF_CM_UNCACHED - CONF_CM_CACHABLE_NONCOHERENT - CONF_CM_CACHABLE_CE - CONF_CM_CACHABLE_COW - CONF_CM_CACHABLE_CUW - CONF_CM_CACHABLE_ACCELERATED - - CONFIG_SYS_XWAY_EBU_BOOTCFG - - Special option for Lantiq XWAY SoCs for booting from NOR flash. - See also arch/mips/cpu/mips32/start.S. - CONFIG_XWAY_SWAP_BYTES Enable compilation of tools/xway-swap-bytes needed for Lantiq diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0f8dd32bdd..ccf2a844be 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -747,6 +747,8 @@ config ARCH_QEMU select OF_CONTROL select PL01X_SERIAL imply CMD_DM + imply DM_RTC + imply RTC_PL031 config ARCH_RMOBILE bool "Renesas ARM SoCs" @@ -861,7 +863,6 @@ config ARCH_VF610 config ARCH_ZYNQ bool "Xilinx Zynq based platform" select BOARD_EARLY_INIT_F if WDT - select BOARD_LATE_INIT select CLK select CLK_ZYNQ select CPU_V7A @@ -881,6 +882,7 @@ config ARCH_ZYNQ select SPL_SEPARATE_BSS if SPL select SUPPORT_SPL imply ARCH_EARLY_INIT_R + imply BOARD_LATE_INIT imply CMD_CLK imply CMD_DM imply CMD_SPL @@ -898,7 +900,6 @@ config ARCH_ZYNQMP_R5 config ARCH_ZYNQMP bool "Xilinx ZynqMP based platform" select ARM64 - select BOARD_LATE_INIT select CLK select DM select DM_SERIAL @@ -907,6 +908,7 @@ config ARCH_ZYNQMP select SPL_BOARD_INIT if SPL select SPL_CLK if SPL select SUPPORT_SPL + imply BOARD_LATE_INIT imply CMD_DM imply FAT_WRITE diff --git a/arch/arm/cpu/arm926ejs/spear/cpu.c b/arch/arm/cpu/arm926ejs/spear/cpu.c index 88a40c6036..51c4a730f4 100644 --- a/arch/arm/cpu/arm926ejs/spear/cpu.c +++ b/arch/arm/cpu/arm926ejs/spear/cpu.c @@ -52,6 +52,9 @@ int arch_cpu_init(void) #if defined(CONFIG_SPEAR_GPIO) periph1_clken |= MISC_GPIO3ENB | MISC_GPIO4ENB; #endif +#if defined(CONFIG_PL022_SPI) + periph1_clken |= MISC_SSP1ENB | MISC_SSP2ENB | MISC_SSP3ENB; +#endif writel(periph1_clken, &misc_p->periph1_clken); diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index 052e0708d4..be00bd55ab 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -835,7 +835,7 @@ int dram_init_banksize(void) return 0; } -#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(EFI_LOADER) void efi_add_known_memory(void) { int i; diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index fc9de73bce..c9c2c3f6d3 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -135,7 +135,7 @@ remove_psci_node: fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, *boot_code_size); -#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(EFI_LOADER) efi_add_memory_map((uintptr_t)&secondary_boot_code, ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT, EFI_RESERVED_MEMORY_TYPE, false); diff --git a/arch/arm/cpu/armv8/zynqmp/cpu.c b/arch/arm/cpu/armv8/zynqmp/cpu.c index 1279dc8658..43ba739d2f 100644 --- a/arch/arm/cpu/armv8/zynqmp/cpu.c +++ b/arch/arm/cpu/armv8/zynqmp/cpu.c @@ -171,38 +171,28 @@ int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, return regs.regs[0]; } -#define ZYNQMP_SIP_SVC_GET_API_VERSION 0xC2000001 - -#define ZYNQMP_PM_VERSION_MAJOR 1 -#define ZYNQMP_PM_VERSION_MINOR 0 -#define ZYNQMP_PM_VERSION_MAJOR_SHIFT 16 -#define ZYNQMP_PM_VERSION_MINOR_MASK 0xFFFF - -#define ZYNQMP_PM_VERSION \ - ((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \ - ZYNQMP_PM_VERSION_MINOR) - #if defined(CONFIG_CLK_ZYNQMP) -void zynqmp_pmufw_version(void) +unsigned int zynqmp_pmufw_version(void) { int ret; u32 ret_payload[PAYLOAD_ARG_CNT]; - u32 pm_api_version; - - ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0, - ret_payload); - pm_api_version = ret_payload[1]; + static u32 pm_api_version = ZYNQMP_PM_VERSION_INVALID; - if (ret) - panic("PMUFW is not found - Please load it!\n"); + /* + * Get PMU version only once and later + * just return stored values instead of + * asking PMUFW again. + */ + if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) { + ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0, + ret_payload); + pm_api_version = ret_payload[1]; - printf("PMUFW:\tv%d.%d\n", - pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, - pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK); + if (ret) + panic("PMUFW is not found - Please load it!\n"); + } - if (pm_api_version < ZYNQMP_PM_VERSION) - panic("PMUFW version error. Expected: v%d.%d\n", - ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR); + return pm_api_version; } #endif diff --git a/arch/arm/dts/am3517-evm-u-boot.dtsi b/arch/arm/dts/am3517-evm-u-boot.dtsi index c02beaad77..59df819f9d 100644 --- a/arch/arm/dts/am3517-evm-u-boot.dtsi +++ b/arch/arm/dts/am3517-evm-u-boot.dtsi @@ -10,10 +10,6 @@ }; }; -&mmc1 { - cd-inverted; -}; - &uart1 { reg-shift = <2>; }; diff --git a/arch/arm/dts/at91-sama5d27_som1_ek.dts b/arch/arm/dts/at91-sama5d27_som1_ek.dts index 5e62d4af71..4cd6db66fe 100644 --- a/arch/arm/dts/at91-sama5d27_som1_ek.dts +++ b/arch/arm/dts/at91-sama5d27_som1_ek.dts @@ -54,6 +54,18 @@ stdout-path = &uart1; }; + onewire_tm: onewire { + gpios = <&pioA 17 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_onewire_tm_default>; + status = "okay"; + + w1_eeprom: w1_eeprom@0 { + compatible = "maxim,ds24b33"; + status = "okay"; + }; + }; + ahb { usb1: ohci@00400000 { num-ports = <3>; @@ -208,6 +220,11 @@ pinmux = <PIN_PA31__GPIO>; bias-disable; }; + + pinctrl_onewire_tm_default: onewire_tm_default { + pinmux = <PIN_PA17__GPIO>; + bias-pull-up; + }; }; }; }; diff --git a/arch/arm/dts/at91-sama5d2_ptc_ek.dts b/arch/arm/dts/at91-sama5d2_ptc_ek.dts index ab5ab21895..068a117585 100644 --- a/arch/arm/dts/at91-sama5d2_ptc_ek.dts +++ b/arch/arm/dts/at91-sama5d2_ptc_ek.dts @@ -56,6 +56,18 @@ stdout-path = &uart0; }; + onewire_tm: onewire { + gpios = <&pioA PIN_PB31 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_onewire_tm_default>; + status = "okay"; + + w1_eeprom: w1_eeprom@0 { + compatible = "maxim,ds24b33"; + status = "okay"; + }; + }; + ahb { usb0: gadget@00300000 { atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>; @@ -208,6 +220,11 @@ pinmux = <PIN_PB11__GPIO>; bias-disable; }; + + pinctrl_onewire_tm_default: onewire_tm_default { + pinmux = <PIN_PB31__GPIO>; + bias-pull-up; + }; }; }; }; diff --git a/arch/arm/dts/at91-sama5d2_xplained.dts b/arch/arm/dts/at91-sama5d2_xplained.dts index 01326a1ee0..33064b390a 100644 --- a/arch/arm/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/dts/at91-sama5d2_xplained.dts @@ -11,6 +11,18 @@ stdout-path = &uart1; }; + onewire_tm: onewire { + gpios = <&pioA PIN_PB0 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_onewire_tm_default>; + status = "okay"; + + w1_eeprom: w1_eeprom@0 { + compatible = "maxim,ds24b33"; + status = "okay"; + }; + }; + ahb { usb1: ohci@00400000 { num-ports = <3>; @@ -270,6 +282,11 @@ pinmux = <PIN_PA31__GPIO>; bias-disable; }; + + pinctrl_onewire_tm_default: onewire_tm_default { + pinmux = <PIN_PB0__GPIO>; + bias-pull-up; + }; }; }; }; diff --git a/arch/arm/dts/at91-sama5d3_xplained.dts b/arch/arm/dts/at91-sama5d3_xplained.dts index 69597102fb..20fba5f067 100644 --- a/arch/arm/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/dts/at91-sama5d3_xplained.dts @@ -36,6 +36,18 @@ }; }; + onewire_tm: onewire { + gpios = <&pioE 23 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_onewire_tm_default>; + status = "okay"; + + w1_eeprom: w1_eeprom@0 { + compatible = "maxim,ds24b33"; + status = "okay"; + }; + }; + ahb { apb { mmc0: mmc@f0000000 { @@ -243,6 +255,11 @@ atmel,pins = <AT91_PIOE 9 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>; /* PE9, conflicts with A9 */ }; + + pinctrl_onewire_tm_default: onewire_tm_default { + atmel,pins = + <AT91_PIOE 23 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>; + }; }; }; }; diff --git a/arch/arm/dts/at91-sama5d4_xplained.dts b/arch/arm/dts/at91-sama5d4_xplained.dts index ea35dc21b6..58a0e60d18 100644 --- a/arch/arm/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/dts/at91-sama5d4_xplained.dts @@ -58,6 +58,18 @@ stdout-path = &usart3; }; + onewire_tm: onewire { + gpios = <&pioE 15 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_onewire_tm_default>; + status = "okay"; + + w1_eeprom: w1_eeprom@0 { + compatible = "maxim,ds24b33"; + status = "okay"; + }; + }; + memory { reg = <0x20000000 0x20000000>; }; @@ -199,6 +211,10 @@ atmel,pins = <AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>; }; + pinctrl_onewire_tm_default: onewire_tm_default { + atmel,pins = + <AT91_PIOE 15 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP>; + }; }; }; }; diff --git a/arch/arm/dts/omap3-beagle-u-boot.dtsi b/arch/arm/dts/omap3-beagle-u-boot.dtsi index 094f9557b7..41beaf0900 100644 --- a/arch/arm/dts/omap3-beagle-u-boot.dtsi +++ b/arch/arm/dts/omap3-beagle-u-boot.dtsi @@ -11,10 +11,6 @@ }; }; -&mmc1 { - cd-inverted; -}; - &uart1 { reg-shift = <2>; }; diff --git a/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi b/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi index 094f9557b7..41beaf0900 100644 --- a/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi +++ b/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi @@ -11,10 +11,6 @@ }; }; -&mmc1 { - cd-inverted; -}; - &uart1 { reg-shift = <2>; }; diff --git a/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi b/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi index 094f9557b7..41beaf0900 100644 --- a/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi +++ b/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi @@ -11,10 +11,6 @@ }; }; -&mmc1 { - cd-inverted; -}; - &uart1 { reg-shift = <2>; }; diff --git a/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi b/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi index b09ce0efb5..de411316d8 100644 --- a/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi +++ b/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi @@ -11,10 +11,6 @@ }; }; -&mmc1 { - cd-inverted; -}; - &uart1 { reg-shift = <2>; }; diff --git a/arch/arm/dts/omap3-evm-u-boot.dtsi b/arch/arm/dts/omap3-evm-u-boot.dtsi index b09ce0efb5..de411316d8 100644 --- a/arch/arm/dts/omap3-evm-u-boot.dtsi +++ b/arch/arm/dts/omap3-evm-u-boot.dtsi @@ -11,10 +11,6 @@ }; }; -&mmc1 { - cd-inverted; -}; - &uart1 { reg-shift = <2>; }; diff --git a/arch/arm/dts/sama5d2.dtsi b/arch/arm/dts/sama5d2.dtsi index 6645a55364..830251a539 100644 --- a/arch/arm/dts/sama5d2.dtsi +++ b/arch/arm/dts/sama5d2.dtsi @@ -769,4 +769,9 @@ }; }; }; + + onewire_tm: onewire { + compatible = "w1-gpio"; + status = "disabled"; + }; }; diff --git a/arch/arm/dts/sama5d3.dtsi b/arch/arm/dts/sama5d3.dtsi index ba707b0ddf..7db66c5d50 100644 --- a/arch/arm/dts/sama5d3.dtsi +++ b/arch/arm/dts/sama5d3.dtsi @@ -1534,4 +1534,9 @@ }; }; }; + + onewire_tm: onewire { + compatible = "w1-gpio"; + status = "disabled"; + }; }; diff --git a/arch/arm/dts/sama5d4.dtsi b/arch/arm/dts/sama5d4.dtsi index 8072b8a4f2..8875d7ba76 100644 --- a/arch/arm/dts/sama5d4.dtsi +++ b/arch/arm/dts/sama5d4.dtsi @@ -1913,4 +1913,9 @@ }; }; }; + + onewire_tm: onewire { + compatible = "w1-gpio"; + status = "disabled"; + }; }; diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index c69c397964..85da592655 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -321,6 +321,12 @@ bias-disable; }; }; + + usbotg_hs_pins_a: usbotg_hs-0 { + pins { + pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* OTG_ID */ + }; + }; }; pinctrl_z: pin-controller-z@54004000 { diff --git a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi index 2f4de3a066..30b173478c 100644 --- a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi @@ -25,6 +25,10 @@ regulator-always-on; }; +&usbotg_hs { + g-tx-fifo-size = <576>; +}; + /* SPL part **************************************/ &qspi { u-boot,dm-spl; @@ -60,3 +64,4 @@ &flash0 { u-boot,dm-spl; }; + diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index d6934f74e0..902a42bee2 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -96,6 +96,21 @@ }; }; +&usbh_ehci { + phys = <&usbphyc_port0>; + phy-names = "usb"; + vbus-supply = <&vbus_sw>; + status = "okay"; +}; + +&usbotg_hs { + pinctrl-names = "default"; + pinctrl-0 = <&usbotg_hs_pins_a>; + phys = <&usbphyc_port1 0>; + phy-names = "usb2-phy"; + status = "okay"; +}; + &usbphyc { status = "okay"; }; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index cdf2946968..33c5981869 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -106,6 +106,26 @@ }; }; + pm_domain { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32mp157c-pd"; + + pd_core_ret: core-ret-power-domain@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + #power-domain-cells = <0>; + label = "CORE-RETENTION"; + + pd_core: core-power-domain@2 { + reg = <2>; + #power-domain-cells = <0>; + label = "CORE"; + }; + }; + }; + soc { compatible = "simple-bus"; #address-cells = <1>; @@ -654,6 +674,22 @@ status = "disabled"; }; + usbotg_hs: usb-otg@49000000 { + compatible = "st,stm32mp1-hsotg", "snps,dwc2"; + reg = <0x49000000 0x10000>; + clocks = <&rcc USBO_K>; + clock-names = "otg"; + resets = <&rcc USBO_R>; + reset-names = "dwc2"; + interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + g-rx-fifo-size = <256>; + g-np-tx-fifo-size = <32>; + g-tx-fifo-size = <128 128 64 64 64 64 32 32>; + dr_mode = "otg"; + power-domains = <&pd_core>; + status = "disabled"; + }; + rcc: rcc@50000000 { compatible = "st,stm32mp1-rcc", "syscon"; reg = <0x50000000 0x1000>; diff --git a/arch/arm/include/asm/arch-omap3/mmc_host_def.h b/arch/arm/include/asm/arch-omap3/mmc_host_def.h index 9f2896c4b9..39a7cba0f6 100644 --- a/arch/arm/include/asm/arch-omap3/mmc_host_def.h +++ b/arch/arm/include/asm/arch-omap3/mmc_host_def.h @@ -51,6 +51,7 @@ typedef struct t2 { #define PBIASLITEPWRDNZ0 (1 << 1) #define PBIASSPEEDCTRL0 (1 << 2) #define PBIASLITEPWRDNZ1 (1 << 9) +#define PBIASLITEVMODE1 (1 << 8) #define PBIASLITEVMODE0 (1 << 0) #define CTLPROGIO1SPEEDCTRL (1 << 20) diff --git a/arch/arm/include/asm/arch-spear/spr_misc.h b/arch/arm/include/asm/arch-spear/spr_misc.h index 65063fca51..0171119351 100644 --- a/arch/arm/include/asm/arch-spear/spr_misc.h +++ b/arch/arm/include/asm/arch-spear/spr_misc.h @@ -146,11 +146,13 @@ struct misc_regs { #define MISC_SMIENB 0x00200000 #define MISC_GPIO3ENB 0x00040000 #define MISC_GPT3ENB 0x00010000 +#define MISC_SSP3ENB 0x00004000 #define MISC_GPIO4ENB 0x00002000 #define MISC_GPT2ENB 0x00000800 #define MISC_FSMCENB 0x00000200 #define MISC_I2CENB 0x00000080 -#define MISC_SSP2ENB 0x00000070 +#define MISC_SSP2ENB 0x00000040 +#define MISC_SSP1ENB 0x00000020 #define MISC_UART0ENB 0x00000008 /* PERIPH_CLK_CFG */ diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index 773b930512..9fa44d084c 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -21,6 +21,21 @@ #define ZYNQMP_FPGA_AUTH_DDR 1 +#define ZYNQMP_SIP_SVC_GET_API_VERSION 0xC2000001 + +#define ZYNQMP_PM_VERSION_MAJOR 1 +#define ZYNQMP_PM_VERSION_MINOR 0 +#define ZYNQMP_PM_VERSION_MAJOR_SHIFT 16 +#define ZYNQMP_PM_VERSION_MINOR_MASK 0xFFFF + +#define ZYNQMP_PM_VERSION \ + ((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \ + ZYNQMP_PM_VERSION_MINOR) + +#define ZYNQMP_PM_VERSION_INVALID ~0 + +#define PMUFW_V1_0 ((1 << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | 0) + enum { IDCODE, VERSION, @@ -44,7 +59,7 @@ unsigned int zynqmp_get_silicon_version(void); void handoff_setup(void); -void zynqmp_pmufw_version(void); +unsigned int zynqmp_pmufw_version(void); int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value); int zynqmp_mmio_read(const u32 address, u32 *value); int invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 171f4d9792..5822b0a52c 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -20,152 +20,8 @@ #error SMP not supported #endif -typedef struct { volatile int counter; } atomic_t; -#if BITS_PER_LONG == 32 -typedef struct { volatile long long counter; } atomic64_t; -#else /* BIT_PER_LONG == 32 */ -typedef struct { volatile long counter; } atomic64_t; -#endif - -#define ATOMIC_INIT(i) { (i) } - -#ifdef __KERNEL__ #include <asm/proc-armv/system.h> - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v, i) (((v)->counter) = (i)) -#define atomic64_read(v) atomic_read(v) -#define atomic64_set(v, i) atomic_set(v, i) - -static inline void atomic_add(int i, volatile atomic_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter += i; - local_irq_restore(flags); -} - -static inline void atomic_sub(int i, volatile atomic_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter -= i; - local_irq_restore(flags); -} - -static inline void atomic_inc(volatile atomic_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter += 1; - local_irq_restore(flags); -} - -static inline void atomic_dec(volatile atomic_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter -= 1; - local_irq_restore(flags); -} - -static inline int atomic_dec_and_test(volatile atomic_t *v) -{ - unsigned long flags = 0; - int val; - - local_irq_save(flags); - val = v->counter; - v->counter = val -= 1; - local_irq_restore(flags); - - return val == 0; -} - -static inline int atomic_add_negative(int i, volatile atomic_t *v) -{ - unsigned long flags = 0; - int val; - - local_irq_save(flags); - val = v->counter; - v->counter = val += i; - local_irq_restore(flags); - - return val < 0; -} - -static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) -{ - unsigned long flags = 0; - - local_irq_save(flags); - *addr &= ~mask; - local_irq_restore(flags); -} - -#if BITS_PER_LONG == 32 - -static inline void atomic64_add(long long i, volatile atomic64_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter += i; - local_irq_restore(flags); -} - -static inline void atomic64_sub(long long i, volatile atomic64_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter -= i; - local_irq_restore(flags); -} - -#else /* BIT_PER_LONG == 32 */ - -static inline void atomic64_add(long i, volatile atomic64_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter += i; - local_irq_restore(flags); -} - -static inline void atomic64_sub(long i, volatile atomic64_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter -= i; - local_irq_restore(flags); -} -#endif - -static inline void atomic64_inc(volatile atomic64_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter += 1; - local_irq_restore(flags); -} - -static inline void atomic64_dec(volatile atomic64_t *v) -{ - unsigned long flags = 0; - - local_irq_save(flags); - v->counter -= 1; - local_irq_restore(flags); -} +#include <asm-generic/atomic.h> /* Atomic operations are already serializing on ARM */ #define smp_mb__before_atomic_dec() barrier() @@ -174,4 +30,3 @@ static inline void atomic64_dec(volatile atomic64_t *v) #define smp_mb__after_atomic_inc() barrier() #endif -#endif diff --git a/arch/arm/include/asm/omap_mmc.h b/arch/arm/include/asm/omap_mmc.h index 42ce8dcd6d..6d31cc4422 100644 --- a/arch/arm/include/asm/omap_mmc.h +++ b/arch/arm/include/asm/omap_mmc.h @@ -68,7 +68,6 @@ struct omap_hsmmc_plat { struct mmc_config cfg; struct hsmmc *base_addr; struct mmc *mmc; - bool cd_inverted; u32 controller_flags; const char *hw_rev; }; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 69856c8942..a6329dc022 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -151,6 +151,7 @@ config TARGET_SAMA5D2_PTC_EK bool "SAMA5D2 PTC EK board" select BOARD_EARLY_INIT_F select SAMA5D2 + select BOARD_LATE_INIT config TARGET_SAMA5D2_XPLAINED bool "SAMA5D2 Xplained board" @@ -177,6 +178,7 @@ config TARGET_SAMA5D3_XPLAINED select BOARD_EARLY_INIT_F select SAMA5D3 select SUPPORT_SPL + select BOARD_LATE_INIT config TARGET_SAMA5D3XEK bool "SAMA5D3X-EK board" diff --git a/arch/arm/mach-davinci/da850_lowlevel.c b/arch/arm/mach-davinci/da850_lowlevel.c index 95dc93a24f..822e0dc4a1 100644 --- a/arch/arm/mach-davinci/da850_lowlevel.c +++ b/arch/arm/mach-davinci/da850_lowlevel.c @@ -288,10 +288,10 @@ int arch_cpu_init(void) /* GPIO setup */ board_gpio_init(); - +#if !CONFIG_IS_ENABLED(DM_SERIAL) NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); - +#endif /* * Fix Power and Emulation Management Register * see sprufw3a.pdf page 37 Table 24 diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c index 421a71b301..12257a42b5 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -6,6 +6,7 @@ #include <common.h> #include <dm.h> +#include <efi_loader.h> #include <errno.h> #include <ns16550.h> #include <usb.h> @@ -210,6 +211,19 @@ int board_early_init_f(void) int board_late_init(void) { +#if CONFIG_IS_ENABLED(EFI_LOADER) + if (gd->bd->bi_dram[1].start) { + /* + * Only bank 0 is below board_get_usable_ram_top(), so all of + * bank 1 is not mapped by the U-Boot MMU configuration, and so + * we must prevent EFI from using it. + */ + efi_add_memory_map(gd->bd->bi_dram[1].start, + gd->bd->bi_dram[1].size >> EFI_PAGE_SHIFT, + EFI_BOOT_SERVICES_DATA, false); + } +#endif + #if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) if (tegra_cpu_is_non_secure()) { printf("CPU is in NS mode\n"); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6e5e0ffe65..071dea04ec 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -28,6 +28,7 @@ config TARGET_MALTA select DM_SERIAL select DYNAMIC_IO_PORT_BASE select MIPS_CM + select MIPS_INSERT_BOOT_CONFIG select MIPS_L1_CACHE_SHIFT_6 select MIPS_L2_CACHE select OF_CONTROL @@ -68,6 +69,22 @@ config ARCH_BMIPS select SYSRESET imply CMD_DM +config ARCH_MT7620 + bool "Support MT7620/7688 SoCs" + imply CMD_DM + select DISPLAY_CPUINFO + select DM + select DM_SERIAL + imply DM_SPI + imply DM_SPI_FLASH + select MIPS_TUNE_24KC + select OF_CONTROL + select ROM_EXCEPTION_VECTORS + select SUPPORTS_CPU_MIPS32_R1 + select SUPPORTS_CPU_MIPS32_R2 + select SUPPORTS_LITTLE_ENDIAN + select SYSRESET + config MACH_PIC32 bool "Support Microchip PIC32" select DM @@ -120,6 +137,7 @@ source "board/qemu-mips/Kconfig" source "arch/mips/mach-ath79/Kconfig" source "arch/mips/mach-bmips/Kconfig" source "arch/mips/mach-pic32/Kconfig" +source "arch/mips/mach-mt7620/Kconfig" if MIPS @@ -218,6 +236,18 @@ config MIPS_CM_BASE the GCRs occupy a region of the physical address space which is otherwise unused, or at minimum that software doesn't need to access. +config MIPS_CACHE_INDEX_BASE + hex "Index base address for cache initialisation" + default 0x80000000 if CPU_MIPS32 + default 0xffffffff80000000 if CPU_MIPS64 + help + This is the base address for a memory block, which is used for + initialising the cache lines. This is also the base address of a memory + block which is used for loading and filling cache lines when + SYS_MIPS_CACHE_INIT_RAM_LOAD is selected. + Normally this is CKSEG0. If the MIPS system needs to move this block + to some SRAM or ScratchPad RAM, adapt this option accordingly. + endmenu menu "OS boot interface" @@ -390,6 +420,28 @@ config MIPS_CM wish U-Boot to configure it or make use of it to retrieve system information such as cache configuration. +config MIPS_INSERT_BOOT_CONFIG + bool + default n + help + Enable this to insert some board-specific boot configuration in + the U-Boot binary at offset 0x10. + +config MIPS_BOOT_CONFIG_WORD0 + hex + depends on MIPS_INSERT_BOOT_CONFIG + default 0x420 if TARGET_MALTA + default 0x0 + help + Value which is inserted as boot config word 0. + +config MIPS_BOOT_CONFIG_WORD1 + hex + depends on MIPS_INSERT_BOOT_CONFIG + default 0x0 + help + Value which is inserted as boot config word 1. + endif endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile index a36f5f1fb6..802244a06e 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -14,6 +14,7 @@ libs-y += arch/mips/lib/ machine-$(CONFIG_ARCH_ATH79) += ath79 machine-$(CONFIG_ARCH_BMIPS) += bmips machine-$(CONFIG_MACH_PIC32) += pic32 +machine-$(CONFIG_ARCH_MT7620) += mt7620 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y)) libs-y += $(machdirs) diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index 6ca0916c06..1d21b2324a 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -84,25 +84,14 @@ ENTRY(_start) b reset mtc0 zero, CP0_COUNT # clear cp0 count for most accurate boot timing -#if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG) +#if defined(CONFIG_MIPS_INSERT_BOOT_CONFIG) /* - * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to - * access external NOR flashes. If the board boots from NOR flash the - * internal BootROM does a blind read at address 0xB0000010 to read the - * initial configuration for that EBU in order to access the flash - * device with correct parameters. This config option is board-specific. + * Store some board-specific boot configuration. This is used by some + * MIPS systems like Malta. */ .org 0x10 - .word CONFIG_SYS_XWAY_EBU_BOOTCFG - .word 0x0 -#endif -#if defined(CONFIG_MALTA) - /* - * Linux expects the Board ID here. - */ - .org 0x10 - .word 0x00000420 # 0x420 (Malta Board with CoreLV) - .word 0x00000000 + .word CONFIG_MIPS_BOOT_CONFIG_WORD0 + .word CONFIG_MIPS_BOOT_CONFIG_WORD1 #endif #if defined(CONFIG_ROM_EXCEPTION_VECTORS) diff --git a/arch/mips/dts/brcm,bcm6838.dtsi b/arch/mips/dts/brcm,bcm6838.dtsi index d365d0f2ce..1018f9ee49 100644 --- a/arch/mips/dts/brcm,bcm6838.dtsi +++ b/arch/mips/dts/brcm,bcm6838.dtsi @@ -55,6 +55,18 @@ u-boot,dm-pre-reloc; }; + gpio_test_port: syscon@14e00294 { + compatible = "syscon"; + reg = <0x14e00294 0x1c>; + }; + + pinctrl: pinctrl { + compatible = "brcm,bcm6838-pinctrl"; + regmap = <&gpio_test_port>; + brcm,pins-count = <74>; + brcm,functions-count = <8>; + }; + uart0: serial@14e00500 { compatible = "brcm,bcm6345-uart"; reg = <0x14e00500 0x18>; diff --git a/arch/mips/dts/gardena-smart-gateway-mt7688.dts b/arch/mips/dts/gardena-smart-gateway-mt7688.dts new file mode 100644 index 0000000000..ee99c3d17c --- /dev/null +++ b/arch/mips/dts/gardena-smart-gateway-mt7688.dts @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +/dts-v1/; + +#include "mt7628a.dtsi" + +/ { + compatible = "gardena,smart-gateway-mt7688", "ralink,mt7628a-soc"; + model = "Gardena smart-Gateway-MT7688"; + + aliases { + serial0 = &uart0; + spi0 = &spi0; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x08000000>; + }; + + chosen { + bootargs = "console=ttyS0,57600"; + stdout-path = &uart0; + }; +}; + +&uart0 { + status = "okay"; + clock-frequency = <40000000>; +}; + +&spi0 { + status = "okay"; + num-cs = <2>; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-flash", "jedec,spi-nor"; + spi-max-frequency = <40000000>; + reg = <0>; + }; + + spi-nand@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + spi-max-frequency = <40000000>; + reg = <1>; + }; +}; diff --git a/arch/mips/dts/linkit-smart-7688.dts b/arch/mips/dts/linkit-smart-7688.dts new file mode 100644 index 0000000000..df4bf907c6 --- /dev/null +++ b/arch/mips/dts/linkit-smart-7688.dts @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +/dts-v1/; + +#include "mt7628a.dtsi" + +/ { + compatible = "seeed,linkit-smart-7688", "ralink,mt7628a-soc"; + model = "LinkIt-Smart-7688"; + + aliases { + serial0 = &uart2; + spi0 = &spi0; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x08000000>; + }; + + chosen { + bootargs = "console=ttyS0,57600"; + stdout-path = &uart2; + }; +}; + +&uart2 { + status = "okay"; + clock-frequency = <40000000>; +}; + +&spi0 { + status = "okay"; + num-cs = <2>; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-flash", "jedec,spi-nor"; + spi-max-frequency = <25000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/dts/mt7628a.dtsi b/arch/mips/dts/mt7628a.dtsi new file mode 100644 index 0000000000..c14259b170 --- /dev/null +++ b/arch/mips/dts/mt7628a.dtsi @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ralink,mt7628a-soc"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "mti,mips24KEc"; + device_type = "cpu"; + reg = <0>; + }; + }; + + resetc: reset-controller { + compatible = "ralink,rt2880-reset"; + #reset-cells = <1>; + }; + + cpuintc: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + palmbus@10000000 { + compatible = "palmbus", "simple-bus"; + reg = <0x10000000 0x200000>; + ranges = <0x0 0x10000000 0x1FFFFF>; + + #address-cells = <1>; + #size-cells = <1>; + + sysc: system-controller@0 { + compatible = "ralink,mt7620a-sysc", "syscon"; + reg = <0x0 0x100>; + }; + + syscon-reboot { + compatible = "syscon-reboot"; + regmap = <&sysc>; + offset = <0x34>; + mask = <0x1>; + }; + + intc: interrupt-controller@200 { + compatible = "ralink,rt2880-intc"; + reg = <0x200 0x100>; + + interrupt-controller; + #interrupt-cells = <1>; + + resets = <&resetc 9>; + reset-names = "intc"; + + interrupt-parent = <&cpuintc>; + interrupts = <2>; + + ralink,intc-registers = <0x9c 0xa0 + 0x6c 0xa4 + 0x80 0x78>; + }; + + memory-controller@300 { + compatible = "ralink,mt7620a-memc"; + reg = <0x300 0x100>; + }; + + spi0: spi@b00 { + compatible = "ralink,mt7621-spi"; + reg = <0xb00 0x40>; + #address-cells = <1>; + #size-cells = <0>; + + clock-frequency = <200000000>; + }; + + uart0: uartlite@c00 { + compatible = "ns16550a"; + reg = <0xc00 0x100>; + + resets = <&resetc 12>; + reset-names = "uart0"; + + interrupt-parent = <&intc>; + interrupts = <20>; + + reg-shift = <2>; + }; + + uart1: uart1@d00 { + compatible = "ns16550a"; + reg = <0xd00 0x100>; + + resets = <&resetc 19>; + reset-names = "uart1"; + + interrupt-parent = <&intc>; + interrupts = <21>; + + reg-shift = <2>; + }; + + uart2: uart2@e00 { + compatible = "ns16550a"; + reg = <0xe00 0x100>; + + resets = <&resetc 20>; + reset-names = "uart2"; + + interrupt-parent = <&intc>; + interrupts = <22>; + + reg-shift = <2>; + }; + }; + + usb_phy: usb-phy@10120000 { + compatible = "mediatek,mt7628-usbphy"; + reg = <0x10120000 0x1000>; + + #phy-cells = <0>; + + ralink,sysctl = <&sysc>; + resets = <&resetc 22 &resetc 25>; + reset-names = "host", "device"; + }; + + ehci@101c0000 { + compatible = "generic-ehci"; + reg = <0x101c0000 0x1000>; + + phys = <&usb_phy>; + phy-names = "usb"; + + interrupt-parent = <&intc>; + interrupts = <18>; + }; +}; diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h new file mode 100644 index 0000000000..c4f08b7820 --- /dev/null +++ b/arch/mips/include/asm/atomic.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2016 Cadence Design Systems Inc. + */ + +#ifndef _MIPS_ATOMIC_H +#define _MIPS_ATOMIC_H + +#include <asm/system.h> +#include <asm-generic/atomic.h> + +#endif diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c index 1d14fc487e..d56fd1e0f4 100644 --- a/arch/mips/lib/cache.c +++ b/arch/mips/lib/cache.c @@ -175,3 +175,23 @@ void invalidate_dcache_range(ulong start_addr, ulong stop) /* ensure cache ops complete before any further memory accesses */ sync(); } + +int dcache_status(void) +{ + unsigned int cca = read_c0_config() & CONF_CM_CMASK; + return cca != CONF_CM_UNCACHED; +} + +void dcache_enable(void) +{ + puts("Not supported!\n"); +} + +void dcache_disable(void) +{ + /* change CCA to uncached */ + change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + + /* ensure the pipeline doesn't contain now-invalid instructions */ + instruction_hazard_barrier(); +} diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S index b209f23f0a..cfad1d9c8a 100644 --- a/arch/mips/lib/cache_init.S +++ b/arch/mips/lib/cache_init.S @@ -14,12 +14,6 @@ #include <asm/cacheops.h> #include <asm/cm.h> -#ifndef CONFIG_SYS_MIPS_CACHE_MODE -#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT -#endif - -#define INDEX_BASE CKSEG0 - .macro f_fill64 dst, offset, val LONG_S \val, (\offset + 0 * LONGSIZE)(\dst) LONG_S \val, (\offset + 1 * LONGSIZE)(\dst) @@ -84,6 +78,7 @@ 10: .set pop .endm + /* * mips_cache_reset - low level initialisation of the primary caches * @@ -255,7 +250,7 @@ l2_probe_done: /* * Now clear that much memory starting from zero. */ - PTR_LI a0, CKSEG1 + PTR_LI a0, CKSEG1ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) PTR_ADDU a1, a0, v0 2: PTR_ADDIU a0, 64 f_fill64 a0, -64, zero @@ -271,7 +266,7 @@ l2_probe_done: bnez R_L2_BYPASSED, l1_init l2_init: - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) PTR_ADDU t1, t0, R_L2_SIZE 1: cache INDEX_STORE_TAG_SD, 0(t0) PTR_ADDU t0, t0, R_L2_LINE @@ -307,48 +302,50 @@ l1_init: * Initialize the I-cache first, */ blez R_IC_SIZE, 1f - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) PTR_ADDU t1, t0, R_IC_SIZE /* clear tag to invalidate */ cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* fill once, so data field parity is correct */ - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) cache_loop t0, t1, R_IC_LINE, FILL /* invalidate again - prudent but not strictly neccessary */ - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I #endif - - /* Enable use of the I-cache by setting Config.K0 */ sync - mfc0 t0, CP0_CONFIG - li t1, CONFIG_SYS_MIPS_CACHE_MODE -#if __mips_isa_rev >= 2 - ins t0, t1, 0, 3 -#else - ori t0, t0, CONF_CM_CMASK - xori t0, t0, CONF_CM_CMASK + + /* + * Enable use of the I-cache by setting Config.K0. The code for this + * must be executed from KSEG1. Jump from KSEG0 to KSEG1 to do this. + * Jump back to KSEG0 after caches are enabled and insert an + * instruction hazard barrier. + */ + PTR_LA t0, change_k0_cca + li t1, CPHYSADDR(~0) + and t0, t0, t1 + PTR_LI t1, CKSEG1 or t0, t0, t1 -#endif - mtc0 t0, CP0_CONFIG + li a0, CONF_CM_CACHABLE_NONCOHERENT + jalr.hb t0 /* * then initialize D-cache. */ 1: blez R_DC_SIZE, 3f - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) PTR_ADDU t1, t0, R_DC_SIZE /* clear all tags */ cache_loop t0, t1, R_DC_LINE, INDEX_STORE_TAG_D #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* load from each line (in cached space) */ - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) 2: LONG_L zero, 0(t0) PTR_ADDU t0, R_DC_LINE bne t0, t1, 2b /* clear all tags */ - PTR_LI t0, INDEX_BASE + PTR_LI t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE) cache_loop t0, t1, R_DC_LINE, INDEX_STORE_TAG_D #endif 3: @@ -391,16 +388,9 @@ l2_unbypass: beqz t0, 2f /* Change Config.K0 to a coherent CCA */ - mfc0 t0, CP0_CONFIG - li t1, CONF_CM_CACHABLE_COW -#if __mips_isa_rev >= 2 - ins t0, t1, 0, 3 -#else - ori t0, t0, CONF_CM_CMASK - xori t0, t0, CONF_CM_CMASK - or t0, t0, t1 -#endif - mtc0 t0, CP0_CONFIG + PTR_LA t0, change_k0_cca + li a0, CONF_CM_CACHABLE_COW + jalr t0 /* * Join the coherent domain such that the caches of this core are kept @@ -421,51 +411,19 @@ l2_unbypass: return: /* Ensure all cache operations complete before returning */ sync - jr ra + jr R_RETURN END(mips_cache_reset) -/* - * dcache_status - get cache status - * - * RETURNS: 0 - cache disabled; 1 - cache enabled - * - */ -LEAF(dcache_status) - mfc0 t0, CP0_CONFIG - li t1, CONF_CM_UNCACHED - andi t0, t0, CONF_CM_CMASK - move v0, zero - beq t0, t1, 2f - li v0, 1 -2: jr ra - END(dcache_status) - -/* - * dcache_disable - disable cache - * - * RETURNS: N/A - * - */ -LEAF(dcache_disable) - mfc0 t0, CP0_CONFIG - li t1, -8 - and t0, t0, t1 - ori t0, t0, CONF_CM_UNCACHED - mtc0 t0, CP0_CONFIG - jr ra - END(dcache_disable) +LEAF(change_k0_cca) + mfc0 t0, CP0_CONFIG +#if __mips_isa_rev >= 2 + ins t0, a0, 0, 3 +#else + xor a0, a0, t0 + andi a0, a0, CONF_CM_CMASK + xor a0, a0, t0 +#endif + mtc0 a0, CP0_CONFIG -/* - * dcache_enable - enable cache - * - * RETURNS: N/A - * - */ -LEAF(dcache_enable) - mfc0 t0, CP0_CONFIG - ori t0, CONF_CM_CMASK - xori t0, CONF_CM_CMASK - ori t0, CONFIG_SYS_MIPS_CACHE_MODE - mtc0 t0, CP0_CONFIG - jr ra - END(dcache_enable) + jr.hb ra + END(change_k0_cca) diff --git a/arch/mips/mach-mt7620/Kconfig b/arch/mips/mach-mt7620/Kconfig new file mode 100644 index 0000000000..13a7bd2cc0 --- /dev/null +++ b/arch/mips/mach-mt7620/Kconfig @@ -0,0 +1,135 @@ +menu "MediaTek MIPS platforms" + depends on ARCH_MT7620 + +config SYS_MALLOC_F_LEN + default 0x1000 + +config SYS_SOC + default "mt7620" if SOC_MT7620 + +choice + prompt "MediaTek MIPS SoC select" + +config SOC_MT7620 + bool "MT7620/8" + select MIPS_L1_CACHE_SHIFT_5 + help + This supports MediaTek MIPS MT7620 family. + +endchoice + +choice + prompt "Board select" + +config BOARD_GARDENA_SMART_GATEWAY_MT7688 + bool "Gardena Smart Gateway" + depends on SOC_MT7620 + select SUPPORTS_BOOT_RAM + help + Gardena Smart Gateway boards have a MT7688 SoC with 128 MiB of RAM + and 8 MiB of flash (SPI NOR) and additional SPI NAND storage. + +config BOARD_LINKIT_SMART_7688 + bool "LinkIt Smart 7688" + depends on SOC_MT7620 + select SUPPORTS_BOOT_RAM + help + Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM + and 32 MiB of flash (SPI). + Between its different peripherals there's an integrated switch with 4 + ethernet ports, 1 USB port, 1 UART, GPIO buttons and LEDs, and + a MT7688 (PCIe). + +endchoice + +choice + prompt "Boot mode" + +config BOOT_RAM + bool "RAM boot" + depends on SUPPORTS_BOOT_RAM + help + This builds an image that is linked to a RAM address. It can be used + for booting from CFE via TFTP using an ELF image, but it can also be + booted from RAM by other bootloaders using a BIN image. + +config BOOT_ROM + bool "ROM boot" + depends on SUPPORTS_BOOT_RAM + help + This builds an image that is linked to a ROM address. It can be + used as main bootloader image which is programmed onto the onboard + flash storage (SPI NOR). + +endchoice + +choice + prompt "DDR2 size" + +config ONBOARD_DDR2_SIZE_256MBIT + bool "256MBit (32MByte) total size" + depends on BOOT_ROM + help + Use 256MBit (32MByte) of DDR total size + +config ONBOARD_DDR2_SIZE_512MBIT + bool "512MBit (64MByte) total size" + depends on BOOT_ROM + help + Use 512MBit (64MByte) of DDR total size + +config ONBOARD_DDR2_SIZE_1024MBIT + bool "1024MBit (128MByte) total size" + depends on BOOT_ROM + help + Use 1024MBit (128MByte) of DDR total size + +config ONBOARD_DDR2_SIZE_2048MBIT + bool "2048MBit (256MByte) total size" + depends on BOOT_ROM + help + Use 2048MBit (256MByte) of DDR total size + +endchoice + +choice + prompt "DDR2 chip width" + +config ONBOARD_DDR2_CHIP_WIDTH_8BIT + bool "8bit DDR chip width" + depends on BOOT_ROM + help + Use DDR chips with 8bit width + +config ONBOARD_DDR2_CHIP_WIDTH_16BIT + bool "16bit DDR chip width" + depends on BOOT_ROM + help + Use DDR chips with 16bit width + +endchoice + +choice + prompt "DDR2 bus width" + +config ONBOARD_DDR2_BUS_WIDTH_16BIT + bool "16bit DDR bus width" + depends on BOOT_ROM + help + Use 16bit DDR bus width + +config ONBOARD_DDR2_BUS_WIDTH_32BIT + bool "32bit DDR bus width" + depends on BOOT_ROM + help + Use 32bit DDR bus width + +endchoice + +config SUPPORTS_BOOT_RAM + bool + +source "board/gardena/smart-gateway-mt7688/Kconfig" +source "board/seeed/linkit-smart-7688/Kconfig" + +endmenu diff --git a/arch/mips/mach-mt7620/Makefile b/arch/mips/mach-mt7620/Makefile new file mode 100644 index 0000000000..1f3e65e8a5 --- /dev/null +++ b/arch/mips/mach-mt7620/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += cpu.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +obj-y += ddr_calibrate.o +obj-y += lowlevel_init.o +endif diff --git a/arch/mips/mach-mt7620/cpu.c b/arch/mips/mach-mt7620/cpu.c new file mode 100644 index 0000000000..457f09f32c --- /dev/null +++ b/arch/mips/mach-mt7620/cpu.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +#include <common.h> +#include <dm.h> +#include <ram.h> +#include <asm/io.h> +#include <linux/io.h> +#include <linux/sizes.h> +#include "mt76xx.h" + +#define STR_LEN 6 + +#ifdef CONFIG_BOOT_ROM +int mach_cpu_init(void) +{ + ddr_calibrate(); + + return 0; +} +#endif + +int dram_init(void) +{ + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M); + + return 0; +} + +int print_cpuinfo(void) +{ + static const char * const boot_str[] = { "PLL (3-Byte SPI Addr)", + "PLL (4-Byte SPI Addr)", + "XTAL (3-Byte SPI Addr)", + "XTAL (4-Byte SPI Addr)" }; + const void *blob = gd->fdt_blob; + void __iomem *sysc_base; + char buf[STR_LEN + 1]; + fdt_addr_t base; + fdt_size_t size; + char *str; + int node; + u32 val; + + /* Get system controller base address */ + node = fdt_node_offset_by_compatible(blob, -1, "ralink,mt7620a-sysc"); + if (node < 0) + return -FDT_ERR_NOTFOUND; + + base = fdtdec_get_addr_size_auto_noparent(blob, node, "reg", + 0, &size, true); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + sysc_base = ioremap_nocache(base, size); + + str = (char *)sysc_base + MT76XX_CHIPID_OFFS; + snprintf(buf, STR_LEN + 1, "%s", str); + val = readl(sysc_base + MT76XX_CHIP_REV_ID_OFFS); + printf("CPU: %-*s Rev %ld.%ld - ", STR_LEN, buf, + (val & GENMASK(11, 8)) >> 8, val & GENMASK(3, 0)); + + val = (readl(sysc_base + MT76XX_SYSCFG0_OFFS) & GENMASK(3, 1)) >> 1; + printf("Boot from %s\n", boot_str[val]); + + return 0; +} diff --git a/arch/mips/mach-mt7620/ddr_calibrate.c b/arch/mips/mach-mt7620/ddr_calibrate.c new file mode 100644 index 0000000000..75763c4528 --- /dev/null +++ b/arch/mips/mach-mt7620/ddr_calibrate.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + * + * This code is mostly based on the code extracted from this MediaTek + * github repository: + * + * https://github.com/MediaTek-Labs/linkit-smart-uboot.git + * + * I was not able to find a specific license or other developers + * copyrights here, so I can't add them here. + * + * Most functions in this file are copied from the MediaTek U-Boot + * repository. Without any documentation, it was impossible to really + * implement this differently. So its mostly a cleaned-up version of + * the original code, with only support for the MT7628 / MT7688 SoC. + */ + +#include <common.h> +#include <linux/io.h> +#include <asm/cacheops.h> +#include <asm/io.h> +#include "mt76xx.h" + +#define NUM_OF_CACHELINE 128 +#define MIN_START 6 +#define MIN_FINE_START 0xf +#define MAX_START 7 +#define MAX_FINE_START 0x0 + +#define CPU_FRAC_DIV 1 + +#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT) +#define DRAM_BUTTOM 0x02000000 +#endif +#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT) +#define DRAM_BUTTOM 0x04000000 +#endif +#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT) +#define DRAM_BUTTOM 0x08000000 +#endif +#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT) +#define DRAM_BUTTOM 0x10000000 +#endif + +static inline void cal_memcpy(void *src, void *dst, u32 size) +{ + u8 *psrc = (u8 *)src; + u8 *pdst = (u8 *)dst; + int i; + + for (i = 0; i < size; i++, psrc++, pdst++) + *pdst = *psrc; +} + +static inline void cal_memset(void *src, u8 pat, u32 size) +{ + u8 *psrc = (u8 *)src; + int i; + + for (i = 0; i < size; i++, psrc++) + *psrc = pat; +} + +#define pref_op(hint, addr) \ + __asm__ __volatile__( \ + ".set push\n" \ + ".set noreorder\n" \ + "pref %0, %1\n" \ + ".set pop\n" \ + : \ + : "i" (hint), "R" (*(u8 *)(addr))) + +static inline void cal_patgen(u32 start_addr, u32 size, u32 bias) +{ + u32 *addr = (u32 *)start_addr; + int i; + + for (i = 0; i < size; i++) + addr[i] = start_addr + i + bias; +} + +static inline int test_loop(int k, int dqs, u32 test_dqs, u32 *coarse_dqs, + u32 offs, u32 pat, u32 val) +{ + u32 nc_addr; + u32 *c_addr; + int i; + + for (nc_addr = 0xa0000000; + nc_addr < (0xa0000000 + DRAM_BUTTOM - NUM_OF_CACHELINE * 32); + nc_addr += (DRAM_BUTTOM >> 6) + offs) { + writel(0x00007474, (void *)MT76XX_MEMCTRL_BASE + 0x64); + wmb(); /* Make sure store if finished */ + + c_addr = (u32 *)(nc_addr & 0xdfffffff); + cal_memset(((u8 *)c_addr), 0x1F, NUM_OF_CACHELINE * 32); + cal_patgen(nc_addr, NUM_OF_CACHELINE * 8, pat); + + if (dqs > 0) + writel(0x00000074 | + (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 12) | + (((k == 0) ? val : test_dqs) << 8), + (void *)MT76XX_MEMCTRL_BASE + 0x64); + else + writel(0x00007400 | + (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 4) | + (((k == 0) ? val : test_dqs) << 0), + (void *)MT76XX_MEMCTRL_BASE + 0x64); + wmb(); /* Make sure store if finished */ + + invalidate_dcache_range((u32)c_addr, + (u32)c_addr + + NUM_OF_CACHELINE * 32); + wmb(); /* Make sure store if finished */ + + for (i = 0; i < NUM_OF_CACHELINE * 8; i++) { + if (i % 8 == 0) + pref_op(0, &c_addr[i]); + } + + for (i = 0; i < NUM_OF_CACHELINE * 8; i++) { + if (c_addr[i] != nc_addr + i + pat) + return -1; + } + } + + return 0; +} + +void ddr_calibrate(void) +{ + u32 min_coarse_dqs[2]; + u32 max_coarse_dqs[2]; + u32 min_fine_dqs[2]; + u32 max_fine_dqs[2]; + u32 coarse_dqs[2]; + u32 fine_dqs[2]; + int reg = 0, ddr_cfg2_reg; + int flag; + int i, k; + int dqs = 0; + u32 min_coarse_dqs_bnd, min_fine_dqs_bnd, coarse_dqs_dll, fine_dqs_dll; + u32 val; + u32 fdiv = 0, frac = 0; + + /* Setup clock to run at full speed */ + val = readl((void *)MT76XX_DYN_CFG0_REG); + fdiv = (u32)((val >> 8) & 0x0F); + if (CPU_FRAC_DIV < 1 || CPU_FRAC_DIV > 10) + frac = val & 0x0f; + else + frac = CPU_FRAC_DIV; + + while (frac < fdiv) { + val = readl((void *)MT76XX_DYN_CFG0_REG); + fdiv = (val >> 8) & 0x0f; + fdiv--; + val &= ~(0x0f << 8); + val |= (fdiv << 8); + writel(val, (void *)MT76XX_DYN_CFG0_REG); + udelay(500); + val = readl((void *)MT76XX_DYN_CFG0_REG); + fdiv = (val >> 8) & 0x0f; + } + + clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4)); + ddr_cfg2_reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x48); + clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x48, + (0x3 << 28) | (0x3 << 26)); + + min_coarse_dqs[0] = MIN_START; + min_coarse_dqs[1] = MIN_START; + min_fine_dqs[0] = MIN_FINE_START; + min_fine_dqs[1] = MIN_FINE_START; + max_coarse_dqs[0] = MAX_START; + max_coarse_dqs[1] = MAX_START; + max_fine_dqs[0] = MAX_FINE_START; + max_fine_dqs[1] = MAX_FINE_START; + dqs = 0; + + /* Add by KP, DQS MIN boundary */ + reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x20); + coarse_dqs_dll = (reg & 0xf00) >> 8; + fine_dqs_dll = (reg & 0xf0) >> 4; + if (coarse_dqs_dll <= 8) + min_coarse_dqs_bnd = 8 - coarse_dqs_dll; + else + min_coarse_dqs_bnd = 0; + + if (fine_dqs_dll <= 8) + min_fine_dqs_bnd = 8 - fine_dqs_dll; + else + min_fine_dqs_bnd = 0; + /* DQS MIN boundary */ + +DQS_CAL: + + for (k = 0; k < 2; k++) { + u32 test_dqs; + + if (k == 0) + test_dqs = MAX_START; + else + test_dqs = MAX_FINE_START; + + do { + flag = test_loop(k, dqs, test_dqs, max_coarse_dqs, + 0x400, 0x3, 0xf); + if (flag == -1) + break; + + test_dqs++; + } while (test_dqs <= 0xf); + + if (k == 0) { + max_coarse_dqs[dqs] = test_dqs; + } else { + test_dqs--; + + if (test_dqs == MAX_FINE_START - 1) { + max_coarse_dqs[dqs]--; + max_fine_dqs[dqs] = 0xf; + } else { + max_fine_dqs[dqs] = test_dqs; + } + } + } + + for (k = 0; k < 2; k++) { + u32 test_dqs; + + if (k == 0) + test_dqs = MIN_START; + else + test_dqs = MIN_FINE_START; + + do { + flag = test_loop(k, dqs, test_dqs, min_coarse_dqs, + 0x480, 0x1, 0x0); + if (k == 0) { + if (flag == -1 || + test_dqs == min_coarse_dqs_bnd) + break; + + test_dqs--; + + if (test_dqs < min_coarse_dqs_bnd) + break; + } else { + if (flag == -1) { + test_dqs++; + break; + } else if (test_dqs == min_fine_dqs_bnd) { + break; + } + + test_dqs--; + + if (test_dqs < min_fine_dqs_bnd) + break; + } + } while (test_dqs >= 0); + + if (k == 0) { + min_coarse_dqs[dqs] = test_dqs; + } else { + if (test_dqs == MIN_FINE_START + 1) { + min_coarse_dqs[dqs]++; + min_fine_dqs[dqs] = 0x0; + } else { + min_fine_dqs[dqs] = test_dqs; + } + } + } + + if (dqs == 0) { + dqs = 1; + goto DQS_CAL; + } + + for (i = 0; i < 2; i++) { + u32 temp; + + coarse_dqs[i] = (max_coarse_dqs[i] + min_coarse_dqs[i]) >> 1; + temp = + (((max_coarse_dqs[i] + min_coarse_dqs[i]) % 2) * 4) + + ((max_fine_dqs[i] + min_fine_dqs[i]) >> 1); + if (temp >= 0x10) { + coarse_dqs[i]++; + fine_dqs[i] = (temp - 0x10) + 0x8; + } else { + fine_dqs[i] = temp; + } + } + reg = (coarse_dqs[1] << 12) | (fine_dqs[1] << 8) | + (coarse_dqs[0] << 4) | fine_dqs[0]; + + clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4)); + writel(reg, (void *)MT76XX_MEMCTRL_BASE + 0x64); + writel(ddr_cfg2_reg, (void *)MT76XX_MEMCTRL_BASE + 0x48); + setbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4)); + + for (i = 0; i < 2; i++) + debug("[%02X%02X%02X%02X]", min_coarse_dqs[i], + min_fine_dqs[i], max_coarse_dqs[i], max_fine_dqs[i]); + debug("\nDDR Calibration DQS reg = %08X\n", reg); +} diff --git a/arch/mips/mach-mt7620/lowlevel_init.S b/arch/mips/mach-mt7620/lowlevel_init.S new file mode 100644 index 0000000000..1a50f160fe --- /dev/null +++ b/arch/mips/mach-mt7620/lowlevel_init.S @@ -0,0 +1,322 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (c) 2018 Stefan Roese <sr@denx.de> + * + * This code is mostly based on the code extracted from this MediaTek + * github repository: + * + * https://github.com/MediaTek-Labs/linkit-smart-uboot.git + * + * I was not able to find a specific license or other developers + * copyrights here, so I can't add them here. + */ + +#include <config.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/asm.h> +#include "mt76xx.h" + +#ifndef BIT +#define BIT(nr) (1 << (nr)) +#endif + +#define DELAY_USEC(us) ((us) / 100) + +#define DDR_CFG1_CHIP_WIDTH_MASK (0x3 << 16) +#define DDR_CFG1_BUS_WIDTH_MASK (0x3 << 12) + +#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT) +#define DDR_CFG1_SIZE_VAL 0x222e2323 +#define DDR_CFG4_SIZE_VAL 7 +#endif +#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT) +#define DDR_CFG1_SIZE_VAL 0x22322323 +#define DDR_CFG4_SIZE_VAL 9 +#endif +#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT) +#define DDR_CFG1_SIZE_VAL 0x22362323 +#define DDR_CFG4_SIZE_VAL 9 +#endif +#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT) +#define DDR_CFG1_SIZE_VAL 0x223a2323 +#define DDR_CFG4_SIZE_VAL 9 +#endif + +#if defined(CONFIG_ONBOARD_DDR2_CHIP_WIDTH_8BIT) +#define DDR_CFG1_CHIP_WIDTH_VAL (0x1 << 16) +#endif +#if defined(CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT) +#define DDR_CFG1_CHIP_WIDTH_VAL (0x2 << 16) +#endif + +#if defined(CONFIG_ONBOARD_DDR2_BUS_WIDTH_16BIT) +#define DDR_CFG1_BUS_WIDTH_VAL (0x2 << 12) +#endif +#if defined(CONFIG_ONBOARD_DDR2_BUS_WIDTH_32BIT) +#define DDR_CFG1_BUS_WIDTH_VAL (0x3 << 12) +#endif + + .set noreorder + +LEAF(lowlevel_init) + + /* Load base addresses as physical addresses for later usage */ + li s0, CKSEG1ADDR(MT76XX_SYSCTL_BASE) + li s1, CKSEG1ADDR(MT76XX_MEMCTRL_BASE) + li s2, CKSEG1ADDR(MT76XX_RGCTRL_BASE) + + /* polling CPLL is ready */ + li t1, DELAY_USEC(1000000) + la t5, MT76XX_ROM_STATUS_REG +1: + lw t2, 0(t5) + andi t2, t2, 0x1 + bnez t2, CPLL_READY + subu t1, t1, 1 + bgtz t1, 1b + nop + la t0, MT76XX_CLKCFG0_REG + lw t3, 0(t0) + ori t3, t3, 0x1 + sw t3, 0(t0) + b CPLL_DONE + nop +CPLL_READY: + la t0, MT76XX_CLKCFG0_REG + lw t1, 0(t0) + li t2, ~0x0c + and t1, t1, t2 + ori t1, t1, 0xc + sw t1, 0(t0) + la t0, MT76XX_DYN_CFG0_REG + lw t3, 0(t0) + li t5, ~((0x0f << 8) | (0x0f << 0)) + and t3, t3, t5 + li t5, (10 << 8) | (1 << 0) + or t3, t3, t5 + sw t3, 0(t0) + la t0, MT76XX_CLKCFG0_REG + lw t3, 0(t0) + li t4, ~0x0F + and t3, t3, t4 + ori t3, t3, 0xc + sw t3, 0(t0) + lw t3, 0(t0) + ori t3, t3, 0x08 + sw t3, 0(t0) + +CPLL_DONE: + /* + * SDR and DDR initialization: delay 200us + */ + li t0, DELAY_USEC(200 + 40) + li t1, 0x1 +1: + sub t0, t0, t1 + bnez t0, 1b + nop + + /* set DRAM IO PAD for MT7628IC */ + /* DDR LDO Enable */ + lw t4, 0x100(s2) + li t2, BIT(31) + or t4, t4, t2 + sw t4, 0x100(s2) + lw t4, 0x10c(s2) + j LDO_1P8V + nop +LDO_1P8V: + li t2, ~BIT(6) + and t4, t4, t2 + sw t4, 0x10c(s2) + j DDRLDO_SOFT_START +LDO_2P5V: + /* suppose external DDR1 LDO 2.5V */ + li t2, BIT(6) + or t4, t4, t2 + sw t4, 0x10c(s2) + +DDRLDO_SOFT_START: + lw t2, 0x10c(s2) + li t3, BIT(16) + or t2, t2, t3 + sw t2, 0x10c(s2) + li t3, DELAY_USEC(250*50) +LDO_DELAY: + subu t3, t3, 1 + bnez t3, LDO_DELAY + nop + + lw t2, 0x10c(s2) + li t3, BIT(18) + or t2, t2, t3 + sw t2, 0x10c(s2) + +SET_RG_BUCK_FPWM: + lw t2, 0x104(s2) + ori t2, t2, BIT(10) + sw t2, 0x104(s2) + +DDR_PAD_CFG: + /* clean CLK PAD */ + lw t2, 0x704(s2) + li t8, 0xfffff0f0 + and t2, t2, t8 + /* clean CMD PAD */ + lw t3, 0x70c(s2) + li t8, 0xfffff0f0 + and t3, t3, t8 + /* clean DQ IPAD */ + lw t4, 0x710(s2) + li t8, 0xfffff8ff + and t4, t4, t8 + /* clean DQ OPAD */ + lw t5, 0x714(s2) + li t8, 0xfffff0f0 + and t5, t5, t8 + /* clean DQS IPAD */ + lw t6, 0x718(s2) + li t8, 0xfffff8ff + and t6, t6, t8 + /* clean DQS OPAD */ + lw t7, 0x71c(s2) + li t8, 0xfffff0f0 + and t7, t7, t8 + + lw t9, 0xc(s0) + srl t9, t9, 16 + andi t9, t9, 0x1 + bnez t9, MT7628_AN_DDR1_PAD +MT7628_KN_PAD: + li t8, 0x00000303 + or t2, t2, t8 + or t3, t3, t8 + or t5, t5, t8 + or t7, t7, t8 + li t8, 0x00000000 + or t4, t4, t8 + or t6, t6, t8 + j SET_PAD_CFG +MT7628_AN_DDR1_PAD: + lw t1, 0x10(s0) + andi t1, t1, 0x1 + beqz t1, MT7628_AN_DDR2_PAD + li t8, 0x00000c0c + or t2, t2, t8 + li t8, 0x00000202 + or t3, t3, t8 + li t8, 0x00000707 + or t5, t5, t8 + li t8, 0x00000c0c + or t7, t7, t8 + li t8, 0x00000000 + or t4, t4, t8 + or t6, t6, t8 + j SET_PAD_CFG +MT7628_AN_DDR2_PAD: + li t8, 0x00000c0c + or t2, t2, t8 + li t8, 0x00000202 + or t3, t3, t8 + li t8, 0x00000404 + or t5, t5, t8 + li t8, 0x00000c0c + or t7, t7, t8 + li t8, 0x00000000 /* ODT off */ + or t4, t4, t8 + or t6, t6, t8 + +SET_PAD_CFG: + sw t2, 0x704(s2) + sw t3, 0x70c(s2) + sw t4, 0x710(s2) + sw t5, 0x714(s2) + sw t6, 0x718(s2) + sw t7, 0x71c(s2) + + /* + * DDR initialization: reset pin to 0 + */ + lw t2, 0x34(s0) + and t2, ~BIT(10) + sw t2, 0x34(s0) + nop + + /* + * DDR initialization: wait til reg DDR_CFG1 bit 21 equal to 1 (ready) + */ +DDR_READY: + li t1, DDR_CFG1_REG + lw t0, 0(t1) + nop + and t2, t0, BIT(21) + beqz t2, DDR_READY + nop + + /* + * DDR initialization + * + * Only DDR2 supported right now. DDR2 support can be added, once + * boards using it will get added to mainline U-Boot. + */ + li t1, DDR_CFG2_REG + lw t0, 0(t1) + nop + and t0, ~BIT(30) + and t0, ~(7 << 4) + or t0, (4 << 4) + or t0, BIT(30) + or t0, BIT(11) + sw t0, 0(t1) + nop + + li t1, DDR_CFG3_REG + lw t2, 0(t1) + /* Disable ODT; reference board ok, ev board fail */ + and t2, ~BIT(6) + or t2, BIT(2) + li t0, DDR_CFG4_REG + lw t1, 0(t0) + li t2, ~(0x01f | 0x0f0) + and t1, t1, t2 + ori t1, t1, DDR_CFG4_SIZE_VAL + sw t1, 0(t0) + nop + + /* + * DDR initialization: config size and width on reg DDR_CFG1 + */ + li t6, DDR_CFG1_SIZE_VAL + + and t6, ~DDR_CFG1_CHIP_WIDTH_MASK + or t6, DDR_CFG1_CHIP_WIDTH_VAL + + /* CONFIG DDR_CFG1[13:12] about TOTAL WIDTH */ + and t6, ~DDR_CFG1_BUS_WIDTH_MASK + or t6, DDR_CFG1_BUS_WIDTH_VAL + + li t5, DDR_CFG1_REG + sw t6, 0(t5) + nop + + /* + * DDR: enable self auto refresh for power saving + * enable it by default for both RAM and ROM version (for CoC) + */ + lw t1, 0x14(s1) + nop + and t1, 0xff000000 + or t1, 0x01 + sw t1, 0x14(s1) + nop + lw t1, 0x10(s1) + nop + or t1, 0x10 + sw t1, 0x10(s1) + nop + + jr ra + nop + END(lowlevel_init) diff --git a/arch/mips/mach-mt7620/mt76xx.h b/arch/mips/mach-mt7620/mt76xx.h new file mode 100644 index 0000000000..17473ea8f1 --- /dev/null +++ b/arch/mips/mach-mt7620/mt76xx.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +#ifndef __MT76XX_H +#define __MT76XX_H + +#define MT76XX_SYSCTL_BASE 0x10000000 + +#define MT76XX_CHIPID_OFFS 0x00 +#define MT76XX_CHIP_REV_ID_OFFS 0x0c +#define MT76XX_SYSCFG0_OFFS 0x10 + +#define MT76XX_MEMCTRL_BASE (MT76XX_SYSCTL_BASE + 0x0300) +#define MT76XX_RGCTRL_BASE (MT76XX_SYSCTL_BASE + 0x1000) + +#define MT76XX_ROM_STATUS_REG (MT76XX_SYSCTL_BASE + 0x0028) +#define MT76XX_CLKCFG0_REG (MT76XX_SYSCTL_BASE + 0x002c) +#define MT76XX_DYN_CFG0_REG (MT76XX_SYSCTL_BASE + 0x0440) + +#define DDR_CFG1_REG (MT76XX_MEMCTRL_BASE + 0x44) +#define DDR_CFG2_REG (MT76XX_MEMCTRL_BASE + 0x48) +#define DDR_CFG3_REG (MT76XX_MEMCTRL_BASE + 0x4c) +#define DDR_CFG4_REG (MT76XX_MEMCTRL_BASE + 0x50) + +#ifndef __ASSEMBLY__ +/* Prototypes */ +void ddr_calibrate(void); +#endif + +#endif diff --git a/arch/nds32/config.mk b/arch/nds32/config.mk index cb3d8b35b5..c5520fd8d8 100644 --- a/arch/nds32/config.mk +++ b/arch/nds32/config.mk @@ -15,7 +15,7 @@ endif CONFIG_STANDALONE_LOAD_ADDR = 0x300000 \ -T $(srctree)/examples/standalone/nds32.lds -PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -mrelax +PLATFORM_RELFLAGS += -fno-common -mrelax PLATFORM_RELFLAGS += -gdwarf-2 PLATFORM_CPPFLAGS += -D__nds32__ -G0 -ffixed-10 -fpie diff --git a/arch/riscv/config.mk b/arch/riscv/config.mk index 219e66683d..c0b3858edd 100644 --- a/arch/riscv/config.mk +++ b/arch/riscv/config.mk @@ -31,7 +31,7 @@ CONFIG_STANDALONE_LOAD_ADDR = 0x00000000 \ -T $(srctree)/examples/standalone/riscv.lds PLATFORM_CPPFLAGS += -ffixed-gp -fpic -PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -gdwarf-2 -ffunction-sections +PLATFORM_RELFLAGS += -fno-common -gdwarf-2 -ffunction-sections LDFLAGS_u-boot += --gc-sections -static -pie EFI_CRT0 := crt0_riscv_efi.o diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index cde0b055a6..6098945049 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -57,14 +57,104 @@ int cleanup_before_linux_select(int flags) return 0; } +/** + * is_in_sandbox_mem() - Checks if a pointer is within sandbox's emulated DRAM + * + * This provides a way to check if a pointer is owned by sandbox (and is within + * its RAM) or not. Sometimes pointers come from a test which conceptually runs + * output sandbox, potentially with direct access to the C-library malloc() + * function, or the sandbox stack (which is not actually within the emulated + * DRAM. + * + * Such pointers obviously cannot be mapped into sandbox's DRAM, so we must + * detect them an process them separately, by recording a mapping to a tag, + * which we can use to map back to the pointer later. + * + * @ptr: Pointer to check + * @return true if this is within sandbox emulated DRAM, false if not + */ +static bool is_in_sandbox_mem(const void *ptr) +{ + return (const uint8_t *)ptr >= gd->arch.ram_buf && + (const uint8_t *)ptr < gd->arch.ram_buf + gd->ram_size; +} + +/** + * phys_to_virt() - Converts a sandbox RAM address to a pointer + * + * Sandbox uses U-Boot addresses from 0 to the size of DRAM. These index into + * the emulated DRAM buffer used by sandbox. This function converts such an + * address to a pointer into this buffer, which can be used to access the + * memory. + * + * If the address is outside this range, it is assumed to be a tag + */ void *phys_to_virt(phys_addr_t paddr) { - return (void *)(gd->arch.ram_buf + paddr); + struct sandbox_mapmem_entry *mentry; + struct sandbox_state *state; + + /* If the address is within emulated DRAM, calculate the value */ + if (paddr < gd->ram_size) + return (void *)(gd->arch.ram_buf + paddr); + + /* + * Otherwise search out list of tags for the correct pointer previously + * created by map_to_sysmem() + */ + state = state_get_current(); + list_for_each_entry(mentry, &state->mapmem_head, sibling_node) { + if (mentry->tag == paddr) { + printf("%s: Used map from %lx to %p\n", __func__, + (ulong)paddr, mentry->ptr); + return mentry->ptr; + } + } + + printf("%s: Cannot map sandbox address %lx (SDRAM from 0 to %lx)\n", + __func__, (ulong)paddr, (ulong)gd->ram_size); + os_abort(); + + /* Not reached */ + return NULL; +} + +struct sandbox_mapmem_entry *find_tag(const void *ptr) +{ + struct sandbox_mapmem_entry *mentry; + struct sandbox_state *state = state_get_current(); + + list_for_each_entry(mentry, &state->mapmem_head, sibling_node) { + if (mentry->ptr == ptr) { + debug("%s: Used map from %p to %lx\n", __func__, ptr, + mentry->tag); + return mentry; + } + } + return NULL; } -phys_addr_t virt_to_phys(void *vaddr) +phys_addr_t virt_to_phys(void *ptr) { - return (phys_addr_t)((uint8_t *)vaddr - gd->arch.ram_buf); + struct sandbox_mapmem_entry *mentry; + + /* + * If it is in emulated RAM, don't bother looking for a tag. Just + * calculate the pointer using the provides offset into the RAM buffer. + */ + if (is_in_sandbox_mem(ptr)) + return (phys_addr_t)((uint8_t *)ptr - gd->arch.ram_buf); + + mentry = find_tag(ptr); + if (!mentry) { + /* Abort so that gdb can be used here */ + printf("%s: Cannot map sandbox address %p (SDRAM from 0 to %lx)\n", + __func__, ptr, (ulong)gd->ram_size); + os_abort(); + } + printf("%s: Used map from %p to %lx\n", __func__, ptr, mentry->tag); + + return mentry->tag; } void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) @@ -87,24 +177,57 @@ void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) return phys_to_virt(paddr); } -void unmap_physmem(const void *vaddr, unsigned long flags) +void unmap_physmem(const void *ptr, unsigned long flags) { #ifdef CONFIG_PCI if (map_dev) { - pci_unmap_physmem(vaddr, map_len, map_dev); + pci_unmap_physmem(ptr, map_len, map_dev); map_dev = NULL; } #endif } -void sandbox_set_enable_pci_map(int enable) +phys_addr_t map_to_sysmem(const void *ptr) { - enable_pci_map = enable; + struct sandbox_mapmem_entry *mentry; + + /* + * If it is in emulated RAM, don't bother creating a tag. Just return + * the offset into the RAM buffer. + */ + if (is_in_sandbox_mem(ptr)) + return (u8 *)ptr - gd->arch.ram_buf; + + /* + * See if there is an existing tag with this pointer. If not, set up a + * new one. + */ + mentry = find_tag(ptr); + if (!mentry) { + struct sandbox_state *state = state_get_current(); + + mentry = malloc(sizeof(*mentry)); + if (!mentry) { + printf("%s: Error: Out of memory\n", __func__); + os_exit(ENOMEM); + } + mentry->tag = state->next_tag++; + mentry->ptr = (void *)ptr; + list_add_tail(&mentry->sibling_node, &state->mapmem_head); + debug("%s: Added map from %p to %lx\n", __func__, ptr, + (ulong)mentry->tag); + } + + /* + * Return the tag as the address to use. A later call to map_sysmem() + * will return ptr + */ + return mentry->tag; } -phys_addr_t map_to_sysmem(const void *ptr) +void sandbox_set_enable_pci_map(int enable) { - return (u8 *)ptr - gd->arch.ram_buf; + enable_pci_map = enable; } void flush_dcache_range(unsigned long start, unsigned long stop) @@ -165,15 +288,3 @@ ulong timer_get_boot_us(void) return (count - base_count) / 1000; } - -int setjmp(jmp_buf jmp) -{ - return os_setjmp((ulong *)jmp, sizeof(*jmp)); -} - -void longjmp(jmp_buf jmp, int ret) -{ - os_longjmp((ulong *)jmp, ret); - while (1) - ; -} diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 5839932b00..9fbcb9ef92 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -143,14 +143,16 @@ void os_tty_raw(int fd, bool allow_sigs) void *os_malloc(size_t length) { struct os_mem_hdr *hdr; + int page_size = getpagesize(); - hdr = mmap(NULL, length + sizeof(*hdr), PROT_READ | PROT_WRITE, + hdr = mmap(NULL, length + page_size, + PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (hdr == MAP_FAILED) return NULL; hdr->length = length; - return hdr + 1; + return (void *)hdr + page_size; } void os_free(void *ptr) @@ -630,24 +632,7 @@ void os_localtime(struct rtc_time *rt) rt->tm_isdst = tm->tm_isdst; } -int os_setjmp(ulong *jmp, int size) +void os_abort(void) { - jmp_buf dummy; - - /* - * We cannot rely on the struct name that jmp_buf uses, so use a - * local variable here - */ - if (size < sizeof(dummy)) { - printf("setjmp: jmpbuf is too small (%d bytes, need %d)\n", - size, sizeof(jmp_buf)); - return -ENOSPC; - } - - return setjmp((struct __jmp_buf_tag *)jmp); -} - -void os_longjmp(ulong *jmp, int ret) -{ - longjmp((struct __jmp_buf_tag *)jmp, ret); + abort(); } diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index cc50819ab9..04a11fed55 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -359,6 +359,14 @@ void state_reset_for_test(struct sandbox_state *state) memset(&state->wdt, '\0', sizeof(state->wdt)); memset(state->spi, '\0', sizeof(state->spi)); + + /* + * Set up the memory tag list. Use the top of emulated SDRAM for the + * first tag number, since that address offset is outside the legal + * range, and can be assumed to be a tag. + */ + INIT_LIST_HEAD(&state->mapmem_head); + state->next_tag = state->ram_size; } int state_init(void) diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 6ac37f1ed7..1aa0f8eef5 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -153,6 +153,7 @@ pinctrl { compatible = "sandbox,pinctrl"; + status = "okay"; pinctrl_i2c0: i2c0 { groups = "i2c"; @@ -164,6 +165,12 @@ groups = "serial_a"; function = "serial"; }; + + pinctrl_onewire0: onewire0 { + groups = "w1"; + function = "w1"; + bias-pull-up; + }; }; reset@1 { @@ -322,6 +329,19 @@ reg = <0x0 0x400>; }; }; + + onewire0: onewire { + compatible = "w1-gpio"; + gpios = <&gpio_a 8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_onewire0>; + status = "okay"; + + sandbox_eeprom0: sandbox_eeprom@0 { + compatible = "sandbox,w1-eeprom"; + status = "okay"; + }; + }; }; #include "cros-ec-keyboard.dtsi" diff --git a/arch/sandbox/include/asm/setjmp.h b/arch/sandbox/include/asm/setjmp.h index 1fe37c91cc..001c7ea322 100644 --- a/arch/sandbox/include/asm/setjmp.h +++ b/arch/sandbox/include/asm/setjmp.h @@ -24,6 +24,11 @@ struct jmp_buf_data { typedef struct jmp_buf_data jmp_buf[1]; +/* + * We have to directly link with the system versions of + * setjmp/longjmp, because setjmp must not return as otherwise + * the stack may become invalid. + */ int setjmp(jmp_buf jmp); __noreturn void longjmp(jmp_buf jmp, int ret); diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 7ed4b512d2..a612ce8944 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -9,6 +9,7 @@ #include <config.h> #include <sysreset.h> #include <stdbool.h> +#include <linux/list.h> #include <linux/stringify.h> /** @@ -45,6 +46,23 @@ struct sandbox_wdt_info { bool running; }; +/** + * struct sandbox_mapmem_entry - maps pointers to/from U-Boot addresses + * + * When map_to_sysmem() is called with an address outside sandbox's emulated + * RAM, a record is created with a tag that can be used to reference that + * pointer. When map_sysmem() is called later with that tag, the pointer will + * be returned, just as it would for a normal sandbox address. + * + * @tag: Address tag (a value which U-Boot uses to refer to the address) + * @ptr: Associated pointer for that tag + */ +struct sandbox_mapmem_entry { + ulong tag; + void *ptr; + struct list_head sibling_node; +}; + /* The complete state of the test system */ struct sandbox_state { const char *cmd; /* Command to execute */ @@ -78,6 +96,9 @@ struct sandbox_state { /* Information about Watchdog */ struct sandbox_wdt_info wdt; + + ulong next_tag; /* Next address tag to allocate */ + struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ }; /* Minimum space we guarantee in the state FDT when calling read/write*/ diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 5b04febd68..cc940712a8 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -5,7 +5,6 @@ CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000 -PLATFORM_CPPFLAGS += -fno-strict-aliasing PLATFORM_CPPFLAGS += -fomit-frame-pointer PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \ $(call cc-option, -fno-unit-at-a-time)) diff --git a/arch/x86/lib/e820.c b/arch/x86/lib/e820.c index 8b34f677d9..d6ae2c4e9d 100644 --- a/arch/x86/lib/e820.c +++ b/arch/x86/lib/e820.c @@ -36,7 +36,7 @@ __weak unsigned int install_e820_map(unsigned int max_entries, return 4; } -#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(EFI_LOADER) void efi_add_known_memory(void) { struct e820_entry e820[E820MAX]; @@ -72,4 +72,4 @@ void efi_add_known_memory(void) efi_add_memory_map(start, pages, type, false); } } -#endif /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */ +#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */ diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index 42b32f5d3d..4e3ad56472 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -7,48 +7,6 @@ #define _XTENSA_ATOMIC_H #include <asm/system.h> - -typedef struct { volatile int counter; } atomic_t; - -#define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v, i) ((v)->counter = (i)) - -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long flags; - - local_irq_save(flags); - v->counter += i; - local_irq_restore(flags); -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long flags; - - local_irq_save(flags); - v->counter -= i; - local_irq_restore(flags); -} - -static inline void atomic_inc(atomic_t *v) -{ - unsigned long flags; - - local_irq_save(flags); - ++v->counter; - local_irq_restore(flags); -} - -static inline void atomic_dec(atomic_t *v) -{ - unsigned long flags; - - local_irq_save(flags); - --v->counter; - local_irq_restore(flags); -} +#include <asm-generic/atomic.h> #endif diff --git a/board/atmel/common/board.c b/board/atmel/common/board.c index 650eb2238c..8f9b5e137c 100644 --- a/board/atmel/common/board.c +++ b/board/atmel/common/board.c @@ -5,7 +5,64 @@ */ #include <common.h> +#include <w1.h> +#include <w1-eeprom.h> +#include <dm/device-internal.h> + +#define AT91_PDA_EEPROM_ID_OFFSET 15 +#define AT91_PDA_EEPROM_ID_LENGTH 5 +#define AT91_PDA_EEPROM_DEFAULT_BUS 0 void dummy(void) { } + +#if defined CONFIG_W1 +void at91_pda_detect(void) +{ + struct udevice *bus, *dev; + u8 buf[AT91_PDA_EEPROM_ID_LENGTH + 1] = {0}; + int ret; + int pda = 0; + + ret = w1_get_bus(AT91_PDA_EEPROM_DEFAULT_BUS, &bus); + if (ret) + return; + + for (device_find_first_child(bus, &dev); + dev; + device_find_next_child(&dev)) { + ret = device_probe(dev); + if (ret) { + continue; + } else { + ret = w1_eeprom_read_buf(dev, AT91_PDA_EEPROM_ID_OFFSET, + (u8 *)buf, AT91_PDA_EEPROM_ID_LENGTH); + if (ret) + return; + break; + } + } + pda = simple_strtoul((const char *)buf, NULL, 10); + + switch (pda) { + case 7000: + if (buf[4] == 'B') + printf("PDA TM7000B detected\n"); + else + printf("PDA TM7000 detected\n"); + break; + case 4300: + printf("PDA TM4300 detected\n"); + break; + case 5000: + printf("PDA TM5000 detected\n"); + break; + } + env_set("pda", (const char *)buf); +} +#else +void at91_pda_detect(void) +{ +} +#endif diff --git a/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c b/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c index d5ddf8d2eb..83634345f3 100644 --- a/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c +++ b/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c @@ -15,6 +15,8 @@ #include <asm/arch/gpio.h> #include <asm/arch/sama5d2.h> +extern void at91_pda_detect(void); + DECLARE_GLOBAL_DATA_PTR; static void board_usb_hw_init(void) @@ -28,6 +30,7 @@ int board_late_init(void) #ifdef CONFIG_DM_VIDEO at91_video_show_board_info(); #endif + at91_pda_detect(); return 0; } #endif diff --git a/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c b/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c index 789841e45a..17e08fa9b2 100644 --- a/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c +++ b/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c @@ -20,6 +20,8 @@ #include <asm/arch/sama5d2.h> #include <asm/arch/sama5d2_smc.h> +extern void at91_pda_detect(void); + DECLARE_GLOBAL_DATA_PTR; #ifdef CONFIG_NAND_ATMEL @@ -65,6 +67,14 @@ static void board_nand_hw_init(void) } #endif +#ifdef CONFIG_BOARD_LATE_INIT +int board_late_init(void) +{ + at91_pda_detect(); + return 0; +} +#endif + static void board_usb_hw_init(void) { atmel_pio4_set_pio_output(AT91_PIO_PORTB, 12, ATMEL_PIO_PUEN_MASK); diff --git a/board/atmel/sama5d2_xplained/sama5d2_xplained.c b/board/atmel/sama5d2_xplained/sama5d2_xplained.c index 592b4d82dd..fccd80ec70 100644 --- a/board/atmel/sama5d2_xplained/sama5d2_xplained.c +++ b/board/atmel/sama5d2_xplained/sama5d2_xplained.c @@ -15,6 +15,8 @@ #include <asm/arch/gpio.h> #include <asm/arch/sama5d2.h> +extern void at91_pda_detect(void); + DECLARE_GLOBAL_DATA_PTR; static void board_usb_hw_init(void) @@ -28,6 +30,7 @@ int board_late_init(void) #ifdef CONFIG_DM_VIDEO at91_video_show_board_info(); #endif + at91_pda_detect(); return 0; } #endif diff --git a/board/atmel/sama5d3_xplained/sama5d3_xplained.c b/board/atmel/sama5d3_xplained/sama5d3_xplained.c index c47f63864b..289f8d8499 100644 --- a/board/atmel/sama5d3_xplained/sama5d3_xplained.c +++ b/board/atmel/sama5d3_xplained/sama5d3_xplained.c @@ -18,6 +18,8 @@ DECLARE_GLOBAL_DATA_PTR; +extern void at91_pda_detect(void); + #ifdef CONFIG_NAND_ATMEL void sama5d3_xplained_nand_hw_init(void) { @@ -72,6 +74,14 @@ void board_debug_uart_init(void) } #endif +#ifdef CONFIG_BOARD_LATE_INIT +int board_late_init(void) +{ + at91_pda_detect(); + return 0; +} +#endif + #ifdef CONFIG_BOARD_EARLY_INIT_F int board_early_init_f(void) { diff --git a/board/atmel/sama5d4_xplained/sama5d4_xplained.c b/board/atmel/sama5d4_xplained/sama5d4_xplained.c index 526c6c7f70..4da64890b3 100644 --- a/board/atmel/sama5d4_xplained/sama5d4_xplained.c +++ b/board/atmel/sama5d4_xplained/sama5d4_xplained.c @@ -17,6 +17,8 @@ DECLARE_GLOBAL_DATA_PTR; +extern void at91_pda_detect(void); + #ifdef CONFIG_NAND_ATMEL static void sama5d4_xplained_nand_hw_init(void) { @@ -71,6 +73,7 @@ static void sama5d4_xplained_usb_hw_init(void) #ifdef CONFIG_BOARD_LATE_INIT int board_late_init(void) { + at91_pda_detect(); #ifdef CONFIG_DM_VIDEO at91_video_show_board_info(); #endif diff --git a/board/gardena/smart-gateway-mt7688/Kconfig b/board/gardena/smart-gateway-mt7688/Kconfig new file mode 100644 index 0000000000..3653f8aadb --- /dev/null +++ b/board/gardena/smart-gateway-mt7688/Kconfig @@ -0,0 +1,12 @@ +if BOARD_GARDENA_SMART_GATEWAY_MT7688 + +config SYS_BOARD + default "smart-gateway-mt7688" + +config SYS_VENDOR + default "gardena" + +config SYS_CONFIG_NAME + default "gardena-smart-gateway-mt7688" + +endif diff --git a/board/gardena/smart-gateway-mt7688/MAINTAINERS b/board/gardena/smart-gateway-mt7688/MAINTAINERS new file mode 100644 index 0000000000..bbb491c1ce --- /dev/null +++ b/board/gardena/smart-gateway-mt7688/MAINTAINERS @@ -0,0 +1,8 @@ +GARDENA_SMART_GATEWAY_MT7688 BOARD +M: Stefan Roese <sr@denx.de> +S: Maintained +F: board/gardena/smart-gateway-mt7688 +F: include/configs/gardena-smart-gateway-mt7688.h +F: configs/gardena-smart-gateway-mt7688_defconfig +F: configs/gardena-smart-gateway-mt7688-ram_defconfig +F: arch/mips/dts/gardena-smart-gateway-mt7688.dts diff --git a/board/gardena/smart-gateway-mt7688/Makefile b/board/gardena/smart-gateway-mt7688/Makefile new file mode 100644 index 0000000000..70cd7a8e56 --- /dev/null +++ b/board/gardena/smart-gateway-mt7688/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += board.o diff --git a/board/gardena/smart-gateway-mt7688/board.c b/board/gardena/smart-gateway-mt7688/board.c new file mode 100644 index 0000000000..5ff546f505 --- /dev/null +++ b/board/gardena/smart-gateway-mt7688/board.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +#include <common.h> +#include <asm/io.h> + +int board_early_init_f(void) +{ + /* + * Nothing to be done here for this board (no UART setup etc) + * right now. We might need some pin muxing, so lets keep this + * function for now. + */ + return 0; +} diff --git a/board/logicpd/omap3som/omap3logic.c b/board/logicpd/omap3som/omap3logic.c index 620423bbc8..48d886930f 100644 --- a/board/logicpd/omap3som/omap3logic.c +++ b/board/logicpd/omap3som/omap3logic.c @@ -331,13 +331,6 @@ int board_late_init(void) #endif #if defined(CONFIG_MMC) -int board_mmc_init(bd_t *bis) -{ - return omap_mmc_init(0, 0, 0, -1, -1); -} -#endif - -#if defined(CONFIG_MMC) void board_mmc_power_init(void) { twl4030_power_mmc_init(0); diff --git a/board/logicpd/omap3som/omap3logic.h b/board/logicpd/omap3som/omap3logic.h index a5601f7a7b..aeb26b90d7 100644 --- a/board/logicpd/omap3som/omap3logic.h +++ b/board/logicpd/omap3som/omap3logic.h @@ -131,145 +131,18 @@ void set_muxconf_regs(void) MUX_VAL(CP(GPMC_WAIT2), (IEN | PTU | EN | M4)); /*GPIO_64*/ MUX_VAL(CP(GPMC_WAIT3), (IEN | PTU | EN | M0)); /*GPMC_WAIT3*/ - MUX_VAL(CP(CAM_HS), (IEN | PTU | EN | M0)); /*CAM_HS */ - MUX_VAL(CP(CAM_VS), (IEN | PTU | EN | M0)); /*CAM_VS */ - MUX_VAL(CP(CAM_XCLKA), (IDIS | PTD | DIS | M0)); /*CAM_XCLKA*/ - MUX_VAL(CP(CAM_PCLK), (IEN | PTU | EN | M0)); /*CAM_PCLK*/ - MUX_VAL(CP(CAM_FLD), (IDIS | PTD | DIS | M4)); /*GPIO_98*/ - MUX_VAL(CP(CAM_D0), (IEN | PTD | DIS | M0)); /*CAM_D0*/ - MUX_VAL(CP(CAM_D1), (IEN | PTD | DIS | M0)); /*CAM_D1*/ - MUX_VAL(CP(CAM_D2), (IEN | PTD | DIS | M0)); /*CAM_D2*/ - MUX_VAL(CP(CAM_D3), (IEN | PTD | DIS | M0)); /*CAM_D3*/ - MUX_VAL(CP(CAM_D4), (IEN | PTD | DIS | M0)); /*CAM_D4*/ - MUX_VAL(CP(CAM_D5), (IEN | PTD | DIS | M0)); /*CAM_D5*/ - MUX_VAL(CP(CAM_D6), (IEN | PTD | DIS | M0)); /*CAM_D6*/ - MUX_VAL(CP(CAM_D7), (IEN | PTD | DIS | M0)); /*CAM_D7*/ - MUX_VAL(CP(CAM_D8), (IEN | PTD | DIS | M0)); /*CAM_D8*/ - MUX_VAL(CP(CAM_D9), (IEN | PTD | DIS | M0)); /*CAM_D9*/ - MUX_VAL(CP(CAM_D10), (IEN | PTD | DIS | M0)); /*CAM_D10*/ - MUX_VAL(CP(CAM_D11), (IEN | PTD | DIS | M0)); /*CAM_D11*/ - MUX_VAL(CP(CAM_XCLKB), (IDIS | PTD | DIS | M0)); /*CAM_XCLKB*/ - MUX_VAL(CP(CAM_WEN), (IEN | PTD | DIS | M4)); /*GPIO_167*/ - MUX_VAL(CP(CAM_STROBE), (IDIS | PTD | DIS | M0)); /*CAM_STROBE*/ - - MUX_VAL(CP(CSI2_DX0), (IEN | PTD | DIS | M0)); /*CSI2_DX0*/ - MUX_VAL(CP(CSI2_DY0), (IEN | PTD | DIS | M0)); /*CSI2_DY0*/ - MUX_VAL(CP(CSI2_DX1), (IEN | PTD | DIS | M0)); /*CSI2_DX1*/ - MUX_VAL(CP(CSI2_DY1), (IEN | PTD | DIS | M0)); /*CSI2_DY1*/ - - MUX_VAL(CP(MCBSP2_FSX), (IEN | PTD | DIS | M0)); /*McBSP2_FSX*/ - MUX_VAL(CP(MCBSP2_CLKX), (IEN | PTD | DIS | M0)); /*McBSP2_CLKX*/ - MUX_VAL(CP(MCBSP2_DR), (IEN | PTD | DIS | M0)); /*McBSP2_DR*/ - MUX_VAL(CP(MCBSP2_DX), (IDIS | PTD | DIS | M0)); /*McBSP2_DX*/ - MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN | M0)); /*MMC1_CLK*/ MUX_VAL(CP(MMC1_CMD), (IEN | PTU | EN | M0)); /*MMC1_CMD*/ MUX_VAL(CP(MMC1_DAT0), (IEN | PTU | EN | M0)); /*MMC1_DAT0*/ MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)); /*MMC1_DAT1*/ MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)); /*MMC1_DAT2*/ MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)); /*MMC1_DAT3*/ - MUX_VAL(CP(MMC1_DAT4), (IEN | PTU | EN | M0)); /*MMC1_DAT4*/ - MUX_VAL(CP(MMC1_DAT5), (IEN | PTU | EN | M0)); /*MMC1_DAT5*/ - MUX_VAL(CP(MMC1_DAT6), (IEN | PTU | EN | M0)); /*MMC1_DAT6*/ - MUX_VAL(CP(MMC1_DAT7), (IEN | PTU | EN | M0)); /*MMC1_DAT7*/ - - MUX_VAL(CP(MMC2_CLK), (IEN | PTD | DIS | M0)); /*MMC2_CLK*/ - MUX_VAL(CP(MMC2_CMD), (IEN | PTU | EN | M0)); /*MMC2_CMD*/ - MUX_VAL(CP(MMC2_DAT0), (IEN | PTU | EN | M0)); /*MMC2_DAT0*/ - MUX_VAL(CP(MMC2_DAT1), (IEN | PTU | EN | M0)); /*MMC2_DAT1*/ - MUX_VAL(CP(MMC2_DAT2), (IEN | PTU | EN | M0)); /*MMC2_DAT2*/ - MUX_VAL(CP(MMC2_DAT3), (IEN | PTU | EN | M0)); /*MMC2_DAT3*/ - MUX_VAL(CP(MMC2_DAT4), (IDIS | PTD | DIS | M0)); /*MMC2_DAT4*/ - MUX_VAL(CP(MMC2_DAT5), (IDIS | PTD | DIS | M0)); /*MMC2_DAT5*/ - MUX_VAL(CP(MMC2_DAT6), (IDIS | PTD | DIS | M0)); /*MMC2_DAT6 */ - MUX_VAL(CP(MMC2_DAT7), (IEN | PTU | EN | M0)); /*MMC2_DAT7*/ - - MUX_VAL(CP(MCBSP3_DX), (IDIS | PTD | DIS | M0)); /*McBSP3_DX*/ - MUX_VAL(CP(MCBSP3_DR), (IEN | PTD | DIS | M0)); /*McBSP3_DR*/ - MUX_VAL(CP(MCBSP3_CLKX), (IEN | PTD | DIS | M0)); /*McBSP3_CLKX*/ - MUX_VAL(CP(MCBSP3_FSX), (IEN | PTD | DIS | M0)); /*McBSP3_FSX*/ - - MUX_VAL(CP(UART2_CTS), (IEN | PTU | EN | M0)); /*UART2_CTS*/ - MUX_VAL(CP(UART2_RTS), (IDIS | PTD | DIS | M0)); /*UART2_RTS*/ - MUX_VAL(CP(UART2_TX), (IDIS | PTD | DIS | M0)); /*UART2_TX*/ - MUX_VAL(CP(UART2_RX), (IEN | PTD | DIS | M0)); /*UART2_RX*/ MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); /*UART1_TX*/ MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); /*UART1_RTS*/ MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)); /*UART1_CTS*/ MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)); /*UART1_RX*/ - MUX_VAL(CP(MCBSP4_CLKX), (IDIS | PTD | DIS | M4)); /*GPIO_152*/ - MUX_VAL(CP(MCBSP4_DR), (IDIS | PTD | DIS | M4)); /*GPIO_153*/ - - MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | DIS | M0)); /*MCBSP1_CLKR*/ - MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | EN | M0)); /*MCBSP1_FSR*/ - MUX_VAL(CP(MCBSP1_DX), (IDIS | PTD | DIS | M0)); /*MCBSP1_DX*/ - MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | DIS | M0)); /*MCBSP1_DR*/ - MUX_VAL(CP(MCBSP_CLKS), (IEN | PTU | DIS | M0)); /*MCBSP_CLKS*/ - MUX_VAL(CP(MCBSP1_FSX), (IEN | PTD | DIS | M0)); /*MCBSP1_FSX*/ - MUX_VAL(CP(MCBSP1_CLKX), (IEN | PTD | DIS | M0)); /*MCBSP1_CLKX*/ - - MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); /*UART3_CTS_*/ - MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); /*UART3_RTS_SD */ - MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); /*UART3_RX_IRRX*/ - MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); /*UART3_TX_IRTX*/ - - MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)); /*HSUSB0_CLK*/ - MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)); /*HSUSB0_STP*/ - MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)); /*HSUSB0_DIR*/ - MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)); /*HSUSB0_NXT*/ - MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA0*/ - MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA1*/ - MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA2*/ - MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA3*/ - MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA4*/ - MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA5*/ - MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA6*/ - MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA7*/ - - MUX_VAL(CP(I2C1_SCL), (IEN | EN | M0)); /*I2C1_SCL*/ - MUX_VAL(CP(I2C1_SDA), (IEN | EN | M0)); /*I2C1_SDA*/ - - MUX_VAL(CP(I2C2_SCL), (IEN | EN | M0)); /*I2C2_SCL*/ - MUX_VAL(CP(I2C2_SDA), (IEN | EN | M0)); /*I2C2_SDA*/ - - MUX_VAL(CP(I2C3_SCL), (IEN | EN | M0)); /*I2C3_SCL*/ - MUX_VAL(CP(I2C3_SDA), (IEN | EN | M0)); /*I2C3_SDA*/ - - MUX_VAL(CP(I2C4_SCL), (IEN | EN | M0)); /*I2C4_SCL*/ - MUX_VAL(CP(I2C4_SDA), (IEN | EN | M0)); /*I2C4_SDA*/ - - MUX_VAL(CP(HDQ_SIO), (IEN | PTU | EN | M0)); /*HDQ_SIO*/ - - MUX_VAL(CP(MCSPI1_CLK), (IEN | PTD | DIS | M0)); /*McSPI1_CLK*/ - MUX_VAL(CP(MCSPI1_SIMO), (IEN | PTD | DIS | M0)); /*McSPI1_SIMO */ - MUX_VAL(CP(MCSPI1_SOMI), (IEN | PTD | DIS | M0)); /*McSPI1_SOMI */ - MUX_VAL(CP(MCSPI1_CS0), (IEN | PTD | EN | M0)); /*McSPI1_CS0*/ - MUX_VAL(CP(MCSPI1_CS1), (IEN | PTD | EN | M4)); /*GPIO_175*/ - MUX_VAL(CP(MCSPI1_CS2), (IEN | PTU | DIS | M4)); /*GPIO_176*/ - MUX_VAL(CP(MCSPI1_CS3), (IEN | PTD | EN | M0)); /*McSPI1_CS3*/ - - MUX_VAL(CP(MCSPI2_CLK), (IEN | PTD | DIS | M0)); /*McSPI2_CLK*/ - MUX_VAL(CP(MCSPI2_SIMO), (IEN | PTD | DIS | M0)); /*McSPI2_SIMO*/ - MUX_VAL(CP(MCSPI2_SOMI), (IEN | PTD | DIS | M0)); /*McSPI2_SOMI*/ - MUX_VAL(CP(MCSPI2_CS0), (IEN | PTD | EN | M0)); /*McSPI2_CS0*/ - MUX_VAL(CP(MCSPI2_CS1), (IEN | PTD | EN | M0)); /*McSPI2_CS1*/ - - MUX_VAL(CP(SYS_32K), (IEN | PTD | DIS | M0)); /*SYS_32K*/ - MUX_VAL(CP(SYS_CLKREQ), (IEN | PTD | DIS | M0)); /*SYS_CLKREQ*/ - MUX_VAL(CP(SYS_NIRQ), (IEN | PTU | EN | M0)); /*SYS_nIRQ*/ - MUX_VAL(CP(SYS_BOOT0), (IEN | PTD | DIS | M4)); /*GPIO_2*/ - MUX_VAL(CP(SYS_BOOT1), (IEN | PTD | DIS | M4)); /*GPIO_3 */ - MUX_VAL(CP(SYS_BOOT2), (IEN | PTD | DIS | M4)); /*GPIO_4*/ - MUX_VAL(CP(SYS_BOOT3), (IEN | PTD | DIS | M4)); /*GPIO_5*/ - MUX_VAL(CP(SYS_BOOT4), (IEN | PTD | DIS | M4)); /*GPIO_6*/ - MUX_VAL(CP(SYS_BOOT5), (IEN | PTD | DIS | M4)); /*GPIO_7*/ - - MUX_VAL(CP(SYS_OFF_MODE), (IEN | PTD | DIS | M0)); /*SYS_OFF_MODE*/ - MUX_VAL(CP(SYS_CLKOUT1), (IEN | PTD | DIS | M0)); /*SYS_CLKOUT1*/ - MUX_VAL(CP(SYS_CLKOUT2), (IEN | PTU | EN | M0)); /*SYS_CLKOUT2*/ - MUX_VAL(CP(JTAG_TCK), (IEN | PTD | DIS | M0)); /*JTAG_TCK*/ MUX_VAL(CP(JTAG_TMS), (IEN | PTD | DIS | M0)); /*JTAG_TMS*/ MUX_VAL(CP(JTAG_TDI), (IEN | PTD | DIS | M0)); /*JTAG_TDI*/ diff --git a/board/seeed/linkit-smart-7688/Kconfig b/board/seeed/linkit-smart-7688/Kconfig new file mode 100644 index 0000000000..a9d63285c3 --- /dev/null +++ b/board/seeed/linkit-smart-7688/Kconfig @@ -0,0 +1,12 @@ +if BOARD_LINKIT_SMART_7688 + +config SYS_BOARD + default "linkit-smart-7688" + +config SYS_VENDOR + default "seeed" + +config SYS_CONFIG_NAME + default "linkit-smart-7688" + +endif diff --git a/board/seeed/linkit-smart-7688/MAINTAINERS b/board/seeed/linkit-smart-7688/MAINTAINERS new file mode 100644 index 0000000000..c3bbad4231 --- /dev/null +++ b/board/seeed/linkit-smart-7688/MAINTAINERS @@ -0,0 +1,8 @@ +LINKIT_SMART_7688 BOARD +M: Stefan Roese <sr@denx.de> +S: Maintained +F: board/seeed/linkit-smart-7688 +F: include/configs/linkit-smart-7688.h +F: configs/linkit-smart-7688_defconfig +F: configs/linkit-smart-7688_ram_defconfig +F: arch/mips/dts/linkit-smart-7688.dts diff --git a/board/seeed/linkit-smart-7688/Makefile b/board/seeed/linkit-smart-7688/Makefile new file mode 100644 index 0000000000..70cd7a8e56 --- /dev/null +++ b/board/seeed/linkit-smart-7688/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += board.o diff --git a/board/seeed/linkit-smart-7688/board.c b/board/seeed/linkit-smart-7688/board.c new file mode 100644 index 0000000000..a28abc00b8 --- /dev/null +++ b/board/seeed/linkit-smart-7688/board.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +#include <common.h> +#include <asm/io.h> + +#define MT76XX_GPIO1_MODE 0xb0000060 + +void board_debug_uart_init(void) +{ + /* Select UART2 mode instead of GPIO mode (default) */ + clrbits_le32((void __iomem *)MT76XX_GPIO1_MODE, GENMASK(27, 26)); +} + +int board_early_init_f(void) +{ + /* + * The pin muxing of UART2 also needs to be done, if debug uart + * is not enabled. So we need to call this function here as well. + */ + board_debug_uart_init(); + + return 0; +} diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index bfc8ab64d3..54feca0ecf 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -5,13 +5,181 @@ #include <config.h> #include <common.h> #include <led.h> +#include <clk.h> +#include <dm.h> +#include <generic-phy.h> +#include <phy.h> +#include <reset.h> +#include <usb.h> #include <asm/arch/stm32.h> +#include <asm/io.h> +#include <power/regulator.h> +#include <usb/dwc2_udc.h> /* * Get a global data pointer */ DECLARE_GLOBAL_DATA_PTR; +#define STM32MP_GUSBCFG 0x40002407 + +#define STM32MP_GGPIO 0x38 +#define STM32MP_GGPIO_VBUS_SENSING BIT(21) + +static struct dwc2_plat_otg_data stm32mp_otg_data = { + .usb_gusbcfg = STM32MP_GUSBCFG, +}; + +static struct reset_ctl usbotg_reset; + +int board_usb_init(int index, enum usb_init_type init) +{ + struct fdtdec_phandle_args args; + struct udevice *dev; + const void *blob = gd->fdt_blob; + struct clk clk; + struct phy phy; + int node; + int phy_provider; + int ret; + + /* find the usb otg node */ + node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2"); + if (node < 0) { + debug("Not found usb_otg device\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, node)) { + debug("stm32 usbotg is disabled in the device tree\n"); + return -ENODEV; + } + + /* Enable clock */ + ret = fdtdec_parse_phandle_with_args(blob, node, "clocks", + "#clock-cells", 0, 0, &args); + if (ret) { + debug("usbotg has no clocks defined in the device tree\n"); + return ret; + } + + ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev); + if (ret) + return ret; + + if (args.args_count != 1) { + debug("Can't find clock ID in the device tree\n"); + return -ENODATA; + } + + clk.dev = dev; + clk.id = args.args[0]; + + ret = clk_enable(&clk); + if (ret) { + debug("Failed to enable usbotg clock\n"); + return ret; + } + + /* Reset */ + ret = fdtdec_parse_phandle_with_args(blob, node, "resets", + "#reset-cells", 0, 0, &args); + if (ret) { + debug("usbotg has no resets defined in the device tree\n"); + goto clk_err; + } + + ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev); + if (ret || args.args_count != 1) + goto clk_err; + + usbotg_reset.dev = dev; + usbotg_reset.id = args.args[0]; + + reset_assert(&usbotg_reset); + udelay(2); + reset_deassert(&usbotg_reset); + + /* Get USB PHY */ + ret = fdtdec_parse_phandle_with_args(blob, node, "phys", + "#phy-cells", 0, 0, &args); + if (!ret) { + phy_provider = fdt_parent_offset(blob, args.node); + ret = uclass_get_device_by_of_offset(UCLASS_PHY, + phy_provider, &dev); + if (ret) + goto clk_err; + + phy.dev = dev; + phy.id = fdtdec_get_uint(blob, args.node, "reg", -1); + + ret = generic_phy_power_on(&phy); + if (ret) { + debug("unable to power on the phy\n"); + goto clk_err; + } + + ret = generic_phy_init(&phy); + if (ret) { + debug("failed to init usb phy\n"); + goto phy_power_err; + } + } + + /* Parse and store data needed for gadget */ + stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg"); + if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) { + debug("usbotg: can't get base address\n"); + ret = -ENODATA; + goto phy_init_err; + } + + stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node, + "g-rx-fifo-size", 0); + stm32mp_otg_data.np_tx_fifo_sz = fdtdec_get_int(blob, node, + "g-np-tx-fifo-size", 0); + stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node, + "g-tx-fifo-size", 0); + /* Enable voltage level detector */ + if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply", + NULL, 0, 0, &args))) { + if (!uclass_get_device_by_of_offset(UCLASS_REGULATOR, + args.node, &dev)) { + ret = regulator_set_enable(dev, true); + if (ret) { + debug("Failed to enable usb33d\n"); + goto phy_init_err; + } + } + } + /* Enable vbus sensing */ + setbits_le32(stm32mp_otg_data.regs_otg + STM32MP_GGPIO, + STM32MP_GGPIO_VBUS_SENSING); + + return dwc2_udc_probe(&stm32mp_otg_data); + +phy_init_err: + generic_phy_exit(&phy); + +phy_power_err: + generic_phy_power_off(&phy); + +clk_err: + clk_disable(&clk); + + return ret; +} + +int board_usb_cleanup(int index, enum usb_init_type init) +{ + /* Reset usbotg */ + reset_assert(&usbotg_reset); + udelay(2); + reset_deassert(&usbotg_reset); + + return 0; +} + int board_late_init(void) { return 0; diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index a359d20021..13845251af 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -608,6 +608,84 @@ static struct clk_synth cdce913_data = { }; #endif +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_CONTROL) && \ + defined(CONFIG_DM_ETH) && defined(CONFIG_DRIVER_TI_CPSW) + +#define MAX_CPSW_SLAVES 2 + +/* At the moment, we do not want to stop booting for any failures here */ +int ft_board_setup(void *fdt, bd_t *bd) +{ + const char *slave_path, *enet_name; + int enetnode, slavenode, phynode; + struct udevice *ethdev; + char alias[16]; + u32 phy_id[2]; + int phy_addr; + int i, ret; + + /* phy address fixup needed only on beagle bone family */ + if (!board_is_beaglebonex()) + goto done; + + for (i = 0; i < MAX_CPSW_SLAVES; i++) { + sprintf(alias, "ethernet%d", i); + + slave_path = fdt_get_alias(fdt, alias); + if (!slave_path) + continue; + + slavenode = fdt_path_offset(fdt, slave_path); + if (slavenode < 0) + continue; + + enetnode = fdt_parent_offset(fdt, slavenode); + enet_name = fdt_get_name(fdt, enetnode, NULL); + + ethdev = eth_get_dev_by_name(enet_name); + if (!ethdev) + continue; + + phy_addr = cpsw_get_slave_phy_addr(ethdev, i); + + /* check for phy_id as well as phy-handle properties */ + ret = fdtdec_get_int_array_count(fdt, slavenode, "phy_id", + phy_id, 2); + if (ret == 2) { + if (phy_id[1] != phy_addr) { + printf("fixing up phy_id for %s, old: %d, new: %d\n", + alias, phy_id[1], phy_addr); + + phy_id[0] = cpu_to_fdt32(phy_id[0]); + phy_id[1] = cpu_to_fdt32(phy_addr); + do_fixup_by_path(fdt, slave_path, "phy_id", + phy_id, sizeof(phy_id), 0); + } + } else { + phynode = fdtdec_lookup_phandle(fdt, slavenode, + "phy-handle"); + if (phynode < 0) + continue; + + ret = fdtdec_get_int(fdt, phynode, "reg", -ENOENT); + if (ret < 0) + continue; + + if (ret != phy_addr) { + printf("fixing up phy-handle for %s, old: %d, new: %d\n", + alias, ret, phy_addr); + + fdt_setprop_u32(fdt, phynode, "reg", + cpu_to_fdt32(phy_addr)); + } + } + } + +done: + return 0; +} +#endif + /* * Basic board specific setup. Pinmux has been handled already. */ diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 89fac6bb67..af91cde7c8 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -281,7 +281,16 @@ int board_early_init_f(void) { int ret = 0; #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CLK_ZYNQMP) - zynqmp_pmufw_version(); + u32 pm_api_version; + + pm_api_version = zynqmp_pmufw_version(); + printf("PMUFW:\tv%d.%d\n", + pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, + pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK); + + if (pm_api_version < ZYNQMP_PM_VERSION) + panic("PMUFW version error. Expected: v%d.%d\n", + ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR); #endif #if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED) diff --git a/cmd/Kconfig b/cmd/Kconfig index 13d4c991bf..ae697fcad9 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -304,11 +304,6 @@ config CMD_XIMG help Extract a part of a multi-image. -config CMD_POWEROFF - bool "poweroff" - help - Poweroff/Shutdown the system - config CMD_SPL bool "spl export - Export boot information for Falcon boot" depends on SPL @@ -832,6 +827,13 @@ config CMD_I2C help I2C support. +config CMD_W1 + depends on W1 + default y if W1 + bool "w1 - Support for Dallas 1-Wire protocol" + help + Dallas 1-wire protocol support + config CMD_LOADB bool "loadb" default y @@ -937,6 +939,11 @@ config CMD_PCMCIA about 1990. These devices are typically removable memory or network cards using a standard 68-pin connector. +config CMD_POWEROFF + bool "poweroff" + help + Poweroff/Shutdown the system + config CMD_READ bool "read - Read binary data from a partition" help @@ -1338,6 +1345,12 @@ config CMD_CACHE help Enable the "icache" and "dcache" commands +config CMD_CONITRACE + bool "conitrace - trace console input codes" + help + Enable the 'conitrace' command which displays the codes received + from the console input as hexadecimal numbers. + config CMD_DISPLAY bool "Enable the 'display' command, for character displays" help diff --git a/cmd/Makefile b/cmd/Makefile index a61fab6583..9e311a79c0 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_CMD_CACHE) += cache.o obj-$(CONFIG_CMD_CBFS) += cbfs.o obj-$(CONFIG_CMD_CLK) += clk.o obj-$(CONFIG_CMD_CONFIG) += config.o +obj-$(CONFIG_CMD_CONITRACE) += conitrace.o obj-$(CONFIG_CMD_CONSOLE) += console.o obj-$(CONFIG_CMD_CPU) += cpu.o obj-$(CONFIG_DATAFLASH_MMC_SELECT) += dataflash_mmc_mux.o @@ -145,6 +146,7 @@ obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o obj-$(CONFIG_CMD_XIMG) += ximg.o obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o obj-$(CONFIG_CMD_SPL) += spl.o +obj-$(CONFIG_CMD_W1) += w1.o obj-$(CONFIG_CMD_ZIP) += zip.o obj-$(CONFIG_CMD_ZFS) += zfs.o diff --git a/cmd/bootefi.c b/cmd/bootefi.c index b60c151fb4..82d755ceb3 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -49,6 +49,11 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + /* Initialize root node */ + ret = efi_root_node_register(); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize EFI driver uclass */ ret = efi_driver_init(); if (ret != EFI_SUCCESS) @@ -116,32 +121,47 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info, { size_t size; const char *env = env_get(env_var); + u16 *pos; loaded_image_info->load_options = NULL; loaded_image_info->load_options_size = 0; if (!env) return; - size = strlen(env) + 1; + size = utf8_utf16_strlen(env) + 1; loaded_image_info->load_options = calloc(size, sizeof(u16)); if (!loaded_image_info->load_options) { printf("ERROR: Out of memory\n"); return; } - utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size); + pos = loaded_image_info->load_options; + utf8_utf16_strcpy(&pos, env); loaded_image_info->load_options_size = size * 2; } -static void *copy_fdt(void *fdt) +/** + * copy_fdt() - Copy the device tree to a new location available to EFI + * + * The FDT is relocated into a suitable location within the EFI memory map. + * An additional 12KB is added to the space in case the device tree needs to be + * expanded later with fdt_open_into(). + * + * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated + * FDT start + * @fdt_sizep: Returns new size of FDT, including + * @return new relocated address of FDT + */ +static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep) { - u64 fdt_size = fdt_totalsize(fdt); unsigned long fdt_ram_start = -1L, fdt_pages; + efi_status_t ret = 0; + void *fdt, *new_fdt; u64 new_fdt_addr; - void *new_fdt; + uint fdt_size; int i; - for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - u64 ram_start = gd->bd->bi_dram[i].start; - u64 ram_size = gd->bd->bi_dram[i].size; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + u64 ram_start = gd->bd->bi_dram[i].start; + u64 ram_size = gd->bd->bi_dram[i].size; if (!ram_size) continue; @@ -154,30 +174,37 @@ static void *copy_fdt(void *fdt) * Give us at least 4KB of breathing room in case the device tree needs * to be expanded later. Round up to the nearest EFI page boundary. */ - fdt_size += 4096; + fdt = map_sysmem(*fdt_addrp, 0); + fdt_size = fdt_totalsize(fdt); + fdt_size += 4096 * 3; fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE); fdt_pages = fdt_size >> EFI_PAGE_SHIFT; - /* Safe fdt location is at 128MB */ - new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size; - if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, - &new_fdt_addr) != EFI_SUCCESS) { + /* Safe fdt location is at 127MB */ + new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, fdt_pages, + &new_fdt_addr); + if (ret != EFI_SUCCESS) { /* If we can't put it there, put it somewhere */ new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size); - if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, - &new_fdt_addr) != EFI_SUCCESS) { + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, fdt_pages, + &new_fdt_addr); + if (ret != EFI_SUCCESS) { printf("ERROR: Failed to reserve space for FDT\n"); - return NULL; + goto done; } } - new_fdt = (void*)(ulong)new_fdt_addr; + new_fdt = map_sysmem(new_fdt_addr, fdt_size); memcpy(new_fdt, fdt, fdt_totalsize(fdt)); fdt_set_totalsize(new_fdt, fdt_size); - return new_fdt; + *fdt_addrp = new_fdt_addr; + *fdt_sizep = fdt_size; +done: + return ret; } static efi_status_t efi_do_enter( @@ -250,22 +277,27 @@ static void efi_carve_out_dt_rsv(void *fdt) } } -static efi_status_t efi_install_fdt(void *fdt) +static efi_status_t efi_install_fdt(ulong fdt_addr) { bootm_headers_t img = { 0 }; - ulong fdt_pages, fdt_size, fdt_start, fdt_end; + ulong fdt_pages, fdt_size, fdt_start; efi_status_t ret; + void *fdt; + fdt = map_sysmem(fdt_addr, 0); if (fdt_check_header(fdt)) { printf("ERROR: invalid device tree\n"); return EFI_INVALID_PARAMETER; } /* Prepare fdt for payload */ - fdt = copy_fdt(fdt); - if (!fdt) - return EFI_OUT_OF_RESOURCES; + ret = copy_fdt(&fdt_addr, &fdt_size); + if (ret) + return ret; + unmap_sysmem(fdt); + fdt = map_sysmem(fdt_addr, 0); + fdt_size = fdt_totalsize(fdt); if (image_setup_libfdt(&img, fdt, 0, NULL)) { printf("ERROR: failed to process device tree\n"); return EFI_LOAD_ERROR; @@ -279,30 +311,35 @@ static efi_status_t efi_install_fdt(void *fdt) return EFI_OUT_OF_RESOURCES; /* And reserve the space in the memory map */ - fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; - fdt_end = ((ulong)fdt) + fdt_totalsize(fdt); - fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; + fdt_start = fdt_addr; fdt_pages = fdt_size >> EFI_PAGE_SHIFT; - /* Give a bootloader the chance to modify the device tree */ - fdt_pages += 2; + ret = efi_add_memory_map(fdt_start, fdt_pages, EFI_BOOT_SERVICES_DATA, true); + return ret; } -/* - * Load an EFI payload into a newly allocated piece of memory, register all - * EFI objects it would want to access and jump to it. +/** + * do_bootefi_exec() - execute EFI binary + * + * @efi: address of the binary + * @device_path: path of the device from which the binary was loaded + * @image_path: device path of the binary + * Return: status code + * + * Load the EFI binary into a newly assigned memory unwinding the relocation + * information, install the loaded image protocol, and call the binary. */ static efi_status_t do_bootefi_exec(void *efi, struct efi_device_path *device_path, struct efi_device_path *image_path) { - struct efi_loaded_image loaded_image_info = {}; - struct efi_object loaded_image_info_obj = {}; - struct efi_object mem_obj = {}; + efi_handle_t mem_handle = NULL; struct efi_device_path *memdp = NULL; efi_status_t ret; + struct efi_loaded_image_obj *image_handle = NULL; + struct efi_loaded_image *loaded_image_info = NULL; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); @@ -310,16 +347,21 @@ static efi_status_t do_bootefi_exec(void *efi, /* * Special case for efi payload not loaded from disk, such as * 'bootefi hello' or for example payload loaded directly into - * memory via jtag/etc: + * memory via jtag, etc: */ if (!device_path && !image_path) { printf("WARNING: using memory device/image path, this may confuse some payloads!\n"); /* actual addresses filled in after efi_load_pe() */ memdp = efi_dp_from_mem(0, 0, 0); device_path = image_path = memdp; - efi_add_handle(&mem_obj); - - ret = efi_add_protocol(mem_obj.handle, &efi_guid_device_path, + /* + * Grub expects that the device path of the loaded image is + * installed on a handle. + */ + ret = efi_create_handle(&mem_handle); + if (ret != EFI_SUCCESS) + goto exit; + ret = efi_add_protocol(mem_handle, &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto exit; @@ -327,8 +369,10 @@ static efi_status_t do_bootefi_exec(void *efi, assert(device_path && image_path); } - efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj, - device_path, image_path); + ret = efi_setup_loaded_image(device_path, image_path, &image_handle, + &loaded_image_info); + if (ret != EFI_SUCCESS) + goto exit; /* * gd lives in a fixed register which may get clobbered while we execute @@ -337,9 +381,9 @@ static efi_status_t do_bootefi_exec(void *efi, efi_save_gd(); /* Transfer environment variable bootargs as load options */ - set_load_options(&loaded_image_info, "bootargs"); + set_load_options(loaded_image_info, "bootargs"); /* Load the EFI payload */ - entry = efi_load_pe(efi, &loaded_image_info); + entry = efi_load_pe(image_handle, efi, loaded_image_info); if (!entry) { ret = EFI_LOAD_ERROR; goto exit; @@ -347,10 +391,10 @@ static efi_status_t do_bootefi_exec(void *efi, if (memdp) { struct efi_device_path_memory *mdp = (void *)memdp; - mdp->memory_type = loaded_image_info.image_code_type; - mdp->start_address = (uintptr_t)loaded_image_info.image_base; + mdp->memory_type = loaded_image_info->image_code_type; + mdp->start_address = (uintptr_t)loaded_image_info->image_base; mdp->end_address = mdp->start_address + - loaded_image_info.image_size; + loaded_image_info->image_size; } /* we don't support much: */ @@ -360,8 +404,8 @@ static efi_status_t do_bootefi_exec(void *efi, /* Call our payload! */ debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); - if (setjmp(&loaded_image_info.exit_jmp)) { - ret = loaded_image_info.exit_status; + if (setjmp(&image_handle->exit_jmp)) { + ret = image_handle->exit_status; goto exit; } @@ -373,7 +417,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* Move into EL2 and keep running there */ armv8_switch_to_el2((ulong)entry, - (ulong)&loaded_image_info_obj.handle, + (ulong)image_handle, (ulong)&systab, 0, (ulong)efi_run_in_el2, ES_TO_AARCH64); @@ -390,7 +434,7 @@ static efi_status_t do_bootefi_exec(void *efi, secure_ram_addr(_do_nonsec_entry)( efi_run_in_hyp, (uintptr_t)entry, - (uintptr_t)loaded_image_info_obj.handle, + (uintptr_t)image_handle, (uintptr_t)&systab); /* Should never reach here, efi exits with longjmp */ @@ -398,13 +442,14 @@ static efi_status_t do_bootefi_exec(void *efi, } #endif - ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry); + ret = efi_do_enter(image_handle, &systab, entry); exit: /* image has returned, loaded-image obj goes *poof*: */ - list_del(&loaded_image_info_obj.link); - if (mem_obj.handle) - list_del(&mem_obj.link); + if (image_handle) + efi_delete_handle(&image_handle->parent); + if (mem_handle) + efi_delete_handle(mem_handle); return ret; } @@ -443,7 +488,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) char *saddr; efi_status_t r; unsigned long fdt_addr; - void *fdt; /* Allow unaligned memory access */ allow_unaligned(); @@ -464,8 +508,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!fdt_addr && *argv[2] != '0') return CMD_RET_USAGE; /* Install device tree */ - fdt = map_sysmem(fdt_addr, 0); - r = efi_install_fdt(fdt); + r = efi_install_fdt(fdt_addr); if (r != EFI_SUCCESS) { printf("ERROR: failed to install device tree\n"); return CMD_RET_FAILURE; @@ -489,8 +532,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif #ifdef CONFIG_CMD_BOOTEFI_SELFTEST if (!strcmp(argv[1], "selftest")) { - struct efi_loaded_image loaded_image_info = {}; - struct efi_object loaded_image_info_obj = {}; + struct efi_loaded_image_obj *image_handle; + struct efi_loaded_image *loaded_image_info; /* Construct a dummy device path. */ bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, @@ -498,9 +541,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) (uintptr_t)&efi_selftest); bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest"); - efi_setup_loaded_image(&loaded_image_info, - &loaded_image_info_obj, - bootefi_device_path, bootefi_image_path); + r = efi_setup_loaded_image(bootefi_device_path, + bootefi_image_path, &image_handle, + &loaded_image_info); + if (r != EFI_SUCCESS) + return CMD_RET_FAILURE; + /* * gd lives in a fixed register which may get clobbered while we * execute the payload. So save it here and restore it on every @@ -508,12 +554,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ efi_save_gd(); /* Transfer environment variable efi_selftest as load options */ - set_load_options(&loaded_image_info, "efi_selftest"); + set_load_options(loaded_image_info, "efi_selftest"); /* Execute the test */ - r = efi_selftest(loaded_image_info_obj.handle, &systab); + r = efi_selftest(image_handle, &systab); efi_restore_gd(); - free(loaded_image_info.load_options); - list_del(&loaded_image_info_obj.link); + free(loaded_image_info->load_options); + efi_delete_handle(&image_handle->parent); return r != EFI_SUCCESS; } else #endif @@ -575,6 +621,13 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) char filename[32] = { 0 }; /* dp->str is u16[32] long */ char *s; + /* efi_set_bootdev is typically called repeatedly, recover memory */ + efi_free_pool(bootefi_device_path); + efi_free_pool(bootefi_image_path); + /* If blk_get_device_part_str fails, avoid duplicate free. */ + bootefi_device_path = NULL; + bootefi_image_path = NULL; + if (strcmp(dev, "Net")) { struct blk_desc *desc; disk_partition_t fs_partition; diff --git a/cmd/conitrace.c b/cmd/conitrace.c new file mode 100644 index 0000000000..85c5422b7e --- /dev/null +++ b/cmd/conitrace.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The 'conitrace' command prints the codes received from the console input as + * hexadecimal numbers. + * + * Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk@gmx.de> + */ +#include <common.h> +#include <command.h> + +static int do_conitrace(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + bool first = true; + + printf("Waiting for your input\n"); + printf("To terminate type 'x'\n"); + + /* Empty input buffer */ + while (tstc()) + getc(); + + for (;;) { + int c = getc(); + + if (first && (c == 'x' || c == 'X')) + break; + + printf("%02x ", c); + first = false; + + /* 1 ms delay - serves to detect separate keystrokes */ + udelay(1000); + if (!tstc()) { + printf("\n"); + first = true; + } + } + + return CMD_RET_SUCCESS; +} + +#ifdef CONFIG_SYS_LONGHELP +static char conitrace_help_text[] = ""; +#endif + +U_BOOT_CMD_COMPLETE( + conitrace, 2, 0, do_conitrace, + "trace console input", + conitrace_help_text, NULL +); @@ -104,6 +104,7 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, int ret; unsigned long addr; unsigned long count; + long offset; struct blk_desc *dev_desc = NULL; disk_partition_t info; int dev = 0; @@ -126,9 +127,11 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, } addr = simple_strtoul(argv[3], NULL, 16); count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16); + /* offset should be a hex, but "-1" is allowed */ + offset = (argc <= 6) ? 0 : simple_strtol(argv[6], NULL, 16); buf = map_sysmem(addr, count); - ret = file_fat_write(argv[4], buf, 0, count, &size); + ret = file_fat_write(argv[4], buf, offset, count, &size); unmap_sysmem(buf); if (ret < 0) { printf("\n** Unable to write \"%s\" from %s %d:%d **\n", @@ -142,10 +145,35 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, } U_BOOT_CMD( - fatwrite, 6, 0, do_fat_fswrite, + fatwrite, 7, 0, do_fat_fswrite, "write file into a dos filesystem", - "<interface> <dev[:part]> <addr> <filename> [<bytes>]\n" + "<interface> <dev[:part]> <addr> <filename> [<bytes> [<offset>]]\n" " - write file 'filename' from the address 'addr' in RAM\n" " to 'dev' on 'interface'" ); + +static int do_fat_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + return do_rm(cmdtp, flag, argc, argv, FS_TYPE_FAT); +} + +U_BOOT_CMD( + fatrm, 4, 1, do_fat_rm, + "delete a file", + "<interface> [<dev[:part]>] <filename>\n" + " - delete a file from 'dev' on 'interface'" +); + +static int do_fat_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return do_mkdir(cmdtp, flag, argc, argv, FS_TYPE_FAT); +} + +U_BOOT_CMD( + fatmkdir, 4, 1, do_fat_mkdir, + "create a directory", + "<interface> [<dev[:part]>] <directory>\n" + " - create a directory in 'dev' on 'interface'" +); #endif @@ -47,8 +47,7 @@ struct selected_dev { static struct selected_dev ubi_dev; #ifdef CONFIG_CMD_UBIFS -int ubifs_is_mounted(void); -void cmd_ubifs_umount(void); +#include <ubifs_uboot.h> #endif static void display_volume_info(struct ubi_device *ubi) diff --git a/cmd/ubifs.c b/cmd/ubifs.c index 11bab7a1a1..e4000b7ad1 100644 --- a/cmd/ubifs.c +++ b/cmd/ubifs.c @@ -19,16 +19,10 @@ static int ubifs_initialized; static int ubifs_mounted; -static int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) +int cmd_ubifs_mount(char *vol_name) { - char *vol_name; int ret; - if (argc != 2) - return CMD_RET_USAGE; - - vol_name = argv[1]; debug("Using volume %s\n", vol_name); if (ubifs_initialized == 0) { @@ -42,7 +36,19 @@ static int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, ubifs_mounted = 1; - return 0; + return ret; +} +static int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + char *vol_name; + + if (argc != 2) + return CMD_RET_USAGE; + + vol_name = argv[1]; + + return cmd_ubifs_mount(vol_name); } int ubifs_is_mounted(void) @@ -50,11 +56,18 @@ int ubifs_is_mounted(void) return ubifs_mounted; } -void cmd_ubifs_umount(void) +int cmd_ubifs_umount(void) { + if (ubifs_initialized == 0) { + printf("No UBIFS volume mounted!\n"); + return -1; + } + uboot_ubifs_umount(); ubifs_mounted = 0; ubifs_initialized = 0; + + return 0; } static int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc, @@ -63,14 +76,7 @@ static int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc, if (argc != 1) return CMD_RET_USAGE; - if (ubifs_initialized == 0) { - printf("No UBIFS volume mounted!\n"); - return -1; - } - - cmd_ubifs_umount(); - - return 0; + return cmd_ubifs_umount(); } static int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc, diff --git a/cmd/w1.c b/cmd/w1.c new file mode 100644 index 0000000000..9c95fcf9cd --- /dev/null +++ b/cmd/w1.c @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * (C) Copyright 2018 + * Microchip Technology, Inc. + * Eugen Hristev <eugen.hristev@microchip.com> + */ +#include <common.h> +#include <command.h> +#include <w1.h> +#include <w1-eeprom.h> +#include <dm/device-internal.h> + +static int w1_bus(void) +{ + struct udevice *bus, *dev; + int ret; + + ret = w1_get_bus(0, &bus); + if (ret) { + printf("one wire interface not found\n"); + return CMD_RET_FAILURE; + } + printf("Bus %d:\t%s", bus->seq, bus->name); + if (device_active(bus)) + printf(" (active)"); + printf("\n"); + + for (device_find_first_child(bus, &dev); + dev; + device_find_next_child(&dev)) { + ret = device_probe(dev); + + printf("\t%s (%d) uclass %s : ", dev->name, dev->seq, + dev->uclass->uc_drv->name); + + if (ret) + printf("device error\n"); + else + printf("family 0x%x\n", w1_get_device_family(dev)); + } + return CMD_RET_SUCCESS; +} + +static int w1_read(int argc, char *const argv[]) +{ + int bus_n = 0, dev_n = 0, offset = 0, len = 512; + int i; + struct udevice *bus, *dev; + int ret; + u8 buf[512]; + + if (argc > 2) + bus_n = simple_strtoul(argv[2], NULL, 10); + + if (argc > 3) + dev_n = simple_strtoul(argv[3], NULL, 10); + + if (argc > 4) + offset = simple_strtoul(argv[4], NULL, 10); + + if (argc > 5) + len = simple_strtoul(argv[5], NULL, 10); + + if (len > 512) { + printf("len needs to be <= 512\n"); + return CMD_RET_FAILURE; + } + + ret = w1_get_bus(bus_n, &bus); + if (ret) { + printf("one wire interface not found\n"); + return CMD_RET_FAILURE; + } + + for (device_find_first_child(bus, &dev), i = 0; + dev && i <= dev_n; + device_find_next_child(&dev), i++) { + ret = device_probe(dev); + if (!ret && i == dev_n) + break; + } + + if (i != dev_n || ret || !dev) { + printf("invalid dev\n"); + return CMD_RET_FAILURE; + } + + if (strcmp(dev->uclass->uc_drv->name, "w1_eeprom")) { + printf("the device present on the interface is of unknown device class\n"); + return CMD_RET_FAILURE; + } + + ret = w1_eeprom_read_buf(dev, offset, (u8 *)buf, len); + if (ret) { + printf("error reading device %s\n", dev->name); + return CMD_RET_FAILURE; + } + + for (i = 0; i < len; i++) + printf("%x", buf[i]); + printf("\n"); + + return CMD_RET_SUCCESS; +} + +int do_w1(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + if (argc < 2) + return CMD_RET_USAGE; + + if (!strcmp(argv[1], "bus")) + return w1_bus(); + + if (!strcmp(argv[1], "read")) + return w1_read(argc, argv); + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(w1, 6, 0, do_w1, + "onewire interface utility commands", + "bus - show onewire bus info (all)\n" + "w1 read [<bus> [<dev> [offset [length]]]]" + " - read from onewire device 'dev' on onewire bus 'bus'" + " starting from offset 'offset' and length 'length'\n" + " defaults: bus 0, dev 0, offset 0, length 512 bytes."); diff --git a/common/Kconfig b/common/Kconfig index 3030da4fc9..41f27a1338 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -259,6 +259,11 @@ config CONSOLE_RECORD_IN_SIZE The buffer is allocated immediately after the malloc() region is ready. +config DISABLE_CONSOLE + bool "Add functionality to disable console completely" + help + Disable console (in & out). + config IDENT_STRING string "Board specific string to be added to uboot version string" help @@ -557,7 +562,7 @@ config VERSION_VARIABLE next reset. config BOARD_LATE_INIT - bool + bool "Execute Board late init" help Sometimes board require some initialization code that might require once the actual init done, example saving board specific env, diff --git a/common/bootm.c b/common/bootm.c index e517d9f118..8bf84ebcb7 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -262,7 +262,7 @@ int bootm_find_images(int flag, int argc, char * const argv[]) puts("Could not find a valid device tree\n"); return 1; } - set_working_fdt_addr((ulong)images.ft_addr); + set_working_fdt_addr(map_to_sysmem(images.ft_addr)); #endif #if IMAGE_ENABLE_FIT diff --git a/common/image-fdt.c b/common/image-fdt.c index 9b41f16248..95748f0ae1 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -193,7 +193,7 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size) *of_flat_tree = of_start; *of_size = of_len; - set_working_fdt_addr((ulong)*of_flat_tree); + set_working_fdt_addr(map_to_sysmem(*of_flat_tree)); return 0; error: diff --git a/common/spl/spl.c b/common/spl/spl.c index 19508c7168..038f2b0e83 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -127,6 +127,11 @@ __weak void spl_board_prepare_for_boot(void) /* Nothing to do! */ } +__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) +{ + return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset); +} + void spl_set_header_raw_uboot(struct spl_image_info *spl_image) { ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos); diff --git a/common/spl/spl_ext.c b/common/spl/spl_ext.c index fd30a61f9a..fe05223605 100644 --- a/common/spl/spl_ext.c +++ b/common/spl/spl_ext.c @@ -16,8 +16,7 @@ int spl_load_image_ext(struct spl_image_info *spl_image, loff_t filelen, actlen; disk_partition_t part_info = {}; - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - - sizeof(struct image_header)); + header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); if (part_get_info(block_dev, partition, &part_info)) { printf("spl: no partition table found\n"); diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c index 0403016bb4..163e540622 100644 --- a/common/spl/spl_fat.c +++ b/common/spl/spl_fat.c @@ -63,8 +63,7 @@ int spl_load_image_fat(struct spl_image_info *spl_image, if (err) goto end; - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - - sizeof(struct image_header)); + header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); err = file_fat_read(filename, header, sizeof(struct image_header)); if (err <= 0) diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 9eabb1c105..cb0cc5299b 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -257,10 +257,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, board_fit_image_post_process(&src, &length); #endif - if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && - IS_ENABLED(CONFIG_SPL_GZIP) && - image_comp == IH_COMP_GZIP && - type == IH_TYPE_KERNEL) { + if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) { size = length; if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN, src, &size)) { @@ -357,7 +354,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_image_info image_info; int node = -1; int images, ret; - int base_offset, align_len = ARCH_DMA_MINALIGN - 1; + int base_offset, hsize, align_len = ARCH_DMA_MINALIGN - 1; int index = 0; /* @@ -386,8 +383,8 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, * For FIT with data embedded, data is loaded as part of FIT image. * For FIT with external data, data is not loaded in this step. */ - fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len - - align_len) & ~align_len); + hsize = (size + info->bl_len + align_len) & ~align_len; + fit = spl_get_load_buffer(-hsize, hsize); sectors = get_aligned_image_size(info, size, 0); count = info->read(info, sector, sectors, fit); debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n", diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 0b2f059570..75c41598e6 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -55,13 +55,13 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image, { unsigned long count; struct image_header *header; + struct blk_desc *bd = mmc_get_blk_desc(mmc); int ret = 0; - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - - sizeof(struct image_header)); + header = spl_get_load_buffer(-sizeof(*header), bd->blksz); /* read image header to find the image size & load address */ - count = blk_dread(mmc_get_blk_desc(mmc), sector, 1, header); + count = blk_dread(bd, sector, 1, header); debug("hdr read sector %lx, count=%lu\n", sector, count); if (count == 0) { ret = -EIO; diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 2722fd3860..6eb190f1ea 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -83,8 +83,8 @@ static int spl_nand_load_image(struct spl_image_info *spl_image, #endif nand_init(); - /*use CONFIG_SYS_TEXT_BASE as temporary storage area */ - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); + header = spl_get_load_buffer(0, sizeof(*header)); + #ifdef CONFIG_SPL_OS_BOOT if (!spl_start_uboot()) { /* diff --git a/common/spl/spl_onenand.c b/common/spl/spl_onenand.c index d32333935a..ee30f328e6 100644 --- a/common/spl/spl_onenand.c +++ b/common/spl/spl_onenand.c @@ -21,8 +21,7 @@ static int spl_onenand_load_image(struct spl_image_info *spl_image, debug("spl: onenand\n"); - /*use CONFIG_SYS_TEXT_BASE as temporary storage area */ - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); + header = spl_get_load_buffer(0, CONFIG_SYS_ONENAND_PAGE_SIZE); /* Load u-boot */ onenand_spl_load_image(CONFIG_SYS_ONENAND_U_BOOT_OFFS, CONFIG_SYS_ONENAND_PAGE_SIZE, (void *)header); diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c index e594beaeaa..619b39a537 100644 --- a/common/spl/spl_ram.c +++ b/common/spl/spl_ram.c @@ -63,8 +63,9 @@ static int spl_ram_load_image(struct spl_image_info *spl_image, * No binman support or no information. For now, fix it * to the address pointed to by U-Boot. */ - u_boot_pos = CONFIG_SYS_TEXT_BASE - - sizeof(struct image_header); + header = spl_get_load_buffer(-sizeof(*header), + sizeof(*header)); + } header = (struct image_header *)map_sysmem(u_boot_pos, 0); diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index ba60a3a3c5..e10cf0124f 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -88,8 +88,7 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, return -ENODEV; } - /* use CONFIG_SYS_TEXT_BASE as temporary storage area */ - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); + header = spl_get_load_buffer(-sizeof(*header), 0x40); #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) payload_offs = fdtdec_get_config_int(gd->fdt_blob, diff --git a/common/spl/spl_ubi.c b/common/spl/spl_ubi.c index a7939e9030..67e5fadd7c 100644 --- a/common/spl/spl_ubi.c +++ b/common/spl/spl_ubi.c @@ -61,8 +61,7 @@ int spl_ubi_load_image(struct spl_image_info *spl_image, puts("Loading Linux failed, falling back to U-Boot.\n"); } #endif - header = (struct image_header *) - (CONFIG_SYS_TEXT_BASE - sizeof(struct image_header)); + header = spl_get_load_buffer(-sizeof(*header), sizeof(header)); volumes[0].vol_id = CONFIG_SPL_UBI_LOAD_MONITOR_ID; volumes[0].load_addr = (void *)header; diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig index 291d569f46..2fc21842d5 100644 --- a/configs/am335x_evm_defconfig +++ b/configs/am335x_evm_defconfig @@ -5,6 +5,7 @@ CONFIG_AM33XX=y CONFIG_SPL=y CONFIG_DISTRO_DEFAULTS=y CONFIG_SPL_LOAD_FIT=y +CONFIG_OF_BOARD_SETUP=y CONFIG_BOOTCOMMAND="if test ${boot_fit} -eq 1; then run update_to_fit; fi; run findfdt; run init_console; run envboot; run distro_bootcmd" CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_VERSION_VARIABLE=y diff --git a/configs/am3517_evm_defconfig b/configs/am3517_evm_defconfig index 96491f37b2..e334030e51 100644 --- a/configs/am3517_evm_defconfig +++ b/configs/am3517_evm_defconfig @@ -38,6 +38,7 @@ CONFIG_DEFAULT_DEVICE_TREE="am3517-evm" CONFIG_SPL_OF_PLATDATA=y # CONFIG_ENV_IS_IN_FAT is not set CONFIG_ENV_IS_IN_NAND=y +CONFIG_DM_PCA953X=y CONFIG_MMC_OMAP_HS=y CONFIG_NAND=y CONFIG_SYS_NAND_BUSWIDTH_16BIT=y @@ -47,6 +48,8 @@ CONFIG_SPL_NAND_SIMPLE=y CONFIG_MII=y CONFIG_DRIVER_TI_EMAC=y # CONFIG_TWL4030_POWER is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SINGLE=y CONFIG_CONS_INDEX=3 CONFIG_SYS_NS16550=y CONFIG_SPI=y diff --git a/configs/bcm968380gerg_ram_defconfig b/configs/bcm968380gerg_ram_defconfig index 4943c8af3b..8b2b3183e6 100644 --- a/configs/bcm968380gerg_ram_defconfig +++ b/configs/bcm968380gerg_ram_defconfig @@ -39,6 +39,7 @@ CONFIG_SPI_FLASH=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_PHY=y CONFIG_BCM6368_USBH_PHY=y +CONFIG_PINCTRL=y CONFIG_POWER_DOMAIN=y CONFIG_BCM6328_POWER_DOMAIN=y CONFIG_DM_RESET=y diff --git a/configs/da850evm_defconfig b/configs/da850evm_defconfig index c30f396e65..6dc70dd387 100644 --- a/configs/da850evm_defconfig +++ b/configs/da850evm_defconfig @@ -24,6 +24,7 @@ CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT="U-Boot > " CONFIG_CRC32_VERIFY=y # CONFIG_CMD_EEPROM is not set +CONFIG_CMD_DM=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_GPT is not set # CONFIG_CMD_PART is not set @@ -50,6 +51,8 @@ CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SINGLE=y CONFIG_SPI_FLASH_MTD=y CONFIG_MII=y CONFIG_DRIVER_TI_EMAC=y diff --git a/configs/da850evm_direct_nor_defconfig b/configs/da850evm_direct_nor_defconfig index 4039d0ee59..8ea522af93 100644 --- a/configs/da850evm_direct_nor_defconfig +++ b/configs/da850evm_direct_nor_defconfig @@ -5,7 +5,6 @@ CONFIG_TARGET_DA850EVM=y CONFIG_DA850_LOWLEVEL=y CONFIG_TI_COMMON_CMD_OPTIONS=y CONFIG_NR_DRAM_BANKS=1 -# CONFIG_SYS_MALLOC_F is not set CONFIG_SYS_EXTRA_OPTIONS="USE_NOR,DIRECT_NOR_BOOT" CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y @@ -21,6 +20,7 @@ CONFIG_SYS_PROMPT="U-Boot > " CONFIG_CMD_IMLS=y CONFIG_CRC32_VERIFY=y # CONFIG_CMD_EEPROM is not set +CONFIG_CMD_DM=y # CONFIG_CMD_GPIO is not set # CONFIG_CMD_GPT is not set # CONFIG_CMD_MMC is not set @@ -48,8 +48,12 @@ CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SINGLE=y CONFIG_MII=y CONFIG_DRIVER_TI_EMAC=y +CONFIG_SPECIFY_CONSOLE_INDEX=y +CONFIG_DM_SERIAL=y CONFIG_SYS_NS16550=y CONFIG_SPI=y CONFIG_DM_SPI=y diff --git a/configs/da850evm_nand_defconfig b/configs/da850evm_nand_defconfig index 11d6a2b4c5..d13d832e81 100644 --- a/configs/da850evm_nand_defconfig +++ b/configs/da850evm_nand_defconfig @@ -24,6 +24,7 @@ CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT="U-Boot > " CONFIG_CRC32_VERIFY=y # CONFIG_CMD_EEPROM is not set +CONFIG_CMD_DM=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_GPT is not set CONFIG_CMD_NAND=y @@ -51,6 +52,8 @@ CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SPI_FLASH_MTD=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SINGLE=y CONFIG_DM_SERIAL=y CONFIG_SYS_NS16550=y CONFIG_SPI=y diff --git a/configs/gardena-smart-gateway-mt7688-ram_defconfig b/configs/gardena-smart-gateway-mt7688-ram_defconfig new file mode 100644 index 0000000000..0e2f158518 --- /dev/null +++ b/configs/gardena-smart-gateway-mt7688-ram_defconfig @@ -0,0 +1,55 @@ +CONFIG_MIPS=y +CONFIG_SYS_TEXT_BASE=0x80010000 +CONFIG_ARCH_MT7620=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_XIMG is not set +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_MTDIDS_DEFAULT="spi-nand0=spi-nand0" +CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:-(ubi)" +CONFIG_CMD_UBI=y +CONFIG_OF_EMBED=y +CONFIG_DEFAULT_DEVICE_TREE="gardena-smart-gateway-mt7688" +CONFIG_ENV_IS_IN_SPI_FLASH=y +# CONFIG_DM_DEVICE_REMOVE is not set +CONFIG_HAVE_BLOCK_DEVICE=y +CONFIG_CLK=y +CONFIG_CPU=y +CONFIG_DM_GPIO=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_MTD=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY=y +CONFIG_POWER_DOMAIN=y +CONFIG_RAM=y +CONFIG_DM_RESET=y +CONFIG_BAUDRATE=57600 +# CONFIG_SPL_SERIAL_PRESENT is not set +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_SYSRESET_SYSCON=y diff --git a/configs/gardena-smart-gateway-mt7688_defconfig b/configs/gardena-smart-gateway-mt7688_defconfig new file mode 100644 index 0000000000..1213227758 --- /dev/null +++ b/configs/gardena-smart-gateway-mt7688_defconfig @@ -0,0 +1,58 @@ +CONFIG_MIPS=y +CONFIG_SYS_TEXT_BASE=0x9c000000 +CONFIG_ARCH_MT7620=y +CONFIG_BOOT_ROM=y +CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y +CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_XIMG is not set +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_MTDIDS_DEFAULT="spi-nand0=spi-nand0" +CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:-(ubi)" +CONFIG_CMD_UBI=y +CONFIG_OF_EMBED=y +CONFIG_DEFAULT_DEVICE_TREE="gardena-smart-gateway-mt7688" +CONFIG_ENV_IS_IN_SPI_FLASH=y +# CONFIG_DM_DEVICE_REMOVE is not set +CONFIG_HAVE_BLOCK_DEVICE=y +CONFIG_CLK=y +CONFIG_CPU=y +CONFIG_DM_GPIO=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_MTD=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY=y +CONFIG_POWER_DOMAIN=y +CONFIG_RAM=y +CONFIG_DM_RESET=y +CONFIG_BAUDRATE=57600 +# CONFIG_SPL_SERIAL_PRESENT is not set +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_SYSRESET_SYSCON=y diff --git a/configs/linkit-smart-7688-ram_defconfig b/configs/linkit-smart-7688-ram_defconfig new file mode 100644 index 0000000000..77cd1c1575 --- /dev/null +++ b/configs/linkit-smart-7688-ram_defconfig @@ -0,0 +1,51 @@ +CONFIG_MIPS=y +CONFIG_SYS_TEXT_BASE=0x80010000 +CONFIG_ARCH_MT7620=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_XIMG is not set +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_OF_EMBED=y +CONFIG_DEFAULT_DEVICE_TREE="linkit-smart-7688" +CONFIG_ENV_IS_IN_SPI_FLASH=y +# CONFIG_DM_DEVICE_REMOVE is not set +CONFIG_HAVE_BLOCK_DEVICE=y +CONFIG_CLK=y +CONFIG_CPU=y +CONFIG_DM_GPIO=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY=y +CONFIG_POWER_DOMAIN=y +CONFIG_RAM=y +CONFIG_DM_RESET=y +CONFIG_BAUDRATE=57600 +# CONFIG_SPL_SERIAL_PRESENT is not set +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_SYSRESET_SYSCON=y diff --git a/configs/linkit-smart-7688_defconfig b/configs/linkit-smart-7688_defconfig new file mode 100644 index 0000000000..62cdda1e0a --- /dev/null +++ b/configs/linkit-smart-7688_defconfig @@ -0,0 +1,55 @@ +CONFIG_MIPS=y +CONFIG_SYS_TEXT_BASE=0x9c000000 +CONFIG_ARCH_MT7620=y +CONFIG_BOOT_ROM=y +CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y +CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_CRC32 is not set +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_OF_EMBED=y +CONFIG_DEFAULT_DEVICE_TREE="linkit-smart-7688" +CONFIG_ENV_IS_IN_SPI_FLASH=y +# CONFIG_DM_DEVICE_REMOVE is not set +CONFIG_HAVE_BLOCK_DEVICE=y +CONFIG_CLK=y +CONFIG_CPU=y +CONFIG_DM_GPIO=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY=y +CONFIG_POWER_DOMAIN=y +CONFIG_RAM=y +CONFIG_DM_RESET=y +CONFIG_BAUDRATE=57600 +# CONFIG_SPL_SERIAL_PRESENT is not set +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_SYSRESET_SYSCON=y diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index 2df35a8082..7fd726fdda 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -8,6 +8,7 @@ CONFIG_DISTRO_DEFAULTS=y CONFIG_NR_DRAM_BANKS=1 # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_CMD_BOOTEFI_SELFTEST=y CONFIG_CMD_PCI=y CONFIG_CMD_USB=y CONFIG_CMD_DATE=y diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig index 2865599c62..fbceaf3c52 100644 --- a/configs/qemu_arm_defconfig +++ b/configs/qemu_arm_defconfig @@ -8,6 +8,7 @@ CONFIG_DISTRO_DEFAULTS=y CONFIG_NR_DRAM_BANKS=1 # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_CMD_BOOTEFI_SELFTEST=y CONFIG_CMD_PCI=y CONFIG_CMD_USB=y CONFIG_CMD_DATE=y diff --git a/configs/sama5d27_som1_ek_mmc1_defconfig b/configs/sama5d27_som1_ek_mmc1_defconfig new file mode 100644 index 0000000000..0ac2445887 --- /dev/null +++ b/configs/sama5d27_som1_ek_mmc1_defconfig @@ -0,0 +1,91 @@ +CONFIG_ARM=y +CONFIG_ARCH_AT91=y +CONFIG_SYS_TEXT_BASE=0x23f00000 +CONFIG_TARGET_SAMA5D27_SOM1_EK=y +CONFIG_SPL_GPIO_SUPPORT=y +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SPL_MMC_SUPPORT=y +CONFIG_SPL_SERIAL_SUPPORT=y +CONFIG_SPL_DRIVERS_MISC_SUPPORT=y +CONFIG_SPL=y +CONFIG_DEBUG_UART_BOARD_INIT=y +CONFIG_DEBUG_UART_BASE=0xf8020000 +CONFIG_DEBUG_UART_CLOCK=82000000 +CONFIG_SPL_FAT_SUPPORT=y +CONFIG_SPL_LIBDISK_SUPPORT=y +CONFIG_DEFAULT_DEVICE_TREE="at91-sama5d27_som1_ek" +CONFIG_DEBUG_UART=y +CONFIG_ENV_VARS_UBOOT_CONFIG=y +CONFIG_FIT=y +CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2" +CONFIG_SD_BOOT=y +CONFIG_BOOTDELAY=3 +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk1p2 rw rootwait" +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_SPL_SEPARATE_BSS=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_I2C=y +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_FAT=y +CONFIG_OF_CONTROL=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-parent dmas dma-names" +CONFIG_ENV_IS_IN_FAT=y +CONFIG_ENV_FAT_DEVICE_AND_PART="1" +CONFIG_DM=y +CONFIG_SPL_DM=y +CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_CLK=y +CONFIG_SPL_CLK=y +CONFIG_CLK_AT91=y +CONFIG_AT91_UTMI=y +CONFIG_AT91_H32MX=y +CONFIG_AT91_GENERIC_CLK=y +CONFIG_DM_GPIO=y +CONFIG_ATMEL_PIO4=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_AT91=y +CONFIG_I2C_EEPROM=y +CONFIG_DM_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ATMEL=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_DM_ETH=y +CONFIG_MACB=y +CONFIG_PINCTRL=y +CONFIG_SPL_PINCTRL=y +CONFIG_PINCTRL_AT91PIO4=y +CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_ATMEL=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_ATMEL_USART=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_TIMER=y +CONFIG_SPL_TIMER=y +CONFIG_ATMEL_PIT_TIMER=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_ATMEL_USBA=y +CONFIG_DM_VIDEO=y +CONFIG_ATMEL_HLCD=y diff --git a/configs/sama5d27_som1_ek_mmc_defconfig b/configs/sama5d27_som1_ek_mmc_defconfig index 56c7252841..fbde79c4ef 100644 --- a/configs/sama5d27_som1_ek_mmc_defconfig +++ b/configs/sama5d27_som1_ek_mmc_defconfig @@ -22,6 +22,8 @@ CONFIG_FIT=y CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2" CONFIG_SD_BOOT=y CONFIG_BOOTDELAY=3 +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait" CONFIG_MISC_INIT_R=y # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_SEPARATE_BSS=y @@ -88,3 +90,8 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_ATMEL_USBA=y CONFIG_DM_VIDEO=y CONFIG_ATMEL_HLCD=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d2_ptc_ek_mmc_defconfig b/configs/sama5d2_ptc_ek_mmc_defconfig index 42f0c95b79..60df0f0062 100644 --- a/configs/sama5d2_ptc_ek_mmc_defconfig +++ b/configs/sama5d2_ptc_ek_mmc_defconfig @@ -63,3 +63,8 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_STORAGE=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d2_ptc_ek_nandflash_defconfig b/configs/sama5d2_ptc_ek_nandflash_defconfig index c4b308596e..4e39406a24 100644 --- a/configs/sama5d2_ptc_ek_nandflash_defconfig +++ b/configs/sama5d2_ptc_ek_nandflash_defconfig @@ -62,3 +62,8 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_STORAGE=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d2_xplained_emmc_defconfig b/configs/sama5d2_xplained_emmc_defconfig new file mode 100644 index 0000000000..ca5d4f4221 --- /dev/null +++ b/configs/sama5d2_xplained_emmc_defconfig @@ -0,0 +1,88 @@ +CONFIG_ARM=y +CONFIG_ARCH_AT91=y +CONFIG_SYS_TEXT_BASE=0x26f00000 +CONFIG_TARGET_SAMA5D2_XPLAINED=y +CONFIG_SPL_GPIO_SUPPORT=y +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SPL_MMC_SUPPORT=y +CONFIG_SPL_SERIAL_SUPPORT=y +CONFIG_SPL_DRIVERS_MISC_SUPPORT=y +CONFIG_SPL=y +CONFIG_DEBUG_UART_BOARD_INIT=y +CONFIG_DEBUG_UART_BASE=0xf8020000 +CONFIG_DEBUG_UART_CLOCK=83000000 +CONFIG_SPL_FAT_SUPPORT=y +CONFIG_SPL_LIBDISK_SUPPORT=y +CONFIG_DEFAULT_DEVICE_TREE="at91-sama5d2_xplained" +CONFIG_DEBUG_UART=y +CONFIG_ENV_VARS_UBOOT_CONFIG=y +CONFIG_FIT=y +CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2,SYS_USE_MMC" +CONFIG_SD_BOOT=y +CONFIG_BOOTDELAY=3 +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait" +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_SPL_SEPARATE_BSS=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_I2C=y +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_FAT=y +CONFIG_OF_CONTROL=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-parent dmas dma-names" +CONFIG_ENV_IS_IN_FAT=y +CONFIG_ENV_FAT_DEVICE_AND_PART="0:1" +CONFIG_DM=y +CONFIG_SPL_DM=y +CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_CLK=y +CONFIG_SPL_CLK=y +CONFIG_CLK_AT91=y +CONFIG_AT91_UTMI=y +CONFIG_AT91_H32MX=y +CONFIG_AT91_GENERIC_CLK=y +CONFIG_DM_GPIO=y +CONFIG_ATMEL_PIO4=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_AT91=y +CONFIG_I2C_EEPROM=y +CONFIG_DM_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ATMEL=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_DM_ETH=y +CONFIG_MACB=y +CONFIG_PINCTRL=y +CONFIG_SPL_PINCTRL=y +CONFIG_PINCTRL_AT91PIO4=y +CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_ATMEL=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_ATMEL_USART=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_TIMER=y +CONFIG_SPL_TIMER=y +CONFIG_ATMEL_PIT_TIMER=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_ATMEL_USBA=y +CONFIG_DM_VIDEO=y +CONFIG_ATMEL_HLCD=y diff --git a/configs/sama5d2_xplained_mmc_defconfig b/configs/sama5d2_xplained_mmc_defconfig index 77dc82ce0c..f8748f8c84 100644 --- a/configs/sama5d2_xplained_mmc_defconfig +++ b/configs/sama5d2_xplained_mmc_defconfig @@ -88,3 +88,8 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_ATMEL_USBA=y CONFIG_DM_VIDEO=y CONFIG_ATMEL_HLCD=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d2_xplained_spiflash_defconfig b/configs/sama5d2_xplained_spiflash_defconfig index fc9ec9c80a..efe71769a4 100644 --- a/configs/sama5d2_xplained_spiflash_defconfig +++ b/configs/sama5d2_xplained_spiflash_defconfig @@ -85,3 +85,8 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_ATMEL_USBA=y CONFIG_DM_VIDEO=y CONFIG_ATMEL_HLCD=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d3_xplained_mmc_defconfig b/configs/sama5d3_xplained_mmc_defconfig index 7f2d276b29..154cdc2189 100644 --- a/configs/sama5d3_xplained_mmc_defconfig +++ b/configs/sama5d3_xplained_mmc_defconfig @@ -76,3 +76,8 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_STORAGE=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d3_xplained_nandflash_defconfig b/configs/sama5d3_xplained_nandflash_defconfig index ac8435e4dd..3bf93de9c0 100644 --- a/configs/sama5d3_xplained_nandflash_defconfig +++ b/configs/sama5d3_xplained_nandflash_defconfig @@ -72,4 +72,9 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_STORAGE=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y CONFIG_FAT_WRITE=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d4_xplained_mmc_defconfig b/configs/sama5d4_xplained_mmc_defconfig index 89393a979e..f60b6b5bc9 100644 --- a/configs/sama5d4_xplained_mmc_defconfig +++ b/configs/sama5d4_xplained_mmc_defconfig @@ -84,3 +84,8 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_ATMEL_USBA=y CONFIG_DM_VIDEO=y CONFIG_ATMEL_HLCD=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d4_xplained_nandflash_defconfig b/configs/sama5d4_xplained_nandflash_defconfig index 5387966316..3524dbffcf 100644 --- a/configs/sama5d4_xplained_nandflash_defconfig +++ b/configs/sama5d4_xplained_nandflash_defconfig @@ -80,3 +80,8 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_ATMEL_USBA=y CONFIG_DM_VIDEO=y CONFIG_ATMEL_HLCD=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sama5d4_xplained_spiflash_defconfig b/configs/sama5d4_xplained_spiflash_defconfig index 39c86ecd9b..3f519cd503 100644 --- a/configs/sama5d4_xplained_spiflash_defconfig +++ b/configs/sama5d4_xplained_spiflash_defconfig @@ -84,3 +84,8 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_ATMEL_USBA=y CONFIG_DM_VIDEO=y CONFIG_ATMEL_HLCD=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_DS24XXX=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index ca121182d6..fb71998235 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -23,6 +23,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTEFI_SELFTEST=y # CONFIG_CMD_ELF is not set CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y @@ -191,6 +192,10 @@ CONFIG_CONSOLE_ROTATION=y CONFIG_CONSOLE_TRUETYPE=y CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_SANDBOX=y CONFIG_WDT=y CONFIG_WDT_SANDBOX=y CONFIG_FS_CBFS=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index e134a66fb1..3bf7538089 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -24,6 +24,8 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y @@ -36,6 +38,8 @@ CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_DM_MMC=y CONFIG_STM32_SDMMC2=y +CONFIG_PHY=y +CONFIG_PHY_STM32_USBPHYC=y # CONFIG_PINCTRL_FULL is not set # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_DM_PMIC=y @@ -47,3 +51,15 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMU1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_DWC2=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" +CONFIG_USB_GADGET_VENDOR_NUM=0x0483 +CONFIG_USB_GADGET_PRODUCT_NUM=0x5720 +CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/vf610twr_defconfig b/configs/vf610twr_defconfig index 59066a36a9..3f38c8813b 100644 --- a/configs/vf610twr_defconfig +++ b/configs/vf610twr_defconfig @@ -39,3 +39,4 @@ CONFIG_PHY_MICREL=y CONFIG_MII=y CONFIG_DM_SERIAL=y CONFIG_FSL_LPUART=y +# CONFIG_EFI_UNICODE_CAPITALIZATION is not set diff --git a/configs/vf610twr_nand_defconfig b/configs/vf610twr_nand_defconfig index 5b269fdaf6..d6e318f58c 100644 --- a/configs/vf610twr_nand_defconfig +++ b/configs/vf610twr_nand_defconfig @@ -39,3 +39,4 @@ CONFIG_PHY_MICREL=y CONFIG_MII=y CONFIG_DM_SERIAL=y CONFIG_FSL_LPUART=y +# CONFIG_EFI_UNICODE_CAPITALIZATION is not set diff --git a/configs/xilinx_zynqmp_mini_emmc0_defconfig b/configs/xilinx_zynqmp_mini_emmc0_defconfig index 19bb70800b..c0ec79c98c 100644 --- a/configs/xilinx_zynqmp_mini_emmc0_defconfig +++ b/configs/xilinx_zynqmp_mini_emmc0_defconfig @@ -9,6 +9,7 @@ CONFIG_NR_DRAM_BANKS=1 CONFIG_FIT=y CONFIG_BOOTDELAY=-1 CONFIG_SUPPORT_RAW_INITRD=y +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_R=y # CONFIG_CMDLINE_EDITING is not set diff --git a/configs/xilinx_zynqmp_mini_emmc1_defconfig b/configs/xilinx_zynqmp_mini_emmc1_defconfig index 041bd0c246..c1f5e64a04 100644 --- a/configs/xilinx_zynqmp_mini_emmc1_defconfig +++ b/configs/xilinx_zynqmp_mini_emmc1_defconfig @@ -9,6 +9,7 @@ CONFIG_NR_DRAM_BANKS=1 CONFIG_FIT=y CONFIG_BOOTDELAY=-1 CONFIG_SUPPORT_RAW_INITRD=y +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_R=y # CONFIG_CMDLINE_EDITING is not set diff --git a/configs/xilinx_zynqmp_mini_nand_defconfig b/configs/xilinx_zynqmp_mini_nand_defconfig index d597e09ce5..e119ec1c3b 100644 --- a/configs/xilinx_zynqmp_mini_nand_defconfig +++ b/configs/xilinx_zynqmp_mini_nand_defconfig @@ -9,6 +9,7 @@ CONFIG_NR_DRAM_BANKS=1 CONFIG_FIT=y CONFIG_BOOTDELAY=-1 CONFIG_SUPPORT_RAW_INITRD=y +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_R=y # CONFIG_CMDLINE_EDITING is not set diff --git a/configs/xilinx_zynqmp_mini_qspi_defconfig b/configs/xilinx_zynqmp_mini_qspi_defconfig index d557139192..9fcc7c2ea3 100644 --- a/configs/xilinx_zynqmp_mini_qspi_defconfig +++ b/configs/xilinx_zynqmp_mini_qspi_defconfig @@ -9,6 +9,7 @@ CONFIG_ZYNQMP_NO_DDR=y CONFIG_NR_DRAM_BANKS=1 # CONFIG_IMAGE_FORMAT_LEGACY is not set CONFIG_BOOTDELAY=-1 +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_CMDLINE_EDITING is not set # CONFIG_AUTO_COMPLETE is not set diff --git a/configs/zynq_cse_nand_defconfig b/configs/zynq_cse_nand_defconfig index ae5a69676d..44ad5bd69c 100644 --- a/configs/zynq_cse_nand_defconfig +++ b/configs/zynq_cse_nand_defconfig @@ -6,6 +6,7 @@ CONFIG_ENV_SIZE=0x190 CONFIG_SPL=y CONFIG_SPL_STACK_R_ADDR=0x200000 CONFIG_SYS_MALLOC_LEN=0x1000 +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_cse_nor_defconfig b/configs/zynq_cse_nor_defconfig index ce5085285d..1f81c0bf74 100644 --- a/configs/zynq_cse_nor_defconfig +++ b/configs/zynq_cse_nor_defconfig @@ -7,6 +7,7 @@ CONFIG_SPL=y CONFIG_SPL_STACK_R_ADDR=0x200000 CONFIG_SYS_MALLOC_LEN=0x1000 CONFIG_BOOTDELAY=-1 +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_cse_qspi_defconfig b/configs/zynq_cse_qspi_defconfig index 02f1a259ca..2e1e34d0ae 100644 --- a/configs/zynq_cse_qspi_defconfig +++ b/configs/zynq_cse_qspi_defconfig @@ -15,6 +15,7 @@ CONFIG_DISTRO_DEFAULTS=y # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set CONFIG_BOOTDELAY=-1 # CONFIG_USE_BOOTCOMMAND is not set +# CONFIG_BOARD_LATE_INIT is not set # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_ARCH_EARLY_INIT_R is not set CONFIG_SPL_STACK_R=y diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig index 46a8f5a0de..82931713a2 100644 --- a/configs/zynq_zybo_defconfig +++ b/configs/zynq_zybo_defconfig @@ -72,3 +72,4 @@ CONFIG_USB_GADGET_PRODUCT_NUM=0x0300 CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_USB_FUNCTION_THOR=y +CONFIG_DISPLAY=y diff --git a/doc/device-tree-bindings/chosen.txt b/doc/device-tree-bindings/chosen.txt index da7b4e6c45..86c533ad6d 100644 --- a/doc/device-tree-bindings/chosen.txt +++ b/doc/device-tree-bindings/chosen.txt @@ -83,3 +83,24 @@ of where said later stage was booted from. You should not define this property yourself in the device-tree, as it may be overwritten without warning. + +firmware-loader property +------------------------ +Multiple file system firmware loader nodes could be defined in device trees for +multiple storage type and their default partition, then a property +"firmware-loader" can be used to pass default firmware loader +node(default storage type) to the firmware loader driver. + +Example +------- +/ { + chosen { + firmware-loader = &fs_loader0; + }; + + fs_loader0: fs-loader@0 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + phandlepart = <&mmc 1>; + }; +}; diff --git a/doc/device-tree-bindings/misc/fs_loader.txt b/doc/device-tree-bindings/misc/fs_loader.txt new file mode 100644 index 0000000000..884fbf47c0 --- /dev/null +++ b/doc/device-tree-bindings/misc/fs_loader.txt @@ -0,0 +1,48 @@ +* File system firmware loader + +Required properties: +-------------------- + +- compatible: should contain "u-boot,fs-loader" +- phandlepart: which block storage device and partition the image loading from, + this property is required for mmc, usb and sata. This is unsigned + 32-bit array. For example phandlepart=<&mmc_0 1>, meaning use + that MMC0 node pointer, partition 1. +- mdtpart: which partition of ubi the image loading from, this property is + required for ubi and mounting. +- ubivol: which volume of ubi the image loading from, this property is required + for ubi and mounting. + +Example of storage device and partition search set for mmc, usb, sata and +ubi in device tree source as shown in below: + + Example of storage type and device partition search set for mmc, usb, + sata and ubi as shown in below: + Example for mmc: + fs_loader0: fs-loader@0 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + phandlepart = <&mmc_0 1>; + }; + + Example for usb: + fs_loader1: fs-loader@1 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + phandlepart = <&usb0 1>; + }; + + Example for sata: + fs_loader2: fs-loader@2 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + phandlepart = <&sata0 1>; + }; + + Example for ubi: + fs_loader3: fs-loader@3 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + mtdpart = "UBI", + ubivol = "ubi0"; + }; diff --git a/doc/device-tree-bindings/pinctrl/bcm6838-pinctrl.txt b/doc/device-tree-bindings/pinctrl/bcm6838-pinctrl.txt new file mode 100644 index 0000000000..2034f05993 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/bcm6838-pinctrl.txt @@ -0,0 +1,35 @@ +* broadcom bcm6838 pinctrl + +Required properties for the pinctrl driver: +- compatible: "brcm,bcm6838-pinctrl" +- regmap: specify the gpio test port syscon +- brcm,pins-count: the number of pin +- brcm,functions-count: the number of function + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +Example: + + gpio_test_port: syscon@14e00294 { + compatible = "syscon"; + reg = <0x14e00294 0x1c>; + }; + + pinctrl: pinctrl { + compatible = "brcm,bcm6838-pinctrl"; + regmap = <&gpio_test_port>; + brcm,pins-count = <74>; + brcm,functions-count = <8>; + + usb0: usb0 { + usb0_pwrflt { + pins = "69"; + function = "1"; + }; + usb0_pwron { + pins = "70"; + function = "1"; + }; + }; + }; diff --git a/doc/device-tree-bindings/w1-eeprom/ds24xxx.txt b/doc/device-tree-bindings/w1-eeprom/ds24xxx.txt new file mode 100644 index 0000000000..2e91be93b7 --- /dev/null +++ b/doc/device-tree-bindings/w1-eeprom/ds24xxx.txt @@ -0,0 +1,37 @@ +Maxim DS24 families driver device binding - one wire protocol EEPROMS from Maxim +======================= + +This memory needs to be connected to a onewire bus, as a child node. +The bus will read the device serial number and match this node with a found +device on the bus +Also check doc/device-tree-bindings/w1 for onewire bus drivers + +Driver: +- drivers/w1-eeprom/ds24xxx.c + +Software ds24xxx device-tree node properties: +Required: +* compatible = "maxim,ds24b33" +or +* compatible = "maxim,ds2431" +Further memories can be added. + +Optional: +* none + +Example: + eeprom1: eeprom@0 { + compatible = "maxim,ds24xxx"; + } + +Example with parent bus: + +onewire_tm: onewire { + compatible = "w1-gpio"; + gpios = <&pioA 32 0>; + + eeprom1: eeprom@0 { + compatible = "maxim,ds24xxx"; + } +}; + diff --git a/doc/device-tree-bindings/w1-eeprom/eep_sandbox.txt b/doc/device-tree-bindings/w1-eeprom/eep_sandbox.txt new file mode 100644 index 0000000000..82bb5899af --- /dev/null +++ b/doc/device-tree-bindings/w1-eeprom/eep_sandbox.txt @@ -0,0 +1,34 @@ +Onewire EEPROM sandbox driver device binding - one wire protocol sandbox EEPROM +======================= + +This memory needs to be connected to a onewire bus, as a child node. +The bus will read the device serial number and match this node with a found +device on the bus +Also check doc/device-tree-bindings/w1 for onewire bus drivers + +Driver: +- drivers/w1-eeprom/eep_sandbox.c + +Software ds24xxx device-tree node properties: +Required: +* compatible = "sandbox,w1-eeprom" + +Optional: +* none + +Example: + eeprom1: eeprom@0 { + compatible = "sandbox,w1-eeprom"; + } + +Example with parent bus: + +onewire_tm: onewire { + compatible = "w1-gpio"; + gpios = <&gpio_a 8>; + + eeprom1: eeprom@0 { + compatible = "sandbox,w1-eeprom"; + } +}; + diff --git a/doc/device-tree-bindings/w1/w1-gpio.txt b/doc/device-tree-bindings/w1/w1-gpio.txt new file mode 100644 index 0000000000..5a582448e4 --- /dev/null +++ b/doc/device-tree-bindings/w1/w1-gpio.txt @@ -0,0 +1,40 @@ +W1 gpio device binding - one wire protocol over bitbanged gpio +======================= + + +Child nodes are required in device tree. The driver will detect +the devices serial number and then search in the child nodes in the device tree +for the proper node and try to match it with the device. + +Also check doc/device-tree-bindings/w1-eeprom for possible child nodes drivers + +Driver: +- drivers/w1/w1-gpio.c + +Software w1 device-tree node properties: +Required: +* compatible = "w1-gpio"; +* gpios = <...>; + This is the gpio used for one wire protocol, using bitbanging + +Optional: +* none + +Example: + +onewire_tm: onewire { + compatible = "w1-gpio"; + gpios = <&pioA 32 0>; +}; + +Example with child: + +onewire_tm: onewire { + compatible = "w1-gpio"; + gpios = <&pioA 32 0>; + + eeprom1: eeprom@0 { + compatible = "maxim,ds24xxx"; + } +}; + diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt index d6fa5c4857..e949ff63ba 100644 --- a/doc/driver-model/README.txt +++ b/doc/driver-model/README.txt @@ -449,6 +449,15 @@ The driver model tree is intended to mirror that of the device tree. The root driver is at device tree offset 0 (the root node, '/'), and its children are the children of the root node. +In order for a device tree to be valid, the content must be correct with +respect to either device tree specification +(https://www.devicetree.org/specifications/) or the device tree bindings that +are found in the doc/device-tree-bindings directory. When not U-Boot specific +the bindings in this directory tend to come from the Linux Kernel. As such +certain design decisions may have been made already for us in terms of how +specific devices are described and bound. In most circumstances we wish to +retain compatibility without additional changes being made to the device tree +source files. Declaring Uclasses ------------------ diff --git a/doc/driver-model/fs_firmware_loader.txt b/doc/driver-model/fs_firmware_loader.txt new file mode 100644 index 0000000000..290915a959 --- /dev/null +++ b/doc/driver-model/fs_firmware_loader.txt @@ -0,0 +1,133 @@ +# Copyright (C) 2018 Intel Corporation <www.intel.com> +# +# SPDX-License-Identifier: GPL-2.0 + +Introduction +============ + +This is file system firmware loader for U-Boot framework, which has very close +to some Linux Firmware API. For the details of Linux Firmware API, you can refer +to https://01.org/linuxgraphics/gfx-docs/drm/driver-api/firmware/index.html. + +File system firmware loader can be used to load whatever(firmware, image, +and binary) from the storage device in file system format into target location +such as memory, then consumer driver such as FPGA driver can program FPGA image +from the target location into FPGA. + +To enable firmware loader, CONFIG_FS_LOADER need to be set at +<board_name>_defconfig such as "CONFIG_FS_LOADER=y". + +Firmware Loader API core features +--------------------------------- + +Firmware storage device described in device tree source +------------------------------------------------------- + For passing data like storage device phandle and partition where the + firmware loading from to the firmware loader driver, those data could be + defined in fs-loader node as shown in below: + + Example for block device: + fs_loader0: fs-loader@0 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + phandlepart = <&mmc 1>; + }; + + <&mmc 1> means block storage device pointer and its partition. + + Above example is a description for block storage, but for UBI storage + device, it can be described in FDT as shown in below: + + Example for ubi: + fs_loader1: fs-loader@1 { + u-boot,dm-pre-reloc; + compatible = "u-boot,fs-loader"; + mtdpart = "UBI", + ubivol = "ubi0"; + }; + + Then, firmware_loader property would be set with the path of fs_loader + node under /chosen node such as: + /{ + chosen { + firmware_loader = &fs_loader0; + }; + }; + + However, this driver is also designed to support U-boot environment + variables, so all these data from FDT can be overwritten + through the U-boot environment variable during run time. + For examples: + "storage_interface" - Storage interface, it can be "mmc", "usb", "sata" + or "ubi". + "fw_dev_part" - Block device number and its partition, it can be "0:1". + "fw_ubi_mtdpart" - UBI device mtd partition, it can be "UBI". + "fw_ubi_volume" - UBI volume, it can be "ubi0". + + When above environment variables are set, environment values would be + used instead of data from FDT. + The benefit of this design allows user to change storage attribute data + at run time through U-boot console and saving the setting as default + environment values in the storage for the next power cycle, so no + compilation is required for both driver and FDT. + +File system firmware Loader API +------------------------------- + +int request_firmware_into_buf(struct device_platdata *plat, + const char *name, + void *buf, size_t size, u32 offset, + struct firmware **firmwarep) +-------------------------------------------------------------------- +Load firmware into a previously allocated buffer + +Parameters: + +1. struct device_platdata *plat + Platform data such as storage and partition firmware loading from + +2. const char *name + name of firmware file + +3. void *buf + address of buffer to load firmware into + +4. size_t size + size of buffer + +5. u32 offset + offset of a file for start reading into buffer + +6. struct firmware **firmwarep + pointer to firmware image + +return: + size of total read + -ve when error + +Description: + The firmware is loaded directly into the buffer pointed to by buf and + the @firmwarep data member is pointed at buf + +Note: Memory would be allocated for firmware image, hence user should + free() *firmwarep and *firmwarep->priv structs after usage of + request_firmware_into_buf(), otherwise it will always leak memory + while subsequent calls of request_firmware_into_buf() with the same + *firmwarep argument. Those arguments can be free through calling API + below release_firmware(); + +Example of creating firmware loader instance and calling +request_firmware_into_buf API: + if (uclass_get_device(UCLASS_FS_FIRMWARE_LOADER, 0, &dev)) { + request_firmware_into_buf(dev->plat, filename, buffer_location, + buffer_size, offset_ofreading, &fw); + } + +void release_firmware(struct firmware *firmware) +------------------------------------------------ +Release the resource associated with a firmware image + +Parameters: + +1. struct firmware *firmware + Firmware resource to release diff --git a/drivers/Kconfig b/drivers/Kconfig index 884a945a19..9ac90c461f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -108,6 +108,10 @@ source "drivers/usb/Kconfig" source "drivers/video/Kconfig" +source "drivers/w1/Kconfig" + +source "drivers/w1-eeprom/Kconfig" + source "drivers/watchdog/Kconfig" config PHYS_TO_BUS diff --git a/drivers/Makefile b/drivers/Makefile index 23ea609b09..1d5905fe73 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -105,6 +105,8 @@ obj-y += smem/ obj-y += soc/ obj-y += thermal/ obj-y += axi/ +obj-$(CONFIG_W1) += w1/ +obj-$(CONFIG_W1_EEPROM) += w1-eeprom/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ endif diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c35912bd33..5fafb63aeb 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -230,8 +230,10 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv) debug("cap 0x%x port_map 0x%x n_ports %d\n", uc_priv->cap, uc_priv->port_map, uc_priv->n_ports); +#if !defined(CONFIG_DM_SCSI) if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; +#endif for (i = 0; i < uc_priv->n_ports; i++) { if (!(port_map & (1 << i))) @@ -980,7 +982,7 @@ static int ahci_start_ports(struct ahci_uc_priv *uc_priv) linkmap = uc_priv->link_port_map; - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + for (i = 0; i < uc_priv->n_ports; i++) { if (((linkmap >> i) & 0x01)) { if (ahci_port_start(uc_priv, (u8) i)) { printf("Can not start port %d\n", i); diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 9e0c823969..facf52711c 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -132,6 +132,29 @@ struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) } /** + * blk_get_by_device() - Get the block device descriptor for the given device + * @dev: Instance of a storage device + * + * Return: With block device descriptor on success , NULL if there is no such + * block device. + */ +struct blk_desc *blk_get_by_device(struct udevice *dev) +{ + struct udevice *child_dev, *next; + + device_foreach_child_safe(child_dev, next, dev) { + if (device_get_uclass_id(child_dev) != UCLASS_BLK) + continue; + + return dev_get_uclass_platdata(child_dev); + } + + debug("%s: No block device found\n", __func__); + + return NULL; +} + +/** * get_desc() - Get the block device descriptor for the given device number * * @if_type: Interface type diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index 03ffa8c11f..c095d5ecaa 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -150,7 +150,8 @@ static ulong zynqmp_align_dma_buffer(u32 *buf, u32 len, u32 swap) new_buf[i] = load_word(&buf[i], swap); buf = new_buf; - } else if (swap != SWAP_DONE) { + } else if ((swap != SWAP_DONE) && + (zynqmp_pmufw_version() <= PMUFW_V1_0)) { /* For bitstream which are aligned */ u32 *new_buf = (u32 *)buf; @@ -196,27 +197,41 @@ static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize, bitstream_type bstype) { ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1); - u32 swap; + u32 swap = 0; ulong bin_buf; int ret; u32 buf_lo, buf_hi; u32 ret_payload[PAYLOAD_ARG_CNT]; - - if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap)) - return FPGA_FAIL; + bool xilfpga_old = false; + + if (zynqmp_pmufw_version() <= PMUFW_V1_0) { + puts("WARN: PMUFW v1.0 or less is detected\n"); + puts("WARN: Not all bitstream formats are supported\n"); + puts("WARN: Please upgrade PMUFW\n"); + xilfpga_old = true; + if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap)) + return FPGA_FAIL; + bsizeptr = (u32 *)&bsize; + flush_dcache_range((ulong)bsizeptr, + (ulong)bsizeptr + sizeof(size_t)); + bstype |= BIT(ZYNQMP_FPGA_BIT_NS); + } bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap); - bsizeptr = (u32 *)&bsize; debug("%s called!\n", __func__); flush_dcache_range(bin_buf, bin_buf + bsize); - flush_dcache_range((ulong)bsizeptr, (ulong)bsizeptr + sizeof(size_t)); buf_lo = (u32)bin_buf; buf_hi = upper_32_bits(bin_buf); - bstype |= BIT(ZYNQMP_FPGA_BIT_NS); - ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi, - (u32)(uintptr_t)bsizeptr, bstype, ret_payload); + + if (xilfpga_old) + ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi, + (u32)(uintptr_t)bsizeptr, bstype, ret_payload); + else + ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi, + (u32)bsize, 0, ret_payload); + if (ret) debug("PL FPGA LOAD fail\n"); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index bfa5c91687..b0fb73f692 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -295,4 +295,13 @@ config MPC83XX_SERDES help Support for serdes found on MPC83xx SoCs. +config FS_LOADER + bool "Enable loader driver for file system" + help + This is file system generic loader which can be used to load + the file image from the storage into target such as memory. + + The consumer driver would then use this loader to program whatever, + ie. the FPGA device. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index da4666fdfc..acf24c44fa 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o +obj-$(CONFIG_FS_LOADER) += fs_loader.o diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c new file mode 100644 index 0000000000..5fe642b4be --- /dev/null +++ b/drivers/misc/fs_loader.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2018 Intel Corporation <www.intel.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <blk.h> +#include <fs.h> +#include <fs_loader.h> +#include <linux/string.h> +#include <mapmem.h> +#include <malloc.h> +#include <spl.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct firmware_priv { + const char *name; /* Filename */ + u32 offset; /* Offset of reading a file */ +}; + +#ifdef CONFIG_CMD_UBIFS +static int mount_ubifs(char *mtdpart, char *ubivol) +{ + int ret = ubi_part(mtdpart, NULL); + + if (ret) { + debug("Cannot find mtd partition %s\n", mtdpart); + return ret; + } + + return cmd_ubifs_mount(ubivol); +} + +static int umount_ubifs(void) +{ + return cmd_ubifs_umount(); +} +#else +static int mount_ubifs(char *mtdpart, char *ubivol) +{ + debug("Error: Cannot load image: no UBIFS support\n"); + return -ENOSYS; +} +#endif + +static int select_fs_dev(struct device_platdata *plat) +{ + int ret; + + if (plat->phandlepart.phandle) { + ofnode node; + + node = ofnode_get_by_phandle(plat->phandlepart.phandle); + + int of_offset = ofnode_to_offset(node); + + struct udevice *dev; + + ret = device_get_global_by_of_offset(of_offset, &dev); + if (!ret) { + struct blk_desc *desc = blk_get_by_device(dev); + if (desc) { + ret = fs_set_blk_dev_with_part(desc, + plat->phandlepart.partition); + } else { + debug("%s: No device found\n", __func__); + return -ENODEV; + } + } + } else if (plat->mtdpart && plat->ubivol) { + ret = mount_ubifs(plat->mtdpart, plat->ubivol); + if (ret) + return ret; + + ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS); + } else { + debug("Error: unsupported storage device.\n"); + return -ENODEV; + } + + if (ret) + debug("Error: could not access storage.\n"); + + return ret; +} + +/** + * _request_firmware_prepare - Prepare firmware struct. + * + * @name: Name of firmware file. + * @dbuf: Address of buffer to load firmware into. + * @size: Size of buffer. + * @offset: Offset of a file for start reading into buffer. + * @firmwarep: Pointer to pointer to firmware image. + * + * Return: Negative value if fail, 0 for successful. + */ +static int _request_firmware_prepare(const char *name, void *dbuf, + size_t size, u32 offset, + struct firmware **firmwarep) +{ + if (!name || name[0] == '\0') + return -EINVAL; + + /* No memory allocation is required if *firmwarep is allocated */ + if (!(*firmwarep)) { + (*firmwarep) = calloc(1, sizeof(struct firmware)); + if (!(*firmwarep)) + return -ENOMEM; + + (*firmwarep)->priv = calloc(1, sizeof(struct firmware_priv)); + if (!(*firmwarep)->priv) { + free(*firmwarep); + return -ENOMEM; + } + } else if (!(*firmwarep)->priv) { + (*firmwarep)->priv = calloc(1, sizeof(struct firmware_priv)); + if (!(*firmwarep)->priv) { + free(*firmwarep); + return -ENOMEM; + } + } + + ((struct firmware_priv *)((*firmwarep)->priv))->name = name; + ((struct firmware_priv *)((*firmwarep)->priv))->offset = offset; + (*firmwarep)->data = dbuf; + (*firmwarep)->size = size; + + return 0; +} + +/** + * release_firmware - Release the resource associated with a firmware image + * @firmware: Firmware resource to release + */ +void release_firmware(struct firmware *firmware) +{ + if (firmware) { + if (firmware->priv) { + free(firmware->priv); + firmware->priv = NULL; + } + free(firmware); + } +} + +/** + * fw_get_filesystem_firmware - load firmware into an allocated buffer. + * @plat: Platform data such as storage and partition firmware loading from. + * @firmware: pointer to firmware image. + * + * Return: Size of total read, negative value when error. + */ +static int fw_get_filesystem_firmware(struct device_platdata *plat, + struct firmware *firmware) +{ + struct firmware_priv *fw_priv = NULL; + loff_t actread; + char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume; + int ret; + + storage_interface = env_get("storage_interface"); + dev_part = env_get("fw_dev_part"); + ubi_mtdpart = env_get("fw_ubi_mtdpart"); + ubi_volume = env_get("fw_ubi_volume"); + + if (storage_interface && dev_part) { + ret = fs_set_blk_dev(storage_interface, dev_part, FS_TYPE_ANY); + } else if (storage_interface && ubi_mtdpart && ubi_volume) { + ret = mount_ubifs(ubi_mtdpart, ubi_volume); + if (ret) + return ret; + + if (!strcmp("ubi", storage_interface)) + ret = fs_set_blk_dev(storage_interface, NULL, + FS_TYPE_UBIFS); + else + ret = -ENODEV; + } else { + ret = select_fs_dev(plat); + } + + if (ret) + goto out; + + fw_priv = firmware->priv; + + ret = fs_read(fw_priv->name, (ulong)map_to_sysmem(firmware->data), + fw_priv->offset, firmware->size, &actread); + if (ret) { + debug("Error: %d Failed to read %s from flash %lld != %d.\n", + ret, fw_priv->name, actread, firmware->size); + } else { + ret = actread; + } + +out: +#ifdef CONFIG_CMD_UBIFS + umount_ubifs(); +#endif + return ret; +} + +/** + * request_firmware_into_buf - Load firmware into a previously allocated buffer. + * @plat: Platform data such as storage and partition firmware loading from. + * @name: Name of firmware file. + * @buf: Address of buffer to load firmware into. + * @size: Size of buffer. + * @offset: Offset of a file for start reading into buffer. + * @firmwarep: Pointer to firmware image. + * + * The firmware is loaded directly into the buffer pointed to by @buf and + * the @firmwarep data member is pointed at @buf. + * + * Return: Size of total read, negative value when error. + */ +int request_firmware_into_buf(struct device_platdata *plat, + const char *name, + void *buf, size_t size, u32 offset, + struct firmware **firmwarep) +{ + int ret; + + if (!plat) + return -EINVAL; + + ret = _request_firmware_prepare(name, buf, size, offset, firmwarep); + if (ret < 0) /* error */ + return ret; + + ret = fw_get_filesystem_firmware(plat, *firmwarep); + + return ret; +} + +static int fs_loader_ofdata_to_platdata(struct udevice *dev) +{ + const char *fs_loader_path; + u32 phandlepart[2]; + + fs_loader_path = ofnode_get_chosen_prop("firmware-loader"); + + if (fs_loader_path) { + ofnode fs_loader_node; + + fs_loader_node = ofnode_path(fs_loader_path); + if (ofnode_valid(fs_loader_node)) { + struct device_platdata *plat; + plat = dev->platdata; + + if (!ofnode_read_u32_array(fs_loader_node, + "phandlepart", + phandlepart, 2)) { + plat->phandlepart.phandle = phandlepart[0]; + plat->phandlepart.partition = phandlepart[1]; + } + + plat->mtdpart = (char *)ofnode_read_string( + fs_loader_node, "mtdpart"); + + plat->ubivol = (char *)ofnode_read_string( + fs_loader_node, "ubivol"); + } + } + + return 0; +} + +static int fs_loader_probe(struct udevice *dev) +{ + return 0; +}; + +static const struct udevice_id fs_loader_ids[] = { + { .compatible = "u-boot,fs-loader"}, + { } +}; + +U_BOOT_DRIVER(fs_loader) = { + .name = "fs-loader", + .id = UCLASS_FS_FIRMWARE_LOADER, + .of_match = fs_loader_ids, + .probe = fs_loader_probe, + .ofdata_to_platdata = fs_loader_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct device_platdata), +}; + +UCLASS_DRIVER(fs_loader) = { + .id = UCLASS_FS_FIRMWARE_LOADER, + .name = "fs-loader", +}; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 4d171f457e..ec853d063f 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -83,7 +83,6 @@ struct omap_hsmmc_data { #if CONFIG_IS_ENABLED(DM_MMC) struct gpio_desc cd_gpio; /* Change Detect GPIO */ struct gpio_desc wp_gpio; /* Write Protect GPIO */ - bool cd_inverted; #else int cd_gpio; int wp_gpio; @@ -216,6 +215,10 @@ static unsigned char mmc_board_init(struct mmc *mmc) /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */ pbias_lite &= ~PBIASLITEVMODE0; #endif +#ifdef CONFIG_TARGET_OMAP3_LOGIC + /* For Logic PD board, 1.8V bias to go enable gpio127 for mmc_cd */ + pbias_lite &= ~PBIASLITEVMODE1; +#endif #ifdef CONFIG_MMC_OMAP36XX_PINS if (get_cpu_family() == CPU_OMAP36XX) { /* Disable extended drain IO before changing PBIAS */ @@ -1364,17 +1367,15 @@ static int omap_hsmmc_set_ios(struct udevice *dev) #if CONFIG_IS_ENABLED(DM_MMC) static int omap_hsmmc_getcd(struct udevice *dev) { - struct omap_hsmmc_data *priv = dev_get_priv(dev); int value = -1; #if CONFIG_IS_ENABLED(DM_GPIO) + struct omap_hsmmc_data *priv = dev_get_priv(dev); value = dm_gpio_get_value(&priv->cd_gpio); #endif /* if no CD return as 1 */ if (value < 0) return 1; - if (priv->cd_inverted) - return !value; return value; } @@ -1856,10 +1857,6 @@ static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev) } #endif -#ifdef OMAP_HSMMC_USE_GPIO - plat->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted"); -#endif - return 0; } #endif @@ -1888,9 +1885,6 @@ static int omap_hsmmc_probe(struct udevice *dev) priv->base_addr = plat->base_addr; priv->controller_flags = plat->controller_flags; priv->hw_rev = plat->hw_rev; -#ifdef OMAP_HSMMC_USE_GPIO - priv->cd_inverted = plat->cd_inverted; -#endif #ifdef CONFIG_BLK mmc = plat->mmc; diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index c31695eba9..8e2a48cfd6 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -1008,6 +1008,25 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) return 1; } +static void cpsw_phy_addr_update(struct cpsw_priv *priv) +{ + struct cpsw_platform_data *data = &priv->data; + u16 alive = mdio_regs->alive & GENMASK(15, 0); + int active = data->active_slave; + int new_addr = ffs(alive) - 1; + + /* + * If there is only one phy alive and its address does not match + * that of active slave, then phy address can safely be updated. + */ + if (hweight16(alive) == 1 && + data->slave_data[active].phy_addr != new_addr) { + printf("Updated phy address for CPSW#%d, old: %d, new: %d\n", + active, data->slave_data[active].phy_addr, new_addr); + data->slave_data[active].phy_addr = new_addr; + } +} + int _cpsw_register(struct cpsw_priv *priv) { struct cpsw_slave *slave; @@ -1034,6 +1053,9 @@ int _cpsw_register(struct cpsw_priv *priv) } cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div); + + cpsw_phy_addr_update(priv); + priv->bus = miiphy_get_dev_by_name(priv->dev->name); for_active_slave(slave, priv) cpsw_phy_init(priv, slave); @@ -1458,6 +1480,13 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) return 0; } +int cpsw_get_slave_phy_addr(struct udevice *dev, int slave) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + struct cpsw_platform_data *data = &priv->data; + + return data->slave_data[slave].phy_addr; +} static const struct udevice_id cpsw_eth_ids[] = { { .compatible = "ti,cpsw" }, diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 68d1c2fcea..e22d048e8f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -699,14 +699,17 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) /* Hardcode for now */ priv->phyaddr = -1; - if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, - &phandle_args)) { - debug("phy-handle does not exist %s\n", dev->name); - return -ENOENT; + if (!dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args)) { + debug("phy-handle does exist %s\n", dev->name); + priv->phyaddr = ofnode_read_u32_default(phandle_args.node, + "reg", -1); + priv->phy_of_node = phandle_args.node; + priv->max_speed = ofnode_read_u32_default(phandle_args.node, + "max-speed", + SPEED_1000); } - priv->phyaddr = ofnode_read_u32_default(phandle_args.node, "reg", -1); - priv->phy_of_node = phandle_args.node; phy_mode = dev_read_prop(dev, "phy-mode", NULL); if (phy_mode) pdata->phy_interface = phy_get_interface_by_name(phy_mode); @@ -716,7 +719,6 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface; - priv->max_speed = dev_read_u32_default(dev, "max-speed", SPEED_1000); priv->int_pcs = dev_read_bool(dev, "is-internal-pcspma"); printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, diff --git a/drivers/pinctrl/broadcom/Kconfig b/drivers/pinctrl/broadcom/Kconfig index 4056782213..b01b725583 100644 --- a/drivers/pinctrl/broadcom/Kconfig +++ b/drivers/pinctrl/broadcom/Kconfig @@ -5,3 +5,11 @@ config PINCTRL_BCM283X help Support pin multiplexing and pin configuration control on Broadcom's 283x family of SoCs. + +config PINCTRL_BCM6838 + depends on ARCH_BMIPS && PINCTRL_FULL && OF_CONTROL + default y + bool "Broadcom 6838 family pin control driver" + help + Support pin multiplexing and pin configuration control on + Broadcom's 6838 family of SoCs. diff --git a/drivers/pinctrl/broadcom/Makefile b/drivers/pinctrl/broadcom/Makefile index 99c7c23583..f94f3ce7c9 100644 --- a/drivers/pinctrl/broadcom/Makefile +++ b/drivers/pinctrl/broadcom/Makefile @@ -5,3 +5,4 @@ # https://spdx.org/licenses obj-$(CONFIG_PINCTRL_BCM283X) += pinctrl-bcm283x.o +obj-$(CONFIG_PINCTRL_BCM6838) += pinctrl-bcm6838.o diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm6838.c b/drivers/pinctrl/broadcom/pinctrl-bcm6838.c new file mode 100644 index 0000000000..48c0b6b374 --- /dev/null +++ b/drivers/pinctrl/broadcom/pinctrl-bcm6838.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <common.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <dm/pinctrl.h> + +#define BCM6838_CMD_LOAD_MUX 0x21 + +#define BCM6838_FUNC_OFFS 12 +#define BCM6838_FUNC_MASK (0x37 << BCM6838_FUNC_OFFS) +#define BCM6838_PIN_OFFS 0 +#define BCM6838_PIN_MASK (0xfff << BCM6838_PIN_OFFS) + +#define BCM6838_MAX_PIN_NAME_LEN 8 +static char bcm6838_pin_name[BCM6838_MAX_PIN_NAME_LEN]; + +#define BCM6838_MAX_FUNC_NAME_LEN 8 +static char bcm6838_func_name[BCM6838_MAX_FUNC_NAME_LEN]; + +struct bcm6838_test_port_hw { + unsigned long port_blk_data1; + unsigned long port_blk_data2; + unsigned long port_command; +}; + +static const struct bcm6838_test_port_hw bcm6838_hw = { + .port_blk_data1 = 0x10, + .port_blk_data2 = 0x14, + .port_command = 0x18 +}; + +struct bcm6838_pinctrl_priv { + const struct bcm6838_test_port_hw *hw; + struct regmap *regmap; + u32 pins_count; + u32 functions_count; +}; + +int bcm6838_pinctrl_get_pins_count(struct udevice *dev) +{ + struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->pins_count; +} + +const char *bcm6838_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + snprintf(bcm6838_pin_name, BCM6838_MAX_PIN_NAME_LEN, "%u", selector); + return bcm6838_pin_name; +} + +int bcm6838_pinctrl_get_functions_count(struct udevice *dev) +{ + struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->functions_count; +} + +const char *bcm6838_pinctrl_get_function_name(struct udevice *dev, + unsigned int selector) +{ + snprintf(bcm6838_func_name, BCM6838_MAX_FUNC_NAME_LEN, "%u", selector); + return bcm6838_func_name; +} + +int bcm6838_pinctrl_pinmux_set(struct udevice *dev, + unsigned int pin_selector, + unsigned int func_selector) +{ + struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev); + const struct bcm6838_test_port_hw *hw = priv->hw; + unsigned int data; + + regmap_write(priv->regmap, hw->port_blk_data1, 0); + data = (func_selector << BCM6838_FUNC_OFFS) & BCM6838_FUNC_MASK; + data |= (pin_selector << BCM6838_PIN_OFFS) & BCM6838_PIN_MASK; + regmap_write(priv->regmap, hw->port_blk_data2, data); + regmap_write(priv->regmap, hw->port_command, BCM6838_CMD_LOAD_MUX); + + return 0; +} + +int bcm6838_pinctrl_probe(struct udevice *dev) +{ + struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev); + const struct bcm6838_test_port_hw *hw = + (const struct bcm6838_test_port_hw *)dev_get_driver_data(dev); + int err; + u32 phandle; + ofnode node; + + err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle); + if (err) { + dev_err(dev, "%s: unable to read regmap\n", __func__); + goto out; + } + + node = ofnode_get_by_phandle(phandle); + if (!ofnode_valid(node)) { + dev_err(dev, "%s: unable to find node\n", __func__); + err = -EINVAL; + goto out; + } + + priv->regmap = syscon_node_to_regmap(node); + if (!priv->regmap) { + dev_err(dev, "%s: unable to find regmap\n", __func__); + err = -ENODEV; + goto out; + } + + err = ofnode_read_u32(dev_ofnode(dev), "brcm,pins-count", + &priv->pins_count); + if (err) { + dev_err(dev, "%s: unable to read brcm,pins-count\n", + __func__); + goto out; + } + + err = ofnode_read_u32(dev_ofnode(dev), "brcm,functions-count", + &priv->functions_count); + if (err) { + dev_err(dev, "%s: unable to read brcm,functions-count\n", + __func__); + goto out; + } + + priv->hw = hw; + + out: + return err; +} + +const struct pinctrl_ops bcm6838_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, + .get_pins_count = bcm6838_pinctrl_get_pins_count, + .get_pin_name = bcm6838_pinctrl_get_pin_name, + .get_functions_count = bcm6838_pinctrl_get_functions_count, + .get_function_name = bcm6838_pinctrl_get_function_name, + .pinmux_set = bcm6838_pinctrl_pinmux_set, +}; + +static const struct udevice_id bcm6838_pinctrl_match[] = { + { + .compatible = "brcm,bcm6838-pinctrl", + .data = (ulong)&bcm6838_hw, + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(bcm6838_pinctrl) = { + .name = "bcm6838_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = bcm6838_pinctrl_match, + .ops = &bcm6838_pinctrl_ops, + .priv_auto_alloc_size = sizeof(struct bcm6838_pinctrl_priv), + .probe = bcm6838_pinctrl_probe, +}; diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c index 468fa2a7d0..755ac08bdf 100644 --- a/drivers/pinctrl/pinctrl-sandbox.c +++ b/drivers/pinctrl/pinctrl-sandbox.c @@ -14,6 +14,7 @@ static const char * const sandbox_pins[] = { "SDA", "TX", "RX", + "W1" }; static const char * const sandbox_groups[] = { @@ -21,12 +22,14 @@ static const char * const sandbox_groups[] = { "serial_a", "serial_b", "spi", + "w1", }; static const char * const sandbox_functions[] = { "i2c", "serial", "spi", + "w1", }; static const struct pinconf_param sandbox_conf_params[] = { diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c index 8955805e3b..8bf04f26a3 100644 --- a/drivers/rtc/pl031.c +++ b/drivers/rtc/pl031.c @@ -8,13 +8,11 @@ #include <common.h> #include <command.h> +#include <dm.h> +#include <errno.h> #include <rtc.h> - -#if defined(CONFIG_CMD_DATE) - -#ifndef CONFIG_SYS_RTC_PL031_BASE -#error CONFIG_SYS_RTC_PL031_BASE is not defined! -#endif +#include <asm/io.h> +#include <asm/types.h> /* * Register definitions @@ -30,78 +28,114 @@ #define RTC_CR_START (1 << 0) -#define RTC_WRITE_REG(addr, val) \ - (*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)) = (val)) -#define RTC_READ_REG(addr) \ - (*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr))) +struct pl031_platdata { + phys_addr_t base; +}; -static int pl031_initted = 0; +static inline u32 pl031_read_reg(struct udevice *dev, int reg) +{ + struct pl031_platdata *pdata = dev_get_platdata(dev); -/* Enable RTC Start in Control register*/ -void rtc_init(void) + return readl(pdata->base + reg); +} + +static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value) { - RTC_WRITE_REG(RTC_CR, RTC_CR_START); + struct pl031_platdata *pdata = dev_get_platdata(dev); - pl031_initted = 1; + return writel(value, pdata->base + reg); } /* - * Reset the RTC. We set the date back to 1970-01-01. + * Probe RTC device + */ +static int pl031_probe(struct udevice *dev) +{ + /* Enable RTC Start in Control register*/ + pl031_write_reg(dev, RTC_CR, RTC_CR_START); + + return 0; +} + +/* + * Get the current time from the RTC */ -void rtc_reset(void) +static int pl031_get(struct udevice *dev, struct rtc_time *tm) { - RTC_WRITE_REG(RTC_LR, 0x00); - if(!pl031_initted) - rtc_init(); + unsigned long tim; + + if (!tm) + return -EINVAL; + + tim = pl031_read_reg(dev, RTC_DR); + + rtc_to_tm(tim, tm); + + debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; } /* * Set the RTC -*/ -int rtc_set(struct rtc_time *tmp) + */ +static int pl031_set(struct udevice *dev, const struct rtc_time *tm) { unsigned long tim; - if(!pl031_initted) - rtc_init(); + if (!tm) + return -EINVAL; - if (tmp == NULL) { - puts("Error setting the date/time\n"); - return -1; - } + debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); /* Calculate number of seconds this incoming time represents */ - tim = rtc_mktime(tmp); + tim = rtc_mktime(tm); - RTC_WRITE_REG(RTC_LR, tim); + pl031_write_reg(dev, RTC_LR, tim); - return -1; + return 0; } /* - * Get the current time from the RTC + * Reset the RTC. We set the date back to 1970-01-01. */ -int rtc_get(struct rtc_time *tmp) +static int pl031_reset(struct udevice *dev) { - ulong tim; + pl031_write_reg(dev, RTC_LR, 0); - if(!pl031_initted) - rtc_init(); + return 0; +} - if (tmp == NULL) { - puts("Error getting the date/time\n"); - return -1; - } +static const struct rtc_ops pl031_ops = { + .get = pl031_get, + .set = pl031_set, + .reset = pl031_reset, +}; - tim = RTC_READ_REG(RTC_DR); +static const struct udevice_id pl031_ids[] = { + { .compatible = "arm,pl031" }, + { } +}; - rtc_to_tm(tim, tmp); +static int pl031_ofdata_to_platdata(struct udevice *dev) +{ + struct pl031_platdata *pdata = dev_get_platdata(dev); - debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + pdata->base = dev_read_addr(dev); return 0; } -#endif +U_BOOT_DRIVER(rtc_pl031) = { + .name = "rtc-pl031", + .id = UCLASS_RTC, + .of_match = pl031_ids, + .probe = pl031_probe, + .ofdata_to_platdata = pl031_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct pl031_platdata), + .ops = &pl031_ops, +}; diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index 399dfd65fe..1b54d1880f 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -17,7 +17,7 @@ /* Information about the efi console */ struct serial_efi_priv { - struct efi_simple_input_interface *con_in; + struct efi_simple_text_input_protocol *con_in; struct efi_simple_text_output_protocol *con_out; struct efi_input_key key; bool have_key; diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c index d8a047bb71..af3c755f96 100644 --- a/drivers/serial/serial_omap.c +++ b/drivers/serial/serial_omap.c @@ -104,6 +104,7 @@ static const struct udevice_id omap_serial_ids[] = { { .compatible = "ti,am3352-uart", }, { .compatible = "ti,am4372-uart", }, { .compatible = "ti,dra742-uart", }, + { .compatible = "ti,am654-uart", }, {} }; #endif /* OF_CONTROL && !OF_PLATDATA */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index dcd719ff0a..7d4d47da4b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -125,6 +125,14 @@ config PIC32_SPI to access the SPI NOR flash, MMC-over-SPI on platforms based on Microchip PIC32 family devices. +config PL022_SPI + bool "ARM AMBA PL022 SSP controller driver" + depends on ARM + help + This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP + controller. If you have an embedded system with an AMBA(R) + bus and a PL022 controller, say Y or M here. + config RENESAS_RPC_SPI bool "Renesas RPC SPI driver" depends on RCAR_GEN3 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 728e30c538..6679987cad 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MXS_SPI) += mxs_spi.o obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o obj-$(CONFIG_PIC32_SPI) += pic32_spi.o +obj-$(CONFIG_PL022_SPI) += pl022_spi.o obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c new file mode 100644 index 0000000000..86b71d2e21 --- /dev/null +++ b/drivers/spi/pl022_spi.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2012 + * Armando Visconti, ST Microelectronics, armando.visconti@st.com. + * + * (C) Copyright 2018 + * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com + * + * Driver for ARM PL022 SPI Controller. + */ + +#include <asm/io.h> +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <dm/platform_data/pl022_spi.h> +#include <fdtdec.h> +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <spi.h> + +#define SSP_CR0 0x000 +#define SSP_CR1 0x004 +#define SSP_DR 0x008 +#define SSP_SR 0x00C +#define SSP_CPSR 0x010 +#define SSP_IMSC 0x014 +#define SSP_RIS 0x018 +#define SSP_MIS 0x01C +#define SSP_ICR 0x020 +#define SSP_DMACR 0x024 +#define SSP_CSR 0x030 /* vendor extension */ +#define SSP_ITCR 0x080 +#define SSP_ITIP 0x084 +#define SSP_ITOP 0x088 +#define SSP_TDR 0x08C + +#define SSP_PID0 0xFE0 +#define SSP_PID1 0xFE4 +#define SSP_PID2 0xFE8 +#define SSP_PID3 0xFEC + +#define SSP_CID0 0xFF0 +#define SSP_CID1 0xFF4 +#define SSP_CID2 0xFF8 +#define SSP_CID3 0xFFC + +/* SSP Control Register 0 - SSP_CR0 */ +#define SSP_CR0_SPO (0x1 << 6) +#define SSP_CR0_SPH (0x1 << 7) +#define SSP_CR0_BIT_MODE(x) ((x) - 1) +#define SSP_SCR_MIN (0x00) +#define SSP_SCR_MAX (0xFF) +#define SSP_SCR_SHFT 8 +#define DFLT_CLKRATE 2 + +/* SSP Control Register 1 - SSP_CR1 */ +#define SSP_CR1_MASK_SSE (0x1 << 1) + +#define SSP_CPSR_MIN (0x02) +#define SSP_CPSR_MAX (0xFE) +#define DFLT_PRESCALE (0x40) + +/* SSP Status Register - SSP_SR */ +#define SSP_SR_MASK_TFE (0x1 << 0) /* Transmit FIFO empty */ +#define SSP_SR_MASK_TNF (0x1 << 1) /* Transmit FIFO not full */ +#define SSP_SR_MASK_RNE (0x1 << 2) /* Receive FIFO not empty */ +#define SSP_SR_MASK_RFF (0x1 << 3) /* Receive FIFO full */ +#define SSP_SR_MASK_BSY (0x1 << 4) /* Busy Flag */ + +struct pl022_spi_slave { + void *base; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct clk clk; +#else + unsigned int freq; +#endif +}; + +/* + * ARM PL022 exists in different 'flavors'. + * This drivers currently support the standard variant (0x00041022), that has a + * 16bit wide and 8 locations deep TX/RX FIFO. + */ +static int pl022_is_supported(struct pl022_spi_slave *ps) +{ + /* PL022 version is 0x00041022 */ + if ((readw(ps->base + SSP_PID0) == 0x22) && + (readw(ps->base + SSP_PID1) == 0x10) && + ((readw(ps->base + SSP_PID2) & 0xf) == 0x04) && + (readw(ps->base + SSP_PID3) == 0x00)) + return 1; + + return 0; +} + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +static int pl022_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct pl022_spi_pdata *plat = bus->platdata; + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + + plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size); + + return clk_get_by_index(bus, 0, &plat->clk); +} +#endif + +static int pl022_spi_probe(struct udevice *bus) +{ + struct pl022_spi_pdata *plat = dev_get_platdata(bus); + struct pl022_spi_slave *ps = dev_get_priv(bus); + + ps->base = ioremap(plat->addr, plat->size); +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + ps->clk = plat->clk; +#else + ps->freq = plat->freq; +#endif + + /* Check the PL022 version */ + if (!pl022_is_supported(ps)) + return -ENOTSUPP; + + /* 8 bits per word, high polarity and default clock rate */ + writew(SSP_CR0_BIT_MODE(8), ps->base + SSP_CR0); + writew(DFLT_PRESCALE, ps->base + SSP_CPSR); + + return 0; +} + +static void flush(struct pl022_spi_slave *ps) +{ + do { + while (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) + readw(ps->base + SSP_DR); + } while (readw(ps->base + SSP_SR) & SSP_SR_MASK_BSY); +} + +static int pl022_spi_claim_bus(struct udevice *dev) +{ + struct udevice *bus = dev->parent; + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 reg; + + /* Enable the SPI hardware */ + reg = readw(ps->base + SSP_CR1); + reg |= SSP_CR1_MASK_SSE; + writew(reg, ps->base + SSP_CR1); + + flush(ps); + + return 0; +} + +static int pl022_spi_release_bus(struct udevice *dev) +{ + struct udevice *bus = dev->parent; + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 reg; + + flush(ps); + + /* Disable the SPI hardware */ + reg = readw(ps->base + SSP_CR1); + reg &= ~SSP_CR1_MASK_SSE; + writew(reg, ps->base + SSP_CR1); + + return 0; +} + +static int pl022_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct pl022_spi_slave *ps = dev_get_priv(bus); + u32 len_tx = 0, len_rx = 0, len; + u32 ret = 0; + const u8 *txp = dout; + u8 *rxp = din, value; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + return 0; + + /* + * TODO: The controller can do non-multiple-of-8 bit + * transfers, but this driver currently doesn't support it. + * + * It's also not clear how such transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + return -1; + } + + len = bitlen / 8; + + while (len_tx < len) { + if (readw(ps->base + SSP_SR) & SSP_SR_MASK_TNF) { + value = txp ? *txp++ : 0; + writew(value, ps->base + SSP_DR); + len_tx++; + } + + if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) { + value = readw(ps->base + SSP_DR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + + while (len_rx < len_tx) { + if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) { + value = readw(ps->base + SSP_DR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + + return ret; +} + +static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr) +{ + return rate / (cpsdvsr * (1 + scr)); +} + +static int pl022_spi_set_speed(struct udevice *bus, uint speed) +{ + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr, + best_cpsr = cpsr; + u32 min, max, best_freq = 0, tmp; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + u32 rate = clk_get_rate(&ps->clk); +#else + u32 rate = ps->freq; +#endif + bool found = false; + + max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN); + min = spi_rate(rate, SSP_CPSR_MAX, SSP_SCR_MAX); + + if (speed > max || speed < min) { + pr_err("Tried to set speed to %dHz but min=%d and max=%d\n", + speed, min, max); + return -EINVAL; + } + + while (cpsr <= SSP_CPSR_MAX && !found) { + while (scr <= SSP_SCR_MAX) { + tmp = spi_rate(rate, cpsr, scr); + + if (abs(speed - tmp) < abs(speed - best_freq)) { + best_freq = tmp; + best_cpsr = cpsr; + best_scr = scr; + + if (tmp == speed) { + found = true; + break; + } + } + + scr++; + } + cpsr += 2; + scr = SSP_SCR_MIN; + } + + writew(best_cpsr, ps->base + SSP_CPSR); + cr0 = readw(ps->base + SSP_CR0); + writew(cr0 | (best_scr << SSP_SCR_SHFT), ps->base + SSP_CR0); + + return 0; +} + +static int pl022_spi_set_mode(struct udevice *bus, uint mode) +{ + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 reg; + + reg = readw(ps->base + SSP_CR0); + reg &= ~(SSP_CR0_SPH | SSP_CR0_SPO); + if (mode & SPI_CPHA) + reg |= SSP_CR0_SPH; + if (mode & SPI_CPOL) + reg |= SSP_CR0_SPO; + writew(reg, ps->base + SSP_CR0); + + return 0; +} + +static int pl022_cs_info(struct udevice *bus, uint cs, + struct spi_cs_info *info) +{ + return 0; +} + +static const struct dm_spi_ops pl022_spi_ops = { + .claim_bus = pl022_spi_claim_bus, + .release_bus = pl022_spi_release_bus, + .xfer = pl022_spi_xfer, + .set_speed = pl022_spi_set_speed, + .set_mode = pl022_spi_set_mode, + .cs_info = pl022_cs_info, +}; + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +static const struct udevice_id pl022_spi_ids[] = { + { .compatible = "arm,pl022-spi" }, + { } +}; +#endif + +U_BOOT_DRIVER(pl022_spi) = { + .name = "pl022_spi", + .id = UCLASS_SPI, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .of_match = pl022_spi_ids, +#endif + .ops = &pl022_spi_ops, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .ofdata_to_platdata = pl022_spi_ofdata_to_platdata, +#endif + .platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata), + .priv_auto_alloc_size = sizeof(struct pl022_spi_slave), + .probe = pl022_spi_probe, +}; diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index f1d3ad3611..0c36a5de0a 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -213,6 +213,14 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) s++; /* ; */ s = parsenum(s, &col); + /* + * Ensure we stay in the bounds of the screen. + */ + if (row >= priv->rows) + row = priv->rows - 1; + if (col >= priv->cols) + col = priv->cols - 1; + priv->ycur = row * priv->y_charsize; priv->xcur_frac = priv->xstart_frac + VID_TO_POS(col * priv->x_charsize); diff --git a/drivers/w1-eeprom/Kconfig b/drivers/w1-eeprom/Kconfig new file mode 100644 index 0000000000..4b7f3c4e0b --- /dev/null +++ b/drivers/w1-eeprom/Kconfig @@ -0,0 +1,29 @@ +# +# EEPROM subsystem configuration +# + +menu "1-wire EEPROM support" + +config W1_EEPROM + bool "Enable support for EEPROMs on 1wire interface" + depends on DM + help + Support for the EEPROMs connected on 1-wire Dallas protocol interface + +if W1_EEPROM + +config W1_EEPROM_DS24XXX + bool "Enable Maxim DS24 families EEPROM support" + depends on W1 + help + Maxim DS24 EEPROMs 1-Wire EEPROM support + +config W1_EEPROM_SANDBOX + bool "Enable sandbox onewire EEPROM driver" + depends on W1 + help + Sandbox driver for a onewire EEPROM memory + +endif + +endmenu diff --git a/drivers/w1-eeprom/Makefile b/drivers/w1-eeprom/Makefile new file mode 100644 index 0000000000..03cc4c8ac8 --- /dev/null +++ b/drivers/w1-eeprom/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_W1_EEPROM) += w1-eeprom-uclass.o + +obj-$(CONFIG_W1_EEPROM_DS24XXX) += ds24xxx.o + +obj-$(CONFIG_W1_EEPROM_SANDBOX) += eep_sandbox.o diff --git a/drivers/w1-eeprom/ds24xxx.c b/drivers/w1-eeprom/ds24xxx.c new file mode 100644 index 0000000000..56186e587c --- /dev/null +++ b/drivers/w1-eeprom/ds24xxx.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co + * Copyright (c) 2018 Microchip Technology, Inc. + * + */ + +#include <common.h> +#include <linux/err.h> +#include <dm.h> +#include <w1-eeprom.h> +#include <w1.h> + +#define W1_F2D_READ_EEPROM 0xf0 + +static int ds24xxx_read_buf(struct udevice *dev, unsigned int offset, + u8 *buf, unsigned int count) +{ + w1_reset_select(dev); + + w1_write_byte(dev, W1_F2D_READ_EEPROM); + w1_write_byte(dev, offset & 0xff); + w1_write_byte(dev, offset >> 8); + + return w1_read_buf(dev, buf, count); +} + +static int ds24xxx_probe(struct udevice *dev) +{ + struct w1_device *w1; + + w1 = dev_get_platdata(dev); + w1->id = 0; + return 0; +} + +static const struct w1_eeprom_ops ds24xxx_ops = { + .read_buf = ds24xxx_read_buf, +}; + +static const struct udevice_id ds24xxx_id[] = { + { .compatible = "maxim,ds24b33", .data = W1_FAMILY_DS24B33 }, + { .compatible = "maxim,ds2431", .data = W1_FAMILY_DS2431 }, + { }, +}; + +U_BOOT_DRIVER(ds24xxx) = { + .name = "ds24xxx", + .id = UCLASS_W1_EEPROM, + .of_match = ds24xxx_id, + .ops = &ds24xxx_ops, + .probe = ds24xxx_probe, +}; diff --git a/drivers/w1-eeprom/eep_sandbox.c b/drivers/w1-eeprom/eep_sandbox.c new file mode 100644 index 0000000000..27c7f9f1b6 --- /dev/null +++ b/drivers/w1-eeprom/eep_sandbox.c @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2018 Microchip Technology, Inc. + * + */ + +#include <common.h> +#include <linux/err.h> +#include <dm.h> +#include <w1-eeprom.h> +#include <w1.h> + +#define W1_F2D_READ_EEPROM 0xf0 + +#define EEP_SANDBOX_SAMPLE_MEM "this is a sample EEPROM memory string." + +static int eep_sandbox_read_buf(struct udevice *dev, unsigned int offset, + u8 *buf, unsigned int count) +{ + /* do not allow to copy more than our maximum sample string */ + if (offset + count < strlen(EEP_SANDBOX_SAMPLE_MEM)) { + offset = 0; + count = strlen(EEP_SANDBOX_SAMPLE_MEM); + } + strncpy((char *)buf, EEP_SANDBOX_SAMPLE_MEM, count); + + /* + * in case the w1 subsystem uses some different kind of sandbox testing, + * like randomized gpio values , we take the buffer from there + */ + + w1_reset_select(dev); + + w1_write_byte(dev, W1_F2D_READ_EEPROM); + w1_write_byte(dev, offset & 0xff); + w1_write_byte(dev, offset >> 8); + + w1_read_buf(dev, buf, count); + + /* + * even if read buf from w1 fails, return success as we hardcoded + * the buffer. + */ + return 0; +} + +static const struct w1_eeprom_ops eep_sandbox_ops = { + .read_buf = eep_sandbox_read_buf, +}; + +static const struct udevice_id eep_sandbox_id[] = { + { .compatible = "sandbox,w1-eeprom", .data = W1_FAMILY_EEP_SANDBOX }, + { }, +}; + +U_BOOT_DRIVER(eep_sandbox) = { + .name = "eep_sandbox", + .id = UCLASS_W1_EEPROM, + .of_match = eep_sandbox_id, + .ops = &eep_sandbox_ops, +}; diff --git a/drivers/w1-eeprom/w1-eeprom-uclass.c b/drivers/w1-eeprom/w1-eeprom-uclass.c new file mode 100644 index 0000000000..7b0579344c --- /dev/null +++ b/drivers/w1-eeprom/w1-eeprom-uclass.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co. + * Copyright (c) 2018 Microchip Technology, Inc. + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * Eugen Hristev <eugen.hristev@microchip.com> + * + */ + +#include <common.h> +#include <dm.h> +#include <w1.h> +#include <w1-eeprom.h> + +#include <dm/device-internal.h> + +int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset, + u8 *buf, unsigned int count) +{ + const struct w1_eeprom_ops *ops = device_get_ops(dev); + u64 id = 0; + int ret; + + if (!ops->read_buf) + return -ENOSYS; + + ret = w1_eeprom_get_id(dev, &id); + if (ret) + return ret; + if (!id) + return -ENODEV; + + return ops->read_buf(dev, offset, buf, count); +} + +int w1_eeprom_register_new_device(u64 id) +{ + u8 family = id & 0xff; + int ret; + struct udevice *dev; + + for (ret = uclass_first_device(UCLASS_W1_EEPROM, &dev); + !ret && dev; + uclass_next_device(&dev)) { + if (ret || !dev) { + debug("cannot find w1 eeprom dev\n"); + return ret; + } + if (dev_get_driver_data(dev) == family) { + struct w1_device *w1; + + w1 = dev_get_parent_platdata(dev); + if (w1->id) /* device already in use */ + continue; + w1->id = id; + debug("%s: Match found: %s:%s %llx\n", __func__, + dev->name, dev->driver->name, id); + return 0; + } + } + + debug("%s: No matches found: error %d\n", __func__, ret); + + return ret; +} + +int w1_eeprom_get_id(struct udevice *dev, u64 *id) +{ + struct w1_device *w1 = dev_get_parent_platdata(dev); + + if (!w1) + return -ENODEV; + *id = w1->id; + + return 0; +} + +UCLASS_DRIVER(w1_eeprom) = { + .name = "w1_eeprom", + .id = UCLASS_W1_EEPROM, + .flags = DM_UC_FLAG_SEQ_ALIAS, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .post_bind = dm_scan_fdt_dev, +#endif +}; + +int w1_eeprom_dm_init(void) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_W1_EEPROM, &uc); + if (ret) { + debug("W1_EEPROM uclass not available\n"); + return ret; + } + + uclass_foreach_dev(dev, uc) { + ret = device_probe(dev); + if (ret == -ENODEV) { /* No such device. */ + debug("W1_EEPROM not available.\n"); + continue; + } + + if (ret) { /* Other error. */ + printf("W1_EEPROM probe failed, error %d\n", ret); + continue; + } + } + + return 0; +} diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig new file mode 100644 index 0000000000..d6e045739d --- /dev/null +++ b/drivers/w1/Kconfig @@ -0,0 +1,25 @@ +# +# W1 subsystem configuration +# + +menu "1-Wire support" + +config W1 + bool "Enable 1-wire controllers support" + default no + depends on DM + help + Support for the Dallas 1-Wire bus. + +if W1 + +config W1_GPIO + bool "Enable 1-wire GPIO bitbanging" + default no + depends on DM_GPIO + help + Emulate a 1-wire bus using a GPIO. + +endif + +endmenu diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile new file mode 100644 index 0000000000..7fd8697f84 --- /dev/null +++ b/drivers/w1/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_W1) += w1-uclass.o + +obj-$(CONFIG_W1_GPIO) += w1-gpio.o diff --git a/drivers/w1/w1-gpio.c b/drivers/w1/w1-gpio.c new file mode 100644 index 0000000000..5e5d6b3f6c --- /dev/null +++ b/drivers/w1/w1-gpio.c @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + */ + +#include <common.h> +#include <dm.h> +#include <w1.h> + +#include <asm/gpio.h> + +#define W1_TIMING_A 6 +#define W1_TIMING_B 64 +#define W1_TIMING_C 60 +#define W1_TIMING_D 10 +#define W1_TIMING_E 9 +#define W1_TIMING_F 55 +#define W1_TIMING_G 0 +#define W1_TIMING_H 480 +#define W1_TIMING_I 70 +#define W1_TIMING_J 410 + +struct w1_gpio_pdata { + struct gpio_desc gpio; + u64 search_id; +}; + +static bool w1_gpio_read_bit(struct udevice *dev) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + int val; + + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT); + udelay(W1_TIMING_A); + + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN); + udelay(W1_TIMING_E); + + val = dm_gpio_get_value(&pdata->gpio); + if (val < 0) + debug("error in retrieving GPIO value"); + udelay(W1_TIMING_F); + + return val; +} + +static u8 w1_gpio_read_byte(struct udevice *dev) +{ + int i; + u8 ret = 0; + + for (i = 0; i < 8; ++i) + ret |= (w1_gpio_read_bit(dev) ? 1 : 0) << i; + + return ret; +} + +static void w1_gpio_write_bit(struct udevice *dev, bool bit) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT); + + bit ? udelay(W1_TIMING_A) : udelay(W1_TIMING_C); + + dm_gpio_set_value(&pdata->gpio, 1); + + bit ? udelay(W1_TIMING_B) : udelay(W1_TIMING_D); +} + +static void w1_gpio_write_byte(struct udevice *dev, u8 byte) +{ + int i; + + for (i = 0; i < 8; ++i) + w1_gpio_write_bit(dev, (byte >> i) & 0x1); +} + +static bool w1_gpio_reset(struct udevice *dev) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + int val; + + /* initiate the reset pulse. first we must pull the bus to low */ + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + udelay(W1_TIMING_G); + + dm_gpio_set_value(&pdata->gpio, 0); + /* wait for the specified time with the bus kept low */ + udelay(W1_TIMING_H); + + /* now we must read the presence pulse */ + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN); + udelay(W1_TIMING_I); + + val = dm_gpio_get_value(&pdata->gpio); + if (val < 0) + debug("error in retrieving GPIO value"); + + /* if nobody pulled the bus down , it means nobody is on the bus */ + if (val != 0) + return 1; + /* we have the bus pulled down, let's wait for the specified presence time */ + udelay(W1_TIMING_J); + + /* read again, the other end should leave the bus free */ + val = dm_gpio_get_value(&pdata->gpio); + if (val < 0) + debug("error in retrieving GPIO value"); + + /* bus is not going up again, so we have an error */ + if (val != 1) + return 1; + + /* all good, presence detected */ + return 0; +} + +static u8 w1_gpio_triplet(struct udevice *dev, bool bdir) +{ + u8 id_bit = w1_gpio_read_bit(dev); + u8 comp_bit = w1_gpio_read_bit(dev); + u8 retval; + + if (id_bit && comp_bit) + return 0x03; /* error */ + + if (!id_bit && !comp_bit) { + /* Both bits are valid, take the direction given */ + retval = bdir ? 0x04 : 0; + } else { + /* Only one bit is valid, take that direction */ + bdir = id_bit; + retval = id_bit ? 0x05 : 0x02; + } + + w1_gpio_write_bit(dev, bdir); + return retval; +} + +static const struct w1_ops w1_gpio_ops = { + .read_byte = w1_gpio_read_byte, + .reset = w1_gpio_reset, + .triplet = w1_gpio_triplet, + .write_byte = w1_gpio_write_byte, +}; + +static int w1_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + int ret; + + ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, 0); + if (ret < 0) + printf("Error claiming GPIO %d\n", ret); + + return ret; +}; + +static const struct udevice_id w1_gpio_id[] = { + { "w1-gpio", 0 }, + { }, +}; + +U_BOOT_DRIVER(w1_gpio_drv) = { + .id = UCLASS_W1, + .name = "w1_gpio_drv", + .of_match = w1_gpio_id, + .ofdata_to_platdata = w1_gpio_ofdata_to_platdata, + .ops = &w1_gpio_ops, + .platdata_auto_alloc_size = sizeof(struct w1_gpio_pdata), +}; diff --git a/drivers/w1/w1-uclass.c b/drivers/w1/w1-uclass.c new file mode 100644 index 0000000000..aecf7fec77 --- /dev/null +++ b/drivers/w1/w1-uclass.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co. + * Copyright (c) 2018 Microchip Technology, Inc. + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * Eugen Hristev <eugen.hristev@microchip.com> + * + */ + +#include <common.h> +#include <dm.h> +#include <w1.h> +#include <w1-eeprom.h> + +#include <dm/device-internal.h> + +#define W1_MATCH_ROM 0x55 +#define W1_SKIP_ROM 0xcc +#define W1_SEARCH 0xf0 + +struct w1_bus { + u64 search_id; +}; + +static int w1_enumerate(struct udevice *bus) +{ + const struct w1_ops *ops = device_get_ops(bus); + struct w1_bus *w1 = dev_get_uclass_priv(bus); + u64 last_rn, rn = w1->search_id, tmp64; + bool last_device = false; + int search_bit, desc_bit = 64; + int last_zero = -1; + u8 triplet_ret = 0; + int i; + + if (!ops->reset || !ops->write_byte || !ops->triplet) + return -ENOSYS; + + while (!last_device) { + last_rn = rn; + rn = 0; + + /* + * Reset bus and all 1-wire device state machines + * so they can respond to our requests. + * + * Return 0 - device(s) present, 1 - no devices present. + */ + if (ops->reset(bus)) { + debug("%s: No devices present on the wire.\n", + __func__); + break; + } + + /* Start the search */ + ops->write_byte(bus, W1_SEARCH); + for (i = 0; i < 64; ++i) { + /* Determine the direction/search bit */ + if (i == desc_bit) + /* took the 0 path last time, so take the 1 path */ + search_bit = 1; + else if (i > desc_bit) + /* take the 0 path on the next branch */ + search_bit = 0; + else + search_bit = ((last_rn >> i) & 0x1); + + /* Read two bits and write one bit */ + triplet_ret = ops->triplet(bus, search_bit); + + /* quit if no device responded */ + if ((triplet_ret & 0x03) == 0x03) + break; + + /* If both directions were valid, and we took the 0 path... */ + if (triplet_ret == 0) + last_zero = i; + + /* extract the direction taken & update the device number */ + tmp64 = (triplet_ret >> 2); + rn |= (tmp64 << i); + } + + /* last device or error, aborting here */ + if ((triplet_ret & 0x03) == 0x03) + last_device = true; + + if ((triplet_ret & 0x03) != 0x03) { + if (desc_bit == last_zero || last_zero < 0) { + last_device = 1; + w1->search_id = 0; + } else { + w1->search_id = rn; + } + desc_bit = last_zero; + + debug("%s: Detected new device 0x%llx (family 0x%x)\n", + bus->name, rn, (u8)(rn & 0xff)); + + /* attempt to register as w1-eeprom device */ + w1_eeprom_register_new_device(rn); + } + } + + return 0; +} + +int w1_get_bus(int busnum, struct udevice **busp) +{ + int ret, i = 0; + + struct udevice *dev; + + for (ret = uclass_first_device(UCLASS_W1, &dev); + !ret; + uclass_next_device(&dev), i++) { + if (ret) { + debug("Cannot find w1 bus %d\n", busnum); + return ret; + } + if (i == busnum) { + *busp = dev; + return 0; + } + } + return ret; +} + +u8 w1_get_device_family(struct udevice *dev) +{ + struct w1_device *w1 = dev_get_parent_platdata(dev); + + return w1->id & 0xff; +} + +int w1_reset_select(struct udevice *dev) +{ + struct w1_device *w1 = dev_get_parent_platdata(dev); + struct udevice *bus = dev_get_parent(dev); + const struct w1_ops *ops = device_get_ops(bus); + int i; + + if (!ops->reset || !ops->write_byte) + return -ENOSYS; + + ops->reset(bus); + + ops->write_byte(bus, W1_MATCH_ROM); + + for (i = 0; i < sizeof(w1->id); i++) + ops->write_byte(bus, (w1->id >> (i * 8)) & 0xff); + + return 0; +} + +int w1_read_byte(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + const struct w1_ops *ops = device_get_ops(bus); + + if (!ops->read_byte) + return -ENOSYS; + + return ops->read_byte(bus); +} + +int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = w1_read_byte(dev); + if (ret < 0) + return ret; + + buf[i] = ret & 0xff; + } + + return 0; +} + +int w1_write_byte(struct udevice *dev, u8 byte) +{ + struct udevice *bus = dev_get_parent(dev); + const struct w1_ops *ops = device_get_ops(bus); + + if (!ops->write_byte) + return -ENOSYS; + + ops->write_byte(bus, byte); + + return 0; +} + +static int w1_post_probe(struct udevice *bus) +{ + w1_enumerate(bus); + + return 0; +} + +int w1_init(void) +{ + struct udevice *bus; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_W1, &uc); + if (ret) + return ret; + + uclass_foreach_dev(bus, uc) { + ret = device_probe(bus); + if (ret == -ENODEV) { /* No such device. */ + printf("W1 controller not available.\n"); + continue; + } + + if (ret) { /* Other error. */ + printf("W1 controller probe failed.\n"); + continue; + } + } + return 0; +} + +UCLASS_DRIVER(w1) = { + .name = "w1", + .id = UCLASS_W1, + .flags = DM_UC_FLAG_SEQ_ALIAS, + .per_device_auto_alloc_size = sizeof(struct w1_bus), + .post_probe = w1_post_probe, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .post_bind = dm_scan_fdt_dev, +#endif + .per_child_platdata_auto_alloc_size = sizeof(struct w1_device), +}; diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 4b722fc5ca..b08949d370 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -260,7 +260,7 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); - printf("FAT: Misaligned buffer address (%p)\n", buffer); + debug("FAT: Misaligned buffer address (%p)\n", buffer); while (size >= mydata->sect_size) { ret = disk_read(startsect++, 1, tmpbuf); @@ -465,15 +465,6 @@ static __u8 mkcksum(const char name[8], const char ext[3]) } /* - * TODO these should go away once fat_write is reworked to use the - * directory iterator - */ -__u8 get_dentfromdir_block[MAX_CLUSTSIZE] - __aligned(ARCH_DMA_MINALIGN); -__u8 do_fat_read_at_block[MAX_CLUSTSIZE] - __aligned(ARCH_DMA_MINALIGN); - -/* * Read boot sector and volume info from a FAT filesystem */ static int @@ -558,10 +549,17 @@ static int get_fs_info(fsdata *mydata) if (mydata->fatsize == 32) { mydata->fatlength = bs.fat32_length; + mydata->total_sect = bs.total_sect; } else { mydata->fatlength = bs.fat_length; + mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0]; + if (!mydata->total_sect) + mydata->total_sect = bs.total_sect; } + if (!mydata->total_sect) /* unlikely */ + mydata->total_sect = (u32)cur_part_info.size; + mydata->fats = bs.fats; mydata->fat_sect = bs.reserved; mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; @@ -633,7 +631,9 @@ static int get_fs_info(fsdata *mydata) typedef struct { fsdata *fsdata; /* filesystem parameters */ + unsigned start_clust; /* first cluster */ unsigned clust; /* current cluster */ + unsigned next_clust; /* next cluster if remaining == 0 */ int last_cluster; /* set once we've read last cluster */ int is_root; /* is iterator at root directory */ int remaining; /* remaining dent's in current cluster */ @@ -664,7 +664,9 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata) return -ENXIO; itr->fsdata = fsdata; + itr->start_clust = 0; itr->clust = fsdata->root_cluster; + itr->next_clust = fsdata->root_cluster; itr->dent = NULL; itr->remaining = 0; itr->last_cluster = 0; @@ -698,11 +700,14 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) assert(fat_itr_isdir(parent)); itr->fsdata = parent->fsdata; + itr->start_clust = clustnum; if (clustnum > 0) { itr->clust = clustnum; + itr->next_clust = clustnum; itr->is_root = 0; } else { itr->clust = parent->fsdata->root_cluster; + itr->next_clust = parent->fsdata->root_cluster; itr->is_root = 1; } itr->dent = NULL; @@ -720,7 +725,7 @@ static void *next_cluster(fat_itr *itr) if (itr->last_cluster) return NULL; - sect = clust_to_sect(itr->fsdata, itr->clust); + sect = clust_to_sect(itr->fsdata, itr->next_clust); debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", sect, itr->fsdata->clust_size, DIRENTSPERBLOCK); @@ -741,18 +746,19 @@ static void *next_cluster(fat_itr *itr) return NULL; } + itr->clust = itr->next_clust; if (itr->is_root && itr->fsdata->fatsize != 32) { - itr->clust++; - sect = clust_to_sect(itr->fsdata, itr->clust); + itr->next_clust++; + sect = clust_to_sect(itr->fsdata, itr->next_clust); if (sect - itr->fsdata->rootdir_sect >= itr->fsdata->rootdir_size) { - debug("cursect: 0x%x\n", itr->clust); + debug("nextclust: 0x%x\n", itr->next_clust); itr->last_cluster = 1; } } else { - itr->clust = get_fatent(itr->fsdata, itr->clust); - if (CHECK_CLUST(itr->clust, itr->fsdata->fatsize)) { - debug("cursect: 0x%x\n", itr->clust); + itr->next_clust = get_fatent(itr->fsdata, itr->next_clust); + if (CHECK_CLUST(itr->next_clust, itr->fsdata->fatsize)) { + debug("nextclust: 0x%x\n", itr->next_clust); itr->last_cluster = 1; } } @@ -768,8 +774,11 @@ static dir_entry *next_dent(fat_itr *itr) itr->fsdata->clust_size; /* have we reached the last cluster? */ - if (!dent) + if (!dent) { + /* a sign for no more entries left */ + itr->dent = NULL; return NULL; + } itr->remaining = nbytes / sizeof(dir_entry) - 1; itr->dent = dent; @@ -924,6 +933,28 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) while (next[0] && !ISDIRDELIM(next[0])) next++; + if (itr->is_root) { + /* root dir doesn't have "." nor ".." */ + if ((((next - path) == 1) && !strncmp(path, ".", 1)) || + (((next - path) == 2) && !strncmp(path, "..", 2))) { + /* point back to itself */ + itr->clust = itr->fsdata->root_cluster; + itr->next_clust = itr->fsdata->root_cluster; + itr->dent = NULL; + itr->remaining = 0; + itr->last_cluster = 0; + + if (next[0] == 0) { + if (type & TYPE_DIR) + return 0; + else + return -ENOENT; + } + + return fat_itr_resolve(itr, next, type); + } + } + while (fat_itr_next(itr)) { int match = 0; unsigned n = max(strlen(itr->name), (size_t)(next - path)); diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 27e0ff6696..fc211e74bc 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -99,7 +99,6 @@ static void set_name(dir_entry *dirent, const char *filename) debug("ext : %s\n", dirent->ext); } -static __u8 num_of_fats; /* * Write fat buffer into block device */ @@ -128,7 +127,7 @@ static int flush_dirty_fat_buffer(fsdata *mydata) return -1; } - if (num_of_fats == 2) { + if (mydata->fats == 2) { /* Update corresponding second FAT blocks */ startblock += mydata->fatlength; if (disk_write(startblock, getsize, bufptr) < 0) { @@ -210,15 +209,14 @@ name11_12: return 1; } -static int is_next_clust(fsdata *mydata, dir_entry *dentptr); -static void flush_dir_table(fsdata *mydata, dir_entry **dentptr); +static int flush_dir_table(fat_itr *itr); /* * Fill dir_slot entries with appropriate name, id, and attr - * The real directory entry is returned by 'dentptr' + * 'itr' will point to a next entry */ -static void -fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) +static int +fill_dir_slot(fat_itr *itr, const char *l_name) { __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)]; dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer; @@ -226,7 +224,7 @@ fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) int idx = 0, ret; /* Get short file name checksum value */ - checksum = mkcksum((*dentptr)->name, (*dentptr)->ext); + checksum = mkcksum(itr->dent->name, itr->dent->ext); do { memset(slotptr, 0x00, sizeof(dir_slot)); @@ -241,120 +239,21 @@ fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) slotptr->id |= LAST_LONG_ENTRY_MASK; while (counter >= 1) { - if (is_next_clust(mydata, *dentptr)) { - /* A new cluster is allocated for directory table */ - flush_dir_table(mydata, dentptr); - } - memcpy(*dentptr, slotptr, sizeof(dir_slot)); - (*dentptr)++; + memcpy(itr->dent, slotptr, sizeof(dir_slot)); slotptr--; counter--; - } - - if (is_next_clust(mydata, *dentptr)) { - /* A new cluster is allocated for directory table */ - flush_dir_table(mydata, dentptr); - } -} - -static __u32 dir_curclust; - -/* - * Extract the full long filename starting at 'retdent' (which is really - * a slot) into 'l_name'. If successful also copy the real directory entry - * into 'retdent' - * If additional adjacent cluster for directory entries is read into memory, - * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and - * the location of the real directory entry is returned by 'retdent' - * Return 0 on success, -1 otherwise. - */ -static int -get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, - dir_entry **retdent, char *l_name) -{ - dir_entry *realdent; - dir_slot *slotptr = (dir_slot *)(*retdent); - dir_slot *slotptr2 = NULL; - __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? - PREFETCH_BLOCKS : - mydata->clust_size); - __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; - int idx = 0, cur_position = 0; - - if (counter > VFAT_MAXSEQ) { - debug("Error: VFAT name is too long\n"); - return -1; - } - - while ((__u8 *)slotptr < buflimit) { - if (counter == 0) - break; - if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) - return -1; - slotptr++; - counter--; - } - - if ((__u8 *)slotptr >= buflimit) { - if (curclust == 0) - return -1; - curclust = get_fatent(mydata, dir_curclust); - if (CHECK_CLUST(curclust, mydata->fatsize)) { - debug("curclust: 0x%x\n", curclust); - printf("Invalid FAT entry\n"); - return -1; - } - - dir_curclust = curclust; - - if (get_cluster(mydata, curclust, get_contents_vfatname_block, - mydata->clust_size * mydata->sect_size) != 0) { - debug("Error: reading directory block\n"); - return -1; - } - - slotptr2 = (dir_slot *)get_contents_vfatname_block; - while (counter > 0) { - if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) - & 0xff) != counter) + if (!fat_itr_next(itr)) + if (!itr->dent && !itr->is_root && flush_dir_table(itr)) return -1; - slotptr2++; - counter--; - } - - /* Save the real directory entry */ - realdent = (dir_entry *)slotptr2; - while ((__u8 *)slotptr2 > get_contents_vfatname_block) { - slotptr2--; - slot2str(slotptr2, l_name, &idx); - } - } else { - /* Save the real directory entry */ - realdent = (dir_entry *)slotptr; } - do { - slotptr--; - if (slot2str(slotptr, l_name, &idx)) - break; - } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); - - l_name[idx] = '\0'; - if (*l_name == DELETED_FLAG) - *l_name = '\0'; - else if (*l_name == aRING) - *l_name = DELETED_FLAG; - downcase(l_name, INT_MAX); - - /* Return the real directory entry */ - *retdent = realdent; - - if (slotptr2) { - memcpy(get_dentfromdir_block, get_contents_vfatname_block, - mydata->clust_size * mydata->sect_size); - cur_position = (__u8 *)realdent - get_contents_vfatname_block; - *retdent = (dir_entry *) &get_dentfromdir_block[cur_position]; - } + if (!itr->dent && !itr->is_root) + /* + * don't care return value here because we have already + * finished completing an entry with name, only ending up + * no more entry left + */ + flush_dir_table(itr); return 0; } @@ -510,7 +409,7 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); - printf("FAT: Misaligned buffer address (%p)\n", buffer); + debug("FAT: Misaligned buffer address (%p)\n", buffer); while (size >= mydata->sect_size) { memcpy(tmpbuf, buffer, mydata->sect_size); @@ -551,6 +450,121 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, return 0; } +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); + +/* + * Read and modify data on existing and consecutive cluster blocks + */ +static int +get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer, + loff_t size, loff_t *gotsize) +{ + unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; + __u32 startsect; + loff_t wsize; + int clustcount, i, ret; + + *gotsize = 0; + if (!size) + return 0; + + assert(pos < bytesperclust); + startsect = clust_to_sect(mydata, clustnum); + + debug("clustnum: %d, startsect: %d, pos: %lld\n", + clustnum, startsect, pos); + + /* partial write at beginning */ + if (pos) { + wsize = min(bytesperclust - pos, size); + ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster); + if (ret != mydata->clust_size) { + debug("Error reading data (got %d)\n", ret); + return -1; + } + + memcpy(tmpbuf_cluster + pos, buffer, wsize); + ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster); + if (ret != mydata->clust_size) { + debug("Error writing data (got %d)\n", ret); + return -1; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += mydata->clust_size; + + if (!size) + return 0; + } + + /* full-cluster write */ + if (size >= bytesperclust) { + clustcount = lldiv(size, bytesperclust); + + if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) { + wsize = clustcount * bytesperclust; + ret = disk_write(startsect, + clustcount * mydata->clust_size, + buffer); + if (ret != clustcount * mydata->clust_size) { + debug("Error writing data (got %d)\n", ret); + return -1; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += clustcount * mydata->clust_size; + } else { + for (i = 0; i < clustcount; i++) { + memcpy(tmpbuf_cluster, buffer, bytesperclust); + ret = disk_write(startsect, + mydata->clust_size, + tmpbuf_cluster); + if (ret != mydata->clust_size) { + debug("Error writing data (got %d)\n", + ret); + return -1; + } + + size -= bytesperclust; + buffer += bytesperclust; + *gotsize += bytesperclust; + + startsect += mydata->clust_size; + } + } + } + + /* partial write at end */ + if (size) { + wsize = size; + ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster); + if (ret != mydata->clust_size) { + debug("Error reading data (got %d)\n", ret); + return -1; + } + memcpy(tmpbuf_cluster, buffer, wsize); + ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster); + if (ret != mydata->clust_size) { + debug("Error writing data (got %d)\n", ret); + return -1; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + } + + assert(!size); + + return 0; +} + /* * Find the first empty cluster */ @@ -569,20 +583,20 @@ static int find_empty_cluster(fsdata *mydata) } /* - * Write directory entries in 'get_dentfromdir_block' to block device + * Write directory entries in itr's buffer to block device */ -static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) +static int flush_dir_table(fat_itr *itr) { + fsdata *mydata = itr->fsdata; int dir_newclust = 0; + unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; - if (set_cluster(mydata, dir_curclust, - get_dentfromdir_block, - mydata->clust_size * mydata->sect_size) != 0) { - printf("error: wrinting directory entry\n"); - return; + if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) { + printf("error: writing directory entry\n"); + return -1; } dir_newclust = find_empty_cluster(mydata); - set_fatent_value(mydata, dir_curclust, dir_newclust); + set_fatent_value(mydata, itr->clust, dir_newclust); if (mydata->fatsize == 32) set_fatent_value(mydata, dir_newclust, 0xffffff8); else if (mydata->fatsize == 16) @@ -590,15 +604,19 @@ static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) else if (mydata->fatsize == 12) set_fatent_value(mydata, dir_newclust, 0xff8); - dir_curclust = dir_newclust; + itr->clust = dir_newclust; + itr->next_clust = dir_newclust; if (flush_dirty_fat_buffer(mydata) < 0) - return; + return -1; - memset(get_dentfromdir_block, 0x00, - mydata->clust_size * mydata->sect_size); + memset(itr->block, 0x00, bytesperclust); - *dentptr = (dir_entry *) get_dentfromdir_block; + itr->dent = (dir_entry *)itr->block; + itr->last_cluster = 1; + itr->remaining = bytesperclust / sizeof(dir_entry) - 1; + + return 0; } /* @@ -626,37 +644,212 @@ static int clear_fatent(fsdata *mydata, __u32 entry) } /* + * Set start cluster in directory entry + */ +static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr, + __u32 start_cluster) +{ + if (mydata->fatsize == 32) + dentptr->starthi = + cpu_to_le16((start_cluster & 0xffff0000) >> 16); + dentptr->start = cpu_to_le16(start_cluster & 0xffff); +} + +/* + * Check whether adding a file makes the file system to + * exceed the size of the block device + * Return -1 when overflow occurs, otherwise return 0 + */ +static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) +{ + __u32 startsect, sect_num, offset; + + if (clustnum > 0) + startsect = clust_to_sect(mydata, clustnum); + else + startsect = mydata->rootdir_sect; + + sect_num = div_u64_rem(size, mydata->sect_size, &offset); + + if (offset != 0) + sect_num++; + + if (startsect + sect_num > total_sector) + return -1; + return 0; +} + +/* * Write at most 'maxsize' bytes from 'buffer' into * the file associated with 'dentptr' * Update the number of bytes written in *gotsize and return 0 * or return -1 on fatal errors. */ static int -set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, - loff_t maxsize, loff_t *gotsize) +set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, + loff_t maxsize, loff_t *gotsize) { - loff_t filesize = FAT2CPU32(dentptr->size); + loff_t filesize; unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; __u32 curclust = START(dentptr); __u32 endclust = 0, newclust = 0; - loff_t actsize; + loff_t cur_pos, offset, actsize, wsize; *gotsize = 0; - debug("Filesize: %llu bytes\n", filesize); - - if (maxsize > 0 && filesize > maxsize) - filesize = maxsize; + filesize = pos + maxsize; debug("%llu bytes\n", filesize); + if (!filesize) { + if (!curclust) + return 0; + if (!CHECK_CLUST(curclust, mydata->fatsize) || + IS_LAST_CLUST(curclust, mydata->fatsize)) { + clear_fatent(mydata, curclust); + set_start_cluster(mydata, dentptr, 0); + return 0; + } + debug("curclust: 0x%x\n", curclust); + debug("Invalid FAT entry\n"); + return -1; + } + if (!curclust) { - if (filesize) { - debug("error: nonempty clusterless file!\n"); + assert(pos == 0); + goto set_clusters; + } + + /* go to cluster at pos */ + cur_pos = bytesperclust; + while (1) { + if (pos <= cur_pos) + break; + if (IS_LAST_CLUST(curclust, mydata->fatsize)) + break; + + newclust = get_fatent(mydata, curclust); + if (!IS_LAST_CLUST(newclust, mydata->fatsize) && + CHECK_CLUST(newclust, mydata->fatsize)) { + debug("curclust: 0x%x\n", curclust); + debug("Invalid FAT entry\n"); return -1; } + + cur_pos += bytesperclust; + curclust = newclust; + } + if (IS_LAST_CLUST(curclust, mydata->fatsize)) { + assert(pos == cur_pos); + goto set_clusters; + } + + assert(pos < cur_pos); + cur_pos -= bytesperclust; + + /* overwrite */ + assert(IS_LAST_CLUST(curclust, mydata->fatsize) || + !CHECK_CLUST(curclust, mydata->fatsize)); + + while (1) { + /* search for allocated consecutive clusters */ + actsize = bytesperclust; + endclust = curclust; + while (1) { + if (filesize <= (cur_pos + actsize)) + break; + + newclust = get_fatent(mydata, endclust); + + if (IS_LAST_CLUST(newclust, mydata->fatsize)) + break; + if (CHECK_CLUST(newclust, mydata->fatsize)) { + debug("curclust: 0x%x\n", curclust); + debug("Invalid FAT entry\n"); + return -1; + } + + actsize += bytesperclust; + endclust = newclust; + } + + /* overwrite to <curclust..endclust> */ + if (pos < cur_pos) + offset = 0; + else + offset = pos - cur_pos; + wsize = min(cur_pos + actsize, filesize) - pos; + if (get_set_cluster(mydata, curclust, offset, + buffer, wsize, &actsize)) { + printf("Error get-and-setting cluster\n"); + return -1; + } + buffer += wsize; + *gotsize += wsize; + cur_pos += offset + wsize; + + if (filesize <= cur_pos) + break; + + /* CHECK: newclust = get_fatent(mydata, endclust); */ + + if (IS_LAST_CLUST(newclust, mydata->fatsize)) + /* no more clusters */ + break; + + curclust = newclust; + } + + if (filesize <= cur_pos) { + /* no more write */ + newclust = get_fatent(mydata, endclust); + if (!IS_LAST_CLUST(newclust, mydata->fatsize)) { + /* truncate the rest */ + clear_fatent(mydata, newclust); + + /* Mark end of file in FAT */ + if (mydata->fatsize == 12) + newclust = 0xfff; + else if (mydata->fatsize == 16) + newclust = 0xffff; + else if (mydata->fatsize == 32) + newclust = 0xfffffff; + set_fatent_value(mydata, endclust, newclust); + } + return 0; } + curclust = endclust; + filesize -= cur_pos; + assert(!(cur_pos % bytesperclust)); + +set_clusters: + /* allocate and write */ + assert(!pos); + + /* Assure that curclust is valid */ + if (!curclust) { + curclust = find_empty_cluster(mydata); + set_start_cluster(mydata, dentptr, curclust); + } else { + newclust = get_fatent(mydata, curclust); + + if (IS_LAST_CLUST(newclust, mydata->fatsize)) { + newclust = determine_fatent(mydata, curclust); + set_fatent_value(mydata, curclust, newclust); + curclust = newclust; + } else { + debug("error: something wrong\n"); + return -1; + } + } + + /* TODO: already partially written */ + if (check_overflow(mydata, curclust, filesize)) { + printf("Error: no space left: %llu\n", filesize); + return -1; + } + actsize = bytesperclust; endclust = curclust; do { @@ -665,6 +858,7 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, newclust = determine_fatent(mydata, endclust); if ((newclust - 1) != endclust) + /* write to <curclust..endclust> */ goto getit; if (CHECK_CLUST(newclust, mydata->fatsize)) { @@ -711,18 +905,8 @@ getit: actsize = bytesperclust; curclust = endclust = newclust; } while (1); -} -/* - * Set start cluster in directory entry - */ -static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr, - __u32 start_cluster) -{ - if (mydata->fatsize == 32) - dentptr->starthi = - cpu_to_le16((start_cluster & 0xffff0000) >> 16); - dentptr->start = cpu_to_le16(start_cluster & 0xffff); + return 0; } /* @@ -740,334 +924,512 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr, } /* - * Check whether adding a file makes the file system to - * exceed the size of the block device - * Return -1 when overflow occurs, otherwise return 0 + * Find a directory entry based on filename or start cluster number + * If the directory entry is not found, + * the new position for writing a directory entry will be returned */ -static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) +static dir_entry *find_directory_entry(fat_itr *itr, char *filename) { - __u32 startsect, sect_num, offset; + int match = 0; - if (clustnum > 0) { - startsect = clust_to_sect(mydata, clustnum); - } else { - startsect = mydata->rootdir_sect; + while (fat_itr_next(itr)) { + /* check both long and short name: */ + if (!strcasecmp(filename, itr->name)) + match = 1; + else if (itr->name != itr->s_name && + !strcasecmp(filename, itr->s_name)) + match = 1; + + if (!match) + continue; + + if (itr->dent->name[0] == '\0') + return NULL; + else + return itr->dent; } - sect_num = div_u64_rem(size, mydata->sect_size, &offset); + if (!itr->dent && !itr->is_root && flush_dir_table(itr)) + /* indicate that allocating dent failed */ + itr->dent = NULL; - if (offset != 0) - sect_num++; + return NULL; +} + +static int split_filename(char *filename, char **dirname, char **basename) +{ + char *p, *last_slash, *last_slash_cont; + +again: + p = filename; + last_slash = NULL; + last_slash_cont = NULL; + while (*p) { + if (ISDIRDELIM(*p)) { + last_slash = p; + last_slash_cont = p; + /* continuous slashes */ + while (ISDIRDELIM(*p)) + last_slash_cont = p++; + if (!*p) + break; + } + p++; + } + + if (last_slash) { + if (last_slash_cont == (filename + strlen(filename) - 1)) { + /* remove trailing slashes */ + *last_slash = '\0'; + goto again; + } + + if (last_slash == filename) { + /* avoid ""(null) directory */ + *dirname = "/"; + } else { + *last_slash = '\0'; + *dirname = filename; + } + + *last_slash_cont = '\0'; + *basename = last_slash_cont + 1; + } else { + *dirname = "/"; /* root by default */ + *basename = filename; + } - if (startsect + sect_num > total_sector) - return -1; return 0; } -/* - * Check if adding several entries exceed one cluster boundary - */ -static int is_next_clust(fsdata *mydata, dir_entry *dentptr) +static int normalize_longname(char *l_filename, const char *filename) { - int cur_position; + const char *p, legal[] = "!#$%&\'()-.@^`_{}~"; + char c; + int name_len; - cur_position = (__u8 *)dentptr - get_dentfromdir_block; + /* Check that the filename is valid */ + for (p = filename; p < filename + strlen(filename); p++) { + c = *p; + + if (('0' <= c) && (c <= '9')) + continue; + if (('A' <= c) && (c <= 'Z')) + continue; + if (('a' <= c) && (c <= 'z')) + continue; + if (strchr(legal, c)) + continue; + /* extended code */ + if ((0x80 <= c) && (c <= 0xff)) + continue; - if (cur_position >= mydata->clust_size * mydata->sect_size) - return 1; - else - return 0; + return -1; + } + + /* Normalize it */ + name_len = strlen(filename); + if (name_len >= VFAT_MAXLEN_BYTES) + /* should return an error? */ + name_len = VFAT_MAXLEN_BYTES - 1; + + memcpy(l_filename, filename, name_len); + l_filename[name_len] = 0; /* terminate the string */ + downcase(l_filename, INT_MAX); + + return 0; } -static dir_entry *empty_dentptr; -/* - * Find a directory entry based on filename or start cluster number - * If the directory entry is not found, - * the new position for writing a directory entry will be returned - */ -static dir_entry *find_directory_entry(fsdata *mydata, int startsect, - char *filename, dir_entry *retdent, __u32 start) +int file_fat_write_at(const char *filename, loff_t pos, void *buffer, + loff_t size, loff_t *actwrite) { - __u32 curclust = sect_to_clust(mydata, startsect); + dir_entry *retdent; + fsdata datablock = { .fatbuf = NULL, }; + fsdata *mydata = &datablock; + fat_itr *itr = NULL; + int ret = -1; + char *filename_copy, *parent, *basename; + char l_filename[VFAT_MAXLEN_BYTES]; - debug("get_dentfromdir: %s\n", filename); + debug("writing %s\n", filename); - while (1) { - dir_entry *dentptr; + filename_copy = strdup(filename); + if (!filename_copy) + return -ENOMEM; - int i; + split_filename(filename_copy, &parent, &basename); + if (!strlen(basename)) { + ret = -EINVAL; + goto exit; + } - if (get_cluster(mydata, curclust, get_dentfromdir_block, - mydata->clust_size * mydata->sect_size) != 0) { - printf("Error: reading directory block\n"); - return NULL; - } + filename = basename; + if (normalize_longname(l_filename, filename)) { + printf("FAT: illegal filename (%s)\n", filename); + ret = -EINVAL; + goto exit; + } - dentptr = (dir_entry *)get_dentfromdir_block; + itr = malloc_cache_aligned(sizeof(fat_itr)); + if (!itr) { + ret = -ENOMEM; + goto exit; + } - dir_curclust = curclust; + ret = fat_itr_root(itr, &datablock); + if (ret) + goto exit; - for (i = 0; i < DIRENTSPERCLUST; i++) { - char s_name[14], l_name[VFAT_MAXLEN_BYTES]; + total_sector = datablock.total_sect; - l_name[0] = '\0'; - if (dentptr->name[0] == DELETED_FLAG) { - dentptr++; - if (is_next_clust(mydata, dentptr)) - break; - continue; - } - if ((dentptr->attr & ATTR_VOLUME)) { - if ((dentptr->attr & ATTR_VFAT) && - (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { - get_long_file_name(mydata, curclust, - get_dentfromdir_block, - &dentptr, l_name); - debug("vfatname: |%s|\n", l_name); - } else { - /* Volume label or VFAT entry */ - dentptr++; - if (is_next_clust(mydata, dentptr)) - break; - continue; - } - } - if (dentptr->name[0] == 0) { - debug("Dentname == NULL - %d\n", i); - empty_dentptr = dentptr; - return NULL; - } + ret = fat_itr_resolve(itr, parent, TYPE_DIR); + if (ret) { + printf("%s: doesn't exist (%d)\n", parent, ret); + goto exit; + } - get_name(dentptr, s_name); + retdent = find_directory_entry(itr, l_filename); - if (strncasecmp(filename, s_name, sizeof(s_name)) && - strncasecmp(filename, l_name, sizeof(l_name))) { - debug("Mismatch: |%s|%s|\n", - s_name, l_name); - dentptr++; - if (is_next_clust(mydata, dentptr)) - break; - continue; - } + if (retdent) { + if (fat_itr_isdir(itr)) { + ret = -EISDIR; + goto exit; + } - memcpy(retdent, dentptr, sizeof(dir_entry)); + /* A file exists */ + if (pos == -1) + /* Append to the end */ + pos = FAT2CPU32(retdent->size); + if (pos > retdent->size) { + /* No hole allowed */ + ret = -EINVAL; + goto exit; + } - debug("DentName: %s", s_name); - debug(", start: 0x%x", START(dentptr)); - debug(", size: 0x%x %s\n", - FAT2CPU32(dentptr->size), - (dentptr->attr & ATTR_DIR) ? - "(DIR)" : ""); + /* Update file size in a directory entry */ + retdent->size = cpu_to_le32(pos + size); + } else { + /* Create a new file */ - return dentptr; + if (itr->is_root) { + /* root dir cannot have "." or ".." */ + if (!strcmp(l_filename, ".") || + !strcmp(l_filename, "..")) { + ret = -EINVAL; + goto exit; + } } - /* - * In FAT16/12, the root dir is locate before data area, shows - * in following: - * ------------------------------------------------------------- - * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | - * ------------------------------------------------------------- - * - * As a result if curclust is in Root dir, it is a negative - * number or 0, 1. - * - */ - if (mydata->fatsize != 32 && (int)curclust <= 1) { - /* Current clust is in root dir, set to next clust */ - curclust++; - if ((int)curclust <= 1) - continue; /* continue to find */ - - /* Reach the end of root dir */ - empty_dentptr = dentptr; - return NULL; + if (!itr->dent) { + printf("Error: allocating new dir entry\n"); + ret = -EIO; + goto exit; } - curclust = get_fatent(mydata, dir_curclust); - if (IS_LAST_CLUST(curclust, mydata->fatsize)) { - empty_dentptr = dentptr; - return NULL; + if (pos) { + /* No hole allowed */ + ret = -EINVAL; + goto exit; } - if (CHECK_CLUST(curclust, mydata->fatsize)) { - debug("curclust: 0x%x\n", curclust); - debug("Invalid FAT entry\n"); - return NULL; + + memset(itr->dent, 0, sizeof(*itr->dent)); + + /* Set short name to set alias checksum field in dir_slot */ + set_name(itr->dent, filename); + if (fill_dir_slot(itr, filename)) { + ret = -EIO; + goto exit; } + + /* Set attribute as archive for regular file */ + fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20); + + retdent = itr->dent; } - return NULL; + ret = set_contents(mydata, retdent, pos, buffer, size, actwrite); + if (ret < 0) { + printf("Error: writing contents\n"); + ret = -EIO; + goto exit; + } + debug("attempt to write 0x%llx bytes\n", *actwrite); + + /* Flush fat buffer */ + ret = flush_dirty_fat_buffer(mydata); + if (ret) { + printf("Error: flush fat buffer\n"); + ret = -EIO; + goto exit; + } + + /* Write directory table to device */ + ret = set_cluster(mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); + if (ret) { + printf("Error: writing directory entry\n"); + ret = -EIO; + } + +exit: + free(filename_copy); + free(mydata->fatbuf); + free(itr); + return ret; } -static int do_fat_write(const char *filename, void *buffer, loff_t size, - loff_t *actwrite) +int file_fat_write(const char *filename, void *buffer, loff_t offset, + loff_t maxsize, loff_t *actwrite) { - dir_entry *dentptr, *retdent; - __u32 startsect; - __u32 start_cluster; - boot_sector bs; - volume_info volinfo; - fsdata datablock; - fsdata *mydata = &datablock; - int cursect, i; - int ret = -1, name_len; - char l_filename[VFAT_MAXLEN_BYTES]; - char bad[2] = " "; - const char illegal[] = "<>:\"/\\|?*"; + return file_fat_write_at(filename, offset, buffer, maxsize, actwrite); +} - *actwrite = size; - dir_curclust = 0; +static int fat_dir_entries(fat_itr *itr) +{ + fat_itr *dirs; + fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata; + /* for FATBUFSIZE */ + int count; - if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { - debug("error: reading boot sector\n"); - return -1; + dirs = malloc_cache_aligned(sizeof(fat_itr)); + if (!dirs) { + debug("Error: allocating memory\n"); + count = -ENOMEM; + goto exit; } - total_sector = bs.total_sect; - if (total_sector == 0) - total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ + /* duplicate fsdata */ + fat_itr_child(dirs, itr); + fsdata = *dirs->fsdata; - if (mydata->fatsize == 32) - mydata->fatlength = bs.fat32_length; - else - mydata->fatlength = bs.fat_length; + /* allocate local fat buffer */ + fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE); + if (!fsdata.fatbuf) { + debug("Error: allocating memory\n"); + count = -ENOMEM; + goto exit; + } + fsdata.fatbufnum = -1; + dirs->fsdata = &fsdata; - mydata->fat_sect = bs.reserved; + for (count = 0; fat_itr_next(dirs); count++) + ; - cursect = mydata->rootdir_sect - = mydata->fat_sect + mydata->fatlength * bs.fats; - num_of_fats = bs.fats; +exit: + free(fsdata.fatbuf); + free(dirs); + return count; +} - mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; - mydata->clust_size = bs.cluster_size; +static int delete_dentry(fat_itr *itr) +{ + fsdata *mydata = itr->fsdata; + dir_entry *dentptr = itr->dent; - if (mydata->fatsize == 32) { - mydata->data_begin = mydata->rootdir_sect - - (mydata->clust_size * 2); - } else { - int rootdir_size; - - rootdir_size = ((bs.dir_entries[1] * (int)256 + - bs.dir_entries[0]) * - sizeof(dir_entry)) / - mydata->sect_size; - mydata->data_begin = mydata->rootdir_sect + - rootdir_size - - (mydata->clust_size * 2); + /* free cluster blocks */ + clear_fatent(mydata, START(dentptr)); + if (flush_dirty_fat_buffer(mydata) < 0) { + printf("Error: flush fat buffer\n"); + return -EIO; } - mydata->fatbufnum = -1; - mydata->fat_dirty = 0; - mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); - if (mydata->fatbuf == NULL) { - debug("Error: allocating memory\n"); - return -1; + /* + * update a directory entry + * TODO: + * - long file name support + * - find and mark the "new" first invalid entry as name[0]=0x00 + */ + memset(dentptr, 0, sizeof(*dentptr)); + dentptr->name[0] = 0xe5; + + if (set_cluster(mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size) != 0) { + printf("error: writing directory entry\n"); + return -EIO; } - if (disk_read(cursect, - (mydata->fatsize == 32) ? - (mydata->clust_size) : - PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { - debug("Error: reading rootdir block\n"); + return 0; +} + +int fat_unlink(const char *filename) +{ + fsdata fsdata = { .fatbuf = NULL, }; + fat_itr *itr = NULL; + int n_entries, ret; + char *filename_copy, *dirname, *basename; + + filename_copy = strdup(filename); + split_filename(filename_copy, &dirname, &basename); + + if (!strcmp(dirname, "/") && !strcmp(basename, "")) { + printf("Error: cannot remove root\n"); + ret = -EINVAL; goto exit; } - dentptr = (dir_entry *) do_fat_read_at_block; - /* Strip leading (back-)slashes */ - while ISDIRDELIM(*filename) - ++filename; - /* Check that the filename is valid */ - for (i = 0; i < strlen(illegal); ++i) { - *bad = illegal[i]; - if (strstr(filename, bad)) { - printf("FAT: illegal filename (%s)\n", filename); - return -1; + itr = malloc_cache_aligned(sizeof(fat_itr)); + if (!itr) { + printf("Error: allocating memory\n"); + return -ENOMEM; + } + + ret = fat_itr_root(itr, &fsdata); + if (ret) + goto exit; + + total_sector = fsdata.total_sect; + + ret = fat_itr_resolve(itr, dirname, TYPE_DIR); + if (ret) { + printf("%s: doesn't exist (%d)\n", dirname, ret); + ret = -ENOENT; + goto exit; + } + + if (!find_directory_entry(itr, basename)) { + printf("%s: doesn't exist\n", basename); + ret = -ENOENT; + goto exit; + } + + if (fat_itr_isdir(itr)) { + n_entries = fat_dir_entries(itr); + if (n_entries < 0) { + ret = n_entries; + goto exit; + } + if (n_entries > 2) { + printf("Error: directory is not empty: %d\n", + n_entries); + ret = -EINVAL; + goto exit; } } - name_len = strlen(filename); - if (name_len >= VFAT_MAXLEN_BYTES) - name_len = VFAT_MAXLEN_BYTES - 1; + ret = delete_dentry(itr); - memcpy(l_filename, filename, name_len); - l_filename[name_len] = 0; /* terminate the string */ - downcase(l_filename, INT_MAX); +exit: + free(fsdata.fatbuf); + free(itr); + free(filename_copy); - startsect = mydata->rootdir_sect; - retdent = find_directory_entry(mydata, startsect, - l_filename, dentptr, 0); - if (retdent) { - /* Update file size and start_cluster in a directory entry */ - retdent->size = cpu_to_le32(size); - start_cluster = START(retdent); - - if (start_cluster) { - if (size) { - ret = check_overflow(mydata, start_cluster, - size); - if (ret) { - printf("Error: %llu overflow\n", size); - goto exit; - } - } + return ret; +} - ret = clear_fatent(mydata, start_cluster); - if (ret) { - printf("Error: clearing FAT entries\n"); - goto exit; - } +int fat_mkdir(const char *new_dirname) +{ + dir_entry *retdent; + fsdata datablock = { .fatbuf = NULL, }; + fsdata *mydata = &datablock; + fat_itr *itr = NULL; + char *dirname_copy, *parent, *dirname; + char l_dirname[VFAT_MAXLEN_BYTES]; + int ret = -1; + loff_t actwrite; + unsigned int bytesperclust; + dir_entry *dotdent = NULL; + + dirname_copy = strdup(new_dirname); + if (!dirname_copy) + goto exit; - if (!size) - set_start_cluster(mydata, retdent, 0); - } else if (size) { - ret = start_cluster = find_empty_cluster(mydata); - if (ret < 0) { - printf("Error: finding empty cluster\n"); - goto exit; - } + split_filename(dirname_copy, &parent, &dirname); + if (!strlen(dirname)) { + ret = -EINVAL; + goto exit; + } - ret = check_overflow(mydata, start_cluster, size); - if (ret) { - printf("Error: %llu overflow\n", size); - goto exit; - } + if (normalize_longname(l_dirname, dirname)) { + printf("FAT: illegal filename (%s)\n", dirname); + ret = -EINVAL; + goto exit; + } - set_start_cluster(mydata, retdent, start_cluster); - } - } else { - /* Set short name to set alias checksum field in dir_slot */ - set_name(empty_dentptr, filename); - fill_dir_slot(mydata, &empty_dentptr, filename); + itr = malloc_cache_aligned(sizeof(fat_itr)); + if (!itr) { + ret = -ENOMEM; + goto exit; + } - if (size) { - ret = start_cluster = find_empty_cluster(mydata); - if (ret < 0) { - printf("Error: finding empty cluster\n"); - goto exit; - } + ret = fat_itr_root(itr, &datablock); + if (ret) + goto exit; + + total_sector = datablock.total_sect; + + ret = fat_itr_resolve(itr, parent, TYPE_DIR); + if (ret) { + printf("%s: doesn't exist (%d)\n", parent, ret); + goto exit; + } + + retdent = find_directory_entry(itr, l_dirname); - ret = check_overflow(mydata, start_cluster, size); - if (ret) { - printf("Error: %llu overflow\n", size); + if (retdent) { + printf("%s: already exists\n", l_dirname); + ret = -EEXIST; + goto exit; + } else { + if (itr->is_root) { + /* root dir cannot have "." or ".." */ + if (!strcmp(l_dirname, ".") || + !strcmp(l_dirname, "..")) { + ret = -EINVAL; goto exit; } - } else { - start_cluster = 0; } - /* Set attribute as archieve for regular file */ - fill_dentry(mydata, empty_dentptr, filename, - start_cluster, size, 0x20); + if (!itr->dent) { + printf("Error: allocating new dir entry\n"); + ret = -EIO; + goto exit; + } + + memset(itr->dent, 0, sizeof(*itr->dent)); + + /* Set short name to set alias checksum field in dir_slot */ + set_name(itr->dent, dirname); + fill_dir_slot(itr, dirname); + + /* Set attribute as archive for regular file */ + fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0, + ATTR_DIR | ATTR_ARCH); - retdent = empty_dentptr; + retdent = itr->dent; } - ret = set_contents(mydata, retdent, buffer, size, actwrite); + /* Default entries */ + bytesperclust = mydata->clust_size * mydata->sect_size; + dotdent = malloc_cache_aligned(bytesperclust); + if (!dotdent) { + ret = -ENOMEM; + goto exit; + } + memset(dotdent, 0, bytesperclust); + + memcpy(dotdent[0].name, ". ", 8); + memcpy(dotdent[0].ext, " ", 3); + dotdent[0].attr = ATTR_DIR | ATTR_ARCH; + + memcpy(dotdent[1].name, ".. ", 8); + memcpy(dotdent[1].ext, " ", 3); + dotdent[1].attr = ATTR_DIR | ATTR_ARCH; + set_start_cluster(mydata, &dotdent[1], itr->start_clust); + + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, + bytesperclust, &actwrite); + if (ret < 0) { + printf("Error: writing contents\n"); + goto exit; + } + /* Write twice for "." */ + set_start_cluster(mydata, &dotdent[0], START(retdent)); + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, + bytesperclust, &actwrite); if (ret < 0) { printf("Error: writing contents\n"); goto exit; } - debug("attempt to write 0x%llx bytes\n", *actwrite); /* Flush fat buffer */ ret = flush_dirty_fat_buffer(mydata); @@ -1077,24 +1439,15 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, } /* Write directory table to device */ - ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block, - mydata->clust_size * mydata->sect_size); + ret = set_cluster(mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); if (ret) printf("Error: writing directory entry\n"); exit: + free(dirname_copy); free(mydata->fatbuf); + free(itr); + free(dotdent); return ret; } - -int file_fat_write(const char *filename, void *buffer, loff_t offset, - loff_t maxsize, loff_t *actwrite) -{ - if (offset != 0) { - printf("Error: non zero offset is currently not supported.\n"); - return -1; - } - - printf("writing %s\n", filename); - return do_fat_write(filename, buffer, maxsize, actwrite); -} @@ -105,6 +105,16 @@ static inline int fs_opendir_unsupported(const char *filename, return -EACCES; } +static inline int fs_unlink_unsupported(const char *filename) +{ + return -1; +} + +static inline int fs_mkdir_unsupported(const char *dirname) +{ + return -1; +} + struct fstype_info { int fstype; char *name; @@ -142,6 +152,8 @@ struct fstype_info { int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp); /* see fs_closedir() */ void (*closedir)(struct fs_dir_stream *dirs); + int (*unlink)(const char *filename); + int (*mkdir)(const char *dirname); }; static struct fstype_info fstypes[] = { @@ -158,8 +170,12 @@ static struct fstype_info fstypes[] = { .read = fat_read_file, #ifdef CONFIG_FAT_WRITE .write = file_fat_write, + .unlink = fat_unlink, + .mkdir = fat_mkdir, #else .write = fs_write_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, #endif .uuid = fs_uuid_unsupported, .opendir = fat_opendir, @@ -185,6 +201,8 @@ static struct fstype_info fstypes[] = { #endif .uuid = ext4fs_uuid, .opendir = fs_opendir_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_SANDBOX @@ -201,6 +219,8 @@ static struct fstype_info fstypes[] = { .write = fs_write_sandbox, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_CMD_UBIFS @@ -217,6 +237,8 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_FS_BTRFS @@ -233,6 +255,8 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = btrfs_uuid, .opendir = fs_opendir_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, }, #endif { @@ -248,6 +272,8 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, }, }; @@ -497,6 +523,33 @@ void fs_closedir(struct fs_dir_stream *dirs) fs_close(); } +int fs_unlink(const char *filename) +{ + int ret; + + struct fstype_info *info = fs_get_info(fs_type); + + ret = info->unlink(filename); + + fs_type = FS_TYPE_ANY; + fs_close(); + + return ret; +} + +int fs_mkdir(const char *dirname) +{ + int ret; + + struct fstype_info *info = fs_get_info(fs_type); + + ret = info->mkdir(dirname); + + fs_type = FS_TYPE_ANY; + fs_close(); + + return ret; +} int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype) @@ -700,3 +753,37 @@ int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_SUCCESS; } +int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype) +{ + if (argc != 4) + return CMD_RET_USAGE; + + if (fs_set_blk_dev(argv[1], argv[2], fstype)) + return 1; + + if (fs_unlink(argv[3])) + return 1; + + return 0; +} + +int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype) +{ + int ret; + + if (argc != 4) + return CMD_RET_USAGE; + + if (fs_set_blk_dev(argv[1], argv[2], fstype)) + return 1; + + ret = fs_mkdir(argv[3]); + if (ret) { + printf("** Unable to create a directory \"%s\" **\n", argv[3]); + return 1; + } + + return 0; +} diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h new file mode 100644 index 0000000000..94d0747194 --- /dev/null +++ b/include/asm-generic/atomic.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _ASM_GENERIC_ATOMIC_H +#define _ASM_GENERIC_ATOMIC_H + +typedef struct { volatile int counter; } atomic_t; +#if BITS_PER_LONG == 32 +typedef struct { volatile long long counter; } atomic64_t; +#else /* BIT_PER_LONG == 32 */ +typedef struct { volatile long counter; } atomic64_t; +#endif + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v, i) ((v)->counter = (i)) +#define atomic64_read(v) atomic_read(v) +#define atomic64_set(v, i) atomic_set(v, i) + +static inline void atomic_add(int i, atomic_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter += i; + local_irq_restore(flags); +} + +static inline void atomic_sub(int i, atomic_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter -= i; + local_irq_restore(flags); +} + +static inline void atomic_inc(atomic_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + ++v->counter; + local_irq_restore(flags); +} + +static inline void atomic_dec(atomic_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + --v->counter; + local_irq_restore(flags); +} + +static inline int atomic_dec_and_test(volatile atomic_t *v) +{ + unsigned long flags = 0; + int val; + + local_irq_save(flags); + val = v->counter; + v->counter = val -= 1; + local_irq_restore(flags); + + return val == 0; +} + +static inline int atomic_add_negative(int i, volatile atomic_t *v) +{ + unsigned long flags = 0; + int val; + + local_irq_save(flags); + val = v->counter; + v->counter = val += i; + local_irq_restore(flags); + + return val < 0; +} + +static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) +{ + unsigned long flags = 0; + + local_irq_save(flags); + *addr &= ~mask; + local_irq_restore(flags); +} + +#if BITS_PER_LONG == 32 + +static inline void atomic64_add(long long i, volatile atomic64_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter += i; + local_irq_restore(flags); +} + +static inline void atomic64_sub(long long i, volatile atomic64_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter -= i; + local_irq_restore(flags); +} + +#else /* BIT_PER_LONG == 32 */ + +static inline void atomic64_add(long i, volatile atomic64_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter += i; + local_irq_restore(flags); +} + +static inline void atomic64_sub(long i, volatile atomic64_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter -= i; + local_irq_restore(flags); +} +#endif + +static inline void atomic64_inc(volatile atomic64_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter += 1; + local_irq_restore(flags); +} + +static inline void atomic64_dec(volatile atomic64_t *v) +{ + unsigned long flags = 0; + + local_irq_save(flags); + v->counter -= 1; + local_irq_restore(flags); +} + +#endif diff --git a/include/blk.h b/include/blk.h index 86f6d5057f..6af219681c 100644 --- a/include/blk.h +++ b/include/blk.h @@ -406,6 +406,15 @@ int blk_select_hwpart(struct udevice *dev, int hwpart); */ int blk_get_from_parent(struct udevice *parent, struct udevice **devp); +/** + * blk_get_by_device() - Get the block device descriptor for the given device + * @dev: Instance of a storage device + * + * Return: With block device descriptor on success , NULL if there is no such + * block device. + */ +struct blk_desc *blk_get_by_device(struct udevice *dev); + #else #include <errno.h> /* diff --git a/include/capitalization.h b/include/capitalization.h new file mode 100644 index 0000000000..9d7e8d259c --- /dev/null +++ b/include/capitalization.h @@ -0,0 +1,2028 @@ +/* SPDX-License-Identifier: Unicode-DFS-2016 */ +/* + * Capitalization tables + */ + +struct capitalization_table { + u16 upper; + u16 lower; +}; + +/* + * Correspondence table for small and capital Unicode letters in the range of + * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt + */ +#define UNICODE_CAPITALIZATION_TABLE { \ + { 0x0531, /* ARMENIAN CAPITAL LETTER AYB */ \ + 0x0561, /* ARMENIAN SMALL LETTER AYB */ }, \ + { 0x0532, /* ARMENIAN CAPITAL LETTER BEN */ \ + 0x0562, /* ARMENIAN SMALL LETTER BEN */ }, \ + { 0x053E, /* ARMENIAN CAPITAL LETTER CA */ \ + 0x056E, /* ARMENIAN SMALL LETTER CA */ }, \ + { 0x0549, /* ARMENIAN CAPITAL LETTER CHA */ \ + 0x0579, /* ARMENIAN SMALL LETTER CHA */ }, \ + { 0x0543, /* ARMENIAN CAPITAL LETTER CHEH */ \ + 0x0573, /* ARMENIAN SMALL LETTER CHEH */ }, \ + { 0x0551, /* ARMENIAN CAPITAL LETTER CO */ \ + 0x0581, /* ARMENIAN SMALL LETTER CO */ }, \ + { 0x0534, /* ARMENIAN CAPITAL LETTER DA */ \ + 0x0564, /* ARMENIAN SMALL LETTER DA */ }, \ + { 0x0535, /* ARMENIAN CAPITAL LETTER ECH */ \ + 0x0565, /* ARMENIAN SMALL LETTER ECH */ }, \ + { 0x0537, /* ARMENIAN CAPITAL LETTER EH */ \ + 0x0567, /* ARMENIAN SMALL LETTER EH */ }, \ + { 0x0538, /* ARMENIAN CAPITAL LETTER ET */ \ + 0x0568, /* ARMENIAN SMALL LETTER ET */ }, \ + { 0x0556, /* ARMENIAN CAPITAL LETTER FEH */ \ + 0x0586, /* ARMENIAN SMALL LETTER FEH */ }, \ + { 0x0542, /* ARMENIAN CAPITAL LETTER GHAD */ \ + 0x0572, /* ARMENIAN SMALL LETTER GHAD */ }, \ + { 0x0533, /* ARMENIAN CAPITAL LETTER GIM */ \ + 0x0563, /* ARMENIAN SMALL LETTER GIM */ }, \ + { 0x0540, /* ARMENIAN CAPITAL LETTER HO */ \ + 0x0570, /* ARMENIAN SMALL LETTER HO */ }, \ + { 0x053B, /* ARMENIAN CAPITAL LETTER INI */ \ + 0x056B, /* ARMENIAN SMALL LETTER INI */ }, \ + { 0x0541, /* ARMENIAN CAPITAL LETTER JA */ \ + 0x0571, /* ARMENIAN SMALL LETTER JA */ }, \ + { 0x054B, /* ARMENIAN CAPITAL LETTER JHEH */ \ + 0x057B, /* ARMENIAN SMALL LETTER JHEH */ }, \ + { 0x0554, /* ARMENIAN CAPITAL LETTER KEH */ \ + 0x0584, /* ARMENIAN SMALL LETTER KEH */ }, \ + { 0x053F, /* ARMENIAN CAPITAL LETTER KEN */ \ + 0x056F, /* ARMENIAN SMALL LETTER KEN */ }, \ + { 0x053C, /* ARMENIAN CAPITAL LETTER LIWN */ \ + 0x056C, /* ARMENIAN SMALL LETTER LIWN */ }, \ + { 0x0544, /* ARMENIAN CAPITAL LETTER MEN */ \ + 0x0574, /* ARMENIAN SMALL LETTER MEN */ }, \ + { 0x0546, /* ARMENIAN CAPITAL LETTER NOW */ \ + 0x0576, /* ARMENIAN SMALL LETTER NOW */ }, \ + { 0x0555, /* ARMENIAN CAPITAL LETTER OH */ \ + 0x0585, /* ARMENIAN SMALL LETTER OH */ }, \ + { 0x054A, /* ARMENIAN CAPITAL LETTER PEH */ \ + 0x057A, /* ARMENIAN SMALL LETTER PEH */ }, \ + { 0x0553, /* ARMENIAN CAPITAL LETTER PIWR */ \ + 0x0583, /* ARMENIAN SMALL LETTER PIWR */ }, \ + { 0x054C, /* ARMENIAN CAPITAL LETTER RA */ \ + 0x057C, /* ARMENIAN SMALL LETTER RA */ }, \ + { 0x0550, /* ARMENIAN CAPITAL LETTER REH */ \ + 0x0580, /* ARMENIAN SMALL LETTER REH */ }, \ + { 0x054D, /* ARMENIAN CAPITAL LETTER SEH */ \ + 0x057D, /* ARMENIAN SMALL LETTER SEH */ }, \ + { 0x0547, /* ARMENIAN CAPITAL LETTER SHA */ \ + 0x0577, /* ARMENIAN SMALL LETTER SHA */ }, \ + { 0x054F, /* ARMENIAN CAPITAL LETTER TIWN */ \ + 0x057F, /* ARMENIAN SMALL LETTER TIWN */ }, \ + { 0x0539, /* ARMENIAN CAPITAL LETTER TO */ \ + 0x0569, /* ARMENIAN SMALL LETTER TO */ }, \ + { 0x054E, /* ARMENIAN CAPITAL LETTER VEW */ \ + 0x057E, /* ARMENIAN SMALL LETTER VEW */ }, \ + { 0x0548, /* ARMENIAN CAPITAL LETTER VO */ \ + 0x0578, /* ARMENIAN SMALL LETTER VO */ }, \ + { 0x053D, /* ARMENIAN CAPITAL LETTER XEH */ \ + 0x056D, /* ARMENIAN SMALL LETTER XEH */ }, \ + { 0x0545, /* ARMENIAN CAPITAL LETTER YI */ \ + 0x0575, /* ARMENIAN SMALL LETTER YI */ }, \ + { 0x0552, /* ARMENIAN CAPITAL LETTER YIWN */ \ + 0x0582, /* ARMENIAN SMALL LETTER YIWN */ }, \ + { 0x0536, /* ARMENIAN CAPITAL LETTER ZA */ \ + 0x0566, /* ARMENIAN SMALL LETTER ZA */ }, \ + { 0x053A, /* ARMENIAN CAPITAL LETTER ZHE */ \ + 0x056A, /* ARMENIAN SMALL LETTER ZHE */ }, \ + { 0x24B6, /* CIRCLED LATIN CAPITAL LETTER A */ \ + 0x24D0, /* CIRCLED LATIN SMALL LETTER A */ }, \ + { 0x24B7, /* CIRCLED LATIN CAPITAL LETTER B */ \ + 0x24D1, /* CIRCLED LATIN SMALL LETTER B */ }, \ + { 0x24B8, /* CIRCLED LATIN CAPITAL LETTER C */ \ + 0x24D2, /* CIRCLED LATIN SMALL LETTER C */ }, \ + { 0x24B9, /* CIRCLED LATIN CAPITAL LETTER D */ \ + 0x24D3, /* CIRCLED LATIN SMALL LETTER D */ }, \ + { 0x24BA, /* CIRCLED LATIN CAPITAL LETTER E */ \ + 0x24D4, /* CIRCLED LATIN SMALL LETTER E */ }, \ + { 0x24BB, /* CIRCLED LATIN CAPITAL LETTER F */ \ + 0x24D5, /* CIRCLED LATIN SMALL LETTER F */ }, \ + { 0x24BC, /* CIRCLED LATIN CAPITAL LETTER G */ \ + 0x24D6, /* CIRCLED LATIN SMALL LETTER G */ }, \ + { 0x24BD, /* CIRCLED LATIN CAPITAL LETTER H */ \ + 0x24D7, /* CIRCLED LATIN SMALL LETTER H */ }, \ + { 0x24BE, /* CIRCLED LATIN CAPITAL LETTER I */ \ + 0x24D8, /* CIRCLED LATIN SMALL LETTER I */ }, \ + { 0x24BF, /* CIRCLED LATIN CAPITAL LETTER J */ \ + 0x24D9, /* CIRCLED LATIN SMALL LETTER J */ }, \ + { 0x24C0, /* CIRCLED LATIN CAPITAL LETTER K */ \ + 0x24DA, /* CIRCLED LATIN SMALL LETTER K */ }, \ + { 0x24C1, /* CIRCLED LATIN CAPITAL LETTER L */ \ + 0x24DB, /* CIRCLED LATIN SMALL LETTER L */ }, \ + { 0x24C2, /* CIRCLED LATIN CAPITAL LETTER M */ \ + 0x24DC, /* CIRCLED LATIN SMALL LETTER M */ }, \ + { 0x24C3, /* CIRCLED LATIN CAPITAL LETTER N */ \ + 0x24DD, /* CIRCLED LATIN SMALL LETTER N */ }, \ + { 0x24C4, /* CIRCLED LATIN CAPITAL LETTER O */ \ + 0x24DE, /* CIRCLED LATIN SMALL LETTER O */ }, \ + { 0x24C5, /* CIRCLED LATIN CAPITAL LETTER P */ \ + 0x24DF, /* CIRCLED LATIN SMALL LETTER P */ }, \ + { 0x24C6, /* CIRCLED LATIN CAPITAL LETTER Q */ \ + 0x24E0, /* CIRCLED LATIN SMALL LETTER Q */ }, \ + { 0x24C7, /* CIRCLED LATIN CAPITAL LETTER R */ \ + 0x24E1, /* CIRCLED LATIN SMALL LETTER R */ }, \ + { 0x24C8, /* CIRCLED LATIN CAPITAL LETTER S */ \ + 0x24E2, /* CIRCLED LATIN SMALL LETTER S */ }, \ + { 0x24C9, /* CIRCLED LATIN CAPITAL LETTER T */ \ + 0x24E3, /* CIRCLED LATIN SMALL LETTER T */ }, \ + { 0x24CA, /* CIRCLED LATIN CAPITAL LETTER U */ \ + 0x24E4, /* CIRCLED LATIN SMALL LETTER U */ }, \ + { 0x24CB, /* CIRCLED LATIN CAPITAL LETTER V */ \ + 0x24E5, /* CIRCLED LATIN SMALL LETTER V */ }, \ + { 0x24CC, /* CIRCLED LATIN CAPITAL LETTER W */ \ + 0x24E6, /* CIRCLED LATIN SMALL LETTER W */ }, \ + { 0x24CD, /* CIRCLED LATIN CAPITAL LETTER X */ \ + 0x24E7, /* CIRCLED LATIN SMALL LETTER X */ }, \ + { 0x24CE, /* CIRCLED LATIN CAPITAL LETTER Y */ \ + 0x24E8, /* CIRCLED LATIN SMALL LETTER Y */ }, \ + { 0x24CF, /* CIRCLED LATIN CAPITAL LETTER Z */ \ + 0x24E9, /* CIRCLED LATIN SMALL LETTER Z */ }, \ + { 0x2CC8, /* COPTIC CAPITAL LETTER AKHMIMIC KHEI */ \ + 0x2CC9, /* COPTIC SMALL LETTER AKHMIMIC KHEI */ }, \ + { 0x2C80, /* COPTIC CAPITAL LETTER ALFA */ \ + 0x2C81, /* COPTIC SMALL LETTER ALFA */ }, \ + { 0x2CF2, /* COPTIC CAPITAL LETTER BOHAIRIC KHEI */ \ + 0x2CF3, /* COPTIC SMALL LETTER BOHAIRIC KHEI */ }, \ + { 0x2CC2, /* COPTIC CAPITAL LETTER CROSSED SHEI */ \ + 0x2CC3, /* COPTIC SMALL LETTER CROSSED SHEI */ }, \ + { 0x2CB6, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE */ \ + 0x2CB7, /* COPTIC SMALL LETTER CRYPTOGRAMMIC EIE */ }, \ + { 0x2CED, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA */ \ + 0x2CEE, /* COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA */ }, \ + { 0x2CBC, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI */ \ + 0x2CBD, /* COPTIC SMALL LETTER CRYPTOGRAMMIC NI */ }, \ + { 0x2CEB, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI */ \ + 0x2CEC, /* COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI */ }, \ + { 0x2C86, /* COPTIC CAPITAL LETTER DALDA */ \ + 0x2C87, /* COPTIC SMALL LETTER DALDA */ }, \ + { 0x03EE, /* COPTIC CAPITAL LETTER DEI */ \ + 0x03EF, /* COPTIC SMALL LETTER DEI */ }, \ + { 0x2CB2, /* COPTIC CAPITAL LETTER DIALECT-P ALEF */ \ + 0x2CB3, /* COPTIC SMALL LETTER DIALECT-P ALEF */ }, \ + { 0x2CCA, /* COPTIC CAPITAL LETTER DIALECT-P HORI */ \ + 0x2CCB, /* COPTIC SMALL LETTER DIALECT-P HORI */ }, \ + { 0x2CB8, /* COPTIC CAPITAL LETTER DIALECT-P KAPA */ \ + 0x2CB9, /* COPTIC SMALL LETTER DIALECT-P KAPA */ }, \ + { 0x2CBA, /* COPTIC CAPITAL LETTER DIALECT-P NI */ \ + 0x2CBB, /* COPTIC SMALL LETTER DIALECT-P NI */ }, \ + { 0x2C88, /* COPTIC CAPITAL LETTER EIE */ \ + 0x2C89, /* COPTIC SMALL LETTER EIE */ }, \ + { 0x03E4, /* COPTIC CAPITAL LETTER FEI */ \ + 0x03E5, /* COPTIC SMALL LETTER FEI */ }, \ + { 0x2CAA, /* COPTIC CAPITAL LETTER FI */ \ + 0x2CAB, /* COPTIC SMALL LETTER FI */ }, \ + { 0x2C84, /* COPTIC CAPITAL LETTER GAMMA */ \ + 0x2C85, /* COPTIC SMALL LETTER GAMMA */ }, \ + { 0x03EA, /* COPTIC CAPITAL LETTER GANGIA */ \ + 0x03EB, /* COPTIC SMALL LETTER GANGIA */ }, \ + { 0x2C8E, /* COPTIC CAPITAL LETTER HATE */ \ + 0x2C8F, /* COPTIC SMALL LETTER HATE */ }, \ + { 0x03E8, /* COPTIC CAPITAL LETTER HORI */ \ + 0x03E9, /* COPTIC SMALL LETTER HORI */ }, \ + { 0x2C92, /* COPTIC CAPITAL LETTER IAUDA */ \ + 0x2C93, /* COPTIC SMALL LETTER IAUDA */ }, \ + { 0x2C94, /* COPTIC CAPITAL LETTER KAPA */ \ + 0x2C95, /* COPTIC SMALL LETTER KAPA */ }, \ + { 0x03E6, /* COPTIC CAPITAL LETTER KHEI */ \ + 0x03E7, /* COPTIC SMALL LETTER KHEI */ }, \ + { 0x2CAC, /* COPTIC CAPITAL LETTER KHI */ \ + 0x2CAD, /* COPTIC SMALL LETTER KHI */ }, \ + { 0x2C9C, /* COPTIC CAPITAL LETTER KSI */ \ + 0x2C9D, /* COPTIC SMALL LETTER KSI */ }, \ + { 0x2C96, /* COPTIC CAPITAL LETTER LAULA */ \ + 0x2C97, /* COPTIC SMALL LETTER LAULA */ }, \ + { 0x2CD0, /* COPTIC CAPITAL LETTER L-SHAPED HA */ \ + 0x2CD1, /* COPTIC SMALL LETTER L-SHAPED HA */ }, \ + { 0x2C98, /* COPTIC CAPITAL LETTER MI */ \ + 0x2C99, /* COPTIC SMALL LETTER MI */ }, \ + { 0x2C9A, /* COPTIC CAPITAL LETTER NI */ \ + 0x2C9B, /* COPTIC SMALL LETTER NI */ }, \ + { 0x2C9E, /* COPTIC CAPITAL LETTER O */ \ + 0x2C9F, /* COPTIC SMALL LETTER O */ }, \ + { 0x2CB4, /* COPTIC CAPITAL LETTER OLD COPTIC AIN */ \ + 0x2CB5, /* COPTIC SMALL LETTER OLD COPTIC AIN */ }, \ + { 0x2CD8, /* COPTIC CAPITAL LETTER OLD COPTIC DJA */ \ + 0x2CD9, /* COPTIC SMALL LETTER OLD COPTIC DJA */ }, \ + { 0x2CC6, /* COPTIC CAPITAL LETTER OLD COPTIC ESH */ \ + 0x2CC7, /* COPTIC SMALL LETTER OLD COPTIC ESH */ }, \ + { 0x2CD6, /* COPTIC CAPITAL LETTER OLD COPTIC GANGIA */ \ + 0x2CD7, /* COPTIC SMALL LETTER OLD COPTIC GANGIA */ }, \ + { 0x2CCE, /* COPTIC CAPITAL LETTER OLD COPTIC HA */ \ + 0x2CCF, /* COPTIC SMALL LETTER OLD COPTIC HA */ }, \ + { 0x2CD4, /* COPTIC CAPITAL LETTER OLD COPTIC HAT */ \ + 0x2CD5, /* COPTIC SMALL LETTER OLD COPTIC HAT */ }, \ + { 0x2CD2, /* COPTIC CAPITAL LETTER OLD COPTIC HEI */ \ + 0x2CD3, /* COPTIC SMALL LETTER OLD COPTIC HEI */ }, \ + { 0x2CCC, /* COPTIC CAPITAL LETTER OLD COPTIC HORI */ \ + 0x2CCD, /* COPTIC SMALL LETTER OLD COPTIC HORI */ }, \ + { 0x2CBE, /* COPTIC CAPITAL LETTER OLD COPTIC OOU */ \ + 0x2CBF, /* COPTIC SMALL LETTER OLD COPTIC OOU */ }, \ + { 0x2CC4, /* COPTIC CAPITAL LETTER OLD COPTIC SHEI */ \ + 0x2CC5, /* COPTIC SMALL LETTER OLD COPTIC SHEI */ }, \ + { 0x2CDA, /* COPTIC CAPITAL LETTER OLD COPTIC SHIMA */ \ + 0x2CDB, /* COPTIC SMALL LETTER OLD COPTIC SHIMA */ }, \ + { 0x2CDE, /* COPTIC CAPITAL LETTER OLD NUBIAN NGI */ \ + 0x2CDF, /* COPTIC SMALL LETTER OLD NUBIAN NGI */ }, \ + { 0x2CE0, /* COPTIC CAPITAL LETTER OLD NUBIAN NYI */ \ + 0x2CE1, /* COPTIC SMALL LETTER OLD NUBIAN NYI */ }, \ + { 0x2CDC, /* COPTIC CAPITAL LETTER OLD NUBIAN SHIMA */ \ + 0x2CDD, /* COPTIC SMALL LETTER OLD NUBIAN SHIMA */ }, \ + { 0x2CE2, /* COPTIC CAPITAL LETTER OLD NUBIAN WAU */ \ + 0x2CE3, /* COPTIC SMALL LETTER OLD NUBIAN WAU */ }, \ + { 0x2CB0, /* COPTIC CAPITAL LETTER OOU */ \ + 0x2CB1, /* COPTIC SMALL LETTER OOU */ }, \ + { 0x2CA0, /* COPTIC CAPITAL LETTER PI */ \ + 0x2CA1, /* COPTIC SMALL LETTER PI */ }, \ + { 0x2CAE, /* COPTIC CAPITAL LETTER PSI */ \ + 0x2CAF, /* COPTIC SMALL LETTER PSI */ }, \ + { 0x2CA2, /* COPTIC CAPITAL LETTER RO */ \ + 0x2CA3, /* COPTIC SMALL LETTER RO */ }, \ + { 0x2CC0, /* COPTIC CAPITAL LETTER SAMPI */ \ + 0x2CC1, /* COPTIC SMALL LETTER SAMPI */ }, \ + { 0x03E2, /* COPTIC CAPITAL LETTER SHEI */ \ + 0x03E3, /* COPTIC SMALL LETTER SHEI */ }, \ + { 0x03EC, /* COPTIC CAPITAL LETTER SHIMA */ \ + 0x03ED, /* COPTIC SMALL LETTER SHIMA */ }, \ + { 0x2CA4, /* COPTIC CAPITAL LETTER SIMA */ \ + 0x2CA5, /* COPTIC SMALL LETTER SIMA */ }, \ + { 0x2C8A, /* COPTIC CAPITAL LETTER SOU */ \ + 0x2C8B, /* COPTIC SMALL LETTER SOU */ }, \ + { 0x2CA6, /* COPTIC CAPITAL LETTER TAU */ \ + 0x2CA7, /* COPTIC SMALL LETTER TAU */ }, \ + { 0x2C90, /* COPTIC CAPITAL LETTER THETHE */ \ + 0x2C91, /* COPTIC SMALL LETTER THETHE */ }, \ + { 0x2CA8, /* COPTIC CAPITAL LETTER UA */ \ + 0x2CA9, /* COPTIC SMALL LETTER UA */ }, \ + { 0x2C82, /* COPTIC CAPITAL LETTER VIDA */ \ + 0x2C83, /* COPTIC SMALL LETTER VIDA */ }, \ + { 0x2C8C, /* COPTIC CAPITAL LETTER ZATA */ \ + 0x2C8D, /* COPTIC SMALL LETTER ZATA */ }, \ + { 0x0410, /* CYRILLIC CAPITAL LETTER A */ \ + 0x0430, /* CYRILLIC SMALL LETTER A */ }, \ + { 0x04D0, /* CYRILLIC CAPITAL LETTER A WITH BREVE */ \ + 0x04D1, /* CYRILLIC SMALL LETTER A WITH BREVE */ }, \ + { 0x04D2, /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS */ \ + 0x04D3, /* CYRILLIC SMALL LETTER A WITH DIAERESIS */ }, \ + { 0x04BC, /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE */ \ + 0x04BD, /* CYRILLIC SMALL LETTER ABKHASIAN CHE */ }, \ + { 0x04BE, /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER */ \ + 0x04BF, /* CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER */ }, \ + { 0x04E0, /* CYRILLIC CAPITAL LETTER ABKHASIAN DZE */ \ + 0x04E1, /* CYRILLIC SMALL LETTER ABKHASIAN DZE */ }, \ + { 0x04A8, /* CYRILLIC CAPITAL LETTER ABKHASIAN HA */ \ + 0x04A9, /* CYRILLIC SMALL LETTER ABKHASIAN HA */ }, \ + { 0x051E, /* CYRILLIC CAPITAL LETTER ALEUT KA */ \ + 0x051F, /* CYRILLIC SMALL LETTER ALEUT KA */ }, \ + { 0x04E8, /* CYRILLIC CAPITAL LETTER BARRED O */ \ + 0x04E9, /* CYRILLIC SMALL LETTER BARRED O */ }, \ + { 0x04EA, /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS */ \ + 0x04EB, /* CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS */ }, \ + { 0x04A0, /* CYRILLIC CAPITAL LETTER BASHKIR KA */ \ + 0x04A1, /* CYRILLIC SMALL LETTER BASHKIR KA */ }, \ + { 0x0411, /* CYRILLIC CAPITAL LETTER BE */ \ + 0x0431, /* CYRILLIC SMALL LETTER BE */ }, \ + { 0x046A, /* CYRILLIC CAPITAL LETTER BIG YUS */ \ + 0x046B, /* CYRILLIC SMALL LETTER BIG YUS */ }, \ + { 0xA66A, /* CYRILLIC CAPITAL LETTER BINOCULAR O */ \ + 0xA66B, /* CYRILLIC SMALL LETTER BINOCULAR O */ }, \ + { 0xA65A, /* CYRILLIC CAPITAL LETTER BLENDED YUS */ \ + 0xA65B, /* CYRILLIC SMALL LETTER BLENDED YUS */ }, \ + { 0xA64C, /* CYRILLIC CAPITAL LETTER BROAD OMEGA */ \ + 0xA64D, /* CYRILLIC SMALL LETTER BROAD OMEGA */ }, \ + { 0x0406, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ \ + 0x0456, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ }, \ + { 0xA686, /* CYRILLIC CAPITAL LETTER CCHE */ \ + 0xA687, /* CYRILLIC SMALL LETTER CCHE */ }, \ + { 0x0427, /* CYRILLIC CAPITAL LETTER CHE */ \ + 0x0447, /* CYRILLIC SMALL LETTER CHE */ }, \ + { 0x04B6, /* CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */ \ + 0x04B7, /* CYRILLIC SMALL LETTER CHE WITH DESCENDER */ }, \ + { 0x04F4, /* CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS */ \ + 0x04F5, /* CYRILLIC SMALL LETTER CHE WITH DIAERESIS */ }, \ + { 0x04B8, /* CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */ \ + 0x04B9, /* CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */ }, \ + { 0xA658, /* CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS */ \ + 0xA659, /* CYRILLIC SMALL LETTER CLOSED LITTLE YUS */ }, \ + { 0xA69A, /* CYRILLIC CAPITAL LETTER CROSSED O */ \ + 0xA69B, /* CYRILLIC SMALL LETTER CROSSED O */ }, \ + { 0x052C, /* CYRILLIC CAPITAL LETTER DCHE */ \ + 0x052D, /* CYRILLIC SMALL LETTER DCHE */ }, \ + { 0x0414, /* CYRILLIC CAPITAL LETTER DE */ \ + 0x0434, /* CYRILLIC SMALL LETTER DE */ }, \ + { 0x0402, /* CYRILLIC CAPITAL LETTER DJE */ \ + 0x0452, /* CYRILLIC SMALL LETTER DJE */ }, \ + { 0xA648, /* CYRILLIC CAPITAL LETTER DJERV */ \ + 0xA649, /* CYRILLIC SMALL LETTER DJERV */ }, \ + { 0xA66C, /* CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O */ \ + 0xA66D, /* CYRILLIC SMALL LETTER DOUBLE MONOCULAR O */ }, \ + { 0xA698, /* CYRILLIC CAPITAL LETTER DOUBLE O */ \ + 0xA699, /* CYRILLIC SMALL LETTER DOUBLE O */ }, \ + { 0xA680, /* CYRILLIC CAPITAL LETTER DWE */ \ + 0xA681, /* CYRILLIC SMALL LETTER DWE */ }, \ + { 0x0405, /* CYRILLIC CAPITAL LETTER DZE */ \ + 0x0455, /* CYRILLIC SMALL LETTER DZE */ }, \ + { 0xA642, /* CYRILLIC CAPITAL LETTER DZELO */ \ + 0xA643, /* CYRILLIC SMALL LETTER DZELO */ }, \ + { 0x040F, /* CYRILLIC CAPITAL LETTER DZHE */ \ + 0x045F, /* CYRILLIC SMALL LETTER DZHE */ }, \ + { 0xA682, /* CYRILLIC CAPITAL LETTER DZWE */ \ + 0xA683, /* CYRILLIC SMALL LETTER DZWE */ }, \ + { 0xA688, /* CYRILLIC CAPITAL LETTER DZZE */ \ + 0xA689, /* CYRILLIC SMALL LETTER DZZE */ }, \ + { 0x052A, /* CYRILLIC CAPITAL LETTER DZZHE */ \ + 0x052B, /* CYRILLIC SMALL LETTER DZZHE */ }, \ + { 0x042D, /* CYRILLIC CAPITAL LETTER E */ \ + 0x044D, /* CYRILLIC SMALL LETTER E */ }, \ + { 0x04EC, /* CYRILLIC CAPITAL LETTER E WITH DIAERESIS */ \ + 0x04ED, /* CYRILLIC SMALL LETTER E WITH DIAERESIS */ }, \ + { 0x0424, /* CYRILLIC CAPITAL LETTER EF */ \ + 0x0444, /* CYRILLIC SMALL LETTER EF */ }, \ + { 0x041B, /* CYRILLIC CAPITAL LETTER EL */ \ + 0x043B, /* CYRILLIC SMALL LETTER EL */ }, \ + { 0x052E, /* CYRILLIC CAPITAL LETTER EL WITH DESCENDER */ \ + 0x052F, /* CYRILLIC SMALL LETTER EL WITH DESCENDER */ }, \ + { 0x0512, /* CYRILLIC CAPITAL LETTER EL WITH HOOK */ \ + 0x0513, /* CYRILLIC SMALL LETTER EL WITH HOOK */ }, \ + { 0x0520, /* CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK */ \ + 0x0521, /* CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK */ }, \ + { 0x04C5, /* CYRILLIC CAPITAL LETTER EL WITH TAIL */ \ + 0x04C6, /* CYRILLIC SMALL LETTER EL WITH TAIL */ }, \ + { 0x041C, /* CYRILLIC CAPITAL LETTER EM */ \ + 0x043C, /* CYRILLIC SMALL LETTER EM */ }, \ + { 0x04CD, /* CYRILLIC CAPITAL LETTER EM WITH TAIL */ \ + 0x04CE, /* CYRILLIC SMALL LETTER EM WITH TAIL */ }, \ + { 0x041D, /* CYRILLIC CAPITAL LETTER EN */ \ + 0x043D, /* CYRILLIC SMALL LETTER EN */ }, \ + { 0x04A2, /* CYRILLIC CAPITAL LETTER EN WITH DESCENDER */ \ + 0x04A3, /* CYRILLIC SMALL LETTER EN WITH DESCENDER */ }, \ + { 0x04C7, /* CYRILLIC CAPITAL LETTER EN WITH HOOK */ \ + 0x04C8, /* CYRILLIC SMALL LETTER EN WITH HOOK */ }, \ + { 0x0528, /* CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK */ \ + 0x0529, /* CYRILLIC SMALL LETTER EN WITH LEFT HOOK */ }, \ + { 0x0522, /* CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK */ \ + 0x0523, /* CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK */ }, \ + { 0x04C9, /* CYRILLIC CAPITAL LETTER EN WITH TAIL */ \ + 0x04CA, /* CYRILLIC SMALL LETTER EN WITH TAIL */ }, \ + { 0x0420, /* CYRILLIC CAPITAL LETTER ER */ \ + 0x0440, /* CYRILLIC SMALL LETTER ER */ }, \ + { 0x048E, /* CYRILLIC CAPITAL LETTER ER WITH TICK */ \ + 0x048F, /* CYRILLIC SMALL LETTER ER WITH TICK */ }, \ + { 0x0421, /* CYRILLIC CAPITAL LETTER ES */ \ + 0x0441, /* CYRILLIC SMALL LETTER ES */ }, \ + { 0x04AA, /* CYRILLIC CAPITAL LETTER ES WITH DESCENDER */ \ + 0x04AB, /* CYRILLIC SMALL LETTER ES WITH DESCENDER */ }, \ + { 0x0472, /* CYRILLIC CAPITAL LETTER FITA */ \ + 0x0473, /* CYRILLIC SMALL LETTER FITA */ }, \ + { 0x0413, /* CYRILLIC CAPITAL LETTER GHE */ \ + 0x0433, /* CYRILLIC SMALL LETTER GHE */ }, \ + { 0x04F6, /* CYRILLIC CAPITAL LETTER GHE WITH DESCENDER */ \ + 0x04F7, /* CYRILLIC SMALL LETTER GHE WITH DESCENDER */ }, \ + { 0x0494, /* CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK */ \ + 0x0495, /* CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK */ }, \ + { 0x0492, /* CYRILLIC CAPITAL LETTER GHE WITH STROKE */ \ + 0x0493, /* CYRILLIC SMALL LETTER GHE WITH STROKE */ }, \ + { 0x04FA, /* CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK */ \ + 0x04FB, /* CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK */ }, \ + { 0x0490, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ \ + 0x0491, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */ }, \ + { 0x0403, /* CYRILLIC CAPITAL LETTER GJE */ \ + 0x0453, /* CYRILLIC SMALL LETTER GJE */ }, \ + { 0x0425, /* CYRILLIC CAPITAL LETTER HA */ \ + 0x0445, /* CYRILLIC SMALL LETTER HA */ }, \ + { 0x04B2, /* CYRILLIC CAPITAL LETTER HA WITH DESCENDER */ \ + 0x04B3, /* CYRILLIC SMALL LETTER HA WITH DESCENDER */ }, \ + { 0x04FC, /* CYRILLIC CAPITAL LETTER HA WITH HOOK */ \ + 0x04FD, /* CYRILLIC SMALL LETTER HA WITH HOOK */ }, \ + { 0x04FE, /* CYRILLIC CAPITAL LETTER HA WITH STROKE */ \ + 0x04FF, /* CYRILLIC SMALL LETTER HA WITH STROKE */ }, \ + { 0x042A, /* CYRILLIC CAPITAL LETTER HARD SIGN */ \ + 0x044A, /* CYRILLIC SMALL LETTER HARD SIGN */ }, \ + { 0xA694, /* CYRILLIC CAPITAL LETTER HWE */ \ + 0xA695, /* CYRILLIC SMALL LETTER HWE */ }, \ + { 0x0418, /* CYRILLIC CAPITAL LETTER I */ \ + 0x0438, /* CYRILLIC SMALL LETTER I */ }, \ + { 0x04E4, /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS */ \ + 0x04E5, /* CYRILLIC SMALL LETTER I WITH DIAERESIS */ }, \ + { 0x040D, /* CYRILLIC CAPITAL LETTER I WITH GRAVE */ \ + 0x045D, /* CYRILLIC SMALL LETTER I WITH GRAVE */ }, \ + { 0x04E2, /* CYRILLIC CAPITAL LETTER I WITH MACRON */ \ + 0x04E3, /* CYRILLIC SMALL LETTER I WITH MACRON */ }, \ + { 0x0415, /* CYRILLIC CAPITAL LETTER IE */ \ + 0x0435, /* CYRILLIC SMALL LETTER IE */ }, \ + { 0x04D6, /* CYRILLIC CAPITAL LETTER IE WITH BREVE */ \ + 0x04D7, /* CYRILLIC SMALL LETTER IE WITH BREVE */ }, \ + { 0x0400, /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */ \ + 0x0450, /* CYRILLIC SMALL LETTER IE WITH GRAVE */ }, \ + { 0x0401, /* CYRILLIC CAPITAL LETTER IO */ \ + 0x0451, /* CYRILLIC SMALL LETTER IO */ }, \ + { 0xA646, /* CYRILLIC CAPITAL LETTER IOTA */ \ + 0xA647, /* CYRILLIC SMALL LETTER IOTA */ }, \ + { 0xA656, /* CYRILLIC CAPITAL LETTER IOTIFIED A */ \ + 0xA657, /* CYRILLIC SMALL LETTER IOTIFIED A */ }, \ + { 0x046C, /* CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS */ \ + 0x046D, /* CYRILLIC SMALL LETTER IOTIFIED BIG YUS */ }, \ + { 0xA65C, /* CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS */ \ + 0xA65D, /* CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS */ }, \ + { 0x0464, /* CYRILLIC CAPITAL LETTER IOTIFIED E */ \ + 0x0465, /* CYRILLIC SMALL LETTER IOTIFIED E */ }, \ + { 0x0468, /* CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS */ \ + 0x0469, /* CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS */ }, \ + { 0xA652, /* CYRILLIC CAPITAL LETTER IOTIFIED YAT */ \ + 0xA653, /* CYRILLIC SMALL LETTER IOTIFIED YAT */ }, \ + { 0x0474, /* CYRILLIC CAPITAL LETTER IZHITSA */ \ + 0x0475, /* CYRILLIC SMALL LETTER IZHITSA */ }, \ + { 0x0476, /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */ \ + 0x0477, /* CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */ }, \ + { 0x0408, /* CYRILLIC CAPITAL LETTER JE */ \ + 0x0458, /* CYRILLIC SMALL LETTER JE */ }, \ + { 0x041A, /* CYRILLIC CAPITAL LETTER KA */ \ + 0x043A, /* CYRILLIC SMALL LETTER KA */ }, \ + { 0x049A, /* CYRILLIC CAPITAL LETTER KA WITH DESCENDER */ \ + 0x049B, /* CYRILLIC SMALL LETTER KA WITH DESCENDER */ }, \ + { 0x04C3, /* CYRILLIC CAPITAL LETTER KA WITH HOOK */ \ + 0x04C4, /* CYRILLIC SMALL LETTER KA WITH HOOK */ }, \ + { 0x049E, /* CYRILLIC CAPITAL LETTER KA WITH STROKE */ \ + 0x049F, /* CYRILLIC SMALL LETTER KA WITH STROKE */ }, \ + { 0x049C, /* CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */ \ + 0x049D, /* CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */ }, \ + { 0x04CB, /* CYRILLIC CAPITAL LETTER KHAKASSIAN CHE */ \ + 0x04CC, /* CYRILLIC SMALL LETTER KHAKASSIAN CHE */ }, \ + { 0x040C, /* CYRILLIC CAPITAL LETTER KJE */ \ + 0x045C, /* CYRILLIC SMALL LETTER KJE */ }, \ + { 0x0500, /* CYRILLIC CAPITAL LETTER KOMI DE */ \ + 0x0501, /* CYRILLIC SMALL LETTER KOMI DE */ }, \ + { 0x0502, /* CYRILLIC CAPITAL LETTER KOMI DJE */ \ + 0x0503, /* CYRILLIC SMALL LETTER KOMI DJE */ }, \ + { 0x0506, /* CYRILLIC CAPITAL LETTER KOMI DZJE */ \ + 0x0507, /* CYRILLIC SMALL LETTER KOMI DZJE */ }, \ + { 0x0508, /* CYRILLIC CAPITAL LETTER KOMI LJE */ \ + 0x0509, /* CYRILLIC SMALL LETTER KOMI LJE */ }, \ + { 0x050A, /* CYRILLIC CAPITAL LETTER KOMI NJE */ \ + 0x050B, /* CYRILLIC SMALL LETTER KOMI NJE */ }, \ + { 0x050C, /* CYRILLIC CAPITAL LETTER KOMI SJE */ \ + 0x050D, /* CYRILLIC SMALL LETTER KOMI SJE */ }, \ + { 0x050E, /* CYRILLIC CAPITAL LETTER KOMI TJE */ \ + 0x050F, /* CYRILLIC SMALL LETTER KOMI TJE */ }, \ + { 0x0504, /* CYRILLIC CAPITAL LETTER KOMI ZJE */ \ + 0x0505, /* CYRILLIC SMALL LETTER KOMI ZJE */ }, \ + { 0x0480, /* CYRILLIC CAPITAL LETTER KOPPA */ \ + 0x0481, /* CYRILLIC SMALL LETTER KOPPA */ }, \ + { 0x046E, /* CYRILLIC CAPITAL LETTER KSI */ \ + 0x046F, /* CYRILLIC SMALL LETTER KSI */ }, \ + { 0x0514, /* CYRILLIC CAPITAL LETTER LHA */ \ + 0x0515, /* CYRILLIC SMALL LETTER LHA */ }, \ + { 0x0466, /* CYRILLIC CAPITAL LETTER LITTLE YUS */ \ + 0x0467, /* CYRILLIC SMALL LETTER LITTLE YUS */ }, \ + { 0x0409, /* CYRILLIC CAPITAL LETTER LJE */ \ + 0x0459, /* CYRILLIC SMALL LETTER LJE */ }, \ + { 0xA668, /* CYRILLIC CAPITAL LETTER MONOCULAR O */ \ + 0xA669, /* CYRILLIC SMALL LETTER MONOCULAR O */ }, \ + { 0xA64A, /* CYRILLIC CAPITAL LETTER MONOGRAPH UK */ \ + 0xA64B, /* CYRILLIC SMALL LETTER MONOGRAPH UK */ }, \ + { 0xA64E, /* CYRILLIC CAPITAL LETTER NEUTRAL YER */ \ + 0xA64F, /* CYRILLIC SMALL LETTER NEUTRAL YER */ }, \ + { 0x040A, /* CYRILLIC CAPITAL LETTER NJE */ \ + 0x045A, /* CYRILLIC SMALL LETTER NJE */ }, \ + { 0x041E, /* CYRILLIC CAPITAL LETTER O */ \ + 0x043E, /* CYRILLIC SMALL LETTER O */ }, \ + { 0x04E6, /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS */ \ + 0x04E7, /* CYRILLIC SMALL LETTER O WITH DIAERESIS */ }, \ + { 0x0460, /* CYRILLIC CAPITAL LETTER OMEGA */ \ + 0x0461, /* CYRILLIC SMALL LETTER OMEGA */ }, \ + { 0x047C, /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO */ \ + 0x047D, /* CYRILLIC SMALL LETTER OMEGA WITH TITLO */ }, \ + { 0x047E, /* CYRILLIC CAPITAL LETTER OT */ \ + 0x047F, /* CYRILLIC SMALL LETTER OT */ }, \ + { 0x041F, /* CYRILLIC CAPITAL LETTER PE */ \ + 0x043F, /* CYRILLIC SMALL LETTER PE */ }, \ + { 0x0524, /* CYRILLIC CAPITAL LETTER PE WITH DESCENDER */ \ + 0x0525, /* CYRILLIC SMALL LETTER PE WITH DESCENDER */ }, \ + { 0x04A6, /* CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK */ \ + 0x04A7, /* CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK */ }, \ + { 0x0470, /* CYRILLIC CAPITAL LETTER PSI */ \ + 0x0471, /* CYRILLIC SMALL LETTER PSI */ }, \ + { 0x051A, /* CYRILLIC CAPITAL LETTER QA */ \ + 0x051B, /* CYRILLIC SMALL LETTER QA */ }, \ + { 0xA644, /* CYRILLIC CAPITAL LETTER REVERSED DZE */ \ + 0xA645, /* CYRILLIC SMALL LETTER REVERSED DZE */ }, \ + { 0xA660, /* CYRILLIC CAPITAL LETTER REVERSED TSE */ \ + 0xA661, /* CYRILLIC SMALL LETTER REVERSED TSE */ }, \ + { 0xA654, /* CYRILLIC CAPITAL LETTER REVERSED YU */ \ + 0xA655, /* CYRILLIC SMALL LETTER REVERSED YU */ }, \ + { 0x0510, /* CYRILLIC CAPITAL LETTER REVERSED ZE */ \ + 0x0511, /* CYRILLIC SMALL LETTER REVERSED ZE */ }, \ + { 0x0516, /* CYRILLIC CAPITAL LETTER RHA */ \ + 0x0517, /* CYRILLIC SMALL LETTER RHA */ }, \ + { 0x047A, /* CYRILLIC CAPITAL LETTER ROUND OMEGA */ \ + 0x047B, /* CYRILLIC SMALL LETTER ROUND OMEGA */ }, \ + { 0x04D8, /* CYRILLIC CAPITAL LETTER SCHWA */ \ + 0x04D9, /* CYRILLIC SMALL LETTER SCHWA */ }, \ + { 0x04DA, /* CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS */ \ + 0x04DB, /* CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS */ }, \ + { 0x048C, /* CYRILLIC CAPITAL LETTER SEMISOFT SIGN */ \ + 0x048D, /* CYRILLIC SMALL LETTER SEMISOFT SIGN */ }, \ + { 0x0428, /* CYRILLIC CAPITAL LETTER SHA */ \ + 0x0448, /* CYRILLIC SMALL LETTER SHA */ }, \ + { 0x0429, /* CYRILLIC CAPITAL LETTER SHCHA */ \ + 0x0449, /* CYRILLIC SMALL LETTER SHCHA */ }, \ + { 0x04BA, /* CYRILLIC CAPITAL LETTER SHHA */ \ + 0x04BB, /* CYRILLIC SMALL LETTER SHHA */ }, \ + { 0x0526, /* CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER */ \ + 0x0527, /* CYRILLIC SMALL LETTER SHHA WITH DESCENDER */ }, \ + { 0x048A, /* CYRILLIC CAPITAL LETTER SHORT I WITH TAIL */ \ + 0x048B, /* CYRILLIC SMALL LETTER SHORT I WITH TAIL */ }, \ + { 0x040E, /* CYRILLIC CAPITAL LETTER SHORT U */ \ + 0x045E, /* CYRILLIC SMALL LETTER SHORT U */ }, \ + { 0xA696, /* CYRILLIC CAPITAL LETTER SHWE */ \ + 0xA697, /* CYRILLIC SMALL LETTER SHWE */ }, \ + { 0xA662, /* CYRILLIC CAPITAL LETTER SOFT DE */ \ + 0xA663, /* CYRILLIC SMALL LETTER SOFT DE */ }, \ + { 0xA664, /* CYRILLIC CAPITAL LETTER SOFT EL */ \ + 0xA665, /* CYRILLIC SMALL LETTER SOFT EL */ }, \ + { 0xA666, /* CYRILLIC CAPITAL LETTER SOFT EM */ \ + 0xA667, /* CYRILLIC SMALL LETTER SOFT EM */ }, \ + { 0x042C, /* CYRILLIC CAPITAL LETTER SOFT SIGN */ \ + 0x044C, /* CYRILLIC SMALL LETTER SOFT SIGN */ }, \ + { 0x04AE, /* CYRILLIC CAPITAL LETTER STRAIGHT U */ \ + 0x04AF, /* CYRILLIC SMALL LETTER STRAIGHT U */ }, \ + { 0x04B0, /* CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */ \ + 0x04B1, /* CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */ }, \ + { 0xA692, /* CYRILLIC CAPITAL LETTER TCHE */ \ + 0xA693, /* CYRILLIC SMALL LETTER TCHE */ }, \ + { 0x0422, /* CYRILLIC CAPITAL LETTER TE */ \ + 0x0442, /* CYRILLIC SMALL LETTER TE */ }, \ + { 0x04AC, /* CYRILLIC CAPITAL LETTER TE WITH DESCENDER */ \ + 0x04AD, /* CYRILLIC SMALL LETTER TE WITH DESCENDER */ }, \ + { 0xA68A, /* CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK */ \ + 0xA68B, /* CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK */ }, \ + { 0x0426, /* CYRILLIC CAPITAL LETTER TSE */ \ + 0x0446, /* CYRILLIC SMALL LETTER TSE */ }, \ + { 0x040B, /* CYRILLIC CAPITAL LETTER TSHE */ \ + 0x045B, /* CYRILLIC SMALL LETTER TSHE */ }, \ + { 0xA690, /* CYRILLIC CAPITAL LETTER TSSE */ \ + 0xA691, /* CYRILLIC SMALL LETTER TSSE */ }, \ + { 0xA68E, /* CYRILLIC CAPITAL LETTER TSWE */ \ + 0xA68F, /* CYRILLIC SMALL LETTER TSWE */ }, \ + { 0xA68C, /* CYRILLIC CAPITAL LETTER TWE */ \ + 0xA68D, /* CYRILLIC SMALL LETTER TWE */ }, \ + { 0x0423, /* CYRILLIC CAPITAL LETTER U */ \ + 0x0443, /* CYRILLIC SMALL LETTER U */ }, \ + { 0x04F0, /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS */ \ + 0x04F1, /* CYRILLIC SMALL LETTER U WITH DIAERESIS */ }, \ + { 0x04F2, /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE */ \ + 0x04F3, /* CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE */ }, \ + { 0x04EE, /* CYRILLIC CAPITAL LETTER U WITH MACRON */ \ + 0x04EF, /* CYRILLIC SMALL LETTER U WITH MACRON */ }, \ + { 0x0478, /* CYRILLIC CAPITAL LETTER UK */ \ + 0x0479, /* CYRILLIC SMALL LETTER UK */ }, \ + { 0x0404, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */ \ + 0x0454, /* CYRILLIC SMALL LETTER UKRAINIAN IE */ }, \ + { 0x0412, /* CYRILLIC CAPITAL LETTER VE */ \ + 0x0432, /* CYRILLIC SMALL LETTER VE */ }, \ + { 0x051C, /* CYRILLIC CAPITAL LETTER WE */ \ + 0x051D, /* CYRILLIC SMALL LETTER WE */ }, \ + { 0x042F, /* CYRILLIC CAPITAL LETTER YA */ \ + 0x044F, /* CYRILLIC SMALL LETTER YA */ }, \ + { 0x0518, /* CYRILLIC CAPITAL LETTER YAE */ \ + 0x0519, /* CYRILLIC SMALL LETTER YAE */ }, \ + { 0x0462, /* CYRILLIC CAPITAL LETTER YAT */ \ + 0x0463, /* CYRILLIC SMALL LETTER YAT */ }, \ + { 0x042B, /* CYRILLIC CAPITAL LETTER YERU */ \ + 0x044B, /* CYRILLIC SMALL LETTER YERU */ }, \ + { 0xA650, /* CYRILLIC CAPITAL LETTER YERU WITH BACK YER */ \ + 0xA651, /* CYRILLIC SMALL LETTER YERU WITH BACK YER */ }, \ + { 0x04F8, /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS */ \ + 0x04F9, /* CYRILLIC SMALL LETTER YERU WITH DIAERESIS */ }, \ + { 0x0407, /* CYRILLIC CAPITAL LETTER YI */ \ + 0x0457, /* CYRILLIC SMALL LETTER YI */ }, \ + { 0xA65E, /* CYRILLIC CAPITAL LETTER YN */ \ + 0xA65F, /* CYRILLIC SMALL LETTER YN */ }, \ + { 0x042E, /* CYRILLIC CAPITAL LETTER YU */ \ + 0x044E, /* CYRILLIC SMALL LETTER YU */ }, \ + { 0x0417, /* CYRILLIC CAPITAL LETTER ZE */ \ + 0x0437, /* CYRILLIC SMALL LETTER ZE */ }, \ + { 0x0498, /* CYRILLIC CAPITAL LETTER ZE WITH DESCENDER */ \ + 0x0499, /* CYRILLIC SMALL LETTER ZE WITH DESCENDER */ }, \ + { 0x04DE, /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS */ \ + 0x04DF, /* CYRILLIC SMALL LETTER ZE WITH DIAERESIS */ }, \ + { 0xA640, /* CYRILLIC CAPITAL LETTER ZEMLYA */ \ + 0xA641, /* CYRILLIC SMALL LETTER ZEMLYA */ }, \ + { 0x0416, /* CYRILLIC CAPITAL LETTER ZHE */ \ + 0x0436, /* CYRILLIC SMALL LETTER ZHE */ }, \ + { 0x04C1, /* CYRILLIC CAPITAL LETTER ZHE WITH BREVE */ \ + 0x04C2, /* CYRILLIC SMALL LETTER ZHE WITH BREVE */ }, \ + { 0x0496, /* CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */ \ + 0x0497, /* CYRILLIC SMALL LETTER ZHE WITH DESCENDER */ }, \ + { 0x04DC, /* CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS */ \ + 0x04DD, /* CYRILLIC SMALL LETTER ZHE WITH DIAERESIS */ }, \ + { 0xA684, /* CYRILLIC CAPITAL LETTER ZHWE */ \ + 0xA685, /* CYRILLIC SMALL LETTER ZHWE */ }, \ + { 0xFF21, /* FULLWIDTH LATIN CAPITAL LETTER A */ \ + 0xFF41, /* FULLWIDTH LATIN SMALL LETTER A */ }, \ + { 0xFF22, /* FULLWIDTH LATIN CAPITAL LETTER B */ \ + 0xFF42, /* FULLWIDTH LATIN SMALL LETTER B */ }, \ + { 0xFF23, /* FULLWIDTH LATIN CAPITAL LETTER C */ \ + 0xFF43, /* FULLWIDTH LATIN SMALL LETTER C */ }, \ + { 0xFF24, /* FULLWIDTH LATIN CAPITAL LETTER D */ \ + 0xFF44, /* FULLWIDTH LATIN SMALL LETTER D */ }, \ + { 0xFF25, /* FULLWIDTH LATIN CAPITAL LETTER E */ \ + 0xFF45, /* FULLWIDTH LATIN SMALL LETTER E */ }, \ + { 0xFF26, /* FULLWIDTH LATIN CAPITAL LETTER F */ \ + 0xFF46, /* FULLWIDTH LATIN SMALL LETTER F */ }, \ + { 0xFF27, /* FULLWIDTH LATIN CAPITAL LETTER G */ \ + 0xFF47, /* FULLWIDTH LATIN SMALL LETTER G */ }, \ + { 0xFF28, /* FULLWIDTH LATIN CAPITAL LETTER H */ \ + 0xFF48, /* FULLWIDTH LATIN SMALL LETTER H */ }, \ + { 0xFF29, /* FULLWIDTH LATIN CAPITAL LETTER I */ \ + 0xFF49, /* FULLWIDTH LATIN SMALL LETTER I */ }, \ + { 0xFF2A, /* FULLWIDTH LATIN CAPITAL LETTER J */ \ + 0xFF4A, /* FULLWIDTH LATIN SMALL LETTER J */ }, \ + { 0xFF2B, /* FULLWIDTH LATIN CAPITAL LETTER K */ \ + 0xFF4B, /* FULLWIDTH LATIN SMALL LETTER K */ }, \ + { 0xFF2C, /* FULLWIDTH LATIN CAPITAL LETTER L */ \ + 0xFF4C, /* FULLWIDTH LATIN SMALL LETTER L */ }, \ + { 0xFF2D, /* FULLWIDTH LATIN CAPITAL LETTER M */ \ + 0xFF4D, /* FULLWIDTH LATIN SMALL LETTER M */ }, \ + { 0xFF2E, /* FULLWIDTH LATIN CAPITAL LETTER N */ \ + 0xFF4E, /* FULLWIDTH LATIN SMALL LETTER N */ }, \ + { 0xFF2F, /* FULLWIDTH LATIN CAPITAL LETTER O */ \ + 0xFF4F, /* FULLWIDTH LATIN SMALL LETTER O */ }, \ + { 0xFF30, /* FULLWIDTH LATIN CAPITAL LETTER P */ \ + 0xFF50, /* FULLWIDTH LATIN SMALL LETTER P */ }, \ + { 0xFF31, /* FULLWIDTH LATIN CAPITAL LETTER Q */ \ + 0xFF51, /* FULLWIDTH LATIN SMALL LETTER Q */ }, \ + { 0xFF32, /* FULLWIDTH LATIN CAPITAL LETTER R */ \ + 0xFF52, /* FULLWIDTH LATIN SMALL LETTER R */ }, \ + { 0xFF33, /* FULLWIDTH LATIN CAPITAL LETTER S */ \ + 0xFF53, /* FULLWIDTH LATIN SMALL LETTER S */ }, \ + { 0xFF34, /* FULLWIDTH LATIN CAPITAL LETTER T */ \ + 0xFF54, /* FULLWIDTH LATIN SMALL LETTER T */ }, \ + { 0xFF35, /* FULLWIDTH LATIN CAPITAL LETTER U */ \ + 0xFF55, /* FULLWIDTH LATIN SMALL LETTER U */ }, \ + { 0xFF36, /* FULLWIDTH LATIN CAPITAL LETTER V */ \ + 0xFF56, /* FULLWIDTH LATIN SMALL LETTER V */ }, \ + { 0xFF37, /* FULLWIDTH LATIN CAPITAL LETTER W */ \ + 0xFF57, /* FULLWIDTH LATIN SMALL LETTER W */ }, \ + { 0xFF38, /* FULLWIDTH LATIN CAPITAL LETTER X */ \ + 0xFF58, /* FULLWIDTH LATIN SMALL LETTER X */ }, \ + { 0xFF39, /* FULLWIDTH LATIN CAPITAL LETTER Y */ \ + 0xFF59, /* FULLWIDTH LATIN SMALL LETTER Y */ }, \ + { 0xFF3A, /* FULLWIDTH LATIN CAPITAL LETTER Z */ \ + 0xFF5A, /* FULLWIDTH LATIN SMALL LETTER Z */ }, \ + { 0x10CD, /* GEORGIAN CAPITAL LETTER AEN */ \ + 0x2D2D, /* GEORGIAN SMALL LETTER AEN */ }, \ + { 0x10A0, /* GEORGIAN CAPITAL LETTER AN */ \ + 0x2D00, /* GEORGIAN SMALL LETTER AN */ }, \ + { 0x10A1, /* GEORGIAN CAPITAL LETTER BAN */ \ + 0x2D01, /* GEORGIAN SMALL LETTER BAN */ }, \ + { 0x10BA, /* GEORGIAN CAPITAL LETTER CAN */ \ + 0x2D1A, /* GEORGIAN SMALL LETTER CAN */ }, \ + { 0x10BD, /* GEORGIAN CAPITAL LETTER CHAR */ \ + 0x2D1D, /* GEORGIAN SMALL LETTER CHAR */ }, \ + { 0x10B9, /* GEORGIAN CAPITAL LETTER CHIN */ \ + 0x2D19, /* GEORGIAN SMALL LETTER CHIN */ }, \ + { 0x10BC, /* GEORGIAN CAPITAL LETTER CIL */ \ + 0x2D1C, /* GEORGIAN SMALL LETTER CIL */ }, \ + { 0x10A3, /* GEORGIAN CAPITAL LETTER DON */ \ + 0x2D03, /* GEORGIAN SMALL LETTER DON */ }, \ + { 0x10A4, /* GEORGIAN CAPITAL LETTER EN */ \ + 0x2D04, /* GEORGIAN SMALL LETTER EN */ }, \ + { 0x10A2, /* GEORGIAN CAPITAL LETTER GAN */ \ + 0x2D02, /* GEORGIAN SMALL LETTER GAN */ }, \ + { 0x10B6, /* GEORGIAN CAPITAL LETTER GHAN */ \ + 0x2D16, /* GEORGIAN SMALL LETTER GHAN */ }, \ + { 0x10C0, /* GEORGIAN CAPITAL LETTER HAE */ \ + 0x2D20, /* GEORGIAN SMALL LETTER HAE */ }, \ + { 0x10C4, /* GEORGIAN CAPITAL LETTER HAR */ \ + 0x2D24, /* GEORGIAN SMALL LETTER HAR */ }, \ + { 0x10C1, /* GEORGIAN CAPITAL LETTER HE */ \ + 0x2D21, /* GEORGIAN SMALL LETTER HE */ }, \ + { 0x10C2, /* GEORGIAN CAPITAL LETTER HIE */ \ + 0x2D22, /* GEORGIAN SMALL LETTER HIE */ }, \ + { 0x10C5, /* GEORGIAN CAPITAL LETTER HOE */ \ + 0x2D25, /* GEORGIAN SMALL LETTER HOE */ }, \ + { 0x10A8, /* GEORGIAN CAPITAL LETTER IN */ \ + 0x2D08, /* GEORGIAN SMALL LETTER IN */ }, \ + { 0x10BF, /* GEORGIAN CAPITAL LETTER JHAN */ \ + 0x2D1F, /* GEORGIAN SMALL LETTER JHAN */ }, \ + { 0x10BB, /* GEORGIAN CAPITAL LETTER JIL */ \ + 0x2D1B, /* GEORGIAN SMALL LETTER JIL */ }, \ + { 0x10A9, /* GEORGIAN CAPITAL LETTER KAN */ \ + 0x2D09, /* GEORGIAN SMALL LETTER KAN */ }, \ + { 0x10B5, /* GEORGIAN CAPITAL LETTER KHAR */ \ + 0x2D15, /* GEORGIAN SMALL LETTER KHAR */ }, \ + { 0x10AA, /* GEORGIAN CAPITAL LETTER LAS */ \ + 0x2D0A, /* GEORGIAN SMALL LETTER LAS */ }, \ + { 0x10AB, /* GEORGIAN CAPITAL LETTER MAN */ \ + 0x2D0B, /* GEORGIAN SMALL LETTER MAN */ }, \ + { 0x10AC, /* GEORGIAN CAPITAL LETTER NAR */ \ + 0x2D0C, /* GEORGIAN SMALL LETTER NAR */ }, \ + { 0x10AD, /* GEORGIAN CAPITAL LETTER ON */ \ + 0x2D0D, /* GEORGIAN SMALL LETTER ON */ }, \ + { 0x10AE, /* GEORGIAN CAPITAL LETTER PAR */ \ + 0x2D0E, /* GEORGIAN SMALL LETTER PAR */ }, \ + { 0x10B4, /* GEORGIAN CAPITAL LETTER PHAR */ \ + 0x2D14, /* GEORGIAN SMALL LETTER PHAR */ }, \ + { 0x10B7, /* GEORGIAN CAPITAL LETTER QAR */ \ + 0x2D17, /* GEORGIAN SMALL LETTER QAR */ }, \ + { 0x10B0, /* GEORGIAN CAPITAL LETTER RAE */ \ + 0x2D10, /* GEORGIAN SMALL LETTER RAE */ }, \ + { 0x10B1, /* GEORGIAN CAPITAL LETTER SAN */ \ + 0x2D11, /* GEORGIAN SMALL LETTER SAN */ }, \ + { 0x10B8, /* GEORGIAN CAPITAL LETTER SHIN */ \ + 0x2D18, /* GEORGIAN SMALL LETTER SHIN */ }, \ + { 0x10A7, /* GEORGIAN CAPITAL LETTER TAN */ \ + 0x2D07, /* GEORGIAN SMALL LETTER TAN */ }, \ + { 0x10B2, /* GEORGIAN CAPITAL LETTER TAR */ \ + 0x2D12, /* GEORGIAN SMALL LETTER TAR */ }, \ + { 0x10B3, /* GEORGIAN CAPITAL LETTER UN */ \ + 0x2D13, /* GEORGIAN SMALL LETTER UN */ }, \ + { 0x10A5, /* GEORGIAN CAPITAL LETTER VIN */ \ + 0x2D05, /* GEORGIAN SMALL LETTER VIN */ }, \ + { 0x10C3, /* GEORGIAN CAPITAL LETTER WE */ \ + 0x2D23, /* GEORGIAN SMALL LETTER WE */ }, \ + { 0x10BE, /* GEORGIAN CAPITAL LETTER XAN */ \ + 0x2D1E, /* GEORGIAN SMALL LETTER XAN */ }, \ + { 0x10C7, /* GEORGIAN CAPITAL LETTER YN */ \ + 0x2D27, /* GEORGIAN SMALL LETTER YN */ }, \ + { 0x10A6, /* GEORGIAN CAPITAL LETTER ZEN */ \ + 0x2D06, /* GEORGIAN SMALL LETTER ZEN */ }, \ + { 0x10AF, /* GEORGIAN CAPITAL LETTER ZHAR */ \ + 0x2D0F, /* GEORGIAN SMALL LETTER ZHAR */ }, \ + { 0x2C00, /* GLAGOLITIC CAPITAL LETTER AZU */ \ + 0x2C30, /* GLAGOLITIC SMALL LETTER AZU */ }, \ + { 0x2C28, /* GLAGOLITIC CAPITAL LETTER BIG YUS */ \ + 0x2C58, /* GLAGOLITIC SMALL LETTER BIG YUS */ }, \ + { 0x2C01, /* GLAGOLITIC CAPITAL LETTER BUKY */ \ + 0x2C31, /* GLAGOLITIC SMALL LETTER BUKY */ }, \ + { 0x2C1D, /* GLAGOLITIC CAPITAL LETTER CHRIVI */ \ + 0x2C4D, /* GLAGOLITIC SMALL LETTER CHRIVI */ }, \ + { 0x2C0C, /* GLAGOLITIC CAPITAL LETTER DJERVI */ \ + 0x2C3C, /* GLAGOLITIC SMALL LETTER DJERVI */ }, \ + { 0x2C04, /* GLAGOLITIC CAPITAL LETTER DOBRO */ \ + 0x2C34, /* GLAGOLITIC SMALL LETTER DOBRO */ }, \ + { 0x2C07, /* GLAGOLITIC CAPITAL LETTER DZELO */ \ + 0x2C37, /* GLAGOLITIC SMALL LETTER DZELO */ }, \ + { 0x2C2A, /* GLAGOLITIC CAPITAL LETTER FITA */ \ + 0x2C5A, /* GLAGOLITIC SMALL LETTER FITA */ }, \ + { 0x2C17, /* GLAGOLITIC CAPITAL LETTER FRITU */ \ + 0x2C47, /* GLAGOLITIC SMALL LETTER FRITU */ }, \ + { 0x2C03, /* GLAGOLITIC CAPITAL LETTER GLAGOLI */ \ + 0x2C33, /* GLAGOLITIC SMALL LETTER GLAGOLI */ }, \ + { 0x2C18, /* GLAGOLITIC CAPITAL LETTER HERU */ \ + 0x2C48, /* GLAGOLITIC SMALL LETTER HERU */ }, \ + { 0x2C0B, /* GLAGOLITIC CAPITAL LETTER I */ \ + 0x2C3B, /* GLAGOLITIC SMALL LETTER I */ }, \ + { 0x2C0A, /* GLAGOLITIC CAPITAL LETTER INITIAL IZHE */ \ + 0x2C3A, /* GLAGOLITIC SMALL LETTER INITIAL IZHE */ }, \ + { 0x2C29, /* GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS */ \ + 0x2C59, /* GLAGOLITIC SMALL LETTER IOTATED BIG YUS */ }, \ + { 0x2C27, /* GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS */ \ + 0x2C57, /* GLAGOLITIC SMALL LETTER IOTATED SMALL YUS */ }, \ + { 0x2C09, /* GLAGOLITIC CAPITAL LETTER IZHE */ \ + 0x2C39, /* GLAGOLITIC SMALL LETTER IZHE */ }, \ + { 0x2C2B, /* GLAGOLITIC CAPITAL LETTER IZHITSA */ \ + 0x2C5B, /* GLAGOLITIC SMALL LETTER IZHITSA */ }, \ + { 0x2C0D, /* GLAGOLITIC CAPITAL LETTER KAKO */ \ + 0x2C3D, /* GLAGOLITIC SMALL LETTER KAKO */ }, \ + { 0x2C2E, /* GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE */ \ + 0x2C5E, /* GLAGOLITIC SMALL LETTER LATINATE MYSLITE */ }, \ + { 0x2C0E, /* GLAGOLITIC CAPITAL LETTER LJUDIJE */ \ + 0x2C3E, /* GLAGOLITIC SMALL LETTER LJUDIJE */ }, \ + { 0x2C0F, /* GLAGOLITIC CAPITAL LETTER MYSLITE */ \ + 0x2C3F, /* GLAGOLITIC SMALL LETTER MYSLITE */ }, \ + { 0x2C10, /* GLAGOLITIC CAPITAL LETTER NASHI */ \ + 0x2C40, /* GLAGOLITIC SMALL LETTER NASHI */ }, \ + { 0x2C11, /* GLAGOLITIC CAPITAL LETTER ONU */ \ + 0x2C41, /* GLAGOLITIC SMALL LETTER ONU */ }, \ + { 0x2C19, /* GLAGOLITIC CAPITAL LETTER OTU */ \ + 0x2C49, /* GLAGOLITIC SMALL LETTER OTU */ }, \ + { 0x2C1A, /* GLAGOLITIC CAPITAL LETTER PE */ \ + 0x2C4A, /* GLAGOLITIC SMALL LETTER PE */ }, \ + { 0x2C12, /* GLAGOLITIC CAPITAL LETTER POKOJI */ \ + 0x2C42, /* GLAGOLITIC SMALL LETTER POKOJI */ }, \ + { 0x2C13, /* GLAGOLITIC CAPITAL LETTER RITSI */ \ + 0x2C43, /* GLAGOLITIC SMALL LETTER RITSI */ }, \ + { 0x2C1E, /* GLAGOLITIC CAPITAL LETTER SHA */ \ + 0x2C4E, /* GLAGOLITIC SMALL LETTER SHA */ }, \ + { 0x2C1B, /* GLAGOLITIC CAPITAL LETTER SHTA */ \ + 0x2C4B, /* GLAGOLITIC SMALL LETTER SHTA */ }, \ + { 0x2C2C, /* GLAGOLITIC CAPITAL LETTER SHTAPIC */ \ + 0x2C5C, /* GLAGOLITIC SMALL LETTER SHTAPIC */ }, \ + { 0x2C14, /* GLAGOLITIC CAPITAL LETTER SLOVO */ \ + 0x2C44, /* GLAGOLITIC SMALL LETTER SLOVO */ }, \ + { 0x2C24, /* GLAGOLITIC CAPITAL LETTER SMALL YUS */ \ + 0x2C54, /* GLAGOLITIC SMALL LETTER SMALL YUS */ }, \ + { 0x2C25, /* GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL */ \ + 0x2C55, /* GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL */ }, \ + { 0x2C22, /* GLAGOLITIC CAPITAL LETTER SPIDERY HA */ \ + 0x2C52, /* GLAGOLITIC SMALL LETTER SPIDERY HA */ }, \ + { 0x2C2D, /* GLAGOLITIC CAPITAL LETTER TROKUTASTI A */ \ + 0x2C5D, /* GLAGOLITIC SMALL LETTER TROKUTASTI A */ }, \ + { 0x2C1C, /* GLAGOLITIC CAPITAL LETTER TSI */ \ + 0x2C4C, /* GLAGOLITIC SMALL LETTER TSI */ }, \ + { 0x2C15, /* GLAGOLITIC CAPITAL LETTER TVRIDO */ \ + 0x2C45, /* GLAGOLITIC SMALL LETTER TVRIDO */ }, \ + { 0x2C16, /* GLAGOLITIC CAPITAL LETTER UKU */ \ + 0x2C46, /* GLAGOLITIC SMALL LETTER UKU */ }, \ + { 0x2C02, /* GLAGOLITIC CAPITAL LETTER VEDE */ \ + 0x2C32, /* GLAGOLITIC SMALL LETTER VEDE */ }, \ + { 0x2C21, /* GLAGOLITIC CAPITAL LETTER YATI */ \ + 0x2C51, /* GLAGOLITIC SMALL LETTER YATI */ }, \ + { 0x2C20, /* GLAGOLITIC CAPITAL LETTER YERI */ \ + 0x2C50, /* GLAGOLITIC SMALL LETTER YERI */ }, \ + { 0x2C1F, /* GLAGOLITIC CAPITAL LETTER YERU */ \ + 0x2C4F, /* GLAGOLITIC SMALL LETTER YERU */ }, \ + { 0x2C05, /* GLAGOLITIC CAPITAL LETTER YESTU */ \ + 0x2C35, /* GLAGOLITIC SMALL LETTER YESTU */ }, \ + { 0x2C26, /* GLAGOLITIC CAPITAL LETTER YO */ \ + 0x2C56, /* GLAGOLITIC SMALL LETTER YO */ }, \ + { 0x2C23, /* GLAGOLITIC CAPITAL LETTER YU */ \ + 0x2C53, /* GLAGOLITIC SMALL LETTER YU */ }, \ + { 0x2C08, /* GLAGOLITIC CAPITAL LETTER ZEMLJA */ \ + 0x2C38, /* GLAGOLITIC SMALL LETTER ZEMLJA */ }, \ + { 0x2C06, /* GLAGOLITIC CAPITAL LETTER ZHIVETE */ \ + 0x2C36, /* GLAGOLITIC SMALL LETTER ZHIVETE */ }, \ + { 0x0391, /* GREEK CAPITAL LETTER ALPHA */ \ + 0x03B1, /* GREEK SMALL LETTER ALPHA */ }, \ + { 0x1F09, /* GREEK CAPITAL LETTER ALPHA WITH DASIA */ \ + 0x1F01, /* GREEK SMALL LETTER ALPHA WITH DASIA */ }, \ + { 0x1F0D, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA */ \ + 0x1F05, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA */ }, \ + { 0x1F0F, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI */ \ + 0x1F07, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI */ }, \ + { 0x1F0B, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA */ \ + 0x1F03, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA */ }, \ + { 0x1FB9, /* GREEK CAPITAL LETTER ALPHA WITH MACRON */ \ + 0x1FB1, /* GREEK SMALL LETTER ALPHA WITH MACRON */ }, \ + { 0x1FBB, /* GREEK CAPITAL LETTER ALPHA WITH OXIA */ \ + 0x1F71, /* GREEK SMALL LETTER ALPHA WITH OXIA */ }, \ + { 0x1F08, /* GREEK CAPITAL LETTER ALPHA WITH PSILI */ \ + 0x1F00, /* GREEK SMALL LETTER ALPHA WITH PSILI */ }, \ + { 0x1F0C, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA */ \ + 0x1F04, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA */ }, \ + { 0x1F0E, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI */ \ + 0x1F06, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI */ }, \ + { 0x1F0A, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA */ \ + 0x1F02, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA */ }, \ + { 0x0386, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */ \ + 0x03AC, /* GREEK SMALL LETTER ALPHA WITH TONOS */ }, \ + { 0x1FBA, /* GREEK CAPITAL LETTER ALPHA WITH VARIA */ \ + 0x1F70, /* GREEK SMALL LETTER ALPHA WITH VARIA */ }, \ + { 0x1FB8, /* GREEK CAPITAL LETTER ALPHA WITH VRACHY */ \ + 0x1FB0, /* GREEK SMALL LETTER ALPHA WITH VRACHY */ }, \ + { 0x0372, /* GREEK CAPITAL LETTER ARCHAIC SAMPI */ \ + 0x0373, /* GREEK SMALL LETTER ARCHAIC SAMPI */ }, \ + { 0x0392, /* GREEK CAPITAL LETTER BETA */ \ + 0x03B2, /* GREEK SMALL LETTER BETA */ }, \ + { 0x03A7, /* GREEK CAPITAL LETTER CHI */ \ + 0x03C7, /* GREEK SMALL LETTER CHI */ }, \ + { 0x0394, /* GREEK CAPITAL LETTER DELTA */ \ + 0x03B4, /* GREEK SMALL LETTER DELTA */ }, \ + { 0x0395, /* GREEK CAPITAL LETTER EPSILON */ \ + 0x03B5, /* GREEK SMALL LETTER EPSILON */ }, \ + { 0x1F19, /* GREEK CAPITAL LETTER EPSILON WITH DASIA */ \ + 0x1F11, /* GREEK SMALL LETTER EPSILON WITH DASIA */ }, \ + { 0x1F1D, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA */ \ + 0x1F15, /* GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA */ }, \ + { 0x1F1B, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA */ \ + 0x1F13, /* GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA */ }, \ + { 0x1FC9, /* GREEK CAPITAL LETTER EPSILON WITH OXIA */ \ + 0x1F73, /* GREEK SMALL LETTER EPSILON WITH OXIA */ }, \ + { 0x1F18, /* GREEK CAPITAL LETTER EPSILON WITH PSILI */ \ + 0x1F10, /* GREEK SMALL LETTER EPSILON WITH PSILI */ }, \ + { 0x1F1C, /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA */ \ + 0x1F14, /* GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA */ }, \ + { 0x1F1A, /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA */ \ + 0x1F12, /* GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA */ }, \ + { 0x0388, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */ \ + 0x03AD, /* GREEK SMALL LETTER EPSILON WITH TONOS */ }, \ + { 0x1FC8, /* GREEK CAPITAL LETTER EPSILON WITH VARIA */ \ + 0x1F72, /* GREEK SMALL LETTER EPSILON WITH VARIA */ }, \ + { 0x0397, /* GREEK CAPITAL LETTER ETA */ \ + 0x03B7, /* GREEK SMALL LETTER ETA */ }, \ + { 0x1F29, /* GREEK CAPITAL LETTER ETA WITH DASIA */ \ + 0x1F21, /* GREEK SMALL LETTER ETA WITH DASIA */ }, \ + { 0x1F2D, /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA */ \ + 0x1F25, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA */ }, \ + { 0x1F2F, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI */ \ + 0x1F27, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI */ }, \ + { 0x1F2B, /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA */ \ + 0x1F23, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA */ }, \ + { 0x1FCB, /* GREEK CAPITAL LETTER ETA WITH OXIA */ \ + 0x1F75, /* GREEK SMALL LETTER ETA WITH OXIA */ }, \ + { 0x1F28, /* GREEK CAPITAL LETTER ETA WITH PSILI */ \ + 0x1F20, /* GREEK SMALL LETTER ETA WITH PSILI */ }, \ + { 0x1F2C, /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA */ \ + 0x1F24, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA */ }, \ + { 0x1F2E, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI */ \ + 0x1F26, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI */ }, \ + { 0x1F2A, /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA */ \ + 0x1F22, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA */ }, \ + { 0x0389, /* GREEK CAPITAL LETTER ETA WITH TONOS */ \ + 0x03AE, /* GREEK SMALL LETTER ETA WITH TONOS */ }, \ + { 0x1FCA, /* GREEK CAPITAL LETTER ETA WITH VARIA */ \ + 0x1F74, /* GREEK SMALL LETTER ETA WITH VARIA */ }, \ + { 0x0393, /* GREEK CAPITAL LETTER GAMMA */ \ + 0x03B3, /* GREEK SMALL LETTER GAMMA */ }, \ + { 0x0370, /* GREEK CAPITAL LETTER HETA */ \ + 0x0371, /* GREEK SMALL LETTER HETA */ }, \ + { 0x0399, /* GREEK CAPITAL LETTER IOTA */ \ + 0x03B9, /* GREEK SMALL LETTER IOTA */ }, \ + { 0x1F39, /* GREEK CAPITAL LETTER IOTA WITH DASIA */ \ + 0x1F31, /* GREEK SMALL LETTER IOTA WITH DASIA */ }, \ + { 0x1F3D, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA */ \ + 0x1F35, /* GREEK SMALL LETTER IOTA WITH DASIA AND OXIA */ }, \ + { 0x1F3F, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI */ \ + 0x1F37, /* GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI */ }, \ + { 0x1F3B, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA */ \ + 0x1F33, /* GREEK SMALL LETTER IOTA WITH DASIA AND VARIA */ }, \ + { 0x03AA, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ \ + 0x03CA, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */ }, \ + { 0x1FD9, /* GREEK CAPITAL LETTER IOTA WITH MACRON */ \ + 0x1FD1, /* GREEK SMALL LETTER IOTA WITH MACRON */ }, \ + { 0x1FDB, /* GREEK CAPITAL LETTER IOTA WITH OXIA */ \ + 0x1F77, /* GREEK SMALL LETTER IOTA WITH OXIA */ }, \ + { 0x1F38, /* GREEK CAPITAL LETTER IOTA WITH PSILI */ \ + 0x1F30, /* GREEK SMALL LETTER IOTA WITH PSILI */ }, \ + { 0x1F3C, /* GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA */ \ + 0x1F34, /* GREEK SMALL LETTER IOTA WITH PSILI AND OXIA */ }, \ + { 0x1F3E, /* GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI */ \ + 0x1F36, /* GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI */ }, \ + { 0x1F3A, /* GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA */ \ + 0x1F32, /* GREEK SMALL LETTER IOTA WITH PSILI AND VARIA */ }, \ + { 0x038A, /* GREEK CAPITAL LETTER IOTA WITH TONOS */ \ + 0x03AF, /* GREEK SMALL LETTER IOTA WITH TONOS */ }, \ + { 0x1FDA, /* GREEK CAPITAL LETTER IOTA WITH VARIA */ \ + 0x1F76, /* GREEK SMALL LETTER IOTA WITH VARIA */ }, \ + { 0x1FD8, /* GREEK CAPITAL LETTER IOTA WITH VRACHY */ \ + 0x1FD0, /* GREEK SMALL LETTER IOTA WITH VRACHY */ }, \ + { 0x039A, /* GREEK CAPITAL LETTER KAPPA */ \ + 0x03BA, /* GREEK SMALL LETTER KAPPA */ }, \ + { 0x039B, /* GREEK CAPITAL LETTER LAMDA */ \ + 0x03BB, /* GREEK SMALL LETTER LAMDA */ }, \ + { 0x039C, /* GREEK CAPITAL LETTER MU */ \ + 0x03BC, /* GREEK SMALL LETTER MU */ }, \ + { 0x039D, /* GREEK CAPITAL LETTER NU */ \ + 0x03BD, /* GREEK SMALL LETTER NU */ }, \ + { 0x03A9, /* GREEK CAPITAL LETTER OMEGA */ \ + 0x03C9, /* GREEK SMALL LETTER OMEGA */ }, \ + { 0x1F69, /* GREEK CAPITAL LETTER OMEGA WITH DASIA */ \ + 0x1F61, /* GREEK SMALL LETTER OMEGA WITH DASIA */ }, \ + { 0x1F6D, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA */ \ + 0x1F65, /* GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA */ }, \ + { 0x1F6F, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI */ \ + 0x1F67, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI */ }, \ + { 0x1F6B, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA */ \ + 0x1F63, /* GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA */ }, \ + { 0x1FFB, /* GREEK CAPITAL LETTER OMEGA WITH OXIA */ \ + 0x1F7D, /* GREEK SMALL LETTER OMEGA WITH OXIA */ }, \ + { 0x1F68, /* GREEK CAPITAL LETTER OMEGA WITH PSILI */ \ + 0x1F60, /* GREEK SMALL LETTER OMEGA WITH PSILI */ }, \ + { 0x1F6C, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA */ \ + 0x1F64, /* GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA */ }, \ + { 0x1F6E, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI */ \ + 0x1F66, /* GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI */ }, \ + { 0x1F6A, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA */ \ + 0x1F62, /* GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA */ }, \ + { 0x038F, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */ \ + 0x03CE, /* GREEK SMALL LETTER OMEGA WITH TONOS */ }, \ + { 0x1FFA, /* GREEK CAPITAL LETTER OMEGA WITH VARIA */ \ + 0x1F7C, /* GREEK SMALL LETTER OMEGA WITH VARIA */ }, \ + { 0x039F, /* GREEK CAPITAL LETTER OMICRON */ \ + 0x03BF, /* GREEK SMALL LETTER OMICRON */ }, \ + { 0x1F49, /* GREEK CAPITAL LETTER OMICRON WITH DASIA */ \ + 0x1F41, /* GREEK SMALL LETTER OMICRON WITH DASIA */ }, \ + { 0x1F4D, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA */ \ + 0x1F45, /* GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA */ }, \ + { 0x1F4B, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA */ \ + 0x1F43, /* GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA */ }, \ + { 0x1FF9, /* GREEK CAPITAL LETTER OMICRON WITH OXIA */ \ + 0x1F79, /* GREEK SMALL LETTER OMICRON WITH OXIA */ }, \ + { 0x1F48, /* GREEK CAPITAL LETTER OMICRON WITH PSILI */ \ + 0x1F40, /* GREEK SMALL LETTER OMICRON WITH PSILI */ }, \ + { 0x1F4C, /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA */ \ + 0x1F44, /* GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA */ }, \ + { 0x1F4A, /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA */ \ + 0x1F42, /* GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA */ }, \ + { 0x038C, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */ \ + 0x03CC, /* GREEK SMALL LETTER OMICRON WITH TONOS */ }, \ + { 0x1FF8, /* GREEK CAPITAL LETTER OMICRON WITH VARIA */ \ + 0x1F78, /* GREEK SMALL LETTER OMICRON WITH VARIA */ }, \ + { 0x0376, /* GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA */ \ + 0x0377, /* GREEK SMALL LETTER PAMPHYLIAN DIGAMMA */ }, \ + { 0x03A6, /* GREEK CAPITAL LETTER PHI */ \ + 0x03C6, /* GREEK SMALL LETTER PHI */ }, \ + { 0x03A0, /* GREEK CAPITAL LETTER PI */ \ + 0x03C0, /* GREEK SMALL LETTER PI */ }, \ + { 0x03A8, /* GREEK CAPITAL LETTER PSI */ \ + 0x03C8, /* GREEK SMALL LETTER PSI */ }, \ + { 0x03A1, /* GREEK CAPITAL LETTER RHO */ \ + 0x03C1, /* GREEK SMALL LETTER RHO */ }, \ + { 0x1FEC, /* GREEK CAPITAL LETTER RHO WITH DASIA */ \ + 0x1FE5, /* GREEK SMALL LETTER RHO WITH DASIA */ }, \ + { 0x03FA, /* GREEK CAPITAL LETTER SAN */ \ + 0x03FB, /* GREEK SMALL LETTER SAN */ }, \ + { 0x03F7, /* GREEK CAPITAL LETTER SHO */ \ + 0x03F8, /* GREEK SMALL LETTER SHO */ }, \ + { 0x03A3, /* GREEK CAPITAL LETTER SIGMA */ \ + 0x03C3, /* GREEK SMALL LETTER SIGMA */ }, \ + { 0x03A4, /* GREEK CAPITAL LETTER TAU */ \ + 0x03C4, /* GREEK SMALL LETTER TAU */ }, \ + { 0x0398, /* GREEK CAPITAL LETTER THETA */ \ + 0x03B8, /* GREEK SMALL LETTER THETA */ }, \ + { 0x03A5, /* GREEK CAPITAL LETTER UPSILON */ \ + 0x03C5, /* GREEK SMALL LETTER UPSILON */ }, \ + { 0x1F59, /* GREEK CAPITAL LETTER UPSILON WITH DASIA */ \ + 0x1F51, /* GREEK SMALL LETTER UPSILON WITH DASIA */ }, \ + { 0x1F5D, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA */ \ + 0x1F55, /* GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA */ }, \ + { 0x1F5F, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI */ \ + 0x1F57, /* GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI */ }, \ + { 0x1F5B, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA */ \ + 0x1F53, /* GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA */ }, \ + { 0x03AB, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ \ + 0x03CB, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ }, \ + { 0x1FE9, /* GREEK CAPITAL LETTER UPSILON WITH MACRON */ \ + 0x1FE1, /* GREEK SMALL LETTER UPSILON WITH MACRON */ }, \ + { 0x1FEB, /* GREEK CAPITAL LETTER UPSILON WITH OXIA */ \ + 0x1F7B, /* GREEK SMALL LETTER UPSILON WITH OXIA */ }, \ + { 0x038E, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */ \ + 0x03CD, /* GREEK SMALL LETTER UPSILON WITH TONOS */ }, \ + { 0x1FEA, /* GREEK CAPITAL LETTER UPSILON WITH VARIA */ \ + 0x1F7A, /* GREEK SMALL LETTER UPSILON WITH VARIA */ }, \ + { 0x1FE8, /* GREEK CAPITAL LETTER UPSILON WITH VRACHY */ \ + 0x1FE0, /* GREEK SMALL LETTER UPSILON WITH VRACHY */ }, \ + { 0x039E, /* GREEK CAPITAL LETTER XI */ \ + 0x03BE, /* GREEK SMALL LETTER XI */ }, \ + { 0x0396, /* GREEK CAPITAL LETTER ZETA */ \ + 0x03B6, /* GREEK SMALL LETTER ZETA */ }, \ + { 0x0041, /* LATIN CAPITAL LETTER A */ \ + 0x0061, /* LATIN SMALL LETTER A */ }, \ + { 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */ \ + 0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */ }, \ + { 0x0102, /* LATIN CAPITAL LETTER A WITH BREVE */ \ + 0x0103, /* LATIN SMALL LETTER A WITH BREVE */ }, \ + { 0x1EAE, /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */ \ + 0x1EAF, /* LATIN SMALL LETTER A WITH BREVE AND ACUTE */ }, \ + { 0x1EB6, /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */ \ + 0x1EB7, /* LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */ }, \ + { 0x1EB0, /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */ \ + 0x1EB1, /* LATIN SMALL LETTER A WITH BREVE AND GRAVE */ }, \ + { 0x1EB2, /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */ \ + 0x1EB3, /* LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */ }, \ + { 0x1EB4, /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE */ \ + 0x1EB5, /* LATIN SMALL LETTER A WITH BREVE AND TILDE */ }, \ + { 0x01CD, /* LATIN CAPITAL LETTER A WITH CARON */ \ + 0x01CE, /* LATIN SMALL LETTER A WITH CARON */ }, \ + { 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ \ + 0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ }, \ + { 0x1EA4, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */ \ + 0x1EA5, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */ }, \ + { 0x1EAC, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */ \ + 0x1EAD, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */ }, \ + { 0x1EA6, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */ \ + 0x1EA7, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */ }, \ + { 0x1EA8, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */ \ + 0x1EA9, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */ }, \ + { 0x1EAA, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */ \ + 0x1EAB, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */ }, \ + { 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ \ + 0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ }, \ + { 0x01DE, /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON */ \ + 0x01DF, /* LATIN SMALL LETTER A WITH DIAERESIS AND MACRON */ }, \ + { 0x0226, /* LATIN CAPITAL LETTER A WITH DOT ABOVE */ \ + 0x0227, /* LATIN SMALL LETTER A WITH DOT ABOVE */ }, \ + { 0x01E0, /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON */ \ + 0x01E1, /* LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON */ }, \ + { 0x1EA0, /* LATIN CAPITAL LETTER A WITH DOT BELOW */ \ + 0x1EA1, /* LATIN SMALL LETTER A WITH DOT BELOW */ }, \ + { 0x0200, /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE */ \ + 0x0201, /* LATIN SMALL LETTER A WITH DOUBLE GRAVE */ }, \ + { 0x00C0, /* LATIN CAPITAL LETTER A WITH GRAVE */ \ + 0x00E0, /* LATIN SMALL LETTER A WITH GRAVE */ }, \ + { 0x1EA2, /* LATIN CAPITAL LETTER A WITH HOOK ABOVE */ \ + 0x1EA3, /* LATIN SMALL LETTER A WITH HOOK ABOVE */ }, \ + { 0x0202, /* LATIN CAPITAL LETTER A WITH INVERTED BREVE */ \ + 0x0203, /* LATIN SMALL LETTER A WITH INVERTED BREVE */ }, \ + { 0x0100, /* LATIN CAPITAL LETTER A WITH MACRON */ \ + 0x0101, /* LATIN SMALL LETTER A WITH MACRON */ }, \ + { 0x0104, /* LATIN CAPITAL LETTER A WITH OGONEK */ \ + 0x0105, /* LATIN SMALL LETTER A WITH OGONEK */ }, \ + { 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ \ + 0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */ }, \ + { 0x01FA, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE */ \ + 0x01FB, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE */ }, \ + { 0x1E00, /* LATIN CAPITAL LETTER A WITH RING BELOW */ \ + 0x1E01, /* LATIN SMALL LETTER A WITH RING BELOW */ }, \ + { 0x023A, /* LATIN CAPITAL LETTER A WITH STROKE */ \ + 0x2C65, /* LATIN SMALL LETTER A WITH STROKE */ }, \ + { 0x00C3, /* LATIN CAPITAL LETTER A WITH TILDE */ \ + 0x00E3, /* LATIN SMALL LETTER A WITH TILDE */ }, \ + { 0xA732, /* LATIN CAPITAL LETTER AA */ \ + 0xA733, /* LATIN SMALL LETTER AA */ }, \ + { 0x00C6, /* LATIN CAPITAL LETTER AE */ \ + 0x00E6, /* LATIN SMALL LETTER AE */ }, \ + { 0x01FC, /* LATIN CAPITAL LETTER AE WITH ACUTE */ \ + 0x01FD, /* LATIN SMALL LETTER AE WITH ACUTE */ }, \ + { 0x01E2, /* LATIN CAPITAL LETTER AE WITH MACRON */ \ + 0x01E3, /* LATIN SMALL LETTER AE WITH MACRON */ }, \ + { 0x2C6D, /* LATIN CAPITAL LETTER ALPHA */ \ + 0x0251, /* LATIN SMALL LETTER ALPHA */ }, \ + { 0xA734, /* LATIN CAPITAL LETTER AO */ \ + 0xA735, /* LATIN SMALL LETTER AO */ }, \ + { 0xA736, /* LATIN CAPITAL LETTER AU */ \ + 0xA737, /* LATIN SMALL LETTER AU */ }, \ + { 0xA738, /* LATIN CAPITAL LETTER AV */ \ + 0xA739, /* LATIN SMALL LETTER AV */ }, \ + { 0xA73A, /* LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR */ \ + 0xA73B, /* LATIN SMALL LETTER AV WITH HORIZONTAL BAR */ }, \ + { 0xA73C, /* LATIN CAPITAL LETTER AY */ \ + 0xA73D, /* LATIN SMALL LETTER AY */ }, \ + { 0x0042, /* LATIN CAPITAL LETTER B */ \ + 0x0062, /* LATIN SMALL LETTER B */ }, \ + { 0x1E02, /* LATIN CAPITAL LETTER B WITH DOT ABOVE */ \ + 0x1E03, /* LATIN SMALL LETTER B WITH DOT ABOVE */ }, \ + { 0x1E04, /* LATIN CAPITAL LETTER B WITH DOT BELOW */ \ + 0x1E05, /* LATIN SMALL LETTER B WITH DOT BELOW */ }, \ + { 0xA796, /* LATIN CAPITAL LETTER B WITH FLOURISH */ \ + 0xA797, /* LATIN SMALL LETTER B WITH FLOURISH */ }, \ + { 0x0181, /* LATIN CAPITAL LETTER B WITH HOOK */ \ + 0x0253, /* LATIN SMALL LETTER B WITH HOOK */ }, \ + { 0x1E06, /* LATIN CAPITAL LETTER B WITH LINE BELOW */ \ + 0x1E07, /* LATIN SMALL LETTER B WITH LINE BELOW */ }, \ + { 0x0243, /* LATIN CAPITAL LETTER B WITH STROKE */ \ + 0x0180, /* LATIN SMALL LETTER B WITH STROKE */ }, \ + { 0x0182, /* LATIN CAPITAL LETTER B WITH TOPBAR */ \ + 0x0183, /* LATIN SMALL LETTER B WITH TOPBAR */ }, \ + { 0xA7B4, /* LATIN CAPITAL LETTER BETA */ \ + 0xA7B5, /* LATIN SMALL LETTER BETA */ }, \ + { 0xA746, /* LATIN CAPITAL LETTER BROKEN L */ \ + 0xA747, /* LATIN SMALL LETTER BROKEN L */ }, \ + { 0x0043, /* LATIN CAPITAL LETTER C */ \ + 0x0063, /* LATIN SMALL LETTER C */ }, \ + { 0x0106, /* LATIN CAPITAL LETTER C WITH ACUTE */ \ + 0x0107, /* LATIN SMALL LETTER C WITH ACUTE */ }, \ + { 0xA792, /* LATIN CAPITAL LETTER C WITH BAR */ \ + 0xA793, /* LATIN SMALL LETTER C WITH BAR */ }, \ + { 0x010C, /* LATIN CAPITAL LETTER C WITH CARON */ \ + 0x010D, /* LATIN SMALL LETTER C WITH CARON */ }, \ + { 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ \ + 0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ }, \ + { 0x1E08, /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE */ \ + 0x1E09, /* LATIN SMALL LETTER C WITH CEDILLA AND ACUTE */ }, \ + { 0x0108, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ \ + 0x0109, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */ }, \ + { 0x010A, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */ \ + 0x010B, /* LATIN SMALL LETTER C WITH DOT ABOVE */ }, \ + { 0x0187, /* LATIN CAPITAL LETTER C WITH HOOK */ \ + 0x0188, /* LATIN SMALL LETTER C WITH HOOK */ }, \ + { 0x023B, /* LATIN CAPITAL LETTER C WITH STROKE */ \ + 0x023C, /* LATIN SMALL LETTER C WITH STROKE */ }, \ + { 0xA7B3, /* LATIN CAPITAL LETTER CHI */ \ + 0xAB53, /* LATIN SMALL LETTER CHI */ }, \ + { 0xA76E, /* LATIN CAPITAL LETTER CON */ \ + 0xA76F, /* LATIN SMALL LETTER CON */ }, \ + { 0xA72C, /* LATIN CAPITAL LETTER CUATRILLO */ \ + 0xA72D, /* LATIN SMALL LETTER CUATRILLO */ }, \ + { 0xA72E, /* LATIN CAPITAL LETTER CUATRILLO WITH COMMA */ \ + 0xA72F, /* LATIN SMALL LETTER CUATRILLO WITH COMMA */ }, \ + { 0x0044, /* LATIN CAPITAL LETTER D */ \ + 0x0064, /* LATIN SMALL LETTER D */ }, \ + { 0x010E, /* LATIN CAPITAL LETTER D WITH CARON */ \ + 0x010F, /* LATIN SMALL LETTER D WITH CARON */ }, \ + { 0x1E10, /* LATIN CAPITAL LETTER D WITH CEDILLA */ \ + 0x1E11, /* LATIN SMALL LETTER D WITH CEDILLA */ }, \ + { 0x1E12, /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW */ \ + 0x1E13, /* LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW */ }, \ + { 0x1E0A, /* LATIN CAPITAL LETTER D WITH DOT ABOVE */ \ + 0x1E0B, /* LATIN SMALL LETTER D WITH DOT ABOVE */ }, \ + { 0x1E0C, /* LATIN CAPITAL LETTER D WITH DOT BELOW */ \ + 0x1E0D, /* LATIN SMALL LETTER D WITH DOT BELOW */ }, \ + { 0x018A, /* LATIN CAPITAL LETTER D WITH HOOK */ \ + 0x0257, /* LATIN SMALL LETTER D WITH HOOK */ }, \ + { 0x1E0E, /* LATIN CAPITAL LETTER D WITH LINE BELOW */ \ + 0x1E0F, /* LATIN SMALL LETTER D WITH LINE BELOW */ }, \ + { 0x0110, /* LATIN CAPITAL LETTER D WITH STROKE */ \ + 0x0111, /* LATIN SMALL LETTER D WITH STROKE */ }, \ + { 0x018B, /* LATIN CAPITAL LETTER D WITH TOPBAR */ \ + 0x018C, /* LATIN SMALL LETTER D WITH TOPBAR */ }, \ + { 0x01F1, /* LATIN CAPITAL LETTER DZ */ \ + 0x01F3, /* LATIN SMALL LETTER DZ */ }, \ + { 0x01C4, /* LATIN CAPITAL LETTER DZ WITH CARON */ \ + 0x01C6, /* LATIN SMALL LETTER DZ WITH CARON */ }, \ + { 0x0045, /* LATIN CAPITAL LETTER E */ \ + 0x0065, /* LATIN SMALL LETTER E */ }, \ + { 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ \ + 0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ }, \ + { 0x0114, /* LATIN CAPITAL LETTER E WITH BREVE */ \ + 0x0115, /* LATIN SMALL LETTER E WITH BREVE */ }, \ + { 0x011A, /* LATIN CAPITAL LETTER E WITH CARON */ \ + 0x011B, /* LATIN SMALL LETTER E WITH CARON */ }, \ + { 0x0228, /* LATIN CAPITAL LETTER E WITH CEDILLA */ \ + 0x0229, /* LATIN SMALL LETTER E WITH CEDILLA */ }, \ + { 0x1E1C, /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE */ \ + 0x1E1D, /* LATIN SMALL LETTER E WITH CEDILLA AND BREVE */ }, \ + { 0x00CA, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ \ + 0x00EA, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */ }, \ + { 0x1EBE, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */ \ + 0x1EBF, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */ }, \ + { 0x1EC6, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */ \ + 0x1EC7, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */ }, \ + { 0x1EC0, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */ \ + 0x1EC1, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */ }, \ + { 0x1EC2, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */ \ + 0x1EC3, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */ }, \ + { 0x1EC4, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */ \ + 0x1EC5, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */ }, \ + { 0x1E18, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW */ \ + 0x1E19, /* LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW */ }, \ + { 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ \ + 0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */ }, \ + { 0x0116, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */ \ + 0x0117, /* LATIN SMALL LETTER E WITH DOT ABOVE */ }, \ + { 0x1EB8, /* LATIN CAPITAL LETTER E WITH DOT BELOW */ \ + 0x1EB9, /* LATIN SMALL LETTER E WITH DOT BELOW */ }, \ + { 0x0204, /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE */ \ + 0x0205, /* LATIN SMALL LETTER E WITH DOUBLE GRAVE */ }, \ + { 0x00C8, /* LATIN CAPITAL LETTER E WITH GRAVE */ \ + 0x00E8, /* LATIN SMALL LETTER E WITH GRAVE */ }, \ + { 0x1EBA, /* LATIN CAPITAL LETTER E WITH HOOK ABOVE */ \ + 0x1EBB, /* LATIN SMALL LETTER E WITH HOOK ABOVE */ }, \ + { 0x0206, /* LATIN CAPITAL LETTER E WITH INVERTED BREVE */ \ + 0x0207, /* LATIN SMALL LETTER E WITH INVERTED BREVE */ }, \ + { 0x0112, /* LATIN CAPITAL LETTER E WITH MACRON */ \ + 0x0113, /* LATIN SMALL LETTER E WITH MACRON */ }, \ + { 0x1E16, /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE */ \ + 0x1E17, /* LATIN SMALL LETTER E WITH MACRON AND ACUTE */ }, \ + { 0x1E14, /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE */ \ + 0x1E15, /* LATIN SMALL LETTER E WITH MACRON AND GRAVE */ }, \ + { 0x0118, /* LATIN CAPITAL LETTER E WITH OGONEK */ \ + 0x0119, /* LATIN SMALL LETTER E WITH OGONEK */ }, \ + { 0x0246, /* LATIN CAPITAL LETTER E WITH STROKE */ \ + 0x0247, /* LATIN SMALL LETTER E WITH STROKE */ }, \ + { 0x1EBC, /* LATIN CAPITAL LETTER E WITH TILDE */ \ + 0x1EBD, /* LATIN SMALL LETTER E WITH TILDE */ }, \ + { 0x1E1A, /* LATIN CAPITAL LETTER E WITH TILDE BELOW */ \ + 0x1E1B, /* LATIN SMALL LETTER E WITH TILDE BELOW */ }, \ + { 0xA724, /* LATIN CAPITAL LETTER EGYPTOLOGICAL AIN */ \ + 0xA725, /* LATIN SMALL LETTER EGYPTOLOGICAL AIN */ }, \ + { 0xA722, /* LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF */ \ + 0xA723, /* LATIN SMALL LETTER EGYPTOLOGICAL ALEF */ }, \ + { 0x014A, /* LATIN CAPITAL LETTER ENG */ \ + 0x014B, /* LATIN SMALL LETTER ENG */ }, \ + { 0x01A9, /* LATIN CAPITAL LETTER ESH */ \ + 0x0283, /* LATIN SMALL LETTER ESH */ }, \ + { 0xA76A, /* LATIN CAPITAL LETTER ET */ \ + 0xA76B, /* LATIN SMALL LETTER ET */ }, \ + { 0x00D0, /* LATIN CAPITAL LETTER ETH */ \ + 0x00F0, /* LATIN SMALL LETTER ETH */ }, \ + { 0x01B7, /* LATIN CAPITAL LETTER EZH */ \ + 0x0292, /* LATIN SMALL LETTER EZH */ }, \ + { 0x01B8, /* LATIN CAPITAL LETTER EZH REVERSED */ \ + 0x01B9, /* LATIN SMALL LETTER EZH REVERSED */ }, \ + { 0x01EE, /* LATIN CAPITAL LETTER EZH WITH CARON */ \ + 0x01EF, /* LATIN SMALL LETTER EZH WITH CARON */ }, \ + { 0x0046, /* LATIN CAPITAL LETTER F */ \ + 0x0066, /* LATIN SMALL LETTER F */ }, \ + { 0x1E1E, /* LATIN CAPITAL LETTER F WITH DOT ABOVE */ \ + 0x1E1F, /* LATIN SMALL LETTER F WITH DOT ABOVE */ }, \ + { 0x0191, /* LATIN CAPITAL LETTER F WITH HOOK */ \ + 0x0192, /* LATIN SMALL LETTER F WITH HOOK */ }, \ + { 0xA798, /* LATIN CAPITAL LETTER F WITH STROKE */ \ + 0xA799, /* LATIN SMALL LETTER F WITH STROKE */ }, \ + { 0x0047, /* LATIN CAPITAL LETTER G */ \ + 0x0067, /* LATIN SMALL LETTER G */ }, \ + { 0x01F4, /* LATIN CAPITAL LETTER G WITH ACUTE */ \ + 0x01F5, /* LATIN SMALL LETTER G WITH ACUTE */ }, \ + { 0x011E, /* LATIN CAPITAL LETTER G WITH BREVE */ \ + 0x011F, /* LATIN SMALL LETTER G WITH BREVE */ }, \ + { 0x01E6, /* LATIN CAPITAL LETTER G WITH CARON */ \ + 0x01E7, /* LATIN SMALL LETTER G WITH CARON */ }, \ + { 0x0122, /* LATIN CAPITAL LETTER G WITH CEDILLA */ \ + 0x0123, /* LATIN SMALL LETTER G WITH CEDILLA */ }, \ + { 0x011C, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ \ + 0x011D, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */ }, \ + { 0x0120, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */ \ + 0x0121, /* LATIN SMALL LETTER G WITH DOT ABOVE */ }, \ + { 0x0193, /* LATIN CAPITAL LETTER G WITH HOOK */ \ + 0x0260, /* LATIN SMALL LETTER G WITH HOOK */ }, \ + { 0x1E20, /* LATIN CAPITAL LETTER G WITH MACRON */ \ + 0x1E21, /* LATIN SMALL LETTER G WITH MACRON */ }, \ + { 0xA7A0, /* LATIN CAPITAL LETTER G WITH OBLIQUE STROKE */ \ + 0xA7A1, /* LATIN SMALL LETTER G WITH OBLIQUE STROKE */ }, \ + { 0x01E4, /* LATIN CAPITAL LETTER G WITH STROKE */ \ + 0x01E5, /* LATIN SMALL LETTER G WITH STROKE */ }, \ + { 0x0194, /* LATIN CAPITAL LETTER GAMMA */ \ + 0x0263, /* LATIN SMALL LETTER GAMMA */ }, \ + { 0x0241, /* LATIN CAPITAL LETTER GLOTTAL STOP */ \ + 0x0242, /* LATIN SMALL LETTER GLOTTAL STOP */ }, \ + { 0x0048, /* LATIN CAPITAL LETTER H */ \ + 0x0068, /* LATIN SMALL LETTER H */ }, \ + { 0x1E2A, /* LATIN CAPITAL LETTER H WITH BREVE BELOW */ \ + 0x1E2B, /* LATIN SMALL LETTER H WITH BREVE BELOW */ }, \ + { 0x021E, /* LATIN CAPITAL LETTER H WITH CARON */ \ + 0x021F, /* LATIN SMALL LETTER H WITH CARON */ }, \ + { 0x1E28, /* LATIN CAPITAL LETTER H WITH CEDILLA */ \ + 0x1E29, /* LATIN SMALL LETTER H WITH CEDILLA */ }, \ + { 0x0124, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ \ + 0x0125, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */ }, \ + { 0x2C67, /* LATIN CAPITAL LETTER H WITH DESCENDER */ \ + 0x2C68, /* LATIN SMALL LETTER H WITH DESCENDER */ }, \ + { 0x1E26, /* LATIN CAPITAL LETTER H WITH DIAERESIS */ \ + 0x1E27, /* LATIN SMALL LETTER H WITH DIAERESIS */ }, \ + { 0x1E22, /* LATIN CAPITAL LETTER H WITH DOT ABOVE */ \ + 0x1E23, /* LATIN SMALL LETTER H WITH DOT ABOVE */ }, \ + { 0x1E24, /* LATIN CAPITAL LETTER H WITH DOT BELOW */ \ + 0x1E25, /* LATIN SMALL LETTER H WITH DOT BELOW */ }, \ + { 0xA7AA, /* LATIN CAPITAL LETTER H WITH HOOK */ \ + 0x0266, /* LATIN SMALL LETTER H WITH HOOK */ }, \ + { 0x0126, /* LATIN CAPITAL LETTER H WITH STROKE */ \ + 0x0127, /* LATIN SMALL LETTER H WITH STROKE */ }, \ + { 0x2C75, /* LATIN CAPITAL LETTER HALF H */ \ + 0x2C76, /* LATIN SMALL LETTER HALF H */ }, \ + { 0xA726, /* LATIN CAPITAL LETTER HENG */ \ + 0xA727, /* LATIN SMALL LETTER HENG */ }, \ + { 0x0049, /* LATIN CAPITAL LETTER I */ \ + 0x0069, /* LATIN SMALL LETTER I */ }, \ + { 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */ \ + 0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */ }, \ + { 0x012C, /* LATIN CAPITAL LETTER I WITH BREVE */ \ + 0x012D, /* LATIN SMALL LETTER I WITH BREVE */ }, \ + { 0x01CF, /* LATIN CAPITAL LETTER I WITH CARON */ \ + 0x01D0, /* LATIN SMALL LETTER I WITH CARON */ }, \ + { 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ \ + 0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ }, \ + { 0x00CF, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ \ + 0x00EF, /* LATIN SMALL LETTER I WITH DIAERESIS */ }, \ + { 0x1E2E, /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE */ \ + 0x1E2F, /* LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE */ }, \ + { 0x1ECA, /* LATIN CAPITAL LETTER I WITH DOT BELOW */ \ + 0x1ECB, /* LATIN SMALL LETTER I WITH DOT BELOW */ }, \ + { 0x0208, /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE */ \ + 0x0209, /* LATIN SMALL LETTER I WITH DOUBLE GRAVE */ }, \ + { 0x00CC, /* LATIN CAPITAL LETTER I WITH GRAVE */ \ + 0x00EC, /* LATIN SMALL LETTER I WITH GRAVE */ }, \ + { 0x1EC8, /* LATIN CAPITAL LETTER I WITH HOOK ABOVE */ \ + 0x1EC9, /* LATIN SMALL LETTER I WITH HOOK ABOVE */ }, \ + { 0x020A, /* LATIN CAPITAL LETTER I WITH INVERTED BREVE */ \ + 0x020B, /* LATIN SMALL LETTER I WITH INVERTED BREVE */ }, \ + { 0x012A, /* LATIN CAPITAL LETTER I WITH MACRON */ \ + 0x012B, /* LATIN SMALL LETTER I WITH MACRON */ }, \ + { 0x012E, /* LATIN CAPITAL LETTER I WITH OGONEK */ \ + 0x012F, /* LATIN SMALL LETTER I WITH OGONEK */ }, \ + { 0x0197, /* LATIN CAPITAL LETTER I WITH STROKE */ \ + 0x0268, /* LATIN SMALL LETTER I WITH STROKE */ }, \ + { 0x0128, /* LATIN CAPITAL LETTER I WITH TILDE */ \ + 0x0129, /* LATIN SMALL LETTER I WITH TILDE */ }, \ + { 0x1E2C, /* LATIN CAPITAL LETTER I WITH TILDE BELOW */ \ + 0x1E2D, /* LATIN SMALL LETTER I WITH TILDE BELOW */ }, \ + { 0xA779, /* LATIN CAPITAL LETTER INSULAR D */ \ + 0xA77A, /* LATIN SMALL LETTER INSULAR D */ }, \ + { 0xA77B, /* LATIN CAPITAL LETTER INSULAR F */ \ + 0xA77C, /* LATIN SMALL LETTER INSULAR F */ }, \ + { 0xA77D, /* LATIN CAPITAL LETTER INSULAR G */ \ + 0x1D79, /* LATIN SMALL LETTER INSULAR G */ }, \ + { 0xA782, /* LATIN CAPITAL LETTER INSULAR R */ \ + 0xA783, /* LATIN SMALL LETTER INSULAR R */ }, \ + { 0xA784, /* LATIN CAPITAL LETTER INSULAR S */ \ + 0xA785, /* LATIN SMALL LETTER INSULAR S */ }, \ + { 0xA786, /* LATIN CAPITAL LETTER INSULAR T */ \ + 0xA787, /* LATIN SMALL LETTER INSULAR T */ }, \ + { 0x0196, /* LATIN CAPITAL LETTER IOTA */ \ + 0x0269, /* LATIN SMALL LETTER IOTA */ }, \ + { 0xA76C, /* LATIN CAPITAL LETTER IS */ \ + 0xA76D, /* LATIN SMALL LETTER IS */ }, \ + { 0x004A, /* LATIN CAPITAL LETTER J */ \ + 0x006A, /* LATIN SMALL LETTER J */ }, \ + { 0x0134, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ \ + 0x0135, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */ }, \ + { 0xA7B2, /* LATIN CAPITAL LETTER J WITH CROSSED-TAIL */ \ + 0x029D, /* LATIN SMALL LETTER J WITH CROSSED-TAIL */ }, \ + { 0x0248, /* LATIN CAPITAL LETTER J WITH STROKE */ \ + 0x0249, /* LATIN SMALL LETTER J WITH STROKE */ }, \ + { 0x004B, /* LATIN CAPITAL LETTER K */ \ + 0x006B, /* LATIN SMALL LETTER K */ }, \ + { 0x1E30, /* LATIN CAPITAL LETTER K WITH ACUTE */ \ + 0x1E31, /* LATIN SMALL LETTER K WITH ACUTE */ }, \ + { 0x01E8, /* LATIN CAPITAL LETTER K WITH CARON */ \ + 0x01E9, /* LATIN SMALL LETTER K WITH CARON */ }, \ + { 0x0136, /* LATIN CAPITAL LETTER K WITH CEDILLA */ \ + 0x0137, /* LATIN SMALL LETTER K WITH CEDILLA */ }, \ + { 0x2C69, /* LATIN CAPITAL LETTER K WITH DESCENDER */ \ + 0x2C6A, /* LATIN SMALL LETTER K WITH DESCENDER */ }, \ + { 0xA742, /* LATIN CAPITAL LETTER K WITH DIAGONAL STROKE */ \ + 0xA743, /* LATIN SMALL LETTER K WITH DIAGONAL STROKE */ }, \ + { 0x1E32, /* LATIN CAPITAL LETTER K WITH DOT BELOW */ \ + 0x1E33, /* LATIN SMALL LETTER K WITH DOT BELOW */ }, \ + { 0x0198, /* LATIN CAPITAL LETTER K WITH HOOK */ \ + 0x0199, /* LATIN SMALL LETTER K WITH HOOK */ }, \ + { 0x1E34, /* LATIN CAPITAL LETTER K WITH LINE BELOW */ \ + 0x1E35, /* LATIN SMALL LETTER K WITH LINE BELOW */ }, \ + { 0xA7A2, /* LATIN CAPITAL LETTER K WITH OBLIQUE STROKE */ \ + 0xA7A3, /* LATIN SMALL LETTER K WITH OBLIQUE STROKE */ }, \ + { 0xA740, /* LATIN CAPITAL LETTER K WITH STROKE */ \ + 0xA741, /* LATIN SMALL LETTER K WITH STROKE */ }, \ + { 0xA744, /* LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE */ \ + 0xA745, /* LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE */ }, \ + { 0x004C, /* LATIN CAPITAL LETTER L */ \ + 0x006C, /* LATIN SMALL LETTER L */ }, \ + { 0x0139, /* LATIN CAPITAL LETTER L WITH ACUTE */ \ + 0x013A, /* LATIN SMALL LETTER L WITH ACUTE */ }, \ + { 0x023D, /* LATIN CAPITAL LETTER L WITH BAR */ \ + 0x019A, /* LATIN SMALL LETTER L WITH BAR */ }, \ + { 0xA7AD, /* LATIN CAPITAL LETTER L WITH BELT */ \ + 0x026C, /* LATIN SMALL LETTER L WITH BELT */ }, \ + { 0x013D, /* LATIN CAPITAL LETTER L WITH CARON */ \ + 0x013E, /* LATIN SMALL LETTER L WITH CARON */ }, \ + { 0x013B, /* LATIN CAPITAL LETTER L WITH CEDILLA */ \ + 0x013C, /* LATIN SMALL LETTER L WITH CEDILLA */ }, \ + { 0x1E3C, /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW */ \ + 0x1E3D, /* LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW */ }, \ + { 0x1E36, /* LATIN CAPITAL LETTER L WITH DOT BELOW */ \ + 0x1E37, /* LATIN SMALL LETTER L WITH DOT BELOW */ }, \ + { 0x1E38, /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON */ \ + 0x1E39, /* LATIN SMALL LETTER L WITH DOT BELOW AND MACRON */ }, \ + { 0x2C60, /* LATIN CAPITAL LETTER L WITH DOUBLE BAR */ \ + 0x2C61, /* LATIN SMALL LETTER L WITH DOUBLE BAR */ }, \ + { 0xA748, /* LATIN CAPITAL LETTER L WITH HIGH STROKE */ \ + 0xA749, /* LATIN SMALL LETTER L WITH HIGH STROKE */ }, \ + { 0x1E3A, /* LATIN CAPITAL LETTER L WITH LINE BELOW */ \ + 0x1E3B, /* LATIN SMALL LETTER L WITH LINE BELOW */ }, \ + { 0x013F, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */ \ + 0x0140, /* LATIN SMALL LETTER L WITH MIDDLE DOT */ }, \ + { 0x2C62, /* LATIN CAPITAL LETTER L WITH MIDDLE TILDE */ \ + 0x026B, /* LATIN SMALL LETTER L WITH MIDDLE TILDE */ }, \ + { 0x0141, /* LATIN CAPITAL LETTER L WITH STROKE */ \ + 0x0142, /* LATIN SMALL LETTER L WITH STROKE */ }, \ + { 0x01C7, /* LATIN CAPITAL LETTER LJ */ \ + 0x01C9, /* LATIN SMALL LETTER LJ */ }, \ + { 0x004D, /* LATIN CAPITAL LETTER M */ \ + 0x006D, /* LATIN SMALL LETTER M */ }, \ + { 0x1E3E, /* LATIN CAPITAL LETTER M WITH ACUTE */ \ + 0x1E3F, /* LATIN SMALL LETTER M WITH ACUTE */ }, \ + { 0x1E40, /* LATIN CAPITAL LETTER M WITH DOT ABOVE */ \ + 0x1E41, /* LATIN SMALL LETTER M WITH DOT ABOVE */ }, \ + { 0x1E42, /* LATIN CAPITAL LETTER M WITH DOT BELOW */ \ + 0x1E43, /* LATIN SMALL LETTER M WITH DOT BELOW */ }, \ + { 0x2C6E, /* LATIN CAPITAL LETTER M WITH HOOK */ \ + 0x0271, /* LATIN SMALL LETTER M WITH HOOK */ }, \ + { 0x1EFA, /* LATIN CAPITAL LETTER MIDDLE-WELSH LL */ \ + 0x1EFB, /* LATIN SMALL LETTER MIDDLE-WELSH LL */ }, \ + { 0x1EFC, /* LATIN CAPITAL LETTER MIDDLE-WELSH V */ \ + 0x1EFD, /* LATIN SMALL LETTER MIDDLE-WELSH V */ }, \ + { 0x004E, /* LATIN CAPITAL LETTER N */ \ + 0x006E, /* LATIN SMALL LETTER N */ }, \ + { 0x0143, /* LATIN CAPITAL LETTER N WITH ACUTE */ \ + 0x0144, /* LATIN SMALL LETTER N WITH ACUTE */ }, \ + { 0x0147, /* LATIN CAPITAL LETTER N WITH CARON */ \ + 0x0148, /* LATIN SMALL LETTER N WITH CARON */ }, \ + { 0x0145, /* LATIN CAPITAL LETTER N WITH CEDILLA */ \ + 0x0146, /* LATIN SMALL LETTER N WITH CEDILLA */ }, \ + { 0x1E4A, /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW */ \ + 0x1E4B, /* LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW */ }, \ + { 0xA790, /* LATIN CAPITAL LETTER N WITH DESCENDER */ \ + 0xA791, /* LATIN SMALL LETTER N WITH DESCENDER */ }, \ + { 0x1E44, /* LATIN CAPITAL LETTER N WITH DOT ABOVE */ \ + 0x1E45, /* LATIN SMALL LETTER N WITH DOT ABOVE */ }, \ + { 0x1E46, /* LATIN CAPITAL LETTER N WITH DOT BELOW */ \ + 0x1E47, /* LATIN SMALL LETTER N WITH DOT BELOW */ }, \ + { 0x01F8, /* LATIN CAPITAL LETTER N WITH GRAVE */ \ + 0x01F9, /* LATIN SMALL LETTER N WITH GRAVE */ }, \ + { 0x019D, /* LATIN CAPITAL LETTER N WITH LEFT HOOK */ \ + 0x0272, /* LATIN SMALL LETTER N WITH LEFT HOOK */ }, \ + { 0x1E48, /* LATIN CAPITAL LETTER N WITH LINE BELOW */ \ + 0x1E49, /* LATIN SMALL LETTER N WITH LINE BELOW */ }, \ + { 0x0220, /* LATIN CAPITAL LETTER N WITH LONG RIGHT LEG */ \ + 0x019E, /* LATIN SMALL LETTER N WITH LONG RIGHT LEG */ }, \ + { 0xA7A4, /* LATIN CAPITAL LETTER N WITH OBLIQUE STROKE */ \ + 0xA7A5, /* LATIN SMALL LETTER N WITH OBLIQUE STROKE */ }, \ + { 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */ \ + 0x00F1, /* LATIN SMALL LETTER N WITH TILDE */ }, \ + { 0x01CA, /* LATIN CAPITAL LETTER NJ */ \ + 0x01CC, /* LATIN SMALL LETTER NJ */ }, \ + { 0x004F, /* LATIN CAPITAL LETTER O */ \ + 0x006F, /* LATIN SMALL LETTER O */ }, \ + { 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */ \ + 0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */ }, \ + { 0x014E, /* LATIN CAPITAL LETTER O WITH BREVE */ \ + 0x014F, /* LATIN SMALL LETTER O WITH BREVE */ }, \ + { 0x01D1, /* LATIN CAPITAL LETTER O WITH CARON */ \ + 0x01D2, /* LATIN SMALL LETTER O WITH CARON */ }, \ + { 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ \ + 0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ }, \ + { 0x1ED0, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */ \ + 0x1ED1, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */ }, \ + { 0x1ED8, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */ \ + 0x1ED9, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */ }, \ + { 0x1ED2, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */ \ + 0x1ED3, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */ }, \ + { 0x1ED4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */ \ + 0x1ED5, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */ }, \ + { 0x1ED6, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */ \ + 0x1ED7, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */ }, \ + { 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ \ + 0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ }, \ + { 0x022A, /* LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON */ \ + 0x022B, /* LATIN SMALL LETTER O WITH DIAERESIS AND MACRON */ }, \ + { 0x022E, /* LATIN CAPITAL LETTER O WITH DOT ABOVE */ \ + 0x022F, /* LATIN SMALL LETTER O WITH DOT ABOVE */ }, \ + { 0x0230, /* LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON */ \ + 0x0231, /* LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON */ }, \ + { 0x1ECC, /* LATIN CAPITAL LETTER O WITH DOT BELOW */ \ + 0x1ECD, /* LATIN SMALL LETTER O WITH DOT BELOW */ }, \ + { 0x0150, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ \ + 0x0151, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ }, \ + { 0x020C, /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE */ \ + 0x020D, /* LATIN SMALL LETTER O WITH DOUBLE GRAVE */ }, \ + { 0x00D2, /* LATIN CAPITAL LETTER O WITH GRAVE */ \ + 0x00F2, /* LATIN SMALL LETTER O WITH GRAVE */ }, \ + { 0x1ECE, /* LATIN CAPITAL LETTER O WITH HOOK ABOVE */ \ + 0x1ECF, /* LATIN SMALL LETTER O WITH HOOK ABOVE */ }, \ + { 0x01A0, /* LATIN CAPITAL LETTER O WITH HORN */ \ + 0x01A1, /* LATIN SMALL LETTER O WITH HORN */ }, \ + { 0x1EDA, /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE */ \ + 0x1EDB, /* LATIN SMALL LETTER O WITH HORN AND ACUTE */ }, \ + { 0x1EE2, /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */ \ + 0x1EE3, /* LATIN SMALL LETTER O WITH HORN AND DOT BELOW */ }, \ + { 0x1EDC, /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE */ \ + 0x1EDD, /* LATIN SMALL LETTER O WITH HORN AND GRAVE */ }, \ + { 0x1EDE, /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */ \ + 0x1EDF, /* LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */ }, \ + { 0x1EE0, /* LATIN CAPITAL LETTER O WITH HORN AND TILDE */ \ + 0x1EE1, /* LATIN SMALL LETTER O WITH HORN AND TILDE */ }, \ + { 0x020E, /* LATIN CAPITAL LETTER O WITH INVERTED BREVE */ \ + 0x020F, /* LATIN SMALL LETTER O WITH INVERTED BREVE */ }, \ + { 0xA74A, /* LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY */ \ + 0xA74B, /* LATIN SMALL LETTER O WITH LONG STROKE OVERLAY */ }, \ + { 0xA74C, /* LATIN CAPITAL LETTER O WITH LOOP */ \ + 0xA74D, /* LATIN SMALL LETTER O WITH LOOP */ }, \ + { 0x014C, /* LATIN CAPITAL LETTER O WITH MACRON */ \ + 0x014D, /* LATIN SMALL LETTER O WITH MACRON */ }, \ + { 0x1E52, /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE */ \ + 0x1E53, /* LATIN SMALL LETTER O WITH MACRON AND ACUTE */ }, \ + { 0x1E50, /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE */ \ + 0x1E51, /* LATIN SMALL LETTER O WITH MACRON AND GRAVE */ }, \ + { 0x01EA, /* LATIN CAPITAL LETTER O WITH OGONEK */ \ + 0x01EB, /* LATIN SMALL LETTER O WITH OGONEK */ }, \ + { 0x01EC, /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON */ \ + 0x01ED, /* LATIN SMALL LETTER O WITH OGONEK AND MACRON */ }, \ + { 0x00D8, /* LATIN CAPITAL LETTER O WITH STROKE */ \ + 0x00F8, /* LATIN SMALL LETTER O WITH STROKE */ }, \ + { 0x01FE, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE */ \ + 0x01FF, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE */ }, \ + { 0x00D5, /* LATIN CAPITAL LETTER O WITH TILDE */ \ + 0x00F5, /* LATIN SMALL LETTER O WITH TILDE */ }, \ + { 0x1E4C, /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE */ \ + 0x1E4D, /* LATIN SMALL LETTER O WITH TILDE AND ACUTE */ }, \ + { 0x1E4E, /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS */ \ + 0x1E4F, /* LATIN SMALL LETTER O WITH TILDE AND DIAERESIS */ }, \ + { 0x022C, /* LATIN CAPITAL LETTER O WITH TILDE AND MACRON */ \ + 0x022D, /* LATIN SMALL LETTER O WITH TILDE AND MACRON */ }, \ + { 0x01A2, /* LATIN CAPITAL LETTER OI */ \ + 0x01A3, /* LATIN SMALL LETTER OI */ }, \ + { 0xA7B6, /* LATIN CAPITAL LETTER OMEGA */ \ + 0xA7B7, /* LATIN SMALL LETTER OMEGA */ }, \ + { 0xA74E, /* LATIN CAPITAL LETTER OO */ \ + 0xA74F, /* LATIN SMALL LETTER OO */ }, \ + { 0x0190, /* LATIN CAPITAL LETTER OPEN E */ \ + 0x025B, /* LATIN SMALL LETTER OPEN E */ }, \ + { 0x0186, /* LATIN CAPITAL LETTER OPEN O */ \ + 0x0254, /* LATIN SMALL LETTER OPEN O */ }, \ + { 0x0222, /* LATIN CAPITAL LETTER OU */ \ + 0x0223, /* LATIN SMALL LETTER OU */ }, \ + { 0x0050, /* LATIN CAPITAL LETTER P */ \ + 0x0070, /* LATIN SMALL LETTER P */ }, \ + { 0x1E54, /* LATIN CAPITAL LETTER P WITH ACUTE */ \ + 0x1E55, /* LATIN SMALL LETTER P WITH ACUTE */ }, \ + { 0x1E56, /* LATIN CAPITAL LETTER P WITH DOT ABOVE */ \ + 0x1E57, /* LATIN SMALL LETTER P WITH DOT ABOVE */ }, \ + { 0xA752, /* LATIN CAPITAL LETTER P WITH FLOURISH */ \ + 0xA753, /* LATIN SMALL LETTER P WITH FLOURISH */ }, \ + { 0x01A4, /* LATIN CAPITAL LETTER P WITH HOOK */ \ + 0x01A5, /* LATIN SMALL LETTER P WITH HOOK */ }, \ + { 0xA754, /* LATIN CAPITAL LETTER P WITH SQUIRREL TAIL */ \ + 0xA755, /* LATIN SMALL LETTER P WITH SQUIRREL TAIL */ }, \ + { 0x2C63, /* LATIN CAPITAL LETTER P WITH STROKE */ \ + 0x1D7D, /* LATIN SMALL LETTER P WITH STROKE */ }, \ + { 0xA750, /* LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER */ \ + 0xA751, /* LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER */ }, \ + { 0x0051, /* LATIN CAPITAL LETTER Q */ \ + 0x0071, /* LATIN SMALL LETTER Q */ }, \ + { 0xA758, /* LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE */ \ + 0xA759, /* LATIN SMALL LETTER Q WITH DIAGONAL STROKE */ }, \ + { 0xA756, /* LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER */ \ + 0xA757, /* LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER */ }, \ + { 0x0052, /* LATIN CAPITAL LETTER R */ \ + 0x0072, /* LATIN SMALL LETTER R */ }, \ + { 0xA75A, /* LATIN CAPITAL LETTER R ROTUNDA */ \ + 0xA75B, /* LATIN SMALL LETTER R ROTUNDA */ }, \ + { 0x0154, /* LATIN CAPITAL LETTER R WITH ACUTE */ \ + 0x0155, /* LATIN SMALL LETTER R WITH ACUTE */ }, \ + { 0x0158, /* LATIN CAPITAL LETTER R WITH CARON */ \ + 0x0159, /* LATIN SMALL LETTER R WITH CARON */ }, \ + { 0x0156, /* LATIN CAPITAL LETTER R WITH CEDILLA */ \ + 0x0157, /* LATIN SMALL LETTER R WITH CEDILLA */ }, \ + { 0x1E58, /* LATIN CAPITAL LETTER R WITH DOT ABOVE */ \ + 0x1E59, /* LATIN SMALL LETTER R WITH DOT ABOVE */ }, \ + { 0x1E5A, /* LATIN CAPITAL LETTER R WITH DOT BELOW */ \ + 0x1E5B, /* LATIN SMALL LETTER R WITH DOT BELOW */ }, \ + { 0x1E5C, /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON */ \ + 0x1E5D, /* LATIN SMALL LETTER R WITH DOT BELOW AND MACRON */ }, \ + { 0x0210, /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE */ \ + 0x0211, /* LATIN SMALL LETTER R WITH DOUBLE GRAVE */ }, \ + { 0x0212, /* LATIN CAPITAL LETTER R WITH INVERTED BREVE */ \ + 0x0213, /* LATIN SMALL LETTER R WITH INVERTED BREVE */ }, \ + { 0x1E5E, /* LATIN CAPITAL LETTER R WITH LINE BELOW */ \ + 0x1E5F, /* LATIN SMALL LETTER R WITH LINE BELOW */ }, \ + { 0xA7A6, /* LATIN CAPITAL LETTER R WITH OBLIQUE STROKE */ \ + 0xA7A7, /* LATIN SMALL LETTER R WITH OBLIQUE STROKE */ }, \ + { 0x024C, /* LATIN CAPITAL LETTER R WITH STROKE */ \ + 0x024D, /* LATIN SMALL LETTER R WITH STROKE */ }, \ + { 0x2C64, /* LATIN CAPITAL LETTER R WITH TAIL */ \ + 0x027D, /* LATIN SMALL LETTER R WITH TAIL */ }, \ + { 0xA73E, /* LATIN CAPITAL LETTER REVERSED C WITH DOT */ \ + 0xA73F, /* LATIN SMALL LETTER REVERSED C WITH DOT */ }, \ + { 0x018E, /* LATIN CAPITAL LETTER REVERSED E */ \ + 0x0258, /* LATIN SMALL LETTER REVERSED E */ }, \ + { 0xA7AB, /* LATIN CAPITAL LETTER REVERSED OPEN E */ \ + 0x025C, /* LATIN SMALL LETTER REVERSED OPEN E */ }, \ + { 0xA75C, /* LATIN CAPITAL LETTER RUM ROTUNDA */ \ + 0xA75D, /* LATIN SMALL LETTER RUM ROTUNDA */ }, \ + { 0x0053, /* LATIN CAPITAL LETTER S */ \ + 0x0073, /* LATIN SMALL LETTER S */ }, \ + { 0x015A, /* LATIN CAPITAL LETTER S WITH ACUTE */ \ + 0x015B, /* LATIN SMALL LETTER S WITH ACUTE */ }, \ + { 0x1E64, /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE */ \ + 0x1E65, /* LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE */ }, \ + { 0x0160, /* LATIN CAPITAL LETTER S WITH CARON */ \ + 0x0161, /* LATIN SMALL LETTER S WITH CARON */ }, \ + { 0x1E66, /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE */ \ + 0x1E67, /* LATIN SMALL LETTER S WITH CARON AND DOT ABOVE */ }, \ + { 0x015E, /* LATIN CAPITAL LETTER S WITH CEDILLA */ \ + 0x015F, /* LATIN SMALL LETTER S WITH CEDILLA */ }, \ + { 0x015C, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ \ + 0x015D, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */ }, \ + { 0x0218, /* LATIN CAPITAL LETTER S WITH COMMA BELOW */ \ + 0x0219, /* LATIN SMALL LETTER S WITH COMMA BELOW */ }, \ + { 0x1E60, /* LATIN CAPITAL LETTER S WITH DOT ABOVE */ \ + 0x1E61, /* LATIN SMALL LETTER S WITH DOT ABOVE */ }, \ + { 0x1E62, /* LATIN CAPITAL LETTER S WITH DOT BELOW */ \ + 0x1E63, /* LATIN SMALL LETTER S WITH DOT BELOW */ }, \ + { 0x1E68, /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE */ \ + 0x1E69, /* LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE */ }, \ + { 0xA7A8, /* LATIN CAPITAL LETTER S WITH OBLIQUE STROKE */ \ + 0xA7A9, /* LATIN SMALL LETTER S WITH OBLIQUE STROKE */ }, \ + { 0x2C7E, /* LATIN CAPITAL LETTER S WITH SWASH TAIL */ \ + 0x023F, /* LATIN SMALL LETTER S WITH SWASH TAIL */ }, \ + { 0xA78B, /* LATIN CAPITAL LETTER SALTILLO */ \ + 0xA78C, /* LATIN SMALL LETTER SALTILLO */ }, \ + { 0x018F, /* LATIN CAPITAL LETTER SCHWA */ \ + 0x0259, /* LATIN SMALL LETTER SCHWA */ }, \ + { 0xA7AC, /* LATIN CAPITAL LETTER SCRIPT G */ \ + 0x0261, /* LATIN SMALL LETTER SCRIPT G */ }, \ + { 0x1E9E, /* LATIN CAPITAL LETTER SHARP S */ \ + 0x00DF, /* LATIN SMALL LETTER SHARP S */ }, \ + { 0x0054, /* LATIN CAPITAL LETTER T */ \ + 0x0074, /* LATIN SMALL LETTER T */ }, \ + { 0x0164, /* LATIN CAPITAL LETTER T WITH CARON */ \ + 0x0165, /* LATIN SMALL LETTER T WITH CARON */ }, \ + { 0x0162, /* LATIN CAPITAL LETTER T WITH CEDILLA */ \ + 0x0163, /* LATIN SMALL LETTER T WITH CEDILLA */ }, \ + { 0x1E70, /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW */ \ + 0x1E71, /* LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW */ }, \ + { 0x021A, /* LATIN CAPITAL LETTER T WITH COMMA BELOW */ \ + 0x021B, /* LATIN SMALL LETTER T WITH COMMA BELOW */ }, \ + { 0x023E, /* LATIN CAPITAL LETTER T WITH DIAGONAL STROKE */ \ + 0x2C66, /* LATIN SMALL LETTER T WITH DIAGONAL STROKE */ }, \ + { 0x1E6A, /* LATIN CAPITAL LETTER T WITH DOT ABOVE */ \ + 0x1E6B, /* LATIN SMALL LETTER T WITH DOT ABOVE */ }, \ + { 0x1E6C, /* LATIN CAPITAL LETTER T WITH DOT BELOW */ \ + 0x1E6D, /* LATIN SMALL LETTER T WITH DOT BELOW */ }, \ + { 0x01AC, /* LATIN CAPITAL LETTER T WITH HOOK */ \ + 0x01AD, /* LATIN SMALL LETTER T WITH HOOK */ }, \ + { 0x1E6E, /* LATIN CAPITAL LETTER T WITH LINE BELOW */ \ + 0x1E6F, /* LATIN SMALL LETTER T WITH LINE BELOW */ }, \ + { 0x01AE, /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK */ \ + 0x0288, /* LATIN SMALL LETTER T WITH RETROFLEX HOOK */ }, \ + { 0x0166, /* LATIN CAPITAL LETTER T WITH STROKE */ \ + 0x0167, /* LATIN SMALL LETTER T WITH STROKE */ }, \ + { 0x00DE, /* LATIN CAPITAL LETTER THORN */ \ + 0x00FE, /* LATIN SMALL LETTER THORN */ }, \ + { 0xA764, /* LATIN CAPITAL LETTER THORN WITH STROKE */ \ + 0xA765, /* LATIN SMALL LETTER THORN WITH STROKE */ }, \ + { 0xA766, /* LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER */ \ + 0xA767, /* LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER */ }, \ + { 0x01BC, /* LATIN CAPITAL LETTER TONE FIVE */ \ + 0x01BD, /* LATIN SMALL LETTER TONE FIVE */ }, \ + { 0x0184, /* LATIN CAPITAL LETTER TONE SIX */ \ + 0x0185, /* LATIN SMALL LETTER TONE SIX */ }, \ + { 0x01A7, /* LATIN CAPITAL LETTER TONE TWO */ \ + 0x01A8, /* LATIN SMALL LETTER TONE TWO */ }, \ + { 0xA72A, /* LATIN CAPITAL LETTER TRESILLO */ \ + 0xA72B, /* LATIN SMALL LETTER TRESILLO */ }, \ + { 0x2C6F, /* LATIN CAPITAL LETTER TURNED A */ \ + 0x0250, /* LATIN SMALL LETTER TURNED A */ }, \ + { 0x2C70, /* LATIN CAPITAL LETTER TURNED ALPHA */ \ + 0x0252, /* LATIN SMALL LETTER TURNED ALPHA */ }, \ + { 0xA78D, /* LATIN CAPITAL LETTER TURNED H */ \ + 0x0265, /* LATIN SMALL LETTER TURNED H */ }, \ + { 0xA77E, /* LATIN CAPITAL LETTER TURNED INSULAR G */ \ + 0xA77F, /* LATIN SMALL LETTER TURNED INSULAR G */ }, \ + { 0xA7B0, /* LATIN CAPITAL LETTER TURNED K */ \ + 0x029E, /* LATIN SMALL LETTER TURNED K */ }, \ + { 0xA780, /* LATIN CAPITAL LETTER TURNED L */ \ + 0xA781, /* LATIN SMALL LETTER TURNED L */ }, \ + { 0x019C, /* LATIN CAPITAL LETTER TURNED M */ \ + 0x026F, /* LATIN SMALL LETTER TURNED M */ }, \ + { 0xA7B1, /* LATIN CAPITAL LETTER TURNED T */ \ + 0x0287, /* LATIN SMALL LETTER TURNED T */ }, \ + { 0x0245, /* LATIN CAPITAL LETTER TURNED V */ \ + 0x028C, /* LATIN SMALL LETTER TURNED V */ }, \ + { 0xA728, /* LATIN CAPITAL LETTER TZ */ \ + 0xA729, /* LATIN SMALL LETTER TZ */ }, \ + { 0x0055, /* LATIN CAPITAL LETTER U */ \ + 0x0075, /* LATIN SMALL LETTER U */ }, \ + { 0x0244, /* LATIN CAPITAL LETTER U BAR */ \ + 0x0289, /* LATIN SMALL LETTER U BAR */ }, \ + { 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */ \ + 0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */ }, \ + { 0x016C, /* LATIN CAPITAL LETTER U WITH BREVE */ \ + 0x016D, /* LATIN SMALL LETTER U WITH BREVE */ }, \ + { 0x01D3, /* LATIN CAPITAL LETTER U WITH CARON */ \ + 0x01D4, /* LATIN SMALL LETTER U WITH CARON */ }, \ + { 0x00DB, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ \ + 0x00FB, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */ }, \ + { 0x1E76, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW */ \ + 0x1E77, /* LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW */ }, \ + { 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ \ + 0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ }, \ + { 0x01D7, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE */ \ + 0x01D8, /* LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE */ }, \ + { 0x01D9, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON */ \ + 0x01DA, /* LATIN SMALL LETTER U WITH DIAERESIS AND CARON */ }, \ + { 0x01DB, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE */ \ + 0x01DC, /* LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE */ }, \ + { 0x01D5, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON */ \ + 0x01D6, /* LATIN SMALL LETTER U WITH DIAERESIS AND MACRON */ }, \ + { 0x1E72, /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW */ \ + 0x1E73, /* LATIN SMALL LETTER U WITH DIAERESIS BELOW */ }, \ + { 0x1EE4, /* LATIN CAPITAL LETTER U WITH DOT BELOW */ \ + 0x1EE5, /* LATIN SMALL LETTER U WITH DOT BELOW */ }, \ + { 0x0170, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ \ + 0x0171, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ }, \ + { 0x0214, /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE */ \ + 0x0215, /* LATIN SMALL LETTER U WITH DOUBLE GRAVE */ }, \ + { 0x00D9, /* LATIN CAPITAL LETTER U WITH GRAVE */ \ + 0x00F9, /* LATIN SMALL LETTER U WITH GRAVE */ }, \ + { 0x1EE6, /* LATIN CAPITAL LETTER U WITH HOOK ABOVE */ \ + 0x1EE7, /* LATIN SMALL LETTER U WITH HOOK ABOVE */ }, \ + { 0x01AF, /* LATIN CAPITAL LETTER U WITH HORN */ \ + 0x01B0, /* LATIN SMALL LETTER U WITH HORN */ }, \ + { 0x1EE8, /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE */ \ + 0x1EE9, /* LATIN SMALL LETTER U WITH HORN AND ACUTE */ }, \ + { 0x1EF0, /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */ \ + 0x1EF1, /* LATIN SMALL LETTER U WITH HORN AND DOT BELOW */ }, \ + { 0x1EEA, /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE */ \ + 0x1EEB, /* LATIN SMALL LETTER U WITH HORN AND GRAVE */ }, \ + { 0x1EEC, /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */ \ + 0x1EED, /* LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */ }, \ + { 0x1EEE, /* LATIN CAPITAL LETTER U WITH HORN AND TILDE */ \ + 0x1EEF, /* LATIN SMALL LETTER U WITH HORN AND TILDE */ }, \ + { 0x0216, /* LATIN CAPITAL LETTER U WITH INVERTED BREVE */ \ + 0x0217, /* LATIN SMALL LETTER U WITH INVERTED BREVE */ }, \ + { 0x016A, /* LATIN CAPITAL LETTER U WITH MACRON */ \ + 0x016B, /* LATIN SMALL LETTER U WITH MACRON */ }, \ + { 0x1E7A, /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS */ \ + 0x1E7B, /* LATIN SMALL LETTER U WITH MACRON AND DIAERESIS */ }, \ + { 0x0172, /* LATIN CAPITAL LETTER U WITH OGONEK */ \ + 0x0173, /* LATIN SMALL LETTER U WITH OGONEK */ }, \ + { 0x016E, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ \ + 0x016F, /* LATIN SMALL LETTER U WITH RING ABOVE */ }, \ + { 0xA7B8, /* LATIN CAPITAL LETTER U WITH STROKE */ \ + 0xA7B9, /* LATIN SMALL LETTER U WITH STROKE */ }, \ + { 0x0168, /* LATIN CAPITAL LETTER U WITH TILDE */ \ + 0x0169, /* LATIN SMALL LETTER U WITH TILDE */ }, \ + { 0x1E78, /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE */ \ + 0x1E79, /* LATIN SMALL LETTER U WITH TILDE AND ACUTE */ }, \ + { 0x1E74, /* LATIN CAPITAL LETTER U WITH TILDE BELOW */ \ + 0x1E75, /* LATIN SMALL LETTER U WITH TILDE BELOW */ }, \ + { 0x01B1, /* LATIN CAPITAL LETTER UPSILON */ \ + 0x028A, /* LATIN SMALL LETTER UPSILON */ }, \ + { 0x0056, /* LATIN CAPITAL LETTER V */ \ + 0x0076, /* LATIN SMALL LETTER V */ }, \ + { 0xA75E, /* LATIN CAPITAL LETTER V WITH DIAGONAL STROKE */ \ + 0xA75F, /* LATIN SMALL LETTER V WITH DIAGONAL STROKE */ }, \ + { 0x1E7E, /* LATIN CAPITAL LETTER V WITH DOT BELOW */ \ + 0x1E7F, /* LATIN SMALL LETTER V WITH DOT BELOW */ }, \ + { 0x01B2, /* LATIN CAPITAL LETTER V WITH HOOK */ \ + 0x028B, /* LATIN SMALL LETTER V WITH HOOK */ }, \ + { 0x1E7C, /* LATIN CAPITAL LETTER V WITH TILDE */ \ + 0x1E7D, /* LATIN SMALL LETTER V WITH TILDE */ }, \ + { 0xA768, /* LATIN CAPITAL LETTER VEND */ \ + 0xA769, /* LATIN SMALL LETTER VEND */ }, \ + { 0xA762, /* LATIN CAPITAL LETTER VISIGOTHIC Z */ \ + 0xA763, /* LATIN SMALL LETTER VISIGOTHIC Z */ }, \ + { 0xA79A, /* LATIN CAPITAL LETTER VOLAPUK AE */ \ + 0xA79B, /* LATIN SMALL LETTER VOLAPUK AE */ }, \ + { 0xA79C, /* LATIN CAPITAL LETTER VOLAPUK OE */ \ + 0xA79D, /* LATIN SMALL LETTER VOLAPUK OE */ }, \ + { 0xA79E, /* LATIN CAPITAL LETTER VOLAPUK UE */ \ + 0xA79F, /* LATIN SMALL LETTER VOLAPUK UE */ }, \ + { 0xA760, /* LATIN CAPITAL LETTER VY */ \ + 0xA761, /* LATIN SMALL LETTER VY */ }, \ + { 0x0057, /* LATIN CAPITAL LETTER W */ \ + 0x0077, /* LATIN SMALL LETTER W */ }, \ + { 0x1E82, /* LATIN CAPITAL LETTER W WITH ACUTE */ \ + 0x1E83, /* LATIN SMALL LETTER W WITH ACUTE */ }, \ + { 0x0174, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ \ + 0x0175, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ }, \ + { 0x1E84, /* LATIN CAPITAL LETTER W WITH DIAERESIS */ \ + 0x1E85, /* LATIN SMALL LETTER W WITH DIAERESIS */ }, \ + { 0x1E86, /* LATIN CAPITAL LETTER W WITH DOT ABOVE */ \ + 0x1E87, /* LATIN SMALL LETTER W WITH DOT ABOVE */ }, \ + { 0x1E88, /* LATIN CAPITAL LETTER W WITH DOT BELOW */ \ + 0x1E89, /* LATIN SMALL LETTER W WITH DOT BELOW */ }, \ + { 0x1E80, /* LATIN CAPITAL LETTER W WITH GRAVE */ \ + 0x1E81, /* LATIN SMALL LETTER W WITH GRAVE */ }, \ + { 0x2C72, /* LATIN CAPITAL LETTER W WITH HOOK */ \ + 0x2C73, /* LATIN SMALL LETTER W WITH HOOK */ }, \ + { 0x0058, /* LATIN CAPITAL LETTER X */ \ + 0x0078, /* LATIN SMALL LETTER X */ }, \ + { 0x1E8C, /* LATIN CAPITAL LETTER X WITH DIAERESIS */ \ + 0x1E8D, /* LATIN SMALL LETTER X WITH DIAERESIS */ }, \ + { 0x1E8A, /* LATIN CAPITAL LETTER X WITH DOT ABOVE */ \ + 0x1E8B, /* LATIN SMALL LETTER X WITH DOT ABOVE */ }, \ + { 0x0059, /* LATIN CAPITAL LETTER Y */ \ + 0x0079, /* LATIN SMALL LETTER Y */ }, \ + { 0x00DD, /* LATIN CAPITAL LETTER Y WITH ACUTE */ \ + 0x00FD, /* LATIN SMALL LETTER Y WITH ACUTE */ }, \ + { 0x0176, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ \ + 0x0177, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ }, \ + { 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ \ + 0x00FF, /* LATIN SMALL LETTER Y WITH DIAERESIS */ }, \ + { 0x1E8E, /* LATIN CAPITAL LETTER Y WITH DOT ABOVE */ \ + 0x1E8F, /* LATIN SMALL LETTER Y WITH DOT ABOVE */ }, \ + { 0x1EF4, /* LATIN CAPITAL LETTER Y WITH DOT BELOW */ \ + 0x1EF5, /* LATIN SMALL LETTER Y WITH DOT BELOW */ }, \ + { 0x1EF2, /* LATIN CAPITAL LETTER Y WITH GRAVE */ \ + 0x1EF3, /* LATIN SMALL LETTER Y WITH GRAVE */ }, \ + { 0x01B3, /* LATIN CAPITAL LETTER Y WITH HOOK */ \ + 0x01B4, /* LATIN SMALL LETTER Y WITH HOOK */ }, \ + { 0x1EF6, /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE */ \ + 0x1EF7, /* LATIN SMALL LETTER Y WITH HOOK ABOVE */ }, \ + { 0x1EFE, /* LATIN CAPITAL LETTER Y WITH LOOP */ \ + 0x1EFF, /* LATIN SMALL LETTER Y WITH LOOP */ }, \ + { 0x0232, /* LATIN CAPITAL LETTER Y WITH MACRON */ \ + 0x0233, /* LATIN SMALL LETTER Y WITH MACRON */ }, \ + { 0x024E, /* LATIN CAPITAL LETTER Y WITH STROKE */ \ + 0x024F, /* LATIN SMALL LETTER Y WITH STROKE */ }, \ + { 0x1EF8, /* LATIN CAPITAL LETTER Y WITH TILDE */ \ + 0x1EF9, /* LATIN SMALL LETTER Y WITH TILDE */ }, \ + { 0x021C, /* LATIN CAPITAL LETTER YOGH */ \ + 0x021D, /* LATIN SMALL LETTER YOGH */ }, \ + { 0x005A, /* LATIN CAPITAL LETTER Z */ \ + 0x007A, /* LATIN SMALL LETTER Z */ }, \ + { 0x0179, /* LATIN CAPITAL LETTER Z WITH ACUTE */ \ + 0x017A, /* LATIN SMALL LETTER Z WITH ACUTE */ }, \ + { 0x017D, /* LATIN CAPITAL LETTER Z WITH CARON */ \ + 0x017E, /* LATIN SMALL LETTER Z WITH CARON */ }, \ + { 0x1E90, /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX */ \ + 0x1E91, /* LATIN SMALL LETTER Z WITH CIRCUMFLEX */ }, \ + { 0x2C6B, /* LATIN CAPITAL LETTER Z WITH DESCENDER */ \ + 0x2C6C, /* LATIN SMALL LETTER Z WITH DESCENDER */ }, \ + { 0x017B, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ \ + 0x017C, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ }, \ + { 0x1E92, /* LATIN CAPITAL LETTER Z WITH DOT BELOW */ \ + 0x1E93, /* LATIN SMALL LETTER Z WITH DOT BELOW */ }, \ + { 0x0224, /* LATIN CAPITAL LETTER Z WITH HOOK */ \ + 0x0225, /* LATIN SMALL LETTER Z WITH HOOK */ }, \ + { 0x1E94, /* LATIN CAPITAL LETTER Z WITH LINE BELOW */ \ + 0x1E95, /* LATIN SMALL LETTER Z WITH LINE BELOW */ }, \ + { 0x01B5, /* LATIN CAPITAL LETTER Z WITH STROKE */ \ + 0x01B6, /* LATIN SMALL LETTER Z WITH STROKE */ }, \ + { 0x2C7F, /* LATIN CAPITAL LETTER Z WITH SWASH TAIL */ \ + 0x0240, /* LATIN SMALL LETTER Z WITH SWASH TAIL */ }, \ + { 0x0000, /* END OF LIST CAPITAL LETTERS */ \ + 0x0000, /* END OF LIST SMALL LETTERS */ }, \ +} + +/* + * Correspondence table for small and capital letters of codepage 437. + * Letters A-Z are handled in code. + */ +#define CP437_CAPITALIZATION_TABLE { \ + { 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ \ + 0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ }, \ + { 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ \ + 0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */ }, \ + { 0x00C6, /* LATIN CAPITAL LETTER AE */ \ + 0x00E6, /* LATIN SMALL LETTER AE */ }, \ + { 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ \ + 0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ }, \ + { 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ \ + 0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ }, \ + { 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */ \ + 0x00F1, /* LATIN SMALL LETTER N WITH TILDE */ }, \ + { 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ \ + 0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ }, \ + { 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ \ + 0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ }, \ + { 0x03A3, /* GREEK CAPITAL LETTER SIGMA */ \ + 0x03C3, /* GREEK SMALL LETTER SIGMA */ }, \ + { 0x03A6, /* GREEK CAPITAL LETTER PHI */ \ + 0x03C6, /* GREEK SMALL LETTER PHI */ }, \ + { 0x0000, 0x0000, }, \ +} + +/* + * Correspondence table for small and capital letters of codepage 1250. + * Letters A-Z are handled in code. + */ +#define CP1250_CAPITALIZATION_TABLE { \ + { 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */ \ + 0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */ }, \ + { 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ \ + 0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ }, \ + { 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ \ + 0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ }, \ + { 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ \ + 0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ }, \ + { 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ \ + 0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ }, \ + { 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ \ + 0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */ }, \ + { 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */ \ + 0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */ }, \ + { 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ \ + 0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ }, \ + { 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */ \ + 0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */ }, \ + { 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ \ + 0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ }, \ + { 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ \ + 0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ }, \ + { 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */ \ + 0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */ }, \ + { 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ \ + 0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ }, \ + { 0x00DD, /* LATIN CAPITAL LETTER Y WITH ACUTE */ \ + 0x00FD, /* LATIN SMALL LETTER Y WITH ACUTE */ }, \ + { 0x0102, /* LATIN CAPITAL LETTER A WITH BREVE */ \ + 0x0103, /* LATIN SMALL LETTER A WITH BREVE */ }, \ + { 0x0104, /* LATIN CAPITAL LETTER A WITH OGONEK */ \ + 0x0105, /* LATIN SMALL LETTER A WITH OGONEK */ }, \ + { 0x0106, /* LATIN CAPITAL LETTER C WITH ACUTE */ \ + 0x0107, /* LATIN SMALL LETTER C WITH ACUTE */ }, \ + { 0x010C, /* LATIN CAPITAL LETTER C WITH CARON */ \ + 0x010D, /* LATIN SMALL LETTER C WITH CARON */ }, \ + { 0x010E, /* LATIN CAPITAL LETTER D WITH CARON */ \ + 0x010F, /* LATIN SMALL LETTER D WITH CARON */ }, \ + { 0x0110, /* LATIN CAPITAL LETTER D WITH STROKE */ \ + 0x0111, /* LATIN SMALL LETTER D WITH STROKE */ }, \ + { 0x0118, /* LATIN CAPITAL LETTER E WITH OGONEK */ \ + 0x0119, /* LATIN SMALL LETTER E WITH OGONEK */ }, \ + { 0x011A, /* LATIN CAPITAL LETTER E WITH CARON */ \ + 0x011B, /* LATIN SMALL LETTER E WITH CARON */ }, \ + { 0x0139, /* LATIN CAPITAL LETTER L WITH ACUTE */ \ + 0x013A, /* LATIN SMALL LETTER L WITH ACUTE */ }, \ + { 0x013D, /* LATIN CAPITAL LETTER L WITH CARON */ \ + 0x013E, /* LATIN SMALL LETTER L WITH CARON */ }, \ + { 0x0141, /* LATIN CAPITAL LETTER L WITH STROKE */ \ + 0x0142, /* LATIN SMALL LETTER L WITH STROKE */ }, \ + { 0x0143, /* LATIN CAPITAL LETTER N WITH ACUTE */ \ + 0x0144, /* LATIN SMALL LETTER N WITH ACUTE */ }, \ + { 0x0147, /* LATIN CAPITAL LETTER N WITH CARON */ \ + 0x0148, /* LATIN SMALL LETTER N WITH CARON */ }, \ + { 0x0150, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ \ + 0x0151, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ }, \ + { 0x0154, /* LATIN CAPITAL LETTER R WITH ACUTE */ \ + 0x0155, /* LATIN SMALL LETTER R WITH ACUTE */ }, \ + { 0x0158, /* LATIN CAPITAL LETTER R WITH CARON */ \ + 0x0159, /* LATIN SMALL LETTER R WITH CARON */ }, \ + { 0x015A, /* LATIN CAPITAL LETTER S WITH ACUTE */ \ + 0x015B, /* LATIN SMALL LETTER S WITH ACUTE */ }, \ + { 0x015E, /* LATIN CAPITAL LETTER S WITH CEDILLA */ \ + 0x015F, /* LATIN SMALL LETTER S WITH CEDILLA */ }, \ + { 0x0160, /* LATIN CAPITAL LETTER S WITH CARON */ \ + 0x0161, /* LATIN SMALL LETTER S WITH CARON */ }, \ + { 0x0162, /* LATIN CAPITAL LETTER T WITH CEDILLA */ \ + 0x0163, /* LATIN SMALL LETTER T WITH CEDILLA */ }, \ + { 0x0164, /* LATIN CAPITAL LETTER T WITH CARON */ \ + 0x0165, /* LATIN SMALL LETTER T WITH CARON */ }, \ + { 0x016E, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ \ + 0x016F, /* LATIN SMALL LETTER U WITH RING ABOVE */ }, \ + { 0x0170, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ \ + 0x0171, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ }, \ + { 0x0179, /* LATIN CAPITAL LETTER Z WITH ACUTE */ \ + 0x017A, /* LATIN SMALL LETTER Z WITH ACUTE */ }, \ + { 0x017B, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ \ + 0x017C, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ }, \ + { 0x017D, /* LATIN CAPITAL LETTER Z WITH CARON */ \ + 0x017E, /* LATIN SMALL LETTER Z WITH CARON */ }, \ + { 0x0000, 0x0000, }, \ +} diff --git a/include/charset.h b/include/charset.h index 11832cbd12..4d45e246e5 100644 --- a/include/charset.h +++ b/include/charset.h @@ -8,44 +8,188 @@ #ifndef __CHARSET_H_ #define __CHARSET_H_ +#include <linux/kernel.h> #include <linux/types.h> #define MAX_UTF8_PER_UTF16 3 /** - * utf16_strlen() - Get the length of an utf16 string + * console_read_unicode() - read Unicode code point from console * - * Returns the number of 16 bit characters in an utf16 string, not - * including the terminating NULL character. + * @code: pointer to store Unicode code point + * Return: 0 = success + */ +int console_read_unicode(s32 *code); + +/** + * utf8_get() - get next UTF-8 code point from buffer + * + * @src: pointer to current byte, updated to point to next byte + * Return: code point, or 0 for end of string, or -1 if no legal + * code point is found. In case of an error src points to + * the incorrect byte. + */ +s32 utf8_get(const char **src); + +/** + * utf8_put() - write UTF-8 code point to buffer + * + * @code: code point + * @dst: pointer to destination buffer, updated to next position + * Return: -1 if the input parameters are invalid + */ +int utf8_put(s32 code, char **dst); + +/** + * utf8_utf16_strnlen() - length of a truncated utf-8 string after conversion + * to utf-16 + * + * @src: utf-8 string + * @count: maximum number of code points to convert + * Return: length in bytes after conversion to utf-16 without the + * trailing \0. If an invalid UTF-8 sequence is hit one + * word will be reserved for a replacement character. + */ +size_t utf8_utf16_strnlen(const char *src, size_t count); + +/** + * utf8_utf16_strlen() - length of a utf-8 string after conversion to utf-16 + * + * @src: utf-8 string + * Return: length in bytes after conversion to utf-16 without the + * trailing \0. -1 if the utf-8 string is not valid. + */ +#define utf8_utf16_strlen(a) utf8_utf16_strnlen((a), SIZE_MAX) + +/** + * utf8_utf16_strncpy() - copy utf-8 string to utf-16 string + * + * @dst: destination buffer + * @src: source buffer + * @count: maximum number of code points to copy + * Return: -1 if the input parameters are invalid + */ +int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count); + +/** + * utf8_utf16_strcpy() - copy utf-8 string to utf-16 string + * + * @dst: destination buffer + * @src: source buffer + * Return: -1 if the input parameters are invalid + */ +#define utf8_utf16_strcpy(d, s) utf8_utf16_strncpy((d), (s), SIZE_MAX) + +/** + * utf16_get() - get next UTF-16 code point from buffer + * + * @src: pointer to current word, updated to point to next word + * Return: code point, or 0 for end of string, or -1 if no legal + * code point is found. In case of an error src points to + * the incorrect word. + */ +s32 utf16_get(const u16 **src); + +/** + * utf16_put() - write UTF-16 code point to buffer + * + * @code: code point + * @dst: pointer to destination buffer, updated to next position + * Return: -1 if the input parameters are invalid + */ +int utf16_put(s32 code, u16 **dst); + +/** + * utf16_strnlen() - length of a truncated utf-16 string * - * @in the string to measure - * @return the string length + * @src: utf-16 string + * @count: maximum number of code points to convert + * Return: length in code points. If an invalid UTF-16 sequence is + * hit one position will be reserved for a replacement + * character. */ -size_t utf16_strlen(const uint16_t *in); +size_t utf16_strnlen(const u16 *src, size_t count); /** - * utf16_strnlen() - Get the length of a fixed-size utf16 string. + * utf16_utf8_strnlen() - length of a truncated utf-16 string after conversion + * to utf-8 * - * Returns the number of 16 bit characters in an utf16 string, - * not including the terminating NULL character, but at most - * 'count' number of characters. In doing this, utf16_strnlen() - * looks at only the first 'count' characters. + * @src: utf-16 string + * @count: maximum number of code points to convert + * Return: length in bytes after conversion to utf-8 without the + * trailing \0. If an invalid UTF-16 sequence is hit one + * byte will be reserved for a replacement character. + */ +size_t utf16_utf8_strnlen(const u16 *src, size_t count); + +/** + * utf16_utf8_strlen() - length of a utf-16 string after conversion to utf-8 * - * @in the string to measure - * @count the maximum number of characters to count - * @return the string length, up to a maximum of 'count' + * @src: utf-16 string + * Return: length in bytes after conversion to utf-8 without the + * trailing \0. -1 if the utf-16 string is not valid. */ -size_t utf16_strnlen(const uint16_t *in, size_t count); +#define utf16_utf8_strlen(a) utf16_utf8_strnlen((a), SIZE_MAX) /** - * utf16_strcpy() - UTF16 equivalent of strcpy() + * utf16_utf8_strncpy() - copy utf-16 string to utf-8 string + * + * @dst: destination buffer + * @src: source buffer + * @count: maximum number of code points to copy + * Return: -1 if the input parameters are invalid */ -uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src); +int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count); /** - * utf16_strdup() - UTF16 equivalent of strdup() + * utf16_utf8_strcpy() - copy utf-16 string to utf-8 string + * + * @dst: destination buffer + * @src: source buffer + * Return: -1 if the input parameters are invalid */ -uint16_t *utf16_strdup(const uint16_t *s); +#define utf16_utf8_strcpy(d, s) utf16_utf8_strncpy((d), (s), SIZE_MAX) + +/** + * utf_to_lower() - convert a Unicode letter to lower case + * + * @code: letter to convert + * Return: lower case letter or unchanged letter + */ +s32 utf_to_lower(const s32 code); + +/** + * utf_to_upper() - convert a Unicode letter to upper case + * + * @code: letter to convert + * Return: upper case letter or unchanged letter + */ +s32 utf_to_upper(const s32 code); + +/** + * u16_strlen - count non-zero words + * + * This function matches wsclen() if the -fshort-wchar compiler flag is set. + * In the EFI context we explicitly need a function handling u16 strings. + * + * @in: null terminated u16 string + * ReturnValue: number of non-zero words. + * This is not the number of utf-16 letters! + */ +size_t u16_strlen(const u16 *in); + +/** + * u16_strlen - count non-zero words + * + * This function matches wscnlen_s() if the -fshort-wchar compiler flag is set. + * In the EFI context we explicitly need a function handling u16 strings. + * + * @in: null terminated u16 string + * @count: maximum number of words to count + * ReturnValue: number of non-zero words. + * This is not the number of utf-16 letters! + */ +size_t u16_strnlen(const u16 *in, size_t count); /** * utf16_to_utf8() - Convert an utf16 string to utf8 @@ -63,17 +207,4 @@ uint16_t *utf16_strdup(const uint16_t *s); */ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size); -/** - * utf8_to_utf16() - Convert an utf8 string to utf16 - * - * Converts up to 'size' characters of the utf16 string 'src' to utf8 - * written to the 'dest' buffer. Stops at 0x00. - * - * @dest the destination buffer to write the utf8 characters - * @src the source utf16 string - * @size maximum number of utf16 characters to convert - * @return the pointer to the first unwritten byte in 'dest' - */ -uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size); - #endif /* __CHARSET_H_ */ diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h index d672e8ebe6..373fee78a9 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -245,22 +245,26 @@ #if defined(CONFIG_CMD_DHCP) #if defined(CONFIG_EFI_LOADER) /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */ -#if defined(CONFIG_ARM64) +#if defined(CONFIG_ARM64) || defined(__aarch64__) #define BOOTENV_EFI_PXE_ARCH "0xb" #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00011:UNDI:003000" -#elif defined(CONFIG_ARM) +#elif defined(CONFIG_ARM) || defined(__arm__) #define BOOTENV_EFI_PXE_ARCH "0xa" #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00010:UNDI:003000" -#elif defined(CONFIG_X86) -/* Always assume we're running 64bit */ +#elif defined(CONFIG_X86) || defined(__x86_64__) #define BOOTENV_EFI_PXE_ARCH "0x7" #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00007:UNDI:003000" -#elif defined(CONFIG_CPU_RISCV_32) +#elif defined(__i386__) +#define BOOTENV_EFI_PXE_ARCH "0x6" +#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00006:UNDI:003000" +#elif defined(CONFIG_CPU_RISCV_32) || ((defined(__riscv) && __riscv_xlen == 32)) #define BOOTENV_EFI_PXE_ARCH "0x19" #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00025:UNDI:003000" -#elif defined(CONFIG_CPU_RISCV_64) +#elif defined(CONFIG_CPU_RISCV_64) || ((defined(__riscv) && __riscv_xlen == 64)) #define BOOTENV_EFI_PXE_ARCH "0x1b" #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00027:UNDI:003000" +#elif defined(CONFIG_SANDBOX) +# error "sandbox EFI support is only supported on ARM and x86" #else #error Please specify an EFI client identifier #endif diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h index 2568e95270..d825f0fc33 100644 --- a/include/configs/MPC8544DS.h +++ b/include/configs/MPC8544DS.h @@ -280,8 +280,7 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4 #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE -#endif /* SCSCI */ +#endif /* CONFIG_SCSI_AHCI */ #endif /* CONFIG_PCI */ diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h index 8c92c3f832..dd081e8c12 100644 --- a/include/configs/MPC8572DS.h +++ b/include/configs/MPC8572DS.h @@ -464,7 +464,6 @@ #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4 #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE #endif /* SCSI */ #endif /* CONFIG_PCI */ diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h index cfb7135870..02fd864727 100644 --- a/include/configs/MPC8610HPCD.h +++ b/include/configs/MPC8610HPCD.h @@ -278,7 +278,6 @@ #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4 #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE #endif #endif /* CONFIG_PCI */ diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h index 68bc710b02..bc69efbbe6 100644 --- a/include/configs/MPC8641HPCN.h +++ b/include/configs/MPC8641HPCN.h @@ -373,7 +373,6 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4 #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE #endif #endif /* CONFIG_PCI */ diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h index 14a6b9e591..319f6aadf5 100644 --- a/include/configs/da850evm.h +++ b/include/configs/da850evm.h @@ -116,7 +116,7 @@ * Serial Driver info */ -#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_DIRECT_NOR_BOOT) +#if !CONFIG_IS_ENABLED(DM_SERIAL) #define CONFIG_SYS_NS16550_SERIAL #define CONFIG_SYS_NS16550_REG_SIZE -4 /* NS16550 register size */ #define CONFIG_SYS_NS16550_COM1 DAVINCI_UART2_BASE /* Base address of UART2 */ diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h index fcaf3a1e13..d8d6d2f6b0 100644 --- a/include/configs/dra7xx_evm.h +++ b/include/configs/dra7xx_evm.h @@ -113,10 +113,6 @@ /* SATA */ #define CONFIG_SCSI_AHCI_PLAT -#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1 -#define CONFIG_SYS_SCSI_MAX_LUN 1 -#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ - CONFIG_SYS_SCSI_MAX_LUN) /* NAND support */ #ifdef CONFIG_NAND diff --git a/include/configs/gardena-smart-gateway-mt7688.h b/include/configs/gardena-smart-gateway-mt7688.h new file mode 100644 index 0000000000..0184147068 --- /dev/null +++ b/include/configs/gardena-smart-gateway-mt7688.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +#ifndef __CONFIG_GARDENA_SMART_GATEWAY_H +#define __CONFIG_GARDENA_SMART_GATEWAY_H + +/* CPU */ +#define CONFIG_SYS_MIPS_TIMER_FREQ 200000000 + +/* RAM */ +#define CONFIG_SYS_SDRAM_BASE 0x80000000 + +#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_SDRAM_BASE + 0x100000 + +#define CONFIG_SYS_INIT_SP_OFFSET 0x400000 + +#ifdef CONFIG_BOOT_RAM +#define CONFIG_SKIP_LOWLEVEL_INIT +#endif + +/* UART */ +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200, \ + 230400, 500000, 1500000 } + +/* RAM */ +#define CONFIG_SYS_MEMTEST_START 0x80100000 +#define CONFIG_SYS_MEMTEST_END 0x80400000 + +/* Memory usage */ +#define CONFIG_SYS_MAXARGS 64 +#define CONFIG_SYS_MALLOC_LEN (1024 * 1024) +#define CONFIG_SYS_BOOTPARAMS_LEN (128 * 1024) +#define CONFIG_SYS_CBSIZE 512 + +/* U-Boot */ +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +/* Environment settings */ +#define CONFIG_ENV_OFFSET 0x80000 +#define CONFIG_ENV_SIZE (64 << 10) +#define CONFIG_ENV_SECT_SIZE (64 << 10) +#define CONFIG_SYS_REDUNDAND_ENVIRONMENT +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + \ + CONFIG_ENV_SECT_SIZE) +#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE + +/* + * Environment is right behind U-Boot in flash. Make sure U-Boot + * doesn't grow into the environment area. + */ +#define CONFIG_BOARD_SIZE_LIMIT CONFIG_ENV_OFFSET + +#endif /* __CONFIG_GARDENA_SMART_GATEWAY_H */ diff --git a/include/configs/imgtec_xilfpga.h b/include/configs/imgtec_xilfpga.h index 29b23fa40e..8e2d72323d 100644 --- a/include/configs/imgtec_xilfpga.h +++ b/include/configs/imgtec_xilfpga.h @@ -19,9 +19,6 @@ /* CPU Timer rate */ #define CONFIG_SYS_MIPS_TIMER_FREQ 50000000 -/* Cache Configuration */ -#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT - /*---------------------------------------------------------------------- * Memory Layout */ diff --git a/include/configs/linkit-smart-7688.h b/include/configs/linkit-smart-7688.h new file mode 100644 index 0000000000..78efa23279 --- /dev/null +++ b/include/configs/linkit-smart-7688.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + */ + +#ifndef __CONFIG_LINKIT_SMART_7688_H +#define __CONFIG_LINKIT_SMART_7688_H + +/* CPU */ +#define CONFIG_SYS_MIPS_TIMER_FREQ 200000000 + +/* RAM */ +#define CONFIG_SYS_SDRAM_BASE 0x80000000 + +#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_SDRAM_BASE + 0x100000 + +#define CONFIG_SYS_INIT_SP_OFFSET 0x400000 + +#ifdef CONFIG_BOOT_RAM +#define CONFIG_SKIP_LOWLEVEL_INIT +#endif + +/* UART */ +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200, \ + 230400, 500000, 1500000 } + +/* RAM */ +#define CONFIG_SYS_MEMTEST_START 0x80100000 +#define CONFIG_SYS_MEMTEST_END 0x80400000 + +/* Memory usage */ +#define CONFIG_SYS_MAXARGS 64 +#define CONFIG_SYS_MALLOC_LEN (1024 * 1024) +#define CONFIG_SYS_BOOTPARAMS_LEN (128 * 1024) +#define CONFIG_SYS_CBSIZE 512 + +/* U-Boot */ +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +/* Environment settings */ +#define CONFIG_ENV_OFFSET 0x40000 +#define CONFIG_ENV_SIZE (16 << 10) +#define CONFIG_ENV_SECT_SIZE (64 << 10) + +/* + * Environment is right behind U-Boot in flash. Make sure U-Boot + * doesn't grow into the environment area. + */ +#define CONFIG_BOARD_SIZE_LIMIT CONFIG_ENV_OFFSET + +#endif /* __CONFIG_LINKIT_SMART_7688_H */ diff --git a/include/configs/pic32mzdask.h b/include/configs/pic32mzdask.h index 374957737d..d3ab5575ee 100644 --- a/include/configs/pic32mzdask.h +++ b/include/configs/pic32mzdask.h @@ -16,9 +16,6 @@ /* CPU Timer rate */ #define CONFIG_SYS_MIPS_TIMER_FREQ 100000000 -/* Cache Configuration */ -#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT - /*---------------------------------------------------------------------- * Memory Layout */ diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h index 66729b7d4f..fedc4662fa 100644 --- a/include/configs/qemu-arm.h +++ b/include/configs/qemu-arm.h @@ -20,12 +20,6 @@ /* For timer, QEMU emulates an ARMv7/ARMv8 architected timer */ #define CONFIG_SYS_HZ 1000 -/* For block devices, QEMU emulates an ICH9 AHCI controller over PCI */ -#define CONFIG_SYS_SCSI_MAX_SCSI_ID 6 - -/* QEMU emulates the ARM AMBA PL031 RTC */ -#define CONFIG_SYS_RTC_PL031_BASE 0x09010000 - /* Environment options */ #define CONFIG_ENV_SIZE SZ_64K diff --git a/include/configs/sama5d27_som1_ek.h b/include/configs/sama5d27_som1_ek.h index 6192328965..7c7479b4d4 100644 --- a/include/configs/sama5d27_som1_ek.h +++ b/include/configs/sama5d27_som1_ek.h @@ -36,17 +36,11 @@ #undef CONFIG_BOOTCOMMAND #ifdef CONFIG_SD_BOOT /* u-boot env in sd/mmc card */ -#define FAT_ENV_INTERFACE "mmc" -#define FAT_ENV_DEVICE_AND_PART "0" -#define FAT_ENV_FILE "uboot.env" #define CONFIG_ENV_SIZE 0x4000 /* bootstrap + u-boot + env in sd card */ -#define CONFIG_BOOTCOMMAND "fatload mmc 0:1 0x21000000 at91-sama5d27_som1_ek.dtb; " \ - "fatload mmc 0:1 0x22000000 zImage; " \ +#define CONFIG_BOOTCOMMAND "fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x21000000 at91-sama5d27_som1_ek.dtb; " \ + "fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x22000000 zImage; " \ "bootz 0x22000000 - 0x21000000" -#undef CONFIG_BOOTARGS -#define CONFIG_BOOTARGS \ - "console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait" #endif #ifdef CONFIG_QSPI_BOOT diff --git a/include/configs/sama5d2_xplained.h b/include/configs/sama5d2_xplained.h index 92f7f0df0e..2cec1c7b42 100644 --- a/include/configs/sama5d2_xplained.h +++ b/include/configs/sama5d2_xplained.h @@ -36,8 +36,8 @@ /* bootstrap + u-boot + env in sd card */ #undef CONFIG_BOOTCOMMAND -#define CONFIG_BOOTCOMMAND "fatload mmc 1:1 0x21000000 at91-sama5d2_xplained.dtb; " \ - "fatload mmc 1:1 0x22000000 zImage; " \ +#define CONFIG_BOOTCOMMAND "fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x21000000 at91-sama5d2_xplained.dtb; " \ + "fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x22000000 zImage; " \ "bootz 0x22000000 - 0x21000000" #elif CONFIG_SPI_BOOT diff --git a/include/configs/sbc8641d.h b/include/configs/sbc8641d.h index c509822814..d777e7a36a 100644 --- a/include/configs/sbc8641d.h +++ b/include/configs/sbc8641d.h @@ -298,7 +298,6 @@ #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4 #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN) -#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE #endif #endif /* CONFIG_PCI */ diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h index 78c382de0c..4180b25f97 100644 --- a/include/configs/x86-common.h +++ b/include/configs/x86-common.h @@ -28,10 +28,6 @@ #define CONFIG_LBA48 #define CONFIG_SYS_64BIT_LBA -#define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 -#define CONFIG_SYS_SCSI_MAX_LUN 1 -#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ - CONFIG_SYS_SCSI_MAX_LUN) #endif /* Generic TPM interfaced through LPC bus */ diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index a65e8fedff..0ab32611ce 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -122,13 +122,6 @@ # define CONFIG_SYS_EEPROM_SIZE (64 * 1024) #endif -#ifdef CONFIG_SATA_CEVA -#define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 -#define CONFIG_SYS_SCSI_MAX_LUN 1 -#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ - CONFIG_SYS_SCSI_MAX_LUN) -#endif - #define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024) #define CONFIG_CLOCKS diff --git a/include/configs/xilinx_zynqmp_mini.h b/include/configs/xilinx_zynqmp_mini.h index 1387d39e79..00ca3d4be8 100644 --- a/include/configs/xilinx_zynqmp_mini.h +++ b/include/configs/xilinx_zynqmp_mini.h @@ -24,7 +24,6 @@ #undef CONFIG_BOOTM_NETBSD #undef CONFIG_BOOTM_VXWORKS #undef CONFIG_BOOTM_LINUX -#undef CONFIG_BOARD_LATE_INIT /* BOOTP options */ #undef CONFIG_BOOTP_BOOTFILESIZE diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index 526fe055a8..f99c2cbf0d 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -127,8 +127,6 @@ /* Boot configuration */ #define CONFIG_SYS_LOAD_ADDR 0 /* default? */ -/* Distro boot enablement */ - #ifdef CONFIG_SPL_BUILD #define BOOTENV #else @@ -244,10 +242,6 @@ #define CONFIG_SYS_LDSCRIPT "arch/arm/mach-zynq/u-boot.lds" -/* Commands */ - -/* SPL part */ - /* MMC support */ #ifdef CONFIG_MMC_SDHCI_ZYNQ #define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 1 @@ -279,8 +273,6 @@ CONFIG_SYS_SPI_ARGS_SIZE) #endif -/* for booting directly linux */ - /* SP location before relocation, must use scratch RAM */ #define CONFIG_SPL_TEXT_BASE 0x0 diff --git a/include/configs/zynq_cse.h b/include/configs/zynq_cse.h index c4587a1837..e7a4d4108a 100644 --- a/include/configs/zynq_cse.h +++ b/include/configs/zynq_cse.h @@ -17,7 +17,6 @@ /* Undef unneeded configs */ #undef CONFIG_EXTRA_ENV_SETTINGS -#undef CONFIG_BOARD_LATE_INIT #undef CONFIG_ZLIB #undef CONFIG_GZIP diff --git a/include/configs/zynq_zybo.h b/include/configs/zynq_zybo.h index 547ecb68fd..7d00b412a7 100644 --- a/include/configs/zynq_zybo.h +++ b/include/configs/zynq_zybo.h @@ -12,8 +12,6 @@ #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 #define CONFIG_ZYNQ_GEM_EEPROM_ADDR 0x50 -#define CONFIG_DISPLAY -#define CONFIG_I2C_EDID #include <configs/zynq-common.h> diff --git a/include/cp1250.h b/include/cp1250.h new file mode 100644 index 0000000000..adacf8a958 --- /dev/null +++ b/include/cp1250.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * Constant CP1250 contains the Unicode code points for characters 0x80 - 0xff + * of the code page 1250. + */ +#define CP1250 { \ + 0x20ac, 0x0000, 0x201a, 0x0000, \ + 0x201e, 0x2026, 0x2020, 0x2021, \ + 0x0000, 0x2030, 0x0160, 0x2039, \ + 0x015a, 0x0164, 0x017d, 0x0179, \ + 0x0000, 0x2018, 0x2019, 0x201c, \ + 0x201d, 0x2022, 0x2013, 0x2014, \ + 0x0000, 0x2122, 0x0161, 0x203a, \ + 0x015b, 0x0165, 0x017e, 0x017a, \ + 0x00a0, 0x02c7, 0x02d8, 0x0141, \ + 0x00a4, 0x0104, 0x00a6, 0x00a7, \ + 0x00a8, 0x00a9, 0x015e, 0x00ab, \ + 0x00ac, 0x00ad, 0x00ae, 0x017b, \ + 0x00b0, 0x00b1, 0x02db, 0x0142, \ + 0x00b4, 0x00b5, 0x00b6, 0x00b7, \ + 0x00b8, 0x0105, 0x015f, 0x00bb, \ + 0x013d, 0x02dd, 0x013e, 0x017c, \ + 0x0154, 0x00c1, 0x00c2, 0x0102, \ + 0x00c4, 0x0139, 0x0106, 0x00c7, \ + 0x010c, 0x00c9, 0x0118, 0x00cb, \ + 0x011a, 0x00cd, 0x00ce, 0x010e, \ + 0x0110, 0x0143, 0x0147, 0x00d3, \ + 0x00d4, 0x0150, 0x00d6, 0x00d7, \ + 0x0158, 0x016e, 0x00da, 0x0170, \ + 0x00dc, 0x00dd, 0x0162, 0x00df, \ + 0x0155, 0x00e1, 0x00e2, 0x0103, \ + 0x00e4, 0x013a, 0x0107, 0x00e7, \ + 0x010d, 0x00e9, 0x0119, 0x00eb, \ + 0x011b, 0x00ed, 0x00ee, 0x010f, \ + 0x0111, 0x0144, 0x0148, 0x00f3, \ + 0x00f4, 0x0151, 0x00f6, 0x00f7, \ + 0x0159, 0x016f, 0x00fa, 0x0171, \ + 0x00fc, 0x00fd, 0x0163, 0x02d9, \ +} diff --git a/include/cp437.h b/include/cp437.h new file mode 100644 index 0000000000..0b2b97132e --- /dev/null +++ b/include/cp437.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * Constant CP437 contains the Unicode code points for characters 0x80 - 0xff + * of the code page 437. + */ +#define CP437 { \ + 0x00c7, 0x00fc, 0x00e9, 0x00e2, \ + 0x00e4, 0x00e0, 0x00e5, 0x00e7, \ + 0x00ea, 0x00eb, 0x00e8, 0x00ef, \ + 0x00ee, 0x00ec, 0x00c4, 0x00c5, \ + 0x00c9, 0x00e6, 0x00c6, 0x00f4, \ + 0x00f6, 0x00f2, 0x00fb, 0x00f9, \ + 0x00ff, 0x00d6, 0x00dc, 0x00a2, \ + 0x00a3, 0x00a5, 0x20a7, 0x0192, \ + 0x00e1, 0x00ed, 0x00f3, 0x00fa, \ + 0x00f1, 0x00d1, 0x00aa, 0x00ba, \ + 0x00bf, 0x2310, 0x00ac, 0x00bd, \ + 0x00bc, 0x00a1, 0x00ab, 0x00bb, \ + 0x2591, 0x2592, 0x2593, 0x2502, \ + 0x2524, 0x2561, 0x2562, 0x2556, \ + 0x2555, 0x2563, 0x2551, 0x2557, \ + 0x255d, 0x255c, 0x255b, 0x2510, \ + 0x2514, 0x2534, 0x252c, 0x251c, \ + 0x2500, 0x253c, 0x255e, 0x255f, \ + 0x255a, 0x2554, 0x2569, 0x2566, \ + 0x2560, 0x2550, 0x256c, 0x2567, \ + 0x2568, 0x2564, 0x2565, 0x2559, \ + 0x2558, 0x2552, 0x2553, 0x256b, \ + 0x256a, 0x2518, 0x250c, 0x2588, \ + 0x2584, 0x258c, 0x2590, 0x2580, \ + 0x03b1, 0x00df, 0x0393, 0x03c0, \ + 0x03a3, 0x03c3, 0x00b5, 0x03c4, \ + 0x03a6, 0x0398, 0x03a9, 0x03b4, \ + 0x221e, 0x03c6, 0x03b5, 0x2229, \ + 0x2261, 0x00b1, 0x2265, 0x2264, \ + 0x2320, 0x2321, 0x00f7, 0x2248, \ + 0x00b0, 0x2219, 0x00b7, 0x221a, \ + 0x207f, 0x00b2, 0x25a0, 0x00a0, \ +} diff --git a/include/cpsw.h b/include/cpsw.h index f135e7bfe0..9f8ce8850f 100644 --- a/include/cpsw.h +++ b/include/cpsw.h @@ -54,5 +54,6 @@ struct cpsw_platform_data { int cpsw_register(struct cpsw_platform_data *data); int ti_cm_get_macid(struct udevice *dev, int slave, u8 *mac_addr); +int cpsw_get_slave_phy_addr(struct udevice *dev, int slave); #endif /* _CPSW_H_ */ diff --git a/include/dm/platform_data/pl022_spi.h b/include/dm/platform_data/pl022_spi.h new file mode 100644 index 0000000000..77fe6da3cb --- /dev/null +++ b/include/dm/platform_data/pl022_spi.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 + * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com + * + * Structure for use with U_BOOT_DEVICE for pl022 SPI devices or to use + * in ofdata_to_platdata. + */ + +#ifndef __PL022_SPI_H__ +#define __PL022_SPI_H__ + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +#include <clk.h> +#endif +#include <fdtdec.h> + +struct pl022_spi_pdata { + fdt_addr_t addr; + fdt_size_t size; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct clk clk; +#else + unsigned int freq; +#endif +}; + +#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 7027ea076d..e6fc3ab92b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -37,6 +37,7 @@ enum uclass_id { UCLASS_DMA, /* Direct Memory Access */ UCLASS_EFI, /* EFI managed devices */ UCLASS_ETH, /* Ethernet device */ + UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_I2C, /* I2C bus */ @@ -92,6 +93,8 @@ enum uclass_id { UCLASS_VIDEO, /* Video or LCD device */ UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */ UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */ + UCLASS_W1, /* Dallas 1-Wire bus */ + UCLASS_W1_EEPROM, /* one-wire EEPROMs */ UCLASS_WDT, /* Watchdot Timer driver */ UCLASS_COUNT, diff --git a/include/efi.h b/include/efi.h index e1854ecd23..b1deb609b4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Extensible Firmware Interface * Based on 'Extensible Firmware Interface Specification' version 0.9, diff --git a/include/efi_api.h b/include/efi_api.h index ebf2a3bc18..bea19a5a12 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Extensible Firmware Interface * Based on 'Extensible Firmware Interface Specification' version 0.9, @@ -31,6 +32,7 @@ enum efi_timer_delay { EFI_TIMER_RELATIVE = 2 }; +#define efi_intn_t ssize_t #define efi_uintn_t size_t typedef uint16_t *efi_string_t; @@ -294,8 +296,7 @@ struct efi_runtime_services { EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) -struct efi_configuration_table -{ +struct efi_configuration_table { efi_guid_t guid; void *table; }; @@ -307,7 +308,7 @@ struct efi_system_table { u16 *fw_vendor; /* physical addr of wchar_t vendor string */ u32 fw_revision; efi_handle_t con_in_handle; - struct efi_simple_input_interface *con_in; + struct efi_simple_text_input_protocol *con_in; efi_handle_t con_out_handle; struct efi_simple_text_output_protocol *con_out; efi_handle_t stderr_handle; @@ -338,19 +339,11 @@ struct efi_loaded_image { unsigned int image_code_type; unsigned int image_data_type; unsigned long unload; - - /* Below are efi loader private fields */ -#ifdef CONFIG_EFI_LOADER - void *reloc_base; - aligned_u64 reloc_size; - efi_status_t exit_status; - struct jmp_buf_data exit_jmp; -#endif }; #define DEVICE_PATH_GUID \ EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, \ - 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) + 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define DEVICE_PATH_TYPE_END 0x7f # define DEVICE_PATH_SUB_TYPE_INSTANCE_END 0x01 @@ -475,8 +468,7 @@ struct efi_device_path_file_path { EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) -struct efi_block_io_media -{ +struct efi_block_io_media { u32 media_id; char removable_media; char media_present; @@ -521,7 +513,6 @@ struct simple_text_output_mode { bool cursor_visible; }; - #define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) @@ -588,20 +579,76 @@ struct efi_simple_text_output_protocol { struct simple_text_output_mode *mode; }; +#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ + EFI_GUID(0xdd9e7534, 0x7762, 0x4698, \ + 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa) + struct efi_input_key { u16 scan_code; s16 unicode_char; }; +#define EFI_SHIFT_STATE_INVALID 0x00000000 +#define EFI_RIGHT_SHIFT_PRESSED 0x00000001 +#define EFI_LEFT_SHIFT_PRESSED 0x00000002 +#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 +#define EFI_LEFT_CONTROL_PRESSED 0x00000008 +#define EFI_RIGHT_ALT_PRESSED 0x00000010 +#define EFI_LEFT_ALT_PRESSED 0x00000020 +#define EFI_RIGHT_LOGO_PRESSED 0x00000040 +#define EFI_LEFT_LOGO_PRESSED 0x00000080 +#define EFI_MENU_KEY_PRESSED 0x00000100 +#define EFI_SYS_REQ_PRESSED 0x00000200 +#define EFI_SHIFT_STATE_VALID 0x80000000 + +#define EFI_TOGGLE_STATE_INVALID 0x00 +#define EFI_SCROLL_LOCK_ACTIVE 0x01 +#define EFI_NUM_LOCK_ACTIVE 0x02 +#define EFI_CAPS_LOCK_ACTIVE 0x04 +#define EFI_KEY_STATE_EXPOSED 0x40 +#define EFI_TOGGLE_STATE_VALID 0x80 + +struct efi_key_state { + u32 key_shift_state; + u8 key_toggle_state; +}; + +struct efi_key_data { + struct efi_input_key key; + struct efi_key_state key_state; +}; + +struct efi_simple_text_input_ex_protocol { + efi_status_t (EFIAPI *reset) ( + struct efi_simple_text_input_ex_protocol *this, + bool extended_verification); + efi_status_t (EFIAPI *read_key_stroke_ex) ( + struct efi_simple_text_input_ex_protocol *this, + struct efi_key_data *key_data); + struct efi_event *wait_for_key_ex; + efi_status_t (EFIAPI *set_state) ( + struct efi_simple_text_input_ex_protocol *this, + u8 key_toggle_state); + efi_status_t (EFIAPI *register_key_notify) ( + struct efi_simple_text_input_ex_protocol *this, + struct efi_key_data *key_data, + efi_status_t (EFIAPI *key_notify_function)( + struct efi_key_data *key_data), + void **notify_handle); + efi_status_t (EFIAPI *unregister_key_notify) ( + struct efi_simple_text_input_ex_protocol *this, + void *notification_handle); +}; + #define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ EFI_GUID(0x387477c1, 0x69c7, 0x11d2, \ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) -struct efi_simple_input_interface { - efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this, - bool ExtendedVerification); +struct efi_simple_text_input_protocol { + efi_status_t(EFIAPI *reset)(struct efi_simple_text_input_protocol *this, + bool extended_verification); efi_status_t(EFIAPI *read_key_stroke)( - struct efi_simple_input_interface *this, + struct efi_simple_text_input_protocol *this, struct efi_input_key *key); struct efi_event *wait_for_key; }; @@ -610,8 +657,7 @@ struct efi_simple_input_interface { EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) -struct efi_device_path_to_text_protocol -{ +struct efi_device_path_to_text_protocol { uint16_t *(EFIAPI *convert_device_node_to_text)( struct efi_device_path *device_node, bool display_only, @@ -659,8 +705,7 @@ struct efi_device_path_utilities_protocol { #define EFI_GOT_BGRA8 1 #define EFI_GOT_BITMASK 2 -struct efi_gop_mode_info -{ +struct efi_gop_mode_info { u32 version; u32 width; u32 height; @@ -669,8 +714,7 @@ struct efi_gop_mode_info u32 pixels_per_scanline; }; -struct efi_gop_mode -{ +struct efi_gop_mode { u32 max_mode; u32 mode; struct efi_gop_mode_info *info; @@ -691,8 +735,7 @@ struct efi_gop_pixel { #define EFI_BLT_BUFFER_TO_VIDEO 2 #define EFI_BLT_VIDEO_TO_VIDEO 3 -struct efi_gop -{ +struct efi_gop { efi_status_t (EFIAPI *query_mode)(struct efi_gop *this, u32 mode_number, efi_uintn_t *size_of_info, struct efi_gop_mode_info **info); @@ -762,8 +805,7 @@ struct efi_simple_network_mode { /* revision of the simple network protocol */ #define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000 -struct efi_simple_network -{ +struct efi_simple_network { u64 revision; efi_status_t (EFIAPI *start)(struct efi_simple_network *this); efi_status_t (EFIAPI *stop)(struct efi_simple_network *this); @@ -808,8 +850,7 @@ struct efi_pxe_packet { u8 packet[1472]; }; -struct efi_pxe_mode -{ +struct efi_pxe_mode { u8 started; u8 ipv6_available; u8 ipv6_supported; @@ -958,4 +999,24 @@ struct efi_driver_binding_protocol { efi_handle_t driver_binding_handle; }; +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ + EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ + 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49) +struct efi_unicode_collation_protocol { + efi_intn_t (EFIAPI *stri_coll)( + struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2); + bool (EFIAPI *metai_match)(struct efi_unicode_collation_protocol *this, + const u16 *string, const u16 *patter); + void (EFIAPI *str_lwr)(struct efi_unicode_collation_protocol + *this, u16 *string); + void (EFIAPI *str_upr)(struct efi_unicode_collation_protocol *this, + u16 *string); + void (EFIAPI *fat_to_str)(struct efi_unicode_collation_protocol *this, + efi_uintn_t fat_size, char *fat, u16 *string); + bool (EFIAPI *str_to_fat)(struct efi_unicode_collation_protocol *this, + const u16 *string, efi_uintn_t fat_size, + char *fat); + char *supported_languages; +}; + #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index f162adfff7..34e44c6677 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -13,13 +13,18 @@ #include <efi_api.h> /* No need for efi loader support in SPL */ -#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(EFI_LOADER) #include <linux/list.h> /* Maximum number of configuration tables */ #define EFI_MAX_CONFIGURATION_TABLES 16 +/* GUID used by the root node */ +#define U_BOOT_GUID \ + EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ + 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) + int __efi_entry_check(void); int __efi_exit_check(void); const char *__efi_nesting(void); @@ -92,15 +97,20 @@ extern struct efi_runtime_services efi_runtime_services; extern struct efi_system_table systab; extern struct efi_simple_text_output_protocol efi_con_out; -extern struct efi_simple_input_interface efi_con_in; +extern struct efi_simple_text_input_protocol efi_con_in; extern struct efi_console_control_protocol efi_console_control; extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; /* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; +/* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */ +extern const struct efi_unicode_collation_protocol + efi_unicode_collation_protocol; uint16_t *efi_dp_str(struct efi_device_path *dp); +/* GUID of the U-Boot root node */ +extern const efi_guid_t efi_u_boot_guid; /* GUID of the EFI_BLOCK_IO_PROTOCOL */ extern const efi_guid_t efi_block_io_guid; extern const efi_guid_t efi_global_variable_guid; @@ -127,6 +137,8 @@ extern const efi_guid_t efi_file_info_guid; /* GUID for file system information */ extern const efi_guid_t efi_file_system_info_guid; extern const efi_guid_t efi_guid_device_path_utilities_protocol; +/* GUID of the Unicode collation protocol */ +extern const efi_guid_t efi_guid_unicode_collation_protocol; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; @@ -172,6 +184,20 @@ struct efi_object { }; /** + * struct efi_loaded_image_obj - handle of a loaded image + */ +struct efi_loaded_image_obj { + /* Generic EFI object parent class data */ + struct efi_object parent; + void *reloc_base; + aligned_u64 reloc_size; + efi_status_t exit_status; + struct jmp_buf_data exit_jmp; + EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, + struct efi_system_table *st); +}; + +/** * struct efi_event * * @link: Link to list of all events @@ -205,6 +231,8 @@ extern struct list_head efi_obj_list; /* List of all events */ extern struct list_head efi_events; +/* Called by bootefi to initialize root node */ +efi_status_t efi_root_node_register(void); /* Called by bootefi to initialize runtime */ efi_status_t efi_initialize_system_table(void); /* Called by bootefi to make console interface available */ @@ -250,7 +278,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout); /* Called from places to check whether a timer expired */ void efi_timer_check(void); /* PE loader implementation */ -void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info); +void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, + struct efi_loaded_image *loaded_image_info); /* Called once to store the pristine gd pointer */ void efi_save_gd(void); /* Special case handler for error/abort that just tries to dtrt to get @@ -331,14 +360,12 @@ int efi_memory_init(void); /* Adds new or overrides configuration table entry to the system table */ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table); /* Sets up a loaded image */ -efi_status_t efi_setup_loaded_image( - struct efi_loaded_image *info, struct efi_object *obj, - struct efi_device_path *device_path, - struct efi_device_path *file_path); +efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, + struct efi_device_path *file_path, + struct efi_loaded_image_obj **handle_ptr, + struct efi_loaded_image **info_ptr); efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, void **buffer); -/* Print information about a loaded image */ -efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc); /* Print information about all loaded images */ void efi_print_image_infos(void *pc); @@ -397,7 +424,15 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path, (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \ ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype)) -/* Convert strings from normal C strings to uEFI strings */ +/** + * ascii2unicode() - convert ASCII string to UTF-16 string + * + * A zero terminated ASCII string is converted to a zero terminated UTF-16 + * string. The output buffer must be preassigned. + * + * @unicode: preassigned output buffer for UTF-16 string + * @ascii: ASCII string to be converted + */ static inline void ascii2unicode(u16 *unicode, const char *ascii) { while (*ascii) @@ -460,7 +495,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor, void *efi_bootmgr_load(struct efi_device_path **device_path, struct efi_device_path **file_path); -#else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */ +#else /* CONFIG_IS_ENABLED(EFI_LOADER) */ /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ #define __efi_runtime_data @@ -477,6 +512,6 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr, static inline void efi_net_set_dhcp_ack(void *pkt, int len) { } static inline void efi_print_image_infos(void *pc) { } -#endif /* CONFIG_EFI_LOADER && !CONFIG_SPL_BUILD */ +#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */ #endif /* _EFI_LOADER_H */ diff --git a/include/efi_selftest.h b/include/efi_selftest.h index d0a76d70ca..56beac305e 100644 --- a/include/efi_selftest.h +++ b/include/efi_selftest.h @@ -53,7 +53,7 @@ enum efi_test_phase { }; extern struct efi_simple_text_output_protocol *con_out; -extern struct efi_simple_input_interface *con_in; +extern struct efi_simple_text_input_protocol *con_in; /* * Exit the boot services. @@ -76,6 +76,22 @@ void efi_st_exit_boot_services(void); void efi_st_printc(int color, const char *fmt, ...) __attribute__ ((format (__printf__, 2, 3))); +/** + * efi_st_translate_char() - translate a unicode character to a string + * + * @code: unicode character + * Return: string + */ +u16 *efi_st_translate_char(u16 code); + +/** + * efi_st_translate_code() - translate a scan code to a human readable string + * + * @code: unicode character + * Return: string + */ +u16 *efi_st_translate_code(u16 code); + /* * Compare memory. * We cannot use lib/string.c due to different CFLAGS values. diff --git a/include/fat.h b/include/fat.h index 09e1423685..bc139f8c88 100644 --- a/include/fat.h +++ b/include/fat.h @@ -173,6 +173,8 @@ typedef struct { int fatbufnum; /* Used by get_fatent, init to -1 */ int rootdir_size; /* Size of root dir for non-FAT32 */ __u32 root_cluster; /* First cluster of root dir for FAT32 */ + u32 total_sect; /* Number of sectors */ + int fats; /* Number of FATs */ } fsdata; static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) @@ -201,5 +203,7 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, int fat_opendir(const char *filename, struct fs_dir_stream **dirsp); int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp); void fat_closedir(struct fs_dir_stream *dirs); +int fat_unlink(const char *filename); +int fat_mkdir(const char *dirname); void fat_close(void); #endif /* _FAT_H_ */ diff --git a/include/fs.h b/include/fs.h index 163da103b4..aa3604db8d 100644 --- a/include/fs.h +++ b/include/fs.h @@ -156,6 +156,24 @@ struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs); void fs_closedir(struct fs_dir_stream *dirs); /* + * fs_unlink - delete a file or directory + * + * If a given name is a directory, it will be deleted only if it's empty + * + * @filename: Name of file or directory to delete + * @return 0 on success, -1 on error conditions + */ +int fs_unlink(const char *filename); + +/* + * fs_mkdir - Create a directory + * + * @filename: Name of directory to create + * @return 0 on success, -1 on error conditions + */ +int fs_mkdir(const char *filename); + +/* * Common implementation for various filesystem commands, optionally limited * to a specific filesystem type via the fstype parameter. */ @@ -169,6 +187,10 @@ int file_exists(const char *dev_type, const char *dev_part, const char *file, int fstype); int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype); +int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype); +int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype); /* * Determine the UUID of the specified filesystem and print it. Optionally it is diff --git a/include/fs_loader.h b/include/fs_loader.h new file mode 100644 index 0000000000..0be4f17e63 --- /dev/null +++ b/include/fs_loader.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 Intel Corporation <www.intel.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ +#ifndef _FS_LOADER_H_ +#define _FS_LOADER_H_ + +#include <dm.h> + +/** + * struct firmware - A place for storing firmware and its attribute data. + * + * This holds information about a firmware and its content. + * + * @size: Size of a file + * @data: Buffer for file + * @priv: Firmware loader private fields + */ +struct firmware { + size_t size; + const u8 *data; + void *priv; +}; + +/** + * struct phandle_part - A place for storing phandle of node and its partition + * + * This holds information about a phandle of the block device, and its + * partition where the firmware would be loaded from. + * + * @phandle: Phandle of storage device node + * @partition: Partition of block device + */ +struct phandle_part { + u32 phandle; + u32 partition; +}; + +/** + * struct phandle_part - A place for storing all supported storage devices + * + * This holds information about all supported storage devices for driver use. + * + * @phandlepart: Attribute data for block device. + * @mtdpart: MTD partition for ubi partition. + * @ubivol: UBI volume-name for ubifsmount. + */ +struct device_platdata { + struct phandle_part phandlepart; + char *mtdpart; + char *ubivol; +}; + +/** + * release_firmware - Release the resource associated with a firmware image + * @firmware: Firmware resource to release + */ +void release_firmware(struct firmware *firmware); + +/** + * request_firmware_into_buf - Load firmware into a previously allocated buffer. + * @plat: Platform data such as storage and partition firmware loading from. + * @name: Name of firmware file. + * @buf: Address of buffer to load firmware into. + * @size: Size of buffer. + * @offset: Offset of a file for start reading into buffer. + * @firmwarep: Pointer to firmware image. + * + * The firmware is loaded directly into the buffer pointed to by @buf and + * the @firmwarep data member is pointed at @buf. + * + * Return: Size of total read, negative value when error. + */ +int request_firmware_into_buf(struct device_platdata *plat, + const char *name, + void *buf, size_t size, u32 offset, + struct firmware **firmwarep); +#endif diff --git a/include/os.h b/include/os.h index c8e0f52d30..5c797212c2 100644 --- a/include/os.h +++ b/include/os.h @@ -331,24 +331,7 @@ int os_spl_to_uboot(const char *fname); void os_localtime(struct rtc_time *rt); /** - * os_setjmp() - Call setjmp() - * - * Call the host system's setjmp() function. - * - * @jmp: Buffer to store current execution state - * @size: Size of buffer - * @return normal setjmp() value if OK, -ENOSPC if @size is too small - */ -int os_setjmp(ulong *jmp, int size); - -/** - * os_longjmp() - Call longjmp() - * - * Call the host system's longjmp() function. - * - * @jmp: Buffer where previous execution state was stored - * @ret: Value to pass to longjmp() + * os_abort() - Raise SIGABRT to exit sandbox (e.g. to debugger) */ -void os_longjmp(ulong *jmp, int ret); - +void os_abort(void); #endif diff --git a/include/spl.h b/include/spl.h index 7fad62c043..b42683c9e7 100644 --- a/include/spl.h +++ b/include/spl.h @@ -303,4 +303,13 @@ void board_return_to_bootrom(void); * the boot-payload */ void spl_perform_fixups(struct spl_image_info *spl_image); + +/* + * spl_get_load_buffer() - get buffer for loading partial image data + * + * Returns memory area which can be populated by partial image data, + * ie. uImage or fitImage header. + */ +struct image_header *spl_get_load_buffer(ssize_t offset, size_t size); + #endif diff --git a/include/test/suites.h b/include/test/suites.h index 071ab4063e..abb3a4b816 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -23,10 +23,11 @@ struct unit_test; int cmd_ut_category(const char *name, struct unit_test *tests, int n_ents, int argc, char * const argv[]); +int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); -int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #endif /* __TEST_SUITES_H__ */ diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h index 80acbcb148..0770228cd8 100644 --- a/include/ubi_uboot.h +++ b/include/ubi_uboot.h @@ -75,5 +75,7 @@ extern int ubi_volume_write(char *volume, void *buf, size_t size); extern int ubi_volume_read(char *volume, char *buf, size_t size); extern struct ubi_device *ubi_devices[]; +int cmd_ubifs_mount(char *vol_name); +int cmd_ubifs_umount(void); #endif diff --git a/include/w1-eeprom.h b/include/w1-eeprom.h new file mode 100644 index 0000000000..22337368b4 --- /dev/null +++ b/include/w1-eeprom.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co + * Copyright (c) 2018 Microchip Technology, Inc. + * + */ + +#ifndef __W1_EEPROM_H +#define __W1_EEPROM_H + +struct udevice; + +struct w1_eeprom_ops { + /* + * Reads a buff from the given EEPROM memory, starting at + * given offset and place the results into the given buffer. + * Should read given count of bytes. + * Should return 0 on success, and normal error.h on error + */ + int (*read_buf)(struct udevice *dev, unsigned int offset, + u8 *buf, unsigned int count); +}; + +int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset, + u8 *buf, unsigned int count); + +int w1_eeprom_dm_init(void); + +int w1_eeprom_register_new_device(u64 id); + +int w1_eeprom_get_id(struct udevice *dev, u64 *id); +#endif diff --git a/include/w1.h b/include/w1.h new file mode 100644 index 0000000000..399177a12e --- /dev/null +++ b/include/w1.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co + * + */ + +#ifndef __W1_H +#define __W1_H + +#include <dm.h> + +#define W1_FAMILY_DS24B33 0x23 +#define W1_FAMILY_DS2431 0x2d +#define W1_FAMILY_EEP_SANDBOX 0xfe + +struct w1_device { + u64 id; +}; + +struct w1_ops { + u8 (*read_byte)(struct udevice *dev); + bool (*reset)(struct udevice *dev); + u8 (*triplet)(struct udevice *dev, bool bdir); + void (*write_byte)(struct udevice *dev, u8 byte); +}; + +int w1_get_bus(int busnum, struct udevice **busp); +u8 w1_get_device_family(struct udevice *dev); + +int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count); +int w1_read_byte(struct udevice *dev); +int w1_reset_select(struct udevice *dev); +int w1_write_buf(struct udevice *dev, u8 *buf, unsigned int count); +int w1_write_byte(struct udevice *dev, u8 byte); + +#endif diff --git a/lib/Makefile b/lib/Makefile index 5f583aed37..f169644850 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -19,7 +19,12 @@ obj-$(CONFIG_ARCH_AT91) += at91/ obj-$(CONFIG_OPTEE) += optee/ obj-$(CONFIG_AES) += aes.o + +ifndef API_BUILD +ifneq ($(CONFIG_UT_UNICODE)$(CONFIG_EFI_LOADER),) obj-y += charset.o +endif +endif obj-$(CONFIG_USB_TTY) += circbuf.o obj-y += crc7.o obj-y += crc8.o diff --git a/lib/charset.c b/lib/charset.c index cd186a5a5a..0cede9b60b 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -5,44 +5,343 @@ * Copyright (c) 2017 Rob Clark */ +#include <common.h> #include <charset.h> +#include <capitalization.h> #include <malloc.h> -/* - * utf8/utf16 conversion mostly lifted from grub +static struct capitalization_table capitalization_table[] = +#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION + UNICODE_CAPITALIZATION_TABLE; +#elif CONFIG_FAT_DEFAULT_CODEPAGE == 1250 + CP1250_CAPITALIZATION_TABLE; +#else + CP437_CAPITALIZATION_TABLE; +#endif + +/** + * get_code() - read Unicode code point from UTF-8 stream + * + * @read_u8: - stream reader + * @src: - string buffer passed to stream reader, optional + * Return: - Unicode code point + */ +static int get_code(u8 (*read_u8)(void *data), void *data) +{ + s32 ch = 0; + + ch = read_u8(data); + if (!ch) + return 0; + if (ch >= 0xc2 && ch <= 0xf4) { + int code = 0; + + if (ch >= 0xe0) { + if (ch >= 0xf0) { + /* 0xf0 - 0xf4 */ + ch &= 0x07; + code = ch << 18; + ch = read_u8(data); + if (ch < 0x80 || ch > 0xbf) + goto error; + ch &= 0x3f; + } else { + /* 0xe0 - 0xef */ + ch &= 0x0f; + } + code += ch << 12; + if ((code >= 0xD800 && code <= 0xDFFF) || + code >= 0x110000) + goto error; + ch = read_u8(data); + if (ch < 0x80 || ch > 0xbf) + goto error; + } + /* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */ + ch &= 0x3f; + code += ch << 6; + ch = read_u8(data); + if (ch < 0x80 || ch > 0xbf) + goto error; + ch &= 0x3f; + ch += code; + } else if (ch >= 0x80) { + goto error; + } + return ch; +error: + return '?'; +} + +/** + * read_string() - read byte from character string + * + * @data: - pointer to string + * Return: - byte read + * + * The string pointer is incremented if it does not point to '\0'. */ +static u8 read_string(void *data) -size_t utf16_strlen(const uint16_t *in) { - size_t i; - for (i = 0; in[i]; i++); - return i; + const char **src = (const char **)data; + u8 c; + + if (!src || !*src || !**src) + return 0; + c = **src; + ++*src; + return c; } -size_t utf16_strnlen(const uint16_t *in, size_t count) +/** + * read_console() - read byte from console + * + * @src - not used, needed to match interface + * Return: - byte read + */ +static u8 read_console(void *data) { - size_t i; - for (i = 0; count-- && in[i]; i++); - return i; + return getc(); +} + +int console_read_unicode(s32 *code) +{ + if (!tstc()) { + /* No input available */ + return 1; + } + + /* Read Unicode code */ + *code = get_code(read_console, NULL); + return 0; +} + +s32 utf8_get(const char **src) +{ + return get_code(read_string, src); +} + +int utf8_put(s32 code, char **dst) +{ + if (!dst || !*dst) + return -1; + if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000) + return -1; + if (code <= 0x007F) { + **dst = code; + } else { + if (code <= 0x07FF) { + **dst = code >> 6 | 0xC0; + } else { + if (code < 0x10000) { + **dst = code >> 12 | 0xE0; + } else { + **dst = code >> 18 | 0xF0; + ++*dst; + **dst = (code >> 12 & 0x3F) | 0x80; + } + ++*dst; + **dst = (code >> 6 & 0x3F) | 0x80; + } + ++*dst; + **dst = (code & 0x3F) | 0x80; + } + ++*dst; + return 0; +} + +size_t utf8_utf16_strnlen(const char *src, size_t count) +{ + size_t len = 0; + + for (; *src && count; --count) { + s32 code = utf8_get(&src); + + if (!code) + break; + if (code < 0) { + /* Reserve space for a replacement character */ + len += 1; + } else if (code < 0x10000) { + len += 1; + } else { + len += 2; + } + } + return len; +} + +int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count) +{ + if (!src || !dst || !*dst) + return -1; + + for (; count && *src; --count) { + s32 code = utf8_get(&src); + + if (code < 0) + code = '?'; + utf16_put(code, dst); + } + **dst = 0; + return 0; +} + +s32 utf16_get(const u16 **src) +{ + s32 code, code2; + + if (!src || !*src) + return -1; + if (!**src) + return 0; + code = **src; + ++*src; + if (code >= 0xDC00 && code <= 0xDFFF) + return -1; + if (code >= 0xD800 && code <= 0xDBFF) { + if (!**src) + return -1; + code &= 0x3ff; + code <<= 10; + code += 0x10000; + code2 = **src; + ++*src; + if (code2 <= 0xDC00 || code2 >= 0xDFFF) + return -1; + code2 &= 0x3ff; + code += code2; + } + return code; +} + +int utf16_put(s32 code, u16 **dst) +{ + if (!dst || !*dst) + return -1; + if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000) + return -1; + if (code < 0x10000) { + **dst = code; + } else { + code -= 0x10000; + **dst = code >> 10 | 0xD800; + ++*dst; + **dst = (code & 0x3ff) | 0xDC00; + } + ++*dst; + return 0; +} + +size_t utf16_strnlen(const u16 *src, size_t count) +{ + size_t len = 0; + + for (; *src && count; --count) { + s32 code = utf16_get(&src); + + if (!code) + break; + /* + * In case of an illegal sequence still reserve space for a + * replacement character. + */ + ++len; + } + return len; +} + +size_t utf16_utf8_strnlen(const u16 *src, size_t count) +{ + size_t len = 0; + + for (; *src && count; --count) { + s32 code = utf16_get(&src); + + if (!code) + break; + if (code < 0) + /* Reserve space for a replacement character */ + len += 1; + else if (code < 0x80) + len += 1; + else if (code < 0x800) + len += 2; + else if (code < 0x10000) + len += 3; + else + len += 4; + } + return len; } -uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src) +int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count) { - uint16_t *tmp = dest; + if (!src || !dst || !*dst) + return -1; - while ((*dest++ = *src++) != '\0') - /* nothing */; - return tmp; + for (; count && *src; --count) { + s32 code = utf16_get(&src); + if (code < 0) + code = '?'; + utf8_put(code, dst); + } + **dst = 0; + return 0; } -uint16_t *utf16_strdup(const uint16_t *s) +s32 utf_to_lower(const s32 code) { - uint16_t *new; - if (!s || !(new = malloc((utf16_strlen(s) + 1) * 2))) - return NULL; - utf16_strcpy(new, s); - return new; + struct capitalization_table *pos = capitalization_table; + s32 ret = code; + + if (code <= 0x7f) { + if (code >= 'A' && code <= 'Z') + ret += 0x20; + return ret; + } + for (; pos->upper; ++pos) { + if (pos->upper == code) { + ret = pos->lower; + break; + } + } + return ret; +} + +s32 utf_to_upper(const s32 code) +{ + struct capitalization_table *pos = capitalization_table; + s32 ret = code; + + if (code <= 0x7f) { + if (code >= 'a' && code <= 'z') + ret -= 0x20; + return ret; + } + for (; pos->lower; ++pos) { + if (pos->lower == code) { + ret = pos->upper; + break; + } + } + return ret; +} + +size_t u16_strlen(const u16 *in) +{ + size_t i; + for (i = 0; in[i]; i++); + return i; +} + +size_t u16_strnlen(const u16 *in, size_t count) +{ + size_t i; + for (i = 0; count-- && in[i]; i++); + return i; } /* Convert UTF-16 to UTF-8. */ @@ -97,59 +396,3 @@ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size) return dest; } - -uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size) -{ - while (size--) { - int extension_bytes; - uint32_t code; - - extension_bytes = 0; - if (*src <= 0x7f) { - code = *src++; - /* Exit on zero byte */ - if (!code) - size = 0; - } else if (*src <= 0xbf) { - /* Illegal code */ - code = '?'; - } else if (*src <= 0xdf) { - code = *src++ & 0x1f; - extension_bytes = 1; - } else if (*src <= 0xef) { - code = *src++ & 0x0f; - extension_bytes = 2; - } else if (*src <= 0xf7) { - code = *src++ & 0x07; - extension_bytes = 3; - } else { - /* Illegal code */ - code = '?'; - } - - for (; extension_bytes && size; --size, --extension_bytes) { - if ((*src & 0xc0) == 0x80) { - code <<= 6; - code |= *src++ & 0x3f; - } else { - /* Illegal code */ - code = '?'; - ++src; - --size; - break; - } - } - - if (code < 0x10000) { - *dest++ = code; - } else { - /* - * Simplified expression for - * (((code - 0x10000) >> 10) & 0x3ff) | 0xd800 - */ - *dest++ = (code >> 10) + 0xd7c0; - *dest++ = (code & 0x3ff) | 0xdc00; - } - } - return dest; -} diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index b484aba072..bb86ffd399 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -19,11 +19,13 @@ #include <efi_driver.h> -/* - * Check node type. We do not support partitions as controller handles. +/** + * check_node_type() - check node type + * + * We do not support partitions as controller handles. * - * @handle handle to be checked - * @return status code + * @handle: handle to be checked + * Return: status code */ static efi_status_t check_node_type(efi_handle_t handle) { @@ -44,13 +46,13 @@ static efi_status_t check_node_type(efi_handle_t handle) return ret; } -/* - * Check if the driver supports the controller. +/** + * efi_uc_supported() - check if the driver supports the controller * - * @this driver binding protocol - * @controller_handle handle of the controller - * @remaining_device_path path specifying the child controller - * @return status code + * @this: driver binding protocol + * @controller_handle: handle of the controller + * @remaining_device_path: path specifying the child controller + * Return: status code */ static efi_status_t EFIAPI efi_uc_supported( struct efi_driver_binding_protocol *this, @@ -92,13 +94,13 @@ out: return EFI_EXIT(ret); } -/* - * Create child controllers and attach driver. +/** + * efi_uc_start() - create child controllers and attach driver * - * @this driver binding protocol - * @controller_handle handle of the controller - * @remaining_device_path path specifying the child controller - * @return status code + * @this: driver binding protocol + * @controller_handle: handle of the controller + * @remaining_device_path: path specifying the child controller + * Return: status code */ static efi_status_t EFIAPI efi_uc_start( struct efi_driver_binding_protocol *this, @@ -146,12 +148,13 @@ out: return EFI_EXIT(ret); } -/* - * Remove a single child controller from the parent controller. +/** + * disconnect_child() - remove a single child controller from the parent + * controller * - * @controller_handle parent controller - * @child_handle child controller - * @return status code + * @controller_handle: parent controller + * @child_handle: child controller + * Return: status code */ static efi_status_t disconnect_child(efi_handle_t controller_handle, efi_handle_t child_handle) @@ -176,14 +179,14 @@ static efi_status_t disconnect_child(efi_handle_t controller_handle, return ret; } -/* - * Remove child controllers and disconnect the controller. +/** + * efi_uc_stop() - Remove child controllers and disconnect the controller * - * @this driver binding protocol - * @controller_handle handle of the controller - * @number_of_children number of child controllers to remove - * @child_handle_buffer handles of the child controllers to remove - * @return status code + * @this: driver binding protocol + * @controller_handle: handle of the controller + * @number_of_children: number of child controllers to remove + * @child_handle_buffer: handles of the child controllers to remove + * Return: status code */ static efi_status_t EFIAPI efi_uc_stop( struct efi_driver_binding_protocol *this, @@ -241,6 +244,12 @@ out: return EFI_EXIT(ret); } +/** + * efi_add_driver() - add driver + * + * @drv: driver to add + * Return: status code + */ static efi_status_t efi_add_driver(struct driver *drv) { efi_status_t ret; @@ -280,11 +289,12 @@ out: return ret; } -/* - * Initialize the EFI drivers. - * Called by board_init_r(). +/** + * efi_driver_init() - initialize the EFI drivers * - * @return 0 = success, any other value will stop further execution + * Called by efi_init_obj_list(). + * + * Return: 0 = success, any other value will stop further execution */ efi_status_t efi_driver_init(void) { @@ -309,12 +319,24 @@ efi_status_t efi_driver_init(void) return ret; } +/** + * efi_uc_init() - initialize the EFI uclass + * + * @class: the EFI uclass + * Return: 0 = success + */ static int efi_uc_init(struct uclass *class) { printf("EFI: Initializing UCLASS_EFI\n"); return 0; } +/** + * efi_uc_destroy() - destroy the EFI uclass + * + * @class: the EFI uclass + * Return: 0 = success + */ static int efi_uc_destroy(struct uclass *class) { printf("Destroying UCLASS_EFI\n"); diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ce6a09f0b4..b921ea8821 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -1,6 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" - depends on (ARM || X86 || RISCV) && OF_LIBFDT + depends on (ARM || X86 || RISCV || SANDBOX) && OF_LIBFDT # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB @@ -15,6 +15,16 @@ config EFI_LOADER interfaces to a loaded EFI application, enabling it to reuse U-Boot's device drivers. +config EFI_UNICODE_CAPITALIZATION + bool "Support Unicode capitalization" + depends on EFI_LOADER + default y + help + Select this option to enable correct handling of the capitalization of + Unicode codepoints in the range 0x0000-0xffff. If this option is not + set, only the the correct handling of the letters of the codepage + used by the FAT file system is ensured. + config EFI_LOADER_BOUNCE_BUFFER bool "EFI Applications use bounce buffers for DMA operations" depends on EFI_LOADER && ARM64 diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 1ffbf52a89..6703435947 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -17,9 +17,19 @@ always += helloworld.efi endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o -obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o -obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o efi_file.o efi_variable.o efi_bootmgr.o +obj-y += efi_bootmgr.o +obj-y += efi_boottime.o +obj-y += efi_console.o +obj-y += efi_device_path.o +obj-y += efi_device_path_to_text.o +obj-y += efi_device_path_utilities.o +obj-y += efi_file.o +obj-y += efi_image_loader.o +obj-y += efi_memory.o +obj-y += efi_root_node.o +obj-y += efi_runtime.o +obj-y += efi_unicode_collation.o +obj-y += efi_variable.o obj-y += efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 853358ab93..0c5764db12 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -60,7 +60,7 @@ static void parse_load_option(struct load_option *lo, void *ptr) ptr += sizeof(u16); lo->label = ptr; - ptr += (utf16_strlen(lo->label) + 1) * 2; + ptr += (u16_strlen(lo->label) + 1) * 2; lo->file_path = ptr; ptr += lo->file_path_length; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index ca61e1ad41..97eb19cd14 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -26,14 +26,6 @@ LIST_HEAD(efi_obj_list); /* List of all events */ LIST_HEAD(efi_events); -/* - * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) - * we need to do trickery with caches. Since we don't want to break the EFI - * aware boot path, only apply hacks when loading exiting directly (breaking - * direct Linux EFI booting along the way - oh well). - */ -static bool efi_is_direct_boot = true; - #ifdef CONFIG_ARM /* * The "gd" pointer lives in a register on ARM and AArch64 that we declare @@ -105,8 +97,8 @@ void efi_save_gd(void) /* * Special case handler for error/abort that just forces things back to u-boot - * world so we can dump out an abort msg, without any care about returning back - * to UEFI world. + * world so we can dump out an abort message, without any care about returning + * back to UEFI world. */ void efi_restore_gd(void) { @@ -183,7 +175,7 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl) * is_valid_tpl() - check if the task priority level is valid * * @tpl: TPL level to check - * ReturnValue: status code + * Return: status code */ efi_status_t is_valid_tpl(efi_uintn_t tpl) { @@ -626,7 +618,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, evt->notify_function = notify_function; evt->notify_context = notify_context; evt->group = group; - /* Disable timers on bootup */ + /* Disable timers on boot up */ evt->trigger_next = -1ULL; evt->is_queued = false; evt->is_signaled = false; @@ -732,7 +724,7 @@ void efi_timer_check(void) * efi_set_timer() - set the trigger time for a timer event or stop the event * @event: event for which the timer is set * @type: type of the timer - * @trigger_time: trigger period in multiples of 100ns + * @trigger_time: trigger period in multiples of 100 ns * * This is the function for internal usage in U-Boot. For the API function * implementing the SetTimer service see efi_set_timer_ext. @@ -747,8 +739,8 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, return EFI_INVALID_PARAMETER; /* - * The parameter defines a multiple of 100ns. - * We use multiples of 1000ns. So divide by 10. + * The parameter defines a multiple of 100 ns. + * We use multiples of 1000 ns. So divide by 10. */ do_div(trigger_time, 10); @@ -774,7 +766,7 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, * event * @event: event for which the timer is set * @type: type of the timer - * @trigger_time: trigger period in multiples of 100ns + * @trigger_time: trigger period in multiples of 100 ns * * This function implements the SetTimer service. * @@ -1061,7 +1053,7 @@ out: /** * efi_get_drivers() - get all drivers associated to a controller * @efiobj: handle of the controller - * @protocol: protocol guid (optional) + * @protocol: protocol GUID (optional) * @number_of_drivers: number of child controllers * @driver_handle_buffer: handles of the the drivers * @@ -1126,7 +1118,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj, /** * efi_disconnect_all_drivers() - disconnect all drivers from a controller * @efiobj: handle of the controller - * @protocol: protocol guid (optional) + * @protocol: protocol GUID (optional) * @child_handle: handle of the child to destroy * * This function implements the DisconnectController service. @@ -1408,7 +1400,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, if (!guid) return EFI_INVALID_PARAMETER; - /* Check for guid override */ + /* Check for GUID override */ for (i = 0; i < systab.nr_tables; i++) { if (!guidcmp(guid, &systab.tables[i].guid)) { if (table) @@ -1432,7 +1424,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, systab.nr_tables = i + 1; out: - /* systab.nr_tables may have changed. So we need to update the crc32 */ + /* systab.nr_tables may have changed. So we need to update the CRC32 */ efi_update_table_header_crc32(&systab.hdr); /* Notify that the configuration table was changed */ @@ -1478,20 +1470,35 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, * * Return: status code */ -efi_status_t efi_setup_loaded_image( - struct efi_loaded_image *info, struct efi_object *obj, - struct efi_device_path *device_path, - struct efi_device_path *file_path) +efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, + struct efi_device_path *file_path, + struct efi_loaded_image_obj **handle_ptr, + struct efi_loaded_image **info_ptr) { efi_status_t ret; + struct efi_loaded_image *info; + struct efi_loaded_image_obj *obj; + + info = calloc(1, sizeof(*info)); + if (!info) + return EFI_OUT_OF_RESOURCES; + obj = calloc(1, sizeof(*obj)); + if (!obj) { + free(info); + return EFI_OUT_OF_RESOURCES; + } /* Add internal object to object list */ - efi_add_handle(obj); - /* efi_exit() assumes that the handle points to the info */ - obj->handle = info; + efi_add_handle(&obj->parent); + + if (info_ptr) + *info_ptr = info; + if (handle_ptr) + *handle_ptr = obj; info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; info->file_path = file_path; + info->system_table = &systab; if (device_path) { info->device_handle = efi_dp_find_obj(device_path, NULL); @@ -1499,8 +1506,8 @@ efi_status_t efi_setup_loaded_image( * When asking for the device path interface, return * bootefi_device_path */ - ret = efi_add_protocol(obj->handle, &efi_guid_device_path, - device_path); + ret = efi_add_protocol(obj->parent.handle, + &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto failure; } @@ -1509,19 +1516,8 @@ efi_status_t efi_setup_loaded_image( * When asking for the loaded_image interface, just * return handle which points to loaded_image_info */ - ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info); - if (ret != EFI_SUCCESS) - goto failure; - - ret = efi_add_protocol(obj->handle, - &efi_guid_device_path_to_text_protocol, - (void *)&efi_device_path_to_text); - if (ret != EFI_SUCCESS) - goto failure; - - ret = efi_add_protocol(obj->handle, - &efi_guid_device_path_utilities_protocol, - (void *)&efi_device_path_utilities); + ret = efi_add_protocol(obj->parent.handle, + &efi_guid_loaded_image, info); if (ret != EFI_SUCCESS) goto failure; @@ -1604,7 +1600,8 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, efi_handle_t *image_handle) { struct efi_loaded_image *info; - struct efi_object *obj; + struct efi_loaded_image_obj **image_obj = + (struct efi_loaded_image_obj **)image_handle; efi_status_t ret; EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, @@ -1620,18 +1617,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, goto error; } - info = calloc(1, sizeof(*info)); - if (!info) { - ret = EFI_OUT_OF_RESOURCES; - goto error; - } - obj = calloc(1, sizeof(*obj)); - if (!obj) { - free(info); - ret = EFI_OUT_OF_RESOURCES; - goto error; - } - if (!source_buffer) { struct efi_device_path *dp, *fp; @@ -1643,35 +1628,35 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, * file parts: */ efi_dp_split_file_path(file_path, &dp, &fp); - ret = efi_setup_loaded_image(info, obj, dp, fp); + ret = efi_setup_loaded_image(dp, fp, image_obj, &info); if (ret != EFI_SUCCESS) goto failure; } else { - /* In this case, file_path is the "device" path, ie. + /* In this case, file_path is the "device" path, i.e. * something like a HARDWARE_DEVICE:MEMORY_MAPPED */ - ret = efi_setup_loaded_image(info, obj, file_path, NULL); + ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info); if (ret != EFI_SUCCESS) - goto failure; + goto error; } - info->reserved = efi_load_pe(source_buffer, info); - if (!info->reserved) { + (*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info); + if (!(*image_obj)->entry) { ret = EFI_UNSUPPORTED; goto failure; } info->system_table = &systab; info->parent_handle = parent_image; - *image_handle = obj->handle; return EFI_EXIT(EFI_SUCCESS); failure: + efi_delete_handle(*image_handle); + *image_handle = NULL; free(info); - efi_delete_handle(obj); error: return EFI_EXIT(ret); } /** - * efi_start_image() - dall the entry point of an image + * efi_start_image() - call the entry point of an image * @image_handle: handle of the image * @exit_data_size: size of the buffer * @exit_data: buffer to receive the exit data of the called image @@ -1687,18 +1672,14 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, unsigned long *exit_data_size, s16 **exit_data) { - EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, - struct efi_system_table *st); - struct efi_loaded_image *info = image_handle; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; efi_status_t ret; EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); - entry = info->reserved; - - efi_is_direct_boot = false; /* call the image! */ - if (setjmp(&info->exit_jmp)) { + if (setjmp(&image_obj->exit_jmp)) { /* * We called the entry point of the child image with EFI_CALL * in the lines below. The child image called the Exit() boot @@ -1721,16 +1702,16 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, assert(__efi_entry_check()); debug("%sEFI: %lu returned by started image\n", __efi_nesting_dec(), - (unsigned long)((uintptr_t)info->exit_status & + (unsigned long)((uintptr_t)image_obj->exit_status & ~EFI_ERROR_MASK)); - return EFI_EXIT(info->exit_status); + return EFI_EXIT(image_obj->exit_status); } - ret = EFI_CALL(entry(image_handle, &systab)); + ret = EFI_CALL(image_obj->entry(image_handle, &systab)); /* * Usually UEFI applications call Exit() instead of returning. - * But because the world doesn not consist of ponies and unicorns, + * But because the world doesn't consist of ponies and unicorns, * we're happy to emulate that behavior on behalf of a payload * that forgot. */ @@ -1757,17 +1738,11 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, int16_t *exit_data) { /* - * We require that the handle points to the original loaded - * image protocol interface. - * - * For getting the longjmp address this is safer than locating - * the protocol because the protocol may have been reinstalled - * pointing to another memory location. - * * TODO: We should call the unload procedure of the loaded * image protocol. */ - struct efi_loaded_image *loaded_image_info = (void *)image_handle; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status, exit_data_size, exit_data); @@ -1781,8 +1756,8 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, */ efi_restore_gd(); - loaded_image_info->exit_status = exit_status; - longjmp(&loaded_image_info->exit_jmp, 1); + image_obj->exit_status = exit_status; + longjmp(&image_obj->exit_jmp, 1); panic("EFI application exited"); } @@ -1811,21 +1786,6 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) } /** - * efi_exit_caches() - fix up caches for EFI payloads if necessary - */ -static void efi_exit_caches(void) -{ -#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64) - /* - * Grub on 32bit ARM needs to have caches disabled before jumping into - * a zImage, but does not know of all cache layers. Give it a hand. - */ - if (efi_is_direct_boot) - cleanup_before_linux(); -#endif -} - -/** * efi_exit_boot_services() - stop all boot services * @image_handle: handle of the loaded image * @map_key: key of the memory map @@ -1874,17 +1834,14 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, } } - /* TODO Should persist EFI variables here */ + /* TODO: Should persist EFI variables here */ board_quiesce_devices(); - /* Fix up caches for EFI payloads if necessary */ - efi_exit_caches(); - /* This stops all lingering devices */ bootm_disable_interrupts(); - /* Disable boottime services */ + /* Disable boot time services */ systab.con_in_handle = NULL; systab.con_in = NULL; systab.con_out_handle = NULL; @@ -2118,7 +2075,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle( ++*protocol_buffer_count; } - /* Copy guids */ + /* Copy GUIDs */ if (*protocol_buffer_count) { size_t j = 0; @@ -2709,7 +2666,7 @@ static efi_status_t efi_bind_controller( * efi_connect_single_controller() - connect a single driver to a controller * @controller_handle: controller * @driver_image_handle: driver - * @remain_device_path: remainting path + * @remain_device_path: remaining path * * Return: status code */ @@ -2790,7 +2747,7 @@ static efi_status_t efi_connect_single_controller( * details. * * First all driver binding protocol handles are tried for binding drivers. - * Afterwards all handles that have openened a protocol of the controller + * Afterwards all handles that have opened a protocol of the controller * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers. * * Return: status code @@ -3123,7 +3080,7 @@ struct efi_system_table __efi_runtime_data systab = { /** * efi_initialize_system_table() - Initialize system table * - * Return Value: status code + * Return: status code */ efi_status_t efi_initialize_system_table(void) { @@ -3135,7 +3092,7 @@ efi_status_t efi_initialize_system_table(void) sizeof(struct efi_configuration_table), (void **)&systab.tables); - /* Set crc32 field in table headers */ + /* Set CRC32 field in table headers */ efi_update_table_header_crc32(&systab.hdr); efi_update_table_header_crc32(&efi_runtime_services.hdr); efi_update_table_header_crc32(&efi_boot_services.hdr); diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index b487288785..7ecdbb1666 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -42,10 +42,12 @@ static struct cout_mode efi_cout_modes[] = { }, }; -const efi_guid_t efi_guid_text_output_protocol = - EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID; +const efi_guid_t efi_guid_text_input_ex_protocol = + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; const efi_guid_t efi_guid_text_input_protocol = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID; +const efi_guid_t efi_guid_text_output_protocol = + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID; #define cESC '\x1b' #define ESC "\x1b" @@ -111,23 +113,28 @@ static efi_status_t EFIAPI efi_cout_output_string( { struct simple_text_output_mode *con = &efi_con_mode; struct cout_mode *mode = &efi_cout_modes[con->mode]; - - EFI_ENTRY("%p, %p", this, string); - - unsigned int n16 = utf16_strlen(string); - char buf[MAX_UTF8_PER_UTF16 * n16 + 1]; + char *buf, *pos; u16 *p; + efi_status_t ret = EFI_SUCCESS; - *utf16_to_utf8((u8 *)buf, string, n16) = '\0'; + EFI_ENTRY("%p, %p", this, string); + buf = malloc(utf16_utf8_strlen(string) + 1); + if (!buf) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + pos = buf; + utf16_utf8_strcpy(&pos, string); fputs(stdout, buf); + free(buf); /* * Update the cursor position. * * The UEFI spec provides advance rules for U+0000, U+0008, U+000A, * and U000D. All other characters, including control characters - * U+0007 (bel) and U+0009 (tab), have to increase the column by one. + * U+0007 (BEL) and U+0009 (TAB), have to increase the column by one. */ for (p = string; *p; ++p) { switch (*p) { @@ -158,7 +165,8 @@ static efi_status_t EFIAPI efi_cout_output_string( con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1); } - return EFI_EXIT(EFI_SUCCESS); +out: + return EFI_EXIT(ret); } static efi_status_t EFIAPI efi_cout_test_string( @@ -177,32 +185,56 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols) return (mode->rows == rows) && (mode->columns == cols); } +/** + * query_console_serial() - query console size + * + * @rows pointer to return number of rows + * @columns pointer to return number of columns + * Returns 0 on success + */ static int query_console_serial(int *rows, int *cols) { - /* Ask the terminal about its size */ - int n[3]; + int ret = 0; + int n[2]; u64 timeout; /* Empty input buffer */ while (tstc()) getc(); - printf(ESC"[18t"); + /* + * Not all terminals understand CSI [18t for querying the console size. + * We should adhere to escape sequences documented in the console_codes + * manpage and the ECMA-48 standard. + * + * So here we follow a different approach. We position the cursor to the + * bottom right and query its position. Before leaving the function we + * restore the original cursor position. + */ + printf(ESC "7" /* Save cursor position */ + ESC "[r" /* Set scrolling region to full window */ + ESC "[999;999H" /* Move to bottom right corner */ + ESC "[6n"); /* Query cursor position */ - /* Check if we have a terminal that understands */ + /* Allow up to one second for a response */ timeout = timer_get_us() + 1000000; while (!tstc()) - if (timer_get_us() > timeout) - return -1; - - /* Read {depth,rows,cols} */ - if (term_read_reply(n, 3, 't')) - return -1; + if (timer_get_us() > timeout) { + ret = -1; + goto out; + } - *cols = n[2]; - *rows = n[1]; + /* Read {rows,cols} */ + if (term_read_reply(n, 2, 'R')) { + ret = 1; + goto out; + } - return 0; + *cols = n[1]; + *rows = n[0]; +out: + printf(ESC "8"); /* Restore cursor position */ + return ret; } /* @@ -298,8 +330,8 @@ static const struct { { 36, 46 }, /* 3: cyan */ { 31, 41 }, /* 4: red */ { 35, 45 }, /* 5: magenta */ - { 33, 43 }, /* 6: brown, map to yellow as edk2 does*/ - { 37, 47 }, /* 7: light grey, map to white */ + { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/ + { 37, 47 }, /* 7: light gray, map to white */ }; /* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */ @@ -351,13 +383,31 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position( struct efi_simple_text_output_protocol *this, unsigned long column, unsigned long row) { + efi_status_t ret = EFI_SUCCESS; + struct simple_text_output_mode *con = &efi_con_mode; + struct cout_mode *mode = &efi_cout_modes[con->mode]; + EFI_ENTRY("%p, %ld, %ld", this, column, row); - printf(ESC"[%d;%df", (int)row, (int)column); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + if (row >= mode->rows || column >= mode->columns) { + ret = EFI_UNSUPPORTED; + goto out; + } + + /* + * Set cursor position by sending CSI H. + * EFI origin is [0, 0], terminal origin is [1, 1]. + */ + printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1); efi_con_mode.cursor_column = column; efi_con_mode.cursor_row = row; - - return EFI_EXIT(EFI_SUCCESS); +out: + return EFI_EXIT(ret); } static efi_status_t EFIAPI efi_cout_enable_cursor( @@ -384,29 +434,58 @@ struct efi_simple_text_output_protocol efi_con_out = { .mode = (void*)&efi_con_mode, }; -static efi_status_t EFIAPI efi_cin_reset( - struct efi_simple_input_interface *this, - bool extended_verification) -{ - EFI_ENTRY("%p, %d", this, extended_verification); +/** + * struct efi_cin_notify_function - registered console input notify function + * + * @link: link to list + * @data: key to notify + * @function: function to call + */ +struct efi_cin_notify_function { + struct list_head link; + struct efi_key_data key; + efi_status_t (EFIAPI *function) + (struct efi_key_data *key_data); +}; - /* Empty input buffer */ - while (tstc()) - getc(); +static bool key_available; +static struct efi_key_data next_key; +static LIST_HEAD(cin_notify_functions); - return EFI_EXIT(EFI_SUCCESS); +/** + * set_shift_mask() - set shift mask + * + * @mod: Xterm shift mask + */ +void set_shift_mask(int mod, struct efi_key_state *key_state) +{ + key_state->key_shift_state = EFI_SHIFT_STATE_VALID; + if (mod) { + --mod; + if (mod & 1) + key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED; + if (mod & 2) + key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED; + if (mod & 4) + key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED; + if (mod & 8) + key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED; + } else { + key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED; + } } -/* - * Analyze modifiers (shift, alt, ctrl) for function keys. +/** + * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys + * * This gets called when we have already parsed CSI. * * @modifiers: bitmask (shift, alt, ctrl) * @return: the unmodified code */ -static char skip_modifiers(int *modifiers) +static int analyze_modifiers(struct efi_key_state *key_state) { - char c, mod = 0, ret = 0; + int c, mod = 0, ret = 0; c = getc(); @@ -430,37 +509,38 @@ static char skip_modifiers(int *modifiers) } } out: - if (mod) - --mod; - if (modifiers) - *modifiers = mod; + set_shift_mask(mod, key_state); if (!ret) ret = c; return ret; } -static efi_status_t EFIAPI efi_cin_read_key_stroke( - struct efi_simple_input_interface *this, - struct efi_input_key *key) +/** + * efi_cin_read_key() - read a key from the console input + * + * @key: - key received + * Return: - status code + */ +static efi_status_t efi_cin_read_key(struct efi_key_data *key) { struct efi_input_key pressed_key = { .scan_code = 0, .unicode_char = 0, }; - char ch; + s32 ch; - EFI_ENTRY("%p, %p", this, key); + if (console_read_unicode(&ch)) + return EFI_NOT_READY; - /* We don't do interrupts, so check for timers cooperatively */ - efi_timer_check(); + key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID; + key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID; - if (!tstc()) { - /* No key pressed */ - return EFI_EXIT(EFI_NOT_READY); - } + /* We do not support multi-word codes */ + if (ch >= 0x10000) + ch = '?'; - ch = getc(); - if (ch == cESC) { + switch (ch) { + case 0x1b: /* * Xterm Control Sequences * https://www.xfree86.org/4.8.0/ctlseqs.html @@ -472,14 +552,13 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke( break; case 'O': /* F1 - F4 */ ch = getc(); - /* skip modifiers */ - if (ch <= '9') + /* consider modifiers */ + if (ch < 'P') { + set_shift_mask(ch - '0', &key->key_state); ch = getc(); + } pressed_key.scan_code = ch - 'P' + 11; break; - case 'a'...'z': - ch = ch - 'a'; - break; case '[': ch = getc(); switch (ch) { @@ -493,7 +572,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke( pressed_key.scan_code = 5; break; case '1': - ch = skip_modifiers(NULL); + ch = analyze_modifiers(&key->key_state); switch (ch) { case '1'...'5': /* F1 - F5 */ pressed_key.scan_code = ch - '1' + 11; @@ -513,7 +592,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke( } break; case '2': - ch = skip_modifiers(NULL); + ch = analyze_modifiers(&key->key_state); switch (ch) { case '0'...'1': /* F9 - F10 */ pressed_key.scan_code = ch - '0' + 19; @@ -528,31 +607,406 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke( break; case '3': /* DEL */ pressed_key.scan_code = 8; - skip_modifiers(NULL); + analyze_modifiers(&key->key_state); break; case '5': /* PG UP */ pressed_key.scan_code = 9; - skip_modifiers(NULL); + analyze_modifiers(&key->key_state); break; case '6': /* PG DOWN */ pressed_key.scan_code = 10; - skip_modifiers(NULL); + analyze_modifiers(&key->key_state); break; - } + } /* [ */ break; + default: + /* ALT key */ + set_shift_mask(3, &key->key_state); } - } else if (ch == 0x7f) { + break; + case 0x7f: /* Backspace */ ch = 0x08; } - if (!pressed_key.scan_code) + if (pressed_key.scan_code) { + key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID; + } else { pressed_key.unicode_char = ch; - *key = pressed_key; - return EFI_EXIT(EFI_SUCCESS); + /* + * Assume left control key for control characters typically + * entered using the control key. + */ + if (ch >= 0x01 && ch <= 0x1f) { + key->key_state.key_shift_state |= + EFI_SHIFT_STATE_VALID; + switch (ch) { + case 0x01 ... 0x07: + case 0x0b ... 0x0c: + case 0x0e ... 0x1f: + key->key_state.key_shift_state |= + EFI_LEFT_CONTROL_PRESSED; + } + } + } + key->key = pressed_key; + + return EFI_SUCCESS; +} + +/** + * efi_cin_notify() - notify registered functions + */ +static void efi_cin_notify(void) +{ + struct efi_cin_notify_function *item; + + list_for_each_entry(item, &cin_notify_functions, link) { + bool match = true; + + /* We do not support toggle states */ + if (item->key.key.unicode_char || item->key.key.scan_code) { + if (item->key.key.unicode_char != + next_key.key.unicode_char || + item->key.key.scan_code != next_key.key.scan_code) + match = false; + } + if (item->key.key_state.key_shift_state && + item->key.key_state.key_shift_state != + next_key.key_state.key_shift_state) + match = false; + + if (match) + /* We don't bother about the return code */ + EFI_CALL(item->function(&next_key)); + } +} + +/** + * efi_cin_check() - check if keyboard input is available + */ +static void efi_cin_check(void) +{ + efi_status_t ret; + + if (key_available) { + efi_signal_event(efi_con_in.wait_for_key, true); + return; + } + + if (tstc()) { + ret = efi_cin_read_key(&next_key); + if (ret == EFI_SUCCESS) { + key_available = true; + + /* Notify registered functions */ + efi_cin_notify(); + + /* Queue the wait for key event */ + if (key_available) + efi_signal_event(efi_con_in.wait_for_key, true); + } + } +} + +/** + * efi_cin_empty_buffer() - empty input buffer + */ +static void efi_cin_empty_buffer(void) +{ + while (tstc()) + getc(); + key_available = false; +} + +/** + * efi_cin_reset_ex() - reset console input + * + * @this: - the extended simple text input protocol + * @extended_verification: - extended verification + * + * This function implements the reset service of the + * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: old value of the task priority level + */ +static efi_status_t EFIAPI efi_cin_reset_ex( + struct efi_simple_text_input_ex_protocol *this, + bool extended_verification) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %d", this, extended_verification); + + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + efi_cin_empty_buffer(); +out: + return EFI_EXIT(ret); } -struct efi_simple_input_interface efi_con_in = { +/** + * efi_cin_read_key_stroke_ex() - read key stroke + * + * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @key_data: key read from console + * Return: status code + * + * This function implements the ReadKeyStrokeEx service of the + * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + */ +static efi_status_t EFIAPI efi_cin_read_key_stroke_ex( + struct efi_simple_text_input_ex_protocol *this, + struct efi_key_data *key_data) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %p", this, key_data); + + /* Check parameters */ + if (!this || !key_data) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* We don't do interrupts, so check for timers cooperatively */ + efi_timer_check(); + + /* Enable console input after ExitBootServices */ + efi_cin_check(); + + if (!key_available) { + ret = EFI_NOT_READY; + goto out; + } + *key_data = next_key; + key_available = false; + efi_con_in.wait_for_key->is_signaled = false; +out: + return EFI_EXIT(ret); +} + +/** + * efi_cin_set_state() - set toggle key state + * + * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @key_toggle_state: key toggle state + * Return: status code + * + * This function implements the SetState service of the + * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + */ +static efi_status_t EFIAPI efi_cin_set_state( + struct efi_simple_text_input_ex_protocol *this, + u8 key_toggle_state) +{ + EFI_ENTRY("%p, %u", this, key_toggle_state); + /* + * U-Boot supports multiple console input sources like serial and + * net console for which a key toggle state cannot be set at all. + * + * According to the UEFI specification it is allowable to not implement + * this service. + */ + return EFI_EXIT(EFI_UNSUPPORTED); +} + +/** + * efi_cin_register_key_notify() - register key notification function + * + * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @key_data: key to be notified + * @key_notify_function: function to be called if the key is pressed + * @notify_handle: handle for unregistering the notification + * Return: status code + * + * This function implements the SetState service of the + * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + */ +static efi_status_t EFIAPI efi_cin_register_key_notify( + struct efi_simple_text_input_ex_protocol *this, + struct efi_key_data *key_data, + efi_status_t (EFIAPI *key_notify_function)( + struct efi_key_data *key_data), + void **notify_handle) +{ + efi_status_t ret = EFI_SUCCESS; + struct efi_cin_notify_function *notify_function; + + EFI_ENTRY("%p, %p, %p, %p", + this, key_data, key_notify_function, notify_handle); + + /* Check parameters */ + if (!this || !key_data || !key_notify_function || !notify_handle) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n", + key_data->key.unicode_char, + key_data->key.scan_code, + key_data->key_state.key_shift_state, + key_data->key_state.key_toggle_state); + + notify_function = calloc(1, sizeof(struct efi_cin_notify_function)); + if (!notify_function) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + notify_function->key = *key_data; + notify_function->function = key_notify_function; + list_add_tail(¬ify_function->link, &cin_notify_functions); + *notify_handle = notify_function; +out: + return EFI_EXIT(ret); +} + +/** + * efi_cin_unregister_key_notify() - unregister key notification function + * + * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @notification_handle: handle received when registering + * Return: status code + * + * This function implements the SetState service of the + * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + */ +static efi_status_t EFIAPI efi_cin_unregister_key_notify( + struct efi_simple_text_input_ex_protocol *this, + void *notification_handle) +{ + efi_status_t ret = EFI_INVALID_PARAMETER; + struct efi_cin_notify_function *item, *notify_function = + notification_handle; + + EFI_ENTRY("%p, %p", this, notification_handle); + + /* Check parameters */ + if (!this || !notification_handle) + goto out; + + list_for_each_entry(item, &cin_notify_functions, link) { + if (item == notify_function) { + ret = EFI_SUCCESS; + break; + } + } + if (ret != EFI_SUCCESS) + goto out; + + /* Remove the notify function */ + list_del(¬ify_function->link); + free(notify_function); +out: + return EFI_EXIT(ret); +} + + +/** + * efi_cin_reset() - drain the input buffer + * + * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @extended_verification: allow for exhaustive verification + * Return: status code + * + * This function implements the Reset service of the + * EFI_SIMPLE_TEXT_INPUT_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + */ +static efi_status_t EFIAPI efi_cin_reset + (struct efi_simple_text_input_protocol *this, + bool extended_verification) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %d", this, extended_verification); + + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + efi_cin_empty_buffer(); +out: + return EFI_EXIT(ret); +} + +/** + * efi_cin_read_key_stroke() - read key stroke + * + * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @key: key read from console + * Return: status code + * + * This function implements the ReadKeyStroke service of the + * EFI_SIMPLE_TEXT_INPUT_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + */ +static efi_status_t EFIAPI efi_cin_read_key_stroke + (struct efi_simple_text_input_protocol *this, + struct efi_input_key *key) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %p", this, key); + + /* Check parameters */ + if (!this || !key) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* We don't do interrupts, so check for timers cooperatively */ + efi_timer_check(); + + /* Enable console input after ExitBootServices */ + efi_cin_check(); + + if (!key_available) { + ret = EFI_NOT_READY; + goto out; + } + *key = next_key.key; + key_available = false; + efi_con_in.wait_for_key->is_signaled = false; +out: + return EFI_EXIT(ret); +} + +static struct efi_simple_text_input_ex_protocol efi_con_in_ex = { + .reset = efi_cin_reset_ex, + .read_key_stroke_ex = efi_cin_read_key_stroke_ex, + .wait_for_key_ex = NULL, + .set_state = efi_cin_set_state, + .register_key_notify = efi_cin_register_key_notify, + .unregister_key_notify = efi_cin_unregister_key_notify, +}; + +struct efi_simple_text_input_protocol efi_con_in = { .reset = efi_cin_reset, .read_key_stroke = efi_cin_read_key_stroke, .wait_for_key = NULL, @@ -560,31 +1014,38 @@ struct efi_simple_input_interface efi_con_in = { static struct efi_event *console_timer_event; -static void EFIAPI efi_key_notify(struct efi_event *event, void *context) -{ -} - /* - * Notification function of the console timer event. + * efi_console_timer_notify() - notify the console timer event * - * event: console timer event - * context: not used + * @event: console timer event + * @context: not used */ static void EFIAPI efi_console_timer_notify(struct efi_event *event, void *context) { EFI_ENTRY("%p, %p", event, context); + efi_cin_check(); + EFI_EXIT(EFI_SUCCESS); +} - /* Check if input is available */ - if (tstc()) { - /* Queue the wait for key event */ - efi_con_in.wait_for_key->is_signaled = true; - efi_signal_event(efi_con_in.wait_for_key, true); - } +/** + * efi_key_notify() - notify the wait for key event + * + * @event: wait for key event + * @context: not used + */ +static void EFIAPI efi_key_notify(struct efi_event *event, void *context) +{ + EFI_ENTRY("%p, %p", event, context); + efi_cin_check(); EFI_EXIT(EFI_SUCCESS); } -/* This gets called from do_bootefi_exec(). */ +/** + * efi_console_register() - install the console protocols + * + * This function is called from do_bootefi_exec(). + */ int efi_console_register(void) { efi_status_t r; @@ -598,17 +1059,27 @@ int efi_console_register(void) r = efi_create_handle((efi_handle_t *)&efi_console_output_obj); if (r != EFI_SUCCESS) goto out_of_memory; + r = efi_add_protocol(efi_console_output_obj->handle, &efi_guid_text_output_protocol, &efi_con_out); if (r != EFI_SUCCESS) goto out_of_memory; + systab.con_out_handle = efi_console_output_obj->handle; + systab.stderr_handle = efi_console_output_obj->handle; + r = efi_create_handle((efi_handle_t *)&efi_console_input_obj); if (r != EFI_SUCCESS) goto out_of_memory; + r = efi_add_protocol(efi_console_input_obj->handle, &efi_guid_text_input_protocol, &efi_con_in); if (r != EFI_SUCCESS) goto out_of_memory; + systab.con_in_handle = efi_console_input_obj->handle; + r = efi_add_protocol(efi_console_input_obj->handle, + &efi_guid_text_input_ex_protocol, &efi_con_in_ex); + if (r != EFI_SUCCESS) + goto out_of_memory; /* Create console events */ r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify, @@ -617,6 +1088,7 @@ int efi_console_register(void) printf("ERROR: Failed to register WaitForKey event\n"); return r; } + efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key; r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, efi_console_timer_notify, NULL, NULL, &console_timer_event); @@ -630,6 +1102,6 @@ int efi_console_register(void) printf("ERROR: Failed to set console timer\n"); return r; out_of_memory: - printf("ERROR: Out of meemory\n"); + printf("ERROR: Out of memory\n"); return r; } diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 9d776a6d99..5a61a1c1dc 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -22,10 +22,6 @@ static const struct efi_device_path END = { .length = sizeof(END), }; -#define U_BOOT_GUID \ - EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ - 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) - /* template ROOT node: */ static const struct efi_device_path_vendor ROOT = { .dp = { diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index ca8037def2..0082236359 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -17,6 +17,15 @@ const efi_guid_t efi_guid_device_path_to_text_protocol = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; +/** + * efi_str_to_u16() - convert ASCII string to UTF-16 + * + * A u16 buffer is allocated from pool. The ASCII string is copied to the u16 + * buffer. + * + * @str: ASCII string + * Return: UTF-16 string. NULL if out of memory. + */ static u16 *efi_str_to_u16(char *str) { efi_uintn_t len; @@ -29,7 +38,6 @@ static u16 *efi_str_to_u16(char *str) if (ret != EFI_SUCCESS) return NULL; ascii2unicode(out, str); - out[len - 1] = 0; return out; } diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index e6a15bcb52..0753a36a20 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -9,6 +9,7 @@ #include <charset.h> #include <efi_loader.h> #include <malloc.h> +#include <mapmem.h> #include <fs.h> /* GUID for file system information */ @@ -126,11 +127,22 @@ static int sanitize_path(char *path) return 0; } -/* NOTE: despite what you would expect, 'file_name' is actually a path. - * With windoze style backlashes, ofc. +/** + * file_open() - open a file handle + * + * @fs: file system + * @parent: directory relative to which the file is to be opened + * @file_name: path of the file to be opened. '\', '.', or '..' may + * be used as modifiers. A leading backslash indicates an + * absolute path. + * @mode: bit mask indicating the access mode (read, write, + * create) + * @attributes: attributes for newly created file + * Returns: handle to the opened file or NULL */ static struct efi_file_handle *file_open(struct file_system *fs, - struct file_handle *parent, s16 *file_name, u64 mode) + struct file_handle *parent, s16 *file_name, u64 mode, + u64 attributes) { struct file_handle *fh; char f0[MAX_UTF8_PER_UTF16] = {0}; @@ -139,7 +151,7 @@ static struct efi_file_handle *file_open(struct file_system *fs, if (file_name) { utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1); - flen = utf16_strlen((u16 *)file_name); + flen = u16_strlen((u16 *)file_name); } /* we could have a parent, but also an absolute path: */ @@ -173,7 +185,12 @@ static struct efi_file_handle *file_open(struct file_system *fs, if (set_blk_dev(fh)) goto error; - if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path))) + if ((mode & EFI_FILE_MODE_CREATE) && + (attributes & EFI_FILE_DIRECTORY)) { + if (fs_mkdir(fh->path)) + goto error; + } else if (!((mode & EFI_FILE_MODE_CREATE) || + fs_exists(fh->path))) goto error; /* figure out if file is a directory: */ @@ -195,15 +212,46 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, s16 *file_name, u64 open_mode, u64 attributes) { struct file_handle *fh = to_fh(file); + efi_status_t ret; EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name, open_mode, attributes); - *new_handle = file_open(fh->fs, fh, file_name, open_mode); - if (!*new_handle) - return EFI_EXIT(EFI_NOT_FOUND); + /* Check parameters */ + if (!file || !new_handle || !file_name) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + if (open_mode != EFI_FILE_MODE_READ && + open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) && + open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_CREATE)) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + /* + * The UEFI spec requires that attributes are only set in create mode. + * The SCT does not care about this and sets EFI_FILE_DIRECTORY in + * read mode. EDK2 does not check that attributes are zero if not in + * create mode. + * + * So here we only check attributes in create mode and do not check + * that they are zero otherwise. + */ + if ((open_mode & EFI_FILE_MODE_CREATE) && + (attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) { + ret = EFI_INVALID_PARAMETER; + goto out; + } - return EFI_EXIT(EFI_SUCCESS); + /* Open file */ + *new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes); + if (*new_handle) + ret = EFI_SUCCESS; + else + ret = EFI_NOT_FOUND; +out: + return EFI_EXIT(ret); } static efi_status_t file_close(struct file_handle *fh) @@ -223,9 +271,21 @@ static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) { struct file_handle *fh = to_fh(file); + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p", file); + + if (set_blk_dev(fh)) { + ret = EFI_DEVICE_ERROR; + goto error; + } + + if (fs_unlink(fh->path)) + ret = EFI_DEVICE_ERROR; file_close(fh); - return EFI_EXIT(EFI_WARN_DELETE_FAILURE); + +error: + return EFI_EXIT(ret); } static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, @@ -233,7 +293,7 @@ static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, { loff_t actread; - if (fs_read(fh->path, (ulong)buffer, fh->offset, + if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size, &actread)) return EFI_DEVICE_ERROR; @@ -363,7 +423,7 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, goto error; } - if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size, + if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size, &actwrite)) { ret = EFI_DEVICE_ERROR; goto error; @@ -438,7 +498,7 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; - EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer); + EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer); if (!guidcmp(info_type, &efi_file_info_guid)) { struct efi_file_info *info = buffer; @@ -598,7 +658,7 @@ efi_open_volume(struct efi_simple_file_system_protocol *this, EFI_ENTRY("%p, %p", this, root); - *root = file_open(fs, NULL, NULL, 0); + *root = file_open(fs, NULL, NULL, 0, 0); return EFI_EXIT(EFI_SUCCESS); } diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index fdf40a62c8..a18ce0a570 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -48,20 +48,21 @@ static int machines[] = { * If the program counter is located within the image the offset to the base * address is shown. * + * @obj: EFI object * @image: loaded image * @pc: program counter (use NULL to suppress offset output) * @return: status code */ -efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc) +static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj, + struct efi_loaded_image *image, + void *pc) { - if (!image) - return EFI_INVALID_PARAMETER; printf("UEFI image"); printf(" [0x%p:0x%p]", - image->reloc_base, image->reloc_base + image->reloc_size - 1); - if (pc && pc >= image->reloc_base && - pc < image->reloc_base + image->reloc_size) - printf(" pc=0x%zx", pc - image->reloc_base); + obj->reloc_base, obj->reloc_base + obj->reloc_size - 1); + if (pc && pc >= obj->reloc_base && + pc < obj->reloc_base + obj->reloc_size) + printf(" pc=0x%zx", pc - obj->reloc_base); if (image->file_path) printf(" '%pD'", image->file_path); printf("\n"); @@ -82,6 +83,7 @@ void efi_print_image_infos(void *pc) list_for_each_entry(handler, &efiobj->protocols, link) { if (!guidcmp(handler->guid, &efi_guid_loaded_image)) { efi_print_image_info( + (struct efi_loaded_image_obj *)efiobj, handler->protocol_interface, pc); } } @@ -196,7 +198,8 @@ static void efi_set_code_and_data_type( * piece of memory. On successful load it then returns the entry point for * the binary. Otherwise NULL. */ -void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) +void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, + struct efi_loaded_image *loaded_image_info) { IMAGE_NT_HEADERS32 *nt; IMAGE_DOS_HEADER *dos; @@ -314,8 +317,8 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) /* Populate the loaded image interface bits */ loaded_image_info->image_base = efi; loaded_image_info->image_size = image_size; - loaded_image_info->reloc_base = efi_reloc; - loaded_image_info->reloc_size = virt_size; + handle->reloc_base = efi_reloc; + handle->reloc_size = virt_size; return entry; } diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 0ac4ff554b..5bd4f4d7fc 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -65,9 +65,54 @@ static int efi_mem_cmp(void *priv, struct list_head *a, struct list_head *b) return -1; } +static uint64_t desc_get_end(struct efi_mem_desc *desc) +{ + return desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT); +} + static void efi_mem_sort(void) { + struct list_head *lhandle; + struct efi_mem_list *prevmem = NULL; + bool merge_again = true; + list_sort(NULL, &efi_mem, efi_mem_cmp); + + /* Now merge entries that can be merged */ + while (merge_again) { + merge_again = false; + list_for_each(lhandle, &efi_mem) { + struct efi_mem_list *lmem; + struct efi_mem_desc *prev = &prevmem->desc; + struct efi_mem_desc *cur; + uint64_t pages; + + lmem = list_entry(lhandle, struct efi_mem_list, link); + if (!prevmem) { + prevmem = lmem; + continue; + } + + cur = &lmem->desc; + + if ((desc_get_end(cur) == prev->physical_start) && + (prev->type == cur->type) && + (prev->attribute == cur->attribute)) { + /* There is an existing map before, reuse it */ + pages = cur->num_pages; + prev->num_pages += pages; + prev->physical_start -= pages << EFI_PAGE_SHIFT; + prev->virtual_start -= pages << EFI_PAGE_SHIFT; + list_del(&lmem->link); + free(lmem); + + merge_again = true; + break; + } + + prevmem = lmem; + } + } } /** efi_mem_carve_out - unmap memory region @@ -303,7 +348,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, switch (type) { case EFI_ALLOCATE_ANY_PAGES: /* Any page */ - addr = efi_find_free_memory(len, gd->start_addr_sp); + addr = efi_find_free_memory(len, -1ULL); if (!addr) { r = EFI_NOT_FOUND; break; diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c new file mode 100644 index 0000000000..b056ba3ee8 --- /dev/null +++ b/lib/efi_loader/efi_root_node.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Root node for system services + * + * Copyright (c) 2018 Heinrich Schuchardt + */ + +#include <common.h> +#include <malloc.h> +#include <efi_loader.h> + +const efi_guid_t efi_u_boot_guid = U_BOOT_GUID; + +struct efi_root_dp { + struct efi_device_path_vendor vendor; + struct efi_device_path end; +} __packed; + +/** + * efi_root_node_register() - create root node + * + * Create the root node on which we install all protocols that are + * not related to a loaded image or a driver. + * + * Return: status code + */ +efi_status_t efi_root_node_register(void) +{ + efi_handle_t root; + efi_status_t ret; + struct efi_root_dp *dp; + + /* Create handle */ + ret = efi_create_handle(&root); + if (ret != EFI_SUCCESS) + return ret; + + /* Install device path protocol */ + dp = calloc(1, sizeof(*dp)); + if (!dp) + return EFI_OUT_OF_RESOURCES; + + /* Fill vendor node */ + dp->vendor.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + dp->vendor.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; + dp->vendor.dp.length = sizeof(struct efi_device_path_vendor); + dp->vendor.guid = efi_u_boot_guid; + + /* Fill end node */ + dp->end.type = DEVICE_PATH_TYPE_END; + dp->end.sub_type = DEVICE_PATH_SUB_TYPE_END; + dp->end.length = sizeof(struct efi_device_path); + + /* Install device path protocol */ + ret = efi_add_protocol(root, &efi_guid_device_path, dp); + if (ret != EFI_SUCCESS) + goto failure; + + /* Install device path to text protocol */ + ret = efi_add_protocol(root, &efi_guid_device_path_to_text_protocol, + (void *)&efi_device_path_to_text); + if (ret != EFI_SUCCESS) + goto failure; + + /* Install device path utilities protocol */ + ret = efi_add_protocol(root, &efi_guid_device_path_utilities_protocol, + (void *)&efi_device_path_utilities); + if (ret != EFI_SUCCESS) + goto failure; + + /* Install Unicode collation protocol */ + ret = efi_add_protocol(root, &efi_guid_unicode_collation_protocol, + (void *)&efi_unicode_collation_protocol); + if (ret != EFI_SUCCESS) + goto failure; + +failure: + return ret; +} diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 27136cbedd..c5fbd91fa3 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -30,8 +30,9 @@ static efi_status_t __efi_runtime EFIAPI efi_device_error(void); static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); /* - * TODO(sjg@chromium.org): These defines and structs should come from the elf - * header for each arch (or a generic header) rather than being repeated here. + * TODO(sjg@chromium.org): These defines and structures should come from the ELF + * header for each architecture (or a generic header) rather than being repeated + * here. */ #if defined(__aarch64__) #define R_RELATIVE R_AARCH64_RELATIVE @@ -79,7 +80,7 @@ struct elf_rela { }; /* - * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI + * EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI * payload are running concurrently at the same time. In this mode, we can * handle a good number of runtime callbacks */ @@ -97,7 +98,7 @@ void __efi_runtime efi_update_table_header_crc32(struct efi_table_hdr *table) } /** - * efi_reset_system_boottime() - reset system at boottime + * efi_reset_system_boottime() - reset system at boot time * * This function implements the ResetSystem() runtime service before * SetVirtualAddressMap() is called. @@ -144,7 +145,7 @@ static void EFIAPI efi_reset_system_boottime( } /** - * efi_get_time_boottime() - get current time at boottime + * efi_get_time_boottime() - get current time at boot time * * This function implements the GetTime runtime service before * SetVirtualAddressMap() is called. @@ -335,7 +336,7 @@ static void efi_runtime_detach(ulong offset) *p = newaddr; } - /* Update crc32 */ + /* Update CRC32 */ efi_update_table_header_crc32(&efi_runtime_services.hdr); } @@ -489,7 +490,7 @@ static efi_status_t EFIAPI efi_set_virtual_address_map( * available at runtime. * * @mmio_ptr: address of the memory-mapped IO region - * @len: size of thememory-mapped IO region + * @len: size of the memory-mapped IO region * Returns: status code */ efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) @@ -607,7 +608,7 @@ efi_status_t __efi_runtime EFIAPI efi_update_capsule( * * @capsule_header_array: pointer to array of virtual pointers * @capsule_count: number of pointers in capsule_header_array - * @capsule_size: maximum capsule size + * @maximum_capsule_size: maximum capsule size * @reset_type: type of reset needed for capsule update * Returns: status code */ diff --git a/lib/efi_loader/efi_unicode_collation.c b/lib/efi_loader/efi_unicode_collation.c new file mode 100644 index 0000000000..7f3ea3c77e --- /dev/null +++ b/lib/efi_loader/efi_unicode_collation.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI Unicode collation protocol + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <common.h> +#include <charset.h> +#include <cp1250.h> +#include <cp437.h> +#include <efi_loader.h> + +/* Characters that may not be used in file names */ +static const char illegal[] = "<>:\"/\\|?*"; + +/* + * EDK2 assumes codepage 1250 when creating FAT 8.3 file names. + * Linux defaults to codepage 437 for FAT 8.3 file names. + */ +#if CONFIG_FAT_DEFAULT_CODEPAGE == 1250 +/* Unicode code points for code page 1250 characters 0x80 - 0xff */ +static const u16 codepage[] = CP1250; +#else +/* Unicode code points for code page 437 characters 0x80 - 0xff */ +static const u16 codepage[] = CP437; +#endif + +/* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */ +const efi_guid_t efi_guid_unicode_collation_protocol = + EFI_UNICODE_COLLATION_PROTOCOL2_GUID; + +/** + * efi_stri_coll() - compare utf-16 strings case-insenitively + * + * @this: unicode collation protocol instance + * @s1: first string + * @s2: second string + * + * This function implements the StriColl() service of the + * EFI_UNICODE_COLLATION_PROTOCOL. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * TODO: + * The implementation does not follow the Unicode collation algorithm. + * For ASCII characters it results in the same sort order as EDK2. + * We could use table UNICODE_CAPITALIZATION_TABLE for better results. + * + * Return: 0: s1 == s2, > 0: s1 > s2, < 0: s1 < s2 + */ +static efi_intn_t EFIAPI efi_stri_coll( + struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2) +{ + s32 c1, c2; + efi_intn_t ret = 0; + + EFI_ENTRY("%p, %ls, %ls", this, s1, s2); + for (; *s1 | *s2; ++s1, ++s2) { + c1 = utf_to_upper(*s1); + c2 = utf_to_upper(*s2); + if (c1 < c2) { + ret = -1; + goto out; + } else if (c1 > c2) { + ret = 1; + goto out; + } + } +out: + EFI_EXIT(EFI_SUCCESS); + return ret; +} + +/** + * metai_match() - compare utf-16 string with a pattern string case-insenitively + * + * @s: string to compare + * @p: pattern string + * + * The pattern string may use these: + * - * matches >= 0 characters + * - ? matches 1 character + * - [<char1><char2>...<charN>] match any character in the set + * - [<char1>-<char2>] matches any character in the range + * + * This function is called my efi_metai_match(). + * + * For '*' pattern searches this function calls itself recursively. + * Performance-wise this is suboptimal, especially for multiple '*' wildcards. + * But it results in simple code. + * + * Return: true if the string is matched. + */ +static bool metai_match(const u16 *s, const u16 *p) +{ + u16 first; + + for (; *s && *p; ++s, ++p) { + switch (*p) { + case '*': + /* Match 0 or more characters */ + ++p; + for (;; ++s) { + if (metai_match(s, p)) + return true; + if (!*s) + return false; + } + case '?': + /* Match any one character */ + break; + case '[': + /* Match any character in the set */ + ++p; + first = *p; + if (first == ']') + /* Empty set */ + return false; + ++p; + if (*p == '-') { + /* Range */ + ++p; + if (*s < first || *s > *p) + return false; + ++p; + if (*p != ']') + return false; + } else { + /* Set */ + bool hit = false; + + if (*s == first) + hit = true; + for (; *p && *p != ']'; ++p) { + if (*p == *s) + hit = true; + } + if (!hit || *p != ']') + return false; + } + break; + default: + /* Match one character */ + if (*p != *s) + return false; + } + } + if (!*p && !*s) + return true; + return false; +} + +/** + * efi_metai_match() - compare utf-16 string with a pattern string + * case-insenitively + * + * @this: unicode collation protocol instance + * @s: string to compare + * @p: pattern string + * + * The pattern string may use these: + * - * matches >= 0 characters + * - ? matches 1 character + * - [<char1><char2>...<charN>] match any character in the set + * - [<char1>-<char2>] matches any character in the range + * + * This function implements the MetaMatch() service of the + * EFI_UNICODE_COLLATION_PROTOCOL. + * + * Return: true if the string is matched. + */ +static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this, + const u16 *string, const u16 *pattern) +{ + bool ret; + + EFI_ENTRY("%p, %ls, %ls", this, string, pattern); + ret = metai_match(string, pattern); + EFI_EXIT(EFI_SUCCESS); + return ret; +} + +/** + * efi_str_lwr() - convert to lower case + * + * @this: unicode collation protocol instance + * @string: string to convert + * @p: pattern string + * + * The conversion is done in place. As long as upper and lower letters use the + * same number of words this does not pose a problem. + * + * This function implements the StrLwr() service of the + * EFI_UNICODE_COLLATION_PROTOCOL. + */ +static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this, + u16 *string) +{ + EFI_ENTRY("%p, %ls", this, string); + for (; *string; ++string) + *string = utf_to_lower(*string); + EFI_EXIT(EFI_SUCCESS); +} + +/** + * efi_str_upr() - convert to upper case + * + * @this: unicode collation protocol instance + * @string: string to convert + * @p: pattern string + * + * The conversion is done in place. As long as upper and lower letters use the + * same number of words this does not pose a problem. + * + * This function implements the StrUpr() service of the + * EFI_UNICODE_COLLATION_PROTOCOL. + */ +static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this, + u16 *string) +{ + EFI_ENTRY("%p, %ls", this, string); + for (; *string; ++string) + *string = utf_to_upper(*string); + EFI_EXIT(EFI_SUCCESS); +} + +/** + * efi_fat_to_str() - convert an 8.3 file name from an OEM codepage to Unicode + * + * @this: unicode collation protocol instance + * @fat_size: size of the string to convert + * @fat: string to convert + * @string: converted string + * + * This function implements the FatToStr() service of the + * EFI_UNICODE_COLLATION_PROTOCOL. + */ +static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this, + efi_uintn_t fat_size, char *fat, u16 *string) +{ + efi_uintn_t i; + u16 c; + + EFI_ENTRY("%p, %zu, %s, %p", this, fat_size, fat, string); + for (i = 0; i < fat_size; ++i) { + c = (unsigned char)fat[i]; + if (c > 0x80) + c = codepage[i - 0x80]; + string[i] = c; + if (!c) + break; + } + string[i] = 0; + EFI_EXIT(EFI_SUCCESS); +} + +/** + * efi_fat_to_str() - convert a utf-16 string to legal characters for a FAT + * file name in an OEM code page + * + * @this: unicode collation protocol instance + * @string: Unicode string to convert + * @fat_size: size of the target buffer + * @fat: converted string + * + * This function implements the StrToFat() service of the + * EFI_UNICODE_COLLATION_PROTOCOL. + * + * Return: true if an illegal character was substituted by '_'. + */ +static bool EFIAPI efi_str_to_fat(struct efi_unicode_collation_protocol *this, + const u16 *string, efi_uintn_t fat_size, + char *fat) +{ + efi_uintn_t i; + s32 c; + bool ret = false; + + EFI_ENTRY("%p, %ls, %zu, %p", this, string, fat_size, fat); + for (i = 0; i < fat_size;) { + c = utf16_get(&string); + switch (c) { + /* Ignore period and space */ + case '.': + case ' ': + continue; + case 0: + break; + } + c = utf_to_upper(c); + if (c >= 0x80) { + int j; + + /* Look for codepage translation */ + for (j = 0; j < 0x80; ++j) { + if (c == codepage[j]) { + c = j + 0x80; + break; + } + } + if (j >= 0x80) { + c = '_'; + ret = true; + } + } else if (c && (c < 0x20 || strchr(illegal, c))) { + c = '_'; + ret = true; + } + + fat[i] = c; + if (!c) + break; + ++i; + } + EFI_EXIT(EFI_SUCCESS); + return ret; +} + +const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = { + .stri_coll = efi_stri_coll, + .metai_match = efi_metai_match, + .str_lwr = efi_str_lwr, + .str_upr = efi_str_upr, + .fat_to_str = efi_fat_to_str, + .str_to_fat = efi_str_to_fat, + .supported_languages = "en", +}; diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 90b637215e..a1313fa215 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -44,10 +44,7 @@ * converted to utf16? */ -#define MAX_VAR_NAME 31 -#define MAX_NATIVE_VAR_NAME \ - (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \ - (MAX_VAR_NAME * MAX_UTF8_PER_UTF16)) +#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_")) static int hex(int ch) { @@ -101,18 +98,20 @@ static char *mem2hex(char *hexstr, const u8 *mem, int count) return hexstr; } -static efi_status_t efi_to_native(char *native, u16 *variable_name, +static efi_status_t efi_to_native(char **native, const u16 *variable_name, efi_guid_t *vendor) { size_t len; + char *pos; - len = utf16_strlen((u16 *)variable_name); - if (len >= MAX_VAR_NAME) - return EFI_DEVICE_ERROR; + len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1; + *native = malloc(len); + if (!*native) + return EFI_OUT_OF_RESOURCES; - native += sprintf(native, "efi_%pUl_", vendor); - native = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len); - *native = '\0'; + pos = *native; + pos += sprintf(pos, "efi_%pUl_", vendor); + utf16_utf8_strcpy(&pos, variable_name); return EFI_SUCCESS; } @@ -168,7 +167,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data) { - char native_name[MAX_NATIVE_VAR_NAME + 1]; + char *native_name; efi_status_t ret; unsigned long in_size; const char *val, *s; @@ -180,13 +179,14 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor, if (!variable_name || !vendor || !data_size) return EFI_EXIT(EFI_INVALID_PARAMETER); - ret = efi_to_native(native_name, variable_name, vendor); + ret = efi_to_native(&native_name, variable_name, vendor); if (ret) return EFI_EXIT(ret); debug("%s: get '%s'\n", __func__, native_name); val = env_get(native_name); + free(native_name); if (!val) return EFI_EXIT(EFI_NOT_FOUND); @@ -256,35 +256,41 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor, u32 attributes, efi_uintn_t data_size, void *data) { - char native_name[MAX_NATIVE_VAR_NAME + 1]; + char *native_name = NULL, *val = NULL, *s; efi_status_t ret = EFI_SUCCESS; - char *val, *s; u32 attr; EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes, data_size, data); - if (!variable_name || !vendor) - return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!variable_name || !vendor) { + ret = EFI_INVALID_PARAMETER; + goto out; + } - ret = efi_to_native(native_name, variable_name, vendor); + ret = efi_to_native(&native_name, variable_name, vendor); if (ret) - return EFI_EXIT(ret); + goto out; #define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS) if ((data_size == 0) || !(attributes & ACCESS_ATTR)) { /* delete the variable: */ env_set(native_name, NULL); - return EFI_EXIT(EFI_SUCCESS); + ret = EFI_SUCCESS; + goto out; } val = env_get(native_name); if (val) { parse_attr(val, &attr); - if (attr & READ_ONLY) - return EFI_EXIT(EFI_WRITE_PROTECTED); + if (attr & READ_ONLY) { + /* We should not free val */ + val = NULL; + ret = EFI_WRITE_PROTECTED; + goto out; + } } val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1); @@ -320,6 +326,8 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor, if (env_set(native_name, val)) ret = EFI_DEVICE_ERROR; +out: + free(native_name); free(val); return EFI_EXIT(ret); diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig index 59f9f36801..b52696778d 100644 --- a/lib/efi_selftest/Kconfig +++ b/lib/efi_selftest/Kconfig @@ -1,6 +1,6 @@ config CMD_BOOTEFI_SELFTEST bool "Allow booting an EFI efi_selftest" - depends on CMD_BOOTEFI + depends on CMD_BOOTEFI && !SANDBOX imply FAT imply FAT_WRITE help diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 590f90b16d..2f55d9d66f 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -24,12 +24,15 @@ efi_selftest_event_groups.o \ efi_selftest_exitbootservices.o \ efi_selftest_fdt.o \ efi_selftest_gop.o \ +efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ +efi_selftest_textinputex.o \ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ +efi_selftest_unicode_collation.o \ efi_selftest_util.o \ efi_selftest_variables.o \ efi_selftest_watchdog.o diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index eb139c127c..42f51b6520 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -9,7 +9,7 @@ #include <vsprintf.h> struct efi_simple_text_output_protocol *con_out; -struct efi_simple_input_interface *con_in; +struct efi_simple_text_input_protocol *con_in; /* * Print a MAC address to an u16 string diff --git a/lib/efi_selftest/efi_selftest_loaded_image.c b/lib/efi_selftest/efi_selftest_loaded_image.c new file mode 100644 index 0000000000..f9b54ae263 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_loaded_image.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_loaded_image + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the Loaded Image Protocol. + */ + +#include <efi_selftest.h> + +static efi_guid_t loaded_image_protocol_guid = + EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, + 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b); +static struct efi_boot_services *boottime; +efi_handle_t image_handle; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + image_handle = img_handle; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Verify that the loaded image protocol is installed on the image handle. + * Verify that the loaded image protocol points to the system table. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t i, protocol_buffer_count = 0; + efi_guid_t **protocol_buffer = NULL; + bool found = false; + struct efi_loaded_image *loaded_image_protocol; + + /* + * Get the GUIDs of all protocols installed on the handle. + */ + ret = boottime->protocols_per_handle(image_handle, &protocol_buffer, + &protocol_buffer_count); + if (ret != EFI_SUCCESS) { + efi_st_error("ProtocolsPerHandle failed\n"); + return EFI_ST_FAILURE; + } + if (!protocol_buffer_count | !protocol_buffer) { + efi_st_error("ProtocolsPerHandle returned no protocol\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("%u protocols installed on image handle\n", + (unsigned int)protocol_buffer_count); + for (i = 0; i < protocol_buffer_count; ++i) { + if (efi_st_memcmp(protocol_buffer[i], + &loaded_image_protocol_guid, + sizeof(efi_guid_t))) + found = true; + } + if (!found) { + efi_st_printf("LoadedImageProtocol not found\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(protocol_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Open the loaded image protocol. + */ + ret = boottime->open_protocol(image_handle, &loaded_image_protocol_guid, + (void **)&loaded_image_protocol, NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (loaded_image_protocol->revision != + EFI_LOADED_IMAGE_PROTOCOL_REVISION) { + efi_st_printf("Incorrect revision\n"); + return EFI_ST_FAILURE; + } + if (!loaded_image_protocol->system_table || + loaded_image_protocol->system_table->hdr.signature != + EFI_SYSTEM_TABLE_SIGNATURE) { + efi_st_printf("System table reference missing\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(loadedimage) = { + .name = "loaded image", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c index 44b8da3ba5..b09e4cdcfa 100644 --- a/lib/efi_selftest/efi_selftest_manageprotocols.c +++ b/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -179,7 +179,12 @@ static int execute(void) efi_st_error("LocateHandleBuffer failed to locate new handle\n"); return EFI_ST_FAILURE; } - boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + /* Release buffer */ + ret = boottime->free_pool(buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } /* * Test error handling in UninstallMultipleProtocols @@ -221,6 +226,7 @@ static int execute(void) efi_st_error("LocateHandleBuffer failed to locate new handle\n"); return EFI_ST_FAILURE; } + /* Clear the buffer, we are reusing it it the next step. */ boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); /* @@ -248,7 +254,12 @@ static int execute(void) efi_st_error("LocateHandle failed to locate new handles\n"); return EFI_ST_FAILURE; } - boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + /* Release buffer */ + ret = boottime->free_pool(buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } /* * Test LocateProtocol @@ -319,6 +330,12 @@ static int execute(void) efi_st_error("Failed to get protocols per handle\n"); return EFI_ST_FAILURE; } + /* Release buffer */ + ret = boottime->free_pool(prot_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } /* * Uninstall remaining protocols diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c index 7aa84de89d..164fbffe6c 100644 --- a/lib/efi_selftest/efi_selftest_textinput.c +++ b/lib/efi_selftest/efi_selftest_textinput.c @@ -14,113 +14,8 @@ #include <efi_selftest.h> -struct translate { - u16 code; - u16 *text; -}; - static struct efi_boot_services *boottime; -static struct translate control_characters[] = { - {0, L"Null"}, - {8, L"BS"}, - {9, L"TAB"}, - {10, L"LF"}, - {13, L"CR"}, - {0, NULL}, -}; - -static u16 ch[] = L"' '"; -static u16 unknown[] = L"unknown"; - -static struct translate scan_codes[] = { - {0x00, L"Null"}, - {0x01, L"Up"}, - {0x02, L"Down"}, - {0x03, L"Right"}, - {0x04, L"Left"}, - {0x05, L"Home"}, - {0x06, L"End"}, - {0x07, L"Insert"}, - {0x08, L"Delete"}, - {0x09, L"Page Up"}, - {0x0a, L"Page Down"}, - {0x0b, L"FN 1"}, - {0x0c, L"FN 2"}, - {0x0d, L"FN 3"}, - {0x0e, L"FN 4"}, - {0x0f, L"FN 5"}, - {0x10, L"FN 6"}, - {0x11, L"FN 7"}, - {0x12, L"FN 8"}, - {0x13, L"FN 9"}, - {0x14, L"FN 10"}, - {0x15, L"FN 11"}, - {0x16, L"FN 12"}, - {0x17, L"Escape"}, - {0x68, L"FN 13"}, - {0x69, L"FN 14"}, - {0x6a, L"FN 15"}, - {0x6b, L"FN 16"}, - {0x6c, L"FN 17"}, - {0x6d, L"FN 18"}, - {0x6e, L"FN 19"}, - {0x6f, L"FN 20"}, - {0x70, L"FN 21"}, - {0x71, L"FN 22"}, - {0x72, L"FN 23"}, - {0x73, L"FN 24"}, - {0x7f, L"Mute"}, - {0x80, L"Volume Up"}, - {0x81, L"Volume Down"}, - {0x100, L"Brightness Up"}, - {0x101, L"Brightness Down"}, - {0x102, L"Suspend"}, - {0x103, L"Hibernate"}, - {0x104, L"Toggle Display"}, - {0x105, L"Recovery"}, - {0x106, L"Reject"}, - {0x0, NULL}, -}; - -/* - * Translate a unicode character to a string. - * - * @code unicode character - * @return string - */ -static u16 *translate_char(u16 code) -{ - struct translate *tr; - - if (code >= ' ') { - ch[1] = code; - return ch; - } - for (tr = control_characters; tr->text; ++tr) { - if (tr->code == code) - return tr->text; - } - return unknown; -} - -/* - * Translate a scan code to a human readable string. - * - * @code unicode character - * @return string - */ -static u16 *translate_code(u16 code) -{ - struct translate *tr; - - for (tr = scan_codes; tr->text; ++tr) { - if (tr->code == code) - return tr->text; - } - return unknown; -} - /* * Setup unit test. * @@ -145,24 +40,45 @@ static int execute(void) { struct efi_input_key input_key = {0}; efi_status_t ret; + efi_uintn_t index; + + /* Drain the console input */ + ret = con_in->reset(con_in, true); + if (ret != EFI_SUCCESS) { + efi_st_error("Reset failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in->read_key_stroke(con_in, &input_key); + if (ret != EFI_NOT_READY) { + efi_st_error("Empty buffer not reported\n"); + return EFI_ST_FAILURE; + } efi_st_printf("Waiting for your input\n"); efi_st_printf("To terminate type 'x'\n"); for (;;) { /* Wait for next key */ - do { - ret = con_in->read_key_stroke(con_in, &input_key); - } while (ret == EFI_NOT_READY); + ret = boottime->wait_for_event(1, &con_in->wait_for_key, + &index); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("WaitForEvent failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in->read_key_stroke(con_in, &input_key); + if (ret != EFI_SUCCESS) { + efi_st_error("ReadKeyStroke failed\n"); + return EFI_ST_FAILURE; + } /* Allow 5 minutes until time out */ boottime->set_watchdog_timer(300, 0, 0, NULL); efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n", (unsigned int)input_key.unicode_char, - translate_char(input_key.unicode_char), + efi_st_translate_char(input_key.unicode_char), (unsigned int)input_key.scan_code, - translate_code(input_key.scan_code)); + efi_st_translate_code(input_key.scan_code)); switch (input_key.unicode_char) { case 'x': diff --git a/lib/efi_selftest/efi_selftest_textinputex.c b/lib/efi_selftest/efi_selftest_textinputex.c new file mode 100644 index 0000000000..de44224ce1 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_textinputex.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_textinput + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * The unicode character and the scan code are printed for text + * input. To run the test: + * + * setenv efi_selftest extended text input + * bootefi selftest + */ + +#include <efi_selftest.h> + +static const efi_guid_t text_input_ex_protocol_guid = + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; + +static struct efi_simple_text_input_ex_protocol *con_in_ex; + +static struct efi_boot_services *boottime; + +static void *efi_key_notify_handle; +static bool efi_running; + +/** + * efi_key_notify_function() - key notification function + * + * This function is called when the registered key is hit. + * + * @key_data: next key + * Return: status code + */ +static efi_status_t EFIAPI efi_key_notify_function + (struct efi_key_data *key_data) +{ + efi_running = false; + + return EFI_SUCCESS; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + struct efi_key_data key_data = { + .key = { + .scan_code = 0, + .unicode_char = 0x18 + }, + .key_state = { + .key_shift_state = EFI_SHIFT_STATE_VALID | + EFI_LEFT_CONTROL_PRESSED, + .key_toggle_state = EFI_TOGGLE_STATE_INVALID, + }, + }; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL, + (void **)&con_in_ex); + if (ret != EFI_SUCCESS) { + con_in_ex = NULL; + efi_st_error + ("Extended text input protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + ret = con_in_ex->register_key_notify(con_in_ex, &key_data, + efi_key_notify_function, + &efi_key_notify_handle); + if (ret != EFI_SUCCESS) { + efi_key_notify_handle = NULL; + efi_st_error + ("Notify function could not be registered.\n"); + return EFI_ST_FAILURE; + } + efi_running = true; + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Unregister notify function. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + ret = con_in_ex->unregister_key_notify + (con_in_ex, efi_key_notify_handle); + if (ret != EFI_SUCCESS) { + efi_st_error + ("Notify function could not be registered.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct efi_key_data input_key = { {0, 0}, {0, 0} }; + efi_status_t ret; + efi_uintn_t index; + + if (!con_in_ex) { + efi_st_printf("Setup failed\n"); + return EFI_ST_FAILURE; + } + + /* Drain the console input */ + ret = con_in_ex->reset(con_in_ex, true); + if (ret != EFI_SUCCESS) { + efi_st_error("Reset failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key); + if (ret != EFI_NOT_READY) { + efi_st_error("Empty buffer not reported\n"); + return EFI_ST_FAILURE; + } + + efi_st_printf("Waiting for your input\n"); + efi_st_printf("To terminate type 'CTRL+x'\n"); + + while (efi_running) { + /* Wait for next key */ + ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex, + &index); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("WaitForEvent failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key); + if (ret != EFI_SUCCESS) { + efi_st_error("ReadKeyStroke failed\n"); + return EFI_ST_FAILURE; + } + + /* Allow 5 minutes until time out */ + boottime->set_watchdog_timer(300, 0, 0, NULL); + + efi_st_printf("Unicode char %u (%ps), scan code %u (", + (unsigned int)input_key.key.unicode_char, + efi_st_translate_char(input_key.key.unicode_char), + (unsigned int)input_key.key.scan_code); + if (input_key.key_state.key_shift_state & + EFI_SHIFT_STATE_VALID) { + if (input_key.key_state.key_shift_state & + (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) + efi_st_printf("SHIFT+"); + if (input_key.key_state.key_shift_state & + (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED)) + efi_st_printf("ALT+"); + if (input_key.key_state.key_shift_state & + (EFI_LEFT_CONTROL_PRESSED | + EFI_RIGHT_CONTROL_PRESSED)) + efi_st_printf("CTRL+"); + if (input_key.key_state.key_shift_state & + (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED)) + efi_st_printf("META+"); + if (input_key.key_state.key_shift_state == + EFI_SHIFT_STATE_VALID) + efi_st_printf("+"); + } + + efi_st_printf("%ps)\n", + efi_st_translate_code(input_key.key.scan_code)); + + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(textinputex) = { + .name = "extended text input", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, + .on_request = true, +}; diff --git a/lib/efi_selftest/efi_selftest_unicode_collation.c b/lib/efi_selftest/efi_selftest_unicode_collation.c new file mode 100644 index 0000000000..9765bd3e44 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_unicode_collation.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_unicode_collation + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test unicode collation protocol. + */ + +#include <efi_selftest.h> + +static const efi_guid_t unicode_collation_protocol_guid = + EFI_UNICODE_COLLATION_PROTOCOL2_GUID; + +static struct efi_boot_services *boottime; + +static struct efi_unicode_collation_protocol *unicode_collation_protocol; + +/** + * setup() - setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * ReturnValue: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&unicode_collation_protocol_guid, NULL, + (void **)&unicode_collation_protocol); + if (ret != EFI_SUCCESS) { + unicode_collation_protocol = NULL; + efi_st_error("Unicode collation protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_stri_coll(void) +{ + efi_intn_t ret; + u16 c1[] = L"first"; + u16 c2[] = L"FIRST"; + u16 c3[] = L"second"; + + ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol, + c1, c2); + if (ret) { + efi_st_error( + "stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c2, ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol, + c1, c3); + if (ret >= 0) { + efi_st_error( + "stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c3, ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol, + c3, c1); + if (ret <= 0) { + efi_st_error( + "stri_coll(\"%ps\", \"%ps\") = %zu\n", c3, c1, ret); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_metai_match(void) +{ + bool ret; + const u16 c[] = L"Das U-Boot"; + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"*"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[rstu] U-Boot"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[q-v] U-Boot"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da? U-Boot"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"D*Bo*t"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[xyz] U-Boot"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[a-d] U-Boot"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da?? U-Boot"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"D*Bo*tt"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_str_lwr(void) +{ + u16 c[] = L"U-Boot"; + + unicode_collation_protocol->str_lwr(unicode_collation_protocol, c); + if (efi_st_strcmp_16_8(c, "u-boot")) { + efi_st_error("str_lwr returned \"%ps\"\n", c); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_str_upr(void) +{ + u16 c[] = L"U-Boot"; + + unicode_collation_protocol->str_upr(unicode_collation_protocol, c); + if (efi_st_strcmp_16_8(c, "U-BOOT")) { + efi_st_error("str_lwr returned \"%ps\"\n", c); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_fat_to_str(void) +{ + u16 str[16]; + + boottime->set_mem(str, sizeof(str), 0); + unicode_collation_protocol->fat_to_str(unicode_collation_protocol, 6, + "U-BOOT", str); + if (efi_st_strcmp_16_8(str, "U-BOOT")) { + efi_st_error("fat_to_str returned \"%ps\"\n", str); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_str_to_fat(void) +{ + char fat[16]; + bool ret; + + boottime->set_mem(fat, sizeof(fat), 0); + ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol, + L"U -Boo.t", 6, fat); + if (ret || efi_st_strcmp_16_8(L"U-BOOT", fat)) { + efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat); + return EFI_ST_FAILURE; + } + + boottime->set_mem(fat, 16, 0); + ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol, + L"U\\Boot", 6, fat); + if (!ret || efi_st_strcmp_16_8(L"U_BOOT", fat)) { + efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/** + * execute() - Execute unit test. + * + * ReturnValue: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + int ret; + + if (!unicode_collation_protocol) { + efi_st_printf("Unicode collation protocol missing\n"); + return EFI_ST_FAILURE; + } + + ret = test_stri_coll(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_metai_match(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_str_lwr(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_str_upr(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_fat_to_str(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_str_to_fat(); + if (ret != EFI_ST_SUCCESS) + return ret; + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(unicoll) = { + .name = "unicode collation", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, + .setup = setup, +}; diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c index 87a04f898a..96a964c863 100644 --- a/lib/efi_selftest/efi_selftest_util.c +++ b/lib/efi_selftest/efi_selftest_util.c @@ -9,6 +9,99 @@ #include <efi_selftest.h> +struct efi_st_translate { + u16 code; + u16 *text; +}; + +static struct efi_st_translate efi_st_control_characters[] = { + {0, L"Null"}, + {8, L"BS"}, + {9, L"TAB"}, + {10, L"LF"}, + {13, L"CR"}, + {0, NULL}, +}; + +static u16 efi_st_ch[] = L"' '"; +static u16 efi_st_unknown[] = L"unknown"; + +static struct efi_st_translate efi_st_scan_codes[] = { + {0x00, L"Null"}, + {0x01, L"Up"}, + {0x02, L"Down"}, + {0x03, L"Right"}, + {0x04, L"Left"}, + {0x05, L"Home"}, + {0x06, L"End"}, + {0x07, L"Insert"}, + {0x08, L"Delete"}, + {0x09, L"Page Up"}, + {0x0a, L"Page Down"}, + {0x0b, L"FN 1"}, + {0x0c, L"FN 2"}, + {0x0d, L"FN 3"}, + {0x0e, L"FN 4"}, + {0x0f, L"FN 5"}, + {0x10, L"FN 6"}, + {0x11, L"FN 7"}, + {0x12, L"FN 8"}, + {0x13, L"FN 9"}, + {0x14, L"FN 10"}, + {0x15, L"FN 11"}, + {0x16, L"FN 12"}, + {0x17, L"Escape"}, + {0x68, L"FN 13"}, + {0x69, L"FN 14"}, + {0x6a, L"FN 15"}, + {0x6b, L"FN 16"}, + {0x6c, L"FN 17"}, + {0x6d, L"FN 18"}, + {0x6e, L"FN 19"}, + {0x6f, L"FN 20"}, + {0x70, L"FN 21"}, + {0x71, L"FN 22"}, + {0x72, L"FN 23"}, + {0x73, L"FN 24"}, + {0x7f, L"Mute"}, + {0x80, L"Volume Up"}, + {0x81, L"Volume Down"}, + {0x100, L"Brightness Up"}, + {0x101, L"Brightness Down"}, + {0x102, L"Suspend"}, + {0x103, L"Hibernate"}, + {0x104, L"Toggle Display"}, + {0x105, L"Recovery"}, + {0x106, L"Reject"}, + {0x0, NULL}, +}; + +u16 *efi_st_translate_char(u16 code) +{ + struct efi_st_translate *tr; + + if (code >= ' ') { + efi_st_ch[1] = code; + return efi_st_ch; + } + for (tr = efi_st_control_characters; tr->text; ++tr) { + if (tr->code == code) + return tr->text; + } + return efi_st_unknown; +} + +u16 *efi_st_translate_code(u16 code) +{ + struct efi_st_translate *tr; + + for (tr = efi_st_scan_codes; tr->text; ++tr) { + if (tr->code == code) + return tr->text; + } + return efi_st_unknown; +} + int efi_st_memcmp(const void *buf1, const void *buf2, size_t length) { const u8 *pos1 = buf1; diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 914fbd30cb..4213441fbf 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -274,28 +274,23 @@ static char *string(char *buf, char *end, char *s, int field_width, return buf; } +/* U-Boot uses UTF-16 strings in the EFI context only. */ +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) static char *string16(char *buf, char *end, u16 *s, int field_width, int precision, int flags) { u16 *str = s ? s : L"<NULL>"; - int utf16_len = utf16_strnlen(str, precision); - u8 utf8[utf16_len * MAX_UTF8_PER_UTF16]; - int utf8_len, i; - - utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8; + ssize_t len = utf16_strnlen(str, precision); if (!(flags & LEFT)) - while (utf8_len < field_width--) + for (; len < field_width; --field_width) ADDCH(buf, ' '); - for (i = 0; i < utf8_len; ++i) - ADDCH(buf, utf8[i]); - while (utf8_len < field_width--) + utf16_utf8_strncpy(&buf, str, len); + for (; len < field_width; --field_width) ADDCH(buf, ' '); return buf; } -#if defined(CONFIG_EFI_LOADER) && \ - !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) static char *device_path_string(char *buf, char *end, void *dp, int field_width, int precision, int flags) { @@ -450,8 +445,8 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, #endif switch (*fmt) { -#if defined(CONFIG_EFI_LOADER) && \ - !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) +/* Device paths only exist in the EFI context. */ +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) case 'D': return device_path_string(buf, end, ptr, field_width, precision, flags); @@ -612,10 +607,14 @@ repeat: continue; case 's': - if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) { +/* U-Boot uses UTF-16 strings in the EFI context only. */ +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) + if (qualifier == 'l') { str = string16(str, end, va_arg(args, u16 *), field_width, precision, flags); - } else { + } else +#endif + { str = string(str, end, va_arg(args, char *), field_width, precision, flags); } diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index cf97b64296..96d3f75750 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -366,7 +366,6 @@ CONFIG_DHCP_MIN_EXT_LEN CONFIG_DIALOG_POWER CONFIG_DIMM_SLOTS_PER_CTLR CONFIG_DIRECT_NOR_BOOT -CONFIG_DISABLE_CONSOLE CONFIG_DISCONTIGMEM CONFIG_DISCOVER_PHY CONFIG_DISPLAY_AER_xxxx @@ -3424,7 +3423,6 @@ CONFIG_SYS_MEM_TOP_HIDE CONFIG_SYS_MFD CONFIG_SYS_MHZ CONFIG_SYS_MII_MODE -CONFIG_SYS_MIPS_CACHE_MODE CONFIG_SYS_MIPS_TIMER_FREQ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR @@ -4070,7 +4068,6 @@ CONFIG_SYS_RSTC_RMR_VAL CONFIG_SYS_RTC_BUS_NUM CONFIG_SYS_RTC_CNT CONFIG_SYS_RTC_OSCILLATOR -CONFIG_SYS_RTC_PL031_BASE CONFIG_SYS_RTC_REG_BASE_ADDR CONFIG_SYS_RTC_SETUP CONFIG_SYS_RV3029_TCR @@ -4101,7 +4098,6 @@ CONFIG_SYS_SCCR_USBDRCM CONFIG_SYS_SCCR_USBMPHCM CONFIG_SYS_SCR CONFIG_SYS_SCRATCH_VA -CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE CONFIG_SYS_SCSI_MAX_LUN CONFIG_SYS_SCSI_MAX_SCSI_ID @@ -4421,7 +4417,6 @@ CONFIG_SYS_XHCI_USB1_ADDR CONFIG_SYS_XHCI_USB2_ADDR CONFIG_SYS_XHCI_USB3_ADDR CONFIG_SYS_XIMG_LEN -CONFIG_SYS_XWAY_EBU_BOOTCFG CONFIG_SYS_ZYNQ_QSPI_WAIT CONFIG_SYS_ZYNQ_SPI_WAIT CONFIG_SYS_i2C_FSL diff --git a/test/Kconfig b/test/Kconfig index 3643761bc6..de16d179d0 100644 --- a/test/Kconfig +++ b/test/Kconfig @@ -15,6 +15,14 @@ config UT_TIME problems. But if you are having problems with udelay() and the like, this is a good place to start. +config UT_UNICODE + bool "Unit tests for Unicode functions" + depends on UNIT_TEST + default y + help + Enables the 'ut unicode' command which tests that the functions for + manipulating Unicode strings work correctly. + source "test/dm/Kconfig" source "test/env/Kconfig" source "test/overlay/Kconfig" diff --git a/test/Makefile b/test/Makefile index 1092011fdb..a5f52fd5ad 100644 --- a/test/Makefile +++ b/test/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_SANDBOX) += command_ut.o obj-$(CONFIG_SANDBOX) += compression.o obj-$(CONFIG_SANDBOX) += print_ut.o obj-$(CONFIG_UT_TIME) += time_ut.o +obj-$(CONFIG_UT_UNICODE) += unicode_ut.o obj-$(CONFIG_$(SPL_)LOG) += log/ diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 934a5a931b..b7e01a4847 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -49,6 +49,9 @@ static cmd_tbl_t cmd_ut_sub[] = { #ifdef CONFIG_UT_TIME U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""), #endif +#if CONFIG_IS_ENABLED(UT_UNICODE) && !defined(API_BUILD) + U_BOOT_CMD_MKENT(unicode, CONFIG_SYS_MAXARGS, 1, do_ut_unicode, "", ""), +#endif #ifdef CONFIG_SANDBOX U_BOOT_CMD_MKENT(compression, CONFIG_SYS_MAXARGS, 1, do_ut_compression, "", ""), @@ -93,6 +96,9 @@ static int do_ut(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #ifdef CONFIG_SYS_LONGHELP static char ut_help_text[] = "all - execute all enabled tests\n" +#ifdef CONFIG_SANDBOX + "ut compression - Test compressors and bootm decompression\n" +#endif #ifdef CONFIG_UT_DM "ut dm [test-name]\n" #endif @@ -105,11 +111,12 @@ static char ut_help_text[] = #ifdef CONFIG_UT_TIME "ut time - Very basic test of time functions\n" #endif -#ifdef CONFIG_SANDBOX - "ut compression - Test compressors and bootm decompression\n" +#if defined(CONFIG_UT_UNICODE) && \ + !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) + "ut unicode [test-name] - test Unicode functions\n" #endif ; -#endif +#endif /* CONFIG_SYS_LONGHELP */ U_BOOT_CMD( ut, CONFIG_SYS_MAXARGS, 1, do_ut, diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 9482239562..86308cfe2d 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -7,18 +7,20 @@ # It currently tests the fs/sb and native commands for ext4 and fat partitions # Expected results are as follows: # EXT4 tests: -# fs-test.sb.ext4.out: Summary: PASS: 24 FAIL: 0 -# fs-test.ext4.out: Summary: PASS: 24 FAIL: 0 -# fs-test.fs.ext4.out: Summary: PASS: 24 FAIL: 0 +# fs-test.sb.ext4 Summary: PASS: 24 FAIL: 0 +# fs-test.nonfs.ext4 Summary: PASS: 24 FAIL: 0 +# fs-test.fs.ext4 Summary: PASS: 24 FAIL: 0 # FAT16 tests: -# fs-test.sb.fat16.out: Summary: PASS: 24 FAIL: 0 -# fs-test.fat16.out: Summary: PASS: 20 FAIL: 4 -# fs-test.fs.fat16.out: Summary: PASS: 20 FAIL: 4 +# fs-test.sb.fat16 Summary: PASS: 24 FAIL: 0 +# fs-test.nonfs.fat16 Summary: PASS: 24 FAIL: 0 +# fs-test.fs.fat16 Summary: PASS: 24 FAIL: 0 # FAT32 tests: -# fs-test.sb.fat32.out: Summary: PASS: 24 FAIL: 0 -# fs-test.fat32.out: Summary: PASS: 20 FAIL: 4 -# fs-test.fs.fat32.out: Summary: PASS: 20 FAIL: 4 -# Total Summary: TOTAL PASS: 200 TOTAL FAIL: 16 +# fs-test.sb.fat32 Summary: PASS: 24 FAIL: 0 +# fs-test.nonfs.fat32 Summary: PASS: 24 FAIL: 0 +# fs-test.fs.fat32 Summary: PASS: 24 FAIL: 0 +# -------------------------------------------- +# Total Summary: TOTAL PASS: 216 TOTAL FAIL: 0 +# -------------------------------------------- # pre-requisite binaries list. PREREQ_BINS="md5sum mkfs mount umount dd fallocate mkdir" @@ -522,7 +524,7 @@ function check_results() { "TC11: 1MB write to $3.w - content verified" # Check lookup of 'dot' directory - grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file' + grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write' pass_fail "TC12: 1MB write to . - write denied" # Check directory traversal diff --git a/test/print_ut.c b/test/print_ut.c index fb46db832e..f0f1d6010a 100644 --- a/test/print_ut.c +++ b/test/print_ut.c @@ -6,8 +6,7 @@ #define DEBUG #include <common.h> -#if defined(CONFIG_EFI_LOADER) && \ - !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) #include <efi_api.h> #endif #include <display_options.h> @@ -19,8 +18,7 @@ /* Test efi_loader specific printing */ static void efi_ut_print(void) { -#if defined(CONFIG_EFI_LOADER) && \ - !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) char str[10]; u8 buf[sizeof(struct efi_device_path_sd_mmc_path) + sizeof(struct efi_device_path)]; diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index 747d52d935..e0833ffe22 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -16,7 +16,7 @@ def test_efi_selftest(u_boot_console): u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False) m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']) if m != 0: - raise Exception('Failures occured during the EFI selftest') + raise Exception('Failures occurred during the EFI selftest') u_boot_console.run_command(cmd='', wait_for_echo=False, wait_for_prompt=False); m = u_boot_console.p.expect(['resetting', 'U-Boot']) if m != 0: @@ -48,3 +48,152 @@ def test_efi_selftest_watchdog_reboot(u_boot_console): if m != 0: raise Exception('Reset failed in \'watchdog reboot\' test') u_boot_console.restart_uboot(); + +@pytest.mark.buildconfigspec('cmd_bootefi_selftest') +def test_efi_selftest_text_input(u_boot_console): + """Test the EFI_SIMPLE_TEXT_INPUT_PROTOCOL + + :param u_boot_console: U-Boot console + + This function calls the text input EFI selftest. + """ + u_boot_console.run_command(cmd='setenv efi_selftest text input') + output = u_boot_console.run_command(cmd='bootefi selftest', + wait_for_prompt=False) + m = u_boot_console.p.expect(['To terminate type \'x\'']) + if m != 0: + raise Exception('No prompt for \'text input\' test') + u_boot_console.drain_console() + u_boot_console.p.timeout = 500 + # EOT + u_boot_console.run_command(cmd=chr(4), wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 4 \(unknown\), scan code 0 \(Null\)']) + if m != 0: + raise Exception('EOT failed in \'text input\' test') + u_boot_console.drain_console() + # BS + u_boot_console.run_command(cmd=chr(8), wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 8 \(BS\), scan code 0 \(Null\)']) + if m != 0: + raise Exception('BS failed in \'text input\' test') + u_boot_console.drain_console() + # TAB + u_boot_console.run_command(cmd=chr(9), wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 9 \(TAB\), scan code 0 \(Null\)']) + if m != 0: + raise Exception('BS failed in \'text input\' test') + u_boot_console.drain_console() + # a + u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False, + wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']) + if m != 0: + raise Exception('\'a\' failed in \'text input\' test') + u_boot_console.drain_console() + # UP escape sequence + u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 0 \(Null\), scan code 1 \(Up\)']) + if m != 0: + raise Exception('UP failed in \'text input\' test') + u_boot_console.drain_console() + # Euro sign + u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect(['Unicode char 8364 \(\'']) + if m != 0: + raise Exception('Euro sign failed in \'text input\' test') + u_boot_console.drain_console() + u_boot_console.run_command(cmd='x', wait_for_echo=False, send_nl=False, + wait_for_prompt=False) + m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']) + if m != 0: + raise Exception('Failures occurred during the EFI selftest') + u_boot_console.restart_uboot(); + +@pytest.mark.buildconfigspec('cmd_bootefi_selftest') +def test_efi_selftest_text_input_ex(u_boot_console): + """Test the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL + + :param u_boot_console: U-Boot console + + This function calls the extended text input EFI selftest. + """ + u_boot_console.run_command(cmd='setenv efi_selftest extended text input') + output = u_boot_console.run_command(cmd='bootefi selftest', + wait_for_prompt=False) + m = u_boot_console.p.expect(['To terminate type \'CTRL\+x\'']) + if m != 0: + raise Exception('No prompt for \'text input\' test') + u_boot_console.drain_console() + u_boot_console.p.timeout = 500 + # EOT + u_boot_console.run_command(cmd=chr(4), wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)']) + if m != 0: + raise Exception('EOT failed in \'text input\' test') + u_boot_console.drain_console() + # BS + u_boot_console.run_command(cmd=chr(8), wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 8 \(BS\), scan code 0 \(\+Null\)']) + if m != 0: + raise Exception('BS failed in \'text input\' test') + u_boot_console.drain_console() + # TAB + u_boot_console.run_command(cmd=chr(9), wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 9 \(TAB\), scan code 0 \(\+Null\)']) + if m != 0: + raise Exception('TAB failed in \'text input\' test') + u_boot_console.drain_console() + # a + u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False, + wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']) + if m != 0: + raise Exception('\'a\' failed in \'text input\' test') + u_boot_console.drain_console() + # UP escape sequence + u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 0 \(Null\), scan code 1 \(\+Up\)']) + if m != 0: + raise Exception('UP failed in \'text input\' test') + u_boot_console.drain_console() + # Euro sign + u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False, + send_nl=False, wait_for_prompt=False) + m = u_boot_console.p.expect(['Unicode char 8364 \(\'']) + if m != 0: + raise Exception('Euro sign failed in \'text input\' test') + u_boot_console.drain_console() + # SHIFT+ALT+FN 5 + u_boot_console.run_command(cmd='\x1b\x5b\x31\x35\x3b\x34\x7e', + wait_for_echo=False, send_nl=False, + wait_for_prompt=False) + m = u_boot_console.p.expect( + ['Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)']) + if m != 0: + raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test') + u_boot_console.drain_console() + u_boot_console.run_command(cmd=chr(24), wait_for_echo=False, send_nl=False, + wait_for_prompt=False) + m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']) + if m != 0: + raise Exception('Failures occurred during the EFI selftest') + u_boot_console.restart_uboot(); diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py new file mode 100644 index 0000000000..6404b311bc --- /dev/null +++ b/test/py/tests/test_fs/conftest.py @@ -0,0 +1,392 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2018, Linaro Limited +# Author: Takahiro Akashi <takahiro.akashi@linaro.org> + +import os +import os.path +import pytest +import re +from subprocess import call, check_call, check_output, CalledProcessError +from fstest_defs import * + +supported_fs_basic = ['fat16', 'fat32', 'ext4'] +supported_fs_ext = ['fat16', 'fat32'] +supported_fs_mkdir = ['fat16', 'fat32'] +supported_fs_unlink = ['fat16', 'fat32'] + +# +# Filesystem test specific setup +# +def pytest_addoption(parser): + parser.addoption('--fs-type', action='append', default=None, + help='Targeting Filesystem Types') + +def pytest_configure(config): + global supported_fs_basic + global supported_fs_ext + global supported_fs_mkdir + global supported_fs_unlink + + def intersect(listA, listB): + return [x for x in listA if x in listB] + + supported_fs = config.getoption('fs_type') + if supported_fs: + print("*** FS TYPE modified: %s" % supported_fs) + supported_fs_basic = intersect(supported_fs, supported_fs_basic) + supported_fs_ext = intersect(supported_fs, supported_fs_ext) + supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir) + supported_fs_unlink = intersect(supported_fs, supported_fs_unlink) + +def pytest_generate_tests(metafunc): + if 'fs_obj_basic' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_basic', supported_fs_basic, + indirect=True, scope='module') + if 'fs_obj_ext' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_ext', supported_fs_ext, + indirect=True, scope='module') + if 'fs_obj_mkdir' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir, + indirect=True, scope='module') + if 'fs_obj_unlink' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_unlink', supported_fs_unlink, + indirect=True, scope='module') + +# +# Helper functions +# +def fstype_to_ubname(fs_type): + if re.match('fat', fs_type): + return 'fat' + else: + return fs_type + +def check_ubconfig(config, fs_type): + if not config.buildconfig.get('config_cmd_%s' % fs_type, None): + pytest.skip('.config feature "CMD_%s" not enabled' % fs_type.upper()) + if not config.buildconfig.get('config_%s_write' % fs_type, None): + pytest.skip('.config feature "%s_WRITE" not enabled' + % fs_type.upper()) + +def mk_fs(config, fs_type, size, id): + fs_img = '%s.%s.img' % (id, fs_type) + fs_img = config.persistent_data_dir + '/' + fs_img + + if fs_type == 'fat16': + mkfs_opt = '-F 16' + elif fs_type == 'fat32': + mkfs_opt = '-F 32' + else: + mkfs_opt = '' + + if re.match('fat', fs_type): + fs_lnxtype = 'vfat' + else: + fs_lnxtype = fs_type + + count = (size + 1048576 - 1) / 1048576 + + try: + check_call('rm -f %s' % fs_img, shell=True) + check_call('dd if=/dev/zero of=%s bs=1M count=%d' + % (fs_img, count), shell=True) + check_call('mkfs.%s %s %s' + % (fs_lnxtype, mkfs_opt, fs_img), shell=True) + return fs_img + except CalledProcessError: + call('rm -f %s' % fs_img, shell=True) + raise + +# from test/py/conftest.py +def tool_is_in_path(tool): + for path in os.environ["PATH"].split(os.pathsep): + fn = os.path.join(path, tool) + if os.path.isfile(fn) and os.access(fn, os.X_OK): + return True + return False + +fuse_mounted = False + +def mount_fs(fs_type, device, mount_point): + global fuse_mounted + + fuse_mounted = False + try: + if tool_is_in_path('guestmount'): + fuse_mounted = True + check_call('guestmount -a %s -m /dev/sda %s' + % (device, mount_point), shell=True) + else: + mount_opt = "loop,rw" + if re.match('fat', fs_type): + mount_opt += ",umask=0000" + + check_call('sudo mount -o %s %s %s' + % (mount_opt, device, mount_point), shell=True) + + # may not be effective for some file systems + check_call('sudo chmod a+rw %s' % mount_point, shell=True) + except CalledProcessError: + raise + +def umount_fs(fs_type, mount_point): + if fuse_mounted: + call('sync') + call('guestunmount %s' % mount_point, shell=True) + else: + call('sudo umount %s' % mount_point, shell=True) + +# +# Fixture for basic fs test +# derived from test/fs/fs-test.sh +# +# NOTE: yield_fixture was deprecated since pytest-3.0 +@pytest.yield_fixture() +def fs_obj_basic(request, u_boot_config): + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + mount_dir = u_boot_config.persistent_data_dir + '/mnt' + + small_file = mount_dir + '/' + SMALL_FILE + big_file = mount_dir + '/' + BIG_FILE + + try: + + # 3GiB volume + fs_img = mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB') + + # Mount the image so we can populate it. + check_call('mkdir -p %s' % mount_dir, shell=True) + mount_fs(fs_type, fs_img, mount_dir) + + # Create a subdirectory. + check_call('mkdir %s/SUBDIR' % mount_dir, shell=True) + + # Create big file in this image. + # Note that we work only on the start 1MB, couple MBs in the 2GB range + # and the last 1 MB of the huge 2.5GB file. + # So, just put random values only in those areas. + check_call('dd if=/dev/urandom of=%s bs=1M count=1' + % big_file, shell=True) + check_call('dd if=/dev/urandom of=%s bs=1M count=2 seek=2047' + % big_file, shell=True) + check_call('dd if=/dev/urandom of=%s bs=1M count=1 seek=2499' + % big_file, shell=True) + + # Create a small file in this image. + check_call('dd if=/dev/urandom of=%s bs=1M count=1' + % small_file, shell=True) + + # Delete the small file copies which possibly are written as part of a + # previous test. + # check_call('rm -f "%s.w"' % MB1, shell=True) + # check_call('rm -f "%s.w2"' % MB1, shell=True) + + # Generate the md5sums of reads that we will test against small file + out = check_output( + 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum' + % small_file, shell=True) + md5val = [ out.split()[0] ] + + # Generate the md5sums of reads that we will test against big file + # One from beginning of file. + out = check_output( + 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum' + % big_file, shell=True) + md5val.append(out.split()[0]) + + # One from end of file. + out = check_output( + 'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum' + % big_file, shell=True) + md5val.append(out.split()[0]) + + # One from the last 1MB chunk of 2GB + out = check_output( + 'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum' + % big_file, shell=True) + md5val.append(out.split()[0]) + + # One from the start 1MB chunk from 2GB + out = check_output( + 'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum' + % big_file, shell=True) + md5val.append(out.split()[0]) + + # One 1MB chunk crossing the 2GB boundary + out = check_output( + 'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum' + % big_file, shell=True) + md5val.append(out.split()[0]) + + umount_fs(fs_type, mount_dir) + except CalledProcessError: + pytest.skip('Setup failed for filesystem: ' + fs_type) + return + else: + yield [fs_ubtype, fs_img, md5val] + finally: + umount_fs(fs_type, mount_dir) + call('rmdir %s' % mount_dir, shell=True) + if fs_img: + call('rm -f %s' % fs_img, shell=True) + +# +# Fixture for extended fs test +# +# NOTE: yield_fixture was deprecated since pytest-3.0 +@pytest.yield_fixture() +def fs_obj_ext(request, u_boot_config): + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + mount_dir = u_boot_config.persistent_data_dir + '/mnt' + + min_file = mount_dir + '/' + MIN_FILE + tmp_file = mount_dir + '/tmpfile' + + try: + + # 128MiB volume + fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') + + # Mount the image so we can populate it. + check_call('mkdir -p %s' % mount_dir, shell=True) + mount_fs(fs_type, fs_img, mount_dir) + + # Create a test directory + check_call('mkdir %s/dir1' % mount_dir, shell=True) + + # Create a small file and calculate md5 + check_call('dd if=/dev/urandom of=%s bs=1K count=20' + % min_file, shell=True) + out = check_output( + 'dd if=%s bs=1K 2> /dev/null | md5sum' + % min_file, shell=True) + md5val = [ out.split()[0] ] + + # Calculate md5sum of Test Case 4 + check_call('dd if=%s of=%s bs=1K count=20' + % (min_file, tmp_file), shell=True) + check_call('dd if=%s of=%s bs=1K seek=5 count=20' + % (min_file, tmp_file), shell=True) + out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum' + % tmp_file, shell=True) + md5val.append(out.split()[0]) + + # Calculate md5sum of Test Case 5 + check_call('dd if=%s of=%s bs=1K count=20' + % (min_file, tmp_file), shell=True) + check_call('dd if=%s of=%s bs=1K seek=5 count=5' + % (min_file, tmp_file), shell=True) + out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum' + % tmp_file, shell=True) + md5val.append(out.split()[0]) + + # Calculate md5sum of Test Case 7 + check_call('dd if=%s of=%s bs=1K count=20' + % (min_file, tmp_file), shell=True) + check_call('dd if=%s of=%s bs=1K seek=20 count=20' + % (min_file, tmp_file), shell=True) + out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum' + % tmp_file, shell=True) + md5val.append(out.split()[0]) + + check_call('rm %s' % tmp_file, shell=True) + umount_fs(fs_type, mount_dir) + except CalledProcessError: + pytest.skip('Setup failed for filesystem: ' + fs_type) + return + else: + yield [fs_ubtype, fs_img, md5val] + finally: + umount_fs(fs_type, mount_dir) + call('rmdir %s' % mount_dir, shell=True) + if fs_img: + call('rm -f %s' % fs_img, shell=True) + +# +# Fixture for mkdir test +# +# NOTE: yield_fixture was deprecated since pytest-3.0 +@pytest.yield_fixture() +def fs_obj_mkdir(request, u_boot_config): + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + try: + # 128MiB volume + fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') + except: + pytest.skip('Setup failed for filesystem: ' + fs_type) + else: + yield [fs_ubtype, fs_img] + finally: + if fs_img: + call('rm -f %s' % fs_img, shell=True) + +# +# Fixture for unlink test +# +# NOTE: yield_fixture was deprecated since pytest-3.0 +@pytest.yield_fixture() +def fs_obj_unlink(request, u_boot_config): + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + mount_dir = u_boot_config.persistent_data_dir + '/mnt' + + try: + + # 128MiB volume + fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') + + # Mount the image so we can populate it. + check_call('mkdir -p %s' % mount_dir, shell=True) + mount_fs(fs_type, fs_img, mount_dir) + + # Test Case 1 & 3 + check_call('mkdir %s/dir1' % mount_dir, shell=True) + check_call('dd if=/dev/urandom of=%s/dir1/file1 bs=1K count=1' + % mount_dir, shell=True) + check_call('dd if=/dev/urandom of=%s/dir1/file2 bs=1K count=1' + % mount_dir, shell=True) + + # Test Case 2 + check_call('mkdir %s/dir2' % mount_dir, shell=True) + for i in range(0, 20): + check_call('mkdir %s/dir2/0123456789abcdef%02x' + % (mount_dir, i), shell=True) + + # Test Case 4 + check_call('mkdir %s/dir4' % mount_dir, shell=True) + + # Test Case 5, 6 & 7 + check_call('mkdir %s/dir5' % mount_dir, shell=True) + check_call('dd if=/dev/urandom of=%s/dir5/file1 bs=1K count=1' + % mount_dir, shell=True) + + umount_fs(fs_type, mount_dir) + except CalledProcessError: + pytest.skip('Setup failed for filesystem: ' + fs_type) + return + else: + yield [fs_ubtype, fs_img] + finally: + umount_fs(fs_type, mount_dir) + call('rmdir %s' % mount_dir, shell=True) + if fs_img: + call('rm -f %s' % fs_img, shell=True) diff --git a/test/py/tests/test_fs/fstest_defs.py b/test/py/tests/test_fs/fstest_defs.py new file mode 100644 index 0000000000..5f107562d9 --- /dev/null +++ b/test/py/tests/test_fs/fstest_defs.py @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0+ + +# $MIN_FILE is the name of the 20KB file in the file system image +MIN_FILE='testfile' + +# $SMALL_FILE is the name of the 1MB file in the file system image +SMALL_FILE='1MB.file' + +# $BIG_FILE is the name of the 2.5GB file in the file system image +BIG_FILE='2.5GB.file' + +ADDR=0x01000008 +LENGTH=0x00100000 diff --git a/test/py/tests/test_fs/test_basic.py b/test/py/tests/test_fs/test_basic.py new file mode 100644 index 0000000000..c067cc9ba3 --- /dev/null +++ b/test/py/tests/test_fs/test_basic.py @@ -0,0 +1,287 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2018, Linaro Limited +# Author: Takahiro Akashi <takahiro.akashi@linaro.org> +# +# U-Boot File System:Basic Test + +""" +This test verifies basic read/write operation on file system. +""" + +import pytest +import re +from fstest_defs import * + +@pytest.mark.boardspec('sandbox') +class TestFsBasic(object): + def test_fs1(self, u_boot_console, fs_obj_basic): + """ + Test Case 1 - ls command, listing a root directory and invalid directory + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 1a - ls'): + # Test Case 1 - ls + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sls host 0:0' % fs_type]) + assert(re.search('2621440000 *%s' % BIG_FILE, ''.join(output))) + assert(re.search('1048576 *%s' % SMALL_FILE, ''.join(output))) + + with u_boot_console.log.section('Test Case 1b - ls (invalid dir)'): + # In addition, test with a nonexistent directory to see if we crash. + output = u_boot_console.run_command( + '%sls host 0:0 invalid_d' % fs_type) + if fs_type == 'ext4': + assert('Can not find directory' in output) + else: + assert('' == output) + + def test_fs2(self, u_boot_console, fs_obj_basic): + """ + Test Case 2 - size command for a small file + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 2a - size (small)'): + # 1MB is 0x0010 0000 + # Test Case 2a - size of small file + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%ssize host 0:0 /%s' % (fs_type, SMALL_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=100000' in ''.join(output)) + + with u_boot_console.log.section('Test Case 2b - size (/../<file>)'): + # Test Case 2b - size of small file via a path using '..' + output = u_boot_console.run_command_list([ + '%ssize host 0:0 /SUBDIR/../%s' % (fs_type, SMALL_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=100000' in ''.join(output)) + + def test_fs3(self, u_boot_console, fs_obj_basic): + """ + Test Case 3 - size command for a large file + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 3 - size (large)'): + # 2.5GB (1024*1024*2500) is 0x9C40 0000 + # Test Case 3 - size of big file + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%ssize host 0:0 /%s' % (fs_type, BIG_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=9c400000' in ''.join(output)) + + def test_fs4(self, u_boot_console, fs_obj_basic): + """ + Test Case 4 - load a small file, 1MB + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 4 - load (small)'): + # Test Case 4a - Read full 1MB of small file + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 4b - Read full 1MB of small file + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + + def test_fs5(self, u_boot_console, fs_obj_basic): + """ + Test Case 5 - load, reading first 1MB of 3GB file + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 5 - load (first 1MB)'): + # Test Case 5a - First 1MB of big file + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s %x 0x0' % (fs_type, ADDR, BIG_FILE, LENGTH), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 5b - First 1MB of big file + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[1] in ''.join(output)) + + def test_fs6(self, u_boot_console, fs_obj_basic): + """ + Test Case 6 - load, reading last 1MB of 3GB file + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 6 - load (last 1MB)'): + # fails for ext as no offset support + # Test Case 6a - Last 1MB of big file + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s %x 0x9c300000' + % (fs_type, ADDR, BIG_FILE, LENGTH), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 6b - Last 1MB of big file + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[2] in ''.join(output)) + + def test_fs7(self, u_boot_console, fs_obj_basic): + """ + Test Case 7 - load, 1MB from the last 1MB in 2GB + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 7 - load (last 1MB in 2GB)'): + # fails for ext as no offset support + # Test Case 7a - One from the last 1MB chunk of 2GB + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s %x 0x7ff00000' + % (fs_type, ADDR, BIG_FILE, LENGTH), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 7b - One from the last 1MB chunk of 2GB + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[3] in ''.join(output)) + + def test_fs8(self, u_boot_console, fs_obj_basic): + """ + Test Case 8 - load, reading first 1MB in 2GB + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 8 - load (first 1MB in 2GB)'): + # fails for ext as no offset support + # Test Case 8a - One from the start 1MB chunk from 2GB + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s %x 0x80000000' + % (fs_type, ADDR, BIG_FILE, LENGTH), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 8b - One from the start 1MB chunk from 2GB + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[4] in ''.join(output)) + + def test_fs9(self, u_boot_console, fs_obj_basic): + """ + Test Case 9 - load, 1MB crossing 2GB boundary + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 9 - load (crossing 2GB boundary)'): + # fails for ext as no offset support + # Test Case 9a - One 1MB chunk crossing the 2GB boundary + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s %x 0x7ff80000' + % (fs_type, ADDR, BIG_FILE, LENGTH), + 'printenv filesize']) + assert('filesize=100000' in ''.join(output)) + + # Test Case 9b - One 1MB chunk crossing the 2GB boundary + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[5] in ''.join(output)) + + def test_fs10(self, u_boot_console, fs_obj_basic): + """ + Test Case 10 - load, reading beyond file end'): + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 10 - load (beyond file end)'): + # Generic failure case + # Test Case 10 - 2MB chunk from the last 1MB of big file + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s 0x00200000 0x9c300000' + % (fs_type, ADDR, BIG_FILE), + 'printenv filesize', + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert('filesize=100000' in ''.join(output)) + + def test_fs11(self, u_boot_console, fs_obj_basic): + """ + Test Case 11 - write' + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 11 - write'): + # Read 1MB from small file + # Write it back to test the writes + # Test Case 11a - Check that the write succeeded + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE), + '%swrite host 0:0 %x /%s.w $filesize' + % (fs_type, ADDR, SMALL_FILE)]) + assert('1048576 bytes written' in ''.join(output)) + + # Test Case 11b - Check md5 of written to is same + # as the one read from + output = u_boot_console.run_command_list([ + '%sload host 0:0 %x /%s.w' % (fs_type, ADDR, SMALL_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + + def test_fs12(self, u_boot_console, fs_obj_basic): + """ + Test Case 12 - write to "." directory + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 12 - write (".")'): + # Next test case checks writing a file whose dirent + # is the first in the block, which is always true for "." + # The write should fail, but the lookup should work + # Test Case 12 - Check directory traversal + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)]) + assert('Unable to write' in ''.join(output)) + + def test_fs13(self, u_boot_console, fs_obj_basic): + """ + Test Case 13 - write to a file with "/./<filename>" + """ + fs_type,fs_img,md5val = fs_obj_basic + with u_boot_console.log.section('Test Case 13 - write ("./<file>")'): + # Read 1MB from small file + # Write it via "same directory", i.e. "." dirent + # Test Case 13a - Check directory traversal + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE), + '%swrite host 0:0 %x /./%s2 $filesize' + % (fs_type, ADDR, SMALL_FILE)]) + assert('1048576 bytes written' in ''.join(output)) + + # Test Case 13b - Check md5 of written to is same + # as the one read from + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x /./%s2' % (fs_type, ADDR, SMALL_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + + # Test Case 13c - Check md5 of written to is same + # as the one read from + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x /%s2' % (fs_type, ADDR, SMALL_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py new file mode 100644 index 0000000000..38217d08bf --- /dev/null +++ b/test/py/tests/test_fs/test_ext.py @@ -0,0 +1,224 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2018, Linaro Limited +# Author: Takahiro Akashi <takahiro.akashi@linaro.org> +# +# U-Boot File System:Exntented Test + +""" +This test verifies extended write operation on file system. +""" + +import pytest +import re +from fstest_defs import * + +@pytest.mark.boardspec('sandbox') +class TestFsExt(object): + def test_fs_ext1(self, u_boot_console, fs_obj_ext): + """ + Test Case 1 - write a file with absolute path + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 1 - write with abs path'): + # Test Case 1a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w1 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + assert('20480 bytes written' in ''.join(output)) + + # Test Case 1b - Check md5 of file content + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x /dir1/%s.w1' % (fs_type, ADDR, MIN_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + + def test_fs_ext2(self, u_boot_console, fs_obj_ext): + """ + Test Case 2 - write to a file with relative path + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 2 - write with rel path'): + # Test Case 2a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x dir1/%s.w2 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + assert('20480 bytes written' in ''.join(output)) + + # Test Case 2b - Check md5 of file content + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x dir1/%s.w2' % (fs_type, ADDR, MIN_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[0] in ''.join(output)) + + def test_fs_ext3(self, u_boot_console, fs_obj_ext): + """ + Test Case 3 - write to a file with invalid path + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 3 - write with invalid path'): + # Test Case 3 - Check if command expectedly failed + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/none/%s.w3 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + assert('Unable to write "/dir1/none/' in ''.join(output)) + + def test_fs_ext4(self, u_boot_console, fs_obj_ext): + """ + Test Case 4 - write at non-zero offset, enlarging file size + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 4 - write at non-zero offset, enlarging file size'): + # Test Case 4a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w4 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + output = u_boot_console.run_command( + '%swrite host 0:0 %x /dir1/%s.w4 $filesize 0x1400' + % (fs_type, ADDR, MIN_FILE)) + assert('20480 bytes written' in output) + + # Test Case 4b - Check size of written file + output = u_boot_console.run_command_list([ + '%ssize host 0:0 /dir1/%s.w4' % (fs_type, MIN_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=6400' in ''.join(output)) + + # Test Case 4c - Check md5 of file content + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x /dir1/%s.w4' % (fs_type, ADDR, MIN_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[1] in ''.join(output)) + + def test_fs_ext5(self, u_boot_console, fs_obj_ext): + """ + Test Case 5 - write at non-zero offset, shrinking file size + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 5 - write at non-zero offset, shrinking file size'): + # Test Case 5a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w5 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + output = u_boot_console.run_command( + '%swrite host 0:0 %x /dir1/%s.w5 0x1400 0x1400' + % (fs_type, ADDR, MIN_FILE)) + assert('5120 bytes written' in output) + + # Test Case 5b - Check size of written file + output = u_boot_console.run_command_list([ + '%ssize host 0:0 /dir1/%s.w5' % (fs_type, MIN_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=2800' in ''.join(output)) + + # Test Case 5c - Check md5 of file content + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x /dir1/%s.w5' % (fs_type, ADDR, MIN_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[2] in ''.join(output)) + + def test_fs_ext6(self, u_boot_console, fs_obj_ext): + """ + Test Case 6 - write nothing at the start, truncating to zero + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 6 - write nothing at the start, truncating to zero'): + # Test Case 6a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w6 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + output = u_boot_console.run_command( + '%swrite host 0:0 %x /dir1/%s.w6 0 0' + % (fs_type, ADDR, MIN_FILE)) + assert('0 bytes written' in output) + + # Test Case 6b - Check size of written file + output = u_boot_console.run_command_list([ + '%ssize host 0:0 /dir1/%s.w6' % (fs_type, MIN_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=0' in ''.join(output)) + + def test_fs_ext7(self, u_boot_console, fs_obj_ext): + """ + Test Case 7 - write at the end (append) + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 7 - write at the end (append)'): + # Test Case 7a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w7 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + output = u_boot_console.run_command( + '%swrite host 0:0 %x /dir1/%s.w7 $filesize $filesize' + % (fs_type, ADDR, MIN_FILE)) + assert('20480 bytes written' in output) + + # Test Case 7b - Check size of written file + output = u_boot_console.run_command_list([ + '%ssize host 0:0 /dir1/%s.w7' % (fs_type, MIN_FILE), + 'printenv filesize', + 'setenv filesize']) + assert('filesize=a000' in ''.join(output)) + + # Test Case 7c - Check md5 of file content + output = u_boot_console.run_command_list([ + 'mw.b %x 00 100' % ADDR, + '%sload host 0:0 %x /dir1/%s.w7' % (fs_type, ADDR, MIN_FILE), + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val[3] in ''.join(output)) + + def test_fs_ext8(self, u_boot_console, fs_obj_ext): + """ + Test Case 8 - write at offset beyond the end of file + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 8 - write beyond the end'): + # Test Case 8a - Check if command expectedly failed + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w8 $filesize' + % (fs_type, ADDR, MIN_FILE)]) + output = u_boot_console.run_command( + '%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x' + % (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400)) + assert('Unable to write "/dir1' in output) + + def test_fs_ext9(self, u_boot_console, fs_obj_ext): + """ + Test Case 9 - write to a non-existing file at non-zero offset + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 9 - write to non-existing file with non-zero offset'): + # Test Case 9a - Check if command expectedly failed + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE), + '%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400' + % (fs_type, ADDR, MIN_FILE)]) + assert('Unable to write "/dir1' in ''.join(output)) diff --git a/test/py/tests/test_fs/test_mkdir.py b/test/py/tests/test_fs/test_mkdir.py new file mode 100644 index 0000000000..d9da97b56b --- /dev/null +++ b/test/py/tests/test_fs/test_mkdir.py @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2018, Linaro Limited +# Author: Takahiro Akashi <takahiro.akashi@linaro.org> +# +# U-Boot File System:mkdir Test + +""" +This test verifies mkdir operation on file system. +""" + +import pytest + +@pytest.mark.boardspec('sandbox') +class TestMkdir(object): + def test_mkdir1(self, u_boot_console, fs_obj_mkdir): + """ + Test Case 1 - create a directory under a root + """ + fs_type,fs_img = fs_obj_mkdir + with u_boot_console.log.section('Test Case 1 - mkdir'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%smkdir host 0:0 dir1' % fs_type, + '%sls host 0:0 /' % fs_type]) + assert('dir1/' in ''.join(output)) + + output = u_boot_console.run_command( + '%sls host 0:0 dir1' % fs_type) + assert('./' in output) + assert('../' in output) + + def test_mkdir2(self, u_boot_console, fs_obj_mkdir): + """ + Test Case 2 - create a directory under a sub-directory + """ + fs_type,fs_img = fs_obj_mkdir + with u_boot_console.log.section('Test Case 2 - mkdir (sub-sub directory)'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%smkdir host 0:0 dir1/dir2' % fs_type, + '%sls host 0:0 dir1' % fs_type]) + assert('dir2/' in ''.join(output)) + + output = u_boot_console.run_command( + '%sls host 0:0 dir1/dir2' % fs_type) + assert('./' in output) + assert('../' in output) + + def test_mkdir3(self, u_boot_console, fs_obj_mkdir): + """ + Test Case 3 - trying to create a directory with a non-existing + path should fail + """ + fs_type,fs_img = fs_obj_mkdir + with u_boot_console.log.section('Test Case 3 - mkdir (non-existing path)'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%smkdir host 0:0 none/dir3' % fs_type]) + assert('Unable to create a directory' in ''.join(output)) + + def test_mkdir4(self, u_boot_console, fs_obj_mkdir): + """ + Test Case 4 - trying to create "." should fail + """ + fs_type,fs_img = fs_obj_mkdir + with u_boot_console.log.section('Test Case 4 - mkdir (".")'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%smkdir host 0:0 .' % fs_type]) + assert('Unable to create a directory' in ''.join(output)) + + def test_mkdir5(self, u_boot_console, fs_obj_mkdir): + """ + Test Case 5 - trying to create ".." should fail + """ + fs_type,fs_img = fs_obj_mkdir + with u_boot_console.log.section('Test Case 5 - mkdir ("..")'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%smkdir host 0:0 ..' % fs_type]) + assert('Unable to create a directory' in ''.join(output)) + + def test_mkdir6(self, u_boot_console, fs_obj_mkdir): + """ + 'Test Case 6 - create as many directories as amount of directory + entries goes beyond a cluster size)' + """ + fs_type,fs_img = fs_obj_mkdir + with u_boot_console.log.section('Test Case 6 - mkdir (create many)'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%smkdir host 0:0 dir6' % fs_type, + '%sls host 0:0 /' % fs_type]) + assert('dir6/' in ''.join(output)) + + for i in range(0, 20): + output = u_boot_console.run_command( + '%smkdir host 0:0 dir6/0123456789abcdef%02x' + % (fs_type, i)) + output = u_boot_console.run_command('%sls host 0:0 dir6' % fs_type) + assert('0123456789abcdef00/' in output) + assert('0123456789abcdef13/' in output) + + output = u_boot_console.run_command( + '%sls host 0:0 dir6/0123456789abcdef13/.' % fs_type) + assert('./' in output) + assert('../' in output) + + output = u_boot_console.run_command( + '%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type) + assert('0123456789abcdef00/' in output) + assert('0123456789abcdef13/' in output) diff --git a/test/py/tests/test_fs/test_unlink.py b/test/py/tests/test_fs/test_unlink.py new file mode 100644 index 0000000000..69c1a6e078 --- /dev/null +++ b/test/py/tests/test_fs/test_unlink.py @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2018, Linaro Limited +# Author: Takahiro Akashi <takahiro.akashi@linaro.org> +# +# U-Boot File System:unlink Test + +""" +This test verifies unlink operation (deleting a file or a directory) +on file system. +""" + +import pytest + +@pytest.mark.boardspec('sandbox') +class TestUnlink(object): + def test_unlink1(self, u_boot_console, fs_obj_unlink): + """ + Test Case 1 - delete a file + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 1 - unlink (file)'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%srm host 0:0 dir1/file1' % fs_type, + '%sls host 0:0 dir1/file1' % fs_type]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command( + '%sls host 0:0 dir1/' % fs_type) + assert(not 'file1' in output) + assert('file2' in output) + + def test_unlink2(self, u_boot_console, fs_obj_unlink): + """ + Test Case 2 - delete many files + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 2 - unlink (many)'): + output = u_boot_console.run_command('host bind 0 %s' % fs_img) + + for i in range(0, 20): + output = u_boot_console.run_command_list([ + '%srm host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i), + '%sls host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i)]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command( + '%sls host 0:0 dir2' % fs_type) + assert('0 file(s), 2 dir(s)' in output) + + def test_unlink3(self, u_boot_console, fs_obj_unlink): + """ + Test Case 3 - trying to delete a non-existing file should fail + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 3 - unlink (non-existing)'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%srm host 0:0 dir1/nofile' % fs_type]) + assert('nofile: doesn\'t exist' in ''.join(output)) + + def test_unlink4(self, u_boot_console, fs_obj_unlink): + """ + Test Case 4 - delete an empty directory + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 4 - unlink (directory)'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%srm host 0:0 dir4' % fs_type]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command( + '%sls host 0:0 /' % fs_type) + assert(not 'dir4' in output) + + def test_unlink5(self, u_boot_console, fs_obj_unlink): + """ + Test Case 5 - trying to deleting a non-empty directory ".." + should fail + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 5 - unlink ("non-empty directory")'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%srm host 0:0 dir5' % fs_type]) + assert('directory is not empty' in ''.join(output)) + + def test_unlink6(self, u_boot_console, fs_obj_unlink): + """ + Test Case 6 - trying to deleting a "." should fail + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 6 - unlink (".")'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%srm host 0:0 dir5/.' % fs_type]) + assert('directory is not empty' in ''.join(output)) + + def test_unlink7(self, u_boot_console, fs_obj_unlink): + """ + Test Case 7 - trying to deleting a ".." should fail + """ + fs_type,fs_img = fs_obj_unlink + with u_boot_console.log.section('Test Case 7 - unlink ("..")'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%srm host 0:0 dir5/..' % fs_type]) + assert('directory is not empty' in ''.join(output)) diff --git a/test/unicode_ut.c b/test/unicode_ut.c new file mode 100644 index 0000000000..b115d18afd --- /dev/null +++ b/test/unicode_ut.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Unit tests for Unicode functions + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <common.h> +#include <charset.h> +#include <command.h> +#include <errno.h> +#include <test/test.h> +#include <test/suites.h> +#include <test/ut.h> + +/* Linker list entry for a Unicode test */ +#define UNICODE_TEST(_name) UNIT_TEST(_name, 0, unicode_test) + +/* Constants c1-c4 and d1-d4 encode the same letters */ + +/* Six characters translating to one utf-8 byte each. */ +static const u16 c1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00}; +/* One character translating to two utf-8 bytes */ +static const u16 c2[] = {0x6b, 0x61, 0x66, 0x62, 0xe1, 0x74, 0x75, 0x72, 0x00}; +/* Three characters translating to three utf-8 bytes each */ +static const u16 c3[] = {0x6f5c, 0x6c34, 0x8266, 0x00}; +/* Three letters translating to four utf-8 bytes each */ +static const u16 c4[] = {0xd801, 0xdc8d, 0xd801, 0xdc96, 0xd801, 0xdc87, + 0x0000}; + +/* Illegal utf-16 strings */ +static const u16 i1[] = {0x69, 0x31, 0xdc87, 0x6c, 0x00}; +static const u16 i2[] = {0x69, 0x32, 0xd801, 0xd801, 0x6c, 0x00}; +static const u16 i3[] = {0x69, 0x33, 0xd801, 0x00}; + +/* Six characters translating to one utf-16 word each. */ +static const char d1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00}; +/* Eight characters translating to one utf-16 word each */ +static const char d2[] = {0x6b, 0x61, 0x66, 0x62, 0xc3, 0xa1, 0x74, 0x75, + 0x72, 0x00}; +/* Three characters translating to one utf-16 word each */ +static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89, + 0xa6, 0x00}; +/* Three letters translating to two utf-16 word each */ +static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96, + 0xf0, 0x90, 0x92, 0x87, 0x00}; + +/* Illegal utf-8 strings */ +static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00}; +static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00}; +static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00}; + +/* U-Boot uses UTF-16 strings in the EFI context only. */ +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) +static int ut_string16(struct unit_test_state *uts) +{ + char buf[20]; + + /* Test length and precision */ + memset(buf, 0xff, sizeof(buf)); + sprintf(buf, "%8.6ls", c2); + ut_asserteq(' ', buf[1]); + ut_assert(!strncmp(&buf[2], d2, 7)); + ut_assert(!buf[9]); + + memset(buf, 0xff, sizeof(buf)); + sprintf(buf, "%8.6ls", c4); + ut_asserteq(' ', buf[4]); + ut_assert(!strncmp(&buf[5], d4, 12)); + ut_assert(!buf[17]); + + memset(buf, 0xff, sizeof(buf)); + sprintf(buf, "%-8.2ls", c4); + ut_asserteq(' ', buf[8]); + ut_assert(!strncmp(buf, d4, 8)); + ut_assert(!buf[14]); + + /* Test handling of illegal utf-16 sequences */ + memset(buf, 0xff, sizeof(buf)); + sprintf(buf, "%ls", i1); + ut_asserteq_str("i1?l", buf); + + memset(buf, 0xff, sizeof(buf)); + sprintf(buf, "%ls", i2); + ut_asserteq_str("i2?l", buf); + + memset(buf, 0xff, sizeof(buf)); + sprintf(buf, "%ls", i3); + ut_asserteq_str("i3?", buf); + + return 0; +} +UNICODE_TEST(ut_string16); +#endif + +static int ut_utf8_get(struct unit_test_state *uts) +{ + const char *s; + s32 code; + int i; + + /* Check characters less than 0x800 */ + s = d2; + for (i = 0; i < 8; ++i) { + code = utf8_get((const char **)&s); + /* c2 is the utf-8 encoding of d2 */ + ut_asserteq(c2[i], code); + if (!code) + break; + } + ut_asserteq_ptr(s, d2 + 9) + + /* Check characters less than 0x10000 */ + s = d3; + for (i = 0; i < 4; ++i) { + code = utf8_get((const char **)&s); + /* c3 is the utf-8 encoding of d3 */ + ut_asserteq(c3[i], code); + if (!code) + break; + } + ut_asserteq_ptr(s, d3 + 9) + + /* Check character greater 0xffff */ + s = d4; + code = utf8_get((const char **)&s); + ut_asserteq(0x0001048d, code); + ut_asserteq_ptr(s, d4 + 4); + + return 0; +} +UNICODE_TEST(ut_utf8_get); + +static int ut_utf8_put(struct unit_test_state *uts) +{ + char buffer[8] = { 0, }; + char *pos; + + /* Commercial at, translates to one character */ + pos = buffer; + ut_assert(!utf8_put('@', &pos)) + ut_asserteq(1, pos - buffer); + ut_asserteq('@', buffer[0]); + ut_assert(!buffer[1]); + + /* Latin letter G with acute, translates to two charactes */ + pos = buffer; + ut_assert(!utf8_put(0x1f4, &pos)); + ut_asserteq(2, pos - buffer); + ut_asserteq_str("\xc7\xb4", buffer); + + /* Tagalog letter i, translates to three characters */ + pos = buffer; + ut_assert(!utf8_put(0x1701, &pos)); + ut_asserteq(3, pos - buffer); + ut_asserteq_str("\xe1\x9c\x81", buffer); + + /* Hamster face, translates to four characters */ + pos = buffer; + ut_assert(!utf8_put(0x1f439, &pos)); + ut_asserteq(4, pos - buffer); + ut_asserteq_str("\xf0\x9f\x90\xb9", buffer); + + /* Illegal code */ + pos = buffer; + ut_asserteq(-1, utf8_put(0xd888, &pos)); + + return 0; +} +UNICODE_TEST(ut_utf8_put); + +static int ut_utf8_utf16_strlen(struct unit_test_state *uts) +{ + ut_asserteq(6, utf8_utf16_strlen(d1)); + ut_asserteq(8, utf8_utf16_strlen(d2)); + ut_asserteq(3, utf8_utf16_strlen(d3)); + ut_asserteq(6, utf8_utf16_strlen(d4)); + + /* illegal utf-8 sequences */ + ut_asserteq(4, utf8_utf16_strlen(j1)); + ut_asserteq(4, utf8_utf16_strlen(j2)); + ut_asserteq(3, utf8_utf16_strlen(j3)); + + return 0; +} +UNICODE_TEST(ut_utf8_utf16_strlen); + +static int ut_utf8_utf16_strnlen(struct unit_test_state *uts) +{ + ut_asserteq(3, utf8_utf16_strnlen(d1, 3)); + ut_asserteq(6, utf8_utf16_strnlen(d1, 13)); + ut_asserteq(6, utf8_utf16_strnlen(d2, 6)); + ut_asserteq(2, utf8_utf16_strnlen(d3, 2)); + ut_asserteq(4, utf8_utf16_strnlen(d4, 2)); + ut_asserteq(6, utf8_utf16_strnlen(d4, 3)); + + /* illegal utf-8 sequences */ + ut_asserteq(4, utf8_utf16_strnlen(j1, 16)); + ut_asserteq(4, utf8_utf16_strnlen(j2, 16)); + ut_asserteq(3, utf8_utf16_strnlen(j3, 16)); + + return 0; +} +UNICODE_TEST(ut_utf8_utf16_strnlen); + +/** + * ut_u16_strcmp() - Compare to u16 strings. + * + * @a1: first string + * @a2: second string + * @count: number of u16 to compare + * Return: -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2 + */ +static int ut_u16_strcmp(const u16 *a1, const u16 *a2, size_t count) +{ + for (; (*a1 || *a2) && count; ++a1, ++a2, --count) { + if (*a1 < *a2) + return -1; + if (*a1 > *a2) + return 1; + } + return 0; +} + +static int ut_utf8_utf16_strcpy(struct unit_test_state *uts) +{ + u16 buf[16]; + u16 *pos; + + pos = buf; + utf8_utf16_strcpy(&pos, d1); + ut_asserteq(6, pos - buf); + ut_assert(!ut_u16_strcmp(buf, c1, SIZE_MAX)); + + pos = buf; + utf8_utf16_strcpy(&pos, d2); + ut_asserteq(8, pos - buf); + ut_assert(!ut_u16_strcmp(buf, c2, SIZE_MAX)); + + pos = buf; + utf8_utf16_strcpy(&pos, d3); + ut_asserteq(3, pos - buf); + ut_assert(!ut_u16_strcmp(buf, c3, SIZE_MAX)); + + pos = buf; + utf8_utf16_strcpy(&pos, d4); + ut_asserteq(6, pos - buf); + ut_assert(!ut_u16_strcmp(buf, c4, SIZE_MAX)); + + /* Illegal utf-8 strings */ + pos = buf; + utf8_utf16_strcpy(&pos, j1); + ut_asserteq(4, pos - buf); + ut_assert(!ut_u16_strcmp(buf, L"j1?l", SIZE_MAX)); + + pos = buf; + utf8_utf16_strcpy(&pos, j2); + ut_asserteq(4, pos - buf); + ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX)); + + pos = buf; + utf8_utf16_strcpy(&pos, j3); + ut_asserteq(3, pos - buf); + ut_assert(!ut_u16_strcmp(buf, L"j3?", SIZE_MAX)); + + return 0; +} +UNICODE_TEST(ut_utf8_utf16_strcpy); + +int ut_utf8_utf16_strncpy(struct unit_test_state *uts) +{ + u16 buf[16]; + u16 *pos; + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf8_utf16_strncpy(&pos, d1, 4); + ut_asserteq(4, pos - buf); + ut_assert(!buf[4]); + ut_assert(!ut_u16_strcmp(buf, c1, 4)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf8_utf16_strncpy(&pos, d2, 10); + ut_asserteq(8, pos - buf); + ut_assert(buf[4]); + ut_assert(!ut_u16_strcmp(buf, c2, SIZE_MAX)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf8_utf16_strncpy(&pos, d3, 2); + ut_asserteq(2, pos - buf); + ut_assert(!buf[2]); + ut_assert(!ut_u16_strcmp(buf, c3, 2)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf8_utf16_strncpy(&pos, d4, 2); + ut_asserteq(4, pos - buf); + ut_assert(!buf[4]); + ut_assert(!ut_u16_strcmp(buf, c4, 4)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf8_utf16_strncpy(&pos, d4, 10); + ut_asserteq(6, pos - buf); + ut_assert(buf[5]); + ut_assert(!ut_u16_strcmp(buf, c4, SIZE_MAX)); + + return 0; +} +UNICODE_TEST(ut_utf8_utf16_strncpy); + +static int ut_utf16_get(struct unit_test_state *uts) +{ + const u16 *s; + s32 code; + int i; + + /* Check characters less than 0x10000 */ + s = c2; + for (i = 0; i < 9; ++i) { + code = utf16_get((const u16 **)&s); + ut_asserteq(c2[i], code); + if (!code) + break; + } + ut_asserteq_ptr(c2 + 8, s); + + /* Check character greater 0xffff */ + s = c4; + code = utf16_get((const u16 **)&s); + ut_asserteq(0x0001048d, code); + ut_asserteq_ptr(c4 + 2, s); + + return 0; +} +UNICODE_TEST(ut_utf16_get); + +static int ut_utf16_put(struct unit_test_state *uts) +{ + u16 buffer[4] = { 0, }; + u16 *pos; + + /* Commercial at, translates to one word */ + pos = buffer; + ut_assert(!utf16_put('@', &pos)); + ut_asserteq(1, pos - buffer); + ut_asserteq((u16)'@', buffer[0]); + ut_assert(!buffer[1]); + + /* Hamster face, translates to two words */ + pos = buffer; + ut_assert(!utf16_put(0x1f439, &pos)); + ut_asserteq(2, pos - buffer); + ut_asserteq((u16)0xd83d, buffer[0]); + ut_asserteq((u16)0xdc39, buffer[1]); + ut_assert(!buffer[2]); + + /* Illegal code */ + pos = buffer; + ut_asserteq(-1, utf16_put(0xd888, &pos)); + + return 0; +} +UNICODE_TEST(ut_utf16_put); + +int ut_utf16_strnlen(struct unit_test_state *uts) +{ + ut_asserteq(3, utf16_strnlen(c1, 3)); + ut_asserteq(6, utf16_strnlen(c1, 13)); + ut_asserteq(6, utf16_strnlen(c2, 6)); + ut_asserteq(2, utf16_strnlen(c3, 2)); + ut_asserteq(2, utf16_strnlen(c4, 2)); + ut_asserteq(3, utf16_strnlen(c4, 3)); + + /* illegal utf-16 word sequences */ + ut_asserteq(4, utf16_strnlen(i1, 16)); + ut_asserteq(4, utf16_strnlen(i2, 16)); + ut_asserteq(3, utf16_strnlen(i3, 16)); + + return 0; +} +UNICODE_TEST(ut_utf16_strnlen); + +int ut_utf16_utf8_strlen(struct unit_test_state *uts) +{ + ut_asserteq(6, utf16_utf8_strlen(c1)); + ut_asserteq(9, utf16_utf8_strlen(c2)); + ut_asserteq(9, utf16_utf8_strlen(c3)); + ut_asserteq(12, utf16_utf8_strlen(c4)); + + /* illegal utf-16 word sequences */ + ut_asserteq(4, utf16_utf8_strlen(i1)); + ut_asserteq(4, utf16_utf8_strlen(i2)); + ut_asserteq(3, utf16_utf8_strlen(i3)); + + return 0; +} +UNICODE_TEST(ut_utf16_utf8_strlen); + +int ut_utf16_utf8_strnlen(struct unit_test_state *uts) +{ + ut_asserteq(3, utf16_utf8_strnlen(c1, 3)); + ut_asserteq(6, utf16_utf8_strnlen(c1, 13)); + ut_asserteq(7, utf16_utf8_strnlen(c2, 6)); + ut_asserteq(6, utf16_utf8_strnlen(c3, 2)); + ut_asserteq(8, utf16_utf8_strnlen(c4, 2)); + ut_asserteq(12, utf16_utf8_strnlen(c4, 3)); + return 0; +} +UNICODE_TEST(ut_utf16_utf8_strnlen); + +int ut_utf16_utf8_strcpy(struct unit_test_state *uts) +{ + char buf[16]; + char *pos; + + pos = buf; + utf16_utf8_strcpy(&pos, c1); + ut_asserteq(6, pos - buf); + ut_asserteq_str(d1, buf); + + pos = buf; + utf16_utf8_strcpy(&pos, c2); + ut_asserteq(9, pos - buf); + ut_asserteq_str(d2, buf); + + pos = buf; + utf16_utf8_strcpy(&pos, c3); + ut_asserteq(9, pos - buf); + ut_asserteq_str(d3, buf); + + pos = buf; + utf16_utf8_strcpy(&pos, c4); + ut_asserteq(12, pos - buf); + ut_asserteq_str(d4, buf); + + /* Illegal utf-16 strings */ + pos = buf; + utf16_utf8_strcpy(&pos, i1); + ut_asserteq(4, pos - buf); + ut_asserteq_str("i1?l", buf); + + pos = buf; + utf16_utf8_strcpy(&pos, i2); + ut_asserteq(4, pos - buf); + ut_asserteq_str("i2?l", buf); + + pos = buf; + utf16_utf8_strcpy(&pos, i3); + ut_asserteq(3, pos - buf); + ut_asserteq_str("i3?", buf); + + return 0; +} +UNICODE_TEST(ut_utf16_utf8_strcpy); + +int ut_utf16_utf8_strncpy(struct unit_test_state *uts) +{ + char buf[16]; + char *pos; + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf16_utf8_strncpy(&pos, c1, 4); + ut_asserteq(4, pos - buf); + ut_assert(!buf[4]); + ut_assert(!strncmp(buf, d1, 4)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf16_utf8_strncpy(&pos, c2, 10); + ut_asserteq(9, pos - buf); + ut_assert(buf[4]); + ut_assert(!strncmp(buf, d2, SIZE_MAX)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf16_utf8_strncpy(&pos, c3, 2); + ut_asserteq(6, pos - buf); + ut_assert(!buf[6]); + ut_assert(!strncmp(buf, d3, 6)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf16_utf8_strncpy(&pos, c4, 2); + ut_asserteq(8, pos - buf); + ut_assert(!buf[8]); + ut_assert(!strncmp(buf, d4, 8)); + + pos = buf; + memset(buf, 0, sizeof(buf)); + utf16_utf8_strncpy(&pos, c4, 10); + ut_asserteq(12, pos - buf); + ut_assert(buf[5]); + ut_assert(!strncmp(buf, d4, SIZE_MAX)); + + return 0; +} +UNICODE_TEST(ut_utf16_utf8_strncpy); + +int ut_utf_to_lower(struct unit_test_state *uts) +{ + ut_asserteq('@', utf_to_lower('@')); + ut_asserteq('a', utf_to_lower('A')); + ut_asserteq('z', utf_to_lower('Z')); + ut_asserteq('[', utf_to_lower('[')); + ut_asserteq('m', utf_to_lower('m')); + /* Latin letter O with diaresis (umlaut) */ + ut_asserteq(0x00f6, utf_to_lower(0x00d6)); +#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION + /* Cyrillic letter I*/ + ut_asserteq(0x0438, utf_to_lower(0x0418)); +#endif + return 0; +} +UNICODE_TEST(ut_utf_to_lower); + +int ut_utf_to_upper(struct unit_test_state *uts) +{ + ut_asserteq('`', utf_to_upper('`')); + ut_asserteq('A', utf_to_upper('a')); + ut_asserteq('Z', utf_to_upper('z')); + ut_asserteq('{', utf_to_upper('{')); + ut_asserteq('M', utf_to_upper('M')); + /* Latin letter O with diaresis (umlaut) */ + ut_asserteq(0x00d6, utf_to_upper(0x00f6)); +#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION + /* Cyrillic letter I */ + ut_asserteq(0x0418, utf_to_upper(0x0438)); +#endif + return 0; +} +UNICODE_TEST(ut_utf_to_upper); + +int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test); + const int n_ents = ll_entry_count(struct unit_test, unicode_test); + + return cmd_ut_category("Unicode", tests, n_ents, argc, argv); +} |