From 8365426fc3f07ef2727699bf51aa98019ba4d1f2 Mon Sep 17 00:00:00 2001 From: nwert Date: Tue, 1 May 2018 17:15:48 +1200 Subject: [PATCH] So it has come to this. --- .gitignore | 3 + Makefile | 69 + README.md | 16 +- hwinit/clock.c | 161 - hwinit/hwinit.c | 296 -- hwinit/max77620.h | 131 - hwinit/sdram.c | 504 --- ipl/ELF.h | 1667 +++++++++ {hwinit => ipl}/btn.c | 7 +- {hwinit => ipl}/btn.h | 0 ipl/clock.c | 449 +++ {hwinit => ipl}/clock.h | 51 +- {hwinit => ipl}/cluster.c | 62 +- {hwinit => ipl}/cluster.h | 0 {hwinit => ipl}/di.c | 5 +- {hwinit => ipl}/di.h | 0 {hwinit => ipl}/di.inl | 0 ipl/diskio.c | 71 + ipl/diskio.h | 80 + {hwinit => ipl}/emc.h | 2 + ipl/ff.c | 6555 +++++++++++++++++++++++++++++++++ ipl/ff.h | 366 ++ ipl/ffconf.h | 283 ++ ipl/ffunicode.c | 608 +++ {hwinit => ipl}/fuse.c | 56 +- {hwinit => ipl}/fuse.h | 88 +- ipl/gfx.c | 308 ++ ipl/gfx.h | 54 + ipl/gpio.c | 94 + ipl/gpio.h | 77 + ipl/heap.c | 133 + hwinit/hwinit.h => ipl/heap.h | 52 +- ipl/hos.c | 436 +++ hwinit/types.h => ipl/hos.h | 12 +- {hwinit => ipl}/i2c.c | 0 {hwinit => ipl}/i2c.h | 0 ipl/ini.c | 93 + ipl/ini.h | 39 + ipl/integer.h | 38 + ipl/kfuse.c | 42 + ipl/kfuse.h | 41 + ipl/link.ld | 21 + ipl/list.h | 95 + ipl/lz.c | 179 + ipl/lz.h | 52 + ipl/main.c | 624 ++++ ipl/max77620.h | 324 ++ ipl/max7762x.c | 141 + ipl/max7762x.h | 68 + ipl/mc.c | 136 + ipl/mc.h | 13 + hwinit/mc.h => ipl/mc_t210.h | 4 +- ipl/mmc.h | 431 +++ ipl/nx_emmc.c | 76 + ipl/nx_emmc.h | 72 + {hwinit => ipl}/pinmux.c | 64 +- {hwinit => ipl}/pinmux.h | 20 + ipl/pkg1.c | 108 + ipl/pkg1.h | 49 + ipl/pkg2.c | 174 + ipl/pkg2.h | 94 + {hwinit => ipl}/pmc.h | 3 + ipl/pmc_t210_lp0.h | 563 +++ ipl/reloc.S | 34 + ipl/sd.h | 95 + ipl/sdmmc.c | 883 +++++ ipl/sdmmc.h | 45 + ipl/sdmmc_driver.c | 1063 ++++++ ipl/sdmmc_driver.h | 107 + ipl/sdmmc_t210.h | 132 + ipl/sdram.c | 523 +++ {hwinit => ipl}/sdram.h | 2 + {hwinit => ipl}/sdram.inl | 328 +- ipl/sdram_lp0.c | 1034 ++++++ ipl/sdram_lz.inl | 124 + ipl/sdram_param_t210.h | 930 +++++ ipl/sdram_param_t210_lp0.h | 961 +++++ ipl/se.c | 256 ++ ipl/se.h | 30 + ipl/se_t210.h | 357 ++ ipl/start.S | 77 + {hwinit => ipl}/t210.h | 17 +- {hwinit => ipl}/tsec.c | 24 +- {hwinit => ipl}/tsec.h | 2 +- ipl/tui.c | 98 + ipl/tui.h | 58 + ipl/types.h | 37 + {hwinit => ipl}/uart.c | 0 {hwinit => ipl}/uart.h | 0 {hwinit => ipl}/util.c | 5 + {hwinit => ipl}/util.h | 1 + tools/emc.def | 641 ++++ tools/fix_regs.py | 35 + tools/mc.def | 448 +++ 94 files changed, 23324 insertions(+), 1283 deletions(-) create mode 100755 .gitignore create mode 100755 Makefile delete mode 100644 hwinit/clock.c delete mode 100644 hwinit/hwinit.c delete mode 100644 hwinit/max77620.h delete mode 100644 hwinit/sdram.c create mode 100755 ipl/ELF.h rename {hwinit => ipl}/btn.c (86%) mode change 100644 => 100755 rename {hwinit => ipl}/btn.h (100%) mode change 100644 => 100755 create mode 100755 ipl/clock.c rename {hwinit => ipl}/clock.h (51%) mode change 100644 => 100755 rename {hwinit => ipl}/cluster.c (53%) mode change 100644 => 100755 rename {hwinit => ipl}/cluster.h (100%) mode change 100644 => 100755 rename {hwinit => ipl}/di.c (97%) mode change 100644 => 100755 rename {hwinit => ipl}/di.h (100%) mode change 100644 => 100755 rename {hwinit => ipl}/di.inl (100%) mode change 100644 => 100755 create mode 100755 ipl/diskio.c create mode 100755 ipl/diskio.h rename {hwinit => ipl}/emc.h (99%) mode change 100644 => 100755 create mode 100755 ipl/ff.c create mode 100755 ipl/ff.h create mode 100755 ipl/ffconf.h create mode 100755 ipl/ffunicode.c rename {hwinit => ipl}/fuse.c (96%) mode change 100644 => 100755 rename {hwinit => ipl}/fuse.h (96%) mode change 100644 => 100755 create mode 100755 ipl/gfx.c create mode 100755 ipl/gfx.h create mode 100755 ipl/gpio.c create mode 100755 ipl/gpio.h create mode 100755 ipl/heap.c rename hwinit/hwinit.h => ipl/heap.h (75%) mode change 100644 => 100755 create mode 100755 ipl/hos.c rename hwinit/types.h => ipl/hos.h (80%) mode change 100644 => 100755 rename {hwinit => ipl}/i2c.c (100%) mode change 100644 => 100755 rename {hwinit => ipl}/i2c.h (100%) mode change 100644 => 100755 create mode 100755 ipl/ini.c create mode 100755 ipl/ini.h create mode 100755 ipl/integer.h create mode 100755 ipl/kfuse.c create mode 100755 ipl/kfuse.h create mode 100755 ipl/link.ld create mode 100755 ipl/list.h create mode 100755 ipl/lz.c create mode 100755 ipl/lz.h create mode 100755 ipl/main.c create mode 100755 ipl/max77620.h create mode 100755 ipl/max7762x.c create mode 100755 ipl/max7762x.h create mode 100755 ipl/mc.c create mode 100755 ipl/mc.h rename hwinit/mc.h => ipl/mc_t210.h (99%) mode change 100644 => 100755 create mode 100755 ipl/mmc.h create mode 100755 ipl/nx_emmc.c create mode 100755 ipl/nx_emmc.h rename {hwinit => ipl}/pinmux.c (96%) mode change 100644 => 100755 rename {hwinit => ipl}/pinmux.h (64%) mode change 100644 => 100755 create mode 100755 ipl/pkg1.c create mode 100755 ipl/pkg1.h create mode 100755 ipl/pkg2.c create mode 100755 ipl/pkg2.h rename {hwinit => ipl}/pmc.h (93%) mode change 100644 => 100755 create mode 100755 ipl/pmc_t210_lp0.h create mode 100755 ipl/reloc.S create mode 100755 ipl/sd.h create mode 100755 ipl/sdmmc.c create mode 100755 ipl/sdmmc.h create mode 100755 ipl/sdmmc_driver.c create mode 100755 ipl/sdmmc_driver.h create mode 100755 ipl/sdmmc_t210.h create mode 100755 ipl/sdram.c rename {hwinit => ipl}/sdram.h (89%) mode change 100644 => 100755 rename {hwinit => ipl}/sdram.inl (71%) mode change 100644 => 100755 create mode 100755 ipl/sdram_lp0.c create mode 100755 ipl/sdram_lz.inl create mode 100755 ipl/sdram_param_t210.h create mode 100755 ipl/sdram_param_t210_lp0.h create mode 100755 ipl/se.c create mode 100755 ipl/se.h create mode 100755 ipl/se_t210.h create mode 100755 ipl/start.S rename {hwinit => ipl}/t210.h (82%) mode change 100644 => 100755 rename {hwinit => ipl}/tsec.c (87%) mode change 100644 => 100755 rename {hwinit => ipl}/tsec.h (93%) mode change 100644 => 100755 create mode 100755 ipl/tui.c create mode 100755 ipl/tui.h create mode 100755 ipl/types.h rename {hwinit => ipl}/uart.c (100%) mode change 100644 => 100755 rename {hwinit => ipl}/uart.h (100%) mode change 100644 => 100755 rename {hwinit => ipl}/util.c (95%) mode change 100644 => 100755 rename {hwinit => ipl}/util.h (98%) mode change 100644 => 100755 create mode 100755 tools/emc.def create mode 100755 tools/fix_regs.py create mode 100755 tools/mc.def diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..768c7ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vs +.vscode +build_ipl/* diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..d85718a --- /dev/null +++ b/Makefile @@ -0,0 +1,69 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +CC = $(DEVKITARM)/bin/arm-none-eabi-gcc +LD = $(DEVKITARM)/bin/arm-none-eabi-ld +OBJCOPY = $(DEVKITARM)/bin/arm-none-eabi-objcopy + +TARGET := ipl +BUILD := build_ipl +SOURCEDIR := ipl +OBJS = $(addprefix $(BUILD)/, \ + start.o \ + main.o \ + btn.o \ + clock.o \ + cluster.o \ + fuse.o \ + gpio.o \ + heap.o \ + hos.o \ + i2c.o \ + kfuse.o \ + lz.o \ + max7762x.o \ + mc.o \ + nx_emmc.o \ + sdmmc.o \ + sdmmc_driver.o \ + sdram.o \ + sdram_lp0.o \ + tui.o \ + util.o \ + di.o \ + gfx.o \ + pinmux.o \ + pkg1.o \ + pkg2.o \ + se.o \ + tsec.o \ + uart.o \ + ini.o \ +) +OBJS += $(addprefix $(BUILD)/, diskio.o ff.o ffunicode.o) + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork +CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11# -Wall +LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections + +.PHONY: all clean + +all: $(BUILD)/$(TARGET) + +clean: + @rm -rf $(OBJS) + @rm -rf $(BUILD)/$(TARGET).elf + @rm -rf $(BUILD)/$(TARGET) + +$(BUILD)/$(TARGET): $(BUILD)/$(TARGET).elf + $(OBJCOPY) -S -O binary $< $@ + +$(BUILD)/$(TARGET).elf: $(OBJS) + $(CC) $(LDFLAGS) -T ipl/link.ld $^ -o $@ + +$(BUILD)/%.o: $(SOURCEDIR)/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/%.o: $(SOURCEDIR)/%.S + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/README.md b/README.md index ae22707..23a6ec8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # hekate -Low level hardware init (for now) for Nintendo Switch. + +![Image of Hekate](https://upload.wikimedia.org/wikipedia/commons/f/fc/H%C3%A9cate_-_Mallarm%C3%A9.png) + +Nintendo Switch bootloader, firmware patcher, and more. + +## ipl config + +The ipl can be configured via 'hekate_ipl.ini' (if it is present on the SD card). Each ini section represents a boot entry, except for the special section 'config' that controls the global configuration. + +Possible key/value combinations: + + - warmboot={SD path} + - secmon={SD path} + - kernel={SD path} + - kip1={SD path} diff --git a/hwinit/clock.c b/hwinit/clock.c deleted file mode 100644 index dcd86f8..0000000 --- a/hwinit/clock.c +++ /dev/null @@ -1,161 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "clock.h" -#include "t210.h" -#include "util.h" - -static const clock_t _clock_uart[] = { - /* UART A */ { 4, 0x10, 0x178, 6, 0, 0 }, - /* UART B */ { 4, 0x10, 0x17C, 7, 0, 0 }, - /* UART C */ { 8, 0x14, 0x1A0, 0x17, 0, 0 }, - /* UART D */ { 0 }, - /* UART E */ { 0 } -}; - -static const clock_t _clock_i2c[] = { - /* I2C1 */ { 4, 0x10, 0x124, 0xC, 6, 0 }, - /* I2C2 */ { 0 }, - /* I2C3 */ { 0 }, - /* I2C4 */ { 0 }, - /* I2C5 */ { 8, 0x14, 0x128, 0xF, 6, 0 }, - /* I2C6 */ { 0 } -}; - -static clock_t _clock_se = { 0x358, 0x360, 0x42C, 0x1F, 0, 0 }; - -static clock_t _clock_host1x = { 4, 0x10, 0x180, 0x1C, 4, 3 }; -static clock_t _clock_tsec = { 0xC, 0x18, 0x1F4, 0x13, 0, 2 }; -static clock_t _clock_sor_safe = { 0x2A4, 0x298, 0, 0x1E, 0, 0 }; -static clock_t _clock_sor0 = { 0x28C, 0x280, 0, 0x16, 0, 0 }; -static clock_t _clock_sor1 = { 0x28C, 0x280, 0x410, 0x17, 0, 2 }; -static clock_t _clock_kfuse = { 8, 0x14, 0, 8, 0, 0 }; - -static clock_t _clock_coresight = { 0xC, 0x18, 0x1D4, 9, 0, 4}; - -void clock_enable(const clock_t *clk) -{ - //Put clock into reset. - CLOCK(clk->reset) = CLOCK(clk->reset) & ~(1 << clk->index) | (1 << clk->index); - //Disable. - CLOCK(clk->enable) &= ~(1 << clk->index); - //Configure clock source if required. - if (clk->source) - CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); - //Enable. - CLOCK(clk->enable) = CLOCK(clk->enable) & ~(1 << clk->index) | (1 << clk->index); - //Take clock off reset. - CLOCK(clk->reset) &= ~(1 << clk->index); -} - -void clock_disable(const clock_t *clk) -{ - //Put clock into reset. - CLOCK(clk->reset) = CLOCK(clk->reset) & ~(1 << clk->index) | (1 << clk->index); - //Disable. - CLOCK(clk->enable) &= ~(1 << clk->index); -} - -void clock_enable_fuse(u32 enable) -{ - CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF | ((enable & 1) << 28) & 0x10000000; -} - -void clock_enable_uart(u32 idx) -{ - clock_enable(&_clock_uart[idx]); -} - -void clock_enable_i2c(u32 idx) -{ - clock_enable(&_clock_i2c[idx]); -} - -void clock_enable_se() -{ - clock_enable(&_clock_se); -} - -void clock_enable_host1x() -{ - clock_enable(&_clock_host1x); -} - -void clock_enable_tsec() -{ - clock_enable(&_clock_tsec); -} - -void clock_enable_sor_safe() -{ - clock_enable(&_clock_sor_safe); -} - -void clock_enable_sor0() -{ - clock_enable(&_clock_sor0); -} - -void clock_enable_sor1() -{ - clock_enable(&_clock_sor1); -} - -void clock_enable_kfuse() -{ - //clock_enable(&_clock_kfuse); - CLOCK(0x8) = CLOCK(0x8) & 0xFFFFFEFF | 0x100; - CLOCK(0x14) &= 0xFFFFFEFF; - CLOCK(0x14) = CLOCK(0x14) & 0xFFFFFEFF | 0x100; - sleep(10); - CLOCK(0x8) &= 0xFFFFFEFF; - sleep(20); -} - -void clock_disable_host1x() -{ - clock_disable(&_clock_host1x); -} - -void clock_disable_tsec() -{ - clock_disable(&_clock_tsec); -} - -void clock_disable_sor_safe() -{ - clock_disable(&_clock_sor_safe); -} - -void clock_disable_sor0() -{ - clock_disable(&_clock_sor0); -} - -void clock_disable_sor1() -{ - clock_disable(&_clock_sor1); -} - -void clock_disable_kfuse() -{ - clock_disable(&_clock_kfuse); -} - -void clock_enable_coresight() -{ - clock_enable(&_clock_coresight); -} diff --git a/hwinit/hwinit.c b/hwinit/hwinit.c deleted file mode 100644 index eb73e07..0000000 --- a/hwinit/hwinit.c +++ /dev/null @@ -1,296 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "clock.h" -#include "uart.h" -#include "i2c.h" -#include "sdram.h" -#include "di.h" -#include "mc.h" -#include "t210.h" -#include "pmc.h" -#include "pinmux.h" -#include "fuse.h" -#include "util.h" - -void config_oscillators() -{ - CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3 | 4; - SYSCTR0(SYSCTR0_CNTFID0) = 19200000; - TMR(0x14) = 0x45F; - CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81 | 0xE; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF | 0x400000; - PMC(APBDEV_PMC_CNTRL2) = PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF | 0x1000; - PMC(APBDEV_PMC_SCRATCH188) = PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF | 0x2000000; - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; - PMC(APBDEV_PMC_TSC_MULT) = PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000 | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; - CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; -} - -void config_gpios() -{ - PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; - PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; - - PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = 0x40; - PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = 0x40; - - GPIO_2(0x8) = GPIO_2(0x8) & 0xFFFFFFFE | 1; - GPIO_1(0xC) = GPIO_1(0xC) & 0xFFFFFFFD | 2; - GPIO_2(0x0) = GPIO_2(0x0) & 0xFFFFFFBF | 0x40; - GPIO_2(0xC) = GPIO_2(0xC) & 0xFFFFFFBF | 0x40; - GPIO_2(0x18) &= 0xFFFFFFFE; - GPIO_1(0x1C) &= 0xFFFFFFFD; - GPIO_2(0x10) &= 0xFFFFFFBF; - GPIO_2(0x1C) &= 0xFFFFFFBF; - - pinmux_config_i2c(I2C_1); - pinmux_config_i2c(I2C_5); - pinmux_config_uart(UART_A); - - GPIO_6(0xC) = GPIO_6(0xC) & 0xFFFFFFBF | 0x40; - GPIO_6(0xC) = GPIO_6(0xC) & 0xFFFFFF7F | 0x80; - GPIO_6(0x1C) &= 0xFFFFFFBF; - GPIO_6(0x1C) &= 0xFFFFFF7F; -} - -void config_pmc_scratch() -{ - PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; - PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; - PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10; -} - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock) -{ - MC(0x670) = bom; - MC(0x674) = size1mb; - if (lock) - MC(0x678) = 1; -} - -void mc_config_carveout() -{ - *(vu32 *)0x8005FFFC = 0xC0EDBBCC; - MC(0x984) = 1; - MC(0x988) = 0; - MC(0x648) = 0; - MC(0x64C) = 0; - MC(0x650) = 1; - - //Official code disables and locks the carveout here. - //mc_config_tsec_carveout(0, 0, 1); - - MC(0x9A0) = 0; - MC(0x9A4) = 0; - MC(0x9A8) = 0; - MC(0x9AC) = 1; - MC(0xC0C) = 0; - MC(0xC10) = 0; - MC(0xC14) = 0; - MC(0xC18) = 0; - MC(0xC1C) = 0; - MC(0xC20) = 0; - MC(0xC24) = 0; - MC(0xC28) = 0; - MC(0xC2C) = 0; - MC(0xC30) = 0; - MC(0xC34) = 0; - MC(0xC38) = 0; - MC(0xC3C) = 0; - MC(0xC08) = 0x4000006; - MC(0xC5C) = 0x80020000; - MC(0xC60) = 0; - MC(0xC64) = 2; - MC(0xC68) = 0; - MC(0xC6C) = 0; - MC(0xC70) = 0x3000000; - MC(0xC74) = 0; - MC(0xC78) = 0x300; - MC(0xC7C) = 0; - MC(0xC80) = 0; - MC(0xC84) = 0; - MC(0xC88) = 0; - MC(0xC8C) = 0; - MC(0xC58) = 0x440167E; - MC(0xCAC) = 0; - MC(0xCB0) = 0; - MC(0xCB4) = 0; - MC(0xCB8) = 0; - MC(0xCBC) = 0; - MC(0xCC0) = 0x3000000; - MC(0xCC4) = 0; - MC(0xCC8) = 0x300; - MC(0xCCC) = 0; - MC(0xCD0) = 0; - MC(0xCD4) = 0; - MC(0xCD8) = 0; - MC(0xCDC) = 0; - MC(0xCA8) = 0x4401E7E; - MC(0xCFC) = 0; - MC(0xD00) = 0; - MC(0xD04) = 0; - MC(0xD08) = 0; - MC(0xD0C) = 0; - MC(0xD10) = 0; - MC(0xD14) = 0; - MC(0xD18) = 0; - MC(0xD1C) = 0; - MC(0xD20) = 0; - MC(0xD24) = 0; - MC(0xD28) = 0; - MC(0xD2C) = 0; - MC(0xCF8) = 0x8F; - MC(0xD4C) = 0; - MC(0xD50) = 0; - MC(0xD54) = 0; - MC(0xD58) = 0; - MC(0xD5C) = 0; - MC(0xD60) = 0; - MC(0xD64) = 0; - MC(0xD68) = 0; - MC(0xD6C) = 0; - MC(0xD70) = 0; - MC(0xD74) = 0; - MC(0xD78) = 0; - MC(0xD7C) = 0; - MC(0xD48) = 0x8F; -} - -void enable_clocks() -{ - CLOCK(0x410) = (CLOCK(0x410) | 0x8000) & 0xFFFFBFFF; - CLOCK(0xD0) |= 0x40800000u; - CLOCK(0x2AC) = 64; - CLOCK(0x294) = 0x40000; - CLOCK(0x304) = 0x18000000; - sleep(2); - - I2S(0x0A0) |= 0x400; - I2S(0x088) &= 0xFFFFFFFE; - I2S(0x1A0) |= 0x400; - I2S(0x188) &= 0xFFFFFFFE; - I2S(0x2A0) |= 0x400; - I2S(0x288) &= 0xFFFFFFFE; - I2S(0x3A0) |= 0x400; - I2S(0x388) &= 0xFFFFFFFE; - I2S(0x4A0) |= 0x400; - I2S(0x488) &= 0xFFFFFFFE; - DISPLAY_A(0xCF8) |= 4; - VIC(0x8C) = 0xFFFFFFFF; - sleep(2); - - CLOCK(0x2A8) = 0x40; - CLOCK(0x300) = 0x18000000; - CLOCK(0x290) = 0x40000; - CLOCK(0x14) = 0xC0; - CLOCK(0x10) = 0x80000130; - CLOCK(0x18) = 0x1F00200; - CLOCK(0x360) = 0x80400808; - CLOCK(0x364) = 0x402000FC; - CLOCK(0x280) = 0x23000780; - CLOCK(0x298) = 0x300; - CLOCK(0xF8) = 0; - CLOCK(0xFC) = 0; - CLOCK(0x3A0) = 0; - CLOCK(0x3A4) = 0; - CLOCK(0x554) = 0; - CLOCK(0xD0) &= 0x1F7FFFFFu; - CLOCK(0x410) &= 0xFFFF3FFF; - CLOCK(0x148) = CLOCK(0x148) & 0x1FFFFFFF | 0x80000000; - CLOCK(0x180) = CLOCK(0x180) & 0x1FFFFFFF | 0x80000000; - CLOCK(0x6A0) = CLOCK(0x6A0) & 0x1FFFFFFF | 0x80000000; -} - -void mc_enable_ahb_redirect() -{ - CLOCK(0x3A4) = CLOCK(0x3A4) & 0xFFF7FFFF | 0x80000; - //MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE; - MC(MC_IRAM_BOM) = 0x40000000; - MC(MC_IRAM_TOM) = 0x4003F000; -} - -void mc_disable_ahb_redirect() -{ - MC(MC_IRAM_BOM) = 0xFFFFF000; - MC(MC_IRAM_TOM) = 0; - //Disable IRAM_CFG_WRITE_ACCESS (sticky). - //MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1; - CLOCK(0x3A4) &= 0xFFF7FFFF; -} - -void mc_enable() -{ - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF | 0x40000000; - //Enable MIPI CAL clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF | 0x2000000; - //Enable MC clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE | 1; - //Enable EMC DLL clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF | 0x4000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x2000001; //Clear EMC and MC reset. - sleep(5); -} - -clock_t clock_unk1 = { 0x358, 0x360, 0x42C, 0x1F, 0, 0 }; -clock_t clock_unk2 = { 0x358, 0x360, 0, 0x1E, 0, 0 }; - -void nx_hwinit() -{ - enable_clocks(); - clock_enable_se(); - clock_enable_fuse(1); - fuse_disable_program(); - - mc_enable(); - - config_oscillators(); - _REG(0x70000000, 0x40) = 0; - - config_gpios(); - - clock_enable_i2c(I2C_1); - clock_enable_i2c(I2C_5); - clock_enable(&clock_unk1); - clock_enable(&clock_unk2); - - i2c_init(I2C_1); - i2c_init(I2C_5); - - //Config PMIC (TODO: use max77620.h) - i2c_send_byte(I2C_5, 0x3C, 4, 0x40); - i2c_send_byte(I2C_5, 0x3C, 0x41, 0x78); - i2c_send_byte(I2C_5, 0x3C, 0x43, 0x38); - i2c_send_byte(I2C_5, 0x3C, 0x44, 0x3A); - i2c_send_byte(I2C_5, 0x3C, 0x45, 0x38); - i2c_send_byte(I2C_5, 0x3C, 0x4A, 0xF); - i2c_send_byte(I2C_5, 0x3C, 0x4E, 0xC7); - i2c_send_byte(I2C_5, 0x3C, 0x4F, 0x4F); - i2c_send_byte(I2C_5, 0x3C, 0x50, 0x29); - i2c_send_byte(I2C_5, 0x3C, 0x52, 0x1B); - i2c_send_byte(I2C_5, 0x3C, 0x16, 42); //42 = (1000 * 1125 - 600000) / 12500 - - config_pmc_scratch(); - - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888 | 0x3333; - - mc_config_carveout(); - - sdram_init(); -} diff --git a/hwinit/max77620.h b/hwinit/max77620.h deleted file mode 100644 index 6e7e1e8..0000000 --- a/hwinit/max77620.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -* Defining registers address and its bit definitions of MAX77620 and MAX20024 -* -* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -*/ - -#ifndef _MAX77620_H_ -#define _MAX77620_H_ - -/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ -#define MAX77620_REG_CNFGGLBL1 0x00 -#define MAX77620_REG_CNFGGLBL2 0x01 -#define MAX77620_REG_CNFGGLBL3 0x02 -#define MAX77620_REG_CNFG1_32K 0x03 -#define MAX77620_REG_CNFGBBC 0x04 -#define MAX77620_REG_IRQTOP 0x05 -#define MAX77620_REG_INTLBT 0x06 -#define MAX77620_REG_IRQSD 0x07 -#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 -#define MAX77620_REG_IRQ_LVL2_L8 0x09 -#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A -#define MAX77620_REG_ONOFFIRQ 0x0B -#define MAX77620_REG_NVERC 0x0C -#define MAX77620_REG_IRQTOPM 0x0D -#define MAX77620_REG_INTENLBT 0x0E -#define MAX77620_REG_IRQMASKSD 0x0F -#define MAX77620_REG_IRQ_MSK_L0_7 0x10 -#define MAX77620_REG_IRQ_MSK_L8 0x11 -#define MAX77620_REG_ONOFFIRQM 0x12 -#define MAX77620_REG_STATLBT 0x13 -#define MAX77620_REG_STATSD 0x14 -#define MAX77620_REG_ONOFFSTAT 0x15 - -/* SD and LDO Registers */ -#define MAX77620_REG_SD0 0x16 -#define MAX77620_REG_SD1 0x17 -#define MAX77620_REG_SD2 0x18 -#define MAX77620_REG_SD3 0x19 -#define MAX77620_REG_SD4 0x1A -#define MAX77620_REG_DVSSD0 0x1B -#define MAX77620_REG_DVSSD1 0x1C -#define MAX77620_REG_SD0_CFG 0x1D -#define MAX77620_REG_SD1_CFG 0x1E -#define MAX77620_REG_SD2_CFG 0x1F -#define MAX77620_REG_SD3_CFG 0x20 -#define MAX77620_REG_SD4_CFG 0x21 -#define MAX77620_REG_SD_CFG2 0x22 -#define MAX77620_REG_LDO0_CFG 0x23 -#define MAX77620_REG_LDO0_CFG2 0x24 -#define MAX77620_REG_LDO1_CFG 0x25 -#define MAX77620_REG_LDO1_CFG2 0x26 -#define MAX77620_REG_LDO2_CFG 0x27 -#define MAX77620_REG_LDO2_CFG2 0x28 -#define MAX77620_REG_LDO3_CFG 0x29 -#define MAX77620_REG_LDO3_CFG2 0x2A -#define MAX77620_REG_LDO4_CFG 0x2B -#define MAX77620_REG_LDO4_CFG2 0x2C -#define MAX77620_REG_LDO5_CFG 0x2D -#define MAX77620_REG_LDO5_CFG2 0x2E -#define MAX77620_REG_LDO6_CFG 0x2F -#define MAX77620_REG_LDO6_CFG2 0x30 -#define MAX77620_REG_LDO7_CFG 0x31 -#define MAX77620_REG_LDO7_CFG2 0x32 -#define MAX77620_REG_LDO8_CFG 0x33 -#define MAX77620_REG_LDO8_CFG2 0x34 -#define MAX77620_REG_LDO_CFG3 0x35 - -#define MAX77620_LDO_SLEW_RATE_MASK 0x1 - -/* LDO Configuration 3 */ -#define MAX77620_TRACK4_MASK BIT(5) -#define MAX77620_TRACK4_SHIFT 5 - -/* Voltage */ -#define MAX77620_SDX_VOLT_MASK 0xFF -#define MAX77620_SD0_VOLT_MASK 0x3F -#define MAX77620_SD1_VOLT_MASK 0x7F -#define MAX77620_LDO_VOLT_MASK 0x3F - -#define MAX77620_REG_GPIO0 0x36 -#define MAX77620_REG_GPIO1 0x37 -#define MAX77620_REG_GPIO2 0x38 -#define MAX77620_REG_GPIO3 0x39 -#define MAX77620_REG_GPIO4 0x3A -#define MAX77620_REG_GPIO5 0x3B -#define MAX77620_REG_GPIO6 0x3C -#define MAX77620_REG_GPIO7 0x3D -#define MAX77620_REG_PUE_GPIO 0x3E -#define MAX77620_REG_PDE_GPIO 0x3F -#define MAX77620_REG_AME_GPIO 0x40 -#define MAX77620_REG_ONOFFCNFG1 0x41 -#define MAX77620_REG_ONOFFCNFG2 0x42 - -/* FPS Registers */ -#define MAX77620_REG_FPS_CFG0 0x43 -#define MAX77620_REG_FPS_CFG1 0x44 -#define MAX77620_REG_FPS_CFG2 0x45 -#define MAX77620_REG_FPS_LDO0 0x46 -#define MAX77620_REG_FPS_LDO1 0x47 -#define MAX77620_REG_FPS_LDO2 0x48 -#define MAX77620_REG_FPS_LDO3 0x49 -#define MAX77620_REG_FPS_LDO4 0x4A -#define MAX77620_REG_FPS_LDO5 0x4B -#define MAX77620_REG_FPS_LDO6 0x4C -#define MAX77620_REG_FPS_LDO7 0x4D -#define MAX77620_REG_FPS_LDO8 0x4E -#define MAX77620_REG_FPS_SD0 0x4F -#define MAX77620_REG_FPS_SD1 0x50 -#define MAX77620_REG_FPS_SD2 0x51 -#define MAX77620_REG_FPS_SD3 0x52 -#define MAX77620_REG_FPS_SD4 0x53 - -#define MAX77620_REG_FPS_GPIO1 0x54 -#define MAX77620_REG_FPS_GPIO2 0x55 -#define MAX77620_REG_FPS_GPIO3 0x56 -#define MAX77620_REG_FPS_RSO 0x57 -#define MAX77620_REG_CID0 0x58 -#define MAX77620_REG_CID1 0x59 -#define MAX77620_REG_CID2 0x5A -#define MAX77620_REG_CID3 0x5B -#define MAX77620_REG_CID4 0x5C -#define MAX77620_REG_CID5 0x5D - -#define MAX77620_REG_DVSSD4 0x5E -#define MAX20024_REG_MAX_ADD 0x70 - -#endif diff --git a/hwinit/sdram.c b/hwinit/sdram.c deleted file mode 100644 index bfc288d..0000000 --- a/hwinit/sdram.c +++ /dev/null @@ -1,504 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "i2c.h" -#include "t210.h" -#include "mc.h" -//#include "emc.h" -#include "pmc.h" -#include "util.h" -#include "fuse.h" - -#include "sdram.inl" - -static u32 _get_sdram_id() -{ - return (fuse_read_odm(4) & 0x38) >> 3; -} - -static void _sdram_config(const u32 *_cfg) -{ - const u32 *_cfg_120 = _cfg + 0x120; - const u32 *_cfg_100 = _cfg + 0x100; - - PMC(0x45C) = (((4 * _cfg[0x12F] >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF; - sleep(_cfg[0x111]); - - u32 req = (4 * _cfg_120[0x10] >> 2) + 0x80000000; - PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0x3FFF0000) >> 16 << 16; - sleep(_cfg_100[0x12]); - PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF; - sleep(_cfg_100[0x12]); - PMC(APBDEV_PMC_WEAK_BIAS) = 0; - sleep(1); - - CLOCK(0x98) = _cfg[4]; - CLOCK(0x9C) = 0; - CLOCK(0x90) = (_cfg[2] << 8) | (*((u16 *)_cfg + 0xA) << 20) | _cfg[1] | 0x40000000; - - u32 wait_end = TMR(0x10) + 300; - while (!((CLOCK(0x90) >> 27) & 1)) - { - if (TMR(0x10) >= wait_end) - goto break_nosleep; - } - sleep(10); -break_nosleep: - - CLOCK(0x19C) = _cfg[0x16] & 0xFFFEFFFF | (_cfg[0x175] >> 11) & 0x10000; - if (_cfg[0x17]) - CLOCK(0x664) = _cfg[0x17]; - if (_cfg[0x1A]) - CLOCK(0x44C) = 0x40000000; - CLOCK(0x328) = 0x2000001; - CLOCK(0x284) = 0x4000; - CLOCK(0x30C) = 0x2000001; - EMC(0xC34) = _cfg_120[0x13]; - EMC(0xC38) = _cfg_120[0x14]; - EMC(0xCF0) = _cfg_120[0x15]; - EMC(0x28) = 1; - sleep(1); - EMC(0x8) = _cfg[0xA9] | 2 * _cfg[0xAA]; - if (_cfg[0xA]) - *(vu32 *)_cfg[0xA] = _cfg[0xB]; - EMC(0x584) = _cfg[0x7B]; - EMC(0x380) = _cfg[0x7D]; - EMC(0x384) = _cfg[0x7E]; - EMC(0x388) = _cfg[0x7F]; - EMC(0x38C) = _cfg[0x80]; - EMC(0x390) = _cfg[0x81]; - EMC(0x394) = _cfg[0x82]; - EMC(0x398) = _cfg[0x83]; - EMC(0x39C) = _cfg[0x84]; - EMC(0x3A0) = _cfg[0x85]; - EMC(0x3A4) = _cfg[0x86]; - EMC(0x3A8) = _cfg[0x87]; - EMC(0x3AC) = _cfg[0x88]; - EMC(0x3B0) = _cfg[0x89]; - EMC(0xC80) = _cfg[0x14A]; - EMC(0xC84) = _cfg[0x14B]; - EMC(0xC88) = _cfg[0x14C]; - EMC(0x330) = (_cfg_120[0x16] | 0xFEEDFEED) & 0x1FFF1FFF; - EMC(0x5F0) = _cfg[0x149]; - EMC(0x5C8) = _cfg[0x7C]; - EMC(0x404) = _cfg_100[0x18]; - EMC(0x408) = _cfg_100[0x19]; - EMC(0x40C) = _cfg_100[0x1A]; - EMC(0x410) = _cfg_100[0x1B]; - EMC(0x418) = _cfg_100[0x1C]; - EMC(0x41C) = _cfg_100[0x1D]; - EMC(0x420) = _cfg_100[0x1E]; - EMC(0x424) = _cfg_100[0x1F]; - if (_cfg[0xE]) - *(vu32 *)_cfg[0xE] = _cfg[0xF]; - EMC(0x30C) = _cfg[0x31]; - EMC(0x578) = _cfg[0x32]; - EMC(0x2F4) = _cfg[0x33]; - EMC(0x458) = _cfg[0x1D]; - EMC(0x45C) = _cfg[0x1E]; - EMC(0x5B0) = _cfg[0x1F]; - EMC(0x5B4) = _cfg[0x20]; - EMC(0x5CC) = _cfg[0x21]; - EMC(0x574) = _cfg[0x22]; - EMC(0x2DC) = _cfg[0x23]; - EMC(0xC48) = _cfg[0x2A]; - EMC(0xC70) = _cfg[0x2B]; - EMC(0xC74) = _cfg[0x2C]; - EMC(0xC4C) = _cfg[0x2D]; - EMC(0xC78) = _cfg[0x2E]; - EMC(0x464) = _cfg[0x26]; - EMC(0xC44) = _cfg[0x2F]; - EMC(0x5E4) = _cfg_120[0xD]; - EMC(0x5E8) = _cfg_120[0xE]; - EMC(0x2C8) = _cfg[0xB0]; - EMC(0x588) = _cfg_120[1]; - EMC(0x58C) = _cfg_120[2]; - EMC(0x594) = _cfg_120[3]; - EMC(0x598) = _cfg_120[4]; - EMC(0x59C) = _cfg_120[5]; - EMC(0x5A0) = _cfg_120[6]; - EMC(0x5A4) = _cfg_120[7]; - EMC(0x5A8) = _cfg_120[8]; - EMC(0x5AC) = _cfg_120[9]; - EMC(0x5B8) = _cfg_120[0xA]; - EMC(0x5BC) = _cfg_120[0xB]; - EMC(0x5C4) = _cfg_120[0xC]; - EMC(0x330) = (_cfg_120[0x16] | 0xFE40FE40) & 0x1FFF1FFF; - EMC(0xC40) = _cfg_120[0x12]; - EMC(0x318) = _cfg_120[0x17]; - EMC(0x334) = _cfg_120[0x18] & 0xFF7FFF7F; - EMC(0x31C) = _cfg_120[0x19]; - EMC(0xC3C) = _cfg_120[0x1A]; - EMC(0xC54) = _cfg_120[0x1B]; - EMC(0xC50) = _cfg_120[0x1C]; - EMC(0xC64) = _cfg_120[0x1F]; - EMC(0xC5C) = _cfg_120[0x1D]; - EMC(0xC58) = _cfg_120[0x1E]; - EMC(0xC60) = _cfg[0x141]; - EMC(0x49C) = _cfg[0x142]; - EMC(0x720) = _cfg[0x143]; - EMC(0x724) = _cfg[0x144]; - EMC(0x728) = _cfg[0x145]; - EMC(0x72C) = _cfg[0x146]; - EMC(0x730) = _cfg[0x147]; - EMC(0x734) = _cfg[0x148]; - EMC(0x740) = _cfg[0x14D]; - EMC(0x744) = _cfg[0x14E]; - EMC(0x748) = _cfg[0x14F]; - EMC(0x74C) = _cfg[0x150]; - EMC(0x750) = _cfg[0x151]; - EMC(0x754) = _cfg[0x152]; - EMC(0x760) = _cfg[0x153]; - EMC(0x770) = _cfg[0x154]; - EMC(0x774) = _cfg[0x155]; - EMC(0x778) = _cfg[0x156]; - EMC(0x780) = _cfg[0x157]; - EMC(0x784) = _cfg[0x158]; - EMC(0x788) = _cfg[0x159]; - EMC(0xBE0) = _cfg[0xB6]; - EMC(0xBE4) = _cfg[0xB7]; - EMC(0xBF0) = _cfg[0xB8]; - EMC(0xBF4) = _cfg[0xB9]; - EMC(0xCF4) = _cfg[0xBA]; - EMC(0x600) = _cfg[0xBD]; - EMC(0x604) = _cfg[0xBE]; - EMC(0x608) = _cfg[0xBF]; - EMC(0x60C) = _cfg[0xC0]; - EMC(0x610) = _cfg[0xC1]; - EMC(0x614) = _cfg[0xC2]; - EMC(0x620) = _cfg[0xC3]; - EMC(0x624) = _cfg[0xC4]; - EMC(0x628) = _cfg[0xC5]; - EMC(0x62C) = _cfg[0xC6]; - EMC(0x630) = _cfg[0xC7]; - EMC(0x634) = _cfg[0xC8]; - EMC(0x330) = _cfg_120[0x16]; - EMC(0x640) = _cfg[0xC9]; - EMC(0x644) = _cfg[0xCA]; - EMC(0x648) = _cfg[0xCB]; - EMC(0x64C) = _cfg[0xCC]; - EMC(0x650) = _cfg[0xCD]; - EMC(0x654) = _cfg[0xCE]; - EMC(0x660) = _cfg[0xCF]; - EMC(0x664) = _cfg[0xD0]; - EMC(0x668) = _cfg[0xD1]; - EMC(0x66C) = _cfg[0xD2]; - EMC(0x670) = _cfg[0xD3]; - EMC(0x674) = _cfg[0xD4]; - EMC(0x680) = _cfg[0xD5]; - EMC(0x684) = _cfg[0xD6]; - EMC(0x688) = _cfg[0xD7]; - EMC(0x68C) = _cfg[0xD8]; - EMC(0x690) = _cfg[0xD9]; - EMC(0x694) = _cfg[0xDA]; - EMC(0x6A0) = _cfg[0xDB]; - EMC(0x6A4) = _cfg[0xDC]; - EMC(0x6A8) = _cfg[0xDD]; - EMC(0x6AC) = _cfg[0xDE]; - EMC(0x6B0) = _cfg[0xDF]; - EMC(0x6B4) = _cfg[0xE0]; - EMC(0x6C0) = _cfg[0xE1]; - EMC(0x6C4) = _cfg[0xE2]; - EMC(0x6C8) = _cfg[0xE3]; - EMC(0x6CC) = _cfg[0xE4]; - EMC(0x6E0) = _cfg[0xE5]; - EMC(0x6E4) = _cfg[0xE6]; - EMC(0x6E8) = _cfg[0xE7]; - EMC(0x6EC) = _cfg[0xE8]; - EMC(0xC00) = _cfg[0xE9]; - EMC(0xC04) = _cfg[0xEA]; - EMC(0xC08) = _cfg[0xEB]; - EMC(0xC0C) = _cfg[0xEC]; - EMC(0xC10) = _cfg[0xED]; - EMC(0xC20) = _cfg[0xEE]; - EMC(0xC24) = _cfg[0xEF]; - EMC(0xC28) = _cfg[0xF0]; - EMC(0xC68) = (*((u8 *)_cfg + 0x500) | 0xFFFFFFFE) & 0xF; - if (_cfg[0xC]) - *(vu32 *)_cfg[0xC] = _cfg[0xD]; - EMC(0x28) = 1; - MC(0x648) = _cfg[0x180]; - MC(0x978) = _cfg[0x181]; - MC(0x64C) = _cfg[0x182]; - MC(0x418) = _cfg[0x183]; - MC(0x590) = _cfg[0x184]; - MC(0x984) = _cfg[0x185]; - MC(0x988) = _cfg[0x186]; - MC(0x54) = _cfg[0x15A]; - MC(0x58) = _cfg[0x15B]; - MC(0x5C) = _cfg[0x15C]; - MC(0x60) = _cfg[0x15D]; - MC(0x64) = _cfg[0x15E]; - MC(0x68) = _cfg[0x15F]; - MC(0x6C) = _cfg[0x160]; - MC(0x50) = _cfg[0x161]; - MC(0x670) = _cfg[0x187]; - MC(0x9D4) = _cfg[0x188]; - MC(0x674) = _cfg[0x189]; - MC(0x9A0) = _cfg[0x1D6]; - MC(0x9A8) = _cfg[0x1D7]; - MC(0x9A4) = _cfg[0x1D8]; - MC(0x90) = _cfg[0x162]; - MC(0x94) = _cfg[0x163]; - MC(0x6F0) = _cfg[0x164]; - MC(0x6F4) = _cfg[0x165]; - MC(0x98) = _cfg[0x166]; - MC(0x9C) = _cfg[0x167]; - MC(0xA0) = _cfg[0x168]; - MC(0xA4) = _cfg[0x169]; - MC(0xA8) = _cfg[0x16A]; - MC(0xAC) = _cfg[0x16B]; - MC(0xB0) = _cfg[0x16C]; - MC(0xB4) = _cfg[0x16D]; - MC(0xB8) = _cfg[0x16E]; - MC(0xBC) = _cfg[0x16F]; - MC(0x6C4) = _cfg[0x17D]; - MC(0xC0) = _cfg[0x170]; - MC(0xC4) = _cfg[0x171]; - MC(0x6C0) = _cfg[0x172]; - MC(0xD0) = _cfg[0x173]; - MC(0xD4) = _cfg[0x174]; - MC(0xD8) = _cfg[0x175]; - MC(0xDC) = _cfg[0x176]; - MC(0xC8) = _cfg[0x177]; - MC(0xE0) = _cfg[0x178]; - MC(0xE8) = _cfg[0x179]; - MC(0x968) = _cfg[0x17A]; - MC(0xEC) = _cfg[0x17B]; - MC(0x9DC) = _cfg[0x17C]; - MC(0xFC) = 1; - MC(0xF4) = _cfg[0x17E]; - MC(0x100) = _cfg[0x17F]; - EMC(0x10) = _cfg[0x34]; - EMC(0x140) = _cfg_100[7]; - EMC(0x700) = _cfg[0x27]; - EMC(0x704) = _cfg[0x28]; - EMC(0x708) = _cfg[0x29]; - EMC(0x2F8) = _cfg[0x24]; - EMC(0x300) = _cfg[0x25]; - EMC(0x2A8) = _cfg[0x1B]; - EMC(0x2A4) = _cfg[0x1C]; - sleep(_cfg[0x30]); - if (_cfg[0x10]) - *(vu32 *)_cfg[0x10] = _cfg[0x11]; - EMC(0x2B8) = _cfg[0xA4]; - EMC(0x560) = _cfg[0xA5]; - EMC(0x55C) = _cfg[0xBB]; - EMC(0x554) = _cfg[0xBC]; - EMC(0xF0) = _cfg[0xAB]; - EMC(0xF4) = _cfg[0xAC]; - EMC(0xC8) = _cfg[0xA1]; - EMC(0xC4) = _cfg[0xA2]; - EMC(0x104) = _cfg[0x7A]; - EMC(0x2C) = _cfg[0x3A]; - EMC(0x30) = _cfg[0x3B]; - EMC(0x590) = _cfg[0x3C]; - EMC(0x580) = _cfg[0x3D]; - EMC(0xC0) = _cfg[0x3E]; - EMC(0x34) = _cfg[0x3F]; - EMC(0x38) = _cfg[0x40]; - EMC(0xAC) = _cfg[0x47]; - EMC(0x144) = _cfg[0x41]; - EMC(0x148) = _cfg[0x42]; - EMC(0x3C) = _cfg[0x43]; - EMC(0x40) = _cfg[0x44]; - EMC(0x44) = _cfg[0x45]; - EMC(0x48) = _cfg[0x46]; - EMC(0x5C0) = _cfg[0x48]; - EMC(0x4C) = _cfg[0x49]; - EMC(0x50) = _cfg[0x4A]; - EMC(0x54) = _cfg[0x4B]; - EMC(0x58) = _cfg[0x4C]; - EMC(0xB8) = _cfg[0x4D]; - EMC(0x5C) = _cfg[0x4E]; - EMC(0x4E0) = _cfg[0x4F]; - EMC(0x498) = _cfg[0x50]; - EMC(0x494) = _cfg[0x51]; - EMC(0x2D0) = _cfg[0x52]; - EMC(0x490) = _cfg[0x53]; - EMC(0x48C) = _cfg[0x54]; - EMC(0x60) = _cfg[0x55]; - EMC(0x568) = _cfg[0x56]; - EMC(0x468) = _cfg[0x57]; - EMC(0x46C) = _cfg[0x58]; - EMC(0x14C) = _cfg[0x59]; - EMC(0x150) = _cfg[0x5A]; - EMC(0x154) = _cfg[0x5B]; - EMC(0x56C) = _cfg[0x5C]; - EMC(0xC68) = _cfg[0x140]; - EMC(0x8) = _cfg[0xA9]; - EMC(0x64) = _cfg[0x5D]; - EMC(0x428) = 0; - EMC(0x68) = _cfg[0x5E]; - EMC(0x6C) = _cfg[0x5F]; - EMC(0x2CC) = _cfg[0x60]; - EMC(0x2D8) = _cfg[0x61]; - EMC(0x2D4) = _cfg[0x62]; - EMC(0x564) = _cfg[0x63]; - EMC(0x70) = _cfg[0x64]; - EMC(0x74) = _cfg[0x65]; - EMC(0x3DC) = _cfg[0x66]; - EMC(0x78) = _cfg[0x67]; - EMC(0x7C) = _cfg[0x68]; - EMC(0x80) = _cfg[0x69]; - EMC(0x84) = _cfg[0x6A]; - EMC(0x88) = _cfg[0x6B]; - EMC(0x8C) = _cfg[0x6C]; - EMC(0x11C) = _cfg[0x6D]; - EMC(0x118) = _cfg[0x6E]; - EMC(0xB4) = _cfg[0x6F]; - EMC(0x90) = _cfg[0x70]; - EMC(0x3E4) = _cfg[0x71]; - EMC(0x94) = _cfg[0x72]; - EMC(0x158) = _cfg[0x73]; - EMC(0x15C) = _cfg[0x74]; - EMC(0x98) = _cfg[0x75]; - EMC(0x9C) = _cfg[0x76]; - EMC(0xA0) = _cfg[0x77]; - EMC(0xA4) = _cfg[0x78]; - EMC(0xA8) = _cfg[0x79]; - EMC(0xB0) = _cfg[0xF2]; - EMC(0x2BC) = _cfg[0xAF]; - EMC(0x2C0) = _cfg[0xB1]; - EMC(0x100) = _cfg[0x8A] & 0xFFFFFFFD; - EMC(0x120) = _cfg[0x8B]; - EMC(0x440) = _cfg_120[0xF]; - EMC(0x444) = _cfg_120[0x10]; - EMC(0x448) = _cfg_120[0x11]; - EMC(0x124) = _cfg_100[0x17]; - EMC(0x480) = *_cfg_120; - EMC(0xC) = ((_cfg[0xA3] & 4 | 0x3C00000) & 0xFFFFFFF7 | _cfg[0xA3] & 8) & 0xFFFFFFFD | _cfg[0xA3] & 2; - if ((_cfg[0x1D4] & 0x80000000) != 0) - { - *(vu32 *)(4 * _cfg[0x1D4] + 0x70000000) = _cfg[0x1D5]; - MC(0xFC) = 1; - } - PMC(0x45C) = ((4 * _cfg_120[0xF] >> 2) + 0x40000000) & 0xCFFF0000; - sleep(_cfg_100[0x11]); - if (!_cfg[0x1B]) - EMC(0x2A4) = _cfg[0x1C] | 0x200; - EMC(0x334) = _cfg_120[0x18]; - if (_cfg[0xFA] << 31) - { - if (*_cfg == 2) - EMC(0x2E4) = 8 * _cfg[0xF4]; - if (*_cfg == 3) - { - EMC(0x2E4) = _cfg[0xF4]; - EMC(0x2E8) = _cfg[0xF5]; - } - } - EMC(0x28) = 1; - sleep(_cfg[0x39]); - PMC(0x4E4) &= 0xFFF8007F; - sleep(_cfg_100[0x15]); - if (*_cfg == 2) - { - EMC(0x24) = (_cfg[0x37] << 16) | (_cfg[0x38] << 12); - sleep(_cfg[0x36] + 200); - EMC(0x24) = ((_cfg[0x37] << 16) | (_cfg[0x38] << 12)) + 0x100; - sleep(_cfg[0x36] + 500); - } - if (*_cfg == 3) - { - EMC(0x24) = (_cfg[0x37] << 16) | (_cfg[0x38] << 12); - sleep(_cfg[0x36] + 200); - EMC(0x24) = ((_cfg[0x37] << 16) | (_cfg[0x38] << 12)) + 0x100; - sleep(_cfg[0x36] + 2000); - } - EMC(0x24) = ((_cfg[0x37] << 16) | (_cfg[0x38] << 12)) + 0x101; - sleep(_cfg[0x35]); - if (*_cfg != 3) - EMC(0xDC) = (_cfg[0xB2] << 30) + 1; - if (*_cfg == 1) - sleep(_cfg[0x36] + 200); - if (*_cfg == 3) - { - if (_cfg[0x12]) - *(vu32 *)_cfg[0x12] = _cfg[0x13]; - EMC(0x134) = _cfg[0x91]; - EMC(0xE8) = _cfg[0x90]; - EMC(0x138) = _cfg[0x92]; - EMC(0x13C) = _cfg[0x93]; - EMC(0x4A4) = _cfg[0x94]; - EMC(0x4C4) = _cfg[0x9A]; - EMC(0x4AC) = _cfg[0x95]; - EMC(0x4BC) = _cfg[0x98]; - EMC(0x4B0) = _cfg[0x96]; - EMC(0x4C0) = _cfg[0x99]; - if (_cfg[0xFA] << 31) - { - EMC(0x2EC) = _cfg[0xF7]; - sleep(_cfg[0xF9]); - EMC(0x2EC) = _cfg[0xF7] ^ 3; - if (!(_cfg[0xB2] & 2)) - { - EMC(0x2EC) = _cfg[0xF8]; - sleep(_cfg[0xF9]); - EMC(0x2EC) = _cfg[0xF8] ^ 3; - } - } - } - PMC(0x1D0) = _cfg_100[0xF]; - if (_cfg[0] == 1 || _cfg[0] == 2 || _cfg[0] == 3) - { - EMC(0x2E0) = _cfg[0xF3]; - EMC(0x2E4) = _cfg[0xF4]; - EMC(0x2E8) = _cfg[0xF5]; - } - if (_cfg[0x14]) - *(vu32 *)_cfg[0x14] = _cfg[0x15]; - EMC(0x28) = 1; - if (_cfg_100[8]) - EMC(0xD4) = ((1 << _cfg_100[8] << 8) - 0xFD) | (_cfg[0x38] << 30); - EMC(0x20) = _cfg[0xB2] | 0x80000000; - EMC(0x3E0) = _cfg[0xAD]; - EMC(0x5F4) = _cfg[0xA8]; - EMC(0xC) = _cfg[0xA3]; - EMC(0x310) = _cfg[0xB4]; - EMC(0x314) = _cfg[0xB5]; - EMC(0x3D8) = _cfg[0xB3]; - EMC(0x100) = _cfg[0x8A] | 2; - EMC(0x28) = 1; - EMC(0x558) = _cfg[0xA6]; - EMC(0x4D8) = _cfg[0xA7]; - SYSREG(AHB_ARBITRATION_XBAR_CTRL) = SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF | (*((u16 *)_cfg + 0x15C) << 16); - MC(0x650) = _cfg[0x18A]; - MC(0x678) = _cfg[0x18B]; - MC(0x9AC) = _cfg[0x1D9]; - MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of MC registers. -} - -void sdram_init() -{ - u32 sdram_id = _get_sdram_id(); - const u32 *cfg = _dram_cfgs[sdram_id]; //TODO: sdram_id should be in [0,4]. - - i2c_send_byte(I2C_5, 0x3C, 0x22, 0x05); - i2c_send_byte(I2C_5, 0x3C, 0x17, 40); //40 = (1000 * 1100 - 600000) / 12500 - - PMC(APBDEV_PMC_VDDP_SEL) = cfg[0x10C]; - sleep(cfg[0x10D]); - PMC(APBDEV_PMC_DDR_PWR) = PMC(0xE8); - PMC(APBDEV_PMC_NO_IOPOWER) = cfg[0x114]; - PMC(APBDEV_PMC_REG_SHORT) = cfg[0x113]; - PMC(APBDEV_PMC_DDR_CNTRL) = cfg[0x116]; - - if (cfg[8]) - *(vu32 *)cfg[8] = cfg[9]; - - _sdram_config(cfg); -} diff --git a/ipl/ELF.h b/ipl/ELF.h new file mode 100755 index 0000000..2af0859 --- /dev/null +++ b/ipl/ELF.h @@ -0,0 +1,1667 @@ +//===-- llvm/Support/ELF.h - ELF constants and data structures --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains common, non-processor-specific data structures and +// constants for the ELF file format. +// +// The details of the ELF32 bits in this file are largely based on the Tool +// Interface Standard (TIS) Executable and Linking Format (ELF) Specification +// Version 1.2, May 1995. The ELF64 stuff is based on ELF-64 Object File Format +// Version 1.5, Draft 2, May 1998 as well as OpenBSD header files. +// +//===----------------------------------------------------------------------===// + +#ifndef _ELF_H_ +#define _ELF_H_ + +#include "types.h" + +typedef u32 Elf32_Addr; // Program address +typedef u32 Elf32_Off; // File offset +typedef u16 Elf32_Half; +typedef u32 Elf32_Word; +typedef s32 Elf32_Sword; + +typedef u64 Elf64_Addr; +typedef u64 Elf64_Off; +typedef u16 Elf64_Half; +typedef u32 Elf64_Word; +typedef s32 Elf64_Sword; +typedef u64 Elf64_Xword; +typedef s64 Elf64_Sxword; + +// Object file magic string. +static const char ElfMagic[] = {0x7f, 'E', 'L', 'F'}; + +// e_ident size and indices. +enum +{ + EI_MAG0 = 0, // File identification index. + EI_MAG1 = 1, // File identification index. + EI_MAG2 = 2, // File identification index. + EI_MAG3 = 3, // File identification index. + EI_CLASS = 4, // File class. + EI_DATA = 5, // Data encoding. + EI_VERSION = 6, // File version. + EI_OSABI = 7, // OS/ABI identification. + EI_ABIVERSION = 8, // ABI version. + EI_PAD = 9, // Start of padding bytes. + EI_NIDENT = 16 // Number of bytes in e_ident. +}; + +struct Elf32_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes + Elf32_Half e_type; // Type of file (see ET_* below) + Elf32_Half e_machine; // Required architecture for this file (see EM_*) + Elf32_Word e_version; // Must be equal to 1 + Elf32_Addr e_entry; // Address to jump to in order to start program + Elf32_Off e_phoff; // Program header table's file offset, in bytes + Elf32_Off e_shoff; // Section header table's file offset, in bytes + Elf32_Word e_flags; // Processor-specific flags + Elf32_Half e_ehsize; // Size of ELF header, in bytes + Elf32_Half e_phentsize; // Size of an entry in the program header table + Elf32_Half e_phnum; // Number of entries in the program header table + Elf32_Half e_shentsize; // Size of an entry in the section header table + Elf32_Half e_shnum; // Number of entries in the section header table + Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table +}; + +// 64-bit ELF header. Fields are the same as for ELF32, but with different +// types (see above). +struct Elf64_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +}; + +// File types +enum +{ + ET_NONE = 0, // No file type + ET_REL = 1, // Relocatable file + ET_EXEC = 2, // Executable file + ET_DYN = 3, // Shared object file + ET_CORE = 4, // Core file + ET_LOPROC = 0xff00, // Beginning of processor-specific codes + ET_HIPROC = 0xffff // Processor-specific +}; + +// Versioning +enum +{ + EV_NONE = 0, + EV_CURRENT = 1 +}; + +// Machine architectures +enum +{ + EM_NONE = 0, // No machine + EM_M32 = 1, // AT&T WE 32100 + EM_SPARC = 2, // SPARC + EM_386 = 3, // Intel 386 + EM_68K = 4, // Motorola 68000 + EM_88K = 5, // Motorola 88000 + EM_486 = 6, // Intel 486 (deprecated) + EM_860 = 7, // Intel 80860 + EM_MIPS = 8, // MIPS R3000 + EM_S370 = 9, // IBM System/370 + EM_MIPS_RS3_LE = 10, // MIPS RS3000 Little-endian + EM_PARISC = 15, // Hewlett-Packard PA-RISC + EM_VPP500 = 17, // Fujitsu VPP500 + EM_SPARC32PLUS = 18, // Enhanced instruction set SPARC + EM_960 = 19, // Intel 80960 + EM_PPC = 20, // PowerPC + EM_PPC64 = 21, // PowerPC64 + EM_S390 = 22, // IBM System/390 + EM_SPU = 23, // IBM SPU/SPC + EM_V800 = 36, // NEC V800 + EM_FR20 = 37, // Fujitsu FR20 + EM_RH32 = 38, // TRW RH-32 + EM_RCE = 39, // Motorola RCE + EM_ARM = 40, // ARM + EM_ALPHA = 41, // DEC Alpha + EM_SH = 42, // Hitachi SH + EM_SPARCV9 = 43, // SPARC V9 + EM_TRICORE = 44, // Siemens TriCore + EM_ARC = 45, // Argonaut RISC Core + EM_H8_300 = 46, // Hitachi H8/300 + EM_H8_300H = 47, // Hitachi H8/300H + EM_H8S = 48, // Hitachi H8S + EM_H8_500 = 49, // Hitachi H8/500 + EM_IA_64 = 50, // Intel IA-64 processor architecture + EM_MIPS_X = 51, // Stanford MIPS-X + EM_COLDFIRE = 52, // Motorola ColdFire + EM_68HC12 = 53, // Motorola M68HC12 + EM_MMA = 54, // Fujitsu MMA Multimedia Accelerator + EM_PCP = 55, // Siemens PCP + EM_NCPU = 56, // Sony nCPU embedded RISC processor + EM_NDR1 = 57, // Denso NDR1 microprocessor + EM_STARCORE = 58, // Motorola Star*Core processor + EM_ME16 = 59, // Toyota ME16 processor + EM_ST100 = 60, // STMicroelectronics ST100 processor + EM_TINYJ = 61, // Advanced Logic Corp. TinyJ embedded processor family + EM_X86_64 = 62, // AMD x86-64 architecture + EM_PDSP = 63, // Sony DSP Processor + EM_PDP10 = 64, // Digital Equipment Corp. PDP-10 + EM_PDP11 = 65, // Digital Equipment Corp. PDP-11 + EM_FX66 = 66, // Siemens FX66 microcontroller + EM_ST9PLUS = 67, // STMicroelectronics ST9+ 8/16 bit microcontroller + EM_ST7 = 68, // STMicroelectronics ST7 8-bit microcontroller + EM_68HC16 = 69, // Motorola MC68HC16 Microcontroller + EM_68HC11 = 70, // Motorola MC68HC11 Microcontroller + EM_68HC08 = 71, // Motorola MC68HC08 Microcontroller + EM_68HC05 = 72, // Motorola MC68HC05 Microcontroller + EM_SVX = 73, // Silicon Graphics SVx + EM_ST19 = 74, // STMicroelectronics ST19 8-bit microcontroller + EM_VAX = 75, // Digital VAX + EM_CRIS = 76, // Axis Communications 32-bit embedded processor + EM_JAVELIN = 77, // Infineon Technologies 32-bit embedded processor + EM_FIREPATH = 78, // Element 14 64-bit DSP Processor + EM_ZSP = 79, // LSI Logic 16-bit DSP Processor + EM_MMIX = 80, // Donald Knuth's educational 64-bit processor + EM_HUANY = 81, // Harvard University machine-independent object files + EM_PRISM = 82, // SiTera Prism + EM_AVR = 83, // Atmel AVR 8-bit microcontroller + EM_FR30 = 84, // Fujitsu FR30 + EM_D10V = 85, // Mitsubishi D10V + EM_D30V = 86, // Mitsubishi D30V + EM_V850 = 87, // NEC v850 + EM_M32R = 88, // Mitsubishi M32R + EM_MN10300 = 89, // Matsushita MN10300 + EM_MN10200 = 90, // Matsushita MN10200 + EM_PJ = 91, // picoJava + EM_OPENRISC = 92, // OpenRISC 32-bit embedded processor + EM_ARC_COMPACT = 93, // ARC International ARCompact processor (old + // spelling/synonym: EM_ARC_A5) + EM_XTENSA = 94, // Tensilica Xtensa Architecture + EM_VIDEOCORE = 95, // Alphamosaic VideoCore processor + EM_TMM_GPP = 96, // Thompson Multimedia General Purpose Processor + EM_NS32K = 97, // National Semiconductor 32000 series + EM_TPC = 98, // Tenor Network TPC processor + EM_SNP1K = 99, // Trebia SNP 1000 processor + EM_ST200 = 100, // STMicroelectronics (www.st.com) ST200 + EM_IP2K = 101, // Ubicom IP2xxx microcontroller family + EM_MAX = 102, // MAX Processor + EM_CR = 103, // National Semiconductor CompactRISC microprocessor + EM_F2MC16 = 104, // Fujitsu F2MC16 + EM_MSP430 = 105, // Texas Instruments embedded microcontroller msp430 + EM_BLACKFIN = 106, // Analog Devices Blackfin (DSP) processor + EM_SE_C33 = 107, // S1C33 Family of Seiko Epson processors + EM_SEP = 108, // Sharp embedded microprocessor + EM_ARCA = 109, // Arca RISC Microprocessor + EM_UNICORE = 110, // Microprocessor series from PKU-Unity Ltd. and MPRC + // of Peking University + EM_EXCESS = 111, // eXcess: 16/32/64-bit configurable embedded CPU + EM_DXP = 112, // Icera Semiconductor Inc. Deep Execution Processor + EM_ALTERA_NIOS2 = 113, // Altera Nios II soft-core processor + EM_CRX = 114, // National Semiconductor CompactRISC CRX + EM_XGATE = 115, // Motorola XGATE embedded processor + EM_C166 = 116, // Infineon C16x/XC16x processor + EM_M16C = 117, // Renesas M16C series microprocessors + EM_DSPIC30F = 118, // Microchip Technology dsPIC30F Digital Signal + // Controller + EM_CE = 119, // Freescale Communication Engine RISC core + EM_M32C = 120, // Renesas M32C series microprocessors + EM_TSK3000 = 131, // Altium TSK3000 core + EM_RS08 = 132, // Freescale RS08 embedded processor + EM_SHARC = 133, // Analog Devices SHARC family of 32-bit DSP + // processors + EM_ECOG2 = 134, // Cyan Technology eCOG2 microprocessor + EM_SCORE7 = 135, // Sunplus S+core7 RISC processor + EM_DSP24 = 136, // New Japan Radio (NJR) 24-bit DSP Processor + EM_VIDEOCORE3 = 137, // Broadcom VideoCore III processor + EM_LATTICEMICO32 = 138, // RISC processor for Lattice FPGA architecture + EM_SE_C17 = 139, // Seiko Epson C17 family + EM_TI_C6000 = 140, // The Texas Instruments TMS320C6000 DSP family + EM_TI_C2000 = 141, // The Texas Instruments TMS320C2000 DSP family + EM_TI_C5500 = 142, // The Texas Instruments TMS320C55x DSP family + EM_MMDSP_PLUS = 160, // STMicroelectronics 64bit VLIW Data Signal Processor + EM_CYPRESS_M8C = 161, // Cypress M8C microprocessor + EM_R32C = 162, // Renesas R32C series microprocessors + EM_TRIMEDIA = 163, // NXP Semiconductors TriMedia architecture family + EM_HEXAGON = 164, // Qualcomm Hexagon processor + EM_8051 = 165, // Intel 8051 and variants + EM_STXP7X = 166, // STMicroelectronics STxP7x family of configurable + // and extensible RISC processors + EM_NDS32 = 167, // Andes Technology compact code size embedded RISC + // processor family + EM_ECOG1 = 168, // Cyan Technology eCOG1X family + EM_ECOG1X = 168, // Cyan Technology eCOG1X family + EM_MAXQ30 = 169, // Dallas Semiconductor MAXQ30 Core Micro-controllers + EM_XIMO16 = 170, // New Japan Radio (NJR) 16-bit DSP Processor + EM_MANIK = 171, // M2000 Reconfigurable RISC Microprocessor + EM_CRAYNV2 = 172, // Cray Inc. NV2 vector architecture + EM_RX = 173, // Renesas RX family + EM_METAG = 174, // Imagination Technologies META processor + // architecture + EM_MCST_ELBRUS = 175, // MCST Elbrus general purpose hardware architecture + EM_ECOG16 = 176, // Cyan Technology eCOG16 family + EM_CR16 = 177, // National Semiconductor CompactRISC CR16 16-bit + // microprocessor + EM_ETPU = 178, // Freescale Extended Time Processing Unit + EM_SLE9X = 179, // Infineon Technologies SLE9X core + EM_L10M = 180, // Intel L10M + EM_K10M = 181, // Intel K10M + EM_AARCH64 = 183, // ARM AArch64 + EM_AVR32 = 185, // Atmel Corporation 32-bit microprocessor family + EM_STM8 = 186, // STMicroeletronics STM8 8-bit microcontroller + EM_TILE64 = 187, // Tilera TILE64 multicore architecture family + EM_TILEPRO = 188, // Tilera TILEPro multicore architecture family + EM_CUDA = 190, // NVIDIA CUDA architecture + EM_TILEGX = 191, // Tilera TILE-Gx multicore architecture family + EM_CLOUDSHIELD = 192, // CloudShield architecture family + EM_COREA_1ST = 193, // KIPO-KAIST Core-A 1st generation processor family + EM_COREA_2ND = 194, // KIPO-KAIST Core-A 2nd generation processor family + EM_ARC_COMPACT2 = 195, // Synopsys ARCompact V2 + EM_OPEN8 = 196, // Open8 8-bit RISC soft processor core + EM_RL78 = 197, // Renesas RL78 family + EM_VIDEOCORE5 = 198, // Broadcom VideoCore V processor + EM_78KOR = 199, // Renesas 78KOR family + EM_56800EX = 200 // Freescale 56800EX Digital Signal Controller (DSC) +}; + +// Object file classes. +enum +{ + ELFCLASSNONE = 0, + ELFCLASS32 = 1, // 32-bit object file + ELFCLASS64 = 2 // 64-bit object file +}; + +// Object file byte orderings. +enum +{ + ELFDATANONE = 0, // Invalid data encoding. + ELFDATA2LSB = 1, // Little-endian object file + ELFDATA2MSB = 2 // Big-endian object file +}; + +// OS ABI identification. +enum +{ + ELFOSABI_NONE = 0, // UNIX System V ABI + ELFOSABI_HPUX = 1, // HP-UX operating system + ELFOSABI_NETBSD = 2, // NetBSD + ELFOSABI_GNU = 3, // GNU/Linux + ELFOSABI_LINUX = 3, // Historical alias for ELFOSABI_GNU. + ELFOSABI_HURD = 4, // GNU/Hurd + ELFOSABI_SOLARIS = 6, // Solaris + ELFOSABI_AIX = 7, // AIX + ELFOSABI_IRIX = 8, // IRIX + ELFOSABI_FREEBSD = 9, // FreeBSD + ELFOSABI_TRU64 = 10, // TRU64 UNIX + ELFOSABI_MODESTO = 11, // Novell Modesto + ELFOSABI_OPENBSD = 12, // OpenBSD + ELFOSABI_OPENVMS = 13, // OpenVMS + ELFOSABI_NSK = 14, // Hewlett-Packard Non-Stop Kernel + ELFOSABI_AROS = 15, // AROS + ELFOSABI_FENIXOS = 16, // FenixOS + ELFOSABI_C6000_ELFABI = 64, // Bare-metal TMS320C6000 + ELFOSABI_C6000_LINUX = 65, // Linux TMS320C6000 + ELFOSABI_ARM = 97, // ARM + ELFOSABI_STANDALONE = 255 // Standalone (embedded) application +}; + +// X86_64 relocations. +enum +{ + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_GOT32 = 3, + R_X86_64_PLT32 = 4, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_GOTPCREL = 9, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_16 = 12, + R_X86_64_PC16 = 13, + R_X86_64_8 = 14, + R_X86_64_PC8 = 15, + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, + R_X86_64_TLSGD = 19, + R_X86_64_TLSLD = 20, + R_X86_64_DTPOFF32 = 21, + R_X86_64_GOTTPOFF = 22, + R_X86_64_TPOFF32 = 23, + R_X86_64_PC64 = 24, + R_X86_64_GOTOFF64 = 25, + R_X86_64_GOTPC32 = 26, + R_X86_64_GOT64 = 27, + R_X86_64_GOTPCREL64 = 28, + R_X86_64_GOTPC64 = 29, + R_X86_64_GOTPLT64 = 30, + R_X86_64_PLTOFF64 = 31, + R_X86_64_SIZE32 = 32, + R_X86_64_SIZE64 = 33, + R_X86_64_GOTPC32_TLSDESC = 34, + R_X86_64_TLSDESC_CALL = 35, + R_X86_64_TLSDESC = 36, + R_X86_64_IRELATIVE = 37 +}; + +// i386 relocations. +// TODO: this is just a subset +enum +{ + R_386_NONE = 0, + R_386_32 = 1, + R_386_PC32 = 2, + R_386_GOT32 = 3, + R_386_PLT32 = 4, + R_386_COPY = 5, + R_386_GLOB_DAT = 6, + R_386_JUMP_SLOT = 7, + R_386_RELATIVE = 8, + R_386_GOTOFF = 9, + R_386_GOTPC = 10, + R_386_32PLT = 11, + R_386_TLS_TPOFF = 14, + R_386_TLS_IE = 15, + R_386_TLS_GOTIE = 16, + R_386_TLS_LE = 17, + R_386_TLS_GD = 18, + R_386_TLS_LDM = 19, + R_386_16 = 20, + R_386_PC16 = 21, + R_386_8 = 22, + R_386_PC8 = 23, + R_386_TLS_GD_32 = 24, + R_386_TLS_GD_PUSH = 25, + R_386_TLS_GD_CALL = 26, + R_386_TLS_GD_POP = 27, + R_386_TLS_LDM_32 = 28, + R_386_TLS_LDM_PUSH = 29, + R_386_TLS_LDM_CALL = 30, + R_386_TLS_LDM_POP = 31, + R_386_TLS_LDO_32 = 32, + R_386_TLS_IE_32 = 33, + R_386_TLS_LE_32 = 34, + R_386_TLS_DTPMOD32 = 35, + R_386_TLS_DTPOFF32 = 36, + R_386_TLS_TPOFF32 = 37, + R_386_TLS_GOTDESC = 39, + R_386_TLS_DESC_CALL = 40, + R_386_TLS_DESC = 41, + R_386_IRELATIVE = 42, + R_386_NUM = 43 +}; + +// ELF Relocation types for PPC32 +enum +{ + R_PPC_NONE = 0, /* No relocation. */ + R_PPC_ADDR32 = 1, + R_PPC_ADDR24 = 2, + R_PPC_ADDR16 = 3, + R_PPC_ADDR16_LO = 4, + R_PPC_ADDR16_HI = 5, + R_PPC_ADDR16_HA = 6, + R_PPC_ADDR14 = 7, + R_PPC_ADDR14_BRTAKEN = 8, + R_PPC_ADDR14_BRNTAKEN = 9, + R_PPC_REL24 = 10, + R_PPC_REL14 = 11, + R_PPC_REL14_BRTAKEN = 12, + R_PPC_REL14_BRNTAKEN = 13, + R_PPC_GOT16 = 14, + R_PPC_GOT16_LO = 15, + R_PPC_GOT16_HI = 16, + R_PPC_GOT16_HA = 17, + R_PPC_REL32 = 26, + R_PPC_TLS = 67, + R_PPC_DTPMOD32 = 68, + R_PPC_TPREL16 = 69, + R_PPC_TPREL16_LO = 70, + R_PPC_TPREL16_HI = 71, + R_PPC_TPREL16_HA = 72, + R_PPC_TPREL32 = 73, + R_PPC_DTPREL16 = 74, + R_PPC_DTPREL16_LO = 75, + R_PPC_DTPREL16_HI = 76, + R_PPC_DTPREL16_HA = 77, + R_PPC_DTPREL32 = 78, + R_PPC_GOT_TLSGD16 = 79, + R_PPC_GOT_TLSGD16_LO = 80, + R_PPC_GOT_TLSGD16_HI = 81, + R_PPC_GOT_TLSGD16_HA = 82, + R_PPC_GOT_TLSLD16 = 83, + R_PPC_GOT_TLSLD16_LO = 84, + R_PPC_GOT_TLSLD16_HI = 85, + R_PPC_GOT_TLSLD16_HA = 86, + R_PPC_GOT_TPREL16 = 87, + R_PPC_GOT_TPREL16_LO = 88, + R_PPC_GOT_TPREL16_HI = 89, + R_PPC_GOT_TPREL16_HA = 90, + R_PPC_GOT_DTPREL16 = 91, + R_PPC_GOT_DTPREL16_LO = 92, + R_PPC_GOT_DTPREL16_HI = 93, + R_PPC_GOT_DTPREL16_HA = 94, + R_PPC_TLSGD = 95, + R_PPC_TLSLD = 96, + R_PPC_REL16 = 249, + R_PPC_REL16_LO = 250, + R_PPC_REL16_HI = 251, + R_PPC_REL16_HA = 252 +}; + +// ELF Relocation types for PPC64 +enum +{ + R_PPC64_NONE = 0, + R_PPC64_ADDR32 = 1, + R_PPC64_ADDR24 = 2, + R_PPC64_ADDR16 = 3, + R_PPC64_ADDR16_LO = 4, + R_PPC64_ADDR16_HI = 5, + R_PPC64_ADDR16_HA = 6, + R_PPC64_ADDR14 = 7, + R_PPC64_ADDR14_BRTAKEN = 8, + R_PPC64_ADDR14_BRNTAKEN = 9, + R_PPC64_REL24 = 10, + R_PPC64_REL14 = 11, + R_PPC64_REL14_BRTAKEN = 12, + R_PPC64_REL14_BRNTAKEN = 13, + R_PPC64_GOT16 = 14, + R_PPC64_GOT16_LO = 15, + R_PPC64_GOT16_HI = 16, + R_PPC64_GOT16_HA = 17, + R_PPC64_REL32 = 26, + R_PPC64_ADDR64 = 38, + R_PPC64_ADDR16_HIGHER = 39, + R_PPC64_ADDR16_HIGHERA = 40, + R_PPC64_ADDR16_HIGHEST = 41, + R_PPC64_ADDR16_HIGHESTA = 42, + R_PPC64_REL64 = 44, + R_PPC64_TOC16 = 47, + R_PPC64_TOC16_LO = 48, + R_PPC64_TOC16_HI = 49, + R_PPC64_TOC16_HA = 50, + R_PPC64_TOC = 51, + R_PPC64_ADDR16_DS = 56, + R_PPC64_ADDR16_LO_DS = 57, + R_PPC64_GOT16_DS = 58, + R_PPC64_GOT16_LO_DS = 59, + R_PPC64_TOC16_DS = 63, + R_PPC64_TOC16_LO_DS = 64, + R_PPC64_TLS = 67, + R_PPC64_DTPMOD64 = 68, + R_PPC64_TPREL16 = 69, + R_PPC64_TPREL16_LO = 70, + R_PPC64_TPREL16_HI = 71, + R_PPC64_TPREL16_HA = 72, + R_PPC64_TPREL64 = 73, + R_PPC64_DTPREL16 = 74, + R_PPC64_DTPREL16_LO = 75, + R_PPC64_DTPREL16_HI = 76, + R_PPC64_DTPREL16_HA = 77, + R_PPC64_DTPREL64 = 78, + R_PPC64_GOT_TLSGD16 = 79, + R_PPC64_GOT_TLSGD16_LO = 80, + R_PPC64_GOT_TLSGD16_HI = 81, + R_PPC64_GOT_TLSGD16_HA = 82, + R_PPC64_GOT_TLSLD16 = 83, + R_PPC64_GOT_TLSLD16_LO = 84, + R_PPC64_GOT_TLSLD16_HI = 85, + R_PPC64_GOT_TLSLD16_HA = 86, + R_PPC64_GOT_TPREL16_DS = 87, + R_PPC64_GOT_TPREL16_LO_DS = 88, + R_PPC64_GOT_TPREL16_HI = 89, + R_PPC64_GOT_TPREL16_HA = 90, + R_PPC64_GOT_DTPREL16_DS = 91, + R_PPC64_GOT_DTPREL16_LO_DS = 92, + R_PPC64_GOT_DTPREL16_HI = 93, + R_PPC64_GOT_DTPREL16_HA = 94, + R_PPC64_TPREL16_DS = 95, + R_PPC64_TPREL16_LO_DS = 96, + R_PPC64_TPREL16_HIGHER = 97, + R_PPC64_TPREL16_HIGHERA = 98, + R_PPC64_TPREL16_HIGHEST = 99, + R_PPC64_TPREL16_HIGHESTA = 100, + R_PPC64_DTPREL16_DS = 101, + R_PPC64_DTPREL16_LO_DS = 102, + R_PPC64_DTPREL16_HIGHER = 103, + R_PPC64_DTPREL16_HIGHERA = 104, + R_PPC64_DTPREL16_HIGHEST = 105, + R_PPC64_DTPREL16_HIGHESTA = 106, + R_PPC64_TLSGD = 107, + R_PPC64_TLSLD = 108, + R_PPC64_REL16 = 249, + R_PPC64_REL16_LO = 250, + R_PPC64_REL16_HI = 251, + R_PPC64_REL16_HA = 252 +}; + +// ELF Relocation types for AArch64 + +enum +{ + R_AARCH64_NONE = 0x100, + + R_AARCH64_ABS64 = 0x101, + R_AARCH64_ABS32 = 0x102, + R_AARCH64_ABS16 = 0x103, + R_AARCH64_PREL64 = 0x104, + R_AARCH64_PREL32 = 0x105, + R_AARCH64_PREL16 = 0x106, + + R_AARCH64_MOVW_UABS_G0 = 0x107, + R_AARCH64_MOVW_UABS_G0_NC = 0x108, + R_AARCH64_MOVW_UABS_G1 = 0x109, + R_AARCH64_MOVW_UABS_G1_NC = 0x10a, + R_AARCH64_MOVW_UABS_G2 = 0x10b, + R_AARCH64_MOVW_UABS_G2_NC = 0x10c, + R_AARCH64_MOVW_UABS_G3 = 0x10d, + R_AARCH64_MOVW_SABS_G0 = 0x10e, + R_AARCH64_MOVW_SABS_G1 = 0x10f, + R_AARCH64_MOVW_SABS_G2 = 0x110, + + R_AARCH64_LD_PREL_LO19 = 0x111, + R_AARCH64_ADR_PREL_LO21 = 0x112, + R_AARCH64_ADR_PREL_PG_HI21 = 0x113, + R_AARCH64_ADD_ABS_LO12_NC = 0x115, + R_AARCH64_LDST8_ABS_LO12_NC = 0x116, + + R_AARCH64_TSTBR14 = 0x117, + R_AARCH64_CONDBR19 = 0x118, + R_AARCH64_JUMP26 = 0x11a, + R_AARCH64_CALL26 = 0x11b, + + R_AARCH64_LDST16_ABS_LO12_NC = 0x11c, + R_AARCH64_LDST32_ABS_LO12_NC = 0x11d, + R_AARCH64_LDST64_ABS_LO12_NC = 0x11e, + + R_AARCH64_LDST128_ABS_LO12_NC = 0x12b, + + R_AARCH64_ADR_GOT_PAGE = 0x137, + R_AARCH64_LD64_GOT_LO12_NC = 0x138, + + R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 0x20b, + R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 0x20c, + R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 0x20d, + R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 0x20e, + R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 0x20f, + R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 0x210, + R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 0x211, + R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 0x212, + R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 0x213, + R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 0x214, + R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 0x215, + R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 0x216, + R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 0x217, + R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 0x218, + R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 0x219, + R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 0x21a, + + R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 0x21b, + R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 0x21c, + R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 0x21d, + R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 0x21e, + R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 0x21f, + + R_AARCH64_TLSLE_MOVW_TPREL_G2 = 0x220, + R_AARCH64_TLSLE_MOVW_TPREL_G1 = 0x221, + R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 0x222, + R_AARCH64_TLSLE_MOVW_TPREL_G0 = 0x223, + R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 0x224, + R_AARCH64_TLSLE_ADD_TPREL_HI12 = 0x225, + R_AARCH64_TLSLE_ADD_TPREL_LO12 = 0x226, + R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 0x227, + R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 0x228, + R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 0x229, + R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 0x22a, + R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 0x22b, + R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 0x22c, + R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 0x22d, + R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 0x22e, + R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 0x22f, + + R_AARCH64_TLSDESC_ADR_PAGE = 0x232, + R_AARCH64_TLSDESC_LD64_LO12_NC = 0x233, + R_AARCH64_TLSDESC_ADD_LO12_NC = 0x234, + + R_AARCH64_TLSDESC_CALL = 0x239 +}; + +// ARM Specific e_flags +enum : u32 +{ + EF_ARM_SOFT_FLOAT = 0x00000200U, + EF_ARM_VFP_FLOAT = 0x00000400U, + EF_ARM_EABI_UNKNOWN = 0x00000000U, + EF_ARM_EABI_VER1 = 0x01000000U, + EF_ARM_EABI_VER2 = 0x02000000U, + EF_ARM_EABI_VER3 = 0x03000000U, + EF_ARM_EABI_VER4 = 0x04000000U, + EF_ARM_EABI_VER5 = 0x05000000U, + EF_ARM_EABIMASK = 0xFF000000U +}; + +// ELF Relocation types for ARM +// Meets 2.08 ABI Specs. + +enum +{ + R_ARM_NONE = 0x00, + R_ARM_PC24 = 0x01, + R_ARM_ABS32 = 0x02, + R_ARM_REL32 = 0x03, + R_ARM_LDR_PC_G0 = 0x04, + R_ARM_ABS16 = 0x05, + R_ARM_ABS12 = 0x06, + R_ARM_THM_ABS5 = 0x07, + R_ARM_ABS8 = 0x08, + R_ARM_SBREL32 = 0x09, + R_ARM_THM_CALL = 0x0a, + R_ARM_THM_PC8 = 0x0b, + R_ARM_BREL_ADJ = 0x0c, + R_ARM_TLS_DESC = 0x0d, + R_ARM_THM_SWI8 = 0x0e, + R_ARM_XPC25 = 0x0f, + R_ARM_THM_XPC22 = 0x10, + R_ARM_TLS_DTPMOD32 = 0x11, + R_ARM_TLS_DTPOFF32 = 0x12, + R_ARM_TLS_TPOFF32 = 0x13, + R_ARM_COPY = 0x14, + R_ARM_GLOB_DAT = 0x15, + R_ARM_JUMP_SLOT = 0x16, + R_ARM_RELATIVE = 0x17, + R_ARM_GOTOFF32 = 0x18, + R_ARM_BASE_PREL = 0x19, + R_ARM_GOT_BREL = 0x1a, + R_ARM_PLT32 = 0x1b, + R_ARM_CALL = 0x1c, + R_ARM_JUMP24 = 0x1d, + R_ARM_THM_JUMP24 = 0x1e, + R_ARM_BASE_ABS = 0x1f, + R_ARM_ALU_PCREL_7_0 = 0x20, + R_ARM_ALU_PCREL_15_8 = 0x21, + R_ARM_ALU_PCREL_23_15 = 0x22, + R_ARM_LDR_SBREL_11_0_NC = 0x23, + R_ARM_ALU_SBREL_19_12_NC = 0x24, + R_ARM_ALU_SBREL_27_20_CK = 0x25, + R_ARM_TARGET1 = 0x26, + R_ARM_SBREL31 = 0x27, + R_ARM_V4BX = 0x28, + R_ARM_TARGET2 = 0x29, + R_ARM_PREL31 = 0x2a, + R_ARM_MOVW_ABS_NC = 0x2b, + R_ARM_MOVT_ABS = 0x2c, + R_ARM_MOVW_PREL_NC = 0x2d, + R_ARM_MOVT_PREL = 0x2e, + R_ARM_THM_MOVW_ABS_NC = 0x2f, + R_ARM_THM_MOVT_ABS = 0x30, + R_ARM_THM_MOVW_PREL_NC = 0x31, + R_ARM_THM_MOVT_PREL = 0x32, + R_ARM_THM_JUMP19 = 0x33, + R_ARM_THM_JUMP6 = 0x34, + R_ARM_THM_ALU_PREL_11_0 = 0x35, + R_ARM_THM_PC12 = 0x36, + R_ARM_ABS32_NOI = 0x37, + R_ARM_REL32_NOI = 0x38, + R_ARM_ALU_PC_G0_NC = 0x39, + R_ARM_ALU_PC_G0 = 0x3a, + R_ARM_ALU_PC_G1_NC = 0x3b, + R_ARM_ALU_PC_G1 = 0x3c, + R_ARM_ALU_PC_G2 = 0x3d, + R_ARM_LDR_PC_G1 = 0x3e, + R_ARM_LDR_PC_G2 = 0x3f, + R_ARM_LDRS_PC_G0 = 0x40, + R_ARM_LDRS_PC_G1 = 0x41, + R_ARM_LDRS_PC_G2 = 0x42, + R_ARM_LDC_PC_G0 = 0x43, + R_ARM_LDC_PC_G1 = 0x44, + R_ARM_LDC_PC_G2 = 0x45, + R_ARM_ALU_SB_G0_NC = 0x46, + R_ARM_ALU_SB_G0 = 0x47, + R_ARM_ALU_SB_G1_NC = 0x48, + R_ARM_ALU_SB_G1 = 0x49, + R_ARM_ALU_SB_G2 = 0x4a, + R_ARM_LDR_SB_G0 = 0x4b, + R_ARM_LDR_SB_G1 = 0x4c, + R_ARM_LDR_SB_G2 = 0x4d, + R_ARM_LDRS_SB_G0 = 0x4e, + R_ARM_LDRS_SB_G1 = 0x4f, + R_ARM_LDRS_SB_G2 = 0x50, + R_ARM_LDC_SB_G0 = 0x51, + R_ARM_LDC_SB_G1 = 0x52, + R_ARM_LDC_SB_G2 = 0x53, + R_ARM_MOVW_BREL_NC = 0x54, + R_ARM_MOVT_BREL = 0x55, + R_ARM_MOVW_BREL = 0x56, + R_ARM_THM_MOVW_BREL_NC = 0x57, + R_ARM_THM_MOVT_BREL = 0x58, + R_ARM_THM_MOVW_BREL = 0x59, + R_ARM_TLS_GOTDESC = 0x5a, + R_ARM_TLS_CALL = 0x5b, + R_ARM_TLS_DESCSEQ = 0x5c, + R_ARM_THM_TLS_CALL = 0x5d, + R_ARM_PLT32_ABS = 0x5e, + R_ARM_GOT_ABS = 0x5f, + R_ARM_GOT_PREL = 0x60, + R_ARM_GOT_BREL12 = 0x61, + R_ARM_GOTOFF12 = 0x62, + R_ARM_GOTRELAX = 0x63, + R_ARM_GNU_VTENTRY = 0x64, + R_ARM_GNU_VTINHERIT = 0x65, + R_ARM_THM_JUMP11 = 0x66, + R_ARM_THM_JUMP8 = 0x67, + R_ARM_TLS_GD32 = 0x68, + R_ARM_TLS_LDM32 = 0x69, + R_ARM_TLS_LDO32 = 0x6a, + R_ARM_TLS_IE32 = 0x6b, + R_ARM_TLS_LE32 = 0x6c, + R_ARM_TLS_LDO12 = 0x6d, + R_ARM_TLS_LE12 = 0x6e, + R_ARM_TLS_IE12GP = 0x6f, + R_ARM_PRIVATE_0 = 0x70, + R_ARM_PRIVATE_1 = 0x71, + R_ARM_PRIVATE_2 = 0x72, + R_ARM_PRIVATE_3 = 0x73, + R_ARM_PRIVATE_4 = 0x74, + R_ARM_PRIVATE_5 = 0x75, + R_ARM_PRIVATE_6 = 0x76, + R_ARM_PRIVATE_7 = 0x77, + R_ARM_PRIVATE_8 = 0x78, + R_ARM_PRIVATE_9 = 0x79, + R_ARM_PRIVATE_10 = 0x7a, + R_ARM_PRIVATE_11 = 0x7b, + R_ARM_PRIVATE_12 = 0x7c, + R_ARM_PRIVATE_13 = 0x7d, + R_ARM_PRIVATE_14 = 0x7e, + R_ARM_PRIVATE_15 = 0x7f, + R_ARM_ME_TOO = 0x80, + R_ARM_THM_TLS_DESCSEQ16 = 0x81, + R_ARM_THM_TLS_DESCSEQ32 = 0x82 +}; + +// Mips Specific e_flags +enum : u32 +{ + EF_MIPS_NOREORDER = 0x00000001, // Don't reorder instructions + EF_MIPS_PIC = 0x00000002, // Position independent code + EF_MIPS_CPIC = 0x00000004, // Call object with Position independent code + EF_MIPS_ABI_O32 = 0x00001000, // This file follows the first MIPS 32 bit ABI + + //ARCH_ASE + EF_MIPS_MICROMIPS = 0x02000000, // microMIPS + EF_MIPS_ARCH_ASE_M16 = + 0x04000000, // Has Mips-16 ISA extensions + //ARCH + EF_MIPS_ARCH_1 = 0x00000000, // MIPS1 instruction set + EF_MIPS_ARCH_2 = 0x10000000, // MIPS2 instruction set + EF_MIPS_ARCH_3 = 0x20000000, // MIPS3 instruction set + EF_MIPS_ARCH_4 = 0x30000000, // MIPS4 instruction set + EF_MIPS_ARCH_5 = 0x40000000, // MIPS5 instruction set + EF_MIPS_ARCH_32 = 0x50000000, // MIPS32 instruction set per linux not elf.h + EF_MIPS_ARCH_64 = 0x60000000, // MIPS64 instruction set per linux not elf.h + EF_MIPS_ARCH_32R2 = 0x70000000, // mips32r2 + EF_MIPS_ARCH_64R2 = 0x80000000, // mips64r2 + EF_MIPS_ARCH = 0xf0000000 // Mask for applying EF_MIPS_ARCH_ variant +}; + +// ELF Relocation types for Mips +// . +enum +{ + R_MIPS_NONE = 0, + R_MIPS_16 = 1, + R_MIPS_32 = 2, + R_MIPS_REL32 = 3, + R_MIPS_26 = 4, + R_MIPS_HI16 = 5, + R_MIPS_LO16 = 6, + R_MIPS_GPREL16 = 7, + R_MIPS_LITERAL = 8, + R_MIPS_GOT16 = 9, + R_MIPS_GOT = 9, + R_MIPS_PC16 = 10, + R_MIPS_CALL16 = 11, + R_MIPS_GPREL32 = 12, + R_MIPS_UNUSED1 = 13, + R_MIPS_UNUSED2 = 14, + R_MIPS_SHIFT5 = 16, + R_MIPS_SHIFT6 = 17, + R_MIPS_64 = 18, + R_MIPS_GOT_DISP = 19, + R_MIPS_GOT_PAGE = 20, + R_MIPS_GOT_OFST = 21, + R_MIPS_GOT_HI16 = 22, + R_MIPS_GOT_LO16 = 23, + R_MIPS_SUB = 24, + R_MIPS_INSERT_A = 25, + R_MIPS_INSERT_B = 26, + R_MIPS_DELETE = 27, + R_MIPS_HIGHER = 28, + R_MIPS_HIGHEST = 29, + R_MIPS_CALL_HI16 = 30, + R_MIPS_CALL_LO16 = 31, + R_MIPS_SCN_DISP = 32, + R_MIPS_REL16 = 33, + R_MIPS_ADD_IMMEDIATE = 34, + R_MIPS_PJUMP = 35, + R_MIPS_RELGOT = 36, + R_MIPS_JALR = 37, + R_MIPS_TLS_DTPMOD32 = 38, + R_MIPS_TLS_DTPREL32 = 39, + R_MIPS_TLS_DTPMOD64 = 40, + R_MIPS_TLS_DTPREL64 = 41, + R_MIPS_TLS_GD = 42, + R_MIPS_TLS_LDM = 43, + R_MIPS_TLS_DTPREL_HI16 = 44, + R_MIPS_TLS_DTPREL_LO16 = 45, + R_MIPS_TLS_GOTTPREL = 46, + R_MIPS_TLS_TPREL32 = 47, + R_MIPS_TLS_TPREL64 = 48, + R_MIPS_TLS_TPREL_HI16 = 49, + R_MIPS_TLS_TPREL_LO16 = 50, + R_MIPS_GLOB_DAT = 51, + R_MIPS_COPY = 126, + R_MIPS_JUMP_SLOT = 127, + R_MIPS_NUM = 218 +}; + +// Special values for the st_other field in the symbol table entry for MIPS. +enum +{ + STO_MIPS_MICROMIPS = 0x80 // MIPS Specific ISA for MicroMips +}; + +// Hexagon Specific e_flags +// Release 5 ABI +enum +{ + // Object processor version flags, bits[3:0] + EF_HEXAGON_MACH_V2 = 0x00000001, // Hexagon V2 + EF_HEXAGON_MACH_V3 = 0x00000002, // Hexagon V3 + EF_HEXAGON_MACH_V4 = 0x00000003, // Hexagon V4 + EF_HEXAGON_MACH_V5 = 0x00000004, // Hexagon V5 + + // Highest ISA version flags + EF_HEXAGON_ISA_MACH = 0x00000000, // Same as specified in bits[3:0] + // of e_flags + EF_HEXAGON_ISA_V2 = 0x00000010, // Hexagon V2 ISA + EF_HEXAGON_ISA_V3 = 0x00000020, // Hexagon V3 ISA + EF_HEXAGON_ISA_V4 = 0x00000030, // Hexagon V4 ISA + EF_HEXAGON_ISA_V5 = 0x00000040 // Hexagon V5 ISA +}; + +// Hexagon specific Section indexes for common small data +// Release 5 ABI +enum +{ + SHN_HEXAGON_SCOMMON = 0xff00, // Other access sizes + SHN_HEXAGON_SCOMMON_1 = 0xff01, // Byte-sized access + SHN_HEXAGON_SCOMMON_2 = 0xff02, // Half-word-sized access + SHN_HEXAGON_SCOMMON_4 = 0xff03, // Word-sized access + SHN_HEXAGON_SCOMMON_8 = 0xff04 // Double-word-size access +}; + +// ELF Relocation types for Hexagon +// Release 5 ABI +enum +{ + R_HEX_NONE = 0, + R_HEX_B22_PCREL = 1, + R_HEX_B15_PCREL = 2, + R_HEX_B7_PCREL = 3, + R_HEX_LO16 = 4, + R_HEX_HI16 = 5, + R_HEX_32 = 6, + R_HEX_16 = 7, + R_HEX_8 = 8, + R_HEX_GPREL16_0 = 9, + R_HEX_GPREL16_1 = 10, + R_HEX_GPREL16_2 = 11, + R_HEX_GPREL16_3 = 12, + R_HEX_HL16 = 13, + R_HEX_B13_PCREL = 14, + R_HEX_B9_PCREL = 15, + R_HEX_B32_PCREL_X = 16, + R_HEX_32_6_X = 17, + R_HEX_B22_PCREL_X = 18, + R_HEX_B15_PCREL_X = 19, + R_HEX_B13_PCREL_X = 20, + R_HEX_B9_PCREL_X = 21, + R_HEX_B7_PCREL_X = 22, + R_HEX_16_X = 23, + R_HEX_12_X = 24, + R_HEX_11_X = 25, + R_HEX_10_X = 26, + R_HEX_9_X = 27, + R_HEX_8_X = 28, + R_HEX_7_X = 29, + R_HEX_6_X = 30, + R_HEX_32_PCREL = 31, + R_HEX_COPY = 32, + R_HEX_GLOB_DAT = 33, + R_HEX_JMP_SLOT = 34, + R_HEX_RELATIVE = 35, + R_HEX_PLT_B22_PCREL = 36, + R_HEX_GOTREL_LO16 = 37, + R_HEX_GOTREL_HI16 = 38, + R_HEX_GOTREL_32 = 39, + R_HEX_GOT_LO16 = 40, + R_HEX_GOT_HI16 = 41, + R_HEX_GOT_32 = 42, + R_HEX_GOT_16 = 43, + R_HEX_DTPMOD_32 = 44, + R_HEX_DTPREL_LO16 = 45, + R_HEX_DTPREL_HI16 = 46, + R_HEX_DTPREL_32 = 47, + R_HEX_DTPREL_16 = 48, + R_HEX_GD_PLT_B22_PCREL = 49, + R_HEX_GD_GOT_LO16 = 50, + R_HEX_GD_GOT_HI16 = 51, + R_HEX_GD_GOT_32 = 52, + R_HEX_GD_GOT_16 = 53, + R_HEX_IE_LO16 = 54, + R_HEX_IE_HI16 = 55, + R_HEX_IE_32 = 56, + R_HEX_IE_GOT_LO16 = 57, + R_HEX_IE_GOT_HI16 = 58, + R_HEX_IE_GOT_32 = 59, + R_HEX_IE_GOT_16 = 60, + R_HEX_TPREL_LO16 = 61, + R_HEX_TPREL_HI16 = 62, + R_HEX_TPREL_32 = 63, + R_HEX_TPREL_16 = 64, + R_HEX_6_PCREL_X = 65, + R_HEX_GOTREL_32_6_X = 66, + R_HEX_GOTREL_16_X = 67, + R_HEX_GOTREL_11_X = 68, + R_HEX_GOT_32_6_X = 69, + R_HEX_GOT_16_X = 70, + R_HEX_GOT_11_X = 71, + R_HEX_DTPREL_32_6_X = 72, + R_HEX_DTPREL_16_X = 73, + R_HEX_DTPREL_11_X = 74, + R_HEX_GD_GOT_32_6_X = 75, + R_HEX_GD_GOT_16_X = 76, + R_HEX_GD_GOT_11_X = 77, + R_HEX_IE_32_6_X = 78, + R_HEX_IE_16_X = 79, + R_HEX_IE_GOT_32_6_X = 80, + R_HEX_IE_GOT_16_X = 81, + R_HEX_IE_GOT_11_X = 82, + R_HEX_TPREL_32_6_X = 83, + R_HEX_TPREL_16_X = 84, + R_HEX_TPREL_11_X = 85 +}; + +// ELF Relocation types for S390/zSeries +enum +{ + R_390_NONE = 0, + R_390_8 = 1, + R_390_12 = 2, + R_390_16 = 3, + R_390_32 = 4, + R_390_PC32 = 5, + R_390_GOT12 = 6, + R_390_GOT32 = 7, + R_390_PLT32 = 8, + R_390_COPY = 9, + R_390_GLOB_DAT = 10, + R_390_JMP_SLOT = 11, + R_390_RELATIVE = 12, + R_390_GOTOFF = 13, + R_390_GOTPC = 14, + R_390_GOT16 = 15, + R_390_PC16 = 16, + R_390_PC16DBL = 17, + R_390_PLT16DBL = 18, + R_390_PC32DBL = 19, + R_390_PLT32DBL = 20, + R_390_GOTPCDBL = 21, + R_390_64 = 22, + R_390_PC64 = 23, + R_390_GOT64 = 24, + R_390_PLT64 = 25, + R_390_GOTENT = 26, + R_390_GOTOFF16 = 27, + R_390_GOTOFF64 = 28, + R_390_GOTPLT12 = 29, + R_390_GOTPLT16 = 30, + R_390_GOTPLT32 = 31, + R_390_GOTPLT64 = 32, + R_390_GOTPLTENT = 33, + R_390_PLTOFF16 = 34, + R_390_PLTOFF32 = 35, + R_390_PLTOFF64 = 36, + R_390_TLS_LOAD = 37, + R_390_TLS_GDCALL = 38, + R_390_TLS_LDCALL = 39, + R_390_TLS_GD32 = 40, + R_390_TLS_GD64 = 41, + R_390_TLS_GOTIE12 = 42, + R_390_TLS_GOTIE32 = 43, + R_390_TLS_GOTIE64 = 44, + R_390_TLS_LDM32 = 45, + R_390_TLS_LDM64 = 46, + R_390_TLS_IE32 = 47, + R_390_TLS_IE64 = 48, + R_390_TLS_IEENT = 49, + R_390_TLS_LE32 = 50, + R_390_TLS_LE64 = 51, + R_390_TLS_LDO32 = 52, + R_390_TLS_LDO64 = 53, + R_390_TLS_DTPMOD = 54, + R_390_TLS_DTPOFF = 55, + R_390_TLS_TPOFF = 56, + R_390_20 = 57, + R_390_GOT20 = 58, + R_390_GOTPLT20 = 59, + R_390_TLS_GOTIE20 = 60, + R_390_IRELATIVE = 61 +}; + +// Section header. +struct Elf32_Shdr +{ + Elf32_Word sh_name; // Section name (index into string table) + Elf32_Word sh_type; // Section type (SHT_*) + Elf32_Word sh_flags; // Section flags (SHF_*) + Elf32_Addr sh_addr; // Address where section is to be loaded + Elf32_Off sh_offset; // File offset of section data, in bytes + Elf32_Word sh_size; // Size of section, in bytes + Elf32_Word sh_link; // Section type-specific header table index link + Elf32_Word sh_info; // Section type-specific extra information + Elf32_Word sh_addralign; // Section address alignment + Elf32_Word sh_entsize; // Size of records contained within the section +}; + +// Section header for ELF64 - same fields as ELF32, different types. +struct Elf64_Shdr +{ + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +}; + +// Special section indices. +enum +{ + SHN_UNDEF = 0, // Undefined, missing, irrelevant, or meaningless + SHN_LORESERVE = 0xff00, // Lowest reserved index + SHN_LOPROC = 0xff00, // Lowest processor-specific index + SHN_HIPROC = 0xff1f, // Highest processor-specific index + SHN_LOOS = 0xff20, // Lowest operating system-specific index + SHN_HIOS = 0xff3f, // Highest operating system-specific index + SHN_ABS = 0xfff1, // Symbol has absolute value; does not need relocation + SHN_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables + SHN_XINDEX = 0xffff, // Mark that the index is >= SHN_LORESERVE + SHN_HIRESERVE = 0xffff // Highest reserved index +}; + +// Section types. +enum : u32 +{ + SHT_NULL = 0, // No associated section (inactive entry). + SHT_PROGBITS = 1, // Program-defined contents. + SHT_SYMTAB = 2, // Symbol table. + SHT_STRTAB = 3, // String table. + SHT_RELA = 4, // Relocation entries; explicit addends. + SHT_HASH = 5, // Symbol hash table. + SHT_DYNAMIC = 6, // Information for dynamic linking. + SHT_NOTE = 7, // Information about the file. + SHT_NOBITS = 8, // Data occupies no space in the file. + SHT_REL = 9, // Relocation entries; no explicit addends. + SHT_SHLIB = 10, // Reserved. + SHT_DYNSYM = 11, // Symbol table. + SHT_INIT_ARRAY = 14, // Pointers to initialization functions. + SHT_FINI_ARRAY = 15, // Pointers to termination functions. + SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions. + SHT_GROUP = 17, // Section group. + SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries. + SHT_LOOS = 0x60000000, // Lowest operating system-specific type. + SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes. + SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table. + SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions. + SHT_GNU_verneed = 0x6ffffffe, // GNU version references. + SHT_GNU_versym = 0x6fffffff, // GNU symbol versions table. + SHT_HIOS = 0x6fffffff, // Highest operating system-specific type. + SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type. + // Fixme: All this is duplicated in MCSectionELF. Why?? + // Exception Index table + SHT_ARM_EXIDX = 0x70000001U, + // BPABI DLL dynamic linking pre-emption map + SHT_ARM_PREEMPTMAP = 0x70000002U, + // Object file compatibility attributes + SHT_ARM_ATTRIBUTES = 0x70000003U, + SHT_ARM_DEBUGOVERLAY = 0x70000004U, + SHT_ARM_OVERLAYSECTION = 0x70000005U, + SHT_HEX_ORDERED = 0x70000000, // Link editor is to sort the entries in + // this section based on their sizes + SHT_X86_64_UNWIND = 0x70000001, // Unwind information + + SHT_MIPS_REGINFO = 0x70000006, // Register usage information + SHT_MIPS_OPTIONS = 0x7000000d, // General options + + SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. + SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. + SHT_HIUSER = 0xffffffff // Highest type reserved for applications. +}; + +// Section flags. +enum : u32 +{ + // Section data should be writable during execution. + SHF_WRITE = 0x1, + + // Section occupies memory during program execution. + SHF_ALLOC = 0x2, + + // Section contains executable machine instructions. + SHF_EXECINSTR = 0x4, + + // The data in this section may be merged. + SHF_MERGE = 0x10, + + // The data in this section is null-terminated strings. + SHF_STRINGS = 0x20, + + // A field in this section holds a section header table index. + SHF_INFO_LINK = 0x40U, + + // Adds special ordering requirements for link editors. + SHF_LINK_ORDER = 0x80U, + + // This section requires special OS-specific processing to avoid incorrect + // behavior. + SHF_OS_NONCONFORMING = 0x100U, + + // This section is a member of a section group. + SHF_GROUP = 0x200U, + + // This section holds Thread-Local Storage. + SHF_TLS = 0x400U, + + // This section is excluded from the final executable or shared library. + SHF_EXCLUDE = 0x80000000U, + + // Start of target-specific flags. + + /// XCORE_SHF_CP_SECTION - All sections with the "c" flag are grouped + /// together by the linker to form the constant pool and the cp register is + /// set to the start of the constant pool by the boot code. + XCORE_SHF_CP_SECTION = 0x800U, + + /// XCORE_SHF_DP_SECTION - All sections with the "d" flag are grouped + /// together by the linker to form the data section and the dp register is + /// set to the start of the section by the boot code. + XCORE_SHF_DP_SECTION = 0x1000U, + + SHF_MASKOS = 0x0ff00000, + + // Bits indicating processor-specific flags. + SHF_MASKPROC = 0xf0000000, + + // If an object file section does not have this flag set, then it may not hold + // more than 2GB and can be freely referred to in objects using smaller code + // models. Otherwise, only objects using larger code models can refer to them. + // For example, a medium code model object can refer to data in a section that + // sets this flag besides being able to refer to data in a section that does + // not set it; likewise, a small code model object can refer only to code in a + // section that does not set this flag. + SHF_X86_64_LARGE = 0x10000000, + + // All sections with the GPREL flag are grouped into a global data area + // for faster accesses + SHF_HEX_GPREL = 0x10000000, + + // Do not strip this section. FIXME: We need target specific SHF_ enums. + SHF_MIPS_NOSTRIP = 0x8000000 +}; + +// Section Group Flags +enum : u32 +{ + GRP_COMDAT = 0x1, + GRP_MASKOS = 0x0ff00000, + GRP_MASKPROC = 0xf0000000 +}; + +// Symbol table entries for ELF32. +struct Elf32_Sym +{ + Elf32_Word st_name; // Symbol name (index into string table) + Elf32_Addr st_value; // Value or address associated with the symbol + Elf32_Word st_size; // Size of the symbol + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf32_Half st_shndx; // Which section (header table index) it's defined in +}; + +// Symbol table entries for ELF64. +struct Elf64_Sym +{ + Elf64_Word st_name; // Symbol name (index into string table) + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf64_Half st_shndx; // Which section (header tbl index) it's defined in + Elf64_Addr st_value; // Value or address associated with the symbol + Elf64_Xword st_size; // Size of the symbol +}; + +// The size (in bytes) of symbol table entries. +enum +{ + SYMENTRY_SIZE32 = 16, // 32-bit symbol entry size + SYMENTRY_SIZE64 = 24 // 64-bit symbol entry size. +}; + +// Symbol bindings. +enum +{ + STB_LOCAL = 0, // Local symbol, not visible outside obj file containing def + STB_GLOBAL = 1, // Global symbol, visible to all object files being combined + STB_WEAK = 2, // Weak symbol, like global but lower-precedence + STB_LOOS = 10, // Lowest operating system-specific binding type + STB_HIOS = 12, // Highest operating system-specific binding type + STB_LOPROC = 13, // Lowest processor-specific binding type + STB_HIPROC = 15 // Highest processor-specific binding type +}; + +// Symbol types. +enum +{ + STT_NOTYPE = 0, // Symbol's type is not specified + STT_OBJECT = 1, // Symbol is a data object (variable, array, etc.) + STT_FUNC = 2, // Symbol is executable code (function, etc.) + STT_SECTION = 3, // Symbol refers to a section + STT_FILE = 4, // Local, absolute symbol that refers to a file + STT_COMMON = 5, // An uninitialized common block + STT_TLS = 6, // Thread local data object + STT_LOOS = 7, // Lowest operating system-specific symbol type + STT_HIOS = 8, // Highest operating system-specific symbol type + STT_GNU_IFUNC = 10, // GNU indirect function + STT_LOPROC = 13, // Lowest processor-specific symbol type + STT_HIPROC = 15 // Highest processor-specific symbol type +}; + +enum +{ + STV_DEFAULT = 0, // Visibility is specified by binding type + STV_INTERNAL = 1, // Defined by processor supplements + STV_HIDDEN = 2, // Not visible to other components + STV_PROTECTED = 3 // Visible in other components but not preemptable +}; + +// Symbol number. +enum +{ + STN_UNDEF = 0 +}; + +// Relocation entry, without explicit addend. +struct Elf32_Rel +{ + Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf32_Word r_info; // Symbol table index and type of relocation to apply +}; + +// Relocation entry with explicit addend. +struct Elf32_Rela +{ + Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf32_Word r_info; // Symbol table index and type of relocation to apply + Elf32_Sword r_addend; // Compute value for relocatable field by adding this +}; + +// Relocation entry, without explicit addend. +struct Elf64_Rel +{ + Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr). + Elf64_Xword r_info; // Symbol table index and type of relocation to apply. +}; + +// Relocation entry with explicit addend. +struct Elf64_Rela +{ + Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr). + Elf64_Xword r_info; // Symbol table index and type of relocation to apply. + Elf64_Sxword r_addend; // Compute value for relocatable field by adding this. +}; + +// Program header for ELF32. +struct Elf32_Phdr +{ + Elf32_Word p_type; // Type of segment + Elf32_Off p_offset; // File offset where segment is located, in bytes + Elf32_Addr p_vaddr; // Virtual address of beginning of segment + Elf32_Addr p_paddr; // Physical address of beginning of segment (OS-specific) + Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero) + Elf32_Word p_memsz; // Num. of bytes in mem image of segment (may be zero) + Elf32_Word p_flags; // Segment flags + Elf32_Word p_align; // Segment alignment constraint +}; + +// Program header for ELF64. +struct Elf64_Phdr +{ + Elf64_Word p_type; // Type of segment + Elf64_Word p_flags; // Segment flags + Elf64_Off p_offset; // File offset where segment is located, in bytes + Elf64_Addr p_vaddr; // Virtual address of beginning of segment + Elf64_Addr p_paddr; // Physical addr of beginning of segment (OS-specific) + Elf64_Xword p_filesz; // Num. of bytes in file image of segment (may be zero) + Elf64_Xword p_memsz; // Num. of bytes in mem image of segment (may be zero) + Elf64_Xword p_align; // Segment alignment constraint +}; + +// Segment types. +enum +{ + PT_NULL = 0, // Unused segment. + PT_LOAD = 1, // Loadable segment. + PT_DYNAMIC = 2, // Dynamic linking information. + PT_INTERP = 3, // Interpreter pathname. + PT_NOTE = 4, // Auxiliary information. + PT_SHLIB = 5, // Reserved. + PT_PHDR = 6, // The program header table itself. + PT_TLS = 7, // The thread-local storage template. + PT_LOOS = 0x60000000, // Lowest operating system-specific pt entry type. + PT_HIOS = 0x6fffffff, // Highest operating system-specific pt entry type. + PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type. + PT_HIPROC = 0x7fffffff, // Highest processor-specific program hdr entry type. + + // x86-64 program header types. + // These all contain stack unwind tables. + PT_GNU_EH_FRAME = 0x6474e550, + PT_SUNW_EH_FRAME = 0x6474e550, + PT_SUNW_UNWIND = 0x6464e550, + + PT_GNU_STACK = 0x6474e551, // Indicates stack executability. + PT_GNU_RELRO = 0x6474e552, // Read-only after relocation. + + // ARM program header types. + PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info + // These all contain stack unwind tables. + PT_ARM_EXIDX = 0x70000001, + PT_ARM_UNWIND = 0x70000001 +}; + +// Segment flag bits. +enum : u32 +{ + PF_X = 1, // Execute + PF_W = 2, // Write + PF_R = 4, // Read + PF_MASKOS = 0x0ff00000, // Bits for operating system-specific semantics. + PF_MASKPROC = 0xf0000000 // Bits for processor-specific semantics. +}; + +// Dynamic table entry for ELF32. +struct Elf32_Dyn +{ + Elf32_Sword d_tag; // Type of dynamic table entry. + union + { + Elf32_Word d_val; // Integer value of entry. + Elf32_Addr d_ptr; // Pointer value of entry. + } d_un; +}; + +// Dynamic table entry for ELF64. +struct Elf64_Dyn +{ + Elf64_Sxword d_tag; // Type of dynamic table entry. + union + { + Elf64_Xword d_val; // Integer value of entry. + Elf64_Addr d_ptr; // Pointer value of entry. + } d_un; +}; + +// Dynamic table entry tags. +enum +{ + DT_NULL = 0, // Marks end of dynamic array. + DT_NEEDED = 1, // String table offset of needed library. + DT_PLTRELSZ = 2, // Size of relocation entries in PLT. + DT_PLTGOT = 3, // Address associated with linkage table. + DT_HASH = 4, // Address of symbolic hash table. + DT_STRTAB = 5, // Address of dynamic string table. + DT_SYMTAB = 6, // Address of dynamic symbol table. + DT_RELA = 7, // Address of relocation table (Rela entries). + DT_RELASZ = 8, // Size of Rela relocation table. + DT_RELAENT = 9, // Size of a Rela relocation entry. + DT_STRSZ = 10, // Total size of the string table. + DT_SYMENT = 11, // Size of a symbol table entry. + DT_INIT = 12, // Address of initialization function. + DT_FINI = 13, // Address of termination function. + DT_SONAME = 14, // String table offset of a shared objects name. + DT_RPATH = 15, // String table offset of library search path. + DT_SYMBOLIC = 16, // Changes symbol resolution algorithm. + DT_REL = 17, // Address of relocation table (Rel entries). + DT_RELSZ = 18, // Size of Rel relocation table. + DT_RELENT = 19, // Size of a Rel relocation entry. + DT_PLTREL = 20, // Type of relocation entry used for linking. + DT_DEBUG = 21, // Reserved for debugger. + DT_TEXTREL = 22, // Relocations exist for non-writable segments. + DT_JMPREL = 23, // Address of relocations associated with PLT. + DT_BIND_NOW = 24, // Process all relocations before execution. + DT_INIT_ARRAY = 25, // Pointer to array of initialization functions. + DT_FINI_ARRAY = 26, // Pointer to array of termination functions. + DT_INIT_ARRAYSZ = 27, // Size of DT_INIT_ARRAY. + DT_FINI_ARRAYSZ = 28, // Size of DT_FINI_ARRAY. + DT_RUNPATH = 29, // String table offset of lib search path. + DT_FLAGS = 30, // Flags. + DT_ENCODING = 32, // Values from here to DT_LOOS follow the rules + // for the interpretation of the d_un union. + + DT_PREINIT_ARRAY = 32, // Pointer to array of preinit functions. + DT_PREINIT_ARRAYSZ = 33, // Size of the DT_PREINIT_ARRAY array. + + DT_LOOS = 0x60000000, // Start of environment specific tags. + DT_HIOS = 0x6FFFFFFF, // End of environment specific tags. + DT_LOPROC = 0x70000000, // Start of processor specific tags. + DT_HIPROC = 0x7FFFFFFF, // End of processor specific tags. + + DT_RELACOUNT = 0x6FFFFFF9, // ELF32_Rela count. + DT_RELCOUNT = 0x6FFFFFFA, // ELF32_Rel count. + + DT_FLAGS_1 = 0X6FFFFFFB, // Flags_1. + DT_VERDEF = 0X6FFFFFFC, // The address of the version definition table. + DT_VERDEFNUM = 0X6FFFFFFD, // The number of entries in DT_VERDEF. + DT_VERNEED = 0X6FFFFFFE, // The address of the version Dependency table. + DT_VERNEEDNUM = 0X6FFFFFFF, // The number of entries in DT_VERNEED. + + // Mips specific dynamic table entry tags. + DT_MIPS_RLD_VERSION = 0x70000001, // 32 bit version number for runtime + // linker interface. + DT_MIPS_TIME_STAMP = 0x70000002, // Time stamp. + DT_MIPS_ICHECKSUM = 0x70000003, // Checksum of external strings + // and common sizes. + DT_MIPS_IVERSION = 0x70000004, // Index of version string + // in string table. + DT_MIPS_FLAGS = 0x70000005, // 32 bits of flags. + DT_MIPS_BASE_ADDRESS = 0x70000006, // Base address of the segment. + DT_MIPS_MSYM = 0x70000007, // Address of .msym section. + DT_MIPS_CONFLICT = 0x70000008, // Address of .conflict section. + DT_MIPS_LIBLIST = 0x70000009, // Address of .liblist section. + DT_MIPS_LOCAL_GOTNO = 0x7000000a, // Number of local global offset + // table entries. + DT_MIPS_CONFLICTNO = 0x7000000b, // Number of entries + // in the .conflict section. + DT_MIPS_LIBLISTNO = 0x70000010, // Number of entries + // in the .liblist section. + DT_MIPS_SYMTABNO = 0x70000011, // Number of entries + // in the .dynsym section. + DT_MIPS_UNREFEXTNO = 0x70000012, // Index of first external dynamic symbol + // not referenced locally. + DT_MIPS_GOTSYM = 0x70000013, // Index of first dynamic symbol + // in global offset table. + DT_MIPS_HIPAGENO = 0x70000014, // Number of page table entries + // in global offset table. + DT_MIPS_RLD_MAP = 0x70000016, // Address of run time loader map, + // used for debugging. + DT_MIPS_DELTA_CLASS = 0x70000017, // Delta C++ class definition. + DT_MIPS_DELTA_CLASS_NO = 0x70000018, // Number of entries + // in DT_MIPS_DELTA_CLASS. + DT_MIPS_DELTA_INSTANCE = 0x70000019, // Delta C++ class instances. + DT_MIPS_DELTA_INSTANCE_NO = 0x7000001A, // Number of entries + // in DT_MIPS_DELTA_INSTANCE. + DT_MIPS_DELTA_RELOC = 0x7000001B, // Delta relocations. + DT_MIPS_DELTA_RELOC_NO = 0x7000001C, // Number of entries + // in DT_MIPS_DELTA_RELOC. + DT_MIPS_DELTA_SYM = 0x7000001D, // Delta symbols that Delta + // relocations refer to. + DT_MIPS_DELTA_SYM_NO = 0x7000001E, // Number of entries + // in DT_MIPS_DELTA_SYM. + DT_MIPS_DELTA_CLASSSYM = 0x70000020, // Delta symbols that hold + // class declarations. + DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021, // Number of entries + // in DT_MIPS_DELTA_CLASSSYM. + DT_MIPS_CXX_FLAGS = 0x70000022, // Flags indicating information + // about C++ flavor. + DT_MIPS_PIXIE_INIT = 0x70000023, // Pixie information. + DT_MIPS_SYMBOL_LIB = 0x70000024, // Address of .MIPS.symlib + DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025, // The GOT index of the first PTE + // for a segment + DT_MIPS_LOCAL_GOTIDX = 0x70000026, // The GOT index of the first PTE + // for a local symbol + DT_MIPS_HIDDEN_GOTIDX = 0x70000027, // The GOT index of the first PTE + // for a hidden symbol + DT_MIPS_PROTECTED_GOTIDX = 0x70000028, // The GOT index of the first PTE + // for a protected symbol + DT_MIPS_OPTIONS = 0x70000029, // Address of `.MIPS.options'. + DT_MIPS_INTERFACE = 0x7000002A, // Address of `.interface'. + DT_MIPS_DYNSTR_ALIGN = 0x7000002B, // Unknown. + DT_MIPS_INTERFACE_SIZE = 0x7000002C, // Size of the .interface section. + DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002D, // Size of rld_text_resolve + // function stored in the GOT. + DT_MIPS_PERF_SUFFIX = 0x7000002E, // Default suffix of DSO to be added + // by rld on dlopen() calls. + DT_MIPS_COMPACT_SIZE = 0x7000002F, // Size of compact relocation + // section (O32). + DT_MIPS_GP_VALUE = 0x70000030, // GP value for auxiliary GOTs. + DT_MIPS_AUX_DYNAMIC = 0x70000031, // Address of auxiliary .dynamic. + DT_MIPS_PLTGOT = 0x70000032, // Address of the base of the PLTGOT. + DT_MIPS_RWPLT = 0x70000034 // Points to the base + // of a writable PLT. +}; + +// DT_FLAGS values. +enum +{ + DF_ORIGIN = 0x01, // The object may reference $ORIGIN. + DF_SYMBOLIC = 0x02, // Search the shared lib before searching the exe. + DF_TEXTREL = 0x04, // Relocations may modify a non-writable segment. + DF_BIND_NOW = 0x08, // Process all relocations on load. + DF_STATIC_TLS = 0x10 // Reject attempts to load dynamically. +}; + +// State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry. +enum +{ + DF_1_NOW = 0x00000001, // Set RTLD_NOW for this object. + DF_1_GLOBAL = 0x00000002, // Set RTLD_GLOBAL for this object. + DF_1_GROUP = 0x00000004, // Set RTLD_GROUP for this object. + DF_1_NODELETE = 0x00000008, // Set RTLD_NODELETE for this object. + DF_1_LOADFLTR = 0x00000010, // Trigger filtee loading at runtime. + DF_1_INITFIRST = 0x00000020, // Set RTLD_INITFIRST for this object. + DF_1_NOOPEN = 0x00000040, // Set RTLD_NOOPEN for this object. + DF_1_ORIGIN = 0x00000080, // $ORIGIN must be handled. + DF_1_DIRECT = 0x00000100, // Direct binding enabled. + DF_1_TRANS = 0x00000200, + DF_1_INTERPOSE = 0x00000400, // Object is used to interpose. + DF_1_NODEFLIB = 0x00000800, // Ignore default lib search path. + DF_1_NODUMP = 0x00001000, // Object can't be dldump'ed. + DF_1_CONFALT = 0x00002000, // Configuration alternative created. + DF_1_ENDFILTEE = 0x00004000, // Filtee terminates filters search. + DF_1_DISPRELDNE = 0x00008000, // Disp reloc applied at build time. + DF_1_DISPRELPND = 0x00010000 // Disp reloc applied at run-time. +}; + +// DT_MIPS_FLAGS values. +enum +{ + RHF_NONE = 0x00000000, // No flags. + RHF_QUICKSTART = 0x00000001, // Uses shortcut pointers. + RHF_NOTPOT = 0x00000002, // Hash size is not a power of two. + RHS_NO_LIBRARY_REPLACEMENT = 0x00000004, // Ignore LD_LIBRARY_PATH. + RHF_NO_MOVE = 0x00000008, // DSO address may not be relocated. + RHF_SGI_ONLY = 0x00000010, // SGI specific features. + RHF_GUARANTEE_INIT = 0x00000020, // Guarantee that .init will finish + // executing before any non-init + // code in DSO is called. + RHF_DELTA_C_PLUS_PLUS = 0x00000040, // Contains Delta C++ code. + RHF_GUARANTEE_START_INIT = 0x00000080, // Guarantee that .init will start + // executing before any non-init + // code in DSO is called. + RHF_PIXIE = 0x00000100, // Generated by pixie. + RHF_DEFAULT_DELAY_LOAD = 0x00000200, // Delay-load DSO by default. + RHF_REQUICKSTART = 0x00000400, // Object may be requickstarted + RHF_REQUICKSTARTED = 0x00000800, // Object has been requickstarted + RHF_CORD = 0x00001000, // Generated by cord. + RHF_NO_UNRES_UNDEF = 0x00002000, // Object contains no unresolved + // undef symbols. + RHF_RLD_ORDER_SAFE = 0x00004000 // Symbol table is in a safe order. +}; + +// ElfXX_VerDef structure version (GNU versioning) +enum +{ + VER_DEF_NONE = 0, + VER_DEF_CURRENT = 1 +}; + +// VerDef Flags (ElfXX_VerDef::vd_flags) +enum +{ + VER_FLG_BASE = 0x1, + VER_FLG_WEAK = 0x2, + VER_FLG_INFO = 0x4 +}; + +// Special constants for the version table. (SHT_GNU_versym/.gnu.version) +enum +{ + VER_NDX_LOCAL = 0, // Unversioned local symbol + VER_NDX_GLOBAL = 1, // Unversioned global symbol + VERSYM_VERSION = 0x7fff, // Version Index mask + VERSYM_HIDDEN = 0x8000 // Hidden bit (non-default version) +}; + +// ElfXX_VerNeed structure version (GNU versioning) +enum +{ + VER_NEED_NONE = 0, + VER_NEED_CURRENT = 1 +}; + +#endif diff --git a/hwinit/btn.c b/ipl/btn.c old mode 100644 new mode 100755 similarity index 86% rename from hwinit/btn.c rename to ipl/btn.c index 09d641a..c346fce --- a/hwinit/btn.c +++ b/ipl/btn.c @@ -16,16 +16,17 @@ #include "btn.h" #include "i2c.h" +#include "gpio.h" #include "t210.h" u32 btn_read() { u32 res = 0; - if(!(GPIO_6(0x3C) & 0x80)) + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) res |= BTN_VOL_DOWN; - if(!(GPIO_6(0x3C) & 0x40)) + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) res |= BTN_VOL_UP; - if(i2c_recv_byte(4, 0x3C, 0x15) & 0x4) + if (i2c_recv_byte(4, 0x3C, 0x15) & 0x4) res |= BTN_POWER; return res; } diff --git a/hwinit/btn.h b/ipl/btn.h old mode 100644 new mode 100755 similarity index 100% rename from hwinit/btn.h rename to ipl/btn.h diff --git a/ipl/clock.c b/ipl/clock.c new file mode 100755 index 0000000..c959749 --- /dev/null +++ b/ipl/clock.c @@ -0,0 +1,449 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "clock.h" +#include "t210.h" +#include "util.h" +#include "sdmmc.h" + +static const clock_t _clock_uart[] = { + /* UART A */ { 4, 0x10, 0x178, 6, 0, 0 }, + /* UART B */ { 4, 0x10, 0x17C, 7, 0, 0 }, + /* UART C */ { 8, 0x14, 0x1A0, 0x17, 0, 0 }, + /* UART D */ { 0 }, + /* UART E */ { 0 } +}; + +static const clock_t _clock_i2c[] = { + /* I2C1 */ { 4, 0x10, 0x124, 0xC, 6, 0 }, + /* I2C2 */ { 0 }, + /* I2C3 */ { 0 }, + /* I2C4 */ { 0 }, + /* I2C5 */ { 8, 0x14, 0x128, 0xF, 6, 0 }, + /* I2C6 */ { 0 } +}; + +static clock_t _clock_se = { 0x358, 0x360, 0x42C, 0x1F, 0, 0 }; + +static clock_t _clock_host1x = { 4, 0x10, 0x180, 0x1C, 4, 3 }; +static clock_t _clock_tsec = { 0xC, 0x18, 0x1F4, 0x13, 0, 2 }; +static clock_t _clock_sor_safe = { 0x2A4, 0x298, 0, 0x1E, 0, 0 }; +static clock_t _clock_sor0 = { 0x28C, 0x280, 0, 0x16, 0, 0 }; +static clock_t _clock_sor1 = { 0x28C, 0x280, 0x410, 0x17, 0, 2 }; +static clock_t _clock_kfuse = { 8, 0x14, 0, 8, 0, 0 }; + +static clock_t _clock_cl_dvfs = { 0x35C, 0x364, 0, 0x1B, 0, 0 }; +static clock_t _clock_coresight = { 0xC, 0x18, 0x1D4, 9, 0, 4}; + +void clock_enable(const clock_t *clk) +{ + //Put clock into reset. + CLOCK(clk->reset) = CLOCK(clk->reset) & ~(1 << clk->index) | (1 << clk->index); + //Disable. + CLOCK(clk->enable) &= ~(1 << clk->index); + //Configure clock source if required. + if (clk->source) + CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); + //Enable. + CLOCK(clk->enable) = CLOCK(clk->enable) & ~(1 << clk->index) | (1 << clk->index); + //Take clock off reset. + CLOCK(clk->reset) &= ~(1 << clk->index); +} + +void clock_disable(const clock_t *clk) +{ + //Put clock into reset. + CLOCK(clk->reset) = CLOCK(clk->reset) & ~(1 << clk->index) | (1 << clk->index); + //Disable. + CLOCK(clk->enable) &= ~(1 << clk->index); +} + +void clock_enable_fuse(u32 enable) +{ + CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF | ((enable & 1) << 28) & 0x10000000; +} + +void clock_enable_uart(u32 idx) +{ + clock_enable(&_clock_uart[idx]); +} + +void clock_enable_i2c(u32 idx) +{ + clock_enable(&_clock_i2c[idx]); +} + +void clock_enable_se() +{ + clock_enable(&_clock_se); +} + +void clock_enable_host1x() +{ + clock_enable(&_clock_host1x); +} + +void clock_disable_host1x() +{ + clock_disable(&_clock_host1x); +} + +void clock_enable_tsec() +{ + clock_enable(&_clock_tsec); +} + +void clock_disable_tsec() +{ + clock_disable(&_clock_tsec); +} + +void clock_enable_sor_safe() +{ + clock_enable(&_clock_sor_safe); +} + +void clock_disable_sor_safe() +{ + clock_disable(&_clock_sor_safe); +} + +void clock_enable_sor0() +{ + clock_enable(&_clock_sor0); +} + +void clock_disable_sor0() +{ + clock_disable(&_clock_sor0); +} + +void clock_enable_sor1() +{ + clock_enable(&_clock_sor1); +} + +void clock_disable_sor1() +{ + clock_disable(&_clock_sor1); +} + +void clock_enable_kfuse() +{ + //clock_enable(&_clock_kfuse); + CLOCK(0x8) = CLOCK(0x8) & 0xFFFFFEFF | 0x100; + CLOCK(0x14) &= 0xFFFFFEFF; + CLOCK(0x14) = CLOCK(0x14) & 0xFFFFFEFF | 0x100; + sleep(10); + CLOCK(0x8) &= 0xFFFFFEFF; + sleep(20); +} + +void clock_disable_kfuse() +{ + clock_disable(&_clock_kfuse); +} + +void clock_enable_cl_dvfs() +{ + clock_enable(&_clock_cl_dvfs); +} + +void clock_enable_coresight() +{ + clock_enable(&_clock_coresight); +} + +#define L_SWR_SDMMC1_RST (1<<14) +#define L_SWR_SDMMC2_RST (1<<9) +#define L_SWR_SDMMC4_RST (1<<15) +#define U_SWR_SDMMC3_RST (1<<5) + +#define L_CLK_ENB_SDMMC1 (1<<14) +#define L_CLK_ENB_SDMMC2 (1<<9) +#define L_CLK_ENB_SDMMC4 (1<<15) +#define U_CLK_ENB_SDMMC3 (1<<5) + +#define L_SET_SDMMC1_RST (1<<14) +#define L_SET_SDMMC2_RST (1<<9) +#define L_SET_SDMMC4_RST (1<<15) +#define U_SET_SDMMC3_RST (1<<5) + +#define L_CLR_SDMMC1_RST (1<<14) +#define L_CLR_SDMMC2_RST (1<<9) +#define L_CLR_SDMMC4_RST (1<<15) +#define U_CLR_SDMMC3_RST (1<<5) + +#define L_SET_CLK_ENB_SDMMC1 (1<<14) +#define L_SET_CLK_ENB_SDMMC2 (1<<9) +#define L_SET_CLK_ENB_SDMMC4 (1<<15) +#define U_SET_CLK_ENB_SDMMC3 (1<<5) + +#define L_CLR_CLK_ENB_SDMMC1 (1<<14) +#define L_CLR_CLK_ENB_SDMMC2 (1<<9) +#define L_CLR_CLK_ENB_SDMMC4 (1<<15) +#define U_CLR_CLK_ENB_SDMMC3 (1<<5) + +static int _clock_sdmmc_is_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC1_RST; + case SDMMC_2: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC2_RST; + case SDMMC_3: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & U_SWR_SDMMC3_RST; + case SDMMC_4: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC4_RST; + } + return 0; +} + +static void _clock_sdmmc_set_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; + } +} + +static void _clock_sdmmc_clear_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; + } +} + +static int _clock_sdmmc_is_enabled(u32 id) +{ + switch (id) + { + case SDMMC_1: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC1; + case SDMMC_2: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC2; + case SDMMC_3: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & U_CLK_ENB_SDMMC3; + case SDMMC_4: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC4; + } + return 0; +} + +static int _clock_sdmmc_set_enable(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; + } +} + +static int _clock_sdmmc_clear_enable(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; + } +} + +static u32 _clock_sdmmc_table[8] = { 0 }; + +static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val) +{ + u32 divisor = 0; + u32 source = 0; + + switch (val) + { + case 25000: + *pout = 24728; + divisor = 31; + break; + case 26000: + *pout = 25500; + divisor = 30; + break; + case 40800: + *pout = 40800; + divisor = 18; + break; + case 50000: + *pout = 48000; + divisor = 15; + break; + case 52000: + *pout = 51000; + divisor = 14; + break; + case 100000: + *pout = 90667; + divisor = 7; + break; + case 200000: + *pout = 163200; + divisor = 3; + break; + case 208000: + *pout = 204000; + divisor = 2; + break; + default: + return 0; + } + + _clock_sdmmc_table[2 * id] = val; + _clock_sdmmc_table[2 * id + 1] = *pout; + + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor; + break; + } + + return 1; +} + +void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) +{ + if (_clock_sdmmc_table[2 * id] == val) + { + *pout = _clock_sdmmc_table[2 * id + 1]; + } + else + { + int is_enabled = _clock_sdmmc_is_enabled(id); + if (is_enabled) + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_config_clock_source_inner(pout, id, val); + if (is_enabled) + _clock_sdmmc_set_enable(id); + _clock_sdmmc_is_reset(id); + } +} + +void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type) +{ + switch (type) + { + case 0: + *pout = 26000; + *pdivisor = 66; + break; + case 1: + *pout = 26000; + *pdivisor = 1; + break; + case 2: + *pout = 52000; + *pdivisor = 1; + break; + case 3: + case 4: + case 11: + *pout = 200000; + *pdivisor = 1; + break; + case 5: + *pout = 25000; + *pdivisor = 64; + case 6: + case 8: + *pout = 25000; + *pdivisor = 1; + break; + case 7: + *pout = 50000; + *pdivisor = 1; + case 10: + *pout = 100000; + *pdivisor = 1; + case 13: + *pout = 40800; + *pdivisor = 1; + break; + case 14: + *pout = 200000; + *pdivisor = 2; + break; + } +} + +int clock_sdmmc_is_not_reset_and_enabled(u32 id) +{ + return !_clock_sdmmc_is_reset(id) && _clock_sdmmc_is_enabled(id); +} + +void clock_sdmmc_enable(u32 id, u32 val) +{ + u32 div = 0; + + if (_clock_sdmmc_is_enabled(id)) + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_set_reset(id); + _clock_sdmmc_config_clock_source_inner(&div, id, val); + _clock_sdmmc_set_enable(id); + _clock_sdmmc_is_reset(id); + sleep((100000 + div - 1) / div); + _clock_sdmmc_clear_reset(id); + _clock_sdmmc_is_reset(id); +} + +void clock_sdmmc_disable(u32 id) +{ + _clock_sdmmc_set_reset(id); + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_is_reset(id); +} diff --git a/hwinit/clock.h b/ipl/clock.h old mode 100644 new mode 100755 similarity index 51% rename from hwinit/clock.h rename to ipl/clock.h index d63521b..d3c6a04 --- a/hwinit/clock.h +++ b/ipl/clock.h @@ -20,20 +20,52 @@ #include "types.h" /*! Clock registers. */ +#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 +#define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18 +#define CLK_RST_CONTROLLER_CCLK_BURST_POLICY 0x20 +#define CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER 0x24 #define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28 #define CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2C #define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 #define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 #define CLK_RST_CONTROLLER_OSC_CTRL 0x50 +#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 +#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 0x164 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC #define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 #define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 +#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C +#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300 +#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304 #define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308 +#define CLK_RST_CONTROLLER_RST_DEV_U_SET 0x310 +#define CLK_RST_CONTROLLER_RST_DEV_U_CLR 0x314 +#define CLK_RST_CONTROLLER_CLK_ENB_L_SET 0x320 +#define CLK_RST_CONTROLLER_CLK_ENB_L_CLR 0x324 #define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328 +#define CLK_RST_CONTROLLER_CLK_ENB_U_SET 0x330 +#define CLK_RST_CONTROLLER_CLK_ENB_U_CLR 0x334 #define CLK_RST_CONTROLLER_RST_DEVICES_V 0x358 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_V 0x360 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_W 0x364 +#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 0x388 +#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 +#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 +#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 #define CLK_RST_CONTROLLER_SPARE_REG0 0x55C #define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 +/*! Generic clock descriptor. */ typedef struct _clock_t { u32 reset; @@ -44,24 +76,33 @@ typedef struct _clock_t u8 clk_div; } clock_t; +/*! Generic clock enable/disable. */ void clock_enable(const clock_t *clk); void clock_disable(const clock_t *clk); + +/*! Clock control for specific hardware portions. */ void clock_enable_fuse(u32 enable); void clock_enable_uart(u32 idx); void clock_enable_i2c(u32 idx); void clock_enable_se(); void clock_enable_host1x(); -void clock_enable_tsec(); -void clock_enable_sor_safe(); -void clock_enable_sor0(); -void clock_enable_sor1(); -void clock_enable_kfuse(); void clock_disable_host1x(); +void clock_enable_tsec(); void clock_disable_tsec(); +void clock_enable_sor_safe(); void clock_disable_sor_safe(); +void clock_enable_sor0(); void clock_disable_sor0(); +void clock_enable_sor1(); void clock_disable_sor1(); +void clock_enable_kfuse(); void clock_disable_kfuse(); +void clock_enable_cl_dvfs(); void clock_enable_coresight(); +void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); +void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type); +int clock_sdmmc_is_not_reset_and_enabled(u32 id); +void clock_sdmmc_enable(u32 id, u32 val); +void clock_sdmmc_disable(u32 id); #endif diff --git a/hwinit/cluster.c b/ipl/cluster.c old mode 100644 new mode 100755 similarity index 53% rename from hwinit/cluster.c rename to ipl/cluster.c index 91c54d9..dcb1e2e --- a/hwinit/cluster.c +++ b/ipl/cluster.c @@ -20,30 +20,26 @@ #include "util.h" #include "pmc.h" #include "t210.h" +#include "max77620.h" void _cluster_enable_power() { - u8 tmp; - - if (i2c_recv_buf_small(&tmp, 1, I2C_5, 0x3C, 0x40)) - { - tmp &= 0xDFu; - i2c_send_byte(I2C_5, 0x3C, 0x40, tmp); - } - i2c_send_byte(I2C_5, 0x3C, 0x3B, 0x09); + u8 tmp = i2c_recv_byte(I2C_5, 0x3C, MAX77620_REG_AME_GPIO); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_AME_GPIO, tmp & 0xDF); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_GPIO5, 0x09); //Enable cores power. - i2c_send_byte(I2C_5, 0x1B, 0x02, 0x20); - i2c_send_byte(I2C_5, 0x1B, 0x03, 0x8D); - i2c_send_byte(I2C_5, 0x1B, 0x00, 0xB7); - i2c_send_byte(I2C_5, 0x1B, 0x01, 0xB7); + i2c_send_byte(I2C_5, 0x1B, 0x2, 0x20); + i2c_send_byte(I2C_5, 0x1B, 0x3, 0x8D); + i2c_send_byte(I2C_5, 0x1B, 0x0, 0xB7); + i2c_send_byte(I2C_5, 0x1B, 0x1, 0xB7); } int _cluster_pmc_enable_partition(u32 part, u32 toggle) { //Check if the partition has already been turned on. if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part) - return 0; + return 1; u32 i = 5001; while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) @@ -68,32 +64,38 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle) return 1; } -void cluster_enable_cpu0(u32 entry) +void cluster_boot_cpu0(u32 entry) { //Set ACTIVE_CLUSER to FAST. FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE; _cluster_enable_power(); - if (!(CLOCK(0xE0) & 0x40000000)) + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) { - CLOCK(0x518) &= 0xFFFFFFF7; + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; sleep(2); - CLOCK(0xE4) = CLOCK(0xE4) & 0xFFFBFFFF | 0x40000; - CLOCK(0xE0) = 0x40404E02; + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02; + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02; + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) = CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) & 0xFFFBFFFF | 0x40000; + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x40404E02; } - while (!(CLOCK(0xE0) & 0x8000000)) + while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000)) ; - CLOCK(0x3B4) = CLOCK(0x3B4) & 0x1FFFFF00 | 6; - CLOCK(0x360) = CLOCK(0x360) & 0xFFFFFFF7 | 8; - CLOCK(0x20) = 0x20008888; - CLOCK(0x24) = 0x80000000; - CLOCK(0x440) = 1; + //Configure MSELECT source and enable clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00 | 6; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) & 0xFFFFFFF7 | 8; + + //Configure initial CPU clock frequency and enable clock. + CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; + CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = 1; clock_enable_coresight(); - CLOCK(0x388) = CLOCK(0x388) & 0xFFFFE000; + //CAR2PMC_CPU_ACK_WIDTH should be set to 0. + CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) = CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) & 0xFFFFF000; //Enable CPU rail. _cluster_pmc_enable_partition(1, 0); @@ -109,13 +111,17 @@ void cluster_enable_cpu0(u32 entry) EXCP_VEC(0x100) = 0; - //Set reset vectors. + //Set reset vector. SB(SB_AA64_RESET_LOW) = entry | 1; SB(SB_AA64_RESET_HIGH) = 0; //Non-secure reset vector write disable. - SB(SB_CSR_0) = 2; + SB(SB_CSR) = 2; + (void)SB(SB_CSR); - //Until here the CPU was in reset, this kicks execution. + //Clear MSELECT reset. CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; + //Clear NONCPU reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; + //Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x411F000F; } diff --git a/hwinit/cluster.h b/ipl/cluster.h old mode 100644 new mode 100755 similarity index 100% rename from hwinit/cluster.h rename to ipl/cluster.h diff --git a/hwinit/di.c b/ipl/di.c old mode 100644 new mode 100755 similarity index 97% rename from hwinit/di.c rename to ipl/di.c index 8629144..d1f2280 --- a/hwinit/di.c +++ b/ipl/di.c @@ -19,6 +19,7 @@ #include "util.h" #include "i2c.h" #include "pmc.h" +#include "max77620.h" #include "di.inl" @@ -35,8 +36,8 @@ static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) void display_init() { //Power on. - i2c_send_byte(I2C_5, 0x3C, 0x23, 0xD0); - i2c_send_byte(I2C_5, 0x3C, 0x3D, 0x09); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_LDO0_CFG, 0xD0); //Configure to 1.2V. + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_GPIO7, 0x09); //Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. CLOCK(0x30C) = 0x1010000; diff --git a/hwinit/di.h b/ipl/di.h old mode 100644 new mode 100755 similarity index 100% rename from hwinit/di.h rename to ipl/di.h diff --git a/hwinit/di.inl b/ipl/di.inl old mode 100644 new mode 100755 similarity index 100% rename from hwinit/di.inl rename to ipl/di.inl diff --git a/ipl/diskio.c b/ipl/diskio.c new file mode 100755 index 0000000..5bddd90 --- /dev/null +++ b/ipl/diskio.c @@ -0,0 +1,71 @@ +/*-----------------------------------------------------------------------*/ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ +/*-----------------------------------------------------------------------*/ +/* If a working storage control module is available, it should be */ +/* attached to the FatFs via a glue function rather than modifying it. */ +/* This is an example of glue functions to attach various exsisting */ +/* storage control modules to the FatFs module with a defined API. */ +/*-----------------------------------------------------------------------*/ + +#include +#include "diskio.h" /* FatFs lower layer API */ +#include "sdmmc.h" + +extern sdmmc_storage_t sd_storage; + +DSTATUS disk_status ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + return 0; +} + +DSTATUS disk_initialize ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + return 0; +} + +DRESULT disk_read ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to read */ +) +{ + if ((u32)buff >= 0x90000000) + return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; + u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere. + if (sdmmc_storage_read(&sd_storage, sector, count, buf)) + { + memcpy(buff, buf, 512 * count); + return RES_OK; + } + return RES_ERROR; +} + +DRESULT disk_write ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to write */ +) +{ + if ((u32)buff >= 0x90000000) + return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere. + memcpy(buf, buff, 512 * count); + if (sdmmc_storage_write(&sd_storage, sector, count, buf)) + return RES_OK; + return RES_ERROR; +} + +DRESULT disk_ioctl ( + BYTE pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + return RES_OK; +} diff --git a/ipl/diskio.h b/ipl/diskio.h new file mode 100755 index 0000000..20ebde9 --- /dev/null +++ b/ipl/diskio.h @@ -0,0 +1,80 @@ +/*-----------------------------------------------------------------------/ +/ Low level disk interface modlue include file (C)ChaN, 2014 / +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "integer.h" + + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + + +DSTATUS disk_initialize (BYTE pdrv); +DSTATUS disk_status (BYTE pdrv); +DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (Used by FatFs) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ + +/* Generic command (Not used by FatFs) */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ +#define ISDIO_READ 55 /* Read data form SD iSDIO register */ +#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ +#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hwinit/emc.h b/ipl/emc.h old mode 100644 new mode 100755 similarity index 99% rename from hwinit/emc.h rename to ipl/emc.h index ce134c2..7a6405d --- a/hwinit/emc.h +++ b/ipl/emc.h @@ -22,6 +22,8 @@ #ifndef _EMC_H_ #define _EMC_H_ +#define EMC_DBG 0x8 +#define EMC_CFG 0xC #define EMC_CONFIG_SAMPLE_DELAY 0x5f0 #define EMC_CFG_UPDATE 0x5f4 #define EMC_ADR_CFG 0x10 diff --git a/ipl/ff.c b/ipl/ff.c new file mode 100755 index 0000000..d29601d --- /dev/null +++ b/ipl/ff.c @@ -0,0 +1,6555 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT Filesystem Module R0.13a / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2017, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/ +/----------------------------------------------------------------------------*/ + + +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of device I/O functions */ + + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if FF_DEFINED != 89352 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + + +/* Character code support macros */ +#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) +#define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) +#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) + + +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Additional file access control and file status flags for internal use */ +#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ +#define FA_MODIFIED 0x40 /* File has been modified */ +#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ + + +/* Name status flags in fn[11] */ +#define NSFLAG 11 /* Index of the name status byte */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ +#define NS_NOLFN 0x40 /* Do not find LFN */ +#define NS_NONAME 0x80 /* Not followed */ + + +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ + + +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ + +#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_OEMName 3 /* OEM name (8-byte) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ +#define BPB_NumFATs 16 /* Number of FATs (BYTE) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ +#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ +#define BPB_Media 21 /* Media descriptor byte (BYTE) */ +#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ +#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ +#define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ +#define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ +#define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ +#define BS_NTres 37 /* WindowsNT error flag (BYTE) */ +#define BS_BootSig 38 /* Extended boot signature (BYTE) */ +#define BS_VolID 39 /* Volume serial number (DWORD) */ +#define BS_VolLab 43 /* Volume label string (8-byte) */ +#define BS_FilSysType 54 /* Filesystem type string (8-byte) */ +#define BS_BootCode 62 /* Boot code (448-byte) */ +#define BS_55AA 510 /* Signature word (WORD) */ + +#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ +#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ +#define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ +#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ +#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ +#define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ +#define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ +#define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ +#define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ +#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ +#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ +#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ + +#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ +#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ +#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ +#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ +#define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ +#define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ +#define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ +#define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ +#define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ +#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ +#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ +#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ + +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ + +#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ +#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ +#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ +#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ + +#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define PTE_Boot 0 /* MBR PTE: Boot indicator */ +#define PTE_StHead 1 /* MBR PTE: Start head */ +#define PTE_StSec 2 /* MBR PTE: Start sector */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_System 4 /* MBR PTE: System ID */ +#define PTE_EdHead 5 /* MBR PTE: End head */ +#define PTE_EdSec 6 /* MBR PTE: End sector */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_StLba 8 /* MBR PTE: Start in LBA */ +#define PTE_SizLba 12 /* MBR PTE: Size in LBA */ + + +/* Post process on fatal error in the file operations */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Re-entrancy related */ +#if FF_FS_REENTRANT +#if FF_USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define LEAVE_FF(fs, res) return res +#endif + + +/* Definitions of volume - physical location conversion */ +#if FF_MULTI_PARTITION +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ +#else +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#endif + + +/* Definitions of sector size */ +#if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if FF_MAX_SS == FF_MIN_SS +#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if FF_FS_NORTC == 1 +#if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 +#error Invalid FF_FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if FF_FS_LOCK != 0 +#if FF_FS_READONLY +#error FF_FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + +/* SBCS up-case tables (\x80-\xFF) */ +#define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ + 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ + 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} + + +/* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ +#define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} +#define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} +#define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} +#define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} + + +/* Macros for table definitions */ +#define MERGE_2STR(a, b) a ## b +#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) + + + + +/*-------------------------------------------------------------------------- + + Module Private Work Area + +---------------------------------------------------------------------------*/ +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is +/ not compliance with C standard. */ + +/*--------------------------------*/ +/* File/Volume controls */ +/*--------------------------------*/ + +#if FF_VOLUMES < 1 || FF_VOLUMES > 10 +#error Wrong FF_VOLUMES setting +#endif +static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static WORD Fsid; /* File system mount ID */ + +#if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 +static BYTE CurrVol; /* Current drive */ +#endif + +#if FF_FS_LOCK != 0 +static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ +#endif + + + +/*--------------------------------*/ +/* LFN/Directory working buffer */ +/*--------------------------------*/ + +#if FF_USE_LFN == 0 /* Non-LFN configuration */ +#if FF_FS_EXFAT +#error LFN must be enabled when enable exFAT +#endif +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() +#define LEAVE_MKFS(res) return res + +#else /* LFN configurations */ +#if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 +#error Wrong setting of FF_MAX_LFN +#endif +#if FF_LFN_BUF < 12 || FF_SFN_BUF < 12 || FF_LFN_BUF < FF_SFN_BUF +#error Wrong setting of FF_LFN_BUF or FF_SFN_BUF +#endif +#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2 +#error Wrong setting of FF_LFN_UNICODE +#endif +static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ + +#if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ +#if FF_FS_EXFAT +static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ +#endif +static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() +#define LEAVE_MKFS(res) return res + +#elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMBUF() +#else +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMBUF() +#endif +#define LEAVE_MKFS(res) return res + +#elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } +#define FREE_NAMBUF() ff_memfree(lfn) +#else +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMBUF() ff_memfree(lfn) +#endif +#define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } +#define MAX_MALLOC 0x8000 + +#else +#error Wrong setting of FF_USE_LFN + +#endif /* FF_USE_LFN == 1 */ +#endif /* FF_USE_LFN == 0 */ + + + +/*--------------------------------*/ +/* Code conversion tables */ +/*--------------------------------*/ + +#if FF_CODE_PAGE == 0 /* Run-time code page configuration */ +#define CODEPAGE CodePage +static WORD CodePage; /* Current code page */ +static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ +static const BYTE Ct437[] = TBL_CT437; +static const BYTE Ct720[] = TBL_CT720; +static const BYTE Ct737[] = TBL_CT737; +static const BYTE Ct771[] = TBL_CT771; +static const BYTE Ct775[] = TBL_CT775; +static const BYTE Ct850[] = TBL_CT850; +static const BYTE Ct852[] = TBL_CT852; +static const BYTE Ct855[] = TBL_CT855; +static const BYTE Ct857[] = TBL_CT857; +static const BYTE Ct860[] = TBL_CT860; +static const BYTE Ct861[] = TBL_CT861; +static const BYTE Ct862[] = TBL_CT862; +static const BYTE Ct863[] = TBL_CT863; +static const BYTE Ct864[] = TBL_CT864; +static const BYTE Ct865[] = TBL_CT865; +static const BYTE Ct866[] = TBL_CT866; +static const BYTE Ct869[] = TBL_CT869; +static const BYTE Dc932[] = TBL_DC932; +static const BYTE Dc936[] = TBL_DC936; +static const BYTE Dc949[] = TBL_DC949; +static const BYTE Dc950[] = TBL_DC950; + +#elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); + +#else /* Static code page configuration (DBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); + +#endif + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Load/Store multi-byte word in the FAT structure */ +/*-----------------------------------------------------------------------*/ + +static +WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static +DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if FF_FS_EXFAT +static +QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +{ + QWORD rv; + + rv = ptr[7]; + rv = rv << 8 | ptr[6]; + rv = rv << 8 | ptr[5]; + rv = rv << 8 | ptr[4]; + rv = rv << 8 | ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} +#endif + +#if !FF_FS_READONLY +static +void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +static +void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +#if FF_FS_EXFAT +static +void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} +#endif +#endif /* !FF_FS_READONLY */ + + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +/* Copy memory to memory */ +static +void mem_cpy (void* dst, const void* src, UINT cnt) +{ + BYTE *d = (BYTE*)dst; + const BYTE *s = (const BYTE*)src; + + if (cnt != 0) { + do { + *d++ = *s++; + } while (--cnt); + } +} + + +/* Fill memory block */ +static +void mem_set (void* dst, int val, UINT cnt) +{ + BYTE *d = (BYTE*)dst; + + do { + *d++ = (BYTE)val; + } while (--cnt); +} + + +/* Compare memory block */ +static +int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ +{ + const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; + int r = 0; + + do { + r = *d++ - *s++; + } while (--cnt && r == 0); + + return r; +} + + +/* Check if chr is contained in the string */ +static +int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ +{ + while (*str && *str != chr) str++; + return *str; +} + + +/* Test if the character is DBC 1st byte */ +static +int dbc_1st (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} + + +/* Test if the character is DBC 2nd byte */ +static +int dbc_2nd (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} + + +#if FF_USE_LFN + +/* Get a character from TCHAR string in defined API encodeing */ +static +DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ + const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ +) +{ + DWORD uc; + const TCHAR *p = *str; + +#if FF_LFN_UNICODE == 1 /* UTF-16 input */ + WCHAR wc; + + uc = *p++; + if (IsSurrogate(uc)) { /* Surrogate? */ + wc = *p++; /* Get low surrogate */ + if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ + uc = uc << 16 | wc; + } + +#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ + BYTE b; + int nf; + + uc = (BYTE)*p++; /* Get a byte */ + if (uc & 0x80) { /* Multiple byte code? */ + if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + uc &= 0x1F; nf = 1; + } else { + if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + uc &= 0x0F; nf = 2; + } else { + if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + uc &= 0x07; nf = 3; + } else { /* Wrong sequence */ + return 0xFFFFFFFF; + } + } + } + do { /* Get trailing bytes */ + b = (BYTE)*p++; + if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ + uc = uc << 6 | (b & 0x3F); + } while (--nf != 0); + if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x10000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + } + +#else /* ANSI/OEM input */ + BYTE b; + WCHAR wc; + + wc = (BYTE)*p++; /* Get a byte */ + if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ + b = (BYTE)*p++; /* Get 2nd byte */ + if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ + wc = (wc << 8) + b; /* Make a DBC */ + } + if (wc != 0) { + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ + if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ + } + uc = wc; + +#endif + *str = p; /* Next read pointer */ + return uc; +} + + +/* Output a TCHAR string in defined API encoding */ +static +BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ + DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ + TCHAR* buf, /* Output buffer */ + UINT szb /* Size of the buffer */ +) +{ +#if FF_LFN_UNICODE == 1 /* UTF-16 output */ + WCHAR hs, wc; + + hs = (WCHAR)(chr >> 16); + wc = (WCHAR)chr; + if (hs == 0) { /* Single encoding unit? */ + if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ + *buf = wc; + return 1; + } + if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ + *buf++ = hs; + *buf++ = wc; + return 2; + +#elif FF_LFN_UNICODE == 2 /* UTF-8 output */ + DWORD hc; + + if (chr < 0x80) { /* Single byte code? */ + if (szb < 1) return 0; /* Buffer overflow? */ + *buf = (TCHAR)chr; + return 1; + } + if (chr < 0x800) { /* 2-byte sequence? */ + if (szb < 2) return 0; /* Buffer overflow? */ + *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 2; + } + if (chr < 0x10000) { /* 3-byte sequence? */ + if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ + *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 3; + } + /* 4-byte sequence */ + if (szb < 4) return 0; /* Buffer overflow? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); + *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 4; + +#else /* ANSI/OEM output */ + WCHAR wc; + + wc = ff_uni2oem(chr, CODEPAGE); + if (wc >= 0x100) { /* Is this a DBC? */ + if (szb < 2) return 0; + *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ + *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ + return 2; + } + if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ + *buf++ = (TCHAR)wc; /* Store the character */ + return 1; +#endif +} +#endif /* FF_USE_LFN */ + + +#if FF_FS_REENTRANT +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ +static +int lock_fs ( /* 1:Ok, 0:timeout */ + FATFS* fs /* Filesystem object */ +) +{ + return ff_req_grant(fs->sobj); +} + + +static +void unlock_fs ( + FATFS* fs, /* Filesystem object */ + FRESULT res /* Result code to be returned */ +) +{ + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } +} + +#endif + + + +#if FF_FS_LOCK != 0 +/*-----------------------------------------------------------------------*/ +/* File lock control functions */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT chk_lock ( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ +) +{ + UINT i, be; + + /* Search open object table for the object */ + be = 0; + for (i = 0; i < FF_FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == FF_FS_LOCK) { /* The object has not been opened */ + return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ + } + + /* The object was opened. Reject any open against writing file and all write mode open */ + return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static +int enq_lock (void) /* Check if an entry is available for a new object */ +{ + UINT i; + + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + return (i == FF_FS_LOCK) ? 0 : 1; +} + + +static +UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ + DIR* dp, /* Directory object pointing the file to register or increment */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i; + + + for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->obj.fs && + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } + + if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->obj.fs; + Files[i].clu = dp->obj.sclust; + Files[i].ofs = dp->dptr; + Files[i].ctr = 0; + } + + if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; /* Index number origin from 1 */ +} + + +static +FRESULT dec_lock ( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ +) +{ + WORD n; + FRESULT res; + + + if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n > 0) n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index nunber */ + } + return res; +} + + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < FF_FS_LOCK; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} + +#endif /* FF_FS_LOCK != 0 */ + + + +/*-----------------------------------------------------------------------*/ +/* Move/Flush disk access window in the filesystem object */ +/*-----------------------------------------------------------------------*/ +#if !FF_FS_READONLY +static +FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ +) +{ + FRESULT res = FR_OK; + + + if (fs->wflag) { /* Is the disk access window dirty */ + if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ + fs->wflag = 0; /* Clear window dirty flag */ + if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ + if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ + } + } else { + res = FR_DISK_ERR; + } + } + return res; +} +#endif + + +static +FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs, /* Filesystem object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ +) +{ + FRESULT res = FR_OK; + + + if (sector != fs->winsect) { /* Window offset changed? */ +#if !FF_FS_READONLY + res = sync_window(fs); /* Write-back changes */ +#endif + if (res == FR_OK) { /* Fill sector window with new data */ + if (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) { + sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ + res = FR_DISK_ERR; + } + fs->winsect = sector; + } + } + return res; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Synchronize filesystem and data on the storage */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ +) +{ + FRESULT res; + + + res = sync_window(fs); + if (res == FR_OK) { + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ + /* Create FSInfo structure */ + mem_set(fs->win, 0, SS(fs)); + st_word(fs->win + BS_55AA, 0xAA55); + st_dword(fs->win + FSI_LeadSig, 0x41615252); + st_dword(fs->win + FSI_StrucSig, 0x61417272); + st_dword(fs->win + FSI_Free_Count, fs->free_clst); + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); + /* Write it into the FSInfo sector */ + fs->winsect = fs->volbase + 1; + disk_write(fs->pdrv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the lower layer */ + if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; + } + + return res; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Get physical sector number from cluster number */ +/*-----------------------------------------------------------------------*/ + +static +DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ + FATFS* fs, /* Filesystem object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; /* Cluster number is origin from 2 */ + if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ + return fs->database + fs->csize * clst; /* Start sector number of the cluster */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + +static +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ +) +{ + UINT wc, bc; + DWORD val; + FATFS *fs = obj->fs; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ + val = 1; /* Internal error */ + + } else { + val = 0xFFFFFFFF; /* Default value falls on disk error */ + + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ + break; + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; + val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ + break; + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ + break; +#if FF_FS_EXFAT + case FS_EXFAT : + if (obj->objsize != 0) { + DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ + DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ + + if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ + break; + } + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ + val = clst + 1; /* Generate the value */ + break; + } + if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } + break; + } + } + /* go to default */ +#endif + default: + val = 1; /* Internal error */ + } + } + + return val; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding filesystem object */ + DWORD clst, /* FAT index number (cluster number) to be changed */ + DWORD val /* New value to be set to the entry */ +) +{ + UINT bc; + BYTE *p; + FRESULT res = FR_INT_ERR; + + + if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = fs->win + bc++ % SS(fs); + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Put 1st byte */ + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = fs->win + bc % SS(fs); + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */ + fs->wflag = 1; + break; + + case FS_FAT16 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ + fs->wflag = 1; + break; + + case FS_FAT32 : +#if FF_FS_EXFAT + case FS_EXFAT : +#endif + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + } + st_dword(fs->win + clst * 4 % SS(fs), val); + fs->wflag = 1; + break; + } + } + return res; +} + +#endif /* !FF_FS_READONLY */ + + + + +#if FF_FS_EXFAT && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* exFAT: Accessing FAT and Allocation Bitmap */ +/*-----------------------------------------------------------------------*/ + +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ + +static +DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* Filesystem object */ + DWORD clst, /* Cluster number to scan from */ + DWORD ncl /* Number of contiguous clusters to find (1..) */ +) +{ + BYTE bm, bv; + UINT i; + DWORD val, scl, ctr; + + + clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ + if (clst >= fs->n_fatent - 2) clst = 0; + scl = val = clst; ctr = 0; + for (;;) { + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + i = val / 8 % SS(fs); bm = 1 << (val % 8); + do { + do { + bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ + if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ + val = 0; bm = 0; i = SS(fs); + } + if (bv == 0) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ + } else { + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ + } + if (val == clst) return 0; /* All cluster scanned? */ + } while (bm != 0); + bm = 1; + } while (++i < SS(fs)); + } +} + + +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ + +static +FRESULT change_bitmap ( + FATFS* fs, /* Filesystem object */ + DWORD clst, /* Cluster number to change from */ + DWORD ncl, /* Number of clusters to be changed */ + int bv /* bit value to be set (0 or 1) */ +) +{ + BYTE bm; + UINT i; + DWORD sect; + + + clst -= 2; /* The first bit corresponds to cluster #2 */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ + for (;;) { + if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; + do { + do { + if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ + fs->win[i] ^= bm; /* Flip the bit */ + fs->wflag = 1; + if (--ncl == 0) return FR_OK; /* All bits processed? */ + } while (bm <<= 1); /* Next bit */ + bm = 1; + } while (++i < SS(fs)); /* Next byte */ + i = 0; + } +} + + +/*---------------------------------------------*/ +/* Fill the first fragment of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_first_frag ( + FFOBJID* obj /* Pointer to the corresponding object */ +) +{ + FRESULT res; + DWORD cl, n; + + + if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ + for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ + res = put_fat(obj->fs, cl, cl + 1); + if (res != FR_OK) return res; + } + obj->stat = 0; /* Change status 'FAT chain is valid' */ + } + return FR_OK; +} + + +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_last_frag ( + FFOBJID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + + + while (obj->n_frag > 0) { /* Create the chain of last fragment */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + +#endif /* FF_FS_EXFAT && !FF_FS_READONLY */ + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +static +FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst, /* Cluster to remove a chain from */ + DWORD pclst /* Previous cluster of clst (0:entire chain) */ +) +{ + FRESULT res = FR_OK; + DWORD nxt; + FATFS *fs = obj->fs; +#if FF_FS_EXFAT || FF_USE_TRIM + DWORD scl = clst, ecl = clst; +#endif +#if FF_USE_TRIM + DWORD rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ + + /* Mark the previous cluster 'EOC' on the FAT if it exists */ + if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) return res; + } + + /* Remove the chain */ + do { + nxt = get_fat(obj, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) return FR_INT_ERR; /* Internal error? */ + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { + res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ + if (res != FR_OK) return res; + } + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst++; + fs->fsi_flag |= 1; + } +#if FF_FS_EXFAT || FF_USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous cluster block */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ + if (res != FR_OK) return res; + } +#endif +#if FF_USE_TRIM + rt[0] = clst2sect(fs, scl); /* Start of data area freed */ + rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ + disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ +#endif + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } while (clst < fs->n_fatent); /* Repeat while not the last link */ + +#if FF_FS_EXFAT + /* Some post processes for chain status */ + if (fs->fs_type == FS_EXFAT) { + if (pclst == 0) { /* Has the entire chain been removed? */ + obj->stat = 0; /* Change the chain status 'initial' */ + } else { + if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ + clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ + while (clst != pclst) { + nxt = get_fat(obj, clst); + if (nxt < 2) return FR_INT_ERR; + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; + if (nxt != clst + 1) break; /* Not contiguous? */ + clst++; + } + if (clst == pclst) { /* Has the chain got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } + } + } +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch a chain or Create a new chain */ +/*-----------------------------------------------------------------------*/ +static +DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst /* Cluster# to stretch, 0:Create a new chain */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + FATFS *fs = obj->fs; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clst; /* Suggested cluster to start to find */ + if (scl == 0 || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch a chain */ + cs = get_fat(obj, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Test for insanity */ + if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; /* Cluster to start to find */ + } + if (fs->free_clst == 0) return 0; /* No free cluster */ + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ + if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ + res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ + if (res == FR_INT_ERR) return 1; + if (res == FR_DISK_ERR) return 0xFFFFFFFF; + if (clst == 0) { /* Is it a new chain? */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ + if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ + obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ + obj->stat = 3; /* Change status 'just fragmented' */ + } + } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } + } else +#endif + { /* On the FAT/FAT32 volume */ + ncl = 0; + if (scl == clst) { /* Stretching an existing chain? */ + ncl = scl + 1; /* Test if next cluster is free */ + if (ncl >= fs->n_fatent) ncl = 2; + cs = get_fat(obj, ncl); /* Get next cluster status */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (cs != 0) { /* Not free? */ + cs = fs->last_clst; /* Start at suggested cluster if it is valid */ + if (cs >= 2 && cs < fs->n_fatent) scl = cs; + ncl = 0; + } + } + if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster found? */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster? */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (ncl == scl) return 0; /* No free cluster found? */ + } + } + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + } + } + + if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + fs->last_clst = ncl; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; + fs->fsi_flag |= 1; + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ + } + + return ncl; /* Return new cluster number or error status */ +} + +#endif /* !FF_FS_READONLY */ + + + + +#if FF_USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* FAT handling - Convert offset into cluster with link map table */ +/*-----------------------------------------------------------------------*/ + +static +DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File offset to be converted to cluster# */ +) +{ + DWORD cl, ncl, *tbl; + FATFS *fs = fp->obj.fs; + + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (ncl == 0) return 0; /* End of table? (error) */ + if (cl < ncl) break; /* In this fragment? */ + cl -= ncl; tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ +} + +#endif /* FF_USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Fill a cluster with zeros */ +/*-----------------------------------------------------------------------*/ + +#if !FF_FS_READONLY +static +FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS *fs, /* Filesystem object */ + DWORD clst /* Directory table to clear */ +) +{ + DWORD sect; + UINT n, szb; + BYTE *ibuf; + + + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + sect = clst2sect(fs, clst); /* Top of the cluster */ + fs->winsect = sect; /* Set window to top of the cluster */ + mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ +#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ + /* Allocate a temporary buffer */ + for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs); szb > SS(fs) && !(ibuf = ff_memalloc(szb)); szb /= 2) ; + if (szb > SS(fs)) { /* Buffer allocated? */ + mem_set(ibuf, 0, szb); + szb /= SS(fs); /* Bytes -> Sectors */ + for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + ff_memfree(ibuf); + } else +#endif + { + ibuf = fs->win; szb = 1; /* Use window buffer (single-sector writes may take a time) */ + for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + } + return (n == fs->csize) ? FR_OK : FR_DISK_ERR; +} +#endif /* !FF_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to directory object */ + DWORD ofs /* Offset of directory table */ +) +{ + DWORD csz, clst; + FATFS *fs = dp->obj.fs; + + + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ + return FR_INT_ERR; + } + dp->dptr = ofs; /* Set current offset */ + clst = dp->obj.sclust; /* Table start cluster (0:root) */ + if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ + clst = fs->dirbase; + if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + } + + if (clst == 0) { /* Static table (root-directory on the FAT volume) */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + dp->sect = fs->dirbase; + + } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ + csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ + while (ofs >= csz) { /* Follow cluster chain */ + clst = get_fat(&dp->obj, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ + ofs -= csz; + } + dp->sect = clst2sect(fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (dp->sect == 0) return FR_INT_ERR; + dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ + dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory table index next */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +) +{ + DWORD ofs, clst; + FATFS *fs = dp->obj.fs; + + + ofs = dp->dptr + SZDIRE; /* Next entry */ + if (dp->sect == 0 || ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ + + if (ofs % SS(fs) == 0) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (dp->clust == 0) { /* Static table */ + if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ + dp->sect = 0; return FR_NO_FILE; + } + } + else { /* Dynamic table */ + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ +#if !FF_FS_READONLY + if (!stretch) { /* If no stretch, report EOT */ + dp->sect = 0; return FR_NO_FILE; + } + clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ + if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ +#else + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ + dp->sect = 0; return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clst2sect(fs, clst); + } + } + } + dp->dptr = ofs; /* Current entry */ + dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Directory handling - Reserve a block of directory entries */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ +) +{ + FRESULT res; + UINT n; + FATFS *fs = dp->obj.fs; + + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; +#if FF_FS_EXFAT + if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { +#else + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { +#endif + if (++n == nent) break; /* A block of contiguous free entries is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dp, 1); + } while (res == FR_OK); /* Next entry with table stretch enabled */ + } + + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ + return res; +} + +#endif /* !FF_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT: Directory handling - Load/Store start cluster number */ +/*-----------------------------------------------------------------------*/ + +static +DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ +) +{ + DWORD cl; + + cl = ld_word(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) { + cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + } + + return cl; +} + + +#if !FF_FS_READONLY +static +void st_clust ( + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir, /* Pointer to the key entry */ + DWORD cl /* Value to be set */ +) +{ + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } +} +#endif + + + +#if FF_USE_LFN +/*--------------------------------------------------------*/ +/* FAT-LFN: Compare a part of file name with an LFN entry */ +/*--------------------------------------------------------*/ +static +int cmp_lfn ( /* 1:matched, 0:not matched */ + const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ + BYTE* dir /* Pointer to the directory entry containing the part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc != 0) { + if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + return 0; /* Not matched */ + } + wc = uc; + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ + + return 1; /* The part of LFN matched */ +} + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT +/*-----------------------------------------------------*/ +/* FAT-LFN: Pick a part of file name from an LFN entry */ +/*-----------------------------------------------------*/ +static +int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ + BYTE* dir /* Pointer to the LFN entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ + + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc != 0) { + if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ + if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; /* The part of LFN is valid */ +} +#endif + + +#if !FF_FS_READONLY +/*-----------------------------------------*/ +/* FAT-LFN: Create an entry of LFN entries */ +/*-----------------------------------------*/ +static +void put_lfn ( + const WCHAR* lfn, /* Pointer to the LFN */ + BYTE* dir, /* Pointer to the LFN entry to be created */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* Checksum of the corresponding SFN */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set checksum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + st_word(dir + LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ + st_word(dir + LfnOfs[s], wc); /* Put it */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ + } while (++s < 13); + if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LFN */ + + + +#if FF_USE_LFN && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Create a Numbered SFN */ +/*-----------------------------------------------------------------------*/ + +static +void gen_numname ( + BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + WCHAR wc; + DWORD sr; + + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ + sr = seq; + while (*lfn) { /* Create a CRC */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sr = (sr << 1) + (wc & 1); + wc >>= 1; + if (sr & 0x10000) sr ^= 0x11021; + } + } + seq = (UINT)sr; + } + + /* itoa (hexdecimal) */ + i = 7; + do { + c = (BYTE)((seq % 16) + '0'); + if (c > '9') c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number to the SFN body */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (dbc_1st(dst[j])) { + if (j == i - 1) break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif /* FF_USE_LFN && !FF_FS_READONLY */ + + + +#if FF_USE_LFN +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Calculate checksum of an SFN entry */ +/*-----------------------------------------------------------------------*/ + +static +BYTE sum_sfn ( + const BYTE* dir /* Pointer to the SFN entry */ +) +{ + BYTE sum = 0; + UINT n = 11; + + do { + sum = (sum >> 1) + (sum << 7) + *dir++; + } while (--n); + return sum; +} + +#endif /* FF_USE_LFN */ + + + +#if FF_FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* exFAT: Checksum */ +/*-----------------------------------------------------------------------*/ + +static +WORD xdir_sum ( /* Get checksum of the directoly entry block */ + const BYTE* dir /* Directory entry block to be calculated */ +) +{ + UINT i, szblk; + WORD sum; + + + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + for (i = sum = 0; i < szblk; i++) { + if (i == XDIR_SetSum) { /* Skip sum field */ + i++; + } else { + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; + } + } + return sum; +} + + + +static +WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ + const WCHAR* name /* File name to be calculated */ +) +{ + WCHAR chr; + WORD sum = 0; + + + while ((chr = *name++) != 0) { + chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be upper-case converted */ + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); + } + return sum; +} + + +#if !FF_FS_READONLY && FF_USE_MKFS +static +DWORD xsum32 ( + BYTE dat, /* Byte to be calculated */ + DWORD sum /* Previous sum */ +) +{ + sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; + return sum; +} +#endif + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 +/*------------------------------------------------------*/ +/* exFAT: Get object information from a directory block */ +/*------------------------------------------------------*/ + +static +void get_xfileinfo ( + BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ + FILINFO* fno /* Buffer to store the extracted file information */ +) +{ + WCHAR wc, hs; + UINT di, si, nc; + + /* Get file name from the entry block */ + si = SZDIRE * 2; /* 1st C1 entry */ + nc = hs = di = 0; + while (nc < dirb[XDIR_NumName]) { + if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ + } + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ + if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ + di += wc; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + fno->fname[di] = 0; /* Terminate the name */ + fno->altname[0] = 0; /* exFAT does not have SFN */ + + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ +} + +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ + + +/*-----------------------------------*/ +/* exFAT: Get a directry entry block */ +/*-----------------------------------*/ + +static +FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Reading direcotry object pointing top of the entry block to load */ +) +{ + FRESULT res; + UINT i, sz_ent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + + + /* Load 85 entry */ + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ + mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; + + /* Load C0 entry */ + res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ + mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; + + /* Load C1 entries */ + i = 2 * SZDIRE; /* C1 offset to load */ + do { + res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ + if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + + /* Sanity check (do it for only accessible object) */ + if (i <= MAXDIRB(FF_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } + return FR_OK; +} + + +/*------------------------------------------------------------------*/ +/* exFAT: Initialize object allocation info with loaded entry block */ +/*------------------------------------------------------------------*/ + +static +void init_alloc_info ( + FATFS* fs, /* Filesystem object */ + FFOBJID* obj /* Object allocation information to be initialized */ +) +{ + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ + obj->n_frag = 0; /* No last fragment info */ +} + + + +#if !FF_FS_READONLY || FF_FS_RPATH != 0 +/*------------------------------------------------*/ +/* exFAT: Load the object's directory entry block */ +/*------------------------------------------------*/ +static +FRESULT load_obj_xdir ( + DIR* dp, /* Blank directory object to be used to access containing direcotry */ + const FFOBJID* obj /* Object with its containing directory information */ +) +{ + FRESULT res; + + /* Open object containing directory */ + dp->obj.fs = obj->fs; + dp->obj.sclust = obj->c_scl; + dp->obj.stat = (BYTE)obj->c_size; + dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->obj.n_frag = 0; + dp->blk_ofs = obj->c_ofs; + + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ + if (res == FR_OK) { + res = load_xdir(dp); /* Load the object's entry block */ + } + return res; +} +#endif + + +#if !FF_FS_READONLY +/*----------------------------------------*/ +/* exFAT: Store the directory entry block */ +/*----------------------------------------*/ +static +FRESULT store_xdir ( + DIR* dp /* Pointer to the direcotry object */ +) +{ + FRESULT res; + UINT nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + + /* Create set sum */ + st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); + nent = dirb[XDIR_NumSec] + 1; + + /* Store the direcotry entry block to the directory */ + res = dir_sdi(dp, dp->blk_ofs); + while (res == FR_OK) { + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; + mem_cpy(dp->dir, dirb, SZDIRE); + dp->obj.fs->wflag = 1; + if (--nent == 0) break; + dirb += SZDIRE; + res = dir_next(dp, 0); + } + return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; +} + + + +/*-------------------------------------------*/ +/* exFAT: Create a new directory enrty block */ +/*-------------------------------------------*/ + +static +void create_xdir ( + BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + const WCHAR* lfn /* Pointer to the object name */ +) +{ + UINT i; + BYTE nc1, nlen; + WCHAR wc; + + + /* Create 85,C0 entry */ + mem_set(dirb, 0, 2 * SZDIRE); + dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ + dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ + + /* Create C1 entries */ + i = SZDIRE * 2; /* Top of C1 entries */ + nlen = nc1 = 0; wc = 1; + do { + dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + do { /* Fill name field */ + if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ + st_word(dirb + i, wc); /* Store it */ + i += 2; + } while (i % SZDIRE != 0); + nc1++; + } while (lfn[nlen]); /* Fill next entry if any char follows */ + + dirb[XDIR_NumName] = nlen; /* Set name length */ + dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_EXFAT */ + + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ + +#define dir_read_file(dp) dir_read(dp, 0) +#define dir_read_label(dp) dir_read(dp, 1) + +static +FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE a, c; +#if FF_USE_LFN + BYTE ord = 0xFF, sum = 0xFF; +#endif + + while (dp->sect) { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; /* Test for the entry type */ + if (c == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + if (FF_USE_LABEL && vol) { + if (c == 0x83) break; /* Volume label entry? */ + } else { + if (c == 0x85) { /* Start of the file entry block? */ + dp->blk_ofs = dp->dptr; /* Get location of the block */ + res = load_xdir(dp); /* Load the entry block */ + if (res == FR_OK) { + dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ + } + break; + } + } + } else +#endif + { /* On the FAT/FAT32 volume */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if FF_USE_LFN /* LFN configuration */ + if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of an LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; + dp->blk_ofs = dp->dptr; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ + } + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + break; + } +#endif + } + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ + return res; +} + +#endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + BYTE c; +#if FF_USE_LFN + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + BYTE nc; + UINT di, ni; + WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ + + while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ +#if FF_MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ + for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ + if ((di % SZDIRE) == 0) di += 2; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + } + if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ + } + return res; + } +#endif + /* On the FAT/FAT32 volume */ +#if FF_USE_LFN + ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if FF_USE_LFN /* LFN configuration */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; + if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (!(dp->fn[NSFLAG] & NS_NOLFN)) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; /* LFN start order */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ + DIR* dp /* Target directory with object name to be created */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if FF_USE_LFN /* LFN configuration */ + UINT n, nlen, nent; + BYTE sn[12], sum; + + + if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res != FR_OK) return res; + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ + + if (dp->obj.stat & 4) { /* Has the directory been stretched? */ + dp->obj.stat &= ~4; + res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ + if (res != FR_OK) return res; + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ + if (res != FR_OK) return res; + if (dp->obj.sclust != 0) { /* Is it a sub directory? */ + DIR dj; + + res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ + if (res != FR_OK) return res; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } + } + + create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ + return FR_OK; + } +#endif + /* On the FAT/FAT32 volume */ + mem_cpy(sn, dp->fn, 12); + if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ + res = dir_find(dp); /* Check if the name collides with existing SFN */ + if (res != FR_OK) break; + } + if (n == 100) return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ + dp->fn[NSFLAG] = sn[NSFLAG]; + } + + /* Create an SFN with/without LFNs. */ + nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res == FR_OK && --nent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->dptr - nent * SZDIRE); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); + fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --nent); + } + } + +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ + +#endif + + /* Set SFN entry */ + if (res == FR_OK) { + res = move_window(fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ + mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ +#if FF_USE_LFN + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + fs->wflag = 1; + } + } + + return res; +} + +#endif /* !FF_FS_READONLY */ + + + +#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if FF_USE_LFN /* LFN configuration */ + DWORD last = dp->dptr; + + res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ + if (res == FR_OK) { + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ + } else { /* On the FAT/FAT32 volume */ + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ + } + fs->wflag = 1; + if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR; + } +#else /* Non LFN configuration */ + + res = move_window(fs, dp->sect); + if (res == FR_OK) { + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ + fs->wflag = 1; + } +#endif + + return res; +} + +#endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ + + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ + +static +void get_fileinfo ( + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ +) +{ + UINT si, di; +#if FF_USE_LFN + WCHAR wc, hs; + FATFS *fs = dp->obj.fs; +#else + TCHAR c; +#endif + + + fno->fname[0] = 0; /* Invaidate file info */ + if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ + +#if FF_USE_LFN /* LFN configuration */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + get_xfileinfo(fs->dirbuf, fno); + return; + } else +#endif + { /* On the FAT/FAT32 volume */ + if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ + si = di = hs = 0; + while (fs->lfnbuf[si] != 0) { + wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ + } + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ + if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ + di += wc; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ + } + } + + si = di = 0; + while (si < 11) { /* Get SFN from SFN entry */ + wc = dp->dir[si++]; /* Get a char */ + if (wc == ' ') continue; /* Skip padding spaces */ + if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ + if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ +#if FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ + wc = wc << 8 | dp->dir[si++]; + } + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ + if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in UTF-16 or UTF-8 */ + if (wc == 0) { di = 0; break; } /* Buffer overflow? */ + di += wc; +#else /* ANSI/OEM output */ + fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ +#endif + } + fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ + + if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ + fno->fname[di++] = '?'; + } else { + for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + wc = (WCHAR)fno->altname[si]; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; + fno->fname[di] = (TCHAR)wc; + } + } + fno->fname[di] = 0; /* Terminate the LFN */ + if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ + } + +#else /* Non-LFN configuration */ + si = di = 0; + while (si < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[si++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ + if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ + fno->fname[di++] = c; + } + fno->fname[di] = 0; +#endif + + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ +} + +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ + + + +#if FF_USE_FIND && FF_FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Pattern matching */ +/*-----------------------------------------------------------------------*/ + +static +DWORD get_achar ( /* Get a character and advances ptr */ + const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ +) +{ + DWORD chr; + + +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ + chr = tchar2uni(ptr); + if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ + chr = ff_wtoupper(chr); + +#else /* ANSI/OEM input */ + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ +#if FF_CODE_PAGE == 0 + if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#elif FF_CODE_PAGE < 900 + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#endif +#if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 + if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ + chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; + } +#endif + +#endif + return chr; +} + + +static +int pattern_matching ( /* 0:not matched, 1:matched */ + const TCHAR* pat, /* Matching pattern */ + const TCHAR* nam, /* String to be tested */ + int skip, /* Number of pre-skip chars (number of ?s) */ + int inf /* Infinite search (* specified) */ +) +{ + const TCHAR *pp, *np; + DWORD pc, nc; + int nm, nx; + + + while (skip--) { /* Pre-skip name chars */ + if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ + } + if (*pat == 0 && inf) return 1; /* (short circuit) */ + + do { + pp = pat; np = nam; /* Top of pattern and name to match */ + for (;;) { + if (*pp == '?' || *pp == '*') { /* Wildcard? */ + nm = nx = 0; + do { /* Analyze the wildcard block */ + if (*pp++ == '?') nm++; else nx = 1; + } while (*pp == '?' || *pp == '*'); + if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ + nc = *np; break; /* Branch mismatched */ + } + pc = get_achar(&pp); /* Get a pattern char */ + nc = get_achar(&np); /* Get a name char */ + if (pc != nc) break; /* Branch mismatched? */ + if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ + } + get_achar(&nam); /* nam++ */ + } while (inf && nc); /* Retry until end of name if infinite search is specified */ + + return 0; +} + +#endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ + + + +/*-----------------------------------------------------------------------*/ +/* Pick a top segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ +) +{ +#if FF_USE_LFN /* LFN configuration */ + BYTE b, cf; + WCHAR wc, *lfn; + DWORD uc; + UINT i, ni, si, di; + const TCHAR *p; + + + /* Create LFN into LFN working buffer */ + p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; + for (;;) { + uc = tchar2uni(&p); /* Get a character */ + if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ + if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ + wc = (WCHAR)uc; + if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ + if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ + lfn[di++] = wc; /* Store the Unicode character */ + } + while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ + *path = p; /* Return pointer to the next segment */ + cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + +#if FF_FS_RPATH != 0 + if ((di == 1 && lfn[di - 1] == '.') || + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ + lfn[di] = 0; + for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ + dp->fn[i] = (i < di) ? '.' : ' '; + } + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Snip off trailing spaces and dots if exist */ + wc = lfn[di - 1]; + if (wc != ' ' && wc != '.') break; + di--; + } + lfn[di] = 0; /* LFN is created into the working buffer */ + if (di == 0) return FR_INVALID_NAME; /* Reject null name */ + + /* Create SFN in directory form */ + for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ + if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ + while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ + + mem_set(dp->fn, ' ', 11); + i = b = 0; ni = 8; + for (;;) { + wc = lfn[si++]; /* Get an LFN character */ + if (wc == 0) break; /* Break on end of the LFN */ + if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ + cf |= NS_LOSS | NS_LFN; + continue; + } + + if (i >= ni || si == di) { /* End of field? */ + if (ni == 11) { /* Name extension overflow? */ + cf |= NS_LOSS | NS_LFN; + break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ + if (si > di) break; /* No name extension? */ + si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ + continue; + } + + if (wc >= 0x80) { /* Is this a non-ASCII character? */ + cf |= NS_LFN; /* LFN entry needs to be created */ +#if FF_CODE_PAGE == 0 + if (ExCvt) { /* At SBCS */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ + } else { /* At DBCS */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ + } +#elif FF_CODE_PAGE < 900 /* SBCS cfg */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ +#else /* DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ +#endif + } + + if (wc >= 0x100) { /* Is this a DBC? */ + if (i >= ni - 1) { /* Field overflow? */ + cf |= NS_LOSS | NS_LFN; + i = ni; continue; /* Next field */ + } + dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ + } else { /* SBC */ + if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ + wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(wc)) { /* ASCII upper case? */ + b |= 2; + } + if (IsLower(wc)) { /* ASCII lower case? */ + b |= 1; wc -= 0x20; + } + } + } + dp->fn[i++] = (BYTE)wc; + } + + if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + + if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ + if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ + } + + dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ + + return FR_OK; + + +#else /* FF_USE_LFN : Non-LFN configuration */ + BYTE c, d, *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + p = *path; sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = 0; ni = 8; +#if FF_FS_RPATH != 0 + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; + *path = p + si; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; /* Get a byte */ + if (c <= ' ') break; /* Break if end of the path name */ + if (c == '/' || c == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (c == '.' || i >= ni) { /* End of body or field overflow? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ + i = 8; ni = 11; /* Enter file extension field */ + continue; + } +#if FF_CODE_PAGE == 0 + if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ + } +#elif FF_CODE_PAGE < 900 + if (c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ + } +#endif + if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ + sfn[i++] = c; + sfn[i++] = d; + } else { /* SBC */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ + if (IsLower(c)) c -= 0x20; /* To upper */ + sfn[i++] = c; + } + } + *path = p + si; /* Return pointer to the next segment */ + if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ + + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + + return FR_OK; +#endif /* FF_USE_LFN */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Follow a file path */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ +) +{ + FRESULT res; + BYTE ns; + FATFS *fs = dp->obj.fs; + + +#if FF_FS_RPATH != 0 + if (*path != '/' && *path != '\\') { /* Without heading separator */ + dp->obj.sclust = fs->cdir; /* Start from current directory */ + } else +#endif + { /* With heading separator */ + while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ + dp->obj.sclust = 0; /* Start from root directory */ + } +#if FF_FS_EXFAT + dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ +#if FF_FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ + DIR dj; + + dp->obj.c_scl = fs->cdc_scl; + dp->obj.c_size = fs->cdc_size; + dp->obj.c_ofs = fs->cdc_ofs; + res = load_obj_xdir(&dj, &dp->obj); + if (res != FR_OK) return res; + dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } +#endif +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + dp->fn[NSFLAG] = NS_NONAME; + res = dir_sdi(dp, 0); + + } else { /* Follow path */ + for (;;) { + res = create_name(dp, &path); /* Get a segment name of the path */ + if (res != FR_OK) break; + res = dir_find(dp); /* Find an object with the segment name */ + ns = dp->fn[NSFLAG]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ + } + } + break; + } + if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ + /* Get into the sub-directory */ + if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; break; + } +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + dp->obj.c_scl = dp->obj.sclust; + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Open next directory */ + } else +#endif + { + dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + } + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get logical drive number from path name */ +/*-----------------------------------------------------------------------*/ + +static +int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ + const TCHAR** path /* Pointer to pointer to the path name */ +) +{ + const TCHAR *tp, *tt; + UINT i; + int vol = -1; +#if FF_STR_VOLUME_ID /* Find string drive id */ + static const char* const volid[] = {FF_VOLUME_STRS}; + const char *sp; + char c; + TCHAR tc; +#endif + + + if (*path != 0) { /* If the pointer is not a null */ + for (tt = *path; (UINT)*tt >= (FF_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find a colon in the path */ + if (*tt == ':') { /* If a colon is exist in the path name */ + tp = *path; + i = *tp++; + if (IsDigit(i) && tp == tt) { /* Is there a numeric drive id + colon? */ + if ((i -= '0') < FF_VOLUMES) { /* If drive id is found, get the value and strip it */ + vol = (int)i; + *path = ++tt; + } + } +#if FF_STR_VOLUME_ID + else { /* No numeric drive number, find string drive id */ + i = 0; tt++; + do { + sp = volid[i]; tp = *path; + do { /* Compare a string drive id with path name */ + c = *sp++; tc = *tp++; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ + if (i < FF_VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = tt; + } + } +#endif + } else { /* No volume id and use default drive */ +#if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 + vol = CurrVol; /* Current drive */ +#else + vol = 0; /* Drive 0 */ +#endif + } + } + return vol; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load a sector and check if it is an FAT VBR */ +/*-----------------------------------------------------------------------*/ + +static +BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ + FATFS* fs, /* Filesystem object */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ +) +{ + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ + + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ + +#if FF_FS_EXFAT + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ +#endif + if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ + if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ + if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ + } + return 2; /* Valid BS but not FAT */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Determine logical drive number and mount the volume if needed */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ + const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + FATFS** rfs, /* Pointer to pointer to the found filesystem object */ + BYTE mode /* !=0: Check write protection for write access */ +) +{ + BYTE fmt, *pt; + int vol; + DSTATUS stat; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; + WORD nrsv; + FATFS *fs; + UINT i; + + + /* Get logical drive number */ + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) return FR_INVALID_DRIVE; + + /* Check if the filesystem object is valid or not */ + fs = FatFs[vol]; /* Get pointer to the filesystem object */ + if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ +#if FF_FS_REENTRANT + if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ +#endif + *rfs = fs; /* Return pointer to the filesystem object */ + + mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ + if (fs->fs_type != 0) { /* If the volume has been mounted */ + stat = disk_status(fs->pdrv); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + } + return FR_OK; /* The filesystem object is valid */ + } + } + + /* The filesystem object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ + + fs->fs_type = 0; /* Clear the filesystem object */ + fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ + stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ + if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ + } + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; + } +#if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; +#endif + + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ + bsect = 0; + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ + if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ + for (i = 0; i < 4; i++) { /* Get partition offset */ + pt = fs->win + (MBR_Table + i * SZ_PTE); + br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; + } + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + if (i != 0) i--; + do { /* Find an FAT volume */ + bsect = br[i]; + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); + } + if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* An FAT volume is found (bsect). Following code initializes the filesystem object */ + +#if FF_FS_EXFAT + if (fmt == 1) { + QWORD maxlba; + + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; + + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ + + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + } + + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ + if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ + + fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ + + fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ + + fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ + + nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = nclst + 2; + + /* Boundaries and Limits */ + fs->volbase = bsect; + fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + + /* Check if bitmap location is in assumption (at the first cluster) */ + if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; + for (i = 0; i < SS(fs); i += SZDIRE) { + if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + } + if (i == SS(fs)) return FR_NO_FILESYSTEM; +#if !FF_FS_READONLY + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ +#endif + fmt = FS_EXFAT; /* FAT sub-type */ + } else +#endif /* FF_FS_EXFAT */ + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ + + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = 0; + if (nclst <= MAX_FAT32) fmt = FS_FAT32; + if (nclst <= MAX_FAT16) fmt = FS_FAT16; + if (nclst <= MAX_FAT12) fmt = FS_FAT12; + if (fmt == 0) return FR_NO_FILESYSTEM; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ + +#if !FF_FS_READONLY + /* Get FSInfo if available */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->fsi_flag = 0x80; +#if (FF_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ + && ld_word(fs->win + BPB_FSInfo32) == 1 + && move_window(fs, bsect + 1) == FR_OK) + { + fs->fsi_flag = 0; + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ + && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 + && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + { +#if (FF_FS_NOFSINFO & 1) == 0 + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#endif +#if (FF_FS_NOFSINFO & 2) == 0 + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#endif + } + } +#endif /* (FF_FS_NOFSINFO & 3) != 3 */ +#endif /* !FF_FS_READONLY */ + } + + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* Volume mount ID */ +#if FF_USE_LFN == 1 + fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ +#if FF_FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ +#endif +#endif +#if FF_FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ +#endif +#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ + clear_lock(fs); +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/directory object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ +) +{ + FRESULT res = FR_INVALID_OBJECT; + + + if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ +#if FF_FS_REENTRANT + if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } else { + unlock_fs(obj->fs, FR_OK); + } + } else { + res = FR_TIMEOUT; + } +#else + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } +#endif + } + *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ + return res; +} + + + + +/*--------------------------------------------------------------------------- + + Public Functions (FatFs API) + +----------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ + const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ +) +{ + FATFS *cfs; + int vol; + FRESULT res; + const TCHAR *rp = path; + + + /* Get logical drive number */ + vol = get_ldnumber(&rp); + if (vol < 0) return FR_INVALID_DRIVE; + cfs = FatFs[vol]; /* Pointer to fs object */ + + if (cfs) { +#if FF_FS_LOCK != 0 + clear_lock(cfs); +#endif +#if FF_FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#endif + cfs->fs_type = 0; /* Clear old fs object */ + } + + if (fs) { + fs->fs_type = 0; /* Clear new fs object */ +#if FF_FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; +#endif + } + FatFs[vol] = fs; /* Register new fs object */ + + if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ + + res = find_volume(&path, &fs, 0); /* Force mounted the volume */ + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_open ( + FIL* fp, /* Pointer to the blank file object */ + const TCHAR* path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; +#if !FF_FS_READONLY + DWORD dw, cl, bcs, clst, sc; + FSIZE_t ofs; +#endif + DEF_NAMBUF + + + if (!fp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; + res = find_volume(&path, &fs, mode); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ +#if !FF_FS_READONLY /* Read/Write configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + res = FR_INVALID_NAME; + } +#if FF_FS_LOCK != 0 + else { + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ + } +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ +#if FF_FS_LOCK != 0 + res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + } + mode |= FA_CREATE_ALWAYS; /* File is created */ + } + else { /* Any object with the same name is already existing */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + /* Get current allocation info */ + fp->obj.fs = fs; + init_alloc_info(fs, &fp->obj); + /* Set directory entry block initial state */ + mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ + mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ + fs->dirbuf[XDIR_Attr] = AM_ARC; + st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); + fs->dirbuf[XDIR_GenFlags] = 1; + res = store_xdir(&dj); + if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ + } + } else +#endif + { + /* Set directory entry initial state */ + cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ + st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ + dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ + st_clust(fs, dj.dir, 0); /* Reset file allocation info */ + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + if (cl != 0) { /* Remove the cluster chain if exist */ + dw = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) { + res = move_window(fs, dw); + fs->last_clst = cl - 1; /* Reuse the cluster hole */ + } + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Is the object exsiting? */ + if (dj.obj.attr & AM_DIR) { /* File open against a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ + res = FR_DENIED; + } + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dj.dir; +#if FF_FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ + if (fp->obj.lockid == 0) res = FR_INT_ERR; +#endif + } +#else /* R/O configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ + res = FR_INVALID_NAME; + } else { + if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ + res = FR_NO_FILE; + } + } + } +#endif + + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ + fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fp->obj.c_ofs = dj.blk_ofs; + init_alloc_info(fs, &fp->obj); + } else +#endif + { + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } +#if FF_USE_FASTSEEK + fp->cltbl = 0; /* Disable fast seek mode */ +#endif + fp->obj.fs = fs; /* Validate the file object */ + fp->obj.id = fs->id; + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ +#if !FF_FS_READONLY +#if !FF_FS_TINY + mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ +#endif + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + fp->fptr = fp->obj.objsize; /* Offset to seek */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ + clst = fp->obj.sclust; /* Follow the cluster chain */ + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ + if ((sc = clst2sect(fs, clst)) == 0) { + res = FR_INT_ERR; + } else { + fp->sect = sc + (DWORD)(ofs / SS(fs)); +#if !FF_FS_TINY + if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; +#endif + } + } + } +#endif + } + + FREE_NAMBUF(); + } + + if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE*)buff; + + + *br = 0; /* Clear read byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + remain = fp->obj.objsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr; /* Repeat until all data read */ + btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow cluster chain from the origin */ + } else { /* Middle or end of the file */ +#if FF_USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ + } + } + if (clst < 2) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fs); /* When remaining bytes >= sector size, */ + if (cc > 0) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if FF_FS_TINY + if (fs->wflag && fs->winsect - sect < cc) { + mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } +#else + if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { + mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + } +#endif +#endif + rcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !FF_FS_TINY + if (fp->sect != sect) { /* Load data sector if not in cache */ +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + } +#endif + fp->sect = sect; + } + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ +#if FF_FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#else + mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#endif + } + + LEAVE_FF(fs, FR_OK); +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Pointer to number of bytes written */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + UINT wcnt, cc, csect; + const BYTE *wbuff = (const BYTE*)buff; + + + *bw = 0; /* Clear write byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + for ( ; btw; /* Repeat until all data written */ + btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + if (clst == 0) { /* If no cluster is allocated, */ + clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ + } + } else { /* On the middle or end of the file */ +#if FF_USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } + } + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ + } +#if FF_FS_TINY + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ +#else + if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fs); /* When remaining bytes >= sector size, */ + if (cc > 0) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if FF_FS_MINIMIZE <= 2 +#if FF_FS_TINY + if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; + } +#else + if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif +#endif + wcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if FF_FS_TINY + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ + if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; + } +#else + if (fp->sect != sect && /* Fill sector cache with file data */ + fp->fptr < fp->obj.objsize && + disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } +#endif + fp->sect = sect; + } + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ +#if FF_FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fs->wflag = 1; +#else + mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fp->flag |= FA_DIRTY; +#endif + } + + fp->flag |= FA_MODIFIED; /* Set file change flag */ + + LEAVE_FF(fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD tm; + BYTE *dir; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { + if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ +#if !FF_FS_TINY + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + /* Update the directory entry */ + tm = GET_FATTIME(); /* Modified time */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ + if (res == FR_OK) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } + if (res == FR_OK) { + DIR dj; + DEF_NAMBUF + + INIT_NAMBUF(fs); + res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ + if (res == FR_OK) { + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + st_dword(fs->dirbuf + XDIR_AccTime, 0); + res = store_xdir(&dj); /* Restore it to the directory */ + if (res == FR_OK) { + res = sync_fs(fs); + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + FREE_NAMBUF(); + } + } else +#endif + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_dword(dir + DIR_ModTime, tm); /* Update modified time */ + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); /* Restore it to the directory */ + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !FF_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL* fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + +#if !FF_FS_READONLY + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) +#endif + { + res = validate(&fp->obj, &fs); /* Lock volume */ + if (res == FR_OK) { +#if FF_FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ + if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ +#else + fp->obj.fs = 0; /* Invalidate file object */ +#endif +#if FF_FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + } + return res; +} + + + + +#if FF_FS_RPATH >= 1 +/*-----------------------------------------------------------------------*/ +/* Change Current Directory or Current Drive, Get Current Directory */ +/*-----------------------------------------------------------------------*/ + +#if FF_VOLUMES >= 2 +FRESULT f_chdrive ( + const TCHAR* path /* Drive number */ +) +{ + int vol; + + + /* Get logical drive number */ + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + + CurrVol = (BYTE)vol; /* Set it as current volume */ + + return FR_OK; +} +#endif + + +FRESULT f_chdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { + fs->cdir = dj.obj.sclust; /* It is the start directory itself */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdc_scl = dj.obj.c_scl; + fs->cdc_size = dj.obj.c_size; + fs->cdc_ofs = dj.obj.c_ofs; + } +#endif + } else { + if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ + fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ + fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fs->cdc_ofs = dj.blk_ofs; + } else +#endif + { + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + } + } else { + res = FR_NO_PATH; /* Reached but a file */ + } + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(fs, res); +} + + +#if FF_FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of path */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEF_NAMBUF + + + *buff = 0; + /* Get logical drive */ + res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + i = len; /* Bottom of buffer (directory stack base) */ + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ + if (res != FR_OK) break; + res = move_window(fs, dj.sect); + if (res != FR_OK) break; + dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read_file(&dj); + if (res != FR_OK) break; + if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (n = 0; fno.fname[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = fno.fname[--n]; + buff[--i] = '/'; + } + } + tp = buff; + if (res == FR_OK) { +#if FF_VOLUMES >= 2 + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; +#endif + if (i == len) { /* Root-directory */ + *tp++ = '/'; + } else { /* Sub-directroy */ + do /* Add stacked path str */ + *tp++ = buff[i++]; + while (i < len); + } + } + *tp = 0; + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* FF_FS_RPATH >= 2 */ +#endif /* FF_FS_RPATH >= 1 */ + + + +#if FF_FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File Read/Write Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File pointer from top of file */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, bcs, nsect; + FSIZE_t ifptr; +#if FF_USE_FASTSEEK + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; +#endif + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) res = (FRESULT)fp->err; +#if FF_FS_EXFAT && !FF_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + +#if FF_USE_FASTSEEK + if (fp->cltbl) { /* Fast seek */ + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; ulen = 2; /* Given table size and required table size */ + cl = fp->obj.sclust; /* Origin of the chain */ + if (cl != 0) { + do { + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { + pcl = cl; ncl++; + cl = get_fat(&fp->obj, cl); + if (cl <= 1) ABORT(fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + } while (cl == pcl + 1); + if (ulen <= tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; *tbl++ = tcl; + } + } while (cl < fs->n_fatent); /* Repeat until end of chain */ + } + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) { + *tbl = 0; /* Terminate table */ + } else { + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ + } + } else { /* Fast seek */ + if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ + fp->fptr = ofs; /* Set file pointer */ + if (ofs > 0) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clst2sect(fs, fp->clust); + if (dsc == 0) ABORT(fs, FR_INT_ERR); + dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); + if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ +#if !FF_FS_TINY +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ +#endif + fp->sect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { +#if FF_FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ +#endif + if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + ofs = fp->obj.objsize; + } + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs > 0) { + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->obj.sclust; /* start from the first cluster */ +#if !FF_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(&fp->obj, 0); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->obj.sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; +#if !FF_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ + if (clst == 0) { /* Clip file size in case of disk full */ + ofs = 0; break; + } + } else +#endif + { + clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + } + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); + fp->clust = clst; + } + fp->fptr += ofs; + if (ofs % SS(fs)) { + nsect = clst2sect(fs, clst); /* Current sector */ + if (nsect == 0) ABORT(fs, FR_INT_ERR); + nsect += (DWORD)(ofs / SS(fs)); + } + } + } + if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ +#if !FF_FS_TINY +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ +#endif + fp->sect = nsect; + } + } + + LEAVE_FF(fs, res); +} + + + +#if FF_FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Create a Directory Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_opendir ( + DIR* dp, /* Pointer to directory object to create */ + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + FATFS *fs; + DEF_NAMBUF + + + if (!dp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + if (res == FR_OK) { + dp->obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(dp, path); /* Follow the path to the directory */ + if (res == FR_OK) { /* Follow completed */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Get object allocation info */ + } else +#endif + { + dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ + } + } else { /* This object is a file */ + res = FR_NO_PATH; + } + } + if (res == FR_OK) { + dp->obj.id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ +#if FF_FS_LOCK != 0 + if (res == FR_OK) { + if (dp->obj.sclust != 0) { + dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; + } else { + dp->obj.lockid = 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Close Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_closedir ( + DIR *dp /* Pointer to the directory object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + + + res = validate(&dp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { +#if FF_FS_LOCK != 0 + if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ + if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ +#else + dp->obj.fs = 0; /* Invalidate directory object */ +#endif +#if FF_FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entries in Sequence */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_readdir ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + FATFS *fs; + DEF_NAMBUF + + + res = validate(&dp->obj, &fs); /* Check validity of the directory object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_NAMBUF(fs); + res = dir_read_file(dp); /* Read an item */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dp, fno); /* Get the object information */ + res = dir_next(dp, 0); /* Increment index for next */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ + } + FREE_NAMBUF(); + } + } + LEAVE_FF(fs, res); +} + + + +#if FF_USE_FIND +/*-----------------------------------------------------------------------*/ +/* Find Next File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findnext ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to the file information structure */ +) +{ + FRESULT res; + + + for (;;) { + res = f_readdir(dp, fno); /* Get a directory item */ + if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ + if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ +#if FF_USE_LFN && FF_USE_FIND == 2 + if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ +#endif + } + return res; +} + + + +/*-----------------------------------------------------------------------*/ +/* Find First File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findfirst ( + DIR* dp, /* Pointer to the blank directory object */ + FILINFO* fno, /* Pointer to the file information structure */ + const TCHAR* path, /* Pointer to the directory to open */ + const TCHAR* pattern /* Pointer to the matching pattern */ +) +{ + FRESULT res; + + + dp->pat = pattern; /* Save pointer to pattern string */ + res = f_opendir(dp, path); /* Open the target directory */ + if (res == FR_OK) { + res = f_findnext(dp, fno); /* Find the first item */ + } + return res; +} + +#endif /* FF_USE_FIND */ + + + +#if FF_FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_stat ( + const TCHAR* path, /* Pointer to the file path */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(&path, &dj.obj.fs, 0); + if (res == FR_OK) { + INIT_NAMBUF(dj.obj.fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ + res = FR_INVALID_NAME; + } else { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(dj.obj.fs, res); +} + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + const TCHAR* path, /* Logical drive number */ + DWORD* nclst, /* Pointer to a variable to return number of free clusters */ + FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD nfree, clst, sect, stat; + UINT i; + FFOBJID obj; + + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + if (res == FR_OK) { + *fatfs = fs; /* Return ptr to the fs object */ + /* If free_clst is valid, return it without full FAT scan */ + if (fs->free_clst <= fs->n_fatent - 2) { + *nclst = fs->free_clst; + } else { + /* Scan FAT to obtain number of free clusters */ + nfree = 0; + if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ + clst = 2; obj.fs = fs; + do { + stat = get_fat(&obj, clst); + if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0) nfree++; + } while (++clst < fs->n_fatent); + } else { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ + BYTE bm; + UINT b; + + clst = fs->n_fatent - 2; /* Number of clusters */ + sect = fs->database; /* Assuming bitmap starts at cluster 2 */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of bits with zero in the bitmap */ + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + } + for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { + if (!(bm & 1)) nfree++; + bm >>= 1; + } + i = (i + 1) % SS(fs); + } while (clst); + } else +#endif + { /* FAT16/32: Scan WORD/DWORD FAT entries */ + clst = fs->n_fatent; /* Number of entries */ + sect = fs->fatbase; /* Top of the FAT */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of entries with zero in the FAT */ + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + } + if (fs->fs_type == FS_FAT16) { + if (ld_word(fs->win + i) == 0) nfree++; + i += 2; + } else { + if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; + i += 4; + } + i %= SS(fs); + } while (--clst); + } + } + *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ + } + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD ncl; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fp->obj.sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(&fp->obj, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fs->n_fatent) { + res = remove_chain(&fp->obj, ncl, fp->clust); + } + } + fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ + fp->flag |= FA_MODIFIED; +#if !FF_FS_TINY + if (res == FR_OK && (fp->flag & FA_DIRTY)) { + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fp->flag &= (BYTE)~FA_DIRTY; + } + } +#endif + if (res != FR_OK) ABORT(fs, res); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + const TCHAR* path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + DIR dj, sdj; + DWORD dclst = 0; + FATFS *fs; +#if FF_FS_EXFAT + FFOBJID obj; +#endif + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; /* Cannot remove dot entry */ + } +#if FF_FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ +#endif + if (res == FR_OK) { /* The object is accessible */ + if (dj.fn[NSFLAG] & NS_NONAME) { + res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + } else { + if (dj.obj.attr & AM_RDO) { + res = FR_DENIED; /* Cannot remove R/O object */ + } + } + if (res == FR_OK) { +#if FF_FS_EXFAT + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + init_alloc_info(fs, &obj); + dclst = obj.sclust; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ +#if FF_FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ + res = FR_DENIED; + } else +#endif + { + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } +#endif + res = dir_sdi(&sdj, 0); + if (res == FR_OK) { + res = dir_read_file(&sdj); /* Test if the directory is empty */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ +#if FF_FS_EXFAT + res = remove_chain(&obj, dclst, 0); +#else + res = remove_chain(&dj.obj, dclst, 0); +#endif + } + if (res == FR_OK) res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + BYTE *dir; + DWORD dcl, pcl, tm; + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ + if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; + } + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ + dj.obj.objsize = (DWORD)fs->csize * SS(fs); + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + tm = GET_FATTIME(); + if (res == FR_OK) { /* Initialize the new directory table */ + res = dir_clear(fs, dcl); /* Clean up the new table */ + if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */ + dir = fs->win; + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + st_dword(dir + DIR_ModTime, tm); + st_clust(fs, dir, dcl); + mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ + dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + st_clust(fs, dir + SZDIRE, pcl); + fs->wflag = 1; + } + } + if (res == FR_OK) { + res = dir_register(&dj); /* Register the object to the directoy */ + } + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ + st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ + fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ + res = store_xdir(&dj); + } else +#endif + { + dir = dj.dir; + st_dword(dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dir, dcl); /* Table start cluster */ + dir[DIR_Attr] = AM_DIR; /* Attribute */ + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } else { + remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR* path_old, /* Pointer to the object name to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + FATFS *fs; + BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; + DWORD dw; + DEF_NAMBUF + + + get_ldnumber(&path_new); /* Snip the drive number of new name off */ + res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ + if (res == FR_OK) { + djo.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&djo, path_old); /* Check old object */ + if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ +#if FF_FS_LOCK != 0 + if (res == FR_OK) { + res = chk_lock(&djo, 2); + } +#endif + if (res == FR_OK) { /* Object to be renamed is found */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ + BYTE nf, nn; + WORD nh; + + mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + mem_cpy(&djn, &djo, sizeof djo); + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; + nh = ld_word(fs->dirbuf + XDIR_NameHash); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; + st_word(fs->dirbuf + XDIR_NameHash, nh); + if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ +/* Start of critical section where an interruption can cause a cross-link */ + res = store_xdir(&djn); + } + } + } else +#endif + { /* At FAT/FAT32 volume */ + mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ + mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + dir = djn.dir; /* Copy directory entry of the object except name */ + mem_cpy(dir + 13, buf + 13, SZDIRE - 13); + dir[DIR_Attr] = buf[DIR_Attr]; + if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ + fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ + dw = clst2sect(fs, ld_clust(fs, dir)); + if (dw == 0) { + res = FR_INT_ERR; + } else { +/* Start of critical section where an interruption can cause a cross-link */ + res = move_window(fs, dw); + dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(fs, dir, djn.obj.sclust); + fs->wflag = 1; + } + } + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { + res = sync_fs(fs); + } + } +/* End of the critical section */ + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_MINIMIZE == 0 */ +#endif /* FF_FS_MINIMIZE <= 1 */ +#endif /* FF_FS_MINIMIZE <= 2 */ + + + +#if FF_USE_CHMOD && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + const TCHAR* path, /* Pointer to the file path */ + BYTE attr, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = store_xdir(&dj); + } else +#endif + { + dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the timestamp to be set */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + res = store_xdir(&dj); + } else +#endif + { + st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* FF_USE_CHMOD && !FF_FS_READONLY */ + + + +#if FF_USE_LABEL +/*-----------------------------------------------------------------------*/ +/* Get Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getlabel ( + const TCHAR* path, /* Logical drive number */ + TCHAR* label, /* Buffer to store the volume label */ + DWORD* vsn /* Variable to store the volume serial number */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + UINT si, di; + WCHAR wc; + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + + /* Get volume label */ + if (res == FR_OK && label) { + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read_label(&dj); /* Find a volume label entry */ + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + WCHAR hs; + + for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + wc = ld_word(dj.dir + XDIR_Label + si * 2); + if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ + hs = wc; continue; + } + wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); + if (wc == 0) { di = 0; break; } + di += wc; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + label[di] = 0; + } else +#endif + { + si = di = 0; /* Extract volume label from AM_VOL entry */ + while (si < 11) { + wc = dj.dir[si++]; +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ + wc = ff_oem2uni(wc, CODEPAGE); + if (wc != 0) wc = put_utf(wc, &label[di], 4); + if (wc == 0) { di = 0; break; } + di += wc; +#else /* ANSI/OEM output */ + label[di++] = (TCHAR)wc; +#endif + } + do { /* Truncate trailing spaces */ + label[di] = 0; + if (di == 0) break; + } while (label[--di] == ' '); + } + } + } + if (res == FR_NO_FILE) { /* No label entry and return nul string */ + label[0] = 0; + res = FR_OK; + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(fs, fs->volbase); + if (res == FR_OK) { + switch (fs->fs_type) { + case FS_EXFAT: + di = BPB_VolIDEx; break; + + case FS_FAT32: + di = BS_VolID32; break; + + default: + di = BS_VolID; + } + *vsn = ld_dword(fs->win + di); + } + } + + LEAVE_FF(fs, res); +} + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Set Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setlabel ( + const TCHAR* label /* Volume label to set with heading logical drive number */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + BYTE dirvn[22]; + UINT di; + WCHAR wc; + static const char badchr[] = "+.,;=[]\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ +#if FF_USE_LFN + DWORD dc; +#endif + + /* Get logical drive */ + res = find_volume(&label, &fs, FA_WRITE); + if (res != FR_OK) LEAVE_FF(fs, res); + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + mem_set(dirvn, 0, 22); + di = 0; + while (*label) { /* Create volume label in directory form */ + dc = tchar2uni(&label); /* Get a Unicode character */ + if (dc >= 0x10000) { + if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ + dc = 0; + } else { + st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; + } + } + if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + st_word(dirvn + di * 2, (WCHAR)dc); di++; + } + } else +#endif + { /* On the FAT/FAT32 volume */ + mem_set(dirvn, ' ', 11); + di = 0; + while (*label) { /* Create volume label in directory form */ +#if FF_USE_LFN + dc = tchar2uni(&label); + wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; +#else /* ANSI/OEM input */ + wc = (BYTE)*label++; + if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; + if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ +#if FF_CODE_PAGE == 0 + if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ +#elif FF_CODE_PAGE < 900 + if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ +#endif +#endif + if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); + dirvn[di++] = (BYTE)wc; + } + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ + } + + /* Set volume label */ + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read_label(&dj); /* Get volume label entry */ + if (res == FR_OK) { + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, 22); + } else { + if (di != 0) { + mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ + } else { + dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ + } + } + fs->wflag = 1; + res = sync_fs(fs); + } else { /* No volume label entry or an error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (di != 0) { /* Create a volume label entry */ + res = dir_alloc(&dj, 1); /* Allocate an entry */ + if (res == FR_OK) { + mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_NumLabel] = (BYTE)di; + mem_cpy(dj.dir + XDIR_Label, dirvn, 22); + } else { + dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ + mem_cpy(dj.dir, dirvn, 11); + } + fs->wflag = 1; + res = sync_fs(fs); + } + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LABEL */ + + + +#if FF_USE_EXPAND && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Allocate a Contiguous Blocks to the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_expand ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t fsz, /* File size to be expanded to */ + BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, stcl, scl, ncl, tcl, lclst; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); +#if FF_FS_EXFAT + if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ +#endif + n = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; lclst = 0; + if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ + if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ + if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ + lclst = scl + tcl - 1; + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; + } + } + } else +#endif + { + scl = clst = stcl; ncl = 0; + for (;;) { /* Find a contiguous cluster block */ + n = get_fat(&fp->obj, clst); + if (++clst >= fs->n_fatent) clst = 2; + if (n == 1) { res = FR_INT_ERR; break; } + if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ + } else { + scl = clst; ncl = 0; /* Not a free cluster */ + } + if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + } + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); + if (res != FR_OK) break; + lclst = clst; + } + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; + } + } + } + + if (res == FR_OK) { + fs->last_clst = lclst; /* Set suggested start cluster to start next */ + if (opt) { /* Is it allocated now? */ + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* FF_USE_EXPAND && !FF_FS_READONLY */ + + + +#if FF_USE_FORWARD +/*-----------------------------------------------------------------------*/ +/* Forward Data to the Stream Directly */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_forward ( + FIL* fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btf, /* Number of bytes to forward */ + UINT* bf /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, csect; + BYTE *dbuf; + + + *bf = 0; /* Clear transfer byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + remain = fp->obj.objsize - fp->fptr; + if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ + fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + if (csect == 0) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->obj.sclust : get_fat(&fp->obj, fp->clust); + if (clst <= 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clst2sect(fs, fp->clust); /* Get current data sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); + sect += csect; +#if FF_FS_TINY + if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ + dbuf = fs->win; +#else + if (fp->sect != sect) { /* Fill sector cache with file data */ +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + dbuf = fp->buf; +#endif + fp->sect = sect; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ + rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ + if (rcnt == 0) ABORT(fs, FR_INT_ERR); + } + + LEAVE_FF(fs, FR_OK); +} +#endif /* FF_USE_FORWARD */ + + + +#if FF_USE_MKFS && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Create an FAT/exFAT volume */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkfs ( + const TCHAR* path, /* Logical drive number */ + BYTE opt, /* Format option */ + DWORD au, /* Size of allocation unit (cluster) [byte] */ + void* work, /* Pointer to working buffer (null: use heap memory) */ + UINT len /* Size of working buffer [byte] */ +) +{ + const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ + BYTE fmt, sys, *buf, *pte, pdrv, part; + WORD ss; /* Sector size */ + DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; + DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ + DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ + UINT i; + int vol; + DSTATUS stat; +#if FF_USE_TRIM || FF_FS_EXFAT + DWORD tbl[3]; +#endif + + + /* Check mounted drive and clear work area */ + vol = get_ldnumber(&path); /* Get target logical drive */ + if (vol < 0) return FR_INVALID_DRIVE; + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ + pdrv = LD2PD(vol); /* Physical drive */ + part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ + + /* Check physical drive status */ + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ +#if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; + if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = FF_MAX_SS; +#endif + if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ + au /= ss; /* Cluster size in unit of sector */ + + /* Get working buffer */ +#if FF_USE_LFN == 3 + if (!work) { /* Use heap memory for working buffer */ + for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && !(buf = ff_memalloc(szb_buf)); szb_buf /= 2) ; + sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ + } else +#endif + { + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + } + if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; + + /* Determine where the volume to be located (b_vol, sz_vol) */ + if (FF_MULTI_PARTITION && part != 0) { + /* Get partition information from partition table in the MBR */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ + pte = buf + (MBR_Table + (part - 1) * SZ_PTE); + if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ + } else { + /* Create a single-partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); + sz_vol -= b_vol; /* Volume size */ + } + if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ + + /* Pre-determine the FAT type */ + do { + if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ + fmt = FS_EXFAT; break; + } + } + if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ + if (opt & FM_FAT32) { /* FAT32 possible? */ + if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ + fmt = FS_FAT32; break; + } + } + if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ + fmt = FS_FAT16; + } while (0); + +#if FF_FS_EXFAT + if (fmt == FS_EXFAT) { /* Create an exFAT volume */ + DWORD szb_bit, szb_case, sum, nb, cl; + WCHAR ch, si; + UINT j, st; + BYTE b; + + if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ +#if FF_USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Determine FAT location, data location and number of clusters */ + if (au == 0) { /* au auto-selection */ + au = 8; + if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ + } + b_fat = b_vol + 32; /* FAT start at offset 32 */ + sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ + if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ + if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ + if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ + + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ + + /* Create a compressed up-case table */ + sect = b_data + au * tbl[0]; /* Table start sector */ + sum = 0; /* Table checksum to be stored in the 82 entry */ + st = si = i = j = szb_case = 0; + do { + switch (st) { + case 0: + ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ + if (ch != si) { + si++; break; /* Store the up-case char if exist */ + } + for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ + if (j >= 128) { + ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ + } + st = 1; /* Do not compress short run */ + /* go to next case */ + case 1: + ch = si++; /* Fill the short run */ + if (--j == 0) st = 0; + break; + + default: + ch = (WCHAR)j; si += j; /* Number of chars to skip */ + st = 0; + } + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); + i += 2; szb_case += 2; + if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + n = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; i = 0; + } + } while (si); + tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ + tbl[2] = 1; /* Number of root dir clusters */ + + /* Initialize the allocation bitmap */ + sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ + nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ + do { + mem_set(buf, 0, szb_buf); + for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the FAT */ + sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ + j = nb = cl = 0; + do { + mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ + if (cl == 0) { /* Set entry 0 and 1 */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; + } + do { /* Create chains of bitmap, up-case and root dir */ + while (nb != 0 && i < szb_buf) { /* Create a chain */ + st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); + i += 4; cl++; nb--; + } + if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb != 0 && i < szb_buf); + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the root directory */ + mem_set(buf, 0, szb_buf); + buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ + buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ + st_dword(buf + SZDIRE * 1 + 20, 2); + st_dword(buf + SZDIRE * 1 + 24, szb_bit); + buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ + st_dword(buf + SZDIRE * 2 + 4, sum); + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); + st_dword(buf + SZDIRE * 2 + 24, szb_case); + sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ + do { /* Fill root directory sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + + /* Create two set of the exFAT VBR blocks */ + sect = b_vol; + for (n = 0; n < 2; n++) { + /* Main record (+0) */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ + st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ + st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ + st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ + for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ + for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + buf[BPB_NumFATsEx] = 1; /* Number of FATs */ + buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ + st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + for (i = sum = 0; i < ss; i++) { /* VBR checksum */ + if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); + } + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + /* Extended bootstrap record (+1..+8) */ + mem_set(buf, 0, ss); + st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + for (j = 1; j < 9; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + } + /* OEM/Reserved record (+9..+10) */ + mem_set(buf, 0, ss); + for ( ; j < 11; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + } + /* Sum record (+11) */ + for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + } + + } else +#endif /* FF_FS_EXFAT */ + { /* Create an FAT/FAT32 volume */ + do { + pau = au; + /* Pre-determine number of clusters and FAT sub-type */ + if (fmt == FS_FAT32) { /* FAT32 volume */ + if (pau == 0) { /* au auto-selection */ + n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ + for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; /* Number of clusters */ + sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 32; /* Number of reserved sectors */ + sz_dir = 0; /* No static directory */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); + } else { /* FAT volume */ + if (pau == 0) { /* au auto-selection */ + n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ + for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; + if (n_clst > MAX_FAT12) { + n = n_clst * 2 + 4; /* FAT size [byte] */ + } else { + fmt = FS_FAT12; + n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ + } + sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 1; /* Number of reserved sectors */ + sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ + } + b_fat = b_vol + sz_rsv; /* FAT base */ + b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ + + /* Align data base to erase block boundary (for flash memory media) */ + n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ + if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ + sz_rsv += n; b_fat += n; + } else { /* FAT: Expand FAT size */ + sz_fat += n / n_fats; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ + n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; + if (fmt == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ + if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); + } + } + if (fmt == FS_FAT16) { + if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ + if (au == 0 && (pau * 2) <= 64) { + au = pau * 2; continue; /* Adjust cluster size and retry */ + } + if ((opt & FM_FAT32)) { + fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + } + if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); + } + if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ + if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); + } + } + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ + + /* Ok, it is the valid cluster configuration */ + break; + } while (1); + +#if FF_USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Create FAT VBR */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ + st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ + buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ + if (sz_vol < 0x10000) { + st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ + } else { + st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ + } + buf[BPB_Media] = 0xF8; /* Media descriptor byte */ + st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ + if (fmt == FS_FAT32) { + st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ + + /* Create FSINFO record if needed */ + if (fmt == FS_FAT32) { + disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ + mem_set(buf, 0, ss); + st_dword(buf + FSI_LeadSig, 0x41615252); + st_dword(buf + FSI_StrucSig, 0x61417272); + st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(buf + BS_55AA, 0xAA55); + disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ + disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ + } + + /* Initialize FAT area */ + mem_set(buf, 0, (UINT)szb_buf); + sect = b_fat; /* FAT start sector */ + for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ + if (fmt == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ + st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ + st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ + } else { + st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ + } + nsect = sz_fat; /* Number of FAT sectors */ + do { /* Fill FAT sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + } + + /* Initialize root directory (fill with zero) */ + nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + do { + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; nsect -= n; + } while (nsect); + } + + /* Determine system ID in the partition table */ + if (FF_FS_EXFAT && fmt == FS_EXFAT) { + sys = 0x07; /* HPFS/NTFS/exFAT */ + } else { + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (large) */ + } else { + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ + } + } + } + + /* Update partition information */ + if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ + /* Update system ID in the partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ + } else { /* Created as a new single partition */ + if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ + mem_set(buf, 0, ss); + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ + pte[PTE_Boot] = 0; /* Boot indicator */ + pte[PTE_StHead] = 1; /* Start head */ + pte[PTE_StSec] = 1; /* Start sector */ + pte[PTE_StCyl] = 0; /* Start cylinder */ + pte[PTE_System] = sys; /* System type */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ + pte[PTE_EdHead] = 254; /* End head */ + pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ + pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ + st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ + st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ + } + } + + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + + LEAVE_MKFS(FR_OK); +} + + + +#if FF_MULTI_PARTITION +/*-----------------------------------------------------------------------*/ +/* Create Partition Table on the Physical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_fdisk ( + BYTE pdrv, /* Physical drive number */ + const DWORD* szt, /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer (null: use heap memory) */ +) +{ + UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; + BYTE s_hd, e_hd, *p, *buf; = (BYTE*)work; + DSTATUS stat; + DWORD sz_disk, sz_part, s_part; + FRESULT res; + + + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; + + buf = (BYTE*)work; +#if FF_USE_LFN == 3 + if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ +#endif + if (!buf) return FR_NOT_ENOUGH_CORE; + + /* Determine the CHS without any consideration of the drive geometry */ + for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; + if (n == 256) n--; + e_hd = n - 1; + sz_cyl = 63 * n; + tot_cyl = sz_disk / sz_cyl; + + /* Create partition table */ + mem_set(buf, 0, FF_MAX_SS); + p = buf + MBR_Table; b_cyl = 0; + for (i = 0; i < 4; i++, p += SZ_PTE) { + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ + if (p_cyl == 0) continue; + s_part = (DWORD)sz_cyl * b_cyl; + sz_part = (DWORD)sz_cyl * p_cyl; + if (i == 0) { /* Exclude first track of cylinder 0 */ + s_hd = 1; + s_part += 63; sz_part -= 63; + } else { + s_hd = 0; + } + e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ + if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); + + /* Set partition table */ + p[1] = s_hd; /* Start head */ + p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ + p[3] = (BYTE)b_cyl; /* Start cylinder */ + p[4] = 0x07; /* System type (temporary setting) */ + p[5] = e_hd; /* End head */ + p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ + p[7] = (BYTE)e_cyl; /* End cylinder */ + st_dword(p + 8, s_part); /* Start sector in LBA */ + st_dword(p + 12, sz_part); /* Number of sectors */ + + /* Next partition */ + b_cyl += p_cyl; + } + st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ + + /* Write it to the MBR */ + res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; + LEAVE_MKFS(res); +} + +#endif /* FF_MULTI_PARTITION */ +#endif /* FF_USE_MKFS && !FF_FS_READONLY */ + + + + +#if FF_USE_STRFUNC +#if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) +#error Wrong FF_STRF_ENCODE setting +#endif +/*-----------------------------------------------------------------------*/ +/* Get a String from the File */ +/*-----------------------------------------------------------------------*/ + +TCHAR* f_gets ( + TCHAR* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer (items) */ + FIL* fp /* Pointer to the file object */ +) +{ + int nc = 0; + TCHAR *p = buff; + BYTE s[2]; + UINT rc; + WCHAR wc; +#if FF_USE_LFN && ((FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3) || (FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3)) + DWORD dc; +#endif +#if FF_USE_LFN && FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3 + UINT ct; +#endif + +#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 output */ +#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ + while (nc < len - 1) { + f_read(fp, s, 1, &rc); + if (rc != 1) break; + wc = s[0]; + if (dbc_1st((BYTE)wc)) { + f_read(fp, s, 1, &rc); + if (rc != 1 || !dbc_2nd(s[0])) continue; + wc = wc << 8 | s[0]; + } + wc = ff_oem2uni(wc, CODEPAGE); + if (wc == 0) continue; +#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ + while (nc < len - 1) { + f_read(fp, s, 2, &rc); + if (rc != 2) break; + wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; +#elif FF_STRF_ENCODE == 3 /* Read a character in UTF-8 */ + while (nc < len - 2) { + f_read(fp, s, 1, &rc); + if (rc != 1) break; + dc = s[0]; + if (dc >= 0x80) { + ct = 0; + if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } + if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } + if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } + if (ct == 0) continue; + do { + f_read(fp, s, 1, &rc); + if (rc != 1 || (s[0] & 0xC0) != 0x80) break; + dc = dc << 6 | (s[0] & 0x3F); + } while (--ct); + if (ct || dc < 0x80 || dc >= 0x110000) continue; + } + if (dc >= 0x10000) { + wc = (WCHAR)(0xD800 | ((dc >> 10) - 0x40)); + *p++ = wc; nc++; + wc = (WCHAR)(0xDC00 | (dc & 0x3FF)); + } else { + wc = (WCHAR)dc; + } +#endif + /* Output it in UTF-16 encoding */ + if (FF_USE_STRFUNC == 2 && wc == '\r') continue; + *p++ = wc; nc++; + if (wc == '\n') break; + } + +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 /* UTF-8 output */ + while (nc < len - 4) { +#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + wc = s[0]; + if (dbc_1st((BYTE)wc)) { + f_read(fp, s, 1, &rc); + if (rc != 1 || !dbc_2nd(s[0])) continue; + wc = wc << 8 | s[0]; + } + dc = ff_oem2uni(wc, CODEPAGE); + if (dc == 0) continue; +#else /* Read a character in UTF-16LE/BE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + dc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; + if (IsSurrogate(dc)) { + f_read(fp, s, 2, &rc); + if (rc != 2) break; + wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; + if (!IsSurrogateH(dc) || !IsSurrogateL(wc)) continue; + dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); + } +#endif + /* Output it in UTF-8 encoding */ + if (FF_USE_STRFUNC == 2 && dc == '\r') continue; + if (dc < 0x80) { /* 1-byte */ + *p++ = (TCHAR)dc; + nc++; + if (dc == '\n') break; + } else { + if (dc < 0x800) { /* 2-byte */ + *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 2; + } else { + if (dc < 0x10000) { /* 3-byte */ + *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 3; + } else { /* 4-byte */ + *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 4; + } + } + } + } + +#else /* Byte-by-byte without any conversion (ANSI/OEM API or UTF-8 to UTF-8) */ + while (nc < len - 1) { + f_read(fp, s, 1, &rc); + if (rc != 1) break; + wc = s[0]; + if (FF_USE_STRFUNC == 2 && wc == '\r') continue; + *p++ = (TCHAR)wc; nc++; + if (wc == '\n') break; + } +#endif + + *p = 0; + return nc ? buff : 0; /* When no data read (EOF or error), return with error. */ +} + + + + +#if !FF_FS_READONLY +#include +/*-----------------------------------------------------------------------*/ +/* Put a Character to the File */ +/*-----------------------------------------------------------------------*/ + +typedef struct { /* Putchar output buffer and work area */ + FIL *fp; /* Ptr to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ +#if FF_USE_LFN && FF_LFN_UNICODE == 1 + WCHAR hs; +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 + BYTE bs[4]; + UINT wi, ct; +#endif + BYTE buf[64]; /* Write buffer */ +} putbuff; + + +static +void putc_bfd ( /* Buffered write with code conversion */ + putbuff* pb, + TCHAR c +) +{ + UINT n; + int i, nc; +#if FF_USE_LFN && (FF_LFN_UNICODE == 1 || (FF_LFN_UNICODE == 2 && (FF_STRF_ENCODE != 3))) + WCHAR hs, wc; +#endif +#if FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 + DWORD dc; + TCHAR *tp; +#endif + + if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ + putc_bfd(pb, '\r'); + } + + i = pb->idx; /* Write index of pb->buf[] */ + if (i < 0) return; + nc = pb->nchr; /* Write unit count */ + +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 +#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 input */ + if (IsSurrogateH(c)) { + pb->hs = c; return; + } + wc = c; hs = pb->hs; pb->hs = 0; + if (hs != 0) { + if (!IsSurrogateL(wc)) hs = 0; + } else { + if (IsSurrogateL(wc)) return; + } +#if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ + if (hs != 0) { /* 4-byte */ + nc += 4; + hs = (hs & 0x3FF) + 0x40; + pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); + pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); + pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); + pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); + } else { + if (wc < 0x80) { /* 1-byte */ + nc++; + pb->buf[i++] = (BYTE)wc; + } else { + if (wc < 0x800) { /* 2-byte */ + nc += 2; + pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); + } else { /* 3-byte */ + nc += 3; + pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); + pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); + } + } +#endif +#else /* UTF-8 input */ + for (;;) { + if (pb->ct == 0) { /* Out of multi-byte sequence? */ + pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ + if ((BYTE)c < 0x80) break; /* 1-byte? */ + if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte? */ + if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ + if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ + return; + } else { /* In the multi-byte sequence */ + if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ + pb->ct = 0; continue; + } + pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ + if (--pb->ct == 0) break; /* End of sequence? */ + return; + } + } +#if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ + pb->buf[i++] = pb->bs[0]; nc++; + if (pb->bs[0] >= 0xC0) { + pb->buf[i++] = pb->bs[1]; nc++; + } + if (pb->bs[0] >= 0xE0) { + pb->buf[i++] = pb->bs[2]; nc++; + } + if (pb->bs[0] >= 0xF0) { + pb->buf[i++] = pb->bs[3]; nc++; + } +#else /* Write it in UTF-16 or ANSI/OEM */ + tp = (TCHAR*)pb->bs; + dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ + if (dc == 0xFFFFFFFF) return; + wc = (WCHAR)dc; + hs = (WCHAR)(dc >> 16); +#endif +#endif +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 && FF_STRF_ENCODE != 3 +#if FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ + if (hs != 0) { + pb->buf[i++] = (BYTE)(hs >> 8); + pb->buf[i++] = (BYTE)hs; + nc++; + } + pb->buf[i++] = (BYTE)(wc >> 8); + pb->buf[i++] = (BYTE)wc; + nc++; +#elif FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ + if (hs != 0) { + pb->buf[i++] = (BYTE)hs; + pb->buf[i++] = (BYTE)(hs >> 8); + nc++; + } + pb->buf[i++] = (BYTE)wc; + pb->buf[i++] = (BYTE)(wc >> 8); + nc++; +#else /* Write a character in ANSI/OEM */ + if (hs != 0) return; + wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ + if (wc == 0) return;; + if (wc >= 0x100) { + pb->buf[i++] = (BYTE)(wc >> 8); nc++; + } + pb->buf[i++] = (BYTE)wc; nc++; +#endif +#endif + +#else /* ANSI/OEM input */ + pb->buf[i++] = (BYTE)c; + nc++; +#endif + + if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ + f_write(pb->fp, pb->buf, (UINT)i, &n); + i = (n == (UINT)i) ? 0 : -1; + } + pb->idx = i; + pb->nchr = nc; +} + + +static +int putc_flush ( /* Flush left characters in the buffer */ + putbuff* pb +) +{ + UINT nw; + + if ( pb->idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK + && (UINT)pb->idx == nw) return pb->nchr; + return EOF; +} + + +static +void putc_init ( /* Initialize write buffer */ + putbuff* pb, + FIL* fp +) +{ + mem_set(pb, 0, sizeof (putbuff)); + pb->fp = fp; +} + + + +int f_putc ( + TCHAR c, /* A character to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + + + putc_init(&pb, fp); + putc_bfd(&pb, c); /* Put the character */ + return putc_flush(&pb); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a String to the File */ +/*-----------------------------------------------------------------------*/ + +int f_puts ( + const TCHAR* str, /* Pointer to the string to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + + + putc_init(&pb, fp); + while (*str) putc_bfd(&pb, *str++); /* Put the string */ + return putc_flush(&pb); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a Formatted String to the File */ +/*-----------------------------------------------------------------------*/ + +int f_printf ( + FIL* fp, /* Pointer to the file object */ + const TCHAR* fmt, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + putbuff pb; + BYTE f, r; + UINT i, j, w; + DWORD v; + TCHAR c, d, str[32], *p; + + + putc_init(&pb, fp); + + va_start(arp, fmt); + + for (;;) { + c = *fmt++; + if (c == 0) break; /* End of string */ + if (c != '%') { /* Non escape character */ + putc_bfd(&pb, c); + continue; + } + w = f = 0; + c = *fmt++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *fmt++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; c = *fmt++; + } + } + if (c == '*') { /* Minimum width by argument */ + w = va_arg(arp, int); + c = *fmt++; + } else { + while (IsDigit(c)) { /* Minimum width */ + w = w * 10 + c - '0'; + c = *fmt++; + } + } + if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ + f |= 4; c = *fmt++; + } + if (c == 0) break; + d = c; + if (IsLower(d)) d -= 0x20; + switch (d) { /* Atgument type is... */ + case 'S' : /* String */ + p = va_arg(arp, TCHAR*); + for (j = 0; p[j]; j++) ; + if (!(f & 2)) { /* Right padded */ + while (j++ < w) putc_bfd(&pb, ' ') ; + } + while (*p) putc_bfd(&pb, *p++) ; /* String body */ + while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ + continue; + + case 'C' : /* Character */ + putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + + case 'B' : /* Unsigned binary */ + r = 2; break; + + case 'O' : /* Unsigned octal */ + r = 8; break; + + case 'D' : /* Signed decimal */ + case 'U' : /* Unsigned decimal */ + r = 10; break; + + case 'X' : /* Unsigned hexdecimal */ + r = 16; break; + + default: /* Unknown type (pass-through) */ + putc_bfd(&pb, c); continue; + } + + /* Get an argument and put it in numeral */ + v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); + if (d == 'D' && (v & 0x80000000)) { + v = 0 - v; + f |= 8; + } + i = 0; + do { + d = (TCHAR)(v % r); v /= r; + if (d > 9) d += (c == 'x') ? 0x27 : 0x07; + str[i++] = d + '0'; + } while (v && i < sizeof str / sizeof *str); + if (f & 8) str[i++] = '-'; + j = i; d = (f & 1) ? '0' : ' '; + if (!(f & 2)) { + while (j++ < w) putc_bfd(&pb, d); /* Right pad */ + } + do { + putc_bfd(&pb, str[--i]); /* Number body */ + } while (i); + while (j++ < w) putc_bfd(&pb, d); /* Left pad */ + } + + va_end(arp); + + return putc_flush(&pb); +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_STRFUNC */ + + + +#if FF_CODE_PAGE == 0 +/*-----------------------------------------------------------------------*/ +/* Set Active Codepage for the Path Name */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setcp ( + WORD cp /* Value to be set as active code page */ +) +{ + static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; + static const BYTE *const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + UINT i; + + + for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + + CodePage = cp; + if (cp >= 900) { /* DBCS */ + ExCvt = 0; + DbcTbl = tables[i]; + } else { /* SBCS */ + ExCvt = tables[i]; + DbcTbl = 0; + } + return FR_OK; +} +#endif /* FF_CODE_PAGE == 0 */ + diff --git a/ipl/ff.h b/ipl/ff.h new file mode 100755 index 0000000..da57ca8 --- /dev/null +++ b/ipl/ff.h @@ -0,0 +1,366 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT Filesystem module R0.13a / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2017, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/ +/----------------------------------------------------------------------------*/ + + +#ifndef FF_DEFINED +#define FF_DEFINED 89352 /* Revision ID */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "integer.h" /* Basic integer types */ +#include "ffconf.h" /* FatFs configuration options */ + +#if FF_DEFINED != FFCONF_DEF +#error Wrong configuration file (ffconf.h). +#endif + + + +/* Definitions of volume management */ + +#if FF_MULTI_PARTITION /* Multiple partition configuration */ +typedef struct { + BYTE pd; /* Physical drive number */ + BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ +} PARTITION; +extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ +#endif + + + +/* Type of path name strings on FatFs API */ + +#ifndef _INC_TCHAR +#define _INC_TCHAR + +#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ +typedef WCHAR TCHAR; +#define _T(x) L ## x +#define _TEXT(x) L ## x +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ +typedef char TCHAR; +#define _T(x) u8 ## x +#define _TEXT(x) u8 ## x +#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2) +#error Wrong FF_LFN_UNICODE setting +#else /* ANSI/OEM code in SBCS/DBCS */ +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x +#endif + +#endif + + + +/* Type of file size variables */ + +#if FF_FS_EXFAT +typedef QWORD FSIZE_t; +#else +typedef DWORD FSIZE_t; +#endif + + + +/* Filesystem object structure (FATFS) */ + +typedef struct { + BYTE fs_type; /* Filesystem type (0:N/A) */ + BYTE pdrv; /* Physical drive number */ + BYTE n_fats; /* Number of FATs (1 or 2) */ + BYTE wflag; /* win[] flag (b0:dirty) */ + BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + WORD id; /* Volume mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ +#if FF_MAX_SS != FF_MIN_SS + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ +#endif +#if FF_USE_LFN + WCHAR* lfnbuf; /* LFN working buffer */ +#endif +#if FF_FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ +#endif +#if FF_FS_REENTRANT + FF_SYNC_t sobj; /* Identifier of sync object */ +#endif +#if !FF_FS_READONLY + DWORD last_clst; /* Last allocated cluster */ + DWORD free_clst; /* Number of free clusters */ +#endif +#if FF_FS_RPATH + DWORD cdir; /* Current directory start cluster (0:root) */ +#if FF_FS_EXFAT + DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ + DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ + DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ +#endif +#endif + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Size of an FAT [sectors] */ + DWORD volbase; /* Volume base sector */ + DWORD fatbase; /* FAT base sector */ + DWORD dirbase; /* Root directory base sector/cluster */ + DWORD database; /* Data base sector */ + DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ +} FATFS; + + + +/* Object ID and allocation information (FFOBJID) */ + +typedef struct { + FATFS* fs; /* Pointer to the hosting volume of this object */ + WORD id; /* Hosting volume mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if FF_FS_EXFAT + DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ +#endif +#if FF_FS_LOCK + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +} FFOBJID; + + + +/* File object structure (FIL) */ + +typedef struct { + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + BYTE flag; /* File status flags */ + BYTE err; /* Abort flag (error code) */ + FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ + DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ +#if !FF_FS_READONLY + DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ +#endif +#if FF_USE_FASTSEEK + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ +#endif +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ +#endif +} FIL; + + + +/* Directory object structure (DIR) */ + +typedef struct { + FFOBJID obj; /* Object identifier */ + DWORD dptr; /* Current read/write offset */ + DWORD clust; /* Current cluster */ + DWORD sect; /* Current sector (0:Read operation has terminated) */ + BYTE* dir; /* Pointer to the directory item in the win[] */ + BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ +#if FF_USE_LFN + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ +#endif +#if FF_USE_FIND + const TCHAR* pat; /* Pointer to the name matching pattern */ +#endif +} DIR; + + + +/* File information structure (FILINFO) */ + +typedef struct { + FSIZE_t fsize; /* File size */ + WORD fdate; /* Modified date */ + WORD ftime; /* Modified time */ + BYTE fattrib; /* File attribute */ +#if FF_USE_LFN + TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ +#else + TCHAR fname[12 + 1]; /* File name */ +#endif +} FILINFO; + + + +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* (0) Succeeded */ + FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ + FR_INT_ERR, /* (2) Assertion failed */ + FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NO_FILE, /* (4) Could not find the file */ + FR_NO_PATH, /* (5) Could not find the path */ + FR_INVALID_NAME, /* (6) The path name format is invalid */ + FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ + FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FR_NOT_ENABLED, /* (12) The volume has no work area */ + FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ + FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ + FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ +} FRESULT; + + + +/*--------------------------------------------------------------*/ +/* FatFs module application interface */ + +FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_close (FIL* fp); /* Close an open file object */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ +FRESULT f_truncate (FIL* fp); /* Truncate the file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ +FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir (DIR* dp); /* Close an open directory */ +FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ +FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ +FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ +FRESULT f_chdir (const TCHAR* path); /* Change current directory */ +FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ +FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ +FRESULT f_setcp (WORD cp); /* Set current code page */ +int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ +int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ +int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ +TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ + +#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) +#define f_error(fp) ((fp)->err) +#define f_tell(fp) ((fp)->fptr) +#define f_size(fp) ((fp)->obj.objsize) +#define f_rewind(fp) f_lseek((fp), 0) +#define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) +#define f_unmount(path) f_mount(0, path, 0) + +#ifndef EOF +#define EOF (-1) +#endif + + + + +/*--------------------------------------------------------------*/ +/* Additional user defined functions */ + +/* RTC function */ +#if !FF_FS_READONLY && !FF_FS_NORTC +DWORD get_fattime (void); +#endif + +/* LFN support functions */ +#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ +WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ +WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ +DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ +#endif +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif + +/* Sync functions */ +#if FF_FS_REENTRANT +int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ +#endif + + + + +/*--------------------------------------------------------------*/ +/* Flags and offset address */ + + +/* File access mode and open method flags (3rd argument of f_open) */ +#define FA_READ 0x01 +#define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA_OPEN_APPEND 0x30 + +/* Fast seek controls (2nd argument of f_lseek) */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) + +/* Format options (2nd argument of f_mkfs) */ +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 + +/* Filesystem type (FATFS.fs_type) */ +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 +#define FS_EXFAT 4 + +/* File attribute bits for directory entry (FILINFO.fattrib) */ +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ + + +#ifdef __cplusplus +} +#endif + +#endif /* FF_DEFINED */ diff --git a/ipl/ffconf.h b/ipl/ffconf.h new file mode 100755 index 0000000..047f73d --- /dev/null +++ b/ipl/ffconf.h @@ -0,0 +1,283 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - Configuration file +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 89352 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define FF_FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: Basic functions are fully enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define FF_USE_STRFUNC 2 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + + +#define FF_USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define FF_USE_MKFS 0 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define FF_USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define FF_USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ + + +#define FF_USE_LABEL 0 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define FF_USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define FF_CODE_PAGE 850 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect code page setting can cause a file open failure. +/ +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() +*/ + + +#define FF_USE_LFN 1 +#define FF_MAX_LFN 255 +/* The FF_USE_LFN switches the support for LFN (long file name). +/ +/ 0: Disable LFN. FF_MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN +/ specification. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree() in ffsystem.c, need to be added to the project. */ + + +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. +/ +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_STRF_ENCODE 0 +/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), +/ f_putc(), f_puts and f_printf() convert the character encoding in it. +/ This option selects assumption of character encoding ON THE FILE to be +/ read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + +#define FF_FS_RPATH 0 +/* This option configures support for relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define FF_VOLUMES 1 +/* Number of volumes (logical drives) to be used. (1-10) */ + + +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "sd" +/* FF_STR_VOLUME_ID switches string support for volume ID. +/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ + + +#define FF_MULTI_PARTITION 0 +/* This option switches support for multiple volumes on the physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When this function is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ + + +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ + + +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + +#define FF_FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ + + +#define FF_FS_EXFAT 0 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ When enable exFAT, also LFN needs to be enabled. +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ + + +#define FF_FS_NORTC 1 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2018 +/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#define FF_SYNC_t HANDLE +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this function. +/ +/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. +/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be +/ included somewhere in the scope of ff.h. */ + +/* #include // O/S definitions */ + + + +/*--- End of configuration options ---*/ diff --git a/ipl/ffunicode.c b/ipl/ffunicode.c new file mode 100755 index 0000000..e1f68a9 --- /dev/null +++ b/ipl/ffunicode.c @@ -0,0 +1,608 @@ +/*------------------------------------------------------------------------*/ +/* Unicode handling functions for FatFs R0.13a */ +/*------------------------------------------------------------------------*/ +/* This module will occupy a huge memory in the .const section when the / +/ FatFs is configured for LFN with DBCS. If the system has any Unicode / +/ utilitiy for the code conversion, this module should be modified to use / +/ that function to avoid silly memory consumption. / +/-------------------------------------------------------------------------*/ +/* +/ Copyright (C) 2017, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +*/ + + +#include "ff.h" + +#if FF_USE_LFN /* This module is blanked when non-LFN configuration */ + +#if FF_DEFINED != 89352 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + +#define MERGE2(a, b) a ## b +#define CVTBL(tbl, cp) MERGE2(tbl, cp) + + +/*------------------------------------------------------------------------*/ +/* Code Conversion Tables */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 +static +const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ + 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 +}; +#endif +#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 +static +const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 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, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 +static +const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 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, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 +static +const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 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, 0x0104, 0x0105, 0x010C, 0x010D, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 +static +const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 +static +const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ + 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, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 +static +const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 +static +const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 +static +const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 +static +const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, + 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 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 +}; +#endif +#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 +static +const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 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 +}; +#endif +#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 +static +const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 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 +}; +#endif +#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 +static +const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, + 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, + 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 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, 0x2219, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 +static +const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ + 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, + 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, + 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, + 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, + 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, + 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, + 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 +}; +#endif +#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 +static +const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 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 +}; +#endif +#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 +static +const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 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, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; +#endif +#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 +static +const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ + 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, + 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, + 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, + 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 +}; +#endif + + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for static code page configuration */ +/* SBCS fixed code page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + WCHAR c = 0; + const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it a valid code? */ + for (c = 0; c < 0x80 && uni != p[c]; c++) ; + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + WCHAR c = 0; + const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } + + return c; +} + +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for static code page configuration */ +/* DBCS fixed code page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE >= 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0, uc; + UINT i, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000) { /* Is it in BMP? */ + if (cp == FF_CODE_PAGE) { /* Is it a valid code? */ + uc = (WCHAR)uni; + p = CVTBL(uni2oem, FF_CODE_PAGE); + hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0; + UINT i, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ + p = CVTBL(oem2uni, FF_CODE_PAGE); + hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for dynamic code page configuration */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 0 + +static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; +static const WCHAR *const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; + + +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0, uc; + UINT i, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WCHAR)uni; + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ + p = cp_table[i]; + if (p) { /* Is it a valid CP ? */ + for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ + c = (c + 0x80) & 0xFF; + } + } else { /* DBCS */ + switch (cp) { + case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; + case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; + case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; + case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; + } + if (p) { /* Is it a valid code page? */ + li = 0; + for (n = 16; n; n--) { /* Find OEM code */ + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0; + UINT i, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ + p = cp_table[i]; + if (p) { /* Is it a valid CP ? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } else { /* DBCS */ + switch (cp) { + case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; + case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; + case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; + case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; + } + if (p) { + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* Unicode up-case conversion */ +/*------------------------------------------------------------------------*/ + +DWORD ff_wtoupper ( /* Returns up-converted code point */ + DWORD uni /* Unicode code point to be up-converted */ +) +{ + /* Compressed upper conversion table */ + static const WORD cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 + }; + static const WORD cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 + }; + const WORD *p; + WORD uc, bc, nc, cmd; + + + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WORD)uni; + p = uc < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || uc < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (uc < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: uc = p[uc - bc]; break; /* Table conversion */ + case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ + case 2: uc -= 16; break; /* Shift -16 */ + case 3: uc -= 32; break; /* Shift -32 */ + case 4: uc -= 48; break; /* Shift -48 */ + case 5: uc -= 26; break; /* Shift -26 */ + case 6: uc += 8; break; /* Shift +8 */ + case 7: uc -= 80; break; /* Shift -80 */ + case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; + } + uni = uc; + } + + return uni; +} + + +#endif /* #if FF_USE_LFN */ diff --git a/hwinit/fuse.c b/ipl/fuse.c old mode 100644 new mode 100755 similarity index 96% rename from hwinit/fuse.c rename to ipl/fuse.c index 7f4e60f..356eb89 --- a/hwinit/fuse.c +++ b/ipl/fuse.c @@ -1,28 +1,28 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "fuse.h" -#include "t210.h" - -void fuse_disable_program() -{ - FUSE(FUSE_DISABLEREGPROGRAM) = 1; -} - -u32 fuse_read_odm(u32 idx) -{ - return FUSE(FUSE_RESERVED_ODMX(idx)); -} +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "fuse.h" +#include "t210.h" + +void fuse_disable_program() +{ + FUSE(FUSE_DISABLEREGPROGRAM) = 1; +} + +u32 fuse_read_odm(u32 idx) +{ + return FUSE(FUSE_RESERVED_ODMX(idx)); +} diff --git a/hwinit/fuse.h b/ipl/fuse.h old mode 100644 new mode 100755 similarity index 96% rename from hwinit/fuse.h rename to ipl/fuse.h index bb9949b..2732eb4 --- a/hwinit/fuse.h +++ b/ipl/fuse.h @@ -1,44 +1,44 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _FUSE_H_ -#define _FUSE_H_ - -#include "types.h" - -/*! Fuse registers. */ -#define FUSE_CTRL 0x0 -#define FUSE_ADDR 0x4 -#define FUSE_RDATA 0x8 -#define FUSE_WDATA 0xC -#define FUSE_TIME_RD1 0x10 -#define FUSE_TIME_RD2 0x14 -#define FUSE_TIME_PGM1 0x18 -#define FUSE_TIME_PGM2 0x1C -#define FUSE_PRIV2INTFC 0x20 -#define FUSE_FUSEBYPASS 0x24 -#define FUSE_PRIVATEKEYDISABLE 0x28 -#define FUSE_DISABLEREGPROGRAM 0x2C -#define FUSE_WRITE_ACCESS_SW 0x30 -#define FUSE_PWR_GOOD_SW 0x34 - -/*! Fuse cache registers. */ -#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) - -void fuse_disable_program(); -u32 fuse_read_odm(u32 idx); - -#endif +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _FUSE_H_ +#define _FUSE_H_ + +#include "types.h" + +/*! Fuse registers. */ +#define FUSE_CTRL 0x0 +#define FUSE_ADDR 0x4 +#define FUSE_RDATA 0x8 +#define FUSE_WDATA 0xC +#define FUSE_TIME_RD1 0x10 +#define FUSE_TIME_RD2 0x14 +#define FUSE_TIME_PGM1 0x18 +#define FUSE_TIME_PGM2 0x1C +#define FUSE_PRIV2INTFC 0x20 +#define FUSE_FUSEBYPASS 0x24 +#define FUSE_PRIVATEKEYDISABLE 0x28 +#define FUSE_DISABLEREGPROGRAM 0x2C +#define FUSE_WRITE_ACCESS_SW 0x30 +#define FUSE_PWR_GOOD_SW 0x34 + +/*! Fuse cache registers. */ +#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) + +void fuse_disable_program(); +u32 fuse_read_odm(u32 idx); + +#endif diff --git a/ipl/gfx.c b/ipl/gfx.c new file mode 100755 index 0000000..4d7d0b2 --- /dev/null +++ b/ipl/gfx.c @@ -0,0 +1,308 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "gfx.h" + +static const u8 _gfx_font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, 0x10, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, +}; + +void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride) +{ + ctxt->fb = fb; + ctxt->width = width; + ctxt->height = height; + ctxt->stride = stride; +} + +void gfx_clear(gfx_ctxt_t *ctxt, u32 color) +{ + for (u32 i = 0; i < ctxt->height * ctxt->stride; i++) + ctxt->fb[i] = color; +} + +void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt) +{ + con->gfx_ctxt = ctxt; + con->x = 0; + con->y = 0; + con->fgcol = 0xFFFFFFFF; + con->fillbg = 0; + con->bgcol = 0xFF000000; +} + +void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol) +{ + con->fgcol = fgcol; + con->fillbg = fillbg; + con->bgcol = bgcol; +} + +void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y) +{ + *x = con->x; + *y = con->y; +} + +void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y) +{ + con->x = x; + con->y = y; +} + +void gfx_putc(gfx_con_t *con, char c) +{ + if (c >= 32 && c < 128) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride; + for (u32 i = 0; i < 8; i++) + { + u8 v = *cbuf++; + for (u32 j = 0; j < 8; j++) + { + if (v & 1) + *fb = con->fgcol; + else if (con->fillbg) + *fb = con->bgcol; + v >>= 1; + fb++; + } + fb += con->gfx_ctxt->stride - 8; + } + con->x += 8; + } + else if (c == '\n') + { + con->x = 0; + con->y += 8; + if (con->y > con->gfx_ctxt->height - 8) + con->y = 0; + } +} + +void gfx_puts(gfx_con_t *con, const char *s) +{ + if (!s) + return; + + for (; *s; s++) + gfx_putc(con, *s); +} + +static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt) +{ + char buf[65]; + static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; + char *p; + int c = fcnt; + + if (base > 36) + return; + + p = buf + 64; + *p = 0; + do + { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (fill != 0) + { + while (c > 0) + { + *--p = fill; + c--; + } + } + + gfx_puts(con, p); +} + +void gfx_printf(gfx_con_t *con, const char *fmt, ...) +{ + va_list ap; + int fill, fcnt; + + va_start(ap, fmt); + while(*fmt) + { + if(*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') + { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } + else + { + fill = ' '; + fcnt -= '0'; + } + } + switch(*fmt) + { + case 'c': + gfx_putc(con, va_arg(ap, u32)); + break; + case 's': + gfx_puts(con, va_arg(ap, char *)); + break; + case 'd': + _gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt); + break; + case 'x': + case 'X': + _gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt); + break; + case 'k': + con->fgcol = va_arg(ap, u32); + break; + case 'K': + con->bgcol = va_arg(ap, u32); + con->fillbg = fcnt; + break; + case '%': + gfx_putc(con, '%'); + break; + case '\0': + goto out; + default: + gfx_putc(con, '%'); + gfx_putc(con, *fmt); + break; + } + } + else + gfx_putc(con, *fmt); + fmt++; + } + + out: + va_end(ap); +} + +void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len) +{ + for(u32 i = 0; i < len; i++) + { + if(i % 0x10 == 0) + { + if(i != 0) + { + gfx_puts(con, "| "); + for(u32 j = 0; j < 0x10; j++) + { + u8 c = buf[i - 0x10 + j]; + if(c >= 32 && c < 128) + gfx_putc(con, c); + else + gfx_putc(con, '.'); + } + gfx_putc(con, '\n'); + } + gfx_printf(con, "%08x: ", base + i); + } + gfx_printf(con, "%02x ", buf[i]); + } + gfx_putc(con, '\n'); +} + +static int abs(int x) +{ + if (x < 0) + return -x; + return x; +} + +void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color) +{ + ctxt->fb[x + y * ctxt->stride] = color; +} + +void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color) +{ + int dx = abs(x1-x0), sx = x0 < x1 ? 1 : -1; + int dy = abs(y1-y0), sy = y0 < y1 ? 1 : -1; + int err = (dx > dy ? dx : -dy) / 2, e2; + + while (1) + { + gfx_set_pixel(ctxt, x0, y0, color); + if (x0 == x1 && y0 == y1) + break; + e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } +} diff --git a/ipl/gfx.h b/ipl/gfx.h new file mode 100755 index 0000000..bb14058 --- /dev/null +++ b/ipl/gfx.h @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _GFX_H_ +#define _GFX_H_ + +#include "types.h" + +typedef struct _gfx_ctxt_t +{ + u32 *fb; + u32 width; + u32 height; + u32 stride; +} gfx_ctxt_t; + +typedef struct _gfx_con_t +{ + gfx_ctxt_t *gfx_ctxt; + u32 x; + u32 y; + u32 fgcol; + int fillbg; + u32 bgcol; +} gfx_con_t; + +void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride); +void gfx_clear(gfx_ctxt_t *ctxt, u32 color); +void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt); +void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol); +void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y); +void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y); +void gfx_putc(gfx_con_t *con, char c); +void gfx_puts(gfx_con_t *con, const char *s); +void gfx_printf(gfx_con_t *con, const char *fmt, ...); +void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len); + +void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color); +void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color); + +#endif diff --git a/ipl/gpio.c b/ipl/gpio.c new file mode 100755 index 0000000..596af03 --- /dev/null +++ b/ipl/gpio.c @@ -0,0 +1,94 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "gpio.h" +#include "t210.h" + +static const u16 _gpio_cnf[31] = { + 0x000, 0x004, 0x008, 0x00C, + 0x100, 0x104, 0x108, 0x10C, + 0x200, 0x204, 0x208, 0x20C, + 0x300, 0x304, 0x308, 0x30C, + 0x400, 0x404, 0x408, 0x40C, + 0x500, 0x504, 0x508, 0x50C, + 0x600, 0x604, 0x608, 0x60C, + 0x700, 0x704, 0x708 +}; + +static const u16 _gpio_oe[31] = { + 0x010, 0x014, 0x018, 0x01C, + 0x110, 0x114, 0x118, 0x11C, + 0x210, 0x214, 0x218, 0x21C, + 0x310, 0x314, 0x318, 0x31C, + 0x410, 0x414, 0x418, 0x41C, + 0x510, 0x514, 0x518, 0x51C, + 0x610, 0x614, 0x618, 0x61C, + 0x710, 0x714, 0x718 +}; + +static const u16 _gpio_out[31] = { + 0x020, 0x024, 0x028, 0x02C, + 0x120, 0x124, 0x128, 0x12C, + 0x220, 0x224, 0x228, 0x22C, + 0x320, 0x324, 0x328, 0x32C, + 0x420, 0x424, 0x428, 0x42C, + 0x520, 0x524, 0x528, 0x52C, + 0x620, 0x624, 0x628, 0x62C, + 0x720, 0x724, 0x728 +}; + +static const u16 _gpio_in[31] = { + 0x030, 0x034, 0x038, 0x03C, + 0x130, 0x134, 0x138, 0x13C, + 0x230, 0x234, 0x238, 0x23C, + 0x330, 0x334, 0x338, 0x33C, + 0x430, 0x434, 0x438, 0x43C, + 0x530, 0x534, 0x538, 0x53C, + 0x630, 0x634, 0x638, 0x63C, + 0x730, 0x734, 0x738 +}; + +void gpio_config(u32 port, u32 pins, int mode) +{ + if (mode) + GPIO(_gpio_cnf[port]) |= pins; + else + GPIO(_gpio_cnf[port]) &= ~pins; + (void)GPIO(_gpio_cnf[port]); +} + +void gpio_output_enable(u32 port, u32 pins, int enable) +{ + if (enable) + GPIO(_gpio_oe[port]) |= pins; + else + GPIO(_gpio_oe[port]) &= ~pins; + (void)GPIO(_gpio_oe[port]); +} + +void gpio_write(u32 port, u32 pins, int high) +{ + if (high) + GPIO(_gpio_out[port]) |= pins; + else + GPIO(_gpio_out[port]) &= ~pins; + (void)GPIO(_gpio_out[port]); +} + +int gpio_read(u32 port, u32 pins) +{ + return GPIO(_gpio_in[port]) & pins ? 1 : 0; +} diff --git a/ipl/gpio.h b/ipl/gpio.h new file mode 100755 index 0000000..39e8c80 --- /dev/null +++ b/ipl/gpio.h @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include "types.h" + +#define GPIO_MODE_SPIO 0 +#define GPIO_MODE_GPIO 1 +#define GPIO_OUTPUT_DISABLE 0 +#define GPIO_OUTPUT_ENABLE 1 +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +/*! GPIO pins (0-7 for each port). */ +#define GPIO_PIN_0 (1 << 0) +#define GPIO_PIN_1 (1 << 1) +#define GPIO_PIN_2 (1 << 2) +#define GPIO_PIN_3 (1 << 3) +#define GPIO_PIN_4 (1 << 4) +#define GPIO_PIN_5 (1 << 5) +#define GPIO_PIN_6 (1 << 6) +#define GPIO_PIN_7 (1 << 7) + +/*! GPIO ports (A-EE). */ +#define GPIO_PORT_A 0 +#define GPIO_PORT_B 1 +#define GPIO_PORT_C 2 +#define GPIO_PORT_D 3 +#define GPIO_PORT_E 4 +#define GPIO_PORT_F 5 +#define GPIO_PORT_G 6 +#define GPIO_PORT_H 7 +#define GPIO_PORT_I 8 +#define GPIO_PORT_J 9 +#define GPIO_PORT_K 10 +#define GPIO_PORT_L 11 +#define GPIO_PORT_M 12 +#define GPIO_PORT_N 13 +#define GPIO_PORT_O 14 +#define GPIO_PORT_P 15 +#define GPIO_PORT_Q 16 +#define GPIO_PORT_R 17 +#define GPIO_PORT_S 18 +#define GPIO_PORT_T 19 +#define GPIO_PORT_U 20 +#define GPIO_PORT_V 21 +#define GPIO_PORT_W 22 +#define GPIO_PORT_X 23 +#define GPIO_PORT_Y 24 +#define GPIO_PORT_Z 25 +#define GPIO_PORT_AA 26 +#define GPIO_PORT_BB 27 +#define GPIO_PORT_CC 28 +#define GPIO_PORT_DD 29 +#define GPIO_PORT_EE 30 + +void gpio_config(u32 port, u32 pins, int mode); +void gpio_output_enable(u32 port, u32 pins, int enable); +void gpio_write(u32 port, u32 pins, int high); +int gpio_read(u32 port, u32 pins); + +#endif diff --git a/ipl/heap.c b/ipl/heap.c new file mode 100755 index 0000000..c90607b --- /dev/null +++ b/ipl/heap.c @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "heap.h" + +typedef struct _hnode +{ + int used; + u32 size; + struct _hnode *prev; + struct _hnode *next; +} hnode_t; + +typedef struct _heap +{ + u32 start; + hnode_t *first; +} heap_t; + +static void _heap_create(heap_t *heap, u32 start) +{ + heap->start = start; + heap->first = NULL; +} + +static u32 _heap_alloc(heap_t *heap, u32 size) +{ + hnode_t *node, *new; + int search = 1; + + size = ALIGN(size, 0x10); + + if (!heap->first) + { + node = (hnode_t *)heap->start; + node->used = 1; + node->size = size; + node->prev = NULL; + node->next = NULL; + heap->first = node; + + return (u32)node + sizeof(hnode_t); + } + + node = heap->first; + while (search) + { + if (!node->used && size + sizeof(hnode_t) < node->size) + { + new = (hnode_t *)((u32)node + sizeof(hnode_t) + size); + + new->size = node->size - sizeof(hnode_t) - size; + node->size = size; + node->used = 1; + new->used = 0; + new->next = node->next; + new->prev = node; + node->next = new; + + return (u32)node + sizeof(hnode_t); + } + if (node->next) + node = node->next; + else + search = 0; + } + + new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); + new->used = 1; + new->size = size; + new->prev = node; + new->next = NULL; + node->next = new; + + return (u32)new + sizeof(hnode_t); +} + +static void _heap_free(heap_t *heap, u32 addr) +{ + hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t)); + node->used = 0; + node = heap->first; + while (node) + { + if (!node->used) + if (node->prev && !node->prev->used) + { + node->prev->size += node->size + sizeof(hnode_t); + node->prev->next = node->next; + if (node->next) + node->next->prev = node->prev; + } + node = node->next; + } +} + +static heap_t _heap; + +void heap_init(u32 base) +{ + _heap_create(&_heap, base); +} + +void *malloc(u32 size) +{ + return (void *)_heap_alloc(&_heap, size); +} + +void *calloc(u32 num, u32 size) +{ + void *res = (void *)_heap_alloc(&_heap, num * size); + memset(res, 0, num * size); + return res; +} + +void free(void *buf) +{ + _heap_free(&_heap, (u32)buf); +} diff --git a/hwinit/hwinit.h b/ipl/heap.h old mode 100644 new mode 100755 similarity index 75% rename from hwinit/hwinit.h rename to ipl/heap.h index fa578b4..e1ab6fa --- a/hwinit/hwinit.h +++ b/ipl/heap.h @@ -1,25 +1,27 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _HWINIT_H_ -#define _HWINIT_H_ - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock); -void mc_enable_ahb_redirect(); -void mc_disable_ahb_redirect(); -void nx_hwinit(); - -#endif +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _HEAP_H_ +#define _HEAP_H_ + +#include "types.h" + +void heap_init(u32 base); +void *malloc(u32 size); +void *calloc(u32 num, u32 size); +void free(void *buf); + +#endif diff --git a/ipl/hos.c b/ipl/hos.c new file mode 100755 index 0000000..ce2965e --- /dev/null +++ b/ipl/hos.c @@ -0,0 +1,436 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "hos.h" +#include "sdmmc.h" +#include "nx_emmc.h" +#include "t210.h" +#include "se.h" +#include "se_t210.h" +#include "pmc.h" +#include "cluster.h" +#include "heap.h" +#include "tsec.h" +#include "pkg2.h" +#include "nx_emmc.h" +#include "util.h" +#include "pkg1.h" +#include "pkg2.h" +#include "ff.h" + +/*#include "gfx.h" +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; +#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/ +#define DPRINTF(...) + +#define NUM_KEYBLOB_KEYS 5 +static const u8 keyblob_keyseeds[NUM_KEYBLOB_KEYS][0x10] = { + { 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0 + { 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0 + { 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, //3.0.1 + { 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, //4.0.0 + { 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 } //5.0.0 +}; + +static const u8 cmac_keyseed[0x10] = + { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 }; + +static const u8 mkey_keyseed_retail[0x10] = + { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C }; + +static const u8 ckey_keyseed[0x10] = + { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; + +static const u8 key8_keyseed[] = + { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; + +static void _se_lock() +{ + for (u32 i = 0; i < 16; i++) + se_key_acc_ctrl(i, 0x15); + + for (u32 i = 0; i < 2; i++) + se_rsa_acc_ctrl(i, 1); + + SE(0x4) = 0; //Make this reg secure only. + SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; //Make all key access regs secure only. + SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; //Make all rsa access regs secure only. + SE(SE_SECURITY_0) &= 0xFFFFFFFB; //Make access lock regs secure only. + + //This is useful for documenting the bits in the SE config registers, so we can keep it around. + /*gfx_printf(&gfx_con, "SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0)); + gfx_printf(&gfx_con, "SE(0x4) = %08X\n", SE(0x4)); + gfx_printf(&gfx_con, "SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET)); + gfx_printf(&gfx_con, "SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET)); + for(u32 i = 0; i < 16; i++) + gfx_printf(&gfx_con, "%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF); + gfx_putc(&gfx_con, '\n'); + for(u32 i = 0; i < 2; i++) + gfx_printf(&gfx_con, "%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF); + gfx_putc(&gfx_con, '\n'); + gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/ +} + +//Key derivation for < 4.0.0 +static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw) +{ + u8 *tmp = (u8 *)malloc(0x10); + + se_key_acc_ctrl(12, 0x15); + se_key_acc_ctrl(13, 0x15); + + //Get TSEC key. + if (tsec_query(tmp, 1, tsec_fw) < 0) + return 0; + se_aes_key_set(13, tmp, 0x10); + + //Derive keyblob key from TSEC+SBK. + memcpy(tmp, keyblob_keyseeds[kb], 0x10); + se_aes_crypt_block_ecb(13, 0, tmp, tmp); + se_aes_unwrap_key(13, 14, tmp); + se_aes_key_clear(14); + + //TODO: verify keyblob CMAC. + //se_aes_unwrap_key(11, 13, cmac_keyseed); + //se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0); + //if (!memcmp(keyblob, tmp, 0x10)) + // return 0; + + //Decrypt keyblob and set keyslots. + se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); + se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); + se_aes_key_set(12, keyblob + 0x20, 0x10); + + //TODO: for some reason SE likes to hang if we don't execute an operation here. + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_crypt_block_ecb(12, 0, tmp, tmp); + + //Generate retail master key. + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_unwrap_key(12, 12, tmp); + + memcpy(tmp, key8_keyseed, 0x10); + se_key_acc_ctrl(8, 0x15); + se_aes_unwrap_key(8, 12, tmp); + + //Generate console specific key. + memcpy(tmp, ckey_keyseed, 0x10); + se_aes_unwrap_key(13, 13, tmp); + + se_key_acc_ctrl(12, 0xFF); + se_key_acc_ctrl(13, 0xFF); + + free(tmp); +} + +typedef struct _launch_ctxt_t +{ + void *keyblob; + + void *pkg1; + const pkg1_id_t *pkg1_id; + + void *warmboot; + u32 warmboot_size; + void *secmon; + u32 secmon_size; + + void *pkg2; + u32 pkg2_size; + + void *kernel; + u32 kernel_size; + link_t kip1_list; +} launch_ctxt_t; + +typedef struct _merge_kip_t +{ + void *kip1; + link_t link; +} merge_kip_t; + +static int _read_emmc_pkg1(launch_ctxt_t *ctxt) +{ + int res = 0; + sdmmc_storage_t storage; + sdmmc_t sdmmc; + + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + + //Read package1. + ctxt->pkg1 = (u8 *)malloc(0x40000); + sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1); + ctxt->pkg1_id = pkg1_identify(ctxt->pkg1); + if (!ctxt->pkg1_id) + { + DPRINTF("%kCould not identify package 1 version (= '%s').%k\n", 0xFF0000FF, (char *)ctxt->pkg1 + 0x10, 0xFFFFFFFF); + goto out; + } + DPRINTF("Identified package1 ('%s'), keyblob version %d\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb); + + //Read the correct keyblob. + ctxt->keyblob = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob); + + res = 1; + +out:; + sdmmc_storage_end(&storage); + return res; +} + +static int _read_emmc_pkg2(launch_ctxt_t *ctxt) +{ + int res = 0; + sdmmc_storage_t storage; + sdmmc_t sdmmc; + + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + sdmmc_storage_set_mmc_partition(&storage, 0); + + //Parse eMMC GPT. + LIST_INIT(gpt); + nx_emmc_gpt_parse(&gpt, &storage); +DPRINTF("parsed GPT\n"); + //Find package2 partition. + emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); + if (!pkg2_part) + goto out; + + //Read in package2 header and get package2 real size. + //TODO: implement memalign for DMA buffers. + u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); + u32 *hdr = (u32 *)(tmp + 0x100); + u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3]; + free(tmp); +DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size); + //Read in package2. + u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); +DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned); + ctxt->pkg2 = malloc(pkg2_size_aligned); + ctxt->pkg2_size = pkg2_size; + nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, + pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2); + + res = 1; + +out:; + nx_emmc_gpt_free(&gpt); + sdmmc_storage_end(&storage); + return res; +} + +static int _config_warmboot(launch_ctxt_t *ctxt, const char *value) +{ + FIL fp; + if (f_open(&fp, value, FA_READ) != FR_OK) + return 0; + ctxt->warmboot_size = f_size(&fp); + ctxt->warmboot = malloc(ctxt->warmboot_size); + f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL); + f_close(&fp); + return 1; +} + +static int _config_secmon(launch_ctxt_t *ctxt, const char *value) +{ + FIL fp; + if (f_open(&fp, value, FA_READ) != FR_OK) + return 0; + ctxt->secmon_size = f_size(&fp); + ctxt->secmon = malloc(ctxt->secmon_size); + f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL); + f_close(&fp); + return 1; +} + +static int _config_kernel(launch_ctxt_t *ctxt, const char *value) +{ + FIL fp; + if (f_open(&fp, value, FA_READ) != FR_OK) + return 0; + ctxt->kernel_size = f_size(&fp); + ctxt->kernel = malloc(ctxt->kernel_size); + f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL); + f_close(&fp); + return 1; +} + +static int _config_kip1(launch_ctxt_t *ctxt, const char *value) +{ + FIL fp; + if (f_open(&fp, value, FA_READ) != FR_OK) + return 0; + merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); + mkip1->kip1 = malloc(f_size(&fp)); + f_read(&fp, mkip1->kip1, f_size(&fp), NULL); +DPRINTF("loaded kip from SD (size %08X)\n", f_size(&fp)); + f_close(&fp); + list_append(&ctxt->kip1_list, &mkip1->link); + return 1; +} + +typedef struct _cfg_handler_t +{ + const char *key; + int (*handler)(launch_ctxt_t *ctxt, const char *value); +} cfg_handler_t; + +static const cfg_handler_t _config_handlers[] = { + { "warmboot", _config_warmboot }, + { "secmon", _config_secmon }, + { "kernel", _config_kernel }, + { "kip1", _config_kip1 }, + { NULL, NULL }, +}; + +static int _config(launch_ctxt_t *ctxt, ini_sec_t *cfg) +{ + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) + for(u32 i = 0; _config_handlers[i].key; i++) + if (!strcmp(_config_handlers[i].key, kv->key) && + !_config_handlers[i].handler(ctxt, kv->val)) + return 0; + return 1; +} + +int hos_launch(ini_sec_t *cfg) +{ + launch_ctxt_t ctxt; + memset(&ctxt, 0, sizeof(launch_ctxt_t)); + list_init(&ctxt.kip1_list); + + if (cfg && !_config(&ctxt, cfg)) + return 0; + + //Read package1 and the correct keyblob. + if (!_read_emmc_pkg1(&ctxt)) + return 0; + + //XXX: remove this once we support 3+. + if (ctxt.pkg1_id->kb > 0) + return 0; + +DPRINTF("loaded pkg1 and keyblob\n"); + //Generate keys. + _keygen_1(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off); +DPRINTF("generated keys\n"); + //Decrypt and unpack package1 if we require parts of it. + if (!ctxt.warmboot || !ctxt.secmon) + { + pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1); + pkg1_unpack((void *)0x8000D000, (void *)ctxt.pkg1_id->secmon_base, ctxt.pkg1_id, ctxt.pkg1); + //gfx_hexdump(&gfx_con, 0x8000D000, (void *)0x8000D000, 0x100); + //gfx_hexdump(&gfx_con, ctxt.pkg1_id->secmon_base, (void *)ctxt.pkg1_id->secmon_base, 0x100); +DPRINTF("decrypted and unpacked pkg1\n"); + } + //Replace 'warmboot.bin' if requested. + if (ctxt.warmboot) + memcpy((void *)0x8000D000, ctxt.warmboot, ctxt.warmboot_size); + //Set warmboot address in PMC. + PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000; + //Replace 'SecureMonitor' if requested. + if (ctxt.secmon) + memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); + else + { + //Else we patch it to allow for an unsigned package2. + patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; + for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) + *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; + } +DPRINTF("loaded warmboot.bin and secmon\n"); + + //Read package2. + if (!_read_emmc_pkg2(&ctxt)) + return 0; +DPRINTF("read pkg2\n"); + //Decrypt package2 and parse KIP1 blobs in INI1 section. + pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2); + + LIST_INIT(kip1_info); + pkg2_parse_kips(&kip1_info, pkg2_hdr); +DPRINTF("parsed ini1\n"); + //Use the kernel included in package2 in case we didn't load one already. + if (!ctxt.kernel) + { + ctxt.kernel = pkg2_hdr->data; + ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; + } + + //Merge extra KIP1s into loaded ones. + LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) + pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); + + //Rebuild and encrypt package2. + pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info); +DPRINTF("rebuilt pkg2\n"); + //Clear 'BootConfig'. + memset((void *)0x4003D000, 0, 0x3000); + + //pkg2_decrypt((void *)0xA9800000); + //sleep(10000); + //btn_wait(); + //return 0; + + //Lock SE before starting 'SecureMonitor'. + _se_lock(); + + vu32 *mb_in = (vu32 *)0x40002EF8; + vu32 *mb_out = (vu32 *)0x40002EFC; + + *mb_in = 0; + *mb_out = 0; + + //Wait for secmon to get ready. + cluster_boot_cpu0(ctxt.pkg1_id->secmon_base); + while (!*mb_out) + sleep(1); + + //Signal 'BootConfig'. + *mb_in = 1; + sleep(100); + + //Signal package2 available. + *mb_in = 2; + sleep(100); + + /*PMC(0x4) = 0x7FFFF3; + PMC(0x2C4) = 0xFFFFFFFF; + PMC(0x2D8) = 0xFFAFFFFF; + PMC(0x5B0) = 0xFFFFFFFF; + PMC(0x5B4) = 0xFFFFFFFF; + PMC(0x5B8) = 0xFFFFFFFF; + PMC(0x5BC) = 0xFFFFFFFF; + PMC(0x5C0) = 0xFFAAFFFF;*/ + + //TODO: Cleanup. + //display_end(); + + //Signal to continue boot. + *mb_in = 3; + sleep(100); + + //Halt ourselves in waitevent state. + while (1) + FLOW_CTLR(0x4) = 0x50000000; + + return 0; +} diff --git a/hwinit/types.h b/ipl/hos.h old mode 100644 new mode 100755 similarity index 80% rename from hwinit/types.h rename to ipl/hos.h index b650c52..a1c4f77 --- a/hwinit/types.h +++ b/ipl/hos.h @@ -14,12 +14,12 @@ * along with this program. If not, see . */ -#ifndef _TYPES_H_ -#define _TYPES_H_ +#ifndef _HOS_H_ +#define _HOS_H_ -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef volatile unsigned int vu32; +#include "types.h" +#include "ini.h" + +int hos_launch(ini_sec_t *cfg); #endif diff --git a/hwinit/i2c.c b/ipl/i2c.c old mode 100644 new mode 100755 similarity index 100% rename from hwinit/i2c.c rename to ipl/i2c.c diff --git a/hwinit/i2c.h b/ipl/i2c.h old mode 100644 new mode 100755 similarity index 100% rename from hwinit/i2c.h rename to ipl/i2c.h diff --git a/ipl/ini.c b/ipl/ini.c new file mode 100755 index 0000000..8551203 --- /dev/null +++ b/ipl/ini.c @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include + +#include "ini.h" +#include "ff.h" +#include "heap.h" + + +static char *_strdup(char *str) +{ + char *res = malloc(strlen(str) + 1); + strcpy(res, str); + return res; +} + +int ini_parse(link_t *dst, char *ini_path) +{ + u32 lblen; + char lbuf[512]; + FIL fp; + ini_sec_t *csec = NULL; + + if (f_open(&fp, ini_path, FA_READ) != FR_OK) + return 0; + + do + { + //Fetch one line. + lbuf[0] = 0; + f_gets(lbuf, 512, &fp); + lblen = strlen(lbuf); + + //Skip empty lines and comments. + if (lblen <= 1 || lbuf[0] == '#') + continue; + + //Remove trailing newline. + if (lbuf[lblen - 1] == '\n') + lbuf[lblen - 1] = 0; + + if (lblen > 2 && lbuf[0] == '[') //Create new section. + { + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } + + u32 i; + for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++) + ; + lbuf[i] = 0; + + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = _strdup(&lbuf[1]); + list_init(&csec->kvs); + } + else if (csec) //Extract key/value. + { + u32 i; + for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++) + ; + lbuf[i] = 0; + + ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); + kv->key = _strdup(&lbuf[0]); + kv->val = _strdup(&lbuf[i + 1]); + list_append(&csec->kvs, &kv->link); + } + } while (!f_eof(&fp)); + + f_close(&fp); + + if (csec) + list_append(dst, &csec->link); + + return 1; +} diff --git a/ipl/ini.h b/ipl/ini.h new file mode 100755 index 0000000..091009e --- /dev/null +++ b/ipl/ini.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _INI_H_ +#define _INI_H_ + +#include "types.h" +#include "list.h" + +typedef struct _ini_kv_t +{ + char *key; + char *val; + link_t link; +} ini_kv_t; + +typedef struct _ini_sec_t +{ + char *name; + link_t kvs; + link_t link; +} ini_sec_t; + +int ini_parse(link_t *dst, char *ini_path); + +#endif diff --git a/ipl/integer.h b/ipl/integer.h new file mode 100755 index 0000000..4fcf5c4 --- /dev/null +++ b/ipl/integer.h @@ -0,0 +1,38 @@ +/*-------------------------------------------*/ +/* Integer type definitions for FatFs module */ +/*-------------------------------------------*/ + +#ifndef FF_INTEGER +#define FF_INTEGER + +#ifdef _WIN32 /* FatFs development platform */ + +#include +#include +typedef unsigned __int64 QWORD; + + +#else /* Embedded platform */ + +/* These types MUST be 16-bit or 32-bit */ +typedef int INT; +typedef unsigned int UINT; + +/* This type MUST be 8-bit */ +typedef unsigned char BYTE; + +/* These types MUST be 16-bit */ +typedef short SHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; + +/* These types MUST be 32-bit */ +typedef long LONG; +typedef unsigned long DWORD; + +/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ +typedef unsigned long long QWORD; + +#endif + +#endif diff --git a/ipl/kfuse.c b/ipl/kfuse.c new file mode 100755 index 0000000..03d95bb --- /dev/null +++ b/ipl/kfuse.c @@ -0,0 +1,42 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "kfuse.h" +#include "clock.h" +#include "t210.h" + +int kfuse_read(u32 *buf) +{ + int res = 0; + + clock_enable_kfuse(); + + while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) + ; + + if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + goto out; + + KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC; + for (int i = 0; i < KFUSE_NUM_WORDS; i++) + buf[i] = KFUSE(KFUSE_KEYS); + + res = 1; + +out:; + clock_disable_kfuse(); + return res; +} diff --git a/ipl/kfuse.h b/ipl/kfuse.h new file mode 100755 index 0000000..4aa1b09 --- /dev/null +++ b/ipl/kfuse.h @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _KFUSE_H_ +#define _KFUSE_H_ + +#include "types.h" + +#define KFUSE_STATE_SOFTRESET (1<<31) +#define KFUSE_STATE_STOP (1<<25) +#define KFUSE_STATE_RESTART (1<<24) +#define KFUSE_STATE_CRCPASS (1<<17) +#define KFUSE_STATE_DONE (1<<16) +#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 +#define KFUSE_STATE_ERRBLOCK_SHIFT 8 +#define KFUSE_STATE_CURBLOCK_MASK 0x3F + +#define KFUSE_KEYADDR_AUTOINC (1<<16) + +#define KFUSE_STATE 0x80 +#define KFUSE_KEYADDR 0x88 +#define KFUSE_KEYS 0x8C + +#define KFUSE_NUM_WORDS 144 + +int kfuse_read(u32 *buf); + +#endif diff --git a/ipl/link.ld b/ipl/link.ld new file mode 100755 index 0000000..695cba7 --- /dev/null +++ b/ipl/link.ld @@ -0,0 +1,21 @@ +ENTRY(_start) + +SECTIONS { + PROVIDE(__ipl_start = 0x40003000); + . = __ipl_start; + .text : { + *(.text*); + } + .data : { + *(.data*); + *(.rodata*); + } + . = ALIGN(0x10); + __ipl_end = .; + .bss : { + __bss_start = .; + *(COMMON) + *(.bss*) + __bss_end = .; + } +} diff --git a/ipl/list.h b/ipl/list.h new file mode 100755 index 0000000..873cbf8 --- /dev/null +++ b/ipl/list.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _LIST_H_ +#define _LIST_H_ + +#include "types.h" + +/*! Initialize list. */ +#define LIST_INIT(name) link_t name = {&name, &name} + +/*! Initialize static list. */ +#define LIST_INIT_STATIC(name) static link_t name = {&name, &name} + +/*! Iterate over all list links. */ +#define LIST_FOREACH(iter, list) \ + for(link_t *iter = (list)->next; iter != (list); iter = iter->next) + +/*! Safely iterate over all list links. */ +#define LIST_FOREACH_SAFE(iter, list) \ + for(link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next) + +/*! Iterate over all list members. */ +#define LIST_FOREACH_ENTRY(etype, iter, list, mn) \ + for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) + +typedef struct _link_t +{ + struct _link_t *prev; + struct _link_t *next; +} link_t; + +static inline void link_init(link_t *l) +{ + l->prev = NULL; + l->next = NULL; +} + +static inline int link_used(link_t *l) +{ + if(l->next == NULL) + return 1; + return 0; +} + +static inline void list_init(link_t *lh) +{ + lh->prev = lh; + lh->next = lh; +} + +static inline void list_prepend(link_t *lh, link_t *l) +{ + l->next = lh->next; + l->prev = lh; + lh->next->prev = l; + lh->next = l; +} + +static inline void list_append(link_t *lh, link_t *l) +{ + l->prev = lh->prev; + l->next = lh; + lh->prev->next = l; + lh->prev = l; +} + +static inline void list_remove(link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; + link_init(l); +} + +static inline int list_empty(link_t *lh) +{ + if(lh->next == lh) + return 1; + return 0; +} + +#endif diff --git a/ipl/lz.c b/ipl/lz.c new file mode 100755 index 0000000..a17c6e4 --- /dev/null +++ b/ipl/lz.c @@ -0,0 +1,179 @@ +/************************************************************************* +* Name: lz.c +* Author: Marcus Geelnard +* Description: LZ77 coder/decoder implementation. +* Reentrant: Yes +* +* The LZ77 compression scheme is a substitutional compression scheme +* proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in +* its design, and uses no fancy bit level compression. +* +* This is my first attempt at an implementation of a LZ77 code/decoder. +* +* The principle of the LZ77 compression algorithm is to store repeated +* occurrences of strings as references to previous occurrences of the same +* string. The point is that the reference consumes less space than the +* string itself, provided that the string is long enough (in this +* implementation, the string has to be at least 4 bytes long, since the +* minimum coded reference is 3 bytes long). Also note that the term +* "string" refers to any kind of byte sequence (it does not have to be +* an ASCII string, for instance). +* +* The coder uses a brute force approach to finding string matches in the +* history buffer (or "sliding window", if you wish), which is very, very +* slow. I recon the complexity is somewhere between O(n^2) and O(n^3), +* depending on the input data. +* +* There is also a faster implementation that uses a large working buffer +* in which a "jump table" is stored, which is used to quickly find +* possible string matches (see the source code for LZ_CompressFast() for +* more information). The faster method is an order of magnitude faster, +* but still quite slow compared to other compression methods. +* +* The upside is that decompression is very fast, and the compression ratio +* is often very good. +* +* The reference to a string is coded as a (length,offset) pair, where the +* length indicates the length of the string, and the offset gives the +* offset from the current data position. To distinguish between string +* references and literal strings (uncompressed bytes), a string reference +* is preceded by a marker byte, which is chosen as the least common byte +* symbol in the input data stream (this marker byte is stored in the +* output stream as the first byte). +* +* Occurrences of the marker byte in the stream are encoded as the marker +* byte followed by a zero byte, which means that occurrences of the marker +* byte have to be coded with two bytes. +* +* The lengths and offsets are coded in a variable length fashion, allowing +* values of any magnitude (up to 4294967295 in this implementation). +* +* With this compression scheme, the worst case compression result is +* (257/256)*insize + 1. +* +*------------------------------------------------------------------------- +* Copyright (c) 2003-2006 Marcus Geelnard +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would +* be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not +* be misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source +* distribution. +* +* Marcus Geelnard +* marcus.geelnard at home.se +*************************************************************************/ + + +/************************************************************************* +* INTERNAL FUNCTIONS * +*************************************************************************/ + + +/************************************************************************* +* _LZ_ReadVarSize() - Read unsigned integer with variable number of +* bytes depending on value. +*************************************************************************/ + +static int _LZ_ReadVarSize( unsigned int * x, const unsigned char * buf ) +{ + unsigned int y, b, num_bytes; + + /* Read complete value (stop when byte contains zero in 8:th bit) */ + y = 0; + num_bytes = 0; + do + { + b = (unsigned int) (*buf ++); + y = (y << 7) | (b & 0x0000007f); + ++ num_bytes; + } + while( b & 0x00000080 ); + + /* Store value in x */ + *x = y; + + /* Return number of bytes read */ + return num_bytes; +} + + + +/************************************************************************* +* PUBLIC FUNCTIONS * +*************************************************************************/ + + +/************************************************************************* +* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder. +* in - Input (compressed) buffer. +* out - Output (uncompressed) buffer. This buffer must be large +* enough to hold the uncompressed data. +* insize - Number of input bytes. +*************************************************************************/ + +void LZ_Uncompress( const unsigned char *in, unsigned char *out, + unsigned int insize ) +{ + unsigned char marker, symbol; + unsigned int i, inpos, outpos, length, offset; + + /* Do we have anything to uncompress? */ + if( insize < 1 ) + { + return; + } + + /* Get marker symbol from input stream */ + marker = in[ 0 ]; + inpos = 1; + + /* Main decompression loop */ + outpos = 0; + do + { + symbol = in[ inpos ++ ]; + if( symbol == marker ) + { + /* We had a marker byte */ + if( in[ inpos ] == 0 ) + { + /* It was a single occurrence of the marker byte */ + out[ outpos ++ ] = marker; + ++ inpos; + } + else + { + /* Extract true length and offset */ + inpos += _LZ_ReadVarSize( &length, &in[ inpos ] ); + inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] ); + + /* Copy corresponding data from history window */ + for( i = 0; i < length; ++ i ) + { + out[ outpos ] = out[ outpos - offset ]; + ++ outpos; + } + } + } + else + { + /* No marker, plain copy */ + out[ outpos ++ ] = symbol; + } + } + while( inpos < insize ); +} diff --git a/ipl/lz.h b/ipl/lz.h new file mode 100755 index 0000000..6f31b4a --- /dev/null +++ b/ipl/lz.h @@ -0,0 +1,52 @@ +/************************************************************************* +* Name: lz.h +* Author: Marcus Geelnard +* Description: LZ77 coder/decoder interface. +* Reentrant: Yes +*------------------------------------------------------------------------- +* Copyright (c) 2003-2006 Marcus Geelnard +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would +* be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not +* be misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source +* distribution. +* +* Marcus Geelnard +* marcus.geelnard at home.se +*************************************************************************/ + +#ifndef _lz_h_ +#define _lz_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* +* Function prototypes +*************************************************************************/ + +void LZ_Uncompress( const unsigned char *in, unsigned char *out, + unsigned int insize ); + + +#ifdef __cplusplus +} +#endif + +#endif /* _lz_h_ */ diff --git a/ipl/main.c b/ipl/main.c new file mode 100755 index 0000000..abace60 --- /dev/null +++ b/ipl/main.c @@ -0,0 +1,624 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include + +#include "clock.h" +#include "uart.h" +#include "i2c.h" +#include "sdram.h" +#include "di.h" +#include "mc.h" +#include "t210.h" +#include "pmc.h" +#include "pinmux.h" +#include "fuse.h" +#include "util.h" +#include "gfx.h" +#include "btn.h" +#include "tsec.h" +#include "kfuse.h" +#include "max77620.h" +#include "max7762x.h" +#include "gpio.h" +#include "sdmmc.h" +#include "ff.h" +#include "tui.h" +#include "heap.h" +#include "list.h" +#include "nx_emmc.h" +#include "se.h" +#include "se_t210.h" +#include "hos.h" +#include "pkg1.h" + +void panic(u32 val) +{ + //Set panic code. + PMC(APBDEV_PMC_SCRATCH200) = val; + //PMC(APBDEV_PMC_CRYPTO_OP) = 1; //Disable SE. + TMR(0x18C) = 0xC45A; + TMR(0x80) = 0xC0000000; + TMR(0x180) = 0x8019; + TMR(0x188) = 1; + while (1) + ; +} + +void config_oscillators() +{ + CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3 | 4; + SYSCTR0(SYSCTR0_CNTFID0) = 19200000; + TMR(0x14) = 0x45F; + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; + PMC(APBDEV_PMC_OSC_EDPD_OVER) = PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81 | 0xE; + PMC(APBDEV_PMC_OSC_EDPD_OVER) = PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF | 0x400000; + PMC(APBDEV_PMC_CNTRL2) = PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF | 0x1000; + PMC(APBDEV_PMC_SCRATCH188) = PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF | 0x2000000; + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; + CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; + PMC(APBDEV_PMC_TSC_MULT) = PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000 | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; +} + +void config_gpios() +{ + PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; + PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = 0x40; + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = 0x40; + + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); + + pinmux_config_i2c(I2C_1); + pinmux_config_i2c(I2C_5); + pinmux_config_uart(UART_A); + + //Configure volume up/down as inputs. + gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); +} + +void config_pmc_scratch() +{ + PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; + PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; + PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10; +} + +void mbist_workaround() +{ + CLOCK(0x410) = (CLOCK(0x410) | 0x8000) & 0xFFFFBFFF; + CLOCK(0xD0) |= 0x40800000u; + CLOCK(0x2AC) = 0x40; + CLOCK(0x294) = 0x40000; + CLOCK(0x304) = 0x18000000; + sleep(2); + + I2S(0x0A0) |= 0x400; + I2S(0x088) &= 0xFFFFFFFE; + I2S(0x1A0) |= 0x400; + I2S(0x188) &= 0xFFFFFFFE; + I2S(0x2A0) |= 0x400; + I2S(0x288) &= 0xFFFFFFFE; + I2S(0x3A0) |= 0x400; + I2S(0x388) &= 0xFFFFFFFE; + I2S(0x4A0) |= 0x400; + I2S(0x488) &= 0xFFFFFFFE; + DISPLAY_A(0xCF8) |= 4; + VIC(0x8C) = 0xFFFFFFFF; + sleep(2); + + CLOCK(0x2A8) = 0x40; + CLOCK(0x300) = 0x18000000; + CLOCK(0x290) = 0x40000; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; + CLOCK(0xF8) = 0; + CLOCK(0xFC) = 0; + CLOCK(0x3A0) = 0; + CLOCK(0x3A4) = 0; + CLOCK(0x554) = 0; + CLOCK(0xD0) &= 0x1F7FFFFF; + CLOCK(0x410) &= 0xFFFF3FFF; + CLOCK(0x148) = CLOCK(0x148) & 0x1FFFFFFF | 0x80000000; + CLOCK(0x180) = CLOCK(0x180) & 0x1FFFFFFF | 0x80000000; + CLOCK(0x6A0) = CLOCK(0x6A0) & 0x1FFFFFFF | 0x80000000; +} + +void config_se_brom() +{ + //Bootrom part we skipped. + u32 sbk[4] = { FUSE(0x1A4), FUSE(0x1A8), FUSE(0x1AC), FUSE(0x1B0) }; + se_aes_key_set(14, sbk, 0x10); + //Lock SBK from being read. + SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E; + //This memset needs to happen here, else TZRAM will behave weirdly later on. + memset((void *)0x7C010000, 0, 0x10000); + PMC(APBDEV_PMC_CRYPTO_OP) = 0; + SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; + //Lock SSK (although it's not set and unused anyways). + SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; +} + +void config_hw() +{ + //Bootrom stuff we skipped by going thru rcm. + config_se_brom(); + //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; + SYSREG(0x110) &= 0xFFFFFF9F; + PMC(0x244) = ((PMC(0x244) >> 1) << 1) & 0xFFFFFFFD; + + mbist_workaround(); + clock_enable_se(); + + //Enable fuse clock. + clock_enable_fuse(1); + //Disable fuse programming. + fuse_disable_program(); + + mc_enable(); + + config_oscillators(); + APB_MISC(0x40) = 0; + config_gpios(); + + //clock_enable_uart(UART_C); + //uart_init(UART_C, 115200); + + clock_enable_cl_dvfs(); + + clock_enable_i2c(I2C_1); + clock_enable_i2c(I2C_5); + + static const clock_t clock_unk1 = { 0x358, 0x360, 0x42C, 0x1F, 0, 0 }; + static const clock_t clock_unk2 = { 0x358, 0x360, 0, 0x1E, 0, 0 }; + clock_enable(&clock_unk1); + clock_enable(&clock_unk2); + + i2c_init(I2C_1); + i2c_init(I2C_5); + + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_CNFGBBC, 0x40); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_ONOFFCNFG1, 0x78); + + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_CFG0, 0x38); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_CFG1, 0x3A); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_CFG2, 0x38); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_LDO4, 0xF); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_LDO8, 0xC7); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_SD0, 0x4F); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_SD1, 0x29); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_FPS_SD3, 0x1B); + + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD0, 42); //42 = (1125000 - 600000) / 12500 -> 1.125V + + config_pmc_scratch(); + + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888 | 0x3333; + + mc_config_carveout(); + + sdram_init(); + //TODO: test this with LP0 wakeup. + sdram_lp0_save_params(sdram_get_params()); +} + +//TODO: ugly. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + +void print_fuseinfo() +{ + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_setpos(&gfx_con, 0, 0); + + gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFFFF9955, 0xFFFFFFFF); + gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC); + + sleep(100000); + btn_wait(); +} + +void print_kfuseinfo() +{ + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_setpos(&gfx_con, 0, 0); + + gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFFFF9955, 0xFFFFFFFF); + u32 buf[KFUSE_NUM_WORDS]; + if (!kfuse_read(buf)) + gfx_printf(&gfx_con, "%kCRC fail.\n", 0xFF0000FF); + else + gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4); + + sleep(100000); + btn_wait(); +} + +void print_tsec_key() +{ + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_setpos(&gfx_con, 0, 0); + + sdmmc_storage_t storage; + sdmmc_t sdmmc; + + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + + //Read package1. + u8 *pkg1 = (u8 *)malloc(0x40000); + sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + if (!pkg1_id) + { + gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n", 0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF); + goto out; + } + + for(u32 i = 1; i <= 3; i++) + { + u8 key[0x10]; + int res = tsec_query(key, i, pkg1 + pkg1_id->tsec_off); + + gfx_printf(&gfx_con, "%kTSEC key %d: %k", 0xFFFF9955, i, 0xFFFFFFFF); + if (res >= 0) + { + for (u32 i = 0; i < 0x10; i++) + gfx_printf(&gfx_con, "%02X", key[i]); + } + else + gfx_printf(&gfx_con, "%kERROR %X", 0xFF0000FF, res); + gfx_putc(&gfx_con, '\n'); + } + +out:; + free(pkg1); + sdmmc_storage_end(&storage); + sleep(100000); + btn_wait(); +} + +void reboot_normal() +{ + panic(0x21); //Bypass fuse programming in package1. +} + +void reboot_rcm() +{ + PMC(APBDEV_PMC_SCRATCH0) = 2; //Reboot into rcm. + PMC(0) |= 0x10; + while (1) + sleep(1); +} + +void power_off() +{ + //TODO: we should probably make sure all regulators are powered off properly. + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); +} + +//TODO: ugly. +sdmmc_t sd_sdmmc; +sdmmc_storage_t sd_storage; +FATFS sd_fs; +int sd_mounted; + +int sd_mount() +{ + if (sd_mounted) + return 1; + + if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11) && + f_mount(&sd_fs, "", 1) == FR_OK) + { + sd_mounted = 1; + return 1; + } + + return 0; +} + +void *sd_file_read(char *path) +{ + FIL fp; + if (f_open(&fp, path, FA_READ) != FR_OK) + return NULL; + + u32 size = f_size(&fp); + void *buf = malloc(size); + + u8 *ptr = buf; + while (size > 0) + { + u32 rsize = MIN(size, 512); + if (f_read(&fp, ptr, rsize, NULL) != FR_OK) + { + free(buf); + return NULL; + } + + ptr += rsize; + size -= rsize; + } + + f_close(&fp); + + return buf; +} + +int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part) +{ + FIL fp; + if (f_open(&fp, sd_path, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) + return 0; + + u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * 512); + + u32 total = part->lba_end - part->lba_start + 1; + u32 lba_curr = part->lba_start; + while(total > 0) + { + u32 num = MIN(total, 512); + + if(!sdmmc_storage_read(storage, lba_curr, num, buf)) + { + gfx_printf(&gfx_con, "%kError reading %d blocks @ LBA %08X%k\n", + 0xFF0000FF, num, lba_curr, 0xFFFFFFFF); + goto out; + } + f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL); + u32 pct = ((lba_curr - part->lba_start) * 100) / (part->lba_end - part->lba_start); + tui_pbar(&gfx_con, 0, gfx_con.y, pct); + + lba_curr += num; + total -= num; + } + tui_pbar(&gfx_con, 0, gfx_con.y, 100); + +out:; + free(buf); + f_close(&fp); + return 1; +} + +void dump_emmc() +{ + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_setpos(&gfx_con, 0, 0); + + if (!sd_mount()) + { + gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF); + goto out; + } + + sdmmc_storage_t storage; + sdmmc_t sdmmc; + if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + { + gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF); + goto out; + } + sdmmc_storage_set_mmc_partition(&storage, 0); + + LIST_INIT(gpt); + nx_emmc_gpt_parse(&gpt, &storage); + int i = 0; + LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) + { + gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++, + part->name, part->lba_start, part->lba_end); + + //XXX: skip these for now. + if (//!strcmp(part->name, "SYSTEM") || + !strcmp(part->name, "USER")) + { + gfx_puts(&gfx_con, "Skipped.\n"); + continue; + } + + dump_emmc_part(part->name, &storage, part); + gfx_putc(&gfx_con, '\n'); + } + + sdmmc_storage_end(&storage); + +out:; + sleep(100000); + btn_wait(); +} + +void launch_firmware() +{ + ini_sec_t *cfg_sec = NULL; + LIST_INIT(ini_sections); + + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_setpos(&gfx_con, 0, 0); + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "hekate_ipl.ini")) + { + //Build configuration menu. + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 16); + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + u32 i = 1; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "config")) + continue; + ments[i].type = MENT_CHOICE; + ments[i].caption = ini_sec->name; + ments[i].data = ini_sec; + i++; + } + if (i > 1) + { + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = { + ments, "Launch configurations", 0, 0 + }; + cfg_sec = (ini_sec_t *)tui_do_menu(&gfx_con, &menu); + if (!cfg_sec) + return; + } + else + gfx_printf(&gfx_con, "%kNo launch configurations found.%k\n", 0xFF0000FF, 0xFFFFFFFF); + free(ments); + } + else + gfx_printf(&gfx_con, "%kFailed to load 'hekate_ipl.ini'.%k\n", 0xFF0000FF, 0xFFFFFFFF); + } + else + gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF); + + if (!cfg_sec) + gfx_printf(&gfx_con, "Using default launch configuration.\n"); + + if (!hos_launch(cfg_sec)) + gfx_printf(&gfx_con, "%kFailed to launch firmware.%k\n", 0xFF0000FF, 0xFFFFFFFF); + + //TODO: free ini. + +out:; + sleep(200000); + btn_wait(); +} + +void about() +{ + static const char octopus[] = + "hekate (c) 2018 naehrwert, st4rk\n\n" + "Thanks to: %kderrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8%k\n\n" + "Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute\n\n" + "Open source and free packages used:\n" + " - FatFs R0.13a (Copyright (C) 2017, ChaN)\n" + " - bcl-1.2.0 (Copyright (c) 2003-2006 Marcus Geelnard)\n\n" + " %k___\n" + " .-' `'.\n" + " / \\\n" + " | ;\n" + " | | ___.--,\n" + " _.._ |0) = (0) | _.---'`__.-( (_.\n" + " __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `\"\"`\n" + " ( ,.--'` ',__ /./; ;, '.__.'` __\n" + " _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n" + " `---' .'.''-._.-'`_./ /\\ '. \\ _.--''````'''--._`-.__.'\n" + " | | .' _.-' | | \\ \\ '. `----`\n" + " \\ \\/ .' \\ \\ '. '-._)\n" + " \\/ / \\ \\ `=.__`'-.\n" + " / /\\ `) ) / / `\"\".`\\\n" + " , _.-'.'\\ \\ / / ( ( / /\n" + " `--'` ) ) .-'.' '.'. | (\n" + " (/` ( (` ) ) '-; %k[switchbrew]%k\n" + " ` '-; (-'%k"; + + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_setpos(&gfx_con, 0, 0); + + gfx_printf(&gfx_con, octopus, 0xFFFFCC00, 0xFFFFFFFF, + 0xFFFFCC00, 0xFFCCFF00, 0xFFFFCC00, 0xFFFFFFFF); + + sleep(1000000); + btn_wait(); +} + +ment_t ment_cinfo[] = { + MDEF_BACK(), + MDEF_HANDLER("Print fuse info", print_fuseinfo), + MDEF_HANDLER("Print kfuse info", print_kfuseinfo), + MDEF_HANDLER("Print TSEC keys", print_tsec_key), + MDEF_END() +}; +menu_t menu_cinfo = { + ment_cinfo, + "Console info", 0, 0 +}; + +ment_t ment_tools[] = { + MDEF_BACK(), + MDEF_HANDLER("Dump eMMC", dump_emmc), + MDEF_END() +}; +menu_t menu_tools = { + ment_tools, + "Tools", 0, 0 +}; + +ment_t ment_top[] = { + MDEF_HANDLER("Launch firmware", launch_firmware), + MDEF_MENU("Tools", &menu_tools), + MDEF_MENU("Console info", &menu_cinfo), + MDEF_HANDLER("Reboot (normal)", reboot_normal), + MDEF_HANDLER("Reboot (rcm)", reboot_rcm), + MDEF_HANDLER("Power off", power_off), + MDEF_HANDLER("About", about), + MDEF_END() +}; +menu_t menu_top = { + ment_top, + "hekate - ipl", 0, 0 +}; + +extern void pivot_stack(u32 stack_top); + +void ipl_main() +{ + config_hw(); + + //Pivot the stack so we have enough space. + pivot_stack(0x90010000); + + //Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. + heap_init(0x90020000); + + //uart_send(UART_C, (u8 *)0x40000000, 0x10000); + //uart_wait_idle(UART_C, UART_TX_IDLE); + + display_init(); + //display_color_screen(0xAABBCCDD); + u32 *fb = display_init_framebuffer(); + gfx_init_ctxt(&gfx_ctxt, fb, 720, 1280, 768); + gfx_clear(&gfx_ctxt, 0xFF000000); + gfx_con_init(&gfx_con, &gfx_ctxt); + + while (1) + tui_do_menu(&gfx_con, &menu_top); + + while (1) + ; +} diff --git a/ipl/max77620.h b/ipl/max77620.h new file mode 100755 index 0000000..7223067 --- /dev/null +++ b/ipl/max77620.h @@ -0,0 +1,324 @@ +/* + * Defining registers address and its bit definitions of MAX77620 and MAX20024 + * + * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef _MFD_MAX77620_H_ +#define _MFD_MAX77620_H_ + +/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ +#define MAX77620_REG_CNFGGLBL1 0x00 +#define MAX77620_REG_CNFGGLBL2 0x01 +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_REG_CNFG1_32K 0x03 +#define MAX77620_REG_CNFGBBC 0x04 +#define MAX77620_REG_IRQTOP 0x05 +#define MAX77620_REG_INTLBT 0x06 +#define MAX77620_REG_IRQSD 0x07 +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 +#define MAX77620_REG_IRQ_LVL2_L8 0x09 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A +#define MAX77620_REG_ONOFFIRQ 0x0B +#define MAX77620_REG_NVERC 0x0C +#define MAX77620_REG_IRQTOPM 0x0D +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_REG_STATLBT 0x13 +#define MAX77620_REG_STATSD 0x14 +#define MAX77620_REG_ONOFFSTAT 0x15 + +/* SD and LDO Registers */ +#define MAX77620_REG_SD0 0x16 +#define MAX77620_REG_SD1 0x17 +#define MAX77620_REG_SD2 0x18 +#define MAX77620_REG_SD3 0x19 +#define MAX77620_REG_SD4 0x1A +#define MAX77620_REG_DVSSD0 0x1B +#define MAX77620_REG_DVSSD1 0x1C +#define MAX77620_REG_SD0_CFG 0x1D +#define MAX77620_REG_SD1_CFG 0x1E +#define MAX77620_REG_SD2_CFG 0x1F +#define MAX77620_REG_SD3_CFG 0x20 +#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_REG_LDO0_CFG 0x23 +#define MAX77620_REG_LDO0_CFG2 0x24 +#define MAX77620_REG_LDO1_CFG 0x25 +#define MAX77620_REG_LDO1_CFG2 0x26 +#define MAX77620_REG_LDO2_CFG 0x27 +#define MAX77620_REG_LDO2_CFG2 0x28 +#define MAX77620_REG_LDO3_CFG 0x29 +#define MAX77620_REG_LDO3_CFG2 0x2A +#define MAX77620_REG_LDO4_CFG 0x2B +#define MAX77620_REG_LDO4_CFG2 0x2C +#define MAX77620_REG_LDO5_CFG 0x2D +#define MAX77620_REG_LDO5_CFG2 0x2E +#define MAX77620_REG_LDO6_CFG 0x2F +#define MAX77620_REG_LDO6_CFG2 0x30 +#define MAX77620_REG_LDO7_CFG 0x31 +#define MAX77620_REG_LDO7_CFG2 0x32 +#define MAX77620_REG_LDO8_CFG 0x33 +#define MAX77620_REG_LDO8_CFG2 0x34 +#define MAX77620_REG_LDO_CFG3 0x35 + +#define MAX77620_LDO_SLEW_RATE_MASK 0x1 + +/* LDO Configuration 3 */ +#define MAX77620_TRACK4_MASK (1 << 5) +#define MAX77620_TRACK4_SHIFT 5 + +/* Voltage */ +#define MAX77620_SDX_VOLT_MASK 0xFF +#define MAX77620_SD0_VOLT_MASK 0x3F +#define MAX77620_SD1_VOLT_MASK 0x7F +#define MAX77620_LDO_VOLT_MASK 0x3F + +#define MAX77620_REG_GPIO0 0x36 +#define MAX77620_REG_GPIO1 0x37 +#define MAX77620_REG_GPIO2 0x38 +#define MAX77620_REG_GPIO3 0x39 +#define MAX77620_REG_GPIO4 0x3A +#define MAX77620_REG_GPIO5 0x3B +#define MAX77620_REG_GPIO6 0x3C +#define MAX77620_REG_GPIO7 0x3D +#define MAX77620_REG_PUE_GPIO 0x3E +#define MAX77620_REG_PDE_GPIO 0x3F +#define MAX77620_REG_AME_GPIO 0x40 +#define MAX77620_REG_ONOFFCNFG1 0x41 +#define MAX77620_REG_ONOFFCNFG2 0x42 + +/* FPS Registers */ +#define MAX77620_REG_FPS_CFG0 0x43 +#define MAX77620_REG_FPS_CFG1 0x44 +#define MAX77620_REG_FPS_CFG2 0x45 +#define MAX77620_REG_FPS_LDO0 0x46 +#define MAX77620_REG_FPS_LDO1 0x47 +#define MAX77620_REG_FPS_LDO2 0x48 +#define MAX77620_REG_FPS_LDO3 0x49 +#define MAX77620_REG_FPS_LDO4 0x4A +#define MAX77620_REG_FPS_LDO5 0x4B +#define MAX77620_REG_FPS_LDO6 0x4C +#define MAX77620_REG_FPS_LDO7 0x4D +#define MAX77620_REG_FPS_LDO8 0x4E +#define MAX77620_REG_FPS_SD0 0x4F +#define MAX77620_REG_FPS_SD1 0x50 +#define MAX77620_REG_FPS_SD2 0x51 +#define MAX77620_REG_FPS_SD3 0x52 +#define MAX77620_REG_FPS_SD4 0x53 +#define MAX77620_REG_FPS_NONE 0 + +#define MAX77620_FPS_SRC_MASK 0xC0 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 + +/* Minimum and maximum FPS period time (in microseconds) are + * different for MAX77620 and Max20024. + */ +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX20024_FPS_PERIOD_MIN_US 20 + +#define MAX77620_FPS_PERIOD_MAX_US 2560 +#define MAX20024_FPS_PERIOD_MAX_US 5120 + +#define MAX77620_REG_FPS_GPIO1 0x54 +#define MAX77620_REG_FPS_GPIO2 0x55 +#define MAX77620_REG_FPS_GPIO3 0x56 +#define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_REG_CID0 0x58 +#define MAX77620_REG_CID1 0x59 +#define MAX77620_REG_CID2 0x5A +#define MAX77620_REG_CID3 0x5B +#define MAX77620_REG_CID4 0x5C +#define MAX77620_REG_CID5 0x5D + +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 + +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 + +/* CNCG2SD */ +#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) + +/* Device Identification Metal */ +#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) +/* Device Indentification OTP */ +#define MAX77620_CID5_DIDO(n) ((n) & 0xF) + +/* SD CNFG1 */ +#define MAX77620_SD_SR_MASK 0xC0 +#define MAX77620_SD_SR_SHIFT 6 +#define MAX77620_SD_POWER_MODE_MASK 0x30 +#define MAX77620_SD_POWER_MODE_SHIFT 4 +#define MAX77620_SD_CFG1_ADE_MASK (1 << 3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) +#define MAX77620_SD_FPWM_MASK 0x04 +#define MAX77620_SD_FPWM_SHIFT 2 +#define MAX77620_SD_FSRADE_MASK 0x01 +#define MAX77620_SD_FSRADE_SHIFT 0 +#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) +#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) + +/* LDO_CNFG2 */ +#define MAX77620_LDO_POWER_MODE_MASK 0xC0 +#define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) +#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) +#define MAX77620_LDO_CFG2_ADE_DISABLE 0 +#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW 0 + +#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) +#define MAX77620_IRQ_TOP_SD_MASK (1 << 6) +#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) +#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) +#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) +#define MAX77620_IRQ_TOP_32K_MASK (1 << 2) +#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) + +#define MAX77620_IRQ_LBM_MASK (1 << 3) +#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) +#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) + +#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0 +#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0 +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0 +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) +#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) + +#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) + +#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) + +#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) +#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) +#define MAX20024_ONOFFCNFG1_CLRSE 0x18 + +#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) +#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) +#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) + +#define MAX77620_GLBLM_MASK (1 << 0) + +#define MAX77620_WDTC_MASK 0x3 +#define MAX77620_WDTOFFC (1 << 4) +#define MAX77620_WDTSLPC (1 << 3) +#define MAX77620_WDTEN (1 << 2) + +#define MAX77620_TWD_MASK 0x3 +#define MAX77620_TWD_2s 0x0 +#define MAX77620_TWD_16s 0x1 +#define MAX77620_TWD_64s 0x2 +#define MAX77620_TWD_128s 0x3 + +#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) +#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) +#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) +#define MAX77620_CNFGGLBL1_LBDAC 0x0E +#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) + +/* CNFG BBC registers */ +#define MAX77620_CNFGBBC_ENABLE (1 << 0) +#define MAX77620_CNFGBBC_CURRENT_MASK 0x06 +#define MAX77620_CNFGBBC_CURRENT_SHIFT 1 +#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 +#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 +#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) +#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 +#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 + +#define MAX77620_FPS_COUNT 3 + +/* Interrupts */ +enum { + MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ + MAX77620_IRQ_TOP_SD, /* SD power fail */ + MAX77620_IRQ_TOP_LDO, /* LDO power fail */ + MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ + MAX77620_IRQ_TOP_RTC, /* RTC */ + MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ + MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ + MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ +}; + +/* GPIOs */ +enum { + MAX77620_GPIO0, + MAX77620_GPIO1, + MAX77620_GPIO2, + MAX77620_GPIO3, + MAX77620_GPIO4, + MAX77620_GPIO5, + MAX77620_GPIO6, + MAX77620_GPIO7, + MAX77620_GPIO_NR, +}; + +/* FPS Source */ +enum max77620_fps_src { + MAX77620_FPS_SRC_0, + MAX77620_FPS_SRC_1, + MAX77620_FPS_SRC_2, + MAX77620_FPS_SRC_NONE, + MAX77620_FPS_SRC_DEF, +}; + +enum max77620_chip_id { + MAX77620, + MAX20024, +}; + +#endif /* _MFD_MAX77620_H_ */ diff --git a/ipl/max7762x.c b/ipl/max7762x.c new file mode 100755 index 0000000..5e8d923 --- /dev/null +++ b/ipl/max7762x.c @@ -0,0 +1,141 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "max7762x.h" +#include "max77620.h" +#include "i2c.h" +#include "util.h" + +#include "gfx.h" +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; +#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__) + +#define REGULATOR_SD 0 +#define REGULATOR_LDO 1 + +typedef struct _max77620_regulator_t +{ + u8 type; + const char *name; + u8 reg_sd; + u32 mv_step; + u32 mv_min; + u32 mv_default; + u32 mv_max; + u8 volt_addr; + u8 cfg_addr; + u8 volt_mask; + u8 enable_mask; + u8 enable_shift; + u8 status_mask; + + u8 fps_addr; + u8 fps_src; + u8 pd_period; + u8 pu_period; +} max77620_regulator_t; + +static const max77620_regulator_t _pmic_regulators[] = { + { REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, 0x3F, 0x30, 4, 0x80, 0x4F, 1, 7, 1 }, + { REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, 0x3F, 0x30, 4, 0x40, 0x50, 0, 1, 5 }, + { REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, 0xFF, 0x30, 4, 0x20, 0x51, 1, 5, 2 }, + { REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, 0xFF, 0x30, 4, 0x10, 0x52, 0, 3, 3 }, + { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, 0x3F, 0xC0, 6, 0x00, 0x46, 3, 7, 0 }, + { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, 0x3F, 0xC0, 6, 0x00, 0x47, 3, 7, 0 }, + { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, 0x3F, 0xC0, 6, 0x00, 0x48, 3, 7, 0 }, + { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, 0x3F, 0xC0, 6, 0x00, 0x49, 3, 7, 0 }, + { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4A, 0, 7, 1 }, + { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4B, 3, 7, 0 }, + { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4C, 3, 7, 0 }, + { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4D, 1, 4, 3 }, + { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4E, 3, 7, 0 } +}; + +int max77620_regulator_get_status(u32 id) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (reg->type == REGULATOR_SD) + return i2c_recv_byte(I2C_5, 0x3C, MAX77620_REG_STATSD) & reg->status_mask ? 0 : 1; + return i2c_recv_byte(I2C_5, 0x3C, reg->cfg_addr) & 8 ? 1 : 0; +} + +int max77620_regulator_config_fps(u32 id) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + i2c_send_byte(I2C_5, 0x3C, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period)); + + return 1; +} + +int max77620_regulator_set_voltage(u32 id, u32 mv) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (mv < reg->mv_default || mv > reg->mv_max) + return 0; + + u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; + u8 val = i2c_recv_byte(I2C_5, 0x3C, reg->volt_addr); + val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); + i2c_send_byte(I2C_5, 0x3C, reg->volt_addr, val); + sleep(1000); + + return 1; +} + +int max77620_regulator_enable(u32 id, int enable) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr; + u8 val = i2c_recv_byte(I2C_5, 0x3C, addr); + if (enable) + val = (val & ~reg->enable_mask) | ((3 << reg->enable_shift) & reg->enable_mask); + else + val &= ~reg->enable_mask; + i2c_send_byte(I2C_5, 0x3C, addr, val); + sleep(1000); + + return 1; +} + +void max77620_config_default() +{ + for (u32 i = 1; i <= REGULATOR_MAX; i++) + { + i2c_recv_byte(I2C_5, 0x3C, MAX77620_REG_CID4); + max77620_regulator_config_fps(i); + max77620_regulator_set_voltage(i, _pmic_regulators[i].mv_default); + if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) + max77620_regulator_enable(i, 1); + } + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD_CFG2, 4); +} diff --git a/ipl/max7762x.h b/ipl/max7762x.h new file mode 100755 index 0000000..0543495 --- /dev/null +++ b/ipl/max7762x.h @@ -0,0 +1,68 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _MAX7762X_H_ +#define _MAX7762X_H_ + +#include "types.h" + +/* +* Switch Power domains (max77620): +* Name | Usage | uV step | uV min | uV default | uV max | Init +*-------+---------------+---------+--------+------------+---------+------------------ +* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) +* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) +* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) +* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | +* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) +* ldo1 | XUSB | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) +* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | +* ldo3 | | 50000 | 800000 | 3100000 | 3100000 | +* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | +* ldo5 | | 50000 | 800000 | 1800000 | 1800000 | +* ldo6 | | 50000 | 800000 | 2900000 | 2900000 | +* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | +* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | +*/ + +/* +* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode +* MAX77620_REG_GPIOx: 0x9 sets output and enable +*/ + +/*! MAX77620 partitions. */ +#define REGULATOR_SD0 0 +#define REGULATOR_SD1 1 +#define REGULATOR_SD2 2 +#define REGULATOR_SD3 3 +#define REGULATOR_LDO0 4 +#define REGULATOR_LDO1 5 +#define REGULATOR_LDO2 6 +#define REGULATOR_LDO3 7 +#define REGULATOR_LDO4 8 +#define REGULATOR_LDO5 9 +#define REGULATOR_LDO6 10 +#define REGULATOR_LDO7 11 +#define REGULATOR_LDO8 12 +#define REGULATOR_MAX 12 + +int max77620_regulator_get_status(u32 id); +int max77620_regulator_config_fps(u32 id); +int max77620_regulator_set_voltage(u32 id, u32 mv); +int max77620_regulator_enable(u32 id, int enable); +void max77620_config_default(); + +#endif diff --git a/ipl/mc.c b/ipl/mc.c new file mode 100755 index 0000000..1c8cc2a --- /dev/null +++ b/ipl/mc.c @@ -0,0 +1,136 @@ +#include "mc.h" +#include "t210.h" +#include "clock.h" +#include "util.h" + +void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock) +{ + MC(MC_SEC_CARVEOUT_BOM) = bom; + MC(MC_SEC_CARVEOUT_SIZE_MB) = size1mb; + if (lock) + MC(MC_SEC_CARVEOUT_REG_CTRL) = 1; +} + +void mc_config_carveout() +{ + *(vu32 *)0x8005FFFC = 0xC0EDBBCC; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = 1; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0; + MC(MC_VIDEO_PROTECT_BOM) = 0; + MC(MC_VIDEO_PROTECT_SIZE_MB) = 0; + MC(MC_VIDEO_PROTECT_REG_CTRL) = 1; + + //Configure TSEC carveout @ 0x90000000, 1MB. + //mc_config_tsec_carveout(0x90000000, 1, 0); + mc_config_tsec_carveout(0, 0, 1); + + MC(MC_MTS_CARVEOUT_BOM) = 0; + MC(MC_MTS_CARVEOUT_SIZE_MB) = 0; + MC(MC_MTS_CARVEOUT_ADR_HI) = 0; + MC(MC_MTS_CARVEOUT_REG_CTRL) = 1; + MC(MC_SECURITY_CARVEOUT1_BOM) = 0; + MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006; + MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000; + MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3000000; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E; + MC(MC_SECURITY_CARVEOUT3_BOM) = 0; + MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0x3000000; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0x300; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E; + MC(MC_SECURITY_CARVEOUT4_BOM) = 0; + MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F; + MC(MC_SECURITY_CARVEOUT5_BOM) = 0; + MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F; +} + +void mc_enable_ahb_redirect() +{ + CLOCK(0x3A4) = CLOCK(0x3A4) & 0xFFF7FFFF | 0x80000; + //MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE; + MC(MC_IRAM_BOM) = 0x40000000; + MC(MC_IRAM_TOM) = 0x4003F000; +} + +void mc_disable_ahb_redirect() +{ + MC(MC_IRAM_BOM) = 0xFFFFF000; + MC(MC_IRAM_TOM) = 0; + //Disable IRAM_CFG_WRITE_ACCESS (sticky). + //MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1; + CLOCK(0x3A4) &= 0xFFF7FFFF; +} + +void mc_enable() +{ + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF | 0x40000000; + //Enable MIPI CAL clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF | 0x2000000; + //Enable MC clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE | 1; + //Enable EMC DLL clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF | 0x4000; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x2000001; //Clear EMC and MC reset. + sleep(5); + + //#ifdef CONFIG_ENABLE_AHB_REDIRECT + mc_disable_ahb_redirect(); + //mc_enable_ahb_redirect(); + //#endif +} diff --git a/ipl/mc.h b/ipl/mc.h new file mode 100755 index 0000000..536b5dc --- /dev/null +++ b/ipl/mc.h @@ -0,0 +1,13 @@ +#ifndef _MC_H_ +#define _MC_H_ + +#include "types.h" +#include "mc_t210.h" + +void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock); +void mc_config_carveout(); +void mc_enable_ahb_redirect(); +void mc_disable_ahb_redirect(); +void mc_enable(); + +#endif diff --git a/hwinit/mc.h b/ipl/mc_t210.h old mode 100644 new mode 100755 similarity index 99% rename from hwinit/mc.h rename to ipl/mc_t210.h index 7eebdf4..4f696a5 --- a/hwinit/mc.h +++ b/ipl/mc_t210.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _MC_H_ -#define _MC_ +#ifndef _MC_T210_H_ +#define _MC_T210_H_ #define MC_INTSTATUS 0x0 #define MC_INTMASK 0x4 diff --git a/ipl/mmc.h b/ipl/mmc.h new file mode 100755 index 0000000..ccf672e --- /dev/null +++ b/ipl/mmc.h @@ -0,0 +1,431 @@ +/* +* Header for MultiMediaCard (MMC) +* +* Copyright 2002 Hewlett-Packard Company +* +* Use consistent with the GNU GPL is permitted, +* provided that this copyright notice is +* preserved in its entirety in all copies and derived works. +* +* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, +* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS +* FITNESS FOR ANY PARTICULAR PURPOSE. +* +* Many thanks to Alessandro Rubini and Jonathan Corbet! +* +* Based strongly on code by: +* +* Author: Yong-iL Joh +* +* Author: Andrew Christian +* 15 May 2002 +*/ + +#ifndef LINUX_MMC_MMC_H +#define LINUX_MMC_MMC_H + +/* Standard MMC commands (4.1) type argument response */ +/* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_BUS_TEST_R 14 /* adtc R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_BUS_TEST_W 19 /* adtc R1 */ +#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ +#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ + +/* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ +#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ +#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ + +/* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + +/* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + +/* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + +/* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 38 /* ac R1b */ + +/* class 9 */ +#define MMC_FAST_IO 39 /* ac R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + +/* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + +/* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ + +/* class 11 */ +#define MMC_QUE_TASK_PARAMS 44 /* ac [20:16] task id R1 */ +#define MMC_QUE_TASK_ADDR 45 /* ac [31:0] data addr R1 */ +#define MMC_EXECUTE_READ_TASK 46 /* adtc [20:16] task id R1 */ +#define MMC_EXECUTE_WRITE_TASK 47 /* adtc [20:16] task id R1 */ +#define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */ + +/* +* MMC_SWITCH argument format: +* +* [31:26] Always 0 +* [25:24] Access Mode +* [23:16] Location of target Byte in EXT_CSD +* [15:08] Value Byte +* [07:03] Always 0 +* [02:00] Command Set +*/ + +/* +MMC status in R1, for native mode (SPI bits are different) +Type +e : error bit +s : status bit +r : detected and set for the actual command response +x : detected and set during command execution. the host must poll +the card by sending status command in order to read these bits. +Clear condition +a : according to the card state +b : always related to the previous command. Reception of +a valid command will clear it (with a delay of one command) +c : clear by read +*/ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_SWITCH_ERROR (1 << 7) /* sx, c */ +#define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ +#define R1_APP_CMD (1 << 5) /* sr, c */ + +#define R1_STATE_IDLE 0 +#define R1_STATE_READY 1 +#define R1_STATE_IDENT 2 +#define R1_STATE_STBY 3 +#define R1_STATE_TRAN 4 +#define R1_STATE_DATA 5 +#define R1_STATE_RCV 6 +#define R1_STATE_PRG 7 +#define R1_STATE_DIS 8 + +/* +* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS +* R1 is the low order byte; R2 is the next highest byte, when present. +*/ +#define R1_SPI_IDLE (1 << 0) +#define R1_SPI_ERASE_RESET (1 << 1) +#define R1_SPI_ILLEGAL_COMMAND (1 << 2) +#define R1_SPI_COM_CRC (1 << 3) +#define R1_SPI_ERASE_SEQ (1 << 4) +#define R1_SPI_ADDRESS (1 << 5) +#define R1_SPI_PARAMETER (1 << 6) +/* R1 bit 7 is always zero */ +#define R2_SPI_CARD_LOCKED (1 << 8) +#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ +#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP +#define R2_SPI_ERROR (1 << 10) +#define R2_SPI_CC_ERROR (1 << 11) +#define R2_SPI_CARD_ECC_ERROR (1 << 12) +#define R2_SPI_WP_VIOLATION (1 << 13) +#define R2_SPI_ERASE_PARAM (1 << 14) +#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ +#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE + +/* +* OCR bits are mostly in host.h +*/ +#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ + +/* +* Card Command Classes (CCC) +*/ +#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ +/* (CMD0,1,2,3,4,7,9,10,12,13,15) */ +/* (and for SPI, CMD58,59) */ +#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ +/* (CMD11) */ +#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ +/* (CMD16,17,18) */ +#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */ +/* (CMD20) */ +#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */ +/* (CMD16,24,25,26,27) */ +#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */ +/* (CMD32,33,34,35,36,37,38,39) */ +#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */ +/* (CMD28,29,30) */ +#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */ +/* (CMD16,CMD42) */ +#define CCC_APP_SPEC (1<<8) /* (8) Application specific */ +/* (CMD55,56,57,ACMD*) */ +#define CCC_IO_MODE (1<<9) /* (9) I/O mode */ +/* (CMD5,39,40,52,53) */ +#define CCC_SWITCH (1<<10) /* (10) High speed switch */ +/* (CMD6,34,35,36,37,50) */ +/* (11) Reserved */ +/* (CMD?) */ + +/* +* CSD field definitions +*/ + +#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ + +#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ +#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ +#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ + +/* +* EXT_CSD fields +*/ + +#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ +#define EXT_CSD_FLUSH_CACHE 32 /* W */ +#define EXT_CSD_CACHE_CTRL 33 /* R/W */ +#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */ +#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ +#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ +#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ +#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ +#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ +#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ +#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ +#define EXT_CSD_HPI_MGMT 161 /* R/W */ +#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ +#define EXT_CSD_BKOPS_EN 163 /* R/W */ +#define EXT_CSD_BKOPS_START 164 /* W */ +#define EXT_CSD_SANITIZE_START 165 /* W */ +#define EXT_CSD_WR_REL_PARAM 166 /* RO */ +#define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_FW_CONFIG 169 /* R/W */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ +#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ +#define EXT_CSD_PART_CONFIG 179 /* R/W */ +#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_STROBE_SUPPORT 184 /* RO */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ +#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ +#define EXT_CSD_REL_WR_SEC_C 222 /* RO */ +#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ +#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ +#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ +#define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ +#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ +#define EXT_CSD_TRIM_MULT 232 /* RO */ +#define EXT_CSD_PWR_CL_200_195 236 /* RO */ +#define EXT_CSD_PWR_CL_200_360 237 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ +#define EXT_CSD_BKOPS_STATUS 246 /* RO */ +#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ +#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ +#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */ +#define EXT_CSD_PRE_EOL_INFO 267 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ +#define EXT_CSD_CMDQ_DEPTH 307 /* RO */ +#define EXT_CSD_CMDQ_SUPPORT 308 /* RO */ +#define EXT_CSD_SUPPORTED_MODE 493 /* RO */ +#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ +#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ +#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ +#define EXT_CSD_MAX_PACKED_READS 501 /* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ +#define EXT_CSD_HPI_FEATURES 503 /* RO */ + +/* +* EXT_CSD field definitions +*/ + +#define EXT_CSD_WR_REL_PARAM_EN (1<<2) + +#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) +#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) +#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) +#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) + +#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) +#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) +#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3) +#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4) + +#define EXT_CSD_PART_SETTING_COMPLETED (0x1) +#define EXT_CSD_PART_SUPPORT_PART_EN (0x1) + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \ + EXT_CSD_CARD_TYPE_HS_52) +#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */ +/* DDR mode @1.8V or 3V I/O */ +#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */ +/* DDR mode @1.2V I/O */ +#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ + | EXT_CSD_CARD_TYPE_DDR_1_2V) +#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */ +#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */ +/* SDR mode @1.2V I/O */ +#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \ + EXT_CSD_CARD_TYPE_HS200_1_2V) +#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */ +#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */ +#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \ + EXT_CSD_CARD_TYPE_HS400_1_2V) +#define EXT_CSD_CARD_TYPE_HS400ES (1<<8) /* Card can run at HS400ES */ + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ +#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ +#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ +#define EXT_CSD_BUS_WIDTH_STROBE (1<<7) /* Enhanced strobe mode */ + +#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */ +#define EXT_CSD_TIMING_HS 1 /* High speed */ +#define EXT_CSD_TIMING_HS200 2 /* HS200 */ +#define EXT_CSD_TIMING_HS400 3 /* HS400 */ +#define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */ + +#define EXT_CSD_SEC_ER_EN (1<<0) +#define EXT_CSD_SEC_BD_BLK_EN (1<<2) +#define EXT_CSD_SEC_GB_CL_EN (1<<4) +#define EXT_CSD_SEC_SANITIZE (1<<6) /* v4.5 only */ + +#define EXT_CSD_RST_N_EN_MASK 0x3 +#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */ + +#define EXT_CSD_NO_POWER_NOTIFICATION 0 +#define EXT_CSD_POWER_ON 1 +#define EXT_CSD_POWER_OFF_SHORT 2 +#define EXT_CSD_POWER_OFF_LONG 3 + +#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */ +#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */ +#define EXT_CSD_PWR_CL_8BIT_SHIFT 4 +#define EXT_CSD_PWR_CL_4BIT_SHIFT 0 + +#define EXT_CSD_PACKED_EVENT_EN (1<<3) + +/* +* EXCEPTION_EVENT_STATUS field +*/ +#define EXT_CSD_URGENT_BKOPS (1<<0) +#define EXT_CSD_DYNCAP_NEEDED (1<<1) +#define EXT_CSD_SYSPOOL_EXHAUSTED (1<<2) +#define EXT_CSD_PACKED_FAILURE (1<<3) + +#define EXT_CSD_PACKED_GENERIC_ERROR (1<<0) +#define EXT_CSD_PACKED_INDEXED_ERROR (1<<1) + +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 + +/* +* BKOPS modes +*/ +#define EXT_CSD_MANUAL_BKOPS_MASK 0x01 +#define EXT_CSD_AUTO_BKOPS_MASK 0x02 + +/* +* Command Queue +*/ +#define EXT_CSD_CMDQ_MODE_ENABLED (1<<0) +#define EXT_CSD_CMDQ_DEPTH_MASK 0x1F +#define EXT_CSD_CMDQ_SUPPORTED (1<<0) + +/* +* MMC_SWITCH access modes +*/ +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ + +/* +* Erase/trim/discard +*/ +#define MMC_ERASE_ARG 0x00000000 +#define MMC_SECURE_ERASE_ARG 0x80000000 +#define MMC_TRIM_ARG 0x00000001 +#define MMC_DISCARD_ARG 0x00000003 +#define MMC_SECURE_TRIM1_ARG 0x80000001 +#define MMC_SECURE_TRIM2_ARG 0x80008000 +#define MMC_SECURE_ARGS 0x80000000 +#define MMC_TRIM_ARGS 0x00008001 + +#endif /* LINUX_MMC_MMC_H */ diff --git a/ipl/nx_emmc.c b/ipl/nx_emmc.c new file mode 100755 index 0000000..f1e837f --- /dev/null +++ b/ipl/nx_emmc.c @@ -0,0 +1,76 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "nx_emmc.h" +#include "heap.h" +#include "list.h" + +void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) +{ + u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE); + + sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); + + gpt_header_t *hdr = (gpt_header_t *)buf; + for (u32 i = 0; i < hdr->num_part_ents; i++) + { + gpt_entry_t *ent = (gpt_entry_t *)(buf + (hdr->part_ent_lba - 1) * NX_EMMC_BLOCKSIZE + i * sizeof(gpt_entry_t)); + emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t)); + part->lba_start = ent->lba_start; + part->lba_end = ent->lba_end; + part->attrs = ent->attrs; + + //HACK + for (u32 i = 0; i < 36; i++) + part->name[i] = ent->name[i]; + part->name[37] = 0; + + list_append(gpt, &part->link); + } + + free(buf); +} + +void nx_emmc_gpt_free(link_t *gpt) +{ + LIST_FOREACH_SAFE(iter, gpt) + free(CONTAINER_OF(iter, emmc_part_t, link)); +} + +emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name) +{ + LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link) + if (!strcmp(part->name, name)) + return part; + return NULL; +} + +int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) +{ + //The last LBA is inclusive. + if (part->lba_start + sector_off > part->lba_end) + return 0; + return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); +} + +int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) +{ + //The last LBA is inclusive. + if (part->lba_start + sector_off > part->lba_end) + return 0; + return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf); +} diff --git a/ipl/nx_emmc.h b/ipl/nx_emmc.h new file mode 100755 index 0000000..037a176 --- /dev/null +++ b/ipl/nx_emmc.h @@ -0,0 +1,72 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _NX_EMMC_H_ +#define _NX_EMMC_H_ + +#include "types.h" +#include "list.h" +#include "sdmmc.h" + +typedef struct _gpt_entry_t +{ + u8 type_guid[0x10]; + u8 part_guid[0x10]; + u64 lba_start; + u64 lba_end; + u64 attrs; + u16 name[36]; +} gpt_entry_t; + +typedef struct _gpt_header_t +{ + u64 signature; + u32 revision; + u32 size; + u32 crc32; + u32 res1; + u64 my_lba; + u64 alt_lba; + u64 first_use_lba; + u64 last_use_lba; + u8 disk_guid[0x10]; + u64 part_ent_lba; + u32 num_part_ents; + u32 part_ent_size; + u32 part_ents_crc32; + u8 res2[420]; +} gpt_header_t; + +#define NX_GPT_FIRST_LBA 1 +#define NX_GPT_NUM_BLOCKS 33 +#define NX_EMMC_BLOCKSIZE 512 + +typedef struct _emmc_part_t +{ + u32 lba_start; + u32 lba_end; + u64 attrs; + u8 name[37]; + link_t link; +} emmc_part_t; + +void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage); +void nx_emmc_gpt_free(link_t *gpt); +emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name); +int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); +int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); + +#endif diff --git a/hwinit/pinmux.c b/ipl/pinmux.c old mode 100644 new mode 100755 similarity index 96% rename from hwinit/pinmux.c rename to ipl/pinmux.c index 7315d3b..d0c03d8 --- a/hwinit/pinmux.c +++ b/ipl/pinmux.c @@ -1,32 +1,32 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "pinmux.h" -#include "t210.h" - -void pinmux_config_uart(u32 idx) -{ - PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = 0; - PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0x48; - PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0; - PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = 0x44; -} - -void pinmux_config_i2c(u32 idx) -{ - PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = 0x40; - PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = 0x40; -} +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "pinmux.h" +#include "t210.h" + +void pinmux_config_uart(u32 idx) +{ + PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = 0; + PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0x48; + PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0; + PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = 0x44; +} + +void pinmux_config_i2c(u32 idx) +{ + PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = 0x40; + PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = 0x40; +} diff --git a/hwinit/pinmux.h b/ipl/pinmux.h old mode 100644 new mode 100755 similarity index 64% rename from hwinit/pinmux.h rename to ipl/pinmux.h index ebe6520..14f0ec4 --- a/hwinit/pinmux.h +++ b/ipl/pinmux.h @@ -19,11 +19,31 @@ #include "types.h" +/*! APB MISC registers. */ +#define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4 +#define APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL 0x8D8 +#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 +#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74 + /*! Pinmux registers. */ +#define PINMUX_AUX_SDMMC1_CLK 0x00 +#define PINMUX_AUX_SDMMC1_CMD 0x04 +#define PINMUX_AUX_SDMMC1_DAT3 0x08 +#define PINMUX_AUX_SDMMC1_DAT2 0x0C +#define PINMUX_AUX_SDMMC1_DAT1 0x10 +#define PINMUX_AUX_SDMMC1_DAT0 0x14 +#define PINMUX_AUX_SDMMC3_CLK 0x1C +#define PINMUX_AUX_SDMMC3_CMD 0x20 +#define PINMUX_AUX_SDMMC3_DAT0 0x24 +#define PINMUX_AUX_SDMMC3_DAT1 0x28 +#define PINMUX_AUX_SDMMC3_DAT2 0x2C +#define PINMUX_AUX_SDMMC3_DAT3 0x30 +#define PINMUX_AUX_DMIC3_CLK 0xB4 #define PINMUX_AUX_UART2_TX 0xF4 #define PINMUX_AUX_UART3_TX 0x104 #define PINMUX_AUX_GPIO_PE6 0x248 #define PINMUX_AUX_GPIO_PH6 0x250 +#define PINMUX_AUX_GPIO_PZ1 0x280 /*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */ #define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x)) #define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x)) diff --git a/ipl/pkg1.c b/ipl/pkg1.c new file mode 100755 index 0000000..2125ae0 --- /dev/null +++ b/ipl/pkg1.c @@ -0,0 +1,108 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "pkg1.h" +#include "se.h" + +#define _ADRP(r, o) 0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F) +#define _MOVZX(r, i, s) 0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F) +#define _MOVKX(r, i, s) 0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F) +#define _BL(a, o) 0x94000000 | (((o) - (a)) >> 2) & 0x3FFFFFF +#define _NOP() 0xD503201F + +PATCHSET_DEF(_secmon_1_patchset, + //Patch the relocator to be able to run from 0x4002D000. + //{ 0x1E0, _ADRP(0, 0x7C013000 - 0x4002D000) } + //Patch package2 decryption and signature/hash checks. + { 0x9F0 + 0xADC, _NOP() }, //Header signature. + { 0x9F0 + 0xB8C, _NOP() }, //Version. + { 0x9F0 + 0xBB0, _NOP() } //Sections SHA2. +); + +PATCHSET_DEF(_secmon_2_patchset, + //Patch package2 decryption and signature/hash checks. + { 0xAC8 + 0xAAC, _NOP() }, //Header signature. + { 0xAC8 + 0xB3C, _NOP() }, //Version. + { 0xAC8 + 0xB58, _NOP() } //Sections SHA2. +); + +/* +* package1.1 header: +* package1.1 layout: +* 1.0: {sm, ldr, wb} { 2, 1, 0 } +* 2.0: {wb, ldr, sm} { 0, 1, 2 } +* 3.0: {wb, ldr, sm} { 0, 1, 2 } +* 3.1: {wb, ldr, sm} { 0, 1, 2 } +* 4.0: {ldr, sm, wb} { 1, 2, 0 } +* 5.0: {ldr, sm, wb} { 1, 2, 0 } +*/ + +static const pkg1_id_t _pkg1_ids[] = { + { "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, 0x40014020, _secmon_1_patchset }, //1.0.0 + { "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, _secmon_2_patchset }, //2.0.0 + { "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0 + { "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1 + { "20170921172629", 3, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0 + { "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0 + { NULL, 0, 0, 0, 0 } //End. +}; + +typedef struct _pk11_hdr_t +{ + u32 magic; + u32 wb_size; + u32 wb_off; + u32 pad; + u32 ldr_size; + u32 ldr_off; + u32 sm_size; + u32 sm_off; +} pk11_hdr_t; + +const pkg1_id_t *pkg1_identify(u8 *pkg1) +{ + for (u32 i = 0; _pkg1_ids[i].id; i++) + if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) + return &_pkg1_ids[i]; + return NULL; +} + +void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1) +{ + //Decrypt package1. + u8 *pkg11 = pkg1 + id->pkg11_off; + u32 pkg11_size = *(u32 *)pkg11; + se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10); +} + +void pkg1_unpack(void *warmboot_dst, void *secmon_dst, const pkg1_id_t *id, u8 *pkg1) +{ + pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20); + + u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size }; + //u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off }; + + u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t); + for (u32 i = 0; i < 3; i++) + { + if (id->sec_map[i] == 0 && warmboot_dst) + memcpy(warmboot_dst, pdata, sec_size[id->sec_map[i]]); + else if (id->sec_map[i] == 2 && secmon_dst) + memcpy(secmon_dst, pdata, sec_size[id->sec_map[i]]); + pdata += sec_size[id->sec_map[i]]; + } +} diff --git a/ipl/pkg1.h b/ipl/pkg1.h new file mode 100755 index 0000000..b94fec3 --- /dev/null +++ b/ipl/pkg1.h @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _PKG1_H_ +#define _PKG1_H_ + +#include "types.h" + +#define PATCHSET_DEF(name, ...) \ + patch_t name[] = { \ + __VA_ARGS__, \ + { 0xFFFFFFFF, 0xFFFFFFFF } \ + } + +typedef struct _patch_t +{ + u32 off; + u32 val; +} patch_t; + +typedef struct _pkg1_id_t +{ + const char *id; + u32 kb; + u32 tsec_off; + u32 pkg11_off; + u32 sec_map[3]; + u32 secmon_base; + patch_t *secmon_patchset; +} pkg1_id_t; + +const pkg1_id_t *pkg1_identify(u8 *pkg1); +void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); +void pkg1_unpack(void *warmboot_dst, void *secmon_dst, const pkg1_id_t *id, u8 *pkg1); + +#endif diff --git a/ipl/pkg2.c b/ipl/pkg2.c new file mode 100755 index 0000000..0cd6750 --- /dev/null +++ b/ipl/pkg2.c @@ -0,0 +1,174 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "pkg2.h" +#include "heap.h" +#include "se.h" + +/*#include "gfx.h" +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; +#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/ +#define DPRINTF(...) + +static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) +{ + u32 size = sizeof(pkg2_kip1_t); + for (u32 j = 0; j < KIP1_NUM_SECTIONS; j++) + size += kip1->sections[j].size_comp; + return size; +} + +void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2) +{ + u8 *ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL]; + pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr; + ptr += sizeof(pkg2_ini1_t); + + for (u32 i = 0; i < ini1->num_procs; i++) + { + pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr; + pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t)); + ki->kip1 = kip1; + ki->size = _pkg2_calc_kip1_size(kip1); + list_append(info, &ki->link); + ptr += ki->size; +DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size); + } +} + +int pkg2_has_kip(link_t *info, u64 tid) +{ + LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link) + if(ki->kip1->tid == tid) + return 1; + return 0; +} + +void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1) +{ + LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link) + if (ki->kip1->tid == tid) + { + ki->kip1 = kip1; + ki->size = _pkg2_calc_kip1_size(kip1); +DPRINTF("replaced kip (new size %08X)\n", ki->size); + return; + } +} + +void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1) +{ + pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t)); + ki->kip1 = kip1; + ki->size = _pkg2_calc_kip1_size(kip1); +DPRINTF("added kip (size %08X)\n", ki->size); + list_append(info, &ki->link); +} + +void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1) +{ + if (pkg2_has_kip(info, kip1->tid)) + pkg2_replace_kip(info, kip1->tid, kip1); + else + pkg2_add_kip(info, kip1); +} + +pkg2_hdr_t *pkg2_decrypt(void *data) +{ + u8 *pdata = (u8 *)data; + + //Skip signature. + pdata += 0x100; + + pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata; + + //Skip header. + pdata += sizeof(pkg2_hdr_t); + + //Decrypt header. + se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + //gfx_hexdump(&gfx_con, (u32)hdr, hdr, 0x100); + + if (hdr->magic != PKG2_MAGIC) + return NULL; + + for (u32 i = 0; i < 4; i++) + { +DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]); + if (!hdr->sec_size[i]) + continue; + + se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]); + //gfx_hexdump(&gfx_con, (u32)pdata, pdata, 0x100); + + pdata += hdr->sec_size[i]; + } + + return hdr; +} + +void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info) +{ + u8 *pdst = (u8 *)dst; + + //Signature. + memset(pdst, 0, 0x100); + pdst += 0x100; + + //Header. + pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdst; + memset(hdr, 0, sizeof(pkg2_hdr_t)); + pdst += sizeof(pkg2_hdr_t); + hdr->magic = PKG2_MAGIC; + hdr->base = 0x10000000; +DPRINTF("kernel @ %08X (%08X)\n", (u32)kernel, kernel_size); + + //Kernel. + memcpy(pdst, kernel, kernel_size); + hdr->sec_size[PKG2_SEC_KERNEL] = kernel_size; + hdr->sec_off[PKG2_SEC_KERNEL] = 0x10000000; + se_aes_crypt_ctr(8, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * 0x10]); + pdst += kernel_size; +DPRINTF("kernel encrypted\n"); + + //INI1. + u32 ini1_size = sizeof(pkg2_ini1_t); + pkg2_ini1_t *ini1 = (pkg2_ini1_t *)pdst; + memset(ini1, 0, sizeof(pkg2_ini1_t)); + ini1->magic = INI1_MAGIC; + pdst += sizeof(pkg2_ini1_t); + LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, kips_info, link) + { +DPRINTF("adding kip1 '%s' @ %08X (%08X)\n", ki->kip1->name, (u32)ki->kip1, ki->size); + memcpy(pdst, ki->kip1, ki->size); + pdst += ki->size; + ini1_size += ki->size; + ini1->num_procs++; + } + ini1->size = ini1_size; + hdr->sec_size[PKG2_SEC_INI1] = ini1_size; + hdr->sec_off[PKG2_SEC_INI1] = 0x14080000; + se_aes_crypt_ctr(8, ini1, ini1_size, ini1, ini1_size, &hdr->sec_ctr[PKG2_SEC_INI1 * 0x10]); +DPRINTF("INI1 encrypted\n"); + + //Encrypt header. + *(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size; + se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + memset(hdr->ctr, 0 , 0x10); + *(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size; +} diff --git a/ipl/pkg2.h b/ipl/pkg2.h new file mode 100755 index 0000000..b9a10db --- /dev/null +++ b/ipl/pkg2.h @@ -0,0 +1,94 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _PKG2_H_ +#define _PKG2_H_ + +#include "types.h" +#include "list.h" + +#define PKG2_MAGIC 0x31324B50 +#define PKG2_SEC_BASE 0x80000000 +#define PKG2_SEC_KERNEL 0 +#define PKG2_SEC_INI1 1 + +#define INI1_MAGIC 0x31494E49 + +typedef struct _pkg2_hdr_t +{ + u8 ctr[0x10]; + u8 sec_ctr[0x40]; + u32 magic; + u32 base; + u32 pad0; + u16 version; + u16 pad1; + u32 sec_size[4]; + u32 sec_off[4]; + u8 sec_sha256[0x80]; + u8 data[]; +} pkg2_hdr_t; + +typedef struct _pkg2_ini1_t +{ + u32 magic; + u32 size; + u32 num_procs; + u32 pad; +} pkg2_ini1_t; + +typedef struct _pkg2_kip1_sec_t +{ + u32 offset; + u32 size_decomp; + u32 size_comp; + u32 attrib; +} pkg2_kip1_sec_t; + +#define KIP1_NUM_SECTIONS 6 + +typedef struct _pkg2_kip1_t +{ + u32 magic; + u8 name[12]; + u64 tid; + u32 proc_cat; + u8 main_thrd_prio; + u8 def_cpu_core; + u8 res; + u8 flags; + pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS]; + u32 caps[0x20]; + u8 data[]; +} pkg2_kip1_t; + +typedef struct _pkg2_kip1_info_t +{ + pkg2_kip1_t *kip1; + u32 size; + link_t link; +} pkg2_kip1_info_t; + +void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2); +int pkg2_has_kip(link_t *info, u64 tid); +void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1); +void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1); +void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1); + +pkg2_hdr_t *pkg2_decrypt(void *data); +void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info); + +#endif diff --git a/hwinit/pmc.h b/ipl/pmc.h old mode 100644 new mode 100755 similarity index 93% rename from hwinit/pmc.h rename to ipl/pmc.h index 50ece38..520b74b --- a/hwinit/pmc.h +++ b/ipl/pmc.h @@ -21,7 +21,10 @@ #define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_STATUS 0x38 #define APBDEV_PMC_NO_IOPOWER 0x44 +#define APBDEV_PMC_SCRATCH0 0x50 +#define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH20 0xA0 +#define APBDEV_PMC_PWR_DET_VAL 0xE4 #define APBDEV_PMC_DDR_PWR 0xE8 #define APBDEV_PMC_CRYPTO_OP 0xF4 #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 diff --git a/ipl/pmc_t210_lp0.h b/ipl/pmc_t210_lp0.h new file mode 100755 index 0000000..95dd033 --- /dev/null +++ b/ipl/pmc_t210_lp0.h @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _TEGRA210_PMC_H_ +#define _TEGRA210_PMC_H_ + +#include "types.h" + +struct tegra_pmc_regs { + u32 cntrl; + u32 sec_disable; + u32 pmc_swrst; + u32 wake_mask; + u32 wake_lvl; + u32 wake_status; + u32 sw_wake_status; + u32 dpd_pads_oride; + u32 dpd_sample; + u32 dpd_enable; + u32 pwrgate_timer_off; + u32 clamp_status; + u32 pwrgate_toggle; + u32 remove_clamping_cmd; + u32 pwrgate_status; + u32 pwrgood_timer; + u32 blink_timer; + u32 no_iopower; + u32 pwr_det; + u32 pwr_det_latch; + u32 scratch0; + u32 scratch1; + u32 scratch2; + u32 scratch3; + u32 scratch4; + u32 scratch5; + u32 scratch6; + u32 scratch7; + u32 scratch8; + u32 scratch9; + u32 scratch10; + u32 scratch11; + u32 scratch12; + u32 scratch13; + u32 scratch14; + u32 scratch15; + u32 scratch16; + u32 scratch17; + u32 scratch18; + u32 scratch19; + u32 odmdata; + u32 scratch21; + u32 scratch22; + u32 scratch23; + u32 secure_scratch0; + u32 secure_scratch1; + u32 secure_scratch2; + u32 secure_scratch3; + u32 secure_scratch4; + u32 secure_scratch5; + u32 cpupwrgood_timer; + u32 cpupwroff_timer; + u32 pg_mask; + u32 pg_mask_1; + u32 auto_wake_lvl; + u32 auto_wake_lvl_mask; + u32 wake_delay; + u32 pwr_det_val; + u32 ddr_pwr; + u32 usb_debounce_del; + u32 usb_a0; + u32 crypto_op; + u32 pllp_wb0_override; + u32 scratch24; + u32 scratch25; + u32 scratch26; + u32 scratch27; + u32 scratch28; + u32 scratch29; + u32 scratch30; + u32 scratch31; + u32 scratch32; + u32 scratch33; + u32 scratch34; + u32 scratch35; + u32 scratch36; + u32 scratch37; + u32 scratch38; + u32 scratch39; + u32 scratch40; + u32 scratch41; + u32 scratch42; + u32 bondout_mirror[3]; + u32 sys_33v_en; + u32 bondout_mirror_access; + u32 gate; + u32 wake2_mask; + u32 wake2_lvl; + u32 wake2_status; + u32 sw_wake2_status; + u32 auto_wake2_lvl_mask; + u32 pg_mask_2; + u32 pg_mask_ce1; + u32 pg_mask_ce2; + u32 pg_mask_ce3; + u32 pwrgate_timer_ce[7]; + u32 pcx_edpd_cntrl; + u32 osc_edpd_over; + u32 clk_out_cntrl; + u32 sata_pwrgt; + u32 sensor_ctrl; + u32 rst_status; + u32 io_dpd_req; + u32 io_dpd_status; + u32 io_dpd2_req; + u32 io_dpd2_status; + u32 sel_dpd_tim; + u32 vddp_sel; + u32 ddr_cfg; + u32 e_no_vttgen; + u8 _rsv0[4]; + u32 pllm_wb0_override_freq; + u32 test_pwrgate; + u32 pwrgate_timer_mult; + u32 dis_sel_dpd; + u32 utmip_uhsic_triggers; + u32 utmip_uhsic_saved_state; + u32 utmip_pad_cfg; + u32 utmip_term_pad_cfg; + u32 utmip_uhsic_sleep_cfg; + u32 utmip_uhsic_sleepwalk_cfg; + u32 utmip_sleepwalk_p[3]; + u32 uhsic_sleepwalk_p0; + u32 utmip_uhsic_status; + u32 utmip_uhsic_fake; + u32 bondout_mirror3[5 - 3]; + u32 secure_scratch6; + u32 secure_scratch7; + u32 scratch43; + u32 scratch44; + u32 scratch45; + u32 scratch46; + u32 scratch47; + u32 scratch48; + u32 scratch49; + u32 scratch50; + u32 scratch51; + u32 scratch52; + u32 scratch53; + u32 scratch54; + u32 scratch55; + u32 scratch0_eco; + u32 por_dpd_ctrl; + u32 scratch2_eco; + u32 utmip_uhsic_line_wakeup; + u32 utmip_bias_master_cntrl; + u32 utmip_master_config; + u32 td_pwrgate_inter_part_timer; + u32 utmip_uhsic2_triggers; + u32 utmip_uhsic2_saved_state; + u32 utmip_uhsic2_sleep_cfg; + u32 utmip_uhsic2_sleepwalk_cfg; + u32 uhsic2_sleepwalk_p1; + u32 utmip_uhsic2_status; + u32 utmip_uhsic2_fake; + u32 utmip_uhsic2_line_wakeup; + u32 utmip_master2_config; + u32 utmip_uhsic_rpd_cfg; + u32 pg_mask_ce0; + u32 pg_mask3[5 - 3]; + u32 pllm_wb0_override2; + u32 tsc_mult; + u32 cpu_vsense_override; + u32 glb_amap_cfg; + u32 sticky_bits; + u32 sec_disable2; + u32 weak_bias; + u32 reg_short; + u32 pg_mask_andor; + u8 _rsv1[0x2c]; + u32 secure_scratch8; /* offset 0x300 */ + u32 secure_scratch9; + u32 secure_scratch10; + u32 secure_scratch11; + u32 secure_scratch12; + u32 secure_scratch13; + u32 secure_scratch14; + u32 secure_scratch15; + u32 secure_scratch16; + u32 secure_scratch17; + u32 secure_scratch18; + u32 secure_scratch19; + u32 secure_scratch20; + u32 secure_scratch21; + u32 secure_scratch22; + u32 secure_scratch23; + u32 secure_scratch24; + u32 secure_scratch25; + u32 secure_scratch26; + u32 secure_scratch27; + u32 secure_scratch28; + u32 secure_scratch29; + u32 secure_scratch30; + u32 secure_scratch31; + u32 secure_scratch32; + u32 secure_scratch33; + u32 secure_scratch34; + u32 secure_scratch35; + u32 secure_scratch36; + u32 secure_scratch37; + u32 secure_scratch38; + u32 secure_scratch39; + u32 secure_scratch40; + u32 secure_scratch41; + u32 secure_scratch42; + u32 secure_scratch43; + u32 secure_scratch44; + u32 secure_scratch45; + u32 secure_scratch46; + u32 secure_scratch47; + u32 secure_scratch48; + u32 secure_scratch49; + u32 secure_scratch50; + u32 secure_scratch51; + u32 secure_scratch52; + u32 secure_scratch53; + u32 secure_scratch54; + u32 secure_scratch55; + u32 secure_scratch56; + u32 secure_scratch57; + u32 secure_scratch58; + u32 secure_scratch59; + u32 secure_scratch60; + u32 secure_scratch61; + u32 secure_scratch62; + u32 secure_scratch63; + u32 secure_scratch64; + u32 secure_scratch65; + u32 secure_scratch66; + u32 secure_scratch67; + u32 secure_scratch68; + u32 secure_scratch69; + u32 secure_scratch70; + u32 secure_scratch71; + u32 secure_scratch72; + u32 secure_scratch73; + u32 secure_scratch74; + u32 secure_scratch75; + u32 secure_scratch76; + u32 secure_scratch77; + u32 secure_scratch78; + u32 secure_scratch79; + u32 _rsv0x420[8]; + u32 cntrl2; /* 0x440 */ + u32 _rsv0x444[2]; + u32 event_counter; /* 0x44C */ + u32 fuse_control; + u32 scratch1_eco; + u32 _rsv0x458[1]; + u32 io_dpd3_req; /* 0x45C */ + u32 io_dpd3_status; + u32 io_dpd4_req; + u32 io_dpd4_status; + u32 _rsv0x46C[30]; + u32 ddr_cntrl; /* 0x4E4 */ + u32 _rsv0x4E8[70]; + u32 scratch56; /* 0x600 */ + u32 scratch57; + u32 scratch58; + u32 scratch59; + u32 scratch60; + u32 scratch61; + u32 scratch62; + u32 scratch63; + u32 scratch64; + u32 scratch65; + u32 scratch66; + u32 scratch67; + u32 scratch68; + u32 scratch69; + u32 scratch70; + u32 scratch71; + u32 scratch72; + u32 scratch73; + u32 scratch74; + u32 scratch75; + u32 scratch76; + u32 scratch77; + u32 scratch78; + u32 scratch79; + u32 scratch80; + u32 scratch81; + u32 scratch82; + u32 scratch83; + u32 scratch84; + u32 scratch85; + u32 scratch86; + u32 scratch87; + u32 scratch88; + u32 scratch89; + u32 scratch90; + u32 scratch91; + u32 scratch92; + u32 scratch93; + u32 scratch94; + u32 scratch95; + u32 scratch96; + u32 scratch97; + u32 scratch98; + u32 scratch99; + u32 scratch100; + u32 scratch101; + u32 scratch102; + u32 scratch103; + u32 scratch104; + u32 scratch105; + u32 scratch106; + u32 scratch107; + u32 scratch108; + u32 scratch109; + u32 scratch110; + u32 scratch111; + u32 scratch112; + u32 scratch113; + u32 scratch114; + u32 scratch115; + u32 scratch116; + u32 scratch117; + u32 scratch118; + u32 scratch119; + u32 scratch120; /* 0x700 */ + u32 scratch121; + u32 scratch122; + u32 scratch123; + u32 scratch124; + u32 scratch125; + u32 scratch126; + u32 scratch127; + u32 scratch128; + u32 scratch129; + u32 scratch130; + u32 scratch131; + u32 scratch132; + u32 scratch133; + u32 scratch134; + u32 scratch135; + u32 scratch136; + u32 scratch137; + u32 scratch138; + u32 scratch139; + u32 scratch140; + u32 scratch141; + u32 scratch142; + u32 scratch143; + u32 scratch144; + u32 scratch145; + u32 scratch146; + u32 scratch147; + u32 scratch148; + u32 scratch149; + u32 scratch150; + u32 scratch151; + u32 scratch152; + u32 scratch153; + u32 scratch154; + u32 scratch155; + u32 scratch156; + u32 scratch157; + u32 scratch158; + u32 scratch159; + u32 scratch160; + u32 scratch161; + u32 scratch162; + u32 scratch163; + u32 scratch164; + u32 scratch165; + u32 scratch166; + u32 scratch167; + u32 scratch168; + u32 scratch169; + u32 scratch170; + u32 scratch171; + u32 scratch172; + u32 scratch173; + u32 scratch174; + u32 scratch175; + u32 scratch176; + u32 scratch177; + u32 scratch178; + u32 scratch179; + u32 scratch180; + u32 scratch181; + u32 scratch182; + u32 scratch183; + u32 scratch184; + u32 scratch185; + u32 scratch186; + u32 scratch187; + u32 scratch188; + u32 scratch189; + u32 scratch190; + u32 scratch191; + u32 scratch192; + u32 scratch193; + u32 scratch194; + u32 scratch195; + u32 scratch196; + u32 scratch197; + u32 scratch198; + u32 scratch199; + u32 scratch200; + u32 scratch201; + u32 scratch202; + u32 scratch203; + u32 scratch204; + u32 scratch205; + u32 scratch206; + u32 scratch207; + u32 scratch208; + u32 scratch209; + u32 scratch210; + u32 scratch211; + u32 scratch212; + u32 scratch213; + u32 scratch214; + u32 scratch215; + u32 scratch216; + u32 scratch217; + u32 scratch218; + u32 scratch219; + u32 scratch220; + u32 scratch221; + u32 scratch222; + u32 scratch223; + u32 scratch224; + u32 scratch225; + u32 scratch226; + u32 scratch227; + u32 scratch228; + u32 scratch229; + u32 scratch230; + u32 scratch231; + u32 scratch232; + u32 scratch233; + u32 scratch234; + u32 scratch235; + u32 scratch236; + u32 scratch237; + u32 scratch238; + u32 scratch239; + u32 scratch240; + u32 scratch241; + u32 scratch242; + u32 scratch243; + u32 scratch244; + u32 scratch245; + u32 scratch246; + u32 scratch247; + u32 scratch248; + u32 scratch249; + u32 scratch250; + u32 scratch251; + u32 scratch252; + u32 scratch253; + u32 scratch254; + u32 scratch255; + u32 scratch256; + u32 scratch257; + u32 scratch258; + u32 scratch259; + u32 scratch260; + u32 scratch261; + u32 scratch262; + u32 scratch263; + u32 scratch264; + u32 scratch265; + u32 scratch266; + u32 scratch267; + u32 scratch268; + u32 scratch269; + u32 scratch270; + u32 scratch271; + u32 scratch272; + u32 scratch273; + u32 scratch274; + u32 scratch275; + u32 scratch276; + u32 scratch277; + u32 scratch278; + u32 scratch279; + u32 scratch280; + u32 scratch281; + u32 scratch282; + u32 scratch283; + u32 scratch284; + u32 scratch285; + u32 scratch286; + u32 scratch287; + u32 scratch288; + u32 scratch289; + u32 scratch290; + u32 scratch291; + u32 scratch292; + u32 scratch293; + u32 scratch294; + u32 scratch295; + u32 scratch296; + u32 scratch297; + u32 scratch298; + u32 scratch299; /* 0x9CC */ + u32 _rsv0x9D0[50]; + u32 secure_scratch80; /* 0xa98 */ + u32 secure_scratch81; + u32 secure_scratch82; + u32 secure_scratch83; + u32 secure_scratch84; + u32 secure_scratch85; + u32 secure_scratch86; + u32 secure_scratch87; + u32 secure_scratch88; + u32 secure_scratch89; + u32 secure_scratch90; + u32 secure_scratch91; + u32 secure_scratch92; + u32 secure_scratch93; + u32 secure_scratch94; + u32 secure_scratch95; + u32 secure_scratch96; + u32 secure_scratch97; + u32 secure_scratch98; + u32 secure_scratch99; + u32 secure_scratch100; + u32 secure_scratch101; + u32 secure_scratch102; + u32 secure_scratch103; + u32 secure_scratch104; + u32 secure_scratch105; + u32 secure_scratch106; + u32 secure_scratch107; + u32 secure_scratch108; + u32 secure_scratch109; + u32 secure_scratch110; + u32 secure_scratch111; + u32 secure_scratch112; + u32 secure_scratch113; + u32 secure_scratch114; + u32 secure_scratch115; + u32 secure_scratch116; + u32 secure_scratch117; + u32 secure_scratch118; + u32 secure_scratch119; +}; + +#endif /* _TEGRA210_PMC_H_ */ diff --git a/ipl/reloc.S b/ipl/reloc.S new file mode 100755 index 0000000..d89a414 --- /dev/null +++ b/ipl/reloc.S @@ -0,0 +1,34 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +/* +* TODO: the placement of the relocator is a bit fragile atm, maybe we +* should include it in start.S and copy it to some known good +* place in IRAM instead. Basically we want it as far back atm +* as it might be overwritten during relocation. +*/ + +.section .text.reloc +.arm + +.globl _reloc_ipl +.type _reloc_ipl, %function +_reloc_ipl: + LDMIA R0!, {R4-R7} + STMIA R1!, {R4-R7} + SUBS R2, #0x10 + BNE _reloc_ipl + BX R3 diff --git a/ipl/sd.h b/ipl/sd.h new file mode 100755 index 0000000..f8c0d4b --- /dev/null +++ b/ipl/sd.h @@ -0,0 +1,95 @@ +/* +* include/linux/mmc/sd.h +* +* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +*/ + +#ifndef LINUX_MMC_SD_H +#define LINUX_MMC_SD_H + +/* SD commands type argument response */ +/* class 0 */ +/* This is basically the same command as for MMC with some quirks. */ +#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ +#define SD_SWITCH_VOLTAGE 11 /* ac R1 */ + +/* class 10 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ + +/* class 5 */ +#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */ +#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */ + +/* Application commands */ +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SD_STATUS 13 /* adtc R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SET_CLR_CARD_DETECT 42 +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +/* OCR bit definitions */ +#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */ +#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ +#define SD_OCR_XPC (1 << 28) /* SDXC power control */ +#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ + +/* +* SD_SWITCH argument format: +* +* [31] Check (0) or switch (1) +* [30:24] Reserved (0) +* [23:20] Function group 6 +* [19:16] Function group 5 +* [15:12] Function group 4 +* [11:8] Function group 3 +* [7:4] Function group 2 +* [3:0] Function group 1 +*/ + +/* +* SD_SEND_IF_COND argument format: +* +* [31:12] Reserved (0) +* [11:8] Host Voltage Supply Flags +* [7:0] Check Pattern (0xAA) +*/ + +/* +* SCR field definitions +*/ + +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */ + +/* +* SD bus widths +*/ +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 + +/* +* SD_SWITCH mode +*/ +#define SD_SWITCH_CHECK 0 +#define SD_SWITCH_SET 1 + +/* +* SD_SWITCH function groups +*/ +#define SD_SWITCH_GRP_ACCESS 0 + +/* +* SD_SWITCH access modes +*/ +#define SD_SWITCH_ACCESS_DEF 0 +#define SD_SWITCH_ACCESS_HS 1 + +#endif /* LINUX_MMC_SD_H */ diff --git a/ipl/sdmmc.c b/ipl/sdmmc.c new file mode 100755 index 0000000..5e18ec4 --- /dev/null +++ b/ipl/sdmmc.c @@ -0,0 +1,883 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "sdmmc.h" +#include "mmc.h" +#include "sd.h" +#include "util.h" +#include "heap.h" + +/*#include "gfx.h" +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; +#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/ +#define DPRINTF(...) + +static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) +{ + const u32 mask = (size < 32 ? 1 << size : 0) - 1; + const u32 off = 3 - ((start) / 32); + const u32 shft = (start) & 31; + u32 res = resp[off] >> shft; + if (size + shft > 32) + res |= resp[off - 1] << ((32 - shft) % 32); + return res & mask; +} + +/* +* Common functions for SD and MMC. +*/ + +static int _sdmmc_storage_check_result(u32 res) +{ + //Error mask: + //R1_OUT_OF_RANGE, R1_ADDRESS_ERROR, R1_BLOCK_LEN_ERROR, + //R1_ERASE_SEQ_ERROR, R1_ERASE_PARAM, R1_WP_VIOLATION, + //R1_LOCK_UNLOCK_FAILED, R1_COM_CRC_ERROR, R1_ILLEGAL_COMMAND, + //R1_CARD_ECC_FAILED, R1_CC_ERROR, R1_ERROR, R1_CID_CSD_OVERWRITE, + //R1_WP_ERASE_SKIP, R1_ERASE_RESET, R1_SWITCH_ERROR + if (!(res & 0xFDF9A080)) + return 1; + //TODO: R1_SWITCH_ERROR we can skip for certain card types. + return 0; +} + +static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state, u32 mask) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, cmd, arg, SDMMC_RSP_TYPE_1, check_busy); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + return 0; + + sdmmc_get_rsp(storage->sdmmc, resp, 4, SDMMC_RSP_TYPE_1); + if (mask) + *resp &= ~mask; + + if (_sdmmc_storage_check_result(*resp)) + if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state) + return 1; + return 0; +} + +static int _sdmmc_storage_execute_cmd_type1(sdmmc_storage_t *storage, u32 cmd, u32 arg, u32 check_busy, u32 expected_state) +{ + u32 tmp; + return _sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, cmd, arg, check_busy, expected_state, 0); +} + +static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage) +{ + sdmmc_cmd_t cmd; + sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); + return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0); +} + +static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf) +{ + sdmmc_cmd_t cmd; + sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) + return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; +} + +static int _sdmmc_storage_select_card(sdmmc_storage_t *storage) +{ + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SELECT_CARD, storage->rca << 16, 1, 0x10); +} + +static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; +} + +static int _sdmmc_storage_set_blocklen(sdmmc_storage_t *storage, u32 blocklen) +{ + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_BLOCKLEN, blocklen, 0, R1_STATE_TRAN); +} + +static int _sdmmc_storage_get_status(sdmmc_storage_t *storage, u32 *resp, u32 mask) +{ + return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, MMC_SEND_STATUS, storage->rca << 16, 0, R1_STATE_TRAN, mask); +} + +static int _sdmmc_storage_check_status(sdmmc_storage_t *storage) +{ + u32 tmp; + return _sdmmc_storage_get_status(storage, &tmp, 0); +} + +static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.num_sectors = num_sectors; + reqbuf.blksize = 512; + reqbuf.is_write = is_write; + reqbuf.is_multi_block = 1; + reqbuf.is_auto_cmd12 = 1; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out)) + { + u32 tmp = 0; + sdmmc_stop_transmission(storage->sdmmc, &tmp); + _sdmmc_storage_get_status(storage, &tmp, 0); + return 0; + } + return 1; +} + +int sdmmc_storage_end(sdmmc_storage_t *storage) +{ + if (!_sdmmc_storage_go_idle_state(storage)) + return 0; + sdmmc_end(storage->sdmmc); + return 1; +} + +static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) +{ + u8 *bbuf = (u8 *)buf; + + while (num_sectors) + { + u32 blkcnt = 0; + //Retry once on error. + if (!_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) + if (!_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) + return 0; + DPRINTF("readwrite: %08X\n", blkcnt); + sector += blkcnt; + num_sectors -= blkcnt; + bbuf += 512 * blkcnt; + } +} + +int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0); +} + +int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1); +} + +/* +* MMC specific functions. +*/ + +static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u32 power) +{ + sdmmc_cmd_t cmd; + + u32 arg = 0; + switch (power) + { + case SDMMC_POWER_1_8: + arg = 0x40000080; //Sector access, voltage. + break; + case SDMMC_POWER_3_3: + arg = 0x403F8000; //Sector access, voltage. + break; + default: + return 0; + } + + sdmmc_init_cmd(&cmd, MMC_SEND_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) + return 0; + + return sdmmc_get_rsp(storage->sdmmc, pout, 4, SDMMC_RSP_TYPE_3); +} + +static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) +{ + u32 timeout = get_tmr() + 1500000; + + while (1) + { + u32 cond = 0; + if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) + break; + if (cond & 0x80000000) + { + if (cond & 0x40000000) + storage->has_sector_access = 1; + return 1; + } + if (get_tmr() > timeout) + break; + sleep(1000); + } + + return 0; +} + +static int _mmc_storage_set_relative_addr(sdmmc_storage_t *storage) +{ + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, 0x10); +} + +static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_SEND_EXT_CSD, 0, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = 512; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_cmd12 = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + return 0; + + u32 tmp = 0; + sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_storage_check_result(tmp); +} + +static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg) +{ + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, 0x10); +} + +static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) +{ + if (bus_width == SDMMC_BUS_WIDTH_1) + return 1; + + u32 arg = 0; + switch (bus_width) + { + case SDMMC_BUS_WIDTH_4: + arg = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); + break; + case SDMMC_BUS_WIDTH_8: + arg = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8); + break; + } + + if (_mmc_storage_switch(storage, arg)) + if (_sdmmc_storage_check_status(storage)) + { + sdmmc_set_bus_width(storage->sdmmc, bus_width); + return 1; + } + + return 0; +} + +static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check) +{ + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS))) + return 0; + if (check && !_sdmmc_storage_check_status(storage)) + return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 2)) + return 0; + DPRINTF("[mmc] switched to HS\n"); + if (check || _sdmmc_storage_check_status(storage)) + return 1; + return 0; +} + +static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage) +{ + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200))) + return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 3)) + return 0; + if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200)) + return 0; + DPRINTF("[mmc] switched to HS200\n"); + return _sdmmc_storage_check_status(storage); +} + +static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) +{ + if (!_mmc_storage_enable_HS200(storage)) + return 0; + sdmmc_get_venclkctl(storage->sdmmc); + if (!_mmc_storage_enable_HS(storage, 0)) + return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8))) + return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400))) + return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 4)) + return 0; + DPRINTF("[mmc] switched to HS400\n"); + return _sdmmc_storage_check_status(storage); +} + +static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type) +{ + //TODO: this should be a config item. + //---v + if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8) + goto out; + + if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && + card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && + type == 4) + return _mmc_storage_enable_HS400(storage); + + if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || + sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4 + && card_type & EXT_CSD_CARD_TYPE_HS200_1_8V + && (type == 4 || type == 3)) + return _mmc_storage_enable_HS200(storage); + +out:; + if (card_type & EXT_CSD_CARD_TYPE_HS_52) + return _mmc_storage_enable_HS(storage, 1); + return 1; +} + +static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage) +{ + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2))) + return 0; + return _sdmmc_storage_check_status(storage); +} + +int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) +{ + memset(storage, 0, sizeof(sdmmc_storage_t)); + storage->sdmmc = sdmmc; + storage->rca = 2; //TODO: this could be a config item. + + if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0)) + return 0; + DPRINTF("[mmc] after init\n"); + + sleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); + + if (!_sdmmc_storage_go_idle_state(storage)) + return 0; + DPRINTF("[mmc] went to idle state\n"); + + if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8)) + return 0; + DPRINTF("[mmc] got op cond\n"); + + if (!_sdmmc_storage_get_cid(storage, storage->cid)) + return 0; + DPRINTF("[mmc] got cid\n"); + + if (!_mmc_storage_set_relative_addr(storage)) + return 0; + DPRINTF("[mmc] set relative addr\n"); + + if (!_sdmmc_storage_get_csd(storage, storage->csd)) + return 0; + DPRINTF("[mmc] got csd\n"); + + if (!sdmmc_setup_clock(storage->sdmmc, 1)) + return 0; + DPRINTF("[mmc] after setup clock\n"); + + if (!_sdmmc_storage_select_card(storage)) + return 0; + DPRINTF("[mmc] card selected\n"); + + if (!_sdmmc_storage_set_blocklen(storage, 512)) + return 0; + DPRINTF("[mmc] set blocklen to 512\n"); + + u32 *csd = (u32 *)storage->csd; + //Check system specification version, only version 4.0 and later support below features. + if (unstuff_bits(csd, 122, 4) < CSD_SPEC_VER_4) + { + storage->sec_cnt = (1 + unstuff_bits(csd, 62, 12)) << (unstuff_bits(csd, 47, 3) + 2); + return 1; + } + + if (!_mmc_storage_switch_buswidth(storage, bus_width)) + return 0; + DPRINTF("[mmc] switched buswidth\n"); + + u8 *ext_csd = (u8 *)malloc(512); + if (!_mmc_storage_get_ext_csd(storage, ext_csd)) + { + free(ext_csd); + return 0; + } + //gfx_hexdump(&gfx_con, 0, ext_csd, 512); + + storage->sec_cnt = *(u32 *)&ext_csd[EXT_CSD_SEC_CNT]; + + if (storage->cid[0xE] == 0x11 && ext_csd[EXT_CSD_BKOPS_EN] & EXT_CSD_BKOPS_LEVEL_2) + _mmc_storage_enable_bkops(storage); + + if (!_mmc_storage_enable_highspeed(storage, ext_csd[EXT_CSD_CARD_TYPE], type)) + { + free(ext_csd); + return 0; + } + DPRINTF("[mmc] switched to possible highspeed mode\n"); + + sdmmc_sd_clock_ctrl(storage->sdmmc, 1); + + free(ext_csd); + return 1; +} + +int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) +{ + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition))) + return 0; + if (!_sdmmc_storage_check_status(storage)) + return 0; + storage->partition = partition; + return 1; +} + +/* +* SD specific functions. +*/ + +static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_state, u32 mask, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +{ + u32 tmp; + if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask)) + return 0; + return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out); +} + +static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state) +{ + if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN)) + return 0; + return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0); +} + +static int _sd_storage_send_if_cond(sdmmc_storage_t *storage) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, 0x1AA, SDMMC_RSP_TYPE_5, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + return 0; + + //TODO: we may have received a timeout error in the above request, which indicates a version 1 card. + + u32 resp = 0; + if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5)) + return 0; + + return (resp & 0xFFF) == 0x1AA ? 1 : 0; +} + +static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int supports_low_voltage) +{ + sdmmc_cmd_t cmdbuf; + u32 arg = (((~is_version_1 & 1) << 28) & 0xBFFFFFFF | ((~is_version_1 & 1) << 30)) & 0xFEFFFFFF | ((supports_low_voltage & ~is_version_1 & 1) << 24) | 0x100000; + sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); + if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) + return 0; + return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); +} + +static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int supports_low_voltage) +{ + u32 timeout = get_tmr() + 1500000; + + while (1) + { + u32 cond = 0; + if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage)) + break; + if (cond & 0x80000000) + { + if (cond & 0x40000000) + storage->has_sector_access = 1; + + if (cond & 0x1000000 && supports_low_voltage) + { + //The low voltage regulator configuration is valid for SDMMC1 only. + if (storage->sdmmc->id == SDMMC_1 && + _sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) + { + if (!sdmmc_enable_low_voltage(storage->sdmmc)) + return 0; + storage->is_low_voltage = 1; + + DPRINTF("-> switched to low voltage\n"); + } + } + + return 1; + } + if (get_tmr() > timeout) + break; + sleep(1000); + } + + return 0; +} + +static int _sd_storage_get_rca(sdmmc_storage_t *storage) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, SD_SEND_RELATIVE_ADDR, 0, SDMMC_RSP_TYPE_4, 0); + + u32 timeout = get_tmr() + 1500000; + + while (1) + { + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + break; + + u32 resp = 0; + if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_4)) + break; + + if (resp >> 16) + { + storage->rca = resp >> 16; + return 1; + } + + if (get_tmr() > timeout) + break; + sleep(1000); + } + + return 0; +} + +int _sd_storage_get_scr(sdmmc_storage_t *storage, void *buf) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, SD_APP_SEND_SCR, 0, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = 8; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_cmd12 = 0; + + if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, 0)) + return 0; + + u32 tmp = 0; + sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_storage_check_result(tmp); +} + +int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, SD_SWITCH, 0xFFFFFF, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = 64; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_cmd12 = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + return 0; + + u32 tmp = 0; + sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_storage_check_result(tmp); +} + +int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int flag, u32 arg) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, SD_SWITCH, arg | (flag << 31) | 0xFFFFF0, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = 64; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_cmd12 = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + return 0; + + u32 tmp = 0; + sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_storage_check_result(tmp); +} + +int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) +{ + if (!_sd_storage_switch(storage, buf, 0, hs_type)) + return 0; + + u32 type_out = buf[16] & 0xF; + if (type_out != hs_type) + return 0; + + if (((u16)buf[0] << 8) | buf[1] < 0x320) + { + if (!_sd_storage_switch(storage, buf, 1, hs_type)) + return 0; + + if (type_out != buf[16] & 0xF) + return 0; + } + + return 1; +} + +int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) +{ + if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) + return 0; + + if (!_sd_storage_switch_get(storage, buf)) + return 0; + + u32 hs_type = 0; + switch (type) + { + case 11: + if (buf[13] & 8) + { + type = 11; + hs_type = 3; + break; + } + //Fall through. + case 10: + if (!(buf[13] & 4)) + return 0; + type = 10; + hs_type = 2; + break; + default: + return 0; + break; + } + + if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) + return 0; + if (!sdmmc_setup_clock(storage->sdmmc, type)) + return 0; + if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) + return 0; + return _sdmmc_storage_check_status(storage); +} + +int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) +{ + if (!_sd_storage_switch_get(storage, buf)) + return 0; + + if (!(buf[13] & 2)) + return 1; + + if (!_sd_storage_enable_highspeed(storage, 1, buf)) + return 0; + if (!_sdmmc_storage_check_status(storage)) + return 0; + return sdmmc_setup_clock(storage->sdmmc, 7); +} + +int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) +{ + memset(storage, 0, sizeof(sdmmc_storage_t)); + storage->sdmmc = sdmmc; + + if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0)) + return 0; + DPRINTF("[sd] after init\n"); + + sleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); + + if (!_sdmmc_storage_go_idle_state(storage)) + return 0; + DPRINTF("[sd] went to idle state\n"); + + if (!_sd_storage_send_if_cond(storage)) + return 0; + DPRINTF("[sd] after send if cond\n"); + + //TODO: use correct version here -----v + if (!_sd_storage_get_op_cond(storage, 0, bus_width == SDMMC_BUS_WIDTH_4 && (type | 1) == 11)) + return 0; + DPRINTF("[sd] got op cond\n"); + + if (!_sdmmc_storage_get_cid(storage, storage->cid)) + return 0; + DPRINTF("[sd] got cid\n"); + + if (!_sd_storage_get_rca(storage)) + return 0; + DPRINTF("[sd] got rca (= %04X)\n", storage->rca); + + if (!_sdmmc_storage_get_csd(storage, storage->csd)) + return 0; + DPRINTF("[sd] got csd\n"); + + //Parse CSD. + u32 *csd = (u32 *)storage->csd; + u32 csd_struct = unstuff_bits(csd, 126, 2); + switch (csd_struct) + { + case 0: + storage->sec_cnt = (1 + unstuff_bits(csd, 62, 12)) << (unstuff_bits(csd, 47, 3) + 2); + break; + case 1: + storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10; + break; + default: + DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct); + //TODO: I've encountered this with one of my SD cards, but + // according to the spec only version 0 and 1 are + // supposed to be in use (mine was version 2). + //return 0; + break; + } + + if (!storage->is_low_voltage) + { + if (!sdmmc_setup_clock(storage->sdmmc, 6)) + return 0; + DPRINTF("[sd] after setup clock\n"); + } + + if (!_sdmmc_storage_select_card(storage)) + return 0; + DPRINTF("[sd] card selected\n"); + + if (!_sdmmc_storage_set_blocklen(storage, 512)) + return 0; + DPRINTF("[sd] set blocklen to 512\n"); + + u32 tmp = 0; + if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN)) + return 0; + DPRINTF("[sd] cleared card detect\n"); + + u8 *buf = (u8 *)malloc(512); + if (!_sd_storage_get_scr(storage, buf)) + return 0; + memcpy(storage->scr, buf, 8); + DPRINTF("[sd] got scr\n"); + + if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4) + { + if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) + { + free(buf); + return 0; + } + sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); + DPRINTF("[sd] switched to wide bus width\n"); + } + else + DPRINTF("[sd] SD does not support wide bus width\n"); + + if (storage->is_low_voltage) + { + if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf)) + { + free(buf); + return 0; + } + DPRINTF("[sd] enabled highspeed (low voltage)\n"); + } + else if (type != 6 && storage->scr[0] & 0xF != 0) + { + if (!_sd_storage_enable_highspeed_high_volt(storage, buf)) + { + free(buf); + return 0; + } + DPRINTF("[sd] enabled highspeed (high voltage)\n"); + } + + sdmmc_sd_clock_ctrl(sdmmc, 1); + + free(buf); + return 1; +} + +/* +* Gamecard specific functions. +*/ + +int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) +{ + u32 resp; + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, 60, 0, SDMMC_RSP_TYPE_1, 1); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = 0x40; + reqbuf.num_sectors = 1; + reqbuf.is_write = 1; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_cmd12 = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) + { + sdmmc_stop_transmission(storage->sdmmc, &resp); + return 0; + } + + if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1)) + return 0; + if (!_sdmmc_storage_check_result(resp)) + return 0; + return _sdmmc_storage_check_status(storage); +} + +int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) +{ + memset(storage, 0, sizeof(sdmmc_storage_t)); + storage->sdmmc = sdmmc; + + if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0)) + return 0; + DPRINTF("[gc] after init\n"); + + sleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); + + if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200)) + return 0; + DPRINTF("[gc] after tuning\n"); + + sdmmc_sd_clock_ctrl(sdmmc, 1); + + return 1; +} diff --git a/ipl/sdmmc.h b/ipl/sdmmc.h new file mode 100755 index 0000000..89e2877 --- /dev/null +++ b/ipl/sdmmc.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _SDMMC_H_ +#define _SDMMC_H_ + +#include "types.h" +#include "sdmmc_driver.h" + +/*! SDMMC storage context. */ +typedef struct _sdmmc_storage_t +{ + sdmmc_t *sdmmc; + u32 rca; + int has_sector_access; + u32 sec_cnt; + int is_low_voltage; + u32 partition; + u8 cid[0x10]; + u8 csd[0x10]; + u8 scr[8]; +} sdmmc_storage_t; + +int sdmmc_storage_end(sdmmc_storage_t *storage); +int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); +int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); +int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); + +#endif diff --git a/ipl/sdmmc_driver.c b/ipl/sdmmc_driver.c new file mode 100755 index 0000000..e5c9b37 --- /dev/null +++ b/ipl/sdmmc_driver.c @@ -0,0 +1,1063 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include + +#include "sdmmc.h" +#include "util.h" +#include "clock.h" +#include "mmc.h" +#include "max7762x.h" +#include "t210.h" +#include "pmc.h" +#include "pinmux.h" +#include "gpio.h" + +/*#include "gfx.h" +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; +#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/ +#define DPRINTF(...) + +/*! SCMMC controller base addresses. */ +static const u32 _sdmmc_bases[4] = { + 0x700B0000, + 0x700B0200, + 0x700B0400, + 0x700B0600, +}; + +int sdmmc_get_voltage(sdmmc_t *sdmmc) +{ + u32 p = sdmmc->regs->pwrcon; + if (!(p & TEGRA_MMC_PWRCTL_SD_BUS_POWER)) + return SDMMC_POWER_OFF; + if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8) + return SDMMC_POWER_1_8; + if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3) + return SDMMC_POWER_3_3; + return -1; +} + +static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) +{ + switch (power) + { + case SDMMC_POWER_OFF: + sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER; + break; + case SDMMC_POWER_1_8: + sdmmc->regs->pwrcon = + (sdmmc->regs->pwrcon & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK) | + TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; + break; + case SDMMC_POWER_3_3: + sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; + break; + default: + return 0; + } + + sdmmc->regs->pwrcon |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; + + return 1; +} + +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc) +{ + u32 h = sdmmc->regs->hostctl; + if (h & TEGRA_MMC_HOSTCTL_8BIT) + return SDMMC_BUS_WIDTH_8; + if (h & TEGRA_MMC_HOSTCTL_4BIT) + return SDMMC_BUS_WIDTH_4; + return SDMMC_BUS_WIDTH_1; +} + +void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) +{ + if (bus_width == SDMMC_BUS_WIDTH_1) + sdmmc->regs->hostctl &= ~(TEGRA_MMC_HOSTCTL_4BIT | TEGRA_MMC_HOSTCTL_8BIT); + else if (bus_width == SDMMC_BUS_WIDTH_4) + { + sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_4BIT; + sdmmc->regs->hostctl &= ~TEGRA_MMC_HOSTCTL_8BIT; + } + else if (bus_width == SDMMC_BUS_WIDTH_8) + sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_8BIT; +} + +void sdmmc_get_venclkctl(sdmmc_t *sdmmc) +{ + sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16; + sdmmc->venclkctl_set = 1; +} + +static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id) +{ + u32 tap_val = 0; + + if (id == 4) + sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800; + sdmmc->regs->field_1C0 &= 0xFFFDFFFF; + if (id == 4) + { + if (!sdmmc->venclkctl_set) + return 0; + tap_val = sdmmc->venclkctl_tap; + } + else + { + static const u32 tap_values[] = { 4, 0, 3, 0 }; + tap_val = tap_values[sdmmc->id]; + } + sdmmc->regs->venclkctl = sdmmc->regs->venclkctl & 0xFF00FFFF | (tap_val << 16); + + return 1; +} + +static int _sdmmc_get_clkcon(sdmmc_t *sdmmc) +{ + return sdmmc->regs->clkcon; +} + +static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) +{ + _sdmmc_get_clkcon(sdmmc); + if (sdmmc->id == SDMMC_4) + *(vu32 *)0x70000AB4 = ((*(vu32 *)0x70000AB4) & 0x3FFC) | 0x1040; + //TODO: load standard values for other controllers, can depend on power. +} + +static int _sdmmc_wait_type4(sdmmc_t *sdmmc) +{ + int res = 1, should_disable_sd_clock = 0; + + if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + } + + sdmmc->regs->field_1B0 |= 0x80000000; + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr() + 5000; + while (sdmmc->regs->field_1B0 & 0x80000000) + { + if (get_tmr() > timeout) + { + res = 0; + goto out; + } + } + + timeout = get_tmr() + 10000; + while (sdmmc->regs->field_1BC & 0x80000000) + { + if (get_tmr() > timeout) + { + res = 0; + goto out; + } + } + +out:; + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + return res; +} + +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) +{ + //Disable the SD clock if it was enabled, and reenable it later. + int should_enable_sd_clock = 0; + if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) + { + should_enable_sd_clock = 1; + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + } + + _sdmmc_config_ven_ceata_clk(sdmmc, type); + + switch (type) + { + case 0: + case 1: + case 5: + case 6: + sdmmc->regs->hostctl &= 0xFB; + sdmmc->regs->hostctl2 &= 0xFFF7; + break; + case 2: + case 7: + sdmmc->regs->hostctl |= 4; + sdmmc->regs->hostctl2 &= 0xFFF7; + break; + case 3: + case 11: + case 13: + case 14: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & 0xFFF8) | 3; + sdmmc->regs->hostctl2 |= 8; + break; + case 4: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & 0xFFF8) | 5; + sdmmc->regs->hostctl2 |= 8; + break; + case 8: + sdmmc->regs->hostctl2 = sdmmc->regs->hostctl2 & 0xFFF8; + sdmmc->regs->hostctl2 |= 8; + break; + case 10: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & 0xFFF8) | 2; + sdmmc->regs->hostctl2 |= 8; + break; + } + + _sdmmc_get_clkcon(sdmmc); + + u32 tmp; + u16 divisor; + clock_sdmmc_get_params(&tmp, &divisor, type); + clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp); + sdmmc->divisor = (tmp + divisor - 1) / divisor; + + //if divisor != 1 && divisor << 31 -> error + + u16 div = divisor >> 1; + divisor = 0; + if (div > 0xFF) + divisor = div >> 8; + sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6); + + //Enable the SD clock again. + if (should_enable_sd_clock) + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + + if (type == 4) + return _sdmmc_wait_type4(sdmmc); + return 1; +} + +static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc) +{ + if (!sdmmc->no_sd) + { + if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + } + sdmmc->sd_clock_enabled = 1; +} + +static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc) +{ + sdmmc->sd_clock_enabled = 0; + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; +} + +void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd) +{ + sdmmc->no_sd = no_sd; + if (no_sd) + { + if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + return; + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + return; + } + if (sdmmc->sd_clock_enabled) + if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; +} + +static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) +{ + switch (type) + { + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_3: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + if (size < 4) + return 0; + rsp[0] = sdmmc->regs->rspreg0; + break; + case SDMMC_RSP_TYPE_2: + if (size < 0x10) + return 0; + rsp[0] = sdmmc->regs->rspreg0; + rsp[1] = sdmmc->regs->rspreg1; + rsp[2] = sdmmc->regs->rspreg2; + rsp[3] = sdmmc->regs->rspreg3; + break; + default: + return 0; + break; + } + + return 1; +} + +int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) +{ + if (!rsp || sdmmc->expected_rsp_type != type) + return 0; + + switch (type) + { + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_3: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + if (size < 4) + return 0; + rsp[0] = sdmmc->rsp[0]; + break; + case SDMMC_RSP_TYPE_2: + if (size < 0x10) + return 0; + rsp[0] = sdmmc->rsp[0]; + rsp[1] = sdmmc->rsp[1]; + rsp[2] = sdmmc->rsp[2]; + rsp[3] = sdmmc->rsp[3]; + break; + default: + return 0; + break; + } + + return 1; +} + +static void _sdmmc_reset(sdmmc_t *sdmmc) +{ + sdmmc->regs->swrst |= + TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE; + _sdmmc_get_clkcon(sdmmc); + u32 timeout = get_tmr() + 2000000; + while (sdmmc->regs->swrst << 29 >> 30 && get_tmr() < timeout) + ; +} + +static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) +{ + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr() + 2000000; + while(sdmmc->regs->prnsts & 1) //CMD inhibit. + if (get_tmr() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + + if (wait_dat) + { + timeout = get_tmr() + 2000000; + while (sdmmc->regs->prnsts & 2) //DAT inhibit. + if (get_tmr() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + } + + return 1; +} + +static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc) +{ + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr() + 2000000; + while (!(sdmmc->regs->prnsts & 0x100000)) //DAT0 line level. + if (get_tmr() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + + return 1; +} + +static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) +{ + switch (sdmmc_get_bus_width(sdmmc)) + { + case SDMMC_BUS_WIDTH_1: + return 0; + break; + case SDMMC_BUS_WIDTH_4: + sdmmc->regs->blksize = 0x40; + break; + case SDMMC_BUS_WIDTH_8: + sdmmc->regs->blksize = 0x80; + break; + } + sdmmc->regs->blkcnt = 1; + sdmmc->regs->trnmod = TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; + return 1; +} + +static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, int is_data_present) +{ + u16 cmdflags = 0; + + switch (cmd->rsp_type) + { + case SDMMC_RSP_TYPE_0: + break; + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + if (cmd->check_busy) + cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY | + TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK | + TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; + else + cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 | + TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK | + TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; + break; + case SDMMC_RSP_TYPE_2: + cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 | + TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; + break; + case SDMMC_RSP_TYPE_3: + cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48; + break; + default: + return 0; + break; + } + + if (is_data_present) + cmdflags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER; + sdmmc->regs->argument = cmd->arg; + sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags; + + return 1; +} + +static void _sdmmc_parse_cmd_48(sdmmc_t *sdmmc, u32 cmd) +{ + sdmmc_cmd_t cmdbuf; + cmdbuf.cmd = cmd; + cmdbuf.arg = 0; + cmdbuf.rsp_type = SDMMC_RSP_TYPE_1; + cmdbuf.check_busy = 0; + _sdmmc_parse_cmdbuf(sdmmc, &cmdbuf, 1); +} + +static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) +{ + if (sdmmc->no_sd) + return 0; + if (!_sdmmc_wait_prnsts_type0(sdmmc, 1)) + return 0; + + _sdmmc_setup_read_small_block(sdmmc); + sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY; + sdmmc->regs->norintsts = sdmmc->regs->norintsts; + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_parse_cmd_48(sdmmc, cmd); + _sdmmc_get_clkcon(sdmmc); + sleep(1); + _sdmmc_reset(sdmmc); + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr() + 5000; + while (get_tmr() < timeout) + { + if (sdmmc->regs->norintsts & 0x20) + { + sdmmc->regs->norintsts = 0x20; + sdmmc->regs->norintstsen &= 0xFFDF; + _sdmmc_get_clkcon(sdmmc); + sleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); + return 1; + } + } + _sdmmc_reset(sdmmc); + sdmmc->regs->norintstsen &= 0xFFDF; + _sdmmc_get_clkcon(sdmmc); + sleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); + return 0; +} + +int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) +{ + u32 max = 0, flag = 0; + + sdmmc->regs->field_1C4 = 0; + switch (type) + { + case 3: + case 4: + case 11: + max = 0x80; + flag = 0x4000; + break; + case 10: + case 13: + case 14: + max = 0x100; + flag = 0x8000; + break; + default: + return 0; + } + + sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFF1FFF) | flag; + sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFFE03F) | 0x40; + sdmmc->regs->field_1C0 |= 0x20000; + sdmmc->regs->hostctl2 |= 0x40; + + for (u32 i = 0; i < max; i++) + { + _sdmmc_config_tuning_once(sdmmc, cmd); + if (!(sdmmc->regs->hostctl2 & 0x40)) + break; + } + + if (sdmmc->regs->hostctl2 & 0x80) + return 1; + return 0; +} + +static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc) +{ + //Enable internal clock and wait till it is stable. + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE; + _sdmmc_get_clkcon(sdmmc); + u32 timeout = get_tmr() + 2000000; + while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) + { + if (get_tmr() > timeout) + return 0; + } + + sdmmc->regs->hostctl2 &= 0x7FFF; + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT; + sdmmc->regs->hostctl2 |= 0x1000; + + if (!(sdmmc->regs->capareg & 0x10000000)) + return 0; + + sdmmc->regs->hostctl2 |= 0x2000; + sdmmc->regs->hostctl &= 0xE7; + sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE; + + return 1; +} + +static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power) +{ + u32 off_pd = 0; + u32 off_pu = 0; + + switch (sdmmc->id) + { + case SDMMC_2: + case SDMMC_4: + if (power != SDMMC_POWER_1_8) + return 0; + off_pd = 5; + off_pu = 5; + break; + case SDMMC_1: + case SDMMC_3: + if (power == SDMMC_POWER_1_8) + { + off_pd = 123; + off_pu = 123; + } + else if (power == SDMMC_POWER_3_3) + { + off_pd = 125; + off_pu = 0; + } + else + return 0; + break; + } + + sdmmc->regs->autocalcfg = ((sdmmc->regs->autocalcfg & 0xFFFF80FF | (off_pd << 8)) >> 7 << 7) | off_pu; + return 1; +} + +static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) +{ + int should_enable_sd_clock = 0; + if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) + { + should_enable_sd_clock = 1; + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + } + + if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000)) + { + sdmmc->regs->sdmemcmppadctl |= 0x80000000; + _sdmmc_get_clkcon(sdmmc); + sleep(1); + } + + sdmmc->regs->autocalcfg |= 0xA0000000; + _sdmmc_get_clkcon(sdmmc); + sleep(1); + + u32 timeout = get_tmr() + 10000; + while (sdmmc->regs->autocalcfg & 0x80000000) + { + if (get_tmr() > timeout) + { + //In case autocalibration fails, we load suggested standard values. + _sdmmc_pad_config_fallback(sdmmc, power); + sdmmc->regs->autocalcfg &= 0xDFFFFFFF; + break; + } + } + + sdmmc->regs->sdmemcmppadctl &= 0x7FFFFFFF; + + if(should_enable_sd_clock) + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; +} + +static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc) +{ + sdmmc->regs->norintstsen |= 0xB; + sdmmc->regs->errintstsen |= 0x17F; + sdmmc->regs->norintsts = sdmmc->regs->norintsts; + sdmmc->regs->errintsts = sdmmc->regs->errintsts; +} + +static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc) +{ + sdmmc->regs->errintstsen &= 0xFE80; + sdmmc->regs->norintstsen &= 0xFFF4; +} + +static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) +{ + u16 norintsts = sdmmc->regs->norintsts; + u16 errintsts = sdmmc->regs->errintsts; + + DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); + + if (pout) + *pout = norintsts; + + //Check for error interrupt. + if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) + { + sdmmc->regs->errintsts = errintsts; + return SDMMC_MASKINT_ERROR; + } + else if (norintsts & mask) + { + sdmmc->regs->norintsts = norintsts & mask; + return SDMMC_MASKINT_MASKED; + } + + return SDMMC_MASKINT_NOERROR; +} + +static int _sdmmc_wait_request(sdmmc_t *sdmmc) +{ + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr() + 2000000; + while (1) + { + int res = _sdmmc_check_mask_interrupt(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE); + if (res == SDMMC_MASKINT_MASKED) + break; + if (res != SDMMC_MASKINT_NOERROR || get_tmr() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + } + + return 1; +} + +static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) +{ + sdmmc_cmd_t cmd; + + if (!_sdmmc_wait_prnsts_type0(sdmmc, 0)) + return 0; + + _sdmmc_enable_interrupts(sdmmc); + cmd.cmd = MMC_STOP_TRANSMISSION; + cmd.arg = 0; + cmd.rsp_type = SDMMC_RSP_TYPE_1; + cmd.check_busy = 1; + _sdmmc_parse_cmdbuf(sdmmc, &cmd, 0); + int res = _sdmmc_wait_request(sdmmc); + _sdmmc_mask_interrupts(sdmmc); + + if (!res) + return 0; + + _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_wait_prnsts_type1(sdmmc); +} + +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) +{ + if (!sdmmc->sd_clock_enabled) + return 0; + + int should_disable_sd_clock = 0; + if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_get_clkcon(sdmmc); + sleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + } + + int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); + sleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + + return res; +} + +static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) +{ + if (!req->blksize || !req->num_sectors) + return 0; + + u32 blkcnt = req->num_sectors; + if (blkcnt >= 0xFFFF) + blkcnt = 0xFFFF; + u32 admaaddr = (u32)req->buf; + + //Check alignment. + if (admaaddr << 29) + return 0; + + sdmmc->regs->admaaddr = admaaddr; + sdmmc->regs->admaaddr_hi = 0; + + sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFF80000; + + sdmmc->regs->blksize = req->blksize | 0x7000; + sdmmc->regs->blkcnt = blkcnt; + + if (blkcnt_out) + *blkcnt_out = blkcnt; + + u32 trnmode = TEGRA_MMC_TRNMOD_DMA_ENABLE; + if (req->is_multi_block) + trnmode = TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT | + TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE | + TEGRA_MMC_TRNMOD_DMA_ENABLE; + if (!req->is_write) + trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; + if (req->is_auto_cmd12) + trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12; + + sdmmc->regs->trnmod = trnmode; + + return 1; +} + +static int _sdmmc_update_dma(sdmmc_t *sdmmc) +{ + u16 blkcnt = 0; + do + { + blkcnt = sdmmc->regs->blkcnt; + u32 timeout = get_tmr() + 1500000; + do + { + int res = 0; + while (1) + { + u16 intr = 0; + res = _sdmmc_check_mask_interrupt(sdmmc, &intr, + TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT); + if (res < 0) + break; + if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) + return 1; //Transfer complete. + if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) + { + //Update DMA. + sdmmc->regs->admaaddr = sdmmc->dma_addr_next; + sdmmc->regs->admaaddr_hi = 0; + sdmmc->dma_addr_next += 0x80000; + } + } + if (res != SDMMC_MASKINT_NOERROR) + { + _sdmmc_reset(sdmmc); + return 0; + } + } while (get_tmr() < timeout); + } while (sdmmc->regs->blkcnt != blkcnt); + + _sdmmc_reset(sdmmc); + return 0; +} + +static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +{ + int has_req_or_check_busy = req || cmd->check_busy; + if (!_sdmmc_wait_prnsts_type0(sdmmc, has_req_or_check_busy)) + return 0; + + u32 blkcnt = 0; + int is_data_present = 0; + if (req) + { + _sdmmc_config_dma(sdmmc, &blkcnt, req); + _sdmmc_enable_interrupts(sdmmc); + is_data_present = 1; + } + else + { + _sdmmc_enable_interrupts(sdmmc); + is_data_present = 0; + } + + _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); + + int res = _sdmmc_wait_request(sdmmc); + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, + sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); + if (res) + { + if (cmd->rsp_type) + { + sdmmc->expected_rsp_type = cmd->rsp_type; + _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); + } + if (req) + _sdmmc_update_dma(sdmmc); + } + + _sdmmc_mask_interrupts(sdmmc); + + if (res) + { + if (req) + { + if (blkcnt_out) + *blkcnt_out = blkcnt; + if (req->is_auto_cmd12) + sdmmc->rsp3 = sdmmc->regs->rspreg3; + } + + if (cmd->check_busy || req) + return _sdmmc_wait_prnsts_type1(sdmmc); + } + + return res; +} + +static int _sdmmc_config_sdmmc1() +{ + //Configure SD card detect. + PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = 0x49; //GPIO control, pull up. + APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; + gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); + sleep(100); + if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) + return 0; + + /* + * Pinmux config: + * DRV_TYPE = DRIVE_2X + * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) + * E_INPUT = ENABLE + * TRISTATE = PASSTHROUGH + * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK + */ + + //Configure SDMMC1 pinmux. + APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = 0x2060; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = 0x2068; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = 0x2068; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = 0x2068; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = 0x2068; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = 0x2068; + + //Make sure the SDMMC1 controller is powered. + PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12); + //Assume 3.3V SD card voltage. + PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); + + //Set enable SD card power. + PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = 0x45; //GPIO control, pull down. + gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); + gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); + + sleep(1000); + + //Enable SD card power. + max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); + max77620_regulator_enable(REGULATOR_LDO2, 1); + + sleep(1000); + + //For good measure. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; + + sleep(1000); + + return 1; +} + +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd) +{ + if (id > SDMMC_4) + return 0; + + if (id == SDMMC_1) + if (!_sdmmc_config_sdmmc1()) + return 0; + + memset(sdmmc, 0, sizeof(sdmmc_t)); + + sdmmc->regs = (t210_sdmmc_t *)_sdmmc_bases[id]; + sdmmc->id = id; + sdmmc->clock_stopped = 1; + + if (clock_sdmmc_is_not_reset_and_enabled(id)) + { + _sdmmc_sd_clock_disable(sdmmc); + _sdmmc_get_clkcon(sdmmc); + } + + u32 clock; + u16 divisor; + clock_sdmmc_get_params(&clock, &divisor, type); + clock_sdmmc_enable(id, clock); + + sdmmc->clock_stopped = 0; + + //TODO: make this skip-able. + sdmmc->regs->field_1F0 |= 0x80000; + sdmmc->regs->field_1AC &= 0xFFFFFFFB; + static const u32 trim_values[] = { 2, 8, 3, 8 }; + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24); + sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7; + if (!_sdmmc_autocal_config_offset(sdmmc, power)) + return 0; + _sdmmc_autocal_execute(sdmmc, power); + if (_sdmmc_enable_internal_clock(sdmmc)) + { + sdmmc_set_bus_width(sdmmc, bus_width); + _sdmmc_set_voltage(sdmmc, power); + if (sdmmc_setup_clock(sdmmc, type)) + { + sdmmc_sd_clock_ctrl(sdmmc, no_sd); + _sdmmc_sd_clock_enable(sdmmc); + _sdmmc_get_clkcon(sdmmc); + return 1; + } + return 0; + } + return 0; +} + +void sdmmc_end(sdmmc_t *sdmmc) +{ + if (!sdmmc->clock_stopped) + { + _sdmmc_sd_clock_disable(sdmmc); + _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); + _sdmmc_get_clkcon(sdmmc); + clock_sdmmc_disable(sdmmc->id); + sdmmc->clock_stopped = 1; + } +} + +void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy) +{ + cmdbuf->cmd = cmd; + cmdbuf->arg = arg; + cmdbuf->rsp_type = rsp_type; + cmdbuf->check_busy = check_busy; +} + +int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +{ + if (!sdmmc->sd_clock_enabled) + return 0; + + //Recalibrate periodically for SDMMC1. + if (sdmmc->id == SDMMC_1 && sdmmc->no_sd) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc)); + + int should_disable_sd_clock = 0; + if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_get_clkcon(sdmmc); + sleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + } + + int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); + sleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + + return res; +} + +int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) +{ + if(sdmmc->id != SDMMC_1) + return 0; + + if (!sdmmc_setup_clock(sdmmc, 8)) + return 0; + + _sdmmc_get_clkcon(sdmmc); + + max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12); + + _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); + _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); + _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); + _sdmmc_get_clkcon(sdmmc); + sleep(5000); + + if (sdmmc->regs->hostctl2 & 8) + { + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_get_clkcon(sdmmc); + sleep(1000u); + if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) + return 1; + } + + return 0; +} diff --git a/ipl/sdmmc_driver.h b/ipl/sdmmc_driver.h new file mode 100755 index 0000000..cc9bc87 --- /dev/null +++ b/ipl/sdmmc_driver.h @@ -0,0 +1,107 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _SDMMC_DRIVER_H_ +#define _SDMMC_DRIVER_H_ + +#include "types.h" +#include "sdmmc_t210.h" + +/*! SDMMC controller IDs. */ +#define SDMMC_1 0 +#define SDMMC_2 1 +#define SDMMC_3 2 +#define SDMMC_4 3 + +/*! SDMMC power types. */ +#define SDMMC_POWER_OFF 0 +#define SDMMC_POWER_1_8 1 +#define SDMMC_POWER_3_3 2 + +/*! SDMMC bus widths. */ +#define SDMMC_BUS_WIDTH_1 0 +#define SDMMC_BUS_WIDTH_4 1 +#define SDMMC_BUS_WIDTH_8 2 + +/*! SDMMC response types. */ +#define SDMMC_RSP_TYPE_0 0 +#define SDMMC_RSP_TYPE_1 1 +#define SDMMC_RSP_TYPE_2 2 +#define SDMMC_RSP_TYPE_3 3 +#define SDMMC_RSP_TYPE_4 4 +#define SDMMC_RSP_TYPE_5 5 + +/*! SDMMC mask interrupt status. */ +#define SDMMC_MASKINT_MASKED 0 +#define SDMMC_MASKINT_NOERROR -1 +#define SDMMC_MASKINT_ERROR -2 + +/*! Helper for SWITCH command argument. */ +#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) + +/*! SDMMC controller context. */ +typedef struct _sdmmc_t +{ + t210_sdmmc_t *regs; + u32 id; + u32 divisor; + u32 clock_stopped; + int no_sd; + int sd_clock_enabled; + int venclkctl_set; + u32 venclkctl_tap; + u32 expected_rsp_type; + u32 dma_addr_next; + u32 rsp[4]; + u32 rsp3; +} sdmmc_t; + +/*! SDMMC command. */ +typedef struct _sdmmc_cmd_t +{ + u16 cmd; + u32 arg; + u32 rsp_type; + u32 check_busy; +} sdmmc_cmd_t; + +/*! SDMMC request. */ +typedef struct _sdmmc_req_t +{ + void *buf; + u32 blksize; + u32 num_sectors; + int is_write; + int is_multi_block; + int is_auto_cmd12; +} sdmmc_req_t; + +int sdmmc_get_voltage(sdmmc_t *sdmmc); +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); +void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); +void sdmmc_get_venclkctl(sdmmc_t *sdmmc); +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); +void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd); +int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type); +int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd); +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd); +void sdmmc_end(sdmmc_t *sdmmc); +void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy); +int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out); +int sdmmc_enable_low_voltage(sdmmc_t *sdmmc); + +#endif diff --git a/ipl/sdmmc_t210.h b/ipl/sdmmc_t210.h new file mode 100755 index 0000000..80862c2 --- /dev/null +++ b/ipl/sdmmc_t210.h @@ -0,0 +1,132 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _SDMMC_T210_H_ +#define _SDMMC_T210_H_ + +#include "types.h" + +#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1 +#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA +#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC +#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE +#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1 + +#define TEGRA_MMC_HOSTCTL_1BIT 0x00 +#define TEGRA_MMC_HOSTCTL_4BIT 0x02 +#define TEGRA_MMC_HOSTCTL_8BIT 0x20 + +#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1 +#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2 +#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4 +#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20 + +#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1 +#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2 +#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4 + +#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1 +#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2 +#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4 +#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0 +#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10 +#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20 + +#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8 +#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10 +#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20 + +#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3 +#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0 +#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1 +#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2 +#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3 + +#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1 +#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2 +#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8 +#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000 +#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000 + +#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20 + +typedef struct _t210_sdmmc_t +{ + vu32 sysad; + vu16 blksize; + vu16 blkcnt; + vu32 argument; + vu16 trnmod; + vu16 cmdreg; + vu32 rspreg0; + vu32 rspreg1; + vu32 rspreg2; + vu32 rspreg3; + vu32 bdata; + vu32 prnsts; + vu8 hostctl; + vu8 pwrcon; + vu8 blkgap; + vu8 wakcon; + vu16 clkcon; + vu8 timeoutcon; + vu8 swrst; + vu16 norintsts; + vu16 errintsts; + vu16 norintstsen; + vu16 errintstsen; + vu16 norintsigen; + vu16 errintsigen; + vu16 acmd12errsts; + vu16 hostctl2; + vu32 capareg; + vu32 capareg_1; + vu32 maxcurr; + vu8 res3[4]; + vu16 setacmd12err; + vu16 setinterr; + vu8 admaerr; + vu8 res4[3]; + vu32 admaaddr; + vu32 admaaddr_hi; + vu8 res5[156]; + vu16 slotintstatus; + vu16 hcver; + vu32 venclkctl; + vu32 venspictl; + vu32 venspiintsts; + vu32 venceatactl; + vu32 venbootctl; + vu32 venbootacktout; + vu32 venbootdattout; + vu32 vendebouncecnt; + vu32 venmiscctl; + vu32 res6[34]; + vu32 field_1AC; + vu32 field_1B0; + vu8 res7[8]; + vu32 field_1BC; + vu32 field_1C0; + vu32 field_1C4; + vu8 field_1C8[24]; + vu32 sdmemcmppadctl; + vu32 autocalcfg; + vu32 autocalintval; + vu32 autocalsts; + vu32 field_1F0; +} t210_sdmmc_t; + +#endif diff --git a/ipl/sdram.c b/ipl/sdram.c new file mode 100755 index 0000000..d8cbccb --- /dev/null +++ b/ipl/sdram.c @@ -0,0 +1,523 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "i2c.h" +#include "t210.h" +#include "mc.h" +#include "emc.h" +#include "pmc.h" +#include "util.h" +#include "fuse.h" +#include "max77620.h" +#include "sdram_param_t210.h" + +#define CONFIG_SDRAM_COMPRESS_CFG + +#ifdef CONFIG_SDRAM_COMPRESS_CFG +#include "lz.h" +#include "sdram_lz.inl" +#else +#include "sdram.inl" +#endif + +static u32 _get_sdram_id() +{ + return (fuse_read_odm(4) & 0x38) >> 3; +} + +static void _sdram_config(const sdram_params_t *params) +{ + PMC(0x45C) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF; + sleep(params->pmc_io_dpd3_req_wait); + + u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000; + PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000; + sleep(params->pmc_io_dpd4_req_wait); + PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF; + sleep(params->pmc_io_dpd4_req_wait); + PMC(APBDEV_PMC_WEAK_BIAS) = 0; + sleep(1); + + CLOCK(0x98) = params->pllm_setup_control; + CLOCK(0x9C) = 0; + CLOCK(0x90) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); + + u32 wait_end = TMR(0x10) + 300; + while (!(CLOCK(0x90) & 0x8000000)) + { + if (TMR(0x10) >= wait_end) + goto break_nosleep; + } + sleep(10); +break_nosleep: + + CLOCK(0x19C) = (params->mc_emem_arb_misc0 >> 11) & 0x10000 | params->emc_clock_source & 0xFFFEFFFF; + if (params->emc_clock_source_dll) + CLOCK(0x664) = params->emc_clock_source_dll; + if (params->clear_clock2_mc1) + CLOCK(0x44C) = 0x40000000; + CLOCK(0x328) = 0x2000001; + CLOCK(0x284) = 0x4000; + CLOCK(0x30C) = 0x2000001; + EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0; + EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1; + EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2; + EMC(EMC_TIMING_CONTROL) = 1; + sleep(1); + EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + if (params->emc_bct_spare2) + *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7; + EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0; + EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1; + EMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2; + EMC(EMC_CMD_MAPPING_CMD1_0) = params->emc_cmd_mapping_cmd1_0; + EMC(EMC_CMD_MAPPING_CMD1_1) = params->emc_cmd_mapping_cmd1_1; + EMC(EMC_CMD_MAPPING_CMD1_2) = params->emc_cmd_mapping_cmd1_2; + EMC(EMC_CMD_MAPPING_CMD2_0) = params->emc_cmd_mapping_cmd2_0; + EMC(EMC_CMD_MAPPING_CMD2_1) = params->emc_cmd_mapping_cmd2_1; + EMC(EMC_CMD_MAPPING_CMD2_2) = params->emc_cmd_mapping_cmd2_2; + EMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0; + EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1; + EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2; + EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte; + EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0; + EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1; + EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112 | 0x1EED1EED; + EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0; + EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1; + EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2; + EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3; + EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0; + EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1; + EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2; + EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3; + if (params->emc_bct_spare6) + *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl; + EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; + EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; + EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2; + EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; + EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; + EMC(EMC_AUTO_CAL_CONFIG5) = params->emc_auto_cal_config5; + EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6; + EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7; + EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; + EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term; + EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; + EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; + EMC(EMC_PMACRO_CMD_TX_DRV) = params->emc_pmacro_cmd_tx_drive; + EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common; + EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel; + EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; + EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; + EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; + EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; + EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0; + EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; + EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; + EMC(EMC_DQS_BRLSHFT_1) = params->emc_dqs_brlshft1; + EMC(EMC_CMD_BRLSHFT_0) = params->emc_cmd_brlshft0; + EMC(EMC_CMD_BRLSHFT_1) = params->emc_cmd_brlshft1; + EMC(EMC_CMD_BRLSHFT_2) = params->emc_cmd_brlshft2; + EMC(EMC_CMD_BRLSHFT_3) = params->emc_cmd_brlshft3; + EMC(EMC_QUSE_BRLSHFT_0) = params->emc_quse_brlshft0; + EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1; + EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2; + EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF | 0x1E401E40; + EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; + EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd; + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F; + EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd; + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = params->emc_pmacro_bg_bias_ctrl0; + EMC(EMC_PMACRO_DATA_PAD_RX_CTRL) = params->emc_pmacro_data_pad_rx_ctrl; + EMC(EMC_PMACRO_CMD_PAD_RX_CTRL) = params->emc_pmacro_cmd_pad_rx_ctrl; + EMC(EMC_PMACRO_DATA_PAD_TX_CTRL) = params->emc_pmacro_data_pad_tx_ctrl; + EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode; + EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode; + EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl; + EMC(EMC_CFG_3) = params->emc_cfg3; + EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0; + EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; + EMC(EMC_PMACRO_TX_PWRD_2) = params->emc_pmacro_tx_pwrd2; + EMC(EMC_PMACRO_TX_PWRD_3) = params->emc_pmacro_tx_pwrd3; + EMC(EMC_PMACRO_TX_PWRD_4) = params->emc_pmacro_tx_pwrd4; + EMC(EMC_PMACRO_TX_PWRD_5) = params->emc_pmacro_tx_pwrd5; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_0) = params->emc_pmacro_tx_sel_clk_src0; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_1) = params->emc_pmacro_tx_sel_clk_src1; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_2) = params->emc_pmacro_tx_sel_clk_src2; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_3) = params->emc_pmacro_tx_sel_clk_src3; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_4) = params->emc_pmacro_tx_sel_clk_src4; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5; + EMC(EMC_PMACRO_DDLL_BYPASS) = params->emc_pmacro_ddll_bypass; + EMC(EMC_PMACRO_DDLL_PWRD_0) = params->emc_pmacro_ddll_pwrd0; + EMC(EMC_PMACRO_DDLL_PWRD_1) = params->emc_pmacro_ddll_pwrd1; + EMC(EMC_PMACRO_DDLL_PWRD_2) = params->emc_pmacro_ddll_pwrd2; + EMC(EMC_PMACRO_CMD_CTRL_0) = params->emc_pmacro_cmd_ctrl0; + EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1; + EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2; + EMC(EMC_PMACRO_IB_VREF_DQ_0) = params->emc_pmacro_ib_vref_dq_0; + EMC(EMC_PMACRO_IB_VREF_DQ_1) = params->emc_pmacro_ib_vref_dq_1; + EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0; + EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1; + EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_3) = params->emc_pmacro_quse_ddll_rank0_3; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_4) = params->emc_pmacro_quse_ddll_rank0_4; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_5) = params->emc_pmacro_quse_ddll_rank0_5; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_0) = params->emc_pmacro_quse_ddll_rank1_0; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_1) = params->emc_pmacro_quse_ddll_rank1_1; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_2) = params->emc_pmacro_quse_ddll_rank1_2; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_3) = params->emc_pmacro_quse_ddll_rank1_3; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) = params->emc_pmacro_ob_ddll_long_dq_rank0_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4) = params->emc_pmacro_ob_ddll_long_dq_rank0_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) = params->emc_pmacro_ob_ddll_long_dq_rank0_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0) = params->emc_pmacro_ob_ddll_long_dq_rank1_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1) = params->emc_pmacro_ob_ddll_long_dq_rank1_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) = params->emc_pmacro_ob_ddll_long_dq_rank1_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ob_ddll_long_dqs_rank0_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4) = params->emc_pmacro_ob_ddll_long_dqs_rank0_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5) = params->emc_pmacro_ob_ddll_long_dqs_rank0_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ob_ddll_long_dqs_rank1_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ob_ddll_long_dqs_rank1_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ob_ddll_long_dqs_rank1_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ob_ddll_long_dqs_rank1_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4) = params->emc_pmacro_ob_ddll_long_dqs_rank1_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5) = params->emc_pmacro_ob_ddll_long_dqs_rank1_5; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ib_ddll_long_dqs_rank0_0; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ib_ddll_long_dqs_rank0_1; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ib_ddll_long_dqs_rank0_2; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ib_ddll_long_dqs_rank0_3; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ib_ddll_long_dqs_rank1_0; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3; + EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0; + EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1; + EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; + EMC(EMC_PMACRO_DDLL_LONG_CMD_3) = params->emc_pmacro_ddll_long_cmd_3; + EMC(EMC_PMACRO_DDLL_LONG_CMD_4) = params->emc_pmacro_ddll_long_cmd_4; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2; + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl & 1 | 0xE; + if (params->emc_bct_spare4) + *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; + EMC(EMC_TIMING_CONTROL) = 1; + MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; + MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi; + MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb; + MC(MC_VIDEO_PROTECT_VPR_OVERRIDE) = params->mc_video_protect_vpr_override; + MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1; + MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg; + MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0; + MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1; + MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask; + MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0; + MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1; + MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2; + MC(MC_EMEM_CFG) = params->mc_emem_cfg; + MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom; + MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi; + MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb; + MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom; + MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi; + MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb; + MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg; + MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req; + MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl; + MC(MC_EMEM_ARB_REFPB_BANK_CTRL) = params->emc_emem_arb_refpb_bank_ctrl; + MC(MC_EMEM_ARB_TIMING_RCD) = params->mc_emem_arb_timing_rcd; + MC(MC_EMEM_ARB_TIMING_RP) = params->mc_emem_arb_timing_rp; + MC(MC_EMEM_ARB_TIMING_RC) = params->mc_emem_arb_timing_rc; + MC(MC_EMEM_ARB_TIMING_RAS) = params->mc_emem_arb_timing_ras; + MC(MC_EMEM_ARB_TIMING_FAW) = params->mc_emem_arb_timing_faw; + MC(MC_EMEM_ARB_TIMING_RRD) = params->mc_emem_arb_timing_rrd; + MC(MC_EMEM_ARB_TIMING_RAP2PRE) = params->mc_emem_arb_timing_rap2pre; + MC(MC_EMEM_ARB_TIMING_WAP2PRE) = params->mc_emem_arb_timing_wap2pre; + MC(MC_EMEM_ARB_TIMING_R2R) = params->mc_emem_arb_timing_r2r; + MC(MC_EMEM_ARB_TIMING_W2W) = params->mc_emem_arb_timing_w2w; + MC(MC_EMEM_ARB_TIMING_CCDMW) = params->mc_emem_arb_timing_ccdmw; + MC(MC_EMEM_ARB_TIMING_R2W) = params->mc_emem_arb_timing_r2w; + MC(MC_EMEM_ARB_TIMING_W2R) = params->mc_emem_arb_timing_w2r; + MC(MC_EMEM_ARB_TIMING_RFCPB) = params->mc_emem_arb_timing_rfcpb; + MC(MC_EMEM_ARB_DA_TURNS) = params->mc_emem_arb_da_turns; + MC(MC_EMEM_ARB_DA_COVERS) = params->mc_emem_arb_da_covers; + MC(MC_EMEM_ARB_MISC0) = params->mc_emem_arb_misc0; + MC(MC_EMEM_ARB_MISC1) = params->mc_emem_arb_misc1; + MC(MC_EMEM_ARB_MISC2) = params->mc_emem_arb_misc2; + MC(MC_EMEM_ARB_RING1_THROTTLE) = params->mc_emem_arb_ring1_throttle; + MC(MC_EMEM_ARB_OVERRIDE) = params->mc_emem_arb_override; + MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1; + MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv; + MC(MC_DA_CONFIG0) = params->mc_da_cfg0; + MC(MC_TIMING_CONTROL) = 1; + MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + MC(MC_STAT_CONTROL) = params->mc_stat_control; + EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0; + EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1; + EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2; + EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0; + EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1; + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; + sleep(params->emc_auto_cal_wait); + if (params->emc_bct_spare8) + *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + EMC(EMC_CFG_2) = params->emc_cfg2; + EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe; + EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1; + EMC(EMC_CFG_PIPE_2) = params->emc_cfg_pipe2; + EMC(EMC_CMDQ) = params->emc_cmd_q; + EMC(EMC_MC2EMCQ) = params->emc_mc2emc_q; + EMC(EMC_MRS_WAIT_CNT) = params->emc_mrs_wait_cnt; + EMC(EMC_MRS_WAIT_CNT2) = params->emc_mrs_wait_cnt2; + EMC(EMC_FBIO_CFG5) = params->emc_fbio_cfg5; + EMC(EMC_RC) = params->emc_rc; + EMC(EMC_RFC) = params->emc_rfc; + EMC(EMC_RFCPB) = params->emc_rfc_pb; + EMC(EMC_REFCTRL2) = params->emc_ref_ctrl2; + EMC(EMC_RFC_SLR) = params->emc_rfc_slr; + EMC(EMC_RAS) = params->emc_ras; + EMC(EMC_RP) = params->emc_rp; + EMC(EMC_TPPD) = params->emc_tppd; + EMC(EMC_R2R) = params->emc_r2r; + EMC(EMC_W2W) = params->emc_w2w; + EMC(EMC_R2W) = params->emc_r2w; + EMC(EMC_W2R) = params->emc_w2r; + EMC(EMC_R2P) = params->emc_r2p; + EMC(EMC_W2P) = params->emc_w2p; + EMC(EMC_CCDMW) = params->emc_ccdmw; + EMC(EMC_RD_RCD) = params->emc_rd_rcd; + EMC(EMC_WR_RCD) = params->emc_wr_rcd; + EMC(EMC_RRD) = params->emc_rrd; + EMC(EMC_REXT) = params->emc_rext; + EMC(EMC_WEXT) = params->emc_wext; + EMC(EMC_WDV) = params->emc_wdv; + EMC(EMC_WDV_CHK) = params->emc_wdv_chk; + EMC(EMC_WSV) = params->emc_wsv; + EMC(EMC_WEV) = params->emc_wev; + EMC(EMC_WDV_MASK) = params->emc_wdv_mask; + EMC(EMC_WS_DURATION) = params->emc_ws_duration; + EMC(EMC_WE_DURATION) = params->emc_we_duration; + EMC(EMC_QUSE) = params->emc_quse; + EMC(EMC_QUSE_WIDTH) = params->emc_quse_width; + EMC(EMC_IBDLY) = params->emc_ibdly; + EMC(EMC_OBDLY) = params->emc_obdly; + EMC(EMC_EINPUT) = params->emc_einput; + EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration; + EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra; + EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width; + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl; + EMC(EMC_DBG) = params->emc_dbg; + EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 0; + EMC(EMC_QSAFE) = params->emc_qsafe; + EMC(EMC_RDV) = params->emc_rdv; + EMC(EMC_RDV_MASK) = params->emc_rdv_mask; + EMC(EMC_RDV_EARLY) = params->emc_rdv_early; + EMC(EMC_RDV_EARLY_MASK) = params->emc_rdv_early_mask; + EMC(EMC_QPOP) = params->emc_qpop; + EMC(EMC_REFRESH) = params->emc_refresh; + EMC(EMC_BURST_REFRESH_NUM) = params->emc_burst_refresh_num; + EMC(EMC_PRE_REFRESH_REQ_CNT) = params->emc_prerefresh_req_cnt; + EMC(EMC_PDEX2WR) = params->emc_pdex2wr; + EMC(EMC_PDEX2RD) = params->emc_pdex2rd; + EMC(EMC_PCHG2PDEN) = params->emc_pchg2pden; + EMC(EMC_ACT2PDEN) = params->emc_act2pden; + EMC(EMC_AR2PDEN) = params->emc_ar2pden; + EMC(EMC_RW2PDEN) = params->emc_rw2pden; + EMC(EMC_CKE2PDEN) = params->emc_cke2pden; + EMC(EMC_PDEX2CKE) = params->emc_pdex2che; + EMC(EMC_PDEX2MRR) = params->emc_pdex2mrr; + EMC(EMC_TXSR) = params->emc_txsr; + EMC(EMC_TXSRDLL) = params->emc_txsr_dll; + EMC(EMC_TCKE) = params->emc_tcke; + EMC(EMC_TCKESR) = params->emc_tckesr; + EMC(EMC_TPD) = params->emc_tpd; + EMC(EMC_TFAW) = params->emc_tfaw; + EMC(EMC_TRPAB) = params->emc_trpab; + EMC(EMC_TCLKSTABLE) = params->emc_tclkstable; + EMC(EMC_TCLKSTOP) = params->emc_tclkstop; + EMC(EMC_TREFBW) = params->emc_trefbw; + EMC(EMC_ODT_WRITE) = params->emc_odt_write; + EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll; + EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period; + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD; + EMC(EMC_CFG_RSV) = params->emc_cfg_rsv; + EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1; + EMC(EMC_PMC_SCRATCH2) = params->emc_pmc_scratch2; + EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3; + EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control; + EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen; + EMC(EMC_CFG) = params->emc_cfg & 0xE | 0x3C00000; + if (params->boot_rom_patch_control & 0x80000000) + { + *(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data; + MC(MC_TIMING_CONTROL) = 1; + } + PMC(0x45C) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000; + sleep(params->pmc_io_dpd3_req_wait); + if (!params->emc_auto_cal_interval) + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200; + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2; + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + if (params->memory_type == 2) + EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt; + if (params->memory_type == 3) + { + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + } + EMC(EMC_TIMING_CONTROL) = 1; + sleep(params->emc_timing_control_wait); + PMC(0x4E4) &= 0xFFF8007F; + sleep(params->pmc_ddr_ctrl_wait); + if (params->memory_type == 2) + { + EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + sleep(params->emc_pin_extra_wait + 200); + EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256; + sleep(params->emc_pin_extra_wait + 500); + } + if (params->memory_type == 3) + { + EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + sleep(params->emc_pin_extra_wait + 200); + EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256; + sleep(params->emc_pin_extra_wait + 2000); + } + EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101; + sleep(params->emc_pin_program_wait); + if (params->memory_type != 3) + EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; + if (params->memory_type == 1) + sleep(params->emc_pin_extra_wait + 200); + if (params->memory_type == 3) + { + if (params->emc_bct_spare10) + *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + EMC(EMC_MRW2) = params->emc_mrw2; + EMC(EMC_MRW) = params->emc_mrw1; + EMC(EMC_MRW3) = params->emc_mrw3; + EMC(EMC_MRW4) = params->emc_mrw4; + EMC(EMC_MRW6) = params->emc_mrw6; + EMC(EMC_MRW14) = params->emc_mrw14; + EMC(EMC_MRW8) = params->emc_mrw8; + EMC(EMC_MRW12) = params->emc_mrw12; + EMC(EMC_MRW9) = params->emc_mrw9; + EMC(EMC_MRW13) = params->emc_mrw13; + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; + sleep(params->emc_zcal_init_wait); + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + if (!(params->emc_dev_select & 2)) + { + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; + sleep(params->emc_zcal_init_wait); + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; + } + } + } + PMC(0x1D0) = params->pmc_ddr_cfg; + if (params->memory_type - 1 <= 2) + { + EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval; + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + if (params->emc_bct_spare12) + *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; + EMC(EMC_TIMING_CONTROL) = 1; + if (params->emc_extra_refresh_num) + EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30); + EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; + EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; + EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; + EMC(EMC_CFG) = params->emc_cfg; + EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq; + EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd; + EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; + EMC(EMC_TIMING_CONTROL) = 1; + EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16); + MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access; + MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access; + MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl; + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of MC registers. +} + +const void *sdram_get_params() +{ + //TODO: sdram_id should be in [0, 7]. + +#ifdef CONFIG_SDRAM_COMPRESS_CFG + u8 *buf = (u8 *)0x40030000; + LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); + return (const void *)&buf[sizeof(sdram_params_t) * _get_sdram_id()]; +#else + return _dram_cfgs[_get_sdram_id()]; +#endif +} + +void sdram_init() +{ + //TODO: sdram_id should be in [0,4]. + const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); + + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD_CFG2, 0x05); + i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_SD1, 40); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V + + PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; + sleep(params->pmc_vddp_sel_wait); + PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); + PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power; + PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + + if (params->emc_bct_spare0) + *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; + + _sdram_config(params); +} diff --git a/hwinit/sdram.h b/ipl/sdram.h old mode 100644 new mode 100755 similarity index 89% rename from hwinit/sdram.h rename to ipl/sdram.h index 45d2f2a..df86631 --- a/hwinit/sdram.h +++ b/ipl/sdram.h @@ -18,5 +18,7 @@ #define _SDRAM_H_ void sdram_init(); +const void *sdram_get_params(); +void sdram_lp0_save_params(const void *params); #endif diff --git a/hwinit/sdram.inl b/ipl/sdram.inl old mode 100644 new mode 100755 similarity index 71% rename from hwinit/sdram.inl rename to ipl/sdram.inl index 73e98d1..2ad630e --- a/hwinit/sdram.inl +++ b/ipl/sdram.inl @@ -819,10 +819,334 @@ static const u8 _dram_cfg_4[1896] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const u32 *_dram_cfgs[5] = { +static const u8 _dram_cfg_5[1896] = { + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, + 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, + 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, + 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, + 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, + 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, + 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, + 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, + 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, + 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, + 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, + 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, + 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, + 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, + 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, + 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, + 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, + 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, + 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, + 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, + 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x15, 0x00, 0x15, 0x00, + 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, 0x16, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, + 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, + 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, + 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, + 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, + 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, + 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, + 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, + 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 _dram_cfg_6[1896] = { + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, + 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, + 0xA6, 0xA6, 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, + 0xA1, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, + 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, + 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, + 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, + 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, 0x0B, 0x1D, 0x0D, + 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, + 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x0D, 0x08, + 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, + 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0D, 0x0C, + 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x04, 0x00, 0x01, 0x08, + 0x00, 0x00, 0x11, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0xCC, 0x00, + 0x0A, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, + 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, + 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, + 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00, + 0x2F, 0x00, 0x33, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, + 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, + 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x15, 0x00, 0x15, 0x00, + 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x16, 0x00, 0x16, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, + 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xFF, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, + 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, 0x64, 0x32, + 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, + 0xFF, 0xFF, 0xAF, 0x4F, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, + 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x81, 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x07, 0x00, + 0x02, 0x03, 0x07, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, + 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, + 0x28, 0x10, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xA3, 0x72, 0x0F, 0x0F, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0x16, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x1E, 0x40, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x24, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const u32 *_dram_cfgs[7] = { (const u32 *)_dram_cfg_0, (const u32 *)_dram_cfg_1, (const u32 *)_dram_cfg_2, (const u32 *)_dram_cfg_3, - (const u32 *)_dram_cfg_4 + (const u32 *)_dram_cfg_4, + (const u32 *)_dram_cfg_5, + (const u32 *)_dram_cfg_6 }; diff --git a/ipl/sdram_lp0.c b/ipl/sdram_lp0.c new file mode 100755 index 0000000..ecffab8 --- /dev/null +++ b/ipl/sdram_lp0.c @@ -0,0 +1,1034 @@ +/* + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "t210.h" +#include "pmc_t210_lp0.h" +#include "sdram_param_t210_lp0.h" + +/* + * This function reads SDRAM parameters from the common BCT format and + * writes them into PMC scratch registers (where the BootROM expects them + * on LP0 resume). + */ +void sdram_lp0_save_params(const void *params) +{ + const struct sdram_params *sdram = (const struct sdram_params *)params; + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + +#define pack(src, src_bits, dst, dst_bits) { \ + u32 mask = 0xffffffff >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \ + dst &= ~(mask << (0 ? dst_bits)); \ + dst |= ((src >> (0 ? src_bits)) & mask) << (0 ? dst_bits); \ +} + +#define s(param, src_bits, pmcreg, dst_bits) \ + pack(sdram->param, src_bits, pmc->pmcreg, dst_bits) + +#define c(value, pmcreg, dst_bits) \ + pack(value, (1 ? dst_bits) - (0 ? dst_bits) : 0, pmc->pmcreg, dst_bits) + +/* 32 bits version of s macro */ +#define s32(param, pmcreg) pmc->pmcreg = sdram->param + +/* 32 bits version c macro */ +#define c32(value, pmcreg) pmc->pmcreg = value + + s(EmcClockSource, 7:0, scratch6, 15:8); + s(EmcClockSourceDll, 7:0, scratch6, 23:16); + s(EmcClockSource, 31:29, scratch6, 26:24); + s(EmcClockSourceDll, 31:29, scratch6, 29:27); + s(EmcClockSourceDll, 11:10, scratch6, 31:30); + s(ClkRstControllerPllmMisc2Override, 9:8, scratch7, 1:0); + s(ClkRstControllerPllmMisc2Override, 2:1, scratch7, 3:2); + s(EmcZqCalLpDdr4WarmBoot, 31:30, scratch7, 5:4); + s(EmcClockSource, 15:15, scratch7, 6:6); + s(EmcClockSource, 26:26, scratch7, 7:7); + s(EmcClockSource, 20:20, scratch7, 8:8); + s(EmcClockSource, 19:19, scratch7, 9:9); + s(ClkRstControllerPllmMisc2Override, 13:13, scratch7, 10:10); + s(ClkRstControllerPllmMisc2Override, 12:12, scratch7, 11:11); + s(ClkRstControllerPllmMisc2Override, 11:11, scratch7, 12:12); + s(ClkRstControllerPllmMisc2Override, 10:10, scratch7, 13:13); + s(ClkRstControllerPllmMisc2Override, 5:5, scratch7, 14:14); + s(ClkRstControllerPllmMisc2Override, 4:4, scratch7, 15:15); + s(ClkRstControllerPllmMisc2Override, 3:3, scratch7, 16:16); + s(ClkRstControllerPllmMisc2Override, 0:0, scratch7, 17:17); + s(EmcZqCalLpDdr4WarmBoot, 1:0, scratch7, 19:18); + s(EmcZqCalLpDdr4WarmBoot, 4:4, scratch7, 20:20); + s(EmcOdtWrite, 5:0, scratch7, 26:21); + s(EmcOdtWrite, 11:8, scratch7, 30:27); + s(EmcOdtWrite, 31:31, scratch7, 31:31); + s(EmcFdpdCtrlCmdNoRamp, 0:0, scratch13, 30:30); + s(EmcCfgPipeClk, 0:0, scratch13, 31:31); + s(McEmemArbMisc2, 0:0, scratch14, 30:30); + s(McDaCfg0, 0:0, scratch14, 31:31); + s(EmcQRst, 6:0, scratch15, 26:20); + s(EmcQRst, 20:16, scratch15, 31:27); + s(EmcPmacroCmdTxDrv, 5:0, scratch16, 25:20); + s(EmcPmacroCmdTxDrv, 13:8, scratch16, 31:26); + s(EmcPmacroAutocalCfg0, 2:0, scratch17, 22:20); + s(EmcPmacroAutocalCfg0, 10:8, scratch17, 25:23); + s(EmcPmacroAutocalCfg0, 18:16, scratch17, 28:26); + s(EmcPmacroAutocalCfg0, 26:24, scratch17, 31:29); + s(EmcPmacroAutocalCfg1, 2:0, scratch18, 22:20); + s(EmcPmacroAutocalCfg1, 10:8, scratch18, 25:23); + s(EmcPmacroAutocalCfg1, 18:16, scratch18, 28:26); + s(EmcPmacroAutocalCfg1, 26:24, scratch18, 31:29); + s(EmcPmacroAutocalCfg2, 2:0, scratch19, 22:20); + s(EmcPmacroAutocalCfg2, 10:8, scratch19, 25:23); + s(EmcPmacroAutocalCfg2, 18:16, scratch19, 28:26); + s(EmcPmacroAutocalCfg2, 26:24, scratch19, 31:29); + s32(EmcCfgRsv,scratch22); + s32(EmcAutoCalConfig, scratch23); + s32(EmcAutoCalVrefSel0, scratch24); + s32(EmcPmacroBrickCtrlRfu1, scratch25); + s32(EmcPmacroBrickCtrlRfu2, scratch26); + s32(EmcPmcScratch1, scratch27); + s32(EmcPmcScratch2, scratch28); + s32(EmcPmcScratch3, scratch29); + s32(McEmemArbDaTurns, scratch30); + s(EmcFbioSpare, 31:24, scratch58, 7:0); + s(EmcFbioSpare, 23:16, scratch58, 15:8); + s(EmcFbioSpare, 15:8, scratch58, 23:16); + s(EmcFbioSpare, 7:2, scratch58, 29:24); + s(EmcFbioSpare, 0:0, scratch58, 30:30); + s(EmcDllCfg0, 29:0, scratch59, 29:0); + s(EmcPmacroDdllBypass, 11:0, scratch60, 11:0); + s(EmcPmacroDdllBypass, 27:13, scratch60, 26:12); + s(EmcPmacroDdllBypass, 31:29, scratch60, 29:27); + s(McEmemArbMisc0, 14:0, scratch61, 14:0); + s(McEmemArbMisc0, 30:16, scratch61, 29:15); + s(EmcFdpdCtrlCmd, 16:0, scratch62, 16:0); + s(EmcFdpdCtrlCmd, 31:20, scratch62, 28:17); + s(EmcAutoCalConfig2, 27:0, scratch63, 27:0); + s(EmcBurstRefreshNum, 3:0, scratch63, 31:28); + s(EmcPmacroZctrl, 27:0, scratch64, 27:0); + s(EmcTppd, 3:0, scratch64, 31:28); + s(EmcCfgDigDll, 10:0, scratch65, 10:0); + s(EmcCfgDigDll, 25:12, scratch65, 24:11); + s(EmcCfgDigDll, 27:27, scratch65, 25:25); + s(EmcCfgDigDll, 31:30, scratch65, 27:26); + s(EmcR2r, 3:0, scratch65, 31:28); + s(EmcFdpdCtrlDq, 16:0, scratch66, 16:0); + s(EmcFdpdCtrlDq, 28:20, scratch66, 25:17); + s(EmcFdpdCtrlDq, 31:30, scratch66, 27:26); + s(EmcW2w, 3:0, scratch66, 31:28); + s(EmcPmacroTxPwrd4, 13:0, scratch67, 13:0); + s(EmcPmacroTxPwrd4, 29:16, scratch67, 27:14); + s(EmcPmacroCommonPadTxCtrl, 3:0, scratch67, 31:28); + s(EmcPmacroTxPwrd5, 13:0, scratch68, 13:0); + s(EmcPmacroTxPwrd5, 29:16, scratch68, 27:14); + s(EmcPmacroDdllPwrd0, 4:0, scratch69, 4:0); + s(EmcPmacroDdllPwrd0, 12:6, scratch69, 11:5); + s(EmcPmacroDdllPwrd0, 20:14, scratch69, 18:12); + s(EmcPmacroDdllPwrd0, 28:22, scratch69, 25:19); + s(EmcPmacroDdllPwrd0, 31:30, scratch69, 27:26); + s(EmcCfg, 4:4, scratch69, 31:31); + s(EmcPmacroDdllPwrd1, 4:0, scratch70, 4:0); + s(EmcPmacroDdllPwrd1, 12:6, scratch70, 11:5); + s(EmcPmacroDdllPwrd1, 20:14, scratch70, 18:12); + s(EmcPmacroDdllPwrd1, 28:22, scratch70, 25:19); + s(EmcPmacroDdllPwrd1, 31:30, scratch70, 27:26); + s(EmcCfg, 5:5, scratch70, 31:31); + s(EmcPmacroDdllPwrd2, 4:0, scratch71, 4:0); + s(EmcPmacroDdllPwrd2, 12:6, scratch71, 11:5); + s(EmcPmacroDdllPwrd2, 20:14, scratch71, 18:12); + s(EmcPmacroDdllPwrd2, 28:22, scratch71, 25:19); + s(EmcPmacroDdllPwrd2, 31:30, scratch71, 27:26); + s(EmcFbioCfg5, 23:20, scratch71, 31:28); + s(EmcPmacroIbVrefDq_0, 6:0, scratch72, 6:0); + s(EmcPmacroIbVrefDq_0, 14:8, scratch72, 13:7); + s(EmcPmacroIbVrefDq_0, 22:16, scratch72, 20:14); + s(EmcPmacroIbVrefDq_0, 30:24, scratch72, 27:21); + s(EmcFbioCfg5, 15:13, scratch72, 30:28); + s(EmcCfg, 6:6, scratch72, 31:31); + s(EmcPmacroIbVrefDq_1, 6:0, scratch73, 6:0); + s(EmcPmacroIbVrefDq_1, 14:8, scratch73, 13:7); + s(EmcPmacroIbVrefDq_1, 22:16, scratch73, 20:14); + s(EmcPmacroIbVrefDq_1, 30:24, scratch73, 27:21); + s(EmcCfg2, 5:3, scratch73, 30:28); + s(EmcCfg, 7:7, scratch73, 31:31); + s(EmcPmacroIbVrefDqs_0, 6:0, scratch74, 6:0); + s(EmcPmacroIbVrefDqs_0, 14:8, scratch74, 13:7); + s(EmcPmacroIbVrefDqs_0, 22:16, scratch74, 20:14); + s(EmcPmacroIbVrefDqs_0, 30:24, scratch74, 27:21); + s(EmcCfg, 17:16, scratch74, 29:28); + s(EmcFbioCfg5, 1:0, scratch74, 31:30); + s(EmcPmacroIbVrefDqs_1, 6:0, scratch75, 6:0); + s(EmcPmacroIbVrefDqs_1, 14:8, scratch75, 13:7); + s(EmcPmacroIbVrefDqs_1, 22:16, scratch75, 20:14); + s(EmcPmacroIbVrefDqs_1, 30:24, scratch75, 27:21); + s(EmcFbioCfg5, 3:2, scratch75, 29:28); + s(EmcCfg2, 27:26, scratch75, 31:30); + s(EmcPmacroDdllShortCmd_0, 6:0, scratch76, 6:0); + s(EmcPmacroDdllShortCmd_0, 14:8, scratch76, 13:7); + s(EmcPmacroDdllShortCmd_0, 22:16, scratch76, 20:14); + s(EmcPmacroDdllShortCmd_0, 30:24, scratch76, 27:21); + s(EmcPmacroCmdPadTxCtrl, 3:2, scratch76, 29:28); + s(EmcPmacroCmdPadTxCtrl, 7:6, scratch76, 31:30); + s(EmcPmacroDdllShortCmd_1, 6:0, scratch77, 6:0); + s(EmcPmacroDdllShortCmd_1, 14:8, scratch77, 13:7); + s(EmcPmacroDdllShortCmd_1, 22:16, scratch77, 20:14); + s(EmcPmacroDdllShortCmd_1, 30:24, scratch77, 27:21); + s(EmcPmacroCmdPadTxCtrl, 11:10, scratch77, 29:28); + s(EmcPmacroCmdPadTxCtrl, 15:14, scratch77, 31:30); + s(EmcAutoCalChannel, 5:0, scratch78, 5:0); + s(EmcAutoCalChannel, 11:8, scratch78, 9:6); + s(EmcAutoCalChannel, 27:16, scratch78, 21:10); + s(EmcAutoCalChannel, 31:29, scratch78, 24:22); + s(EmcConfigSampleDelay, 6:0, scratch78, 31:25); + s(EmcPmacroRxTerm, 5:0, scratch79, 5:0); + s(EmcPmacroRxTerm, 13:8, scratch79, 11:6); + s(EmcPmacroRxTerm, 21:16, scratch79, 17:12); + s(EmcPmacroRxTerm, 29:24, scratch79, 23:18); + s(EmcRc, 7:0, scratch79, 31:24); + s(EmcPmacroDqTxDrv, 5:0, scratch80, 5:0); + s(EmcPmacroDqTxDrv, 13:8, scratch80, 11:6); + s(EmcPmacroDqTxDrv, 21:16, scratch80, 17:12); + s(EmcPmacroDqTxDrv, 29:24, scratch80, 23:18); + s(EmcSelDpdCtrl, 5:2, scratch80, 27:24); + s(EmcSelDpdCtrl, 8:8, scratch80, 28:28); + s(EmcSelDpdCtrl, 18:16, scratch80, 31:29); + s(EmcPmacroCaTxDrv, 5:0, scratch81, 5:0); + s(EmcPmacroCaTxDrv, 13:8, scratch81, 11:6); + s(EmcPmacroCaTxDrv, 21:16, scratch81, 17:12); + s(EmcPmacroCaTxDrv, 29:24, scratch81, 23:18); + s(EmcObdly, 5:0, scratch81, 29:24); + s(EmcObdly, 29:28, scratch81, 31:30); + s(EmcZcalInterval, 23:10, scratch82, 13:0); + s(EmcZcalInterval, 9:0, scratch82, 23:14); + s(EmcPmacroCmdRxTermMode, 1:0, scratch82, 25:24); + s(EmcPmacroCmdRxTermMode, 5:4, scratch82, 27:26); + s(EmcPmacroCmdRxTermMode, 9:8, scratch82, 29:28); + s(EmcPmacroCmdRxTermMode, 13:12, scratch82, 31:30); + s(EmcDataBrlshft0, 23:0, scratch83, 23:0); + s(EmcPmacroDataRxTermMode, 1:0, scratch83, 25:24); + s(EmcPmacroDataRxTermMode, 5:4, scratch83, 27:26); + s(EmcPmacroDataRxTermMode, 9:8, scratch83, 29:28); + s(EmcPmacroDataRxTermMode, 13:12, scratch83, 31:30); + s(EmcDataBrlshft1, 23:0, scratch84, 23:0); + s(McEmemArbTimingRc, 7:0, scratch84, 31:24); + s(EmcDqsBrlshft0, 23:0, scratch85, 23:0); + s(McEmemArbRsv, 7:0, scratch85, 31:24); + s(EmcDqsBrlshft1, 23:0, scratch86, 23:0); + s(EmcCfgPipe2, 11:0, scratch87, 11:0); + s(EmcCfgPipe2, 27:16, scratch87, 23:12); + s(EmcCfgPipe1, 11:0, scratch88, 11:0); + s(EmcCfgPipe1, 27:16, scratch88, 23:12); + s(EmcPmacroCmdCtrl0, 5:0, scratch89, 5:0); + s(EmcPmacroCmdCtrl0, 13:8, scratch89, 11:6); + s(EmcPmacroCmdCtrl0, 21:16, scratch89, 17:12); + s(EmcPmacroCmdCtrl0, 29:24, scratch89, 23:18); + s(EmcPmacroCmdCtrl1, 5:0, scratch90, 5:0); + s(EmcPmacroCmdCtrl1, 13:8, scratch90, 11:6); + s(EmcPmacroCmdCtrl1, 21:16, scratch90, 17:12); + s(EmcPmacroCmdCtrl1, 29:24, scratch90, 23:18); + s(EmcRas, 6:0, scratch90, 30:24); + s(EmcCfg, 8:8, scratch90, 31:31); + s(EmcPmacroVttgenCtrl2, 23:0, scratch91, 23:0); + s(EmcW2p, 6:0, scratch91, 30:24); + s(EmcCfg, 9:9, scratch91, 31:31); + s(EmcPmacroCmdPadRxCtrl, 2:0, scratch92, 2:0); + s(EmcPmacroCmdPadRxCtrl, 5:4, scratch92, 4:3); + s(EmcPmacroCmdPadRxCtrl, 10:8, scratch92, 7:5); + s(EmcPmacroCmdPadRxCtrl, 22:12, scratch92, 18:8); + s(EmcPmacroCmdPadRxCtrl, 28:24, scratch92, 23:19); + s(EmcQSafe, 6:0, scratch92, 30:24); + s(EmcCfg, 18:18, scratch92, 31:31); + s(EmcPmacroDataPadRxCtrl, 2:0, scratch93, 2:0); + s(EmcPmacroDataPadRxCtrl, 5:4, scratch93, 4:3); + s(EmcPmacroDataPadRxCtrl, 10:8, scratch93, 7:5); + s(EmcPmacroDataPadRxCtrl, 22:12, scratch93, 18:8); + s(EmcPmacroDataPadRxCtrl, 28:24, scratch93, 23:19); + s(EmcRdv, 6:0, scratch93, 30:24); + s(EmcCfg, 21:21, scratch93, 31:31); + s(McEmemArbDaCovers, 23:0, scratch94, 23:0); + s(EmcRw2Pden, 6:0, scratch94, 30:24); + s(EmcCfg, 22:22, scratch94, 31:31); + s(EmcPmacroCmdCtrl2, 5:0, scratch95, 5:0); + s(EmcPmacroCmdCtrl2, 13:9, scratch95, 10:6); + s(EmcPmacroCmdCtrl2, 21:16, scratch95, 16:11); + s(EmcPmacroCmdCtrl2, 29:24, scratch95, 22:17); + s(EmcRfcPb, 8:0, scratch95, 31:23); + s(EmcPmacroQuseDdllRank0_0, 10:0, scratch96, 10:0); + s(EmcPmacroQuseDdllRank0_0, 26:16, scratch96, 21:11); + s(EmcCfgUpdate, 2:0, scratch96, 24:22); + s(EmcCfgUpdate, 10:8, scratch96, 27:25); + s(EmcCfgUpdate, 31:28, scratch96, 31:28); + s(EmcPmacroQuseDdllRank0_1, 10:0, scratch97, 10:0); + s(EmcPmacroQuseDdllRank0_1, 26:16, scratch97, 21:11); + s(EmcRfc, 9:0, scratch97, 31:22); + s(EmcPmacroQuseDdllRank0_2, 10:0, scratch98, 10:0); + s(EmcPmacroQuseDdllRank0_2, 26:16, scratch98, 21:11); + s(EmcTxsr, 9:0, scratch98, 31:22); + s(EmcPmacroQuseDdllRank0_3, 10:0, scratch99, 10:0); + s(EmcPmacroQuseDdllRank0_3, 26:16, scratch99, 21:11); + s(EmcMc2EmcQ, 2:0, scratch99, 24:22); + s(EmcMc2EmcQ, 10:8, scratch99, 27:25); + s(EmcMc2EmcQ, 27:24, scratch99, 31:28); + s(EmcPmacroQuseDdllRank0_4, 10:0, scratch100, 10:0); + s(EmcPmacroQuseDdllRank0_4, 26:16, scratch100, 21:11); + s(McEmemArbRing1Throttle, 4:0, scratch100, 26:22); + s(McEmemArbRing1Throttle, 20:16, scratch100, 31:27); + s(EmcPmacroQuseDdllRank0_5, 10:0, scratch101, 10:0); + s(EmcPmacroQuseDdllRank0_5, 26:16, scratch101, 21:11); + s(EmcPmacroQuseDdllRank1_0, 10:0, scratch102, 10:0); + s(EmcPmacroQuseDdllRank1_0, 26:16, scratch102, 21:11); + s(EmcAr2Pden, 8:0, scratch102, 30:22); + s(EmcCfg, 23:23, scratch102, 31:31); + s(EmcPmacroQuseDdllRank1_1, 10:0, scratch103, 10:0); + s(EmcPmacroQuseDdllRank1_1, 26:16, scratch103, 21:11); + s(EmcRfcSlr, 8:0, scratch103, 30:22); + s(EmcCfg, 24:24, scratch103, 31:31); + s(EmcPmacroQuseDdllRank1_2, 10:0, scratch104, 10:0); + s(EmcPmacroQuseDdllRank1_2, 26:16, scratch104, 21:11); + s(EmcIbdly, 6:0, scratch104, 28:22); + s(EmcIbdly, 29:28, scratch104, 30:29); + s(EmcCfg, 25:25, scratch104, 31:31); + s(EmcPmacroQuseDdllRank1_3, 10:0, scratch105, 10:0); + s(EmcPmacroQuseDdllRank1_3, 26:16, scratch105, 21:11); + s(McEmemArbTimingRFCPB, 8:0, scratch105, 30:22); + s(EmcCfg, 26:26, scratch105, 31:31); + s(EmcPmacroQuseDdllRank1_4, 10:0, scratch106, 10:0); + s(EmcPmacroQuseDdllRank1_4, 26:16, scratch106, 21:11); + s(EmcTfaw, 6:0, scratch106, 28:22); + s(EmcPmacroDataPadTxCtrl, 3:2, scratch106, 30:29); + s(EmcCfg, 28:28, scratch106, 31:31); + s(EmcPmacroQuseDdllRank1_5, 10:0, scratch107, 10:0); + s(EmcPmacroQuseDdllRank1_5, 26:16, scratch107, 21:11); + s(EmcTClkStable, 6:0, scratch107, 28:22); + s(EmcPmacroDataPadTxCtrl, 7:6, scratch107, 30:29); + s(EmcCfg, 29:29, scratch107, 31:31); + s(EmcPmacroObDdllLongDqRank0_0, 10:0, scratch108, 10:0); + s(EmcPmacroObDdllLongDqRank0_0, 26:16, scratch108, 21:11); + s(EmcPdex2Mrr, 6:0, scratch108, 28:22); + s(EmcPmacroDataPadTxCtrl, 11:10, scratch108, 30:29); + s(EmcCfg, 30:30, scratch108, 31:31); + s(EmcPmacroObDdllLongDqRank0_1, 10:0, scratch109, 10:0); + s(EmcPmacroObDdllLongDqRank0_1, 26:16, scratch109, 21:11); + s(EmcRdvMask, 6:0, scratch109, 28:22); + s(EmcPmacroDataPadTxCtrl, 15:14, scratch109, 30:29); + s(EmcCfg, 31:31, scratch109, 31:31); + s(EmcPmacroObDdllLongDqRank0_2, 10:0, scratch110, 10:0); + s(EmcPmacroObDdllLongDqRank0_2, 26:16, scratch110, 21:11); + s(EmcRdvEarlyMask, 6:0, scratch110, 28:22); + s(EmcFbioCfg5, 4:4, scratch110, 29:29); + s(EmcFbioCfg5, 8:8, scratch110, 30:30); + s(EmcFbioCfg5, 10:10, scratch110, 31:31); + s(EmcPmacroObDdllLongDqRank0_3, 10:0, scratch111, 10:0); + s(EmcPmacroObDdllLongDqRank0_3, 26:16, scratch111, 21:11); + s(EmcRdvEarly, 6:0, scratch111, 28:22); + s(EmcFbioCfg5, 12:12, scratch111, 29:29); + s(EmcFbioCfg5, 25:24, scratch111, 31:30); + s(EmcPmacroObDdllLongDqRank0_4, 10:0, scratch112, 10:0); + s(EmcPmacroObDdllLongDqRank0_4, 26:16, scratch112, 21:11); + s(EmcPmacroDdllShortCmd_2, 6:0, scratch112, 28:22); + s(EmcFbioCfg5, 28:26, scratch112, 31:29); + s(EmcPmacroObDdllLongDqRank0_5, 10:0, scratch113, 10:0); + s(EmcPmacroObDdllLongDqRank0_5, 26:16, scratch113, 21:11); + s(McEmemArbTimingRp, 6:0, scratch113, 28:22); + s(EmcFbioCfg5, 31:30, scratch113, 30:29); + s(EmcCfg2, 0:0, scratch113, 31:31); + s(EmcPmacroObDdllLongDqRank1_0, 10:0, scratch114, 10:0); + s(EmcPmacroObDdllLongDqRank1_0, 26:16, scratch114, 21:11); + s(McEmemArbTimingRas, 6:0, scratch114, 28:22); + s(EmcCfg2, 2:1, scratch114, 30:29); + s(EmcCfg2, 7:7, scratch114, 31:31); + s(EmcPmacroObDdllLongDqRank1_1, 10:0, scratch115, 10:0); + s(EmcPmacroObDdllLongDqRank1_1, 26:16, scratch115, 21:11); + s(McEmemArbTimingFaw, 6:0, scratch115, 28:22); + s(EmcCfg2, 11:10, scratch115, 30:29); + s(EmcCfg2, 14:14, scratch115, 31:31); + s(EmcPmacroObDdllLongDqRank1_2, 10:0, scratch123, 10:0); + s(EmcPmacroObDdllLongDqRank1_2, 26:16, scratch123, 21:11); + s(McEmemArbTimingRap2Pre, 6:0, scratch123, 28:22); + s(EmcCfg2, 16:15, scratch123, 30:29); + s(EmcCfg2, 20:20, scratch123, 31:31); + s(EmcPmacroObDdllLongDqRank1_3, 10:0, scratch124, 10:0); + s(EmcPmacroObDdllLongDqRank1_3, 26:16, scratch124, 21:11); + s(McEmemArbTimingWap2Pre, 6:0, scratch124, 28:22); + s(EmcCfg2, 24:22, scratch124, 31:29); + s(EmcPmacroObDdllLongDqRank1_4, 10:0, scratch125, 10:0); + s(EmcPmacroObDdllLongDqRank1_4, 26:16, scratch125, 21:11); + s(McEmemArbTimingR2W, 6:0, scratch125, 28:22); + s(EmcCfg2, 25:25, scratch125, 29:29); + s(EmcCfg2, 29:28, scratch125, 31:30); + s(EmcPmacroObDdllLongDqRank1_5, 10:0, scratch126, 10:0); + s(EmcPmacroObDdllLongDqRank1_5, 26:16, scratch126, 21:11); + s(McEmemArbTimingW2R, 6:0, scratch126, 28:22); + s(EmcCfg2, 31:30, scratch126, 30:29); + s(EmcCfgPipe, 0:0, scratch126, 31:31); + s(EmcPmacroObDdllLongDqsRank0_0, 10:0, scratch127, 10:0); + s(EmcPmacroObDdllLongDqsRank0_0, 26:16, scratch127, 21:11); + s(EmcRp, 5:0, scratch127, 27:22); + s(EmcCfgPipe, 4:1, scratch127, 31:28); + s(EmcPmacroObDdllLongDqsRank0_1, 10:0, scratch128, 10:0); + s(EmcPmacroObDdllLongDqsRank0_1, 26:16, scratch128, 21:11); + s(EmcR2w, 5:0, scratch128, 27:22); + s(EmcCfgPipe, 8:5, scratch128, 31:28); + s(EmcPmacroObDdllLongDqsRank0_2, 10:0, scratch129, 10:0); + s(EmcPmacroObDdllLongDqsRank0_2, 26:16, scratch129, 21:11); + s(EmcW2r, 5:0, scratch129, 27:22); + s(EmcCfgPipe, 11:9, scratch129, 30:28); + s(EmcCfgPipe, 16:16, scratch129, 31:31); + s(EmcPmacroObDdllLongDqsRank0_3, 10:0, scratch130, 10:0); + s(EmcPmacroObDdllLongDqsRank0_3, 26:16, scratch130, 21:11); + s(EmcR2p, 5:0, scratch130, 27:22); + s(EmcCfgPipe, 20:17, scratch130, 31:28); + s(EmcPmacroObDdllLongDqsRank0_4, 10:0, scratch131, 10:0); + s(EmcPmacroObDdllLongDqsRank0_4, 26:16, scratch131, 21:11); + s(EmcCcdmw, 5:0, scratch131, 27:22); + s(EmcCfgPipe, 24:21, scratch131, 31:28); + s(EmcPmacroObDdllLongDqsRank0_5, 10:0, scratch132, 10:0); + s(EmcPmacroObDdllLongDqsRank0_5, 26:16, scratch132, 21:11); + s(EmcRdRcd, 5:0, scratch132, 27:22); + s(EmcCfgPipe, 27:25, scratch132, 30:28); + s(EmcPmacroTxPwrd0, 0:0, scratch132, 31:31); + s(EmcPmacroObDdllLongDqsRank1_0, 10:0, scratch133, 10:0); + s(EmcPmacroObDdllLongDqsRank1_0, 26:16, scratch133, 21:11); + s(EmcWrRcd, 5:0, scratch133, 27:22); + s(EmcPmacroTxPwrd0, 4:1, scratch133, 31:28); + s(EmcPmacroObDdllLongDqsRank1_1, 10:0, scratch134, 10:0); + s(EmcPmacroObDdllLongDqsRank1_1, 26:16, scratch134, 21:11); + s(EmcWdv, 5:0, scratch134, 27:22); + s(EmcPmacroTxPwrd0, 8:5, scratch134, 31:28); + s(EmcPmacroObDdllLongDqsRank1_2, 10:0, scratch135, 10:0); + s(EmcPmacroObDdllLongDqsRank1_2, 26:16, scratch135, 21:11); + s(EmcQUse, 5:0, scratch135, 27:22); + s(EmcPmacroTxPwrd0, 12:9, scratch135, 31:28); + s(EmcPmacroObDdllLongDqsRank1_3, 10:0, scratch136, 10:0); + s(EmcPmacroObDdllLongDqsRank1_3, 26:16, scratch136, 21:11); + s(EmcPdEx2Wr, 5:0, scratch136, 27:22); + s(EmcPmacroTxPwrd0, 13:13, scratch136, 28:28); + s(EmcPmacroTxPwrd0, 18:16, scratch136, 31:29); + s(EmcPmacroObDdllLongDqsRank1_4, 10:0, scratch137, 10:0); + s(EmcPmacroObDdllLongDqsRank1_4, 26:16, scratch137, 21:11); + s(EmcPdEx2Rd, 5:0, scratch137, 27:22); + s(EmcPmacroTxPwrd0, 22:19, scratch137, 31:28); + s(EmcPmacroObDdllLongDqsRank1_5, 10:0, scratch138, 10:0); + s(EmcPmacroObDdllLongDqsRank1_5, 26:16, scratch138, 21:11); + s(EmcPdex2Cke, 5:0, scratch138, 27:22); + s(EmcPmacroTxPwrd0, 26:23, scratch138, 31:28); + s(EmcPmacroIbDdllLongDqsRank0_0, 10:0, scratch139, 10:0); + s(EmcPmacroIbDdllLongDqsRank0_0, 26:16, scratch139, 21:11); + s(EmcPChg2Pden, 5:0, scratch139, 27:22); + s(EmcPmacroTxPwrd0, 29:27, scratch139, 30:28); + s(EmcPmacroTxPwrd1, 0:0, scratch139, 31:31); + s(EmcPmacroIbDdllLongDqsRank0_1, 10:0, scratch140, 10:0); + s(EmcPmacroIbDdllLongDqsRank0_1, 26:16, scratch140, 21:11); + s(EmcAct2Pden, 5:0, scratch140, 27:22); + s(EmcPmacroTxPwrd1, 4:1, scratch140, 31:28); + s(EmcPmacroIbDdllLongDqsRank0_2, 10:0, scratch141, 10:0); + s(EmcPmacroIbDdllLongDqsRank0_2, 26:16, scratch141, 21:11); + s(EmcCke2Pden, 5:0, scratch141, 27:22); + s(EmcPmacroTxPwrd1, 8:5, scratch141, 31:28); + s(EmcPmacroIbDdllLongDqsRank0_3, 10:0, scratch142, 10:0); + s(EmcPmacroIbDdllLongDqsRank0_3, 26:16, scratch142, 21:11); + s(EmcTcke, 5:0, scratch142, 27:22); + s(EmcPmacroTxPwrd1, 12:9, scratch142, 31:28); + s(EmcPmacroIbDdllLongDqsRank1_0, 10:0, scratch143, 10:0); + s(EmcPmacroIbDdllLongDqsRank1_0, 26:16, scratch143, 21:11); + s(EmcTrpab, 5:0, scratch143, 27:22); + s(EmcPmacroTxPwrd1, 13:13, scratch143, 28:28); + s(EmcPmacroTxPwrd1, 18:16, scratch143, 31:29); + s(EmcPmacroIbDdllLongDqsRank1_1, 10:0, scratch144, 10:0); + s(EmcPmacroIbDdllLongDqsRank1_1, 26:16, scratch144, 21:11); + s(EmcClkenOverride, 3:1, scratch144, 24:22); + s(EmcClkenOverride, 8:6, scratch144, 27:25); + s(EmcPmacroTxPwrd1, 22:19, scratch144, 31:28); + s(EmcPmacroIbDdllLongDqsRank1_2, 10:0, scratch145, 10:0); + s(EmcPmacroIbDdllLongDqsRank1_2, 26:16, scratch145, 21:11); + s(EmcEInput, 5:0, scratch145, 27:22); + s(EmcPmacroTxPwrd1, 26:23, scratch145, 31:28); + s(EmcPmacroIbDdllLongDqsRank1_3, 10:0, scratch146, 10:0); + s(EmcPmacroIbDdllLongDqsRank1_3, 26:16, scratch146, 21:11); + s(EmcEInputDuration, 5:0, scratch146, 27:22); + s(EmcPmacroTxPwrd1, 29:27, scratch146, 30:28); + s(EmcPmacroTxPwrd2, 0:0, scratch146, 31:31); + s(EmcPmacroDdllLongCmd_0, 10:0, scratch147, 10:0); + s(EmcPmacroDdllLongCmd_0, 26:16, scratch147, 21:11); + s(EmcPutermExtra, 5:0, scratch147, 27:22); + s(EmcPmacroTxPwrd2, 4:1, scratch147, 31:28); + s(EmcPmacroDdllLongCmd_1, 10:0, scratch148, 10:0); + s(EmcPmacroDdllLongCmd_1, 26:16, scratch148, 21:11); + s(EmcTckesr, 5:0, scratch148, 27:22); + s(EmcPmacroTxPwrd2, 8:5, scratch148, 31:28); + s(EmcPmacroDdllLongCmd_2, 10:0, scratch149, 10:0); + s(EmcPmacroDdllLongCmd_2, 26:16, scratch149, 21:11); + s(EmcTpd, 5:0, scratch149, 27:22); + s(EmcPmacroTxPwrd2, 12:9, scratch149, 31:28); + s(EmcPmacroDdllLongCmd_3, 10:0, scratch150, 10:0); + s(EmcPmacroDdllLongCmd_3, 26:16, scratch150, 21:11); + s(EmcWdvMask, 5:0, scratch150, 27:22); + s(EmcPmacroTxPwrd2, 13:13, scratch150, 28:28); + s(EmcPmacroTxPwrd2, 18:16, scratch150, 31:29); + s(McEmemArbCfg, 8:0, scratch151, 8:0); + s(McEmemArbCfg, 20:16, scratch151, 13:9); + s(McEmemArbCfg, 31:24, scratch151, 21:14); + s(EmcWdvChk, 5:0, scratch151, 27:22); + s(EmcPmacroTxPwrd2, 22:19, scratch151, 31:28); + s(McEmemArbMisc1, 12:0, scratch152, 12:0); + s(McEmemArbMisc1, 25:21, scratch152, 17:13); + s(McEmemArbMisc1, 31:28, scratch152, 21:18); + s(EmcCmdBrlshft0, 5:0, scratch152, 27:22); + s(EmcPmacroTxPwrd2, 26:23, scratch152, 31:28); + s(EmcMrsWaitCnt2, 9:0, scratch153, 9:0); + s(EmcMrsWaitCnt2, 26:16, scratch153, 20:10); + s(EmcPmacroIbRxrt, 10:0, scratch153, 31:21); + s(EmcMrsWaitCnt, 9:0, scratch154, 9:0); + s(EmcMrsWaitCnt, 26:16, scratch154, 20:10); + s(EmcPmacroDdllLongCmd_4, 10:0, scratch154, 31:21); + s(EmcAutoCalInterval, 20:0, scratch155, 20:0); + s(McEmemArbOutstandingReq, 8:0, scratch155, 29:21); + s(McEmemArbOutstandingReq, 31:30, scratch155, 31:30); + s(McEmemArbRefpbHpCtrl, 6:0, scratch156, 6:0); + s(McEmemArbRefpbHpCtrl, 14:8, scratch156, 13:7); + s(McEmemArbRefpbHpCtrl, 22:16, scratch156, 20:14); + s(EmcCmdBrlshft1, 5:0, scratch156, 26:21); + s(EmcRrd, 4:0, scratch156, 31:27); + s(EmcQuseBrlshft0, 19:0, scratch157, 19:0); + s(EmcFbioCfg8, 27:16, scratch157, 31:20); + s(EmcQuseBrlshft1, 19:0, scratch158, 19:0); + s(EmcTxsrDll, 11:0, scratch158, 31:20); + s(EmcQuseBrlshft2, 19:0, scratch159, 19:0); + s(EmcTxdsrvttgen, 11:0, scratch159, 31:20); + s(EmcQuseBrlshft3, 19:0, scratch160, 19:0); + s(EmcPmacroVttgenCtrl0, 3:0, scratch160, 23:20); + s(EmcPmacroVttgenCtrl0, 11:8, scratch160, 27:24); + s(EmcPmacroVttgenCtrl0, 19:16, scratch160, 31:28); + s(EmcPmacroVttgenCtrl1, 19:0, scratch161, 19:0); + s(EmcCmdBrlshft2, 5:0, scratch161, 25:20); + s(EmcCmdBrlshft3, 5:0, scratch161, 31:26); + s(EmcAutoCalConfig3, 5:0, scratch162, 5:0); + s(EmcAutoCalConfig3, 13:8, scratch162, 11:6); + s(EmcAutoCalConfig3, 18:16, scratch162, 14:12); + s(EmcAutoCalConfig3, 22:20, scratch162, 17:15); + s(EmcTRefBw, 13:0, scratch162, 31:18); + s(EmcAutoCalConfig4, 5:0, scratch163, 5:0); + s(EmcAutoCalConfig4, 13:8, scratch163, 11:6); + s(EmcAutoCalConfig4, 18:16, scratch163, 14:12); + s(EmcAutoCalConfig4, 22:20, scratch163, 17:15); + s(EmcQpop, 6:0, scratch163, 24:18); + s(EmcQpop, 22:16, scratch163, 31:25); + s(EmcAutoCalConfig5, 5:0, scratch164, 5:0); + s(EmcAutoCalConfig5, 13:8, scratch164, 11:6); + s(EmcAutoCalConfig5, 18:16, scratch164, 14:12); + s(EmcAutoCalConfig5, 22:20, scratch164, 17:15); + s(EmcPmacroAutocalCfgCommon, 5:0, scratch164, 23:18); + s(EmcPmacroAutocalCfgCommon, 13:8, scratch164, 29:24); + s(EmcPmacroAutocalCfgCommon, 16:16, scratch164, 30:30); + s(EmcPmacroTxPwrd2, 27:27, scratch164, 31:31); + s(EmcAutoCalConfig6, 5:0, scratch165, 5:0); + s(EmcAutoCalConfig6, 13:8, scratch165, 11:6); + s(EmcAutoCalConfig6, 18:16, scratch165, 14:12); + s(EmcAutoCalConfig6, 22:20, scratch165, 17:15); + s(EmcWev, 5:0, scratch165, 23:18); + s(EmcWsv, 5:0, scratch165, 29:24); + s(EmcPmacroTxPwrd2, 29:28, scratch165, 31:30); + s(EmcAutoCalConfig7, 5:0, scratch166, 5:0); + s(EmcAutoCalConfig7, 13:8, scratch166, 11:6); + s(EmcAutoCalConfig7, 18:16, scratch166, 14:12); + s(EmcAutoCalConfig7, 22:20, scratch166, 17:15); + s(EmcCfg3, 2:0, scratch166, 20:18); + s(EmcCfg3, 6:4, scratch166, 23:21); + s(EmcQuseWidth, 3:0, scratch166, 27:24); + s(EmcQuseWidth, 29:28, scratch166, 29:28); + s(EmcPmacroTxPwrd3, 1:0, scratch166, 31:30); + s(EmcAutoCalConfig8, 5:0, scratch167, 5:0); + s(EmcAutoCalConfig8, 13:8, scratch167, 11:6); + s(EmcAutoCalConfig8, 18:16, scratch167, 14:12); + s(EmcAutoCalConfig8, 22:20, scratch167, 17:15); + s(EmcPmacroBgBiasCtrl0, 2:0, scratch167, 20:18); + s(EmcPmacroBgBiasCtrl0, 6:4, scratch167, 23:21); + s(McEmemArbTimingRcd, 5:0, scratch167, 29:24); + s(EmcPmacroTxPwrd3, 3:2, scratch167, 31:30); + s(EmcXm2CompPadCtrl2, 17:0, scratch168, 17:0); + s(McEmemArbTimingCcdmw, 5:0, scratch168, 23:18); + s(McEmemArbOverride, 27:27, scratch168, 24:24); + s(McEmemArbOverride, 26:26, scratch168, 25:25); + s(McEmemArbOverride, 16:16, scratch168, 26:26); + s(McEmemArbOverride, 10:10, scratch168, 27:27); + s(McEmemArbOverride, 4:4, scratch168, 28:28); + s(McEmemArbOverride, 3:3, scratch168, 29:29); + s(EmcPmacroTxPwrd3, 5:4, scratch168, 31:30); + s(EmcXm2CompPadCtrl3, 17:0, scratch169, 17:0); + s(EmcRext, 4:0, scratch169, 22:18); + s(EmcTClkStop, 4:0, scratch169, 27:23); + s(EmcPmacroTxPwrd3, 9:6, scratch169, 31:28); + s(EmcZcalWaitCnt, 10:0, scratch170, 10:0); + s(EmcZcalWaitCnt, 21:16, scratch170, 16:11); + s(EmcZcalWaitCnt, 31:31, scratch170, 17:17); + s(EmcWext, 4:0, scratch170, 22:18); + s(EmcRefctrl2, 0:0, scratch170, 23:23); + s(EmcRefctrl2, 26:24, scratch170, 26:24); + s(EmcRefctrl2, 31:31, scratch170, 27:27); + s(EmcPmacroTxPwrd3, 13:10, scratch170, 31:28); + s(EmcZcalMrwCmd, 7:0, scratch171, 7:0); + s(EmcZcalMrwCmd, 23:16, scratch171, 15:8); + s(EmcZcalMrwCmd, 31:30, scratch171, 17:16); + s(EmcWeDuration, 4:0, scratch171, 22:18); + s(EmcWsDuration, 4:0, scratch171, 27:23); + s(EmcPmacroTxPwrd3, 19:16, scratch171, 31:28); + s(EmcSwizzleRank0Byte0, 2:0, scratch172, 2:0); + s(EmcSwizzleRank0Byte0, 6:4, scratch172, 5:3); + s(EmcSwizzleRank0Byte0, 10:8, scratch172, 8:6); + s(EmcSwizzleRank0Byte0, 14:12, scratch172, 11:9); + s(EmcSwizzleRank0Byte0, 18:16, scratch172, 14:12); + s(EmcSwizzleRank0Byte0, 22:20, scratch172, 17:15); + s(EmcPutermWidth, 31:31, scratch172, 18:18); + s(EmcPutermWidth, 3:0, scratch172, 22:19); + s(McEmemArbTimingRrd, 4:0, scratch172, 27:23); + s(EmcPmacroTxPwrd3, 23:20, scratch172, 31:28); + s(EmcSwizzleRank0Byte1, 2:0, scratch173, 2:0); + s(EmcSwizzleRank0Byte1, 6:4, scratch173, 5:3); + s(EmcSwizzleRank0Byte1, 10:8, scratch173, 8:6); + s(EmcSwizzleRank0Byte1, 14:12, scratch173, 11:9); + s(EmcSwizzleRank0Byte1, 18:16, scratch173, 14:12); + s(EmcSwizzleRank0Byte1, 22:20, scratch173, 17:15); + s(McEmemArbTimingR2R, 4:0, scratch173, 22:18); + s(McEmemArbTimingW2W, 4:0, scratch173, 27:23); + s(EmcPmacroTxPwrd3, 27:24, scratch173, 31:28); + s(EmcSwizzleRank0Byte2, 2:0, scratch174, 2:0); + s(EmcSwizzleRank0Byte2, 6:4, scratch174, 5:3); + s(EmcSwizzleRank0Byte2, 10:8, scratch174, 8:6); + s(EmcSwizzleRank0Byte2, 14:12, scratch174, 11:9); + s(EmcSwizzleRank0Byte2, 18:16, scratch174, 14:12); + s(EmcSwizzleRank0Byte2, 22:20, scratch174, 17:15); + s(EmcPmacroTxPwrd3, 29:28, scratch174, 19:18); + s(EmcPmacroTxSelClkSrc0, 11:0, scratch174, 31:20); + s(EmcSwizzleRank0Byte3, 2:0, scratch175, 2:0); + s(EmcSwizzleRank0Byte3, 6:4, scratch175, 5:3); + s(EmcSwizzleRank0Byte3, 10:8, scratch175, 8:6); + s(EmcSwizzleRank0Byte3, 14:12, scratch175, 11:9); + s(EmcSwizzleRank0Byte3, 18:16, scratch175, 14:12); + s(EmcSwizzleRank0Byte3, 22:20, scratch175, 17:15); + s(EmcPmacroTxSelClkSrc0, 27:16, scratch175, 29:18); + s(EmcPmacroTxSelClkSrc1, 1:0, scratch175, 31:30); + s(EmcSwizzleRank1Byte0, 2:0, scratch176, 2:0); + s(EmcSwizzleRank1Byte0, 6:4, scratch176, 5:3); + s(EmcSwizzleRank1Byte0, 10:8, scratch176, 8:6); + s(EmcSwizzleRank1Byte0, 14:12, scratch176, 11:9); + s(EmcSwizzleRank1Byte0, 18:16, scratch176, 14:12); + s(EmcSwizzleRank1Byte0, 22:20, scratch176, 17:15); + s(EmcPmacroTxSelClkSrc1, 11:2, scratch176, 27:18); + s(EmcPmacroTxSelClkSrc1, 19:16, scratch176, 31:28); + s(EmcSwizzleRank1Byte1, 2:0, scratch177, 2:0); + s(EmcSwizzleRank1Byte1, 6:4, scratch177, 5:3); + s(EmcSwizzleRank1Byte1, 10:8, scratch177, 8:6); + s(EmcSwizzleRank1Byte1, 14:12, scratch177, 11:9); + s(EmcSwizzleRank1Byte1, 18:16, scratch177, 14:12); + s(EmcSwizzleRank1Byte1, 22:20, scratch177, 17:15); + s(EmcPmacroTxSelClkSrc1, 27:20, scratch177, 25:18); + s(EmcPmacroTxSelClkSrc3, 5:0, scratch177, 31:26); + s(EmcSwizzleRank1Byte2, 2:0, scratch178, 2:0); + s(EmcSwizzleRank1Byte2, 6:4, scratch178, 5:3); + s(EmcSwizzleRank1Byte2, 10:8, scratch178, 8:6); + s(EmcSwizzleRank1Byte2, 14:12, scratch178, 11:9); + s(EmcSwizzleRank1Byte2, 18:16, scratch178, 14:12); + s(EmcSwizzleRank1Byte2, 22:20, scratch178, 17:15); + s(EmcPmacroTxSelClkSrc3, 11:6, scratch178, 23:18); + s(EmcPmacroTxSelClkSrc3, 23:16, scratch178, 31:24); + s(EmcSwizzleRank1Byte3, 2:0, scratch179, 2:0); + s(EmcSwizzleRank1Byte3, 6:4, scratch179, 5:3); + s(EmcSwizzleRank1Byte3, 10:8, scratch179, 8:6); + s(EmcSwizzleRank1Byte3, 14:12, scratch179, 11:9); + s(EmcSwizzleRank1Byte3, 18:16, scratch179, 14:12); + s(EmcSwizzleRank1Byte3, 22:20, scratch179, 17:15); + s(EmcPmacroTxSelClkSrc3, 27:24, scratch179, 21:18); + s(EmcPmacroTxSelClkSrc2, 9:0, scratch179, 31:22); + s(EmcPmacroCmdBrickCtrlFdpd, 17:0, scratch180, 17:0); + s(EmcPmacroTxSelClkSrc2, 11:10, scratch180, 19:18); + s(EmcPmacroTxSelClkSrc2, 27:16, scratch180, 31:20); + s(EmcPmacroDataBrickCtrlFdpd, 17:0, scratch181, 17:0); + s(EmcPmacroTxSelClkSrc4, 11:0, scratch181, 29:18); + s(EmcPmacroTxSelClkSrc4, 17:16, scratch181, 31:30); + s(EmcFbioCfg7, 16:0, scratch182, 16:0); + s(McEmemArbRefpbBankCtrl, 6:0, scratch182, 23:17); + s(McEmemArbRefpbBankCtrl, 14:8, scratch182, 30:24); + s(McEmemArbRefpbBankCtrl, 31:31, scratch182, 31:31); + s(EmcDynSelfRefControl, 15:0, scratch183, 15:0); + s(EmcDynSelfRefControl, 31:31, scratch183, 16:16); + s(EmcPmacroTxSelClkSrc4, 27:18, scratch183, 26:17); + s(EmcPmacroTxSelClkSrc5, 4:0, scratch183, 31:27); + s(EmcDllCfg1, 16:0, scratch184, 16:0); + s(EmcPmacroTxSelClkSrc5, 11:5, scratch184, 23:17); + s(EmcPmacroTxSelClkSrc5, 23:16, scratch184, 31:24); + s(EmcPmacroPadCfgCtrl, 1:0, scratch185, 1:0); + s(EmcPmacroPadCfgCtrl, 6:5, scratch185, 3:2); + s(EmcPmacroPadCfgCtrl, 11:9, scratch185, 6:4); + s(EmcPmacroPadCfgCtrl, 13:13, scratch185, 7:7); + s(EmcPmacroPadCfgCtrl, 17:16, scratch185, 9:8); + s(EmcPmacroPadCfgCtrl, 21:20, scratch185, 11:10); + s(EmcPmacroPadCfgCtrl, 25:24, scratch185, 13:12); + s(EmcPmacroPadCfgCtrl, 30:28, scratch185, 16:14); + s(EmcPmacroTxSelClkSrc5, 27:24, scratch185, 20:17); + s(EmcPmacroCmdPadTxCtrl, 1:0, scratch185, 22:21); + s(EmcPmacroCmdPadTxCtrl, 5:4, scratch185, 24:23); + s(EmcPmacroCmdPadTxCtrl, 9:8, scratch185, 26:25); + s(EmcPmacroCmdPadTxCtrl, 13:12, scratch185, 28:27); + s(EmcPmacroCmdPadTxCtrl, 16:16, scratch185, 29:29); + s(EmcPmacroCmdPadTxCtrl, 21:20, scratch185, 31:30); + s(EmcRefresh, 15:0, scratch186, 15:0); + s(EmcCmdQ, 4:0, scratch186, 20:16); + s(EmcCmdQ, 10:8, scratch186, 23:21); + s(EmcCmdQ, 14:12, scratch186, 26:24); + s(EmcCmdQ, 28:24, scratch186, 31:27); + s(EmcAcpdControl, 15:0, scratch187, 15:0); + s(EmcAutoCalVrefSel1, 15:0, scratch187, 31:16); + s(EmcXm2CompPadCtrl, 1:0, scratch188, 1:0); + s(EmcXm2CompPadCtrl, 6:3, scratch188, 5:2); + s(EmcXm2CompPadCtrl, 9:9, scratch188, 6:6); + s(EmcXm2CompPadCtrl, 19:11, scratch188, 15:7); + s(EmcCfgDigDllPeriod, 15:0, scratch188, 31:16); + s(EmcCfgDigDll_1, 15:0, scratch189, 15:0); + s(EmcPreRefreshReqCnt, 15:0, scratch189, 31:16); + s(EmcPmacroCmdPadTxCtrl, 27:24, scratch190, 19:16); + s(EmcPmacroDataPadTxCtrl, 1:0, scratch190, 21:20); + s(EmcPmacroDataPadTxCtrl, 5:4, scratch190, 23:22); + s(EmcPmacroDataPadTxCtrl, 9:8, scratch190, 25:24); + s(EmcPmacroDataPadTxCtrl, 13:12, scratch190, 27:26); + s(EmcPmacroDataPadTxCtrl, 16:16, scratch190, 28:28); + s(EmcPmacroDataPadTxCtrl, 21:20, scratch190, 30:29); + s(EmcPmacroDataPadTxCtrl, 24:24, scratch190, 31:31); + s(EmcPmacroDataPadTxCtrl, 27:25, scratch191, 2:0); + + s(EmcPinGpio, 1:0, scratch8, 31:30); + s(EmcPinGpioEn, 1:0, scratch9, 31:30); + s(EmcDevSelect, 1:0, scratch10, 31:30); + s(EmcZcalWarmColdBootEnables, 1:0, scratch11, 31:30); + s(EmcCfgDigDllPeriodWarmBoot, 1:0, scratch12, 31:30); + s32(EmcBctSpare13, scratch31); + s32(EmcBctSpare12, scratch32); + s32(EmcBctSpare7, scratch33); + s32(EmcBctSpare6, scratch40); + s32(EmcBctSpare5, scratch42); + s32(EmcBctSpare4, scratch44); + s32(SwizzleRankByteEncode, scratch45); + s32(EmcBctSpare2, scratch46); + s32(EmcBctSpare1, scratch47); + s32(EmcBctSpare0, scratch48); + s32(EmcBctSpare9, scratch50); + s32(EmcBctSpare8, scratch51); + s32(BootRomPatchData, scratch56); + s32(BootRomPatchControl, scratch57); + s(McClkenOverrideAllWarmBoot, 0:0, scratch58, 31:31); + s(EmcClkenOverrideAllWarmBoot, 0:0, scratch59, 30:30); + s(EmcMrsWarmBootEnable, 0:0, scratch59, 31:31); + s(ClearClk2Mc1, 0:0, scratch60, 30:30); + s(EmcWarmBootExtraModeRegWriteEnable, 0:0, scratch60, 31:31); + s(ClkRstControllerPllmMisc2OverrideEnable, 0:0, scratch61, 30:30); + s(EmcDbgWriteMux, 0:0, scratch61, 31:31); + s(EmcExtraRefreshNum, 2:0, scratch62, 31:29); + s(PmcIoDpd3ReqWait, 2:0, scratch68, 30:28); + s(AhbArbitrationXbarCtrlMemInitDone, 0:0, scratch68, 31:31); + s(MemoryType, 2:0, scratch69, 30:28); + s(PmcIoDpd4ReqWait, 2:0, scratch70, 30:28); + s(EmcTimingControlWait, 7:0, scratch86, 31:24); + s(EmcZcalWarmBootWait, 7:0, scratch87, 31:24); + s(WarmBootWait, 7:0, scratch88, 31:24); + s(EmcPinProgramWait, 7:0, scratch89, 31:24); + s(EmcAutoCalWait, 9:0, scratch101, 31:22); + s(SwizzleRankByteEncode, 15:0, scratch190, 15:0); + + switch (sdram->MemoryType) { + case NvBootMemoryType_LpDdr2: + case NvBootMemoryType_LpDdr4: + s(EmcMrwLpddr2ZcalWarmBoot, 23:16, scratch5, 7:0); + s(EmcMrwLpddr2ZcalWarmBoot, 7:0, scratch5, 15:8); + s(EmcWarmBootMrwExtra, 23:16, scratch5, 23:16); + s(EmcWarmBootMrwExtra, 7:0, scratch5, 31:24); + s(EmcMrwLpddr2ZcalWarmBoot, 31:30, scratch6, 1:0); + s(EmcWarmBootMrwExtra, 31:30, scratch6, 3:2); + s(EmcMrwLpddr2ZcalWarmBoot, 27:26, scratch6, 5:4); + s(EmcWarmBootMrwExtra, 27:26, scratch6, 7:6); + s(EmcMrw6, 27:0, scratch8, 27:0); + s(EmcMrw6, 31:30, scratch8, 29:28); + s(EmcMrw8, 27:0, scratch9, 27:0); + s(EmcMrw8, 31:30, scratch9, 29:28); + s(EmcMrw9, 27:0, scratch10, 27:0); + s(EmcMrw9, 31:30, scratch10, 29:28); + s(EmcMrw10, 27:0, scratch11, 27:0); + s(EmcMrw10, 31:30, scratch11, 29:28); + s(EmcMrw12, 27:0, scratch12, 27:0); + s(EmcMrw12, 31:30, scratch12, 29:28); + s(EmcMrw13, 27:0, scratch13, 27:0); + s(EmcMrw13, 31:30, scratch13, 29:28); + s(EmcMrw14, 27:0, scratch14, 27:0); + s(EmcMrw14, 31:30, scratch14, 29:28); + s(EmcMrw1, 7:0, scratch15, 7:0); + s(EmcMrw1, 23:16, scratch15, 15:8); + s(EmcMrw1, 27:26, scratch15, 17:16); + s(EmcMrw1, 31:30, scratch15, 19:18); + s(EmcWarmBootMrwExtra, 7:0, scratch16, 7:0); + s(EmcWarmBootMrwExtra, 23:16, scratch16, 15:8); + s(EmcWarmBootMrwExtra, 27:26, scratch16, 17:16); + s(EmcWarmBootMrwExtra, 31:30, scratch16, 19:18); + s(EmcMrw2, 7:0, scratch17, 7:0); + s(EmcMrw2, 23:16, scratch17, 15:8); + s(EmcMrw2, 27:26, scratch17, 17:16); + s(EmcMrw2, 31:30, scratch17, 19:18); + s(EmcMrw3, 7:0, scratch18, 7:0); + s(EmcMrw3, 23:16, scratch18, 15:8); + s(EmcMrw3, 27:26, scratch18, 17:16); + s(EmcMrw3, 31:30, scratch18, 19:18); + s(EmcMrw4, 7:0, scratch19, 7:0); + s(EmcMrw4, 23:16, scratch19, 15:8); + s(EmcMrw4, 27:26, scratch19, 17:16); + s(EmcMrw4, 31:30, scratch19, 19:18); + break; + case NvBootMemoryType_Ddr3: + s(EmcMrs, 13:0, scratch5, 13:0); + s(EmcEmrs, 13:0, scratch5, 27:14); + s(EmcMrs, 21:20, scratch5, 29:28); + s(EmcMrs, 31:30, scratch5, 31:30); + s(EmcEmrs2, 13:0, scratch8, 13:0); + s(EmcEmrs3, 13:0, scratch8, 27:14); + s(EmcEmrs, 21:20, scratch8, 29:28); + s(EmcWarmBootMrsExtra, 13:0, scratch9, 13:0); + s(EmcEmrs, 31:30, scratch9, 15:14); + s(EmcEmrs2, 21:20, scratch9, 17:16); + s(EmcEmrs2, 31:30, scratch9, 19:18); + s(EmcEmrs3, 21:20, scratch9, 21:20); + s(EmcEmrs3, 31:30, scratch9, 23:22); + s(EmcWarmBootMrsExtra, 31:30, scratch9, 25:24); + s(EmcWarmBootMrsExtra, 21:20, scratch9, 27:26); + s(EmcZqCalDdr3WarmBoot, 31:30, scratch9, 29:28); + s(EmcMrs, 27:26, scratch10, 1:0); + s(EmcEmrs, 27:26, scratch10, 3:2); + s(EmcEmrs2, 27:26, scratch10, 5:4); + s(EmcEmrs3, 27:26, scratch10, 7:6); + s(EmcWarmBootMrsExtra, 27:27, scratch10, 8:8); + s(EmcWarmBootMrsExtra, 26:26, scratch10, 9:9); + s(EmcZqCalDdr3WarmBoot, 0:0, scratch10, 10:10); + s(EmcZqCalDdr3WarmBoot, 4:4, scratch10, 11:11); + break; + } + + s32(EmcCmdMappingByte, secure_scratch8); + s32(EmcPmacroBrickMapping0, secure_scratch9); + s32(EmcPmacroBrickMapping1, secure_scratch10); + s32(EmcPmacroBrickMapping2, secure_scratch11); + s32(McVideoProtectGpuOverride0, secure_scratch12); + s(EmcCmdMappingCmd0_0, 6:0, secure_scratch13, 6:0); + s(EmcCmdMappingCmd0_0, 14:8, secure_scratch13, 13:7); + s(EmcCmdMappingCmd0_0, 22:16, secure_scratch13, 20:14); + s(EmcCmdMappingCmd0_0, 30:24, secure_scratch13, 27:21); + s(McVideoProtectBomAdrHi, 1:0, secure_scratch13, 29:28); + s(McVideoProtectWriteAccess, 1:0, secure_scratch13, 31:30); + s(EmcCmdMappingCmd0_1, 6:0, secure_scratch14, 6:0); + s(EmcCmdMappingCmd0_1, 14:8, secure_scratch14, 13:7); + s(EmcCmdMappingCmd0_1, 22:16, secure_scratch14, 20:14); + s(EmcCmdMappingCmd0_1, 30:24, secure_scratch14, 27:21); + s(McSecCarveoutAdrHi, 1:0, secure_scratch14, 29:28); + s(McMtsCarveoutAdrHi, 1:0, secure_scratch14, 31:30); + s(EmcCmdMappingCmd1_0, 6:0, secure_scratch15, 6:0); + s(EmcCmdMappingCmd1_0, 14:8, secure_scratch15, 13:7); + s(EmcCmdMappingCmd1_0, 22:16, secure_scratch15, 20:14); + s(EmcCmdMappingCmd1_0, 30:24, secure_scratch15, 27:21); + s(McGeneralizedCarveout5BomHi, 1:0, secure_scratch15, 29:28); + s(McGeneralizedCarveout3BomHi, 1:0, secure_scratch15, 31:30); + s(EmcCmdMappingCmd1_1, 6:0, secure_scratch16, 6:0); + s(EmcCmdMappingCmd1_1, 14:8, secure_scratch16, 13:7); + s(EmcCmdMappingCmd1_1, 22:16, secure_scratch16, 20:14); + s(EmcCmdMappingCmd1_1, 30:24, secure_scratch16, 27:21); + s(McGeneralizedCarveout2BomHi, 1:0, secure_scratch16, 29:28); + s(McGeneralizedCarveout4BomHi, 1:0, secure_scratch16, 31:30); + s(EmcCmdMappingCmd2_0, 6:0, secure_scratch17, 6:0); + s(EmcCmdMappingCmd2_0, 14:8, secure_scratch17, 13:7); + s(EmcCmdMappingCmd2_0, 22:16, secure_scratch17, 20:14); + s(EmcCmdMappingCmd2_0, 30:24, secure_scratch17, 27:21); + s(McGeneralizedCarveout1BomHi, 1:0, secure_scratch17, 29:28); + s(EmcAdrCfg, 0:0, secure_scratch17, 30:30); + s(EmcFbioSpare, 1:1, secure_scratch17, 31:31); + s(EmcCmdMappingCmd2_1, 6:0, secure_scratch18, 6:0); + s(EmcCmdMappingCmd2_1, 14:8, secure_scratch18, 13:7); + s(EmcCmdMappingCmd2_1, 22:16, secure_scratch18, 20:14); + s(EmcCmdMappingCmd2_1, 30:24, secure_scratch18, 27:21); + s(EmcFbioCfg8, 15:15, secure_scratch18, 28:28); + s(McEmemAdrCfg, 0:0, secure_scratch18, 29:29); + s(McSecCarveoutProtectWriteAccess, 0:0, secure_scratch18, 30:30); + s(McMtsCarveoutRegCtrl, 0:0, secure_scratch18, 31:31); + s(EmcCmdMappingCmd3_0, 6:0, secure_scratch19, 6:0); + s(EmcCmdMappingCmd3_0, 14:8, secure_scratch19, 13:7); + s(EmcCmdMappingCmd3_0, 22:16, secure_scratch19, 20:14); + s(EmcCmdMappingCmd3_0, 30:24, secure_scratch19, 27:21); + s(McGeneralizedCarveout2Cfg0, 6:3, secure_scratch19, 31:28); + s(EmcCmdMappingCmd3_1, 6:0, secure_scratch20, 6:0); + s(EmcCmdMappingCmd3_1, 14:8, secure_scratch20, 13:7); + s(EmcCmdMappingCmd3_1, 22:16, secure_scratch20, 20:14); + s(EmcCmdMappingCmd3_1, 30:24, secure_scratch20, 27:21); + s(McGeneralizedCarveout2Cfg0, 10:7, secure_scratch20, 31:28); + s(McGeneralizedCarveout4Cfg0, 26:0, secure_scratch39, 26:0); + s(McGeneralizedCarveout2Cfg0, 17:14, secure_scratch39, 30:27); + s(McVideoProtectVprOverride, 0:0, secure_scratch39, 31:31); + s(McGeneralizedCarveout5Cfg0, 26:0, secure_scratch40, 26:0); + s(McGeneralizedCarveout2Cfg0, 21:18, secure_scratch40, 30:27); + s(McVideoProtectVprOverride, 1:1, secure_scratch40, 31:31); + s(EmcCmdMappingCmd0_2, 6:0, secure_scratch41, 6:0); + s(EmcCmdMappingCmd0_2, 14:8, secure_scratch41, 13:7); + s(EmcCmdMappingCmd0_2, 22:16, secure_scratch41, 20:14); + s(EmcCmdMappingCmd0_2, 27:24, secure_scratch41, 24:21); + s(McGeneralizedCarveout1Cfg0, 6:3, secure_scratch41, 28:25); + s(McGeneralizedCarveout2Cfg0, 13:11, secure_scratch41, 31:29); + s(EmcCmdMappingCmd1_2, 6:0, secure_scratch42, 6:0); + s(EmcCmdMappingCmd1_2, 14:8, secure_scratch42, 13:7); + s(EmcCmdMappingCmd1_2, 22:16, secure_scratch42, 20:14); + s(EmcCmdMappingCmd1_2, 27:24, secure_scratch42, 24:21); + s(McGeneralizedCarveout1Cfg0, 13:7, secure_scratch42, 31:25); + s(EmcCmdMappingCmd2_2, 6:0, secure_scratch43, 6:0); + s(EmcCmdMappingCmd2_2, 14:8, secure_scratch43, 13:7); + s(EmcCmdMappingCmd2_2, 22:16, secure_scratch43, 20:14); + s(EmcCmdMappingCmd2_2, 27:24, secure_scratch43, 24:21); + s(McGeneralizedCarveout1Cfg0, 17:14, secure_scratch43, 28:25); + s(McGeneralizedCarveout3Cfg0, 13:11, secure_scratch43, 31:29); + s(EmcCmdMappingCmd3_2, 6:0, secure_scratch44, 6:0); + s(EmcCmdMappingCmd3_2, 14:8, secure_scratch44, 13:7); + s(EmcCmdMappingCmd3_2, 22:16, secure_scratch44, 20:14); + s(EmcCmdMappingCmd3_2, 27:24, secure_scratch44, 24:21); + s(McGeneralizedCarveout1Cfg0, 21:18, secure_scratch44, 28:25); + s(McVideoProtectVprOverride, 3:2, secure_scratch44, 30:29); + s(McVideoProtectVprOverride, 6:6, secure_scratch44, 31:31); + s(McEmemAdrCfgChannelMask, 31:9, secure_scratch45, 22:0); + s(McEmemAdrCfgDev0, 2:0, secure_scratch45, 25:23); + s(McEmemAdrCfgDev0, 9:8, secure_scratch45, 27:26); + s(McEmemAdrCfgDev0, 19:16, secure_scratch45, 31:28); + s(McEmemAdrCfgBankMask0, 31:10, secure_scratch46, 21:0); + s(McEmemAdrCfgDev1, 2:0, secure_scratch46, 24:22); + s(McEmemAdrCfgDev1, 9:8, secure_scratch46, 26:25); + s(McEmemAdrCfgDev1, 19:16, secure_scratch46, 30:27); + s(McVideoProtectVprOverride, 7:7, secure_scratch46, 31:31); + s(McEmemAdrCfgBankMask1, 31:10, secure_scratch47, 21:0); + s(McGeneralizedCarveout3Cfg0, 10:3, secure_scratch47, 29:22); + s(McVideoProtectVprOverride, 9:8, secure_scratch47, 31:30); + s(McEmemAdrCfgBankMask2, 31:10, secure_scratch48, 21:0); + s(McGeneralizedCarveout3Cfg0, 21:14, secure_scratch48, 29:22); + s(McVideoProtectVprOverride, 11:11, secure_scratch48, 30:30); + s(McVideoProtectVprOverride, 14:14, secure_scratch48, 31:31); + s(McVideoProtectGpuOverride1, 15:0, secure_scratch49, 15:0); + s(McEmemCfg, 13:0, secure_scratch49, 29:16); + s(McEmemCfg, 31:31, secure_scratch49, 30:30); + s(McVideoProtectVprOverride, 15:15, secure_scratch49, 31:31); + s(McGeneralizedCarveout3Bom, 31:17, secure_scratch50, 14:0); + s(McGeneralizedCarveout1Bom, 31:17, secure_scratch50, 29:15); + s(McVideoProtectVprOverride, 18:17, secure_scratch50, 31:30); + s(McGeneralizedCarveout4Bom, 31:17, secure_scratch51, 14:0); + s(McGeneralizedCarveout2Bom, 31:17, secure_scratch51, 29:15); + s(McVideoProtectVprOverride, 20:19, secure_scratch51, 31:30); + s(McGeneralizedCarveout5Bom, 31:17, secure_scratch52, 14:0); + s(McVideoProtectBom, 31:20, secure_scratch52, 26:15); + s(McVideoProtectVprOverride, 23:21, secure_scratch52, 29:27); + s(McVideoProtectVprOverride, 26:26, secure_scratch52, 30:30); + s(McVideoProtectVprOverride, 29:29, secure_scratch52, 31:31); + s(McVideoProtectSizeMb, 11:0, secure_scratch53, 11:0); + s(McSecCarveoutBom, 31:20, secure_scratch53, 23:12); + s(McVideoProtectVprOverride, 31:30, secure_scratch53, 25:24); + s(McVideoProtectVprOverride1, 1:0, secure_scratch53, 27:26); + s(McVideoProtectVprOverride1, 7:4, secure_scratch53, 31:28); + s(McSecCarveoutSizeMb, 11:0, secure_scratch54, 11:0); + s(McMtsCarveoutBom, 31:20, secure_scratch54, 23:12); + s(McVideoProtectVprOverride1, 15:8, secure_scratch54, 31:24); + s(McMtsCarveoutSizeMb, 11:0, secure_scratch55, 11:0); + s(McGeneralizedCarveout4Size128kb, 11:0, secure_scratch55, 23:12); + s(McVideoProtectVprOverride1, 16:16, secure_scratch55, 24:24); + s(McGeneralizedCarveout2Cfg0, 2:0, secure_scratch55, 27:25); + s(McGeneralizedCarveout2Cfg0, 25:22, secure_scratch55, 31:28); + s(McGeneralizedCarveout3Size128kb, 11:0, secure_scratch56, 11:0); + s(McGeneralizedCarveout2Size128kb, 11:0, secure_scratch56, 23:12); + s(McGeneralizedCarveout2Cfg0, 26:26, secure_scratch56, 24:24); + s(McGeneralizedCarveout1Cfg0, 2:0, secure_scratch56, 27:25); + s(McGeneralizedCarveout1Cfg0, 25:22, secure_scratch56, 31:28); + s(McGeneralizedCarveout1Size128kb, 11:0, secure_scratch57, 11:0); + s(McGeneralizedCarveout5Size128kb, 11:0, secure_scratch57, 23:12); + s(McGeneralizedCarveout1Cfg0, 26:26, secure_scratch57, 24:24); + s(McGeneralizedCarveout3Cfg0, 2:0, secure_scratch57, 27:25); + s(McGeneralizedCarveout3Cfg0, 25:22, secure_scratch57, 31:28); + s(McGeneralizedCarveout3Cfg0, 26:26, secure_scratch58, 0:0); + + s32(McGeneralizedCarveout1Access0, secure_scratch59); + s32(McGeneralizedCarveout1Access1, secure_scratch60); + s32(McGeneralizedCarveout1Access2, secure_scratch61); + s32(McGeneralizedCarveout1Access3, secure_scratch62); + s32(McGeneralizedCarveout1Access4, secure_scratch63); + s32(McGeneralizedCarveout2Access0, secure_scratch64); + s32(McGeneralizedCarveout2Access1, secure_scratch65); + s32(McGeneralizedCarveout2Access2, secure_scratch66); + s32(McGeneralizedCarveout2Access3, secure_scratch67); + s32(McGeneralizedCarveout2Access4, secure_scratch68); + s32(McGeneralizedCarveout3Access0, secure_scratch69); + s32(McGeneralizedCarveout3Access1, secure_scratch70); + s32(McGeneralizedCarveout3Access2, secure_scratch71); + s32(McGeneralizedCarveout3Access3, secure_scratch72); + s32(McGeneralizedCarveout3Access4, secure_scratch73); + s32(McGeneralizedCarveout4Access0, secure_scratch74); + s32(McGeneralizedCarveout4Access1, secure_scratch75); + s32(McGeneralizedCarveout4Access2, secure_scratch76); + s32(McGeneralizedCarveout4Access3, secure_scratch77); + s32(McGeneralizedCarveout4Access4, secure_scratch78); + s32(McGeneralizedCarveout5Access0, secure_scratch79); + s32(McGeneralizedCarveout5Access1, secure_scratch80); + s32(McGeneralizedCarveout5Access2, secure_scratch81); + s32(McGeneralizedCarveout5Access3, secure_scratch82); + s32(McGeneralizedCarveout1ForceInternalAccess0, secure_scratch84); + s32(McGeneralizedCarveout1ForceInternalAccess1, secure_scratch85); + s32(McGeneralizedCarveout1ForceInternalAccess2, secure_scratch86); + s32(McGeneralizedCarveout1ForceInternalAccess3, secure_scratch87); + s32(McGeneralizedCarveout1ForceInternalAccess4, secure_scratch88); + s32(McGeneralizedCarveout2ForceInternalAccess0, secure_scratch89); + s32(McGeneralizedCarveout2ForceInternalAccess1, secure_scratch90); + s32(McGeneralizedCarveout2ForceInternalAccess2, secure_scratch91); + s32(McGeneralizedCarveout2ForceInternalAccess3, secure_scratch92); + s32(McGeneralizedCarveout2ForceInternalAccess4, secure_scratch93); + s32(McGeneralizedCarveout3ForceInternalAccess0, secure_scratch94); + s32(McGeneralizedCarveout3ForceInternalAccess1, secure_scratch95); + s32(McGeneralizedCarveout3ForceInternalAccess2, secure_scratch96); + s32(McGeneralizedCarveout3ForceInternalAccess3, secure_scratch97); + s32(McGeneralizedCarveout3ForceInternalAccess4, secure_scratch98); + s32(McGeneralizedCarveout4ForceInternalAccess0, secure_scratch99); + s32(McGeneralizedCarveout4ForceInternalAccess1, secure_scratch100); + s32(McGeneralizedCarveout4ForceInternalAccess2, secure_scratch101); + s32(McGeneralizedCarveout4ForceInternalAccess3, secure_scratch102); + s32(McGeneralizedCarveout4ForceInternalAccess4, secure_scratch103); + s32(McGeneralizedCarveout5ForceInternalAccess0, secure_scratch104); + s32(McGeneralizedCarveout5ForceInternalAccess1, secure_scratch105); + s32(McGeneralizedCarveout5ForceInternalAccess2, secure_scratch106); + s32(McGeneralizedCarveout5ForceInternalAccess3, secure_scratch107); + + /* Locking PMC secure scratch register (8 ~ 15) for writing */ + //c(0x5555, sec_disable2, 15:0); + /* Locking PMC secure scratch register (4~ 7) for both reading and writing */ + //c(0xff, sec_disable, 19:12); + + c32(0, scratch2); + s(PllMInputDivider, 7:0, scratch2, 7:0); + s(PllMFeedbackDivider, 7:0, scratch2, 15:8); + s(PllMPostDivider, 4:0, scratch2, 20:16); + s(PllMKVCO, 0:0, scratch2, 21:21); + s(PllMKCP, 1:0, scratch2, 23:22); + + c32(0, scratch35); + s(PllMSetupControl, 15:0, scratch35, 15:0); + + c32(0, scratch3); + s(PllMInputDivider, 7:0, scratch3, 7:0); + c(0x3e, scratch3, 15:8); + c(0, scratch3, 20:16); + s(PllMKVCO, 0:0, scratch3, 21:21); + s(PllMKCP, 1:0, scratch3, 23:22); + + c32(0, scratch36); + s(PllMSetupControl, 23:0, scratch36, 23:0); + + c32(0, scratch4); + s(PllMStableTime, 9:0, scratch4, 9:0); +} diff --git a/ipl/sdram_lz.inl b/ipl/sdram_lz.inl new file mode 100755 index 0000000..0974245 --- /dev/null +++ b/ipl/sdram_lz.inl @@ -0,0 +1,124 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +static const u8 _dram_cfg_lz[1262] = { + 0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x2C, 0x17, 0x04, 0x09, 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08, + 0x17, 0x10, 0x10, 0x00, 0x00, 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0xB4, 0x01, 0x70, 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, + 0x70, 0x17, 0x10, 0x24, 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, + 0x00, 0x00, 0x00, 0x17, 0x04, 0x04, 0x17, 0x09, 0x18, 0xFF, 0xFF, 0x1F, + 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x77, + 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08, 0x17, 0x08, 0x08, 0xA6, 0xA6, + 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x04, 0x04, + 0x04, 0x04, 0x17, 0x04, 0x04, 0x17, 0x04, 0x3C, 0x1F, 0x1F, 0x1F, 0x1F, + 0x17, 0x04, 0x04, 0x17, 0x06, 0x06, 0x00, 0x00, 0x04, 0x08, 0x17, 0x06, + 0x46, 0xA1, 0x01, 0x00, 0x00, 0x32, 0x17, 0x0B, 0x64, 0x01, 0x17, 0x04, + 0x7C, 0x17, 0x07, 0x0C, 0x03, 0x17, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, + 0x17, 0x0B, 0x2C, 0x09, 0x00, 0x00, 0x00, 0x17, 0x05, 0x5D, 0x17, 0x07, + 0x10, 0x0B, 0x17, 0x07, 0x28, 0x08, 0x17, 0x07, 0x0C, 0x17, 0x04, 0x1C, + 0x20, 0x00, 0x00, 0x00, 0x06, 0x17, 0x04, 0x04, 0x17, 0x07, 0x08, 0x17, + 0x04, 0x50, 0x17, 0x04, 0x2C, 0x17, 0x04, 0x1C, 0x17, 0x04, 0x10, 0x17, + 0x08, 0x6C, 0x17, 0x04, 0x10, 0x17, 0x04, 0x38, 0x17, 0x04, 0x40, 0x05, + 0x17, 0x07, 0x1C, 0x17, 0x08, 0x58, 0x17, 0x04, 0x24, 0x17, 0x04, 0x18, + 0x17, 0x08, 0x64, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x17, 0x09, 0x0C, 0x17, 0x05, 0x82, + 0x58, 0x17, 0x07, 0x61, 0xC1, 0x17, 0x07, 0x50, 0x17, 0x04, 0x04, 0x17, + 0x08, 0x81, 0x48, 0x17, 0x04, 0x04, 0x17, 0x04, 0x28, 0x17, 0x04, 0x60, + 0x17, 0x08, 0x54, 0x27, 0x17, 0x04, 0x04, 0x17, 0x07, 0x14, 0x17, 0x04, + 0x04, 0x04, 0x17, 0x07, 0x81, 0x58, 0x17, 0x0C, 0x0C, 0x1C, 0x03, 0x00, + 0x00, 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x17, 0x04, 0x5A, 0xF3, 0x0C, + 0x04, 0x05, 0x1B, 0x06, 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, + 0x08, 0x1D, 0x09, 0x0A, 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, + 0x02, 0x1B, 0x1C, 0x23, 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, + 0x0A, 0x0B, 0x1D, 0x0D, 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, + 0x24, 0x06, 0x07, 0x9A, 0x12, 0x17, 0x05, 0x83, 0x41, 0x00, 0xFF, 0x17, + 0x10, 0x83, 0x6C, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, + 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, + 0x00, 0x0B, 0x08, 0x72, 0x72, 0x0E, 0x0C, 0x17, 0x04, 0x20, 0x08, 0x08, + 0x0D, 0x0C, 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x17, 0x06, + 0x2C, 0x11, 0x08, 0x17, 0x10, 0x84, 0x67, 0x15, 0x00, 0xCC, 0x00, 0x0A, + 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, 0xFF, + 0x0F, 0xFF, 0x0F, 0x17, 0x08, 0x83, 0x4C, 0x01, 0x03, 0x00, 0x70, 0x00, + 0x0C, 0x00, 0x01, 0x17, 0x04, 0x0C, 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, + 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, 0x17, 0x04, 0x10, 0xA0, 0x00, 0x2C, + 0x00, 0x01, 0x37, 0x00, 0x00, 0x00, 0x80, 0x17, 0x06, 0x48, 0x08, 0x00, + 0x04, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, + 0x28, 0x28, 0x17, 0x04, 0x04, 0x11, 0x11, 0x11, 0x11, 0x17, 0x04, 0x04, + 0xBE, 0x00, 0x00, 0x17, 0x05, 0x58, 0x17, 0x08, 0x5C, 0x17, 0x22, 0x85, + 0x6A, 0x17, 0x1A, 0x1A, 0x14, 0x00, 0x12, 0x00, 0x10, 0x17, 0x05, 0x83, + 0x0A, 0x17, 0x16, 0x18, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, + 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x17, 0x05, 0x83, 0x0C, 0x17, + 0x04, 0x20, 0x17, 0x18, 0x18, 0x28, 0x00, 0x28, 0x17, 0x04, 0x04, 0x17, + 0x08, 0x08, 0x17, 0x10, 0x10, 0x00, 0x14, 0x17, 0x05, 0x5A, 0x17, 0x04, + 0x5C, 0x17, 0x04, 0x5E, 0x17, 0x04, 0x0E, 0x17, 0x0E, 0x78, 0x17, 0x09, + 0x82, 0x50, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, + 0x17, 0x08, 0x18, 0x80, 0x01, 0x00, 0x00, 0x40, 0x17, 0x04, 0x20, 0x03, + 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, 0x11, 0x17, 0x08, 0x82, 0x58, + 0x17, 0x0C, 0x38, 0x17, 0x1B, 0x81, 0x6C, 0x17, 0x08, 0x85, 0x60, 0x17, + 0x08, 0x86, 0x50, 0x17, 0x08, 0x86, 0x60, 0x17, 0x06, 0x83, 0x21, 0x22, + 0x04, 0xFF, 0xFF, 0xAF, 0x4F, 0x17, 0x0C, 0x86, 0x74, 0x17, 0x08, 0x2C, + 0x8B, 0xFF, 0x07, 0x17, 0x06, 0x81, 0x04, 0x32, 0x54, 0x76, 0x10, 0x47, + 0x32, 0x65, 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, + 0x64, 0x32, 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, + 0x32, 0x67, 0x17, 0x04, 0x24, 0x49, 0x92, 0x24, 0x17, 0x04, 0x04, 0x17, + 0x11, 0x7C, 0x1B, 0x17, 0x04, 0x04, 0x17, 0x13, 0x81, 0x14, 0x2F, 0x41, + 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x17, 0x04, 0x7C, 0xFF, 0xFF, 0xFF, + 0x7F, 0x0B, 0xD7, 0x06, 0x40, 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, + 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x17, 0x06, 0x86, 0x59, + 0x17, 0x0F, 0x89, 0x14, 0x37, 0x17, 0x07, 0x82, 0x72, 0x10, 0x17, 0x06, + 0x83, 0x0D, 0x00, 0x11, 0x01, 0x17, 0x05, 0x85, 0x39, 0x17, 0x04, 0x0E, + 0x0A, 0x17, 0x07, 0x89, 0x29, 0x17, 0x04, 0x1B, 0x17, 0x08, 0x86, 0x77, + 0x17, 0x09, 0x12, 0x20, 0x00, 0x00, 0x00, 0x81, 0x10, 0x09, 0x28, 0x93, + 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, 0x17, 0x18, 0x82, 0x2C, 0xFF, + 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0x17, 0x04, 0x04, 0xDC, 0xDC, + 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x17, 0x04, 0x04, 0x17, 0x04, 0x04, + 0x17, 0x05, 0x82, 0x24, 0x03, 0x07, 0x17, 0x04, 0x04, 0x00, 0x00, 0x24, + 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, + 0x9C, 0x4B, 0x17, 0x04, 0x64, 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, + 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x17, 0x06, 0x85, 0x60, 0x17, + 0x10, 0x82, 0x74, 0x17, 0x08, 0x08, 0x17, 0x08, 0x88, 0x00, 0x17, 0x04, + 0x10, 0x04, 0x17, 0x0B, 0x87, 0x6C, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, + 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x17, 0x08, 0x8B, 0x18, + 0x1F, 0x17, 0x09, 0x81, 0x73, 0x00, 0xFF, 0x00, 0xFF, 0x17, 0x05, 0x86, + 0x48, 0x17, 0x04, 0x0C, 0x17, 0x07, 0x86, 0x34, 0x00, 0x00, 0xF0, 0x17, + 0x09, 0x87, 0x54, 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x17, 0x0C, 0x81, + 0x52, 0x17, 0x0A, 0x1C, 0x17, 0x10, 0x81, 0x6C, 0x17, 0x0A, 0x82, 0x21, + 0x17, 0x07, 0x82, 0x4D, 0x17, 0x0A, 0x8A, 0x1B, 0x17, 0x11, 0x2C, 0x76, + 0x0C, 0x17, 0x0A, 0x8A, 0x67, 0x17, 0x0F, 0x84, 0x28, 0x17, 0x06, 0x34, + 0x17, 0x17, 0x3A, 0x7E, 0x16, 0x40, 0x17, 0x0C, 0x8B, 0x1F, 0x17, 0x2A, + 0x38, 0x1E, 0x17, 0x0A, 0x38, 0x17, 0x13, 0x81, 0x28, 0x00, 0xC0, 0x17, + 0x17, 0x55, 0x46, 0x24, 0x17, 0x0A, 0x81, 0x28, 0x17, 0x14, 0x38, 0x17, + 0x18, 0x81, 0x60, 0x46, 0x2C, 0x17, 0x06, 0x38, 0xEC, 0x17, 0x0D, 0x16, + 0x17, 0x0E, 0x82, 0x3C, 0x17, 0x82, 0x0C, 0x8E, 0x68, 0x17, 0x04, 0x24, + 0x17, 0x5C, 0x8E, 0x68, 0x17, 0x07, 0x82, 0x5F, 0x80, 0x17, 0x87, 0x01, + 0x8E, 0x68, 0x02, 0x17, 0x81, 0x4A, 0x8E, 0x68, 0x17, 0x0C, 0x87, 0x78, + 0x17, 0x85, 0x28, 0x8E, 0x68, 0x17, 0x8E, 0x68, 0x9D, 0x50, 0x17, 0x81, + 0x24, 0x8E, 0x68, 0x17, 0x04, 0x2C, 0x17, 0x28, 0x8E, 0x68, 0x17, 0x04, + 0x30, 0x17, 0x85, 0x3C, 0x8E, 0x68, 0x12, 0x17, 0x07, 0x85, 0x70, 0x17, + 0x88, 0x74, 0x8E, 0x68, 0x17, 0x87, 0x3E, 0x9D, 0x50, 0x0C, 0x17, 0x04, + 0x04, 0x17, 0x12, 0x8E, 0x68, 0x18, 0x17, 0x87, 0x12, 0xBB, 0x20, 0x17, + 0x83, 0x04, 0x9D, 0x50, 0x15, 0x17, 0x05, 0x8D, 0x76, 0x17, 0x0F, 0x8B, + 0x49, 0x17, 0x0B, 0x18, 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, + 0x34, 0x00, 0x36, 0x00, 0x2F, 0x00, 0x33, 0x17, 0x09, 0x84, 0x0C, 0x17, + 0x18, 0x18, 0x17, 0x20, 0x8E, 0x68, 0x15, 0x17, 0x07, 0x5A, 0x17, 0x06, + 0x5E, 0x16, 0x00, 0x15, 0x17, 0x82, 0x40, 0x9D, 0x50, 0x17, 0x86, 0x5F, + 0xBB, 0x20, 0x3A, 0x00, 0x00, 0x00, 0x1D, 0x17, 0x81, 0x4F, 0xAC, 0x38, + 0x3B, 0x17, 0x04, 0x04, 0x17, 0x86, 0x30, 0x8E, 0x68, 0x17, 0x81, 0x53, + 0xAC, 0x38, 0x07, 0x17, 0x0D, 0x8E, 0x68, 0xA3, 0x72, 0x17, 0x83, 0x10, + 0x8E, 0x68 +}; diff --git a/ipl/sdram_param_t210.h b/ipl/sdram_param_t210.h new file mode 100755 index 0000000..2ab6d42 --- /dev/null +++ b/ipl/sdram_param_t210.h @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * See file CREDITS for list of people who contributed to this + * project. + */ + +/** + * Defines the SDRAM parameter structure. + * + * Note that PLLM is used by EMC. + */ + +#ifndef _SDRAM_PARAM_T210_H_ +#define _SDRAM_PARAM_T210_H_ + +#define MEMORY_TYPE_NONE 0 +#define MEMORY_TYPE_DDR 0 +#define MEMORY_TYPE_LPDDR 0 +#define MEMORY_TYPE_DDR2 0 +#define MEMORY_TYPE_LPDDR2 1 +#define MEMORY_TYPE_DDR3 2 +#define MEMORY_TYPE_LPDDR4 3 + +/** + * Defines the SDRAM parameter structure + */ +typedef struct _sdram_params { + /* Specifies the type of memory device */ + u32 memory_type; + + /* MC/EMC clock source configuration */ + + /* Specifies the M value for PllM */ + u32 pllm_input_divider; + /* Specifies the N value for PllM */ + u32 pllm_feedback_divider; + /* Specifies the time to wait for PLLM to lock (in microseconds) */ + u32 pllm_stable_time; + /* Specifies misc. control bits */ + u32 pllm_setup_control; + /* Specifies the P value for PLLM */ + u32 pllm_post_divider; + /* Specifies value for Charge Pump Gain Control */ + u32 pllm_kcp; + /* Specifies VCO gain */ + u32 pllm_kvco; + /* Spare BCT param */ + u32 emc_bct_spare0; + /* Spare BCT param */ + u32 emc_bct_spare1; + /* Spare BCT param */ + u32 emc_bct_spare2; + /* Spare BCT param */ + u32 emc_bct_spare3; + /* Spare BCT param */ + u32 emc_bct_spare4; + /* Spare BCT param */ + u32 emc_bct_spare5; + /* Spare BCT param */ + u32 emc_bct_spare6; + /* Spare BCT param */ + u32 emc_bct_spare7; + /* Spare BCT param */ + u32 emc_bct_spare8; + /* Spare BCT param */ + u32 emc_bct_spare9; + /* Spare BCT param */ + u32 emc_bct_spare10; + /* Spare BCT param */ + u32 emc_bct_spare11; + /* Spare BCT param */ + u32 emc_bct_spare12; + /* Spare BCT param */ + u32 emc_bct_spare13; + + /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ + u32 emc_clock_source; + u32 emc_clock_source_dll; + + /* Defines possible override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override; + /* enables override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override_enable; + /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ + u32 clear_clock2_mc1; + + /* Auto-calibration of EMC pads */ + + /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ + u32 emc_auto_cal_interval; + /* + * Specifies the value for EMC_AUTO_CAL_CONFIG + * Note: Trigger bits are set by the SDRAM code. + */ + u32 emc_auto_cal_config; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ + u32 emc_auto_cal_config2; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ + u32 emc_auto_cal_config3; + + u32 emc_auto_cal_config4; + u32 emc_auto_cal_config5; + u32 emc_auto_cal_config6; + u32 emc_auto_cal_config7; + u32 emc_auto_cal_config8; + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ + u32 emc_auto_cal_vref_sel0; + u32 emc_auto_cal_vref_sel1; + + /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ + u32 emc_auto_cal_channel; + + /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ + u32 emc_pmacro_auto_cal_cfg0; + u32 emc_pmacro_auto_cal_cfg1; + u32 emc_pmacro_auto_cal_cfg2; + + u32 emc_pmacro_rx_term; + u32 emc_pmacro_dq_tx_drive; + u32 emc_pmacro_ca_tx_drive; + u32 emc_pmacro_cmd_tx_drive; + u32 emc_pmacro_auto_cal_common; + u32 emc_pmacro_zcrtl; + + /* + * Specifies the time for the calibration + * to stabilize (in microseconds) + */ + u32 emc_auto_cal_wait; + + u32 emc_xm2_comp_pad_ctrl; + u32 emc_xm2_comp_pad_ctrl2; + u32 emc_xm2_comp_pad_ctrl3; + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + u32 emc_adr_cfg; + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + u32 emc_pin_program_wait; + /* Specifies the extra delay before/after pin RESET/CKE command */ + u32 emc_pin_extra_wait; + + u32 emc_pin_gpio_enable; + u32 emc_pin_gpio; + + /* + * Specifies the extra delay after the first writing + * of EMC_TIMING_CONTROL + */ + u32 emc_timing_control_wait; + + /* Timing parameters required for the SDRAM */ + + /* Specifies the value for EMC_RC */ + u32 emc_rc; + /* Specifies the value for EMC_RFC */ + u32 emc_rfc; + + u32 emc_rfc_pb; + u32 emc_ref_ctrl2; + + /* Specifies the value for EMC_RFC_SLR */ + u32 emc_rfc_slr; + /* Specifies the value for EMC_RAS */ + u32 emc_ras; + /* Specifies the value for EMC_RP */ + u32 emc_rp; + /* Specifies the value for EMC_R2R */ + u32 emc_r2r; + /* Specifies the value for EMC_W2W */ + u32 emc_w2w; + /* Specifies the value for EMC_R2W */ + u32 emc_r2w; + /* Specifies the value for EMC_W2R */ + u32 emc_w2r; + /* Specifies the value for EMC_R2P */ + u32 emc_r2p; + /* Specifies the value for EMC_W2P */ + u32 emc_w2p; + /* Specifies the value for EMC_RD_RCD */ + + u32 emc_tppd; + u32 emc_ccdmw; + + u32 emc_rd_rcd; + /* Specifies the value for EMC_WR_RCD */ + u32 emc_wr_rcd; + /* Specifies the value for EMC_RRD */ + u32 emc_rrd; + /* Specifies the value for EMC_REXT */ + u32 emc_rext; + /* Specifies the value for EMC_WEXT */ + u32 emc_wext; + /* Specifies the value for EMC_WDV */ + u32 emc_wdv; + + u32 emc_wdv_chk; + u32 emc_wsv; + u32 emc_wev; + + /* Specifies the value for EMC_WDV_MASK */ + u32 emc_wdv_mask; + + u32 emc_ws_duration; + u32 emc_we_duration; + + /* Specifies the value for EMC_QUSE */ + u32 emc_quse; + /* Specifies the value for EMC_QUSE_WIDTH */ + u32 emc_quse_width; + /* Specifies the value for EMC_IBDLY */ + u32 emc_ibdly; + + u32 emc_obdly; + + /* Specifies the value for EMC_EINPUT */ + u32 emc_einput; + /* Specifies the value for EMC_EINPUT_DURATION */ + u32 emc_einput_duration; + /* Specifies the value for EMC_PUTERM_EXTRA */ + u32 emc_puterm_extra; + /* Specifies the value for EMC_PUTERM_WIDTH */ + u32 emc_puterm_width; + + u32 emc_qrst; + u32 emc_qsafe; + u32 emc_rdv; + u32 emc_rdv_mask; + + u32 emc_rdv_early; + u32 emc_rdv_early_mask; + + /* Specifies the value for EMC_QPOP */ + u32 emc_qpop; + + /* Specifies the value for EMC_REFRESH */ + u32 emc_refresh; + /* Specifies the value for EMC_BURST_REFRESH_NUM */ + u32 emc_burst_refresh_num; + /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ + u32 emc_prerefresh_req_cnt; + /* Specifies the value for EMC_PDEX2WR */ + u32 emc_pdex2wr; + /* Specifies the value for EMC_PDEX2RD */ + u32 emc_pdex2rd; + /* Specifies the value for EMC_PCHG2PDEN */ + u32 emc_pchg2pden; + /* Specifies the value for EMC_ACT2PDEN */ + u32 emc_act2pden; + /* Specifies the value for EMC_AR2PDEN */ + u32 emc_ar2pden; + /* Specifies the value for EMC_RW2PDEN */ + u32 emc_rw2pden; + + u32 emc_cke2pden; + u32 emc_pdex2che; + u32 emc_pdex2mrr; + + /* Specifies the value for EMC_TXSR */ + u32 emc_txsr; + /* Specifies the value for EMC_TXSRDLL */ + u32 emc_txsr_dll; + /* Specifies the value for EMC_TCKE */ + u32 emc_tcke; + /* Specifies the value for EMC_TCKESR */ + u32 emc_tckesr; + /* Specifies the value for EMC_TPD */ + u32 emc_tpd; + /* Specifies the value for EMC_TFAW */ + u32 emc_tfaw; + /* Specifies the value for EMC_TRPAB */ + u32 emc_trpab; + /* Specifies the value for EMC_TCLKSTABLE */ + u32 emc_tclkstable; + /* Specifies the value for EMC_TCLKSTOP */ + u32 emc_tclkstop; + /* Specifies the value for EMC_TREFBW */ + u32 emc_trefbw; + + /* FBIO configuration values */ + + /* Specifies the value for EMC_FBIO_CFG5 */ + u32 emc_fbio_cfg5; + /* Specifies the value for EMC_FBIO_CFG7 */ + u32 emc_fbio_cfg7; + u32 emc_fbio_cfg8; + + /* Command mapping for CMD brick 0 */ + u32 emc_cmd_mapping_cmd0_0; + u32 emc_cmd_mapping_cmd0_1; + u32 emc_cmd_mapping_cmd0_2; + u32 emc_cmd_mapping_cmd1_0; + u32 emc_cmd_mapping_cmd1_1; + u32 emc_cmd_mapping_cmd1_2; + u32 emc_cmd_mapping_cmd2_0; + u32 emc_cmd_mapping_cmd2_1; + u32 emc_cmd_mapping_cmd2_2; + u32 emc_cmd_mapping_cmd3_0; + u32 emc_cmd_mapping_cmd3_1; + u32 emc_cmd_mapping_cmd3_2; + u32 emc_cmd_mapping_byte; + + /* Specifies the value for EMC_FBIO_SPARE */ + u32 emc_fbio_spare; + + /* Specifies the value for EMC_CFG_RSV */ + u32 emc_cfg_rsv; + + /* MRS command values */ + + /* Specifies the value for EMC_MRS */ + u32 emc_mrs; + /* Specifies the MP0 command to initialize mode registers */ + u32 emc_emrs; + /* Specifies the MP2 command to initialize mode registers */ + u32 emc_emrs2; + /* Specifies the MP3 command to initialize mode registers */ + u32 emc_emrs3; + /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ + u32 emc_mrw1; + /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ + u32 emc_mrw2; + /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ + u32 emc_mrw3; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 emc_mrw4; + + /* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */ + u32 emc_mrw6; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw8; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw9; + /* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */ + u32 emc_mrw10; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw12; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw13; + /* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */ + u32 emc_mrw14; + + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at cold boot + */ + u32 emc_mrw_extra; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at warm boot + */ + u32 emc_warm_boot_mrw_extra; + /* + * Specify the enable of extra Mode Register programming at + * warm boot + */ + u32 emc_warm_boot_extramode_reg_write_enable; + /* + * Specify the enable of extra Mode Register programming at + * cold boot + */ + u32 emc_extramode_reg_write_enable; + + /* Specifies the EMC_MRW reset command value */ + u32 emc_mrw_reset_command; + /* Specifies the EMC Reset wait time (in microseconds) */ + u32 emc_mrw_reset_ninit_wait; + /* Specifies the value for EMC_MRS_WAIT_CNT */ + u32 emc_mrs_wait_cnt; + /* Specifies the value for EMC_MRS_WAIT_CNT2 */ + u32 emc_mrs_wait_cnt2; + + /* EMC miscellaneous configurations */ + + /* Specifies the value for EMC_CFG */ + u32 emc_cfg; + /* Specifies the value for EMC_CFG_2 */ + u32 emc_cfg2; + /* Specifies the pipe bypass controls */ + u32 emc_cfg_pipe; + + u32 emc_cfg_pipe_clk; + u32 emc_fdpd_ctrl_cmd_no_ramp; + u32 emc_cfg_update; + + /* Specifies the value for EMC_DBG */ + u32 emc_dbg; + + u32 emc_dbg_write_mux; + + /* Specifies the value for EMC_CMDQ */ + u32 emc_cmd_q; + /* Specifies the value for EMC_MC2EMCQ */ + u32 emc_mc2emc_q; + /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ + u32 emc_dyn_self_ref_control; + + /* Specifies the value for MEM_INIT_DONE */ + u32 ahb_arbitration_xbar_ctrl_meminit_done; + + /* Specifies the value for EMC_CFG_DIG_DLL */ + u32 emc_cfg_dig_dll; + u32 emc_cfg_dig_dll_1; + + /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ + u32 emc_cfg_dig_dll_period; + /* Specifies the value of *DEV_SELECTN of various EMC registers */ + u32 emc_dev_select; + + /* Specifies the value for EMC_SEL_DPD_CTRL */ + u32 emc_sel_dpd_ctrl; + + /* Pads trimmer delays */ + u32 emc_fdpd_ctrl_dq; + u32 emc_fdpd_ctrl_cmd; + u32 emc_pmacro_ib_vref_dq_0; + u32 emc_pmacro_ib_vref_dq_1; + u32 emc_pmacro_ib_vref_dqs_0; + u32 emc_pmacro_ib_vref_dqs_1; + u32 emc_pmacro_ib_rxrt; + u32 emc_cfg_pipe1; + u32 emc_cfg_pipe2; + + /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ + u32 emc_pmacro_quse_ddll_rank0_0; + u32 emc_pmacro_quse_ddll_rank0_1; + u32 emc_pmacro_quse_ddll_rank0_2; + u32 emc_pmacro_quse_ddll_rank0_3; + u32 emc_pmacro_quse_ddll_rank0_4; + u32 emc_pmacro_quse_ddll_rank0_5; + u32 emc_pmacro_quse_ddll_rank1_0; + u32 emc_pmacro_quse_ddll_rank1_1; + u32 emc_pmacro_quse_ddll_rank1_2; + u32 emc_pmacro_quse_ddll_rank1_3; + u32 emc_pmacro_quse_ddll_rank1_4; + u32 emc_pmacro_quse_ddll_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dq_rank0_0; + u32 emc_pmacro_ob_ddll_long_dq_rank0_1; + u32 emc_pmacro_ob_ddll_long_dq_rank0_2; + u32 emc_pmacro_ob_ddll_long_dq_rank0_3; + u32 emc_pmacro_ob_ddll_long_dq_rank0_4; + u32 emc_pmacro_ob_ddll_long_dq_rank0_5; + u32 emc_pmacro_ob_ddll_long_dq_rank1_0; + u32 emc_pmacro_ob_ddll_long_dq_rank1_1; + u32 emc_pmacro_ob_ddll_long_dq_rank1_2; + u32 emc_pmacro_ob_ddll_long_dq_rank1_3; + u32 emc_pmacro_ob_ddll_long_dq_rank1_4; + u32 emc_pmacro_ob_ddll_long_dq_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_5; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_5; + + u32 emc_pmacro_ib_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_3; + + u32 emc_pmacro_ddll_long_cmd_0; + u32 emc_pmacro_ddll_long_cmd_1; + u32 emc_pmacro_ddll_long_cmd_2; + u32 emc_pmacro_ddll_long_cmd_3; + u32 emc_pmacro_ddll_long_cmd_4; + u32 emc_pmacro_ddll_short_cmd_0; + u32 emc_pmacro_ddll_short_cmd_1; + u32 emc_pmacro_ddll_short_cmd_2; + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + u32 warm_boot_wait; + + /* Specifies the value for EMC_ODT_WRITE */ + u32 emc_odt_write; + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + u32 emc_zcal_interval; + /* Specifies the value for EMC_ZCAL_WAIT_CNT */ + u32 emc_zcal_wait_cnt; + /* Specifies the value for EMC_ZCAL_MRW_CMD */ + u32 emc_zcal_mrw_cmd; + + /* DRAM initialization sequence flow control */ + + /* Specifies the MRS command value for resetting DLL */ + u32 emc_mrs_reset_dll; + /* Specifies the command for ZQ initialization of device 0 */ + u32 emc_zcal_init_dev0; + /* Specifies the command for ZQ initialization of device 1 */ + u32 emc_zcal_init_dev1; + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + u32 emc_zcal_init_wait; + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + u32 emc_zcal_warm_cold_boot_enables; + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + u32 emc_mrw_lpddr2zcal_warm_boot; + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + u32 emc_zqcal_ddr3_warm_boot; + + u32 emc_zqcal_lpddr4_warm_boot; + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + u32 emc_zcal_warm_boot_wait; + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + u32 emc_mrs_warm_boot_enable; + /* + * Specifies the wait time after sending an MRS DLL reset command + * in microseconds) + */ + u32 emc_mrs_reset_dll_wait; + /* Specifies the extra MRS command to initialize mode registers */ + u32 emc_mrs_extra; + /* Specifies the extra MRS command at warm boot */ + u32 emc_warm_boot_mrs_extra; + /* Specifies the EMRS command to enable the DDR2 DLL */ + u32 emc_emrs_ddr2_dll_enable; + /* Specifies the MRS command to reset the DDR2 DLL */ + u32 emc_mrs_ddr2_dll_reset; + /* Specifies the EMRS command to set OCD calibration */ + u32 emc_emrs_ddr2_ocd_calib; + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + u32 emc_ddr2_wait; + /* Specifies the value for EMC_CLKEN_OVERRIDE */ + u32 emc_clken_override; + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + u32 emc_extra_refresh_num; + /* Specifies the master override for all EMC clocks */ + u32 emc_clken_override_allwarm_boot; + /* Specifies the master override for all MC clocks */ + u32 mc_clken_override_allwarm_boot; + /* Specifies digital dll period, choosing between 4 to 64 ms */ + u32 emc_cfg_dig_dll_period_warm_boot; + + /* Pad controls */ + + /* Specifies the value for PMC_VDDP_SEL */ + u32 pmc_vddp_sel; + /* Specifies the wait time after programming PMC_VDDP_SEL */ + u32 pmc_vddp_sel_wait; + /* Specifies the value for PMC_DDR_PWR */ + u32 pmc_ddr_pwr; + /* Specifies the value for PMC_DDR_CFG */ + u32 pmc_ddr_cfg; + /* Specifies the value for PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req; + /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req_wait; + + u32 pmc_io_dpd4_req_wait; + + /* Specifies the value for PMC_REG_SHORT */ + u32 pmc_reg_short; + /* Specifies the value for PMC_NO_IOPOWER */ + u32 pmc_no_io_power; + + u32 pmc_ddr_ctrl_wait; + u32 pmc_ddr_ctrl; + + /* Specifies the value for EMC_ACPD_CONTROL */ + u32 emc_acpd_control; + + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ + u32 emc_swizzle_rank0_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ + u32 emc_swizzle_rank0_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ + u32 emc_swizzle_rank0_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ + u32 emc_swizzle_rank0_byte3; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ + u32 emc_swizzle_rank1_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ + u32 emc_swizzle_rank1_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ + u32 emc_swizzle_rank1_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ + u32 emc_swizzle_rank1_byte3; + + /* Specifies the value for EMC_TXDSRVTTGEN */ + u32 emc_txdsrvttgen; + + /* Specifies the value for EMC_DATA_BRLSHFT_0 */ + u32 emc_data_brlshft0; + u32 emc_data_brlshft1; + + u32 emc_dqs_brlshft0; + u32 emc_dqs_brlshft1; + + u32 emc_cmd_brlshft0; + u32 emc_cmd_brlshft1; + u32 emc_cmd_brlshft2; + u32 emc_cmd_brlshft3; + + u32 emc_quse_brlshft0; + u32 emc_quse_brlshft1; + u32 emc_quse_brlshft2; + u32 emc_quse_brlshft3; + + u32 emc_dll_cfg0; + u32 emc_dll_cfg1; + + u32 emc_pmc_scratch1; + u32 emc_pmc_scratch2; + u32 emc_pmc_scratch3; + + u32 emc_pmacro_pad_cfg_ctrl; + + u32 emc_pmacro_vttgen_ctrl0; + u32 emc_pmacro_vttgen_ctrl1; + u32 emc_pmacro_vttgen_ctrl2; + + u32 emc_pmacro_brick_ctrl_rfu1; + u32 emc_pmacro_cmd_brick_ctrl_fdpd; + u32 emc_pmacro_brick_ctrl_rfu2; + u32 emc_pmacro_data_brick_ctrl_fdpd; + u32 emc_pmacro_bg_bias_ctrl0; + u32 emc_pmacro_data_pad_rx_ctrl; + u32 emc_pmacro_cmd_pad_rx_ctrl; + u32 emc_pmacro_data_rx_term_mode; + u32 emc_pmacro_cmd_rx_term_mode; + u32 emc_pmacro_data_pad_tx_ctrl; + u32 emc_pmacro_common_pad_tx_ctrl; + u32 emc_pmacro_cmd_pad_tx_ctrl; + u32 emc_cfg3; + + u32 emc_pmacro_tx_pwrd0; + u32 emc_pmacro_tx_pwrd1; + u32 emc_pmacro_tx_pwrd2; + u32 emc_pmacro_tx_pwrd3; + u32 emc_pmacro_tx_pwrd4; + u32 emc_pmacro_tx_pwrd5; + + u32 emc_config_sample_delay; + + u32 emc_pmacro_brick_mapping0; + u32 emc_pmacro_brick_mapping1; + u32 emc_pmacro_brick_mapping2; + + u32 emc_pmacro_tx_sel_clk_src0; + u32 emc_pmacro_tx_sel_clk_src1; + u32 emc_pmacro_tx_sel_clk_src2; + u32 emc_pmacro_tx_sel_clk_src3; + u32 emc_pmacro_tx_sel_clk_src4; + u32 emc_pmacro_tx_sel_clk_src5; + + u32 emc_pmacro_ddll_bypass; + + u32 emc_pmacro_ddll_pwrd0; + u32 emc_pmacro_ddll_pwrd1; + u32 emc_pmacro_ddll_pwrd2; + + u32 emc_pmacro_cmd_ctrl0; + u32 emc_pmacro_cmd_ctrl1; + u32 emc_pmacro_cmd_ctrl2; + + /* DRAM size information */ + + /* Specifies the value for MC_EMEM_ADR_CFG */ + u32 mc_emem_adr_cfg; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ + u32 mc_emem_adr_cfg_dev0; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ + u32 mc_emem_adr_cfg_dev1; + + u32 mc_emem_adr_cfg_channel_mask; + + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */ + u32 mc_emem_adr_cfg_bank_mask0; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ + u32 mc_emem_adr_cfg_bank_mask1; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ + u32 mc_emem_adr_cfg_bank_mask2; + + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + u32 mc_emem_cfg; + + /* MC arbitration configuration */ + + /* Specifies the value for MC_EMEM_ARB_CFG */ + u32 mc_emem_arb_cfg; + /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ + u32 mc_emem_arb_outstanding_req; + + u32 emc_emem_arb_refpb_hp_ctrl; + u32 emc_emem_arb_refpb_bank_ctrl; + + /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ + u32 mc_emem_arb_timing_rcd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ + u32 mc_emem_arb_timing_rp; + /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ + u32 mc_emem_arb_timing_rc; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ + u32 mc_emem_arb_timing_ras; + /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ + u32 mc_emem_arb_timing_faw; + /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ + u32 mc_emem_arb_timing_rrd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ + u32 mc_emem_arb_timing_rap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ + u32 mc_emem_arb_timing_wap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ + u32 mc_emem_arb_timing_r2r; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ + u32 mc_emem_arb_timing_w2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ + u32 mc_emem_arb_timing_r2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ + u32 mc_emem_arb_timing_w2r; + + u32 mc_emem_arb_timing_rfcpb; + + /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ + u32 mc_emem_arb_da_turns; + /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ + u32 mc_emem_arb_da_covers; + /* Specifies the value for MC_EMEM_ARB_MISC0 */ + u32 mc_emem_arb_misc0; + /* Specifies the value for MC_EMEM_ARB_MISC1 */ + u32 mc_emem_arb_misc1; + u32 mc_emem_arb_misc2; + + /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ + u32 mc_emem_arb_ring1_throttle; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ + u32 mc_emem_arb_override; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ + u32 mc_emem_arb_override1; + /* Specifies the value for MC_EMEM_ARB_RSV */ + u32 mc_emem_arb_rsv; + + u32 mc_da_cfg0; + u32 mc_emem_arb_timing_ccdmw; + + /* Specifies the value for MC_CLKEN_OVERRIDE */ + u32 mc_clken_override; + + /* Specifies the value for MC_STAT_CONTROL */ + u32 mc_stat_control; + /* Specifies the value for MC_VIDEO_PROTECT_BOM */ + u32 mc_video_protect_bom; + /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ + u32 mc_video_protect_bom_adr_hi; + /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ + u32 mc_video_protect_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ + u32 mc_video_protect_vpr_override; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ + u32 mc_video_protect_vpr_override1; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ + u32 mc_video_protect_gpu_override0; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ + u32 mc_video_protect_gpu_override1; + /* Specifies the value for MC_SEC_CARVEOUT_BOM */ + u32 mc_sec_carveout_bom; + /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ + u32 mc_sec_carveout_adr_hi; + /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ + u32 mc_sec_carveout_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */ + u32 mc_video_protect_write_access; + /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */ + u32 mc_sec_carveout_protect_write_access; + + u32 mc_generalized_carveout1_bom; + u32 mc_generalized_carveout1_bom_hi; + u32 mc_generalized_carveout1_size_128kb; + u32 mc_generalized_carveout1_access0; + u32 mc_generalized_carveout1_access1; + u32 mc_generalized_carveout1_access2; + u32 mc_generalized_carveout1_access3; + u32 mc_generalized_carveout1_access4; + u32 mc_generalized_carveout1_force_internal_access0; + u32 mc_generalized_carveout1_force_internal_access1; + u32 mc_generalized_carveout1_force_internal_access2; + u32 mc_generalized_carveout1_force_internal_access3; + u32 mc_generalized_carveout1_force_internal_access4; + u32 mc_generalized_carveout1_cfg0; + + u32 mc_generalized_carveout2_bom; + u32 mc_generalized_carveout2_bom_hi; + u32 mc_generalized_carveout2_size_128kb; + u32 mc_generalized_carveout2_access0; + u32 mc_generalized_carveout2_access1; + u32 mc_generalized_carveout2_access2; + u32 mc_generalized_carveout2_access3; + u32 mc_generalized_carveout2_access4; + u32 mc_generalized_carveout2_force_internal_access0; + u32 mc_generalized_carveout2_force_internal_access1; + u32 mc_generalized_carveout2_force_internal_access2; + u32 mc_generalized_carveout2_force_internal_access3; + u32 mc_generalized_carveout2_force_internal_access4; + u32 mc_generalized_carveout2_cfg0; + + u32 mc_generalized_carveout3_bom; + u32 mc_generalized_carveout3_bom_hi; + u32 mc_generalized_carveout3_size_128kb; + u32 mc_generalized_carveout3_access0; + u32 mc_generalized_carveout3_access1; + u32 mc_generalized_carveout3_access2; + u32 mc_generalized_carveout3_access3; + u32 mc_generalized_carveout3_access4; + u32 mc_generalized_carveout3_force_internal_access0; + u32 mc_generalized_carveout3_force_internal_access1; + u32 mc_generalized_carveout3_force_internal_access2; + u32 mc_generalized_carveout3_force_internal_access3; + u32 mc_generalized_carveout3_force_internal_access4; + u32 mc_generalized_carveout3_cfg0; + + u32 mc_generalized_carveout4_bom; + u32 mc_generalized_carveout4_bom_hi; + u32 mc_generalized_carveout4_size_128kb; + u32 mc_generalized_carveout4_access0; + u32 mc_generalized_carveout4_access1; + u32 mc_generalized_carveout4_access2; + u32 mc_generalized_carveout4_access3; + u32 mc_generalized_carveout4_access4; + u32 mc_generalized_carveout4_force_internal_access0; + u32 mc_generalized_carveout4_force_internal_access1; + u32 mc_generalized_carveout4_force_internal_access2; + u32 mc_generalized_carveout4_force_internal_access3; + u32 mc_generalized_carveout4_force_internal_access4; + u32 mc_generalized_carveout4_cfg0; + + u32 mc_generalized_carveout5_bom; + u32 mc_generalized_carveout5_bom_hi; + u32 mc_generalized_carveout5_size_128kb; + u32 mc_generalized_carveout5_access0; + u32 mc_generalized_carveout5_access1; + u32 mc_generalized_carveout5_access2; + u32 mc_generalized_carveout5_access3; + u32 mc_generalized_carveout5_access4; + u32 mc_generalized_carveout5_force_internal_access0; + u32 mc_generalized_carveout5_force_internal_access1; + u32 mc_generalized_carveout5_force_internal_access2; + u32 mc_generalized_carveout5_force_internal_access3; + u32 mc_generalized_carveout5_force_internal_access4; + u32 mc_generalized_carveout5_cfg0; + + /* Specifies enable for CA training */ + u32 emc_ca_training_enable; + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + u32 swizzle_rank_byte_encode; + /* Specifies enable and offset for patched boot rom write */ + u32 boot_rom_patch_control; + /* Specifies data for patched boot rom write */ + u32 boot_rom_patch_data; + + /* Specifies the value for MC_MTS_CARVEOUT_BOM */ + u32 mc_mts_carveout_bom; + /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ + u32 mc_mts_carveout_adr_hi; + /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ + u32 mc_mts_carveout_size_mb; + /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ + u32 mc_mts_carveout_reg_ctrl; +} sdram_params_t; + +#endif diff --git a/ipl/sdram_param_t210_lp0.h b/ipl/sdram_param_t210_lp0.h new file mode 100755 index 0000000..7807997 --- /dev/null +++ b/ipl/sdram_param_t210_lp0.h @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * Defines the SDRAM parameter structure. + * + * Note that PLLM is used by EMC. The field names are in camel case to ease + * directly converting BCT config files (*.cfg) into C structure. + */ + +#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ +#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ + +#include "types.h" + +enum { + /* Specifies the memory type to be undefined */ + NvBootMemoryType_None = 0, + + /* Specifies the memory type to be DDR SDRAM */ + NvBootMemoryType_Ddr = 0, + + /* Specifies the memory type to be LPDDR SDRAM */ + NvBootMemoryType_LpDdr = 0, + + /* Specifies the memory type to be DDR2 SDRAM */ + NvBootMemoryType_Ddr2 = 0, + + /* Specifies the memory type to be LPDDR2 SDRAM */ + NvBootMemoryType_LpDdr2, + + /* Specifies the memory type to be DDR3 SDRAM */ + NvBootMemoryType_Ddr3, + + /* Specifies the memory type to be LPDDR4 SDRAM */ + NvBootMemoryType_LpDdr4, + + NvBootMemoryType_Num, + + /* Specifies an entry in the ram_code table that's not in use */ + NvBootMemoryType_Unused = 0X7FFFFFF, +}; + +/** + * Defines the SDRAM parameter structure + */ +struct sdram_params { + + /* Specifies the type of memory device */ + u32 MemoryType; + + /* MC/EMC clock source configuration */ + + /* Specifies the M value for PllM */ + u32 PllMInputDivider; + /* Specifies the N value for PllM */ + u32 PllMFeedbackDivider; + /* Specifies the time to wait for PLLM to lock (in microseconds) */ + u32 PllMStableTime; + /* Specifies misc. control bits */ + u32 PllMSetupControl; + /* Specifies the P value for PLLM */ + u32 PllMPostDivider; + /* Specifies value for Charge Pump Gain Control */ + u32 PllMKCP; + /* Specifies VCO gain */ + u32 PllMKVCO; + /* Spare BCT param */ + u32 EmcBctSpare0; + /* Spare BCT param */ + u32 EmcBctSpare1; + /* Spare BCT param */ + u32 EmcBctSpare2; + /* Spare BCT param */ + u32 EmcBctSpare3; + /* Spare BCT param */ + u32 EmcBctSpare4; + /* Spare BCT param */ + u32 EmcBctSpare5; + /* Spare BCT param */ + u32 EmcBctSpare6; + /* Spare BCT param */ + u32 EmcBctSpare7; + /* Spare BCT param */ + u32 EmcBctSpare8; + /* Spare BCT param */ + u32 EmcBctSpare9; + /* Spare BCT param */ + u32 EmcBctSpare10; + /* Spare BCT param */ + u32 EmcBctSpare11; + /* Spare BCT param */ + u32 EmcBctSpare12; + /* Spare BCT param */ + u32 EmcBctSpare13; + + /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ + u32 EmcClockSource; + u32 EmcClockSourceDll; + + /* Defines possible override for PLLLM_MISC2 */ + u32 ClkRstControllerPllmMisc2Override; + /* enables override for PLLLM_MISC2 */ + u32 ClkRstControllerPllmMisc2OverrideEnable; + /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ + u32 ClearClk2Mc1; + + /* Auto-calibration of EMC pads */ + + /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ + u32 EmcAutoCalInterval; + /* + * Specifies the value for EMC_AUTO_CAL_CONFIG + * Note: Trigger bits are set by the SDRAM code. + */ + u32 EmcAutoCalConfig; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ + u32 EmcAutoCalConfig2; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ + u32 EmcAutoCalConfig3; + + /* Specifies the values for EMC_AUTO_CAL_CONFIG4-8 */ + u32 EmcAutoCalConfig4; + u32 EmcAutoCalConfig5; + u32 EmcAutoCalConfig6; + u32 EmcAutoCalConfig7; + u32 EmcAutoCalConfig8; + + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ + u32 EmcAutoCalVrefSel0; + u32 EmcAutoCalVrefSel1; + + /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ + u32 EmcAutoCalChannel; + + /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ + u32 EmcPmacroAutocalCfg0; + u32 EmcPmacroAutocalCfg1; + u32 EmcPmacroAutocalCfg2; + u32 EmcPmacroRxTerm; + u32 EmcPmacroDqTxDrv; + u32 EmcPmacroCaTxDrv; + u32 EmcPmacroCmdTxDrv; + u32 EmcPmacroAutocalCfgCommon; + u32 EmcPmacroZctrl; + + /* + * Specifies the time for the calibration + * to stabilize (in microseconds) + */ + u32 EmcAutoCalWait; + + u32 EmcXm2CompPadCtrl; + u32 EmcXm2CompPadCtrl2; + u32 EmcXm2CompPadCtrl3; + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + u32 EmcAdrCfg; + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + u32 EmcPinProgramWait; + /* Specifies the extra delay before/after pin RESET/CKE command */ + u32 EmcPinExtraWait; + + u32 EmcPinGpioEn; + u32 EmcPinGpio; + + /* + * Specifies the extra delay after the first writing + * of EMC_TIMING_CONTROL + */ + u32 EmcTimingControlWait; + + /* Timing parameters required for the SDRAM */ + + /* Specifies the value for EMC_RC */ + u32 EmcRc; + /* Specifies the value for EMC_RFC */ + u32 EmcRfc; + /* Specifies the value for EMC_RFC_PB */ + u32 EmcRfcPb; + /* Specifies the value for EMC_RFC_CTRL2 */ + u32 EmcRefctrl2; + /* Specifies the value for EMC_RFC_SLR */ + u32 EmcRfcSlr; + /* Specifies the value for EMC_RAS */ + u32 EmcRas; + /* Specifies the value for EMC_RP */ + u32 EmcRp; + /* Specifies the value for EMC_R2R */ + u32 EmcR2r; + /* Specifies the value for EMC_W2W */ + u32 EmcW2w; + /* Specifies the value for EMC_R2W */ + u32 EmcR2w; + /* Specifies the value for EMC_W2R */ + u32 EmcW2r; + /* Specifies the value for EMC_R2P */ + u32 EmcR2p; + /* Specifies the value for EMC_W2P */ + u32 EmcW2p; + + u32 EmcTppd; + u32 EmcCcdmw; + + /* Specifies the value for EMC_RD_RCD */ + u32 EmcRdRcd; + /* Specifies the value for EMC_WR_RCD */ + u32 EmcWrRcd; + /* Specifies the value for EMC_RRD */ + u32 EmcRrd; + /* Specifies the value for EMC_REXT */ + u32 EmcRext; + /* Specifies the value for EMC_WEXT */ + u32 EmcWext; + /* Specifies the value for EMC_WDV */ + u32 EmcWdv; + + u32 EmcWdvChk; + u32 EmcWsv; + u32 EmcWev; + + /* Specifies the value for EMC_WDV_MASK */ + u32 EmcWdvMask; + + u32 EmcWsDuration; + u32 EmcWeDuration; + + /* Specifies the value for EMC_QUSE */ + u32 EmcQUse; + /* Specifies the value for EMC_QUSE_WIDTH */ + u32 EmcQuseWidth; + /* Specifies the value for EMC_IBDLY */ + u32 EmcIbdly; + /* Specifies the value for EMC_OBDLY */ + u32 EmcObdly; + /* Specifies the value for EMC_EINPUT */ + u32 EmcEInput; + /* Specifies the value for EMC_EINPUT_DURATION */ + u32 EmcEInputDuration; + /* Specifies the value for EMC_PUTERM_EXTRA */ + u32 EmcPutermExtra; + /* Specifies the value for EMC_PUTERM_WIDTH */ + u32 EmcPutermWidth; + /* Specifies the value for EMC_PUTERM_ADJ */ + u32 EmcPutermAdj; + + /* Specifies the value for EMC_QRST */ + u32 EmcQRst; + /* Specifies the value for EMC_QSAFE */ + u32 EmcQSafe; + /* Specifies the value for EMC_RDV */ + u32 EmcRdv; + /* Specifies the value for EMC_RDV_MASK */ + u32 EmcRdvMask; + /* Specifies the value for EMC_RDV_EARLY */ + u32 EmcRdvEarly; + /* Specifies the value for EMC_RDV_EARLY_MASK */ + u32 EmcRdvEarlyMask; + /* Specifies the value for EMC_QPOP */ + u32 EmcQpop; + + /* Specifies the value for EMC_REFRESH */ + u32 EmcRefresh; + /* Specifies the value for EMC_BURST_REFRESH_NUM */ + u32 EmcBurstRefreshNum; + /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ + u32 EmcPreRefreshReqCnt; + /* Specifies the value for EMC_PDEX2WR */ + u32 EmcPdEx2Wr; + /* Specifies the value for EMC_PDEX2RD */ + u32 EmcPdEx2Rd; + /* Specifies the value for EMC_PCHG2PDEN */ + u32 EmcPChg2Pden; + /* Specifies the value for EMC_ACT2PDEN */ + u32 EmcAct2Pden; + /* Specifies the value for EMC_AR2PDEN */ + u32 EmcAr2Pden; + /* Specifies the value for EMC_RW2PDEN */ + u32 EmcRw2Pden; + /* Specifies the value for EMC_CKE2PDEN */ + u32 EmcCke2Pden; + /* Specifies the value for EMC_PDEX2CKE */ + u32 EmcPdex2Cke; + /* Specifies the value for EMC_PDEX2MRR */ + u32 EmcPdex2Mrr; + /* Specifies the value for EMC_TXSR */ + u32 EmcTxsr; + /* Specifies the value for EMC_TXSRDLL */ + u32 EmcTxsrDll; + /* Specifies the value for EMC_TCKE */ + u32 EmcTcke; + /* Specifies the value for EMC_TCKESR */ + u32 EmcTckesr; + /* Specifies the value for EMC_TPD */ + u32 EmcTpd; + /* Specifies the value for EMC_TFAW */ + u32 EmcTfaw; + /* Specifies the value for EMC_TRPAB */ + u32 EmcTrpab; + /* Specifies the value for EMC_TCLKSTABLE */ + u32 EmcTClkStable; + /* Specifies the value for EMC_TCLKSTOP */ + u32 EmcTClkStop; + /* Specifies the value for EMC_TREFBW */ + u32 EmcTRefBw; + + /* FBIO configuration values */ + + /* Specifies the value for EMC_FBIO_CFG5 */ + u32 EmcFbioCfg5; + /* Specifies the value for EMC_FBIO_CFG7 */ + u32 EmcFbioCfg7; + /* Specifies the value for EMC_FBIO_CFG8 */ + u32 EmcFbioCfg8; + + /* Command mapping for CMD brick 0 */ + u32 EmcCmdMappingCmd0_0; + u32 EmcCmdMappingCmd0_1; + u32 EmcCmdMappingCmd0_2; + u32 EmcCmdMappingCmd1_0; + u32 EmcCmdMappingCmd1_1; + u32 EmcCmdMappingCmd1_2; + u32 EmcCmdMappingCmd2_0; + u32 EmcCmdMappingCmd2_1; + u32 EmcCmdMappingCmd2_2; + u32 EmcCmdMappingCmd3_0; + u32 EmcCmdMappingCmd3_1; + u32 EmcCmdMappingCmd3_2; + u32 EmcCmdMappingByte; + + /* Specifies the value for EMC_FBIO_SPARE */ + u32 EmcFbioSpare; + + /* Specifies the value for EMC_CFG_RSV */ + u32 EmcCfgRsv; + + /* MRS command values */ + + /* Specifies the value for EMC_MRS */ + u32 EmcMrs; + /* Specifies the MP0 command to initialize mode registers */ + u32 EmcEmrs; + /* Specifies the MP2 command to initialize mode registers */ + u32 EmcEmrs2; + /* Specifies the MP3 command to initialize mode registers */ + u32 EmcEmrs3; + /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ + u32 EmcMrw1; + /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ + u32 EmcMrw2; + /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ + u32 EmcMrw3; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 EmcMrw4; + /* Specifies the programming to LPDDR2 Mode Register 3? at cold boot */ + u32 EmcMrw6; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 EmcMrw8; + /* Specifies the programming to LPDDR2 Mode Register 11? at cold boot */ + u32 EmcMrw9; + /* Specifies the programming to LPDDR2 Mode Register 12 at cold boot */ + u32 EmcMrw10; + /* Specifies the programming to LPDDR2 Mode Register 14 at cold boot */ + u32 EmcMrw12; + /* Specifies the programming to LPDDR2 Mode Register 14? at cold boot */ + u32 EmcMrw13; + /* Specifies the programming to LPDDR2 Mode Register 22 at cold boot */ + u32 EmcMrw14; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at cold boot + */ + u32 EmcMrwExtra; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at warm boot + */ + u32 EmcWarmBootMrwExtra; + /* + * Specify the enable of extra Mode Register programming at + * warm boot + */ + u32 EmcWarmBootExtraModeRegWriteEnable; + /* + * Specify the enable of extra Mode Register programming at + * cold boot + */ + u32 EmcExtraModeRegWriteEnable; + + /* Specifies the EMC_MRW reset command value */ + u32 EmcMrwResetCommand; + /* Specifies the EMC Reset wait time (in microseconds) */ + u32 EmcMrwResetNInitWait; + /* Specifies the value for EMC_MRS_WAIT_CNT */ + u32 EmcMrsWaitCnt; + /* Specifies the value for EMC_MRS_WAIT_CNT2 */ + u32 EmcMrsWaitCnt2; + + /* EMC miscellaneous configurations */ + + /* Specifies the value for EMC_CFG */ + u32 EmcCfg; + /* Specifies the value for EMC_CFG_2 */ + u32 EmcCfg2; + /* Specifies the pipe bypass controls */ + u32 EmcCfgPipe; + u32 EmcCfgPipeClk; + u32 EmcFdpdCtrlCmdNoRamp; + u32 EmcCfgUpdate; + + /* Specifies the value for EMC_DBG */ + u32 EmcDbg; + u32 EmcDbgWriteMux; + + /* Specifies the value for EMC_CMDQ */ + u32 EmcCmdQ; + /* Specifies the value for EMC_MC2EMCQ */ + u32 EmcMc2EmcQ; + /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ + u32 EmcDynSelfRefControl; + + /* Specifies the value for MEM_INIT_DONE */ + u32 AhbArbitrationXbarCtrlMemInitDone; + + /* Specifies the value for EMC_CFG_DIG_DLL */ + u32 EmcCfgDigDll; + u32 EmcCfgDigDll_1; + /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ + u32 EmcCfgDigDllPeriod; + /* Specifies the value of *DEV_SELECTN of various EMC registers */ + u32 EmcDevSelect; + + /* Specifies the value for EMC_SEL_DPD_CTRL */ + u32 EmcSelDpdCtrl; + + /* Pads trimmer delays */ + u32 EmcFdpdCtrlDq; + u32 EmcFdpdCtrlCmd; + u32 EmcPmacroIbVrefDq_0; + u32 EmcPmacroIbVrefDq_1; + u32 EmcPmacroIbVrefDqs_0; + u32 EmcPmacroIbVrefDqs_1; + u32 EmcPmacroIbRxrt; + u32 EmcCfgPipe1; + u32 EmcCfgPipe2; + + /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ + u32 EmcPmacroQuseDdllRank0_0; + u32 EmcPmacroQuseDdllRank0_1; + u32 EmcPmacroQuseDdllRank0_2; + u32 EmcPmacroQuseDdllRank0_3; + u32 EmcPmacroQuseDdllRank0_4; + u32 EmcPmacroQuseDdllRank0_5; + u32 EmcPmacroQuseDdllRank1_0; + u32 EmcPmacroQuseDdllRank1_1; + u32 EmcPmacroQuseDdllRank1_2; + u32 EmcPmacroQuseDdllRank1_3; + u32 EmcPmacroQuseDdllRank1_4; + u32 EmcPmacroQuseDdllRank1_5; + + u32 EmcPmacroObDdllLongDqRank0_0; + u32 EmcPmacroObDdllLongDqRank0_1; + u32 EmcPmacroObDdllLongDqRank0_2; + u32 EmcPmacroObDdllLongDqRank0_3; + u32 EmcPmacroObDdllLongDqRank0_4; + u32 EmcPmacroObDdllLongDqRank0_5; + u32 EmcPmacroObDdllLongDqRank1_0; + u32 EmcPmacroObDdllLongDqRank1_1; + u32 EmcPmacroObDdllLongDqRank1_2; + u32 EmcPmacroObDdllLongDqRank1_3; + u32 EmcPmacroObDdllLongDqRank1_4; + u32 EmcPmacroObDdllLongDqRank1_5; + + u32 EmcPmacroObDdllLongDqsRank0_0; + u32 EmcPmacroObDdllLongDqsRank0_1; + u32 EmcPmacroObDdllLongDqsRank0_2; + u32 EmcPmacroObDdllLongDqsRank0_3; + u32 EmcPmacroObDdllLongDqsRank0_4; + u32 EmcPmacroObDdllLongDqsRank0_5; + u32 EmcPmacroObDdllLongDqsRank1_0; + u32 EmcPmacroObDdllLongDqsRank1_1; + u32 EmcPmacroObDdllLongDqsRank1_2; + u32 EmcPmacroObDdllLongDqsRank1_3; + u32 EmcPmacroObDdllLongDqsRank1_4; + u32 EmcPmacroObDdllLongDqsRank1_5; + + u32 EmcPmacroIbDdllLongDqsRank0_0; + u32 EmcPmacroIbDdllLongDqsRank0_1; + u32 EmcPmacroIbDdllLongDqsRank0_2; + u32 EmcPmacroIbDdllLongDqsRank0_3; + u32 EmcPmacroIbDdllLongDqsRank1_0; + u32 EmcPmacroIbDdllLongDqsRank1_1; + u32 EmcPmacroIbDdllLongDqsRank1_2; + u32 EmcPmacroIbDdllLongDqsRank1_3; + + u32 EmcPmacroDdllLongCmd_0; + u32 EmcPmacroDdllLongCmd_1; + u32 EmcPmacroDdllLongCmd_2; + u32 EmcPmacroDdllLongCmd_3; + u32 EmcPmacroDdllLongCmd_4; + u32 EmcPmacroDdllShortCmd_0; + u32 EmcPmacroDdllShortCmd_1; + u32 EmcPmacroDdllShortCmd_2; + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + u32 WarmBootWait; + + /* Specifies the value for EMC_ODT_WRITE */ + u32 EmcOdtWrite; + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + u32 EmcZcalInterval; + /* Specifies the value for EMC_ZCAL_WAIT_CNT */ + u32 EmcZcalWaitCnt; + /* Specifies the value for EMC_ZCAL_MRW_CMD */ + u32 EmcZcalMrwCmd; + + /* DRAM initialization sequence flow control */ + + /* Specifies the MRS command value for resetting DLL */ + u32 EmcMrsResetDll; + /* Specifies the command for ZQ initialization of device 0 */ + u32 EmcZcalInitDev0; + /* Specifies the command for ZQ initialization of device 1 */ + u32 EmcZcalInitDev1; + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + u32 EmcZcalInitWait; + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + u32 EmcZcalWarmColdBootEnables; + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + u32 EmcMrwLpddr2ZcalWarmBoot; + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + u32 EmcZqCalDdr3WarmBoot; + u32 EmcZqCalLpDdr4WarmBoot; + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + u32 EmcZcalWarmBootWait; + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + u32 EmcMrsWarmBootEnable; + /* + * Specifies the wait time after sending an MRS DLL reset command + * in microseconds) + */ + u32 EmcMrsResetDllWait; + /* Specifies the extra MRS command to initialize mode registers */ + u32 EmcMrsExtra; + /* Specifies the extra MRS command at warm boot */ + u32 EmcWarmBootMrsExtra; + /* Specifies the EMRS command to enable the DDR2 DLL */ + u32 EmcEmrsDdr2DllEnable; + /* Specifies the MRS command to reset the DDR2 DLL */ + u32 EmcMrsDdr2DllReset; + /* Specifies the EMRS command to set OCD calibration */ + u32 EmcEmrsDdr2OcdCalib; + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + u32 EmcDdr2Wait; + /* Specifies the value for EMC_CLKEN_OVERRIDE */ + u32 EmcClkenOverride; + + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + u32 EmcExtraRefreshNum; + /* Specifies the master override for all EMC clocks */ + u32 EmcClkenOverrideAllWarmBoot; + /* Specifies the master override for all MC clocks */ + u32 McClkenOverrideAllWarmBoot; + /* Specifies digital dll period, choosing between 4 to 64 ms */ + u32 EmcCfgDigDllPeriodWarmBoot; + + /* Pad controls */ + + /* Specifies the value for PMC_VDDP_SEL */ + u32 PmcVddpSel; + /* Specifies the wait time after programming PMC_VDDP_SEL */ + u32 PmcVddpSelWait; + /* Specifies the value for PMC_DDR_PWR */ + u32 PmcDdrPwr; + /* Specifies the value for PMC_DDR_CFG */ + u32 PmcDdrCfg; + /* Specifies the value for PMC_IO_DPD3_REQ */ + u32 PmcIoDpd3Req; + /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ + u32 PmcIoDpd3ReqWait; + u32 PmcIoDpd4ReqWait; + + /* Specifies the value for PMC_REG_SHORT */ + u32 PmcRegShort; + /* Specifies the value for PMC_NO_IOPOWER */ + u32 PmcNoIoPower; + + u32 PmcDdrCntrlWait; + u32 PmcDdrCntrl; + + /* Specifies the value for EMC_ACPD_CONTROL */ + u32 EmcAcpdControl; + + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE_CFG */ + u32 EmcSwizzleRank0ByteCfg; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ + u32 EmcSwizzleRank0Byte0; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ + u32 EmcSwizzleRank0Byte1; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ + u32 EmcSwizzleRank0Byte2; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ + u32 EmcSwizzleRank0Byte3; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE_CFG */ + u32 EmcSwizzleRank1ByteCfg; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ + u32 EmcSwizzleRank1Byte0; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ + u32 EmcSwizzleRank1Byte1; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ + u32 EmcSwizzleRank1Byte2; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ + u32 EmcSwizzleRank1Byte3; + + /* Specifies the value for EMC_TXDSRVTTGEN */ + u32 EmcTxdsrvttgen; + + /* Specifies the value for EMC_DATA_BRLSHFT_0 */ + u32 EmcDataBrlshft0; + u32 EmcDataBrlshft1; + + u32 EmcDqsBrlshft0; + u32 EmcDqsBrlshft1; + + u32 EmcCmdBrlshft0; + u32 EmcCmdBrlshft1; + u32 EmcCmdBrlshft2; + u32 EmcCmdBrlshft3; + + u32 EmcQuseBrlshft0; + u32 EmcQuseBrlshft1; + u32 EmcQuseBrlshft2; + u32 EmcQuseBrlshft3; + + u32 EmcDllCfg0; + u32 EmcDllCfg1; + + u32 EmcPmcScratch1; + u32 EmcPmcScratch2; + u32 EmcPmcScratch3; + + u32 EmcPmacroPadCfgCtrl; + + u32 EmcPmacroVttgenCtrl0; + u32 EmcPmacroVttgenCtrl1; + u32 EmcPmacroVttgenCtrl2; + + u32 EmcPmacroBrickCtrlRfu1; + u32 EmcPmacroCmdBrickCtrlFdpd; + u32 EmcPmacroBrickCtrlRfu2; + u32 EmcPmacroDataBrickCtrlFdpd; + u32 EmcPmacroBgBiasCtrl0; + u32 EmcPmacroDataPadRxCtrl; + u32 EmcPmacroCmdPadRxCtrl; + u32 EmcPmacroDataRxTermMode; + u32 EmcPmacroCmdRxTermMode; + u32 EmcPmacroDataPadTxCtrl; + u32 EmcPmacroCommonPadTxCtrl; + u32 EmcPmacroCmdPadTxCtrl; + u32 EmcCfg3; + + u32 EmcPmacroTxPwrd0; + u32 EmcPmacroTxPwrd1; + u32 EmcPmacroTxPwrd2; + u32 EmcPmacroTxPwrd3; + u32 EmcPmacroTxPwrd4; + u32 EmcPmacroTxPwrd5; + + u32 EmcConfigSampleDelay; + + u32 EmcPmacroBrickMapping0; + u32 EmcPmacroBrickMapping1; + u32 EmcPmacroBrickMapping2; + + u32 EmcPmacroTxSelClkSrc0; + u32 EmcPmacroTxSelClkSrc1; + u32 EmcPmacroTxSelClkSrc2; + u32 EmcPmacroTxSelClkSrc3; + u32 EmcPmacroTxSelClkSrc4; + u32 EmcPmacroTxSelClkSrc5; + + u32 EmcPmacroDdllBypass; + + u32 EmcPmacroDdllPwrd0; + u32 EmcPmacroDdllPwrd1; + u32 EmcPmacroDdllPwrd2; + + u32 EmcPmacroCmdCtrl0; + u32 EmcPmacroCmdCtrl1; + u32 EmcPmacroCmdCtrl2; + + /* DRAM size information */ + + /* Specifies the value for MC_EMEM_ADR_CFG */ + u32 McEmemAdrCfg; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ + u32 McEmemAdrCfgDev0; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ + u32 McEmemAdrCfgDev1; + u32 McEmemAdrCfgChannelMask; + + /* Specifies the value for MC_EMEM_BANK_SWIZZLECfg0 */ + u32 McEmemAdrCfgBankMask0; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ + u32 McEmemAdrCfgBankMask1; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ + u32 McEmemAdrCfgBankMask2; + + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + u32 McEmemCfg; + + /* MC arbitration configuration */ + + /* Specifies the value for MC_EMEM_ARB_CFG */ + u32 McEmemArbCfg; + /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ + u32 McEmemArbOutstandingReq; + + u32 McEmemArbRefpbHpCtrl; + u32 McEmemArbRefpbBankCtrl; + + /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ + u32 McEmemArbTimingRcd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ + u32 McEmemArbTimingRp; + /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ + u32 McEmemArbTimingRc; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ + u32 McEmemArbTimingRas; + /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ + u32 McEmemArbTimingFaw; + /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ + u32 McEmemArbTimingRrd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ + u32 McEmemArbTimingRap2Pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ + u32 McEmemArbTimingWap2Pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ + u32 McEmemArbTimingR2R; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ + u32 McEmemArbTimingW2W; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ + u32 McEmemArbTimingR2W; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ + u32 McEmemArbTimingW2R; + + u32 McEmemArbTimingRFCPB; + + /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ + u32 McEmemArbDaTurns; + /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ + u32 McEmemArbDaCovers; + /* Specifies the value for MC_EMEM_ARB_MISC0 */ + u32 McEmemArbMisc0; + /* Specifies the value for MC_EMEM_ARB_MISC1 */ + u32 McEmemArbMisc1; + u32 McEmemArbMisc2; + + /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ + u32 McEmemArbRing1Throttle; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ + u32 McEmemArbOverride; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ + u32 McEmemArbOverride1; + /* Specifies the value for MC_EMEM_ARB_RSV */ + u32 McEmemArbRsv; + + u32 McDaCfg0; + u32 McEmemArbTimingCcdmw; + + /* Specifies the value for MC_CLKEN_OVERRIDE */ + u32 McClkenOverride; + + /* Specifies the value for MC_STAT_CONTROL */ + u32 McStatControl; + + /* Specifies the value for MC_VIDEO_PROTECT_BOM */ + u32 McVideoProtectBom; + /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ + u32 McVideoProtectBomAdrHi; + /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ + u32 McVideoProtectSizeMb; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ + u32 McVideoProtectVprOverride; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ + u32 McVideoProtectVprOverride1; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ + u32 McVideoProtectGpuOverride0; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ + u32 McVideoProtectGpuOverride1; + /* Specifies the value for MC_SEC_CARVEOUT_BOM */ + u32 McSecCarveoutBom; + /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ + u32 McSecCarveoutAdrHi; + /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ + u32 McSecCarveoutSizeMb; + /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL. + VIDEO_PROTECT_WRITEAccess */ + u32 McVideoProtectWriteAccess; + /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL. + SEC_CARVEOUT_WRITEAccess */ + u32 McSecCarveoutProtectWriteAccess; + + /* Write-Protect Regions (WPR) */ + u32 McGeneralizedCarveout1Bom; + u32 McGeneralizedCarveout1BomHi; + u32 McGeneralizedCarveout1Size128kb; + u32 McGeneralizedCarveout1Access0; + u32 McGeneralizedCarveout1Access1; + u32 McGeneralizedCarveout1Access2; + u32 McGeneralizedCarveout1Access3; + u32 McGeneralizedCarveout1Access4; + u32 McGeneralizedCarveout1ForceInternalAccess0; + u32 McGeneralizedCarveout1ForceInternalAccess1; + u32 McGeneralizedCarveout1ForceInternalAccess2; + u32 McGeneralizedCarveout1ForceInternalAccess3; + u32 McGeneralizedCarveout1ForceInternalAccess4; + u32 McGeneralizedCarveout1Cfg0; + + u32 McGeneralizedCarveout2Bom; + u32 McGeneralizedCarveout2BomHi; + u32 McGeneralizedCarveout2Size128kb; + u32 McGeneralizedCarveout2Access0; + u32 McGeneralizedCarveout2Access1; + u32 McGeneralizedCarveout2Access2; + u32 McGeneralizedCarveout2Access3; + u32 McGeneralizedCarveout2Access4; + u32 McGeneralizedCarveout2ForceInternalAccess0; + u32 McGeneralizedCarveout2ForceInternalAccess1; + u32 McGeneralizedCarveout2ForceInternalAccess2; + u32 McGeneralizedCarveout2ForceInternalAccess3; + u32 McGeneralizedCarveout2ForceInternalAccess4; + u32 McGeneralizedCarveout2Cfg0; + + u32 McGeneralizedCarveout3Bom; + u32 McGeneralizedCarveout3BomHi; + u32 McGeneralizedCarveout3Size128kb; + u32 McGeneralizedCarveout3Access0; + u32 McGeneralizedCarveout3Access1; + u32 McGeneralizedCarveout3Access2; + u32 McGeneralizedCarveout3Access3; + u32 McGeneralizedCarveout3Access4; + u32 McGeneralizedCarveout3ForceInternalAccess0; + u32 McGeneralizedCarveout3ForceInternalAccess1; + u32 McGeneralizedCarveout3ForceInternalAccess2; + u32 McGeneralizedCarveout3ForceInternalAccess3; + u32 McGeneralizedCarveout3ForceInternalAccess4; + u32 McGeneralizedCarveout3Cfg0; + + u32 McGeneralizedCarveout4Bom; + u32 McGeneralizedCarveout4BomHi; + u32 McGeneralizedCarveout4Size128kb; + u32 McGeneralizedCarveout4Access0; + u32 McGeneralizedCarveout4Access1; + u32 McGeneralizedCarveout4Access2; + u32 McGeneralizedCarveout4Access3; + u32 McGeneralizedCarveout4Access4; + u32 McGeneralizedCarveout4ForceInternalAccess0; + u32 McGeneralizedCarveout4ForceInternalAccess1; + u32 McGeneralizedCarveout4ForceInternalAccess2; + u32 McGeneralizedCarveout4ForceInternalAccess3; + u32 McGeneralizedCarveout4ForceInternalAccess4; + u32 McGeneralizedCarveout4Cfg0; + + u32 McGeneralizedCarveout5Bom; + u32 McGeneralizedCarveout5BomHi; + u32 McGeneralizedCarveout5Size128kb; + u32 McGeneralizedCarveout5Access0; + u32 McGeneralizedCarveout5Access1; + u32 McGeneralizedCarveout5Access2; + u32 McGeneralizedCarveout5Access3; + u32 McGeneralizedCarveout5Access4; + u32 McGeneralizedCarveout5ForceInternalAccess0; + u32 McGeneralizedCarveout5ForceInternalAccess1; + u32 McGeneralizedCarveout5ForceInternalAccess2; + u32 McGeneralizedCarveout5ForceInternalAccess3; + u32 McGeneralizedCarveout5ForceInternalAccess4; + u32 McGeneralizedCarveout5Cfg0; + + /* Specifies enable for CA training */ + u32 EmcCaTrainingEnable; + + /* Set if bit 6 select is greater than bit 7 select; uses aremc. + spec packet SWIZZLE_BIT6_GT_BIT7 */ + u32 SwizzleRankByteEncode; + /* Specifies enable and offset for patched boot ROM write */ + u32 BootRomPatchControl; + /* Specifies data for patched boot ROM write */ + u32 BootRomPatchData; + + /* Specifies the value for MC_MTS_CARVEOUT_BOM */ + u32 McMtsCarveoutBom; + /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ + u32 McMtsCarveoutAdrHi; + /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ + u32 McMtsCarveoutSizeMb; + /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ + u32 McMtsCarveoutRegCtrl; + + /* End */ +}; + +#endif /* __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ */ diff --git a/ipl/se.c b/ipl/se.c new file mode 100755 index 0000000..af2d697 --- /dev/null +++ b/ipl/se.c @@ -0,0 +1,256 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include "se.h" +#include "heap.h" +#include "t210.h" +#include "se_t210.h" + +typedef struct _se_ll_t +{ + vu32 num; + vu32 addr; + vu32 size; +} se_ll_t; + +static void _gf256_mul_x(void *block) +{ + u8 *pdata = (u8 *)block; + u32 carry = 0; + + for (u32 i = 0xF; i >= 0; i--) + { + u8 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 7; + } + + if (carry) + pdata[0xF] ^= 0x87; +} + +static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size) +{ + ll->num = 0; + ll->addr = addr; + ll->size = size; +} + +static void _se_ll_set(se_ll_t *dst, se_ll_t *src) +{ + SE(SE_IN_LL_ADDR_REG_OFFSET) = (u32)src; + SE(SE_OUT_LL_ADDR_REG_OFFSET) = (u32)dst; +} + +static int _se_wait() +{ + while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET))) + ; + if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) || + SE(SE_STATUS_0) & 3 || + SE(SE_ERR_STATUS_0) != 0) + return 0; + return 1; +} + +static int _se_execute(u32 op, void *dst, u32 dst_size, void *src, u32 src_size) +{ + se_ll_t *ll_dst = NULL, *ll_src = NULL; + + if (dst) + { + ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); + _se_ll_init(ll_dst, (u32)dst, dst_size); + } + + if (src) + { + ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); + _se_ll_init(ll_src, (u32)src, src_size); + } + + _se_ll_set(ll_dst, ll_src); + + SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0); + SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET); + SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); + + int res = _se_wait(); + + if (src) + free(ll_src); + if (dst) + free(ll_dst); + + return res; +} + +static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, void *src, u32 src_size) +{ + u8 *block = (u8 *)malloc(0x10); + memset(block, 0, 0x10); + + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + + memcpy(block, src, src_size); + int res = _se_execute(op, block, 0x10, block, 0x10); + memcpy(dst, block, dst_size); + + free(block); + return res; +} + +static void _se_aes_ctr_set(void *ctr) +{ + u32 *data = (u32 *)ctr; + for (u32 i = 0; i < 4; i++) + SE(SE_CRYPTO_CTR_REG_OFFSET + 4 * i) = data[i]; +} + +void se_rsa_acc_ctrl(u32 rs, u32 flags) +{ + if (flags & 0x7F) + SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = ((flags >> 4) & 4 | flags & 3) ^ 7; + if (flags & 0x80) + SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); +} + +void se_key_acc_ctrl(u32 ks, u32 flags) +{ + if (flags & 0x7F) + SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; + if (flags & 0x80) + SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); +} + +void se_aes_key_set(u32 ks, void *key, u32 size) +{ + u32 *data = (u32 *)key; + for (u32 i = 0; i < size / 4; i++) + { + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; + SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; + } +} + +void se_aes_key_clear(u32 ks) +{ + for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++) + { + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; + SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0; + } +} + +int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, void *input) +{ + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); + return _se_execute(OP_START, NULL, 0, input, 0x10); +} + +int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, void *src) +{ + if (enc) + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); + } + else + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + } + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + return _se_execute(OP_START, dst, 0x10, src, 0x10); +} + +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, void *src, u32 src_size, void *ctr) +{ + SE(SE_SPARE_0_REG_OFFSET) = 1; + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); + _se_aes_ctr_set(ctr); + + u32 src_size_aligned = src_size & 0xFFFFFFF0; + u32 src_size_delta = src_size & 0xF; + + if (src_size_aligned) + { + SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; + if (!_se_execute(OP_START, dst, dst_size, src, src_size_aligned)) + return 0; + } + + if (src_size - src_size_aligned && src_size_aligned < dst_size) + return _se_execute_one_block(OP_START, dst + src_size_aligned, + MIN(src_size_delta, dst_size - src_size_aligned), + src + src_size_aligned, src_size_delta); + + return 1; +} + +int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize) +{ + int res = 0; + u8 *tweak = (u8 *)malloc(0x10); + u8 *pdst = (u8 *)dst; + u8 *psrc = (u8 *)src; + + //Generate tweak. + for (int i = 0xF; i >= 0; i--) + { + tweak[i] = sec & 0xFF; + sec >>= 8; + } + if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) + goto out; + + //We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < secsize / 0x10; i++) + { + for (u32 j = 0; j < 0x10; j++) + pdst[j] = psrc[j] ^ tweak[j]; + if (!se_aes_crypt_block_ecb(ks2, enc, pdst, pdst)) + goto out; + for (u32 j = 0; j < 0x10; j++) + pdst[j] = pdst[j] ^ tweak[j]; + _gf256_mul_x(tweak); + psrc += 0x10; + pdst += 0x10; + } + + res = 1; + +out:; + free(tweak); + return res; +} + +int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs) +{ + u8 *pdst = (u8 *)dst; + u8 *psrc = (u8 *)src; + + for (u32 i = 0; i < num_secs; i++) + if (!se_aes_xts_crypt_sec(ks1, ks2, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize)) + return 0; + + return 1; +} diff --git a/ipl/se.h b/ipl/se.h new file mode 100755 index 0000000..edeea70 --- /dev/null +++ b/ipl/se.h @@ -0,0 +1,30 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _SE_H_ +#define _SE_H_ + +#include "types.h" + +void se_rsa_acc_ctrl(u32 rs, u32 flags); +void se_key_acc_ctrl(u32 ks, u32 flags); +void se_aes_key_set(u32 ks, void *key, u32 size); +void se_aes_key_clear(u32 ks); +int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, void *input); +int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, void *src); +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, void *src, u32 src_size, void *ctr); + +#endif diff --git a/ipl/se_t210.h b/ipl/se_t210.h new file mode 100755 index 0000000..e1bd968 --- /dev/null +++ b/ipl/se_t210.h @@ -0,0 +1,357 @@ +/* +* Driver for Tegra Security Engine +* +* Copyright (c) 2011-2013, NVIDIA Corporation. All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _CRYPTO_TEGRA_SE_H +#define _CRYPTO_TEGRA_SE_H + +#include "types.h" + +#define TEGRA_SE_CRA_PRIORITY 300 +#define TEGRA_SE_COMPOSITE_PRIORITY 400 +#define TEGRA_SE_CRYPTO_QUEUE_LENGTH 50 +#define SE_MAX_SRC_SG_COUNT 50 +#define SE_MAX_DST_SG_COUNT 50 + +#define TEGRA_SE_KEYSLOT_COUNT 16 +#define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF + +/* SE register definitions */ +#define SE_SECURITY_0 0x000 +#define SE_KEY_SCHED_READ_SHIFT 3 + +#define SE_CONFIG_REG_OFFSET 0x014 +#define SE_CONFIG_ENC_ALG_SHIFT 12 +#define SE_CONFIG_DEC_ALG_SHIFT 8 +#define ALG_AES_ENC 1 +#define ALG_RNG 2 +#define ALG_SHA 3 +#define ALG_RSA 4 +#define ALG_NOP 0 +#define ALG_AES_DEC 1 +#define SE_CONFIG_ENC_ALG(x) (x << SE_CONFIG_ENC_ALG_SHIFT) +#define SE_CONFIG_DEC_ALG(x) (x << SE_CONFIG_DEC_ALG_SHIFT) +#define SE_CONFIG_DST_SHIFT 2 +#define DST_MEMORY 0 +#define DST_HASHREG 1 +#define DST_KEYTAB 2 +#define DST_SRK 3 +#define DST_RSAREG 4 +#define SE_CONFIG_DST(x) (x << SE_CONFIG_DST_SHIFT) +#define SE_CONFIG_ENC_MODE_SHIFT 24 +#define SE_CONFIG_DEC_MODE_SHIFT 16 +#define MODE_KEY128 0 +#define MODE_KEY192 1 +#define MODE_KEY256 2 +#define MODE_SHA1 0 +#define MODE_SHA224 4 +#define MODE_SHA256 5 +#define MODE_SHA384 6 +#define MODE_SHA512 7 +#define SE_CONFIG_ENC_MODE(x) (x << SE_CONFIG_ENC_MODE_SHIFT) +#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT) + +#define SE_RNG_CONFIG_REG_OFFSET 0x340 +#define DRBG_MODE_SHIFT 0 +#define DRBG_MODE_NORMAL 0 +#define DRBG_MODE_FORCE_INSTANTION 1 +#define DRBG_MODE_FORCE_RESEED 2 +#define SE_RNG_CONFIG_MODE(x) (x << DRBG_MODE_SHIFT) + +#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344 +#define DRBG_RO_ENT_SRC_SHIFT 1 +#define DRBG_RO_ENT_SRC_ENABLE 1 +#define DRBG_RO_ENT_SRC_DISABLE 0 +#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) (x << DRBG_RO_ENT_SRC_SHIFT) +#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0 +#define DRBG_RO_ENT_SRC_LOCK_ENABLE 1 +#define DRBG_RO_ENT_SRC_LOCK_DISABLE 0 +#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) (x << DRBG_RO_ENT_SRC_LOCK_SHIFT) + +#define DRBG_SRC_SHIFT 2 +#define DRBG_SRC_NONE 0 +#define DRBG_SRC_ENTROPY 1 +#define DRBG_SRC_LFSR 2 +#define SE_RNG_CONFIG_SRC(x) (x << DRBG_SRC_SHIFT) + +#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 + +#define SE_KEYTABLE_REG_OFFSET 0x31c +#define SE_KEYTABLE_SLOT_SHIFT 4 +#define SE_KEYTABLE_SLOT(x) (x << SE_KEYTABLE_SLOT_SHIFT) +#define SE_KEYTABLE_QUAD_SHIFT 2 +#define QUAD_KEYS_128 0 +#define QUAD_KEYS_192 1 +#define QUAD_KEYS_256 1 +#define QUAD_ORG_IV 2 +#define QUAD_UPDTD_IV 3 +#define SE_KEYTABLE_QUAD(x) (x << SE_KEYTABLE_QUAD_SHIFT) +#define SE_KEYTABLE_OP_TYPE_SHIFT 9 +#define OP_READ 0 +#define OP_WRITE 1 +#define SE_KEYTABLE_OP_TYPE(x) (x << SE_KEYTABLE_OP_TYPE_SHIFT) +#define SE_KEYTABLE_TABLE_SEL_SHIFT 8 +#define TABLE_KEYIV 0 +#define TABLE_SCHEDULE 1 +#define SE_KEYTABLE_TABLE_SEL(x) (x << SE_KEYTABLE_TABLE_SEL_SHIFT) +#define SE_KEYTABLE_PKT_SHIFT 0 +#define SE_KEYTABLE_PKT(x) (x << SE_KEYTABLE_PKT_SHIFT) + +#define SE_OP_DONE_SHIFT 4 +#define OP_DONE 1 +#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT)) + +#define SE_CRYPTO_REG_OFFSET 0x304 +#define SE_CRYPTO_HASH_SHIFT 0 +#define HASH_DISABLE 0 +#define HASH_ENABLE 1 +#define SE_CRYPTO_HASH(x) (x << SE_CRYPTO_HASH_SHIFT) +#define SE_CRYPTO_XOR_POS_SHIFT 1 +#define XOR_BYPASS 0 +#define XOR_TOP 2 +#define XOR_BOTTOM 3 +#define SE_CRYPTO_XOR_POS(x) (x << SE_CRYPTO_XOR_POS_SHIFT) +#define SE_CRYPTO_INPUT_SEL_SHIFT 3 +#define INPUT_AHB 0 +#define INPUT_RANDOM 1 +#define INPUT_AESOUT 2 +#define INPUT_LNR_CTR 3 +#define SE_CRYPTO_INPUT_SEL(x) (x << SE_CRYPTO_INPUT_SEL_SHIFT) +#define SE_CRYPTO_VCTRAM_SEL_SHIFT 5 +#define VCTRAM_AHB 0 +#define VCTRAM_AESOUT 2 +#define VCTRAM_PREVAHB 3 +#define SE_CRYPTO_VCTRAM_SEL(x) (x << SE_CRYPTO_VCTRAM_SEL_SHIFT) +#define SE_CRYPTO_IV_SEL_SHIFT 7 +#define IV_ORIGINAL 0 +#define IV_UPDATED 1 +#define SE_CRYPTO_IV_SEL(x) (x << SE_CRYPTO_IV_SEL_SHIFT) +#define SE_CRYPTO_CORE_SEL_SHIFT 8 +#define CORE_DECRYPT 0 +#define CORE_ENCRYPT 1 +#define SE_CRYPTO_CORE_SEL(x) (x << SE_CRYPTO_CORE_SEL_SHIFT) +#define SE_CRYPTO_CTR_VAL_SHIFT 11 +#define SE_CRYPTO_CTR_VAL(x) (x << SE_CRYPTO_CTR_VAL_SHIFT) +#define SE_CRYPTO_KEY_INDEX_SHIFT 24 +#define SE_CRYPTO_KEY_INDEX(x) (x << SE_CRYPTO_KEY_INDEX_SHIFT) +#define SE_CRYPTO_CTR_CNTN_SHIFT 11 +#define SE_CRYPTO_CTR_CNTN(x) (x << SE_CRYPTO_CTR_CNTN_SHIFT) + +#define SE_CRYPTO_CTR_REG_COUNT 4 +#define SE_CRYPTO_CTR_REG_OFFSET 0x308 + +#define SE_OPERATION_REG_OFFSET 0x008 +#define SE_OPERATION_SHIFT 0 +#define OP_ABORT 0 +#define OP_START 1 +#define OP_RESTART 2 +#define OP_CTX_SAVE 3 +#define OP_RESTART_IN 4 +#define SE_OPERATION(x) (x << SE_OPERATION_SHIFT) + +#define SE_CONTEXT_SAVE_CONFIG_REG_OFFSET 0x070 +#define SE_CONTEXT_SAVE_WORD_QUAD_SHIFT 0 +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIG_IV 2 +#define UPD_IV 3 +#define SE_CONTEXT_SAVE_WORD_QUAD(x) (x << SE_CONTEXT_SAVE_WORD_QUAD_SHIFT) + +#define SE_CONTEXT_SAVE_KEY_INDEX_SHIFT 8 +#define SE_CONTEXT_SAVE_KEY_INDEX(x) (x << SE_CONTEXT_SAVE_KEY_INDEX_SHIFT) + +#define SE_CONTEXT_SAVAE_STICKY_WORD_QUAD_SHIFT 24 +#define STICKY_0_3 0 +#define STICKY_4_7 1 +#define SE_CONTEXT_SAVE_STICKY_WORD_QUAD(x) \ + (x << SE_CONTEXT_SAVAE_STICKY_WORD_QUAD_SHIFT) + +#define SE_CONTEXT_SAVE_SRC_SHIFT 29 +#define STICKY_BITS 0 +#define KEYTABLE 2 +#define MEM 4 +#define SRK 6 + +#define RSA_KEYTABLE 1 +#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT) + +#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16 +#define SE_CONTEXT_SAVE_RSA_KEY_INDEX(x) \ + (x << SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT) + +#define SE_CONTEXT_RSA_WORD_QUAD_SHIFT 12 +#define SE_CONTEXT_RSA_WORD_QUAD(x) \ + (x << SE_CONTEXT_RSA_WORD_QUAD_SHIFT) + +#define SE_INT_ENABLE_REG_OFFSET 0x00c +#define SE_INT_STATUS_REG_OFFSET 0x010 +#define INT_DISABLE 0 +#define INT_ENABLE 1 +#define INT_UNSET 0 +#define INT_SET 1 +#define SE_INT_OP_DONE_SHIFT 4 +#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT) +#define SE_INT_ERROR_SHIFT 16 +#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT) +#define SE_STATUS_0 0x800 +#define SE_ERR_STATUS_0 0x804 + +#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330 +#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 +#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x) \ + (x << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT) + +#define SE_KEY_INDEX_SHIFT 8 +#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) (x << SE_KEY_INDEX_SHIFT) + +#define SE_IN_LL_ADDR_REG_OFFSET 0x018 +#define SE_OUT_LL_ADDR_REG_OFFSET 0x024 + +#define SE_KEYTABLE_DATA0_REG_OFFSET 0x320 +#define SE_KEYTABLE_REG_MAX_DATA 16 + +#define SE_BLOCK_COUNT_REG_OFFSET 0x318 + +#define SE_SPARE_0_REG_OFFSET 0x80c + +#define SE_SHA_CONFIG_REG_OFFSET 0x200 +#define SHA_DISABLE 0 +#define SHA_ENABLE 1 + +#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204 +#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214 + +#define SE_HASH_RESULT_REG_COUNT 16 +#define SE_HASH_RESULT_REG_OFFSET 0x030 +#define TEGRA_SE_KEY_256_SIZE 32 +#define TEGRA_SE_KEY_192_SIZE 24 +#define TEGRA_SE_KEY_128_SIZE 16 +#define TEGRA_SE_AES_BLOCK_SIZE 16 +#define TEGRA_SE_AES_MIN_KEY_SIZE 16 +#define TEGRA_SE_AES_MAX_KEY_SIZE 32 +#define TEGRA_SE_AES_IV_SIZE 16 +#define TEGRA_SE_RNG_IV_SIZE 16 +#define TEGRA_SE_RNG_DT_SIZE 16 +#define TEGRA_SE_RNG_KEY_SIZE 16 +#define TEGRA_SE_RNG_SEED_SIZE (TEGRA_SE_RNG_IV_SIZE + \ + TEGRA_SE_RNG_KEY_SIZE + \ + TEGRA_SE_RNG_DT_SIZE) + +#define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16 +#define TEGRA_SE_RSA512_DIGEST_SIZE 64 +#define TEGRA_SE_RSA1024_DIGEST_SIZE 128 +#define TEGRA_SE_RSA1536_DIGEST_SIZE 192 +#define TEGRA_SE_RSA2048_DIGEST_SIZE 256 + +#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280 +#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 +#define SE_KEY_READ_DISABLE_SHIFT 0 +#define SE_KEY_UPDATE_DISABLE_SHIFT 1 + +#define SE_CONTEXT_BUFER_SIZE 1072 +#define SE_CONTEXT_DRBG_BUFER_SIZE 2112 + +#define SE_CONTEXT_SAVE_RANDOM_DATA_OFFSET 0 +#define SE_CONTEXT_SAVE_RANDOM_DATA_SIZE 16 +#define SE_CONTEXT_SAVE_STICKY_BITS_OFFSET \ + (SE_CONTEXT_SAVE_RANDOM_DATA_OFFSET + SE_CONTEXT_SAVE_RANDOM_DATA_SIZE) +#define SE_CONTEXT_SAVE_STICKY_BITS_SIZE 16 + +#define SE_CONTEXT_SAVE_KEYS_OFFSET (SE_CONTEXT_SAVE_STICKY_BITS_OFFSET + \ + SE_CONTEXT_SAVE_STICKY_BITS_SIZE) +#define SE11_CONTEXT_SAVE_KEYS_OFFSET (SE_CONTEXT_SAVE_STICKY_BITS_OFFSET + \ + SE_CONTEXT_SAVE_STICKY_BITS_SIZE + \ + SE_CONTEXT_SAVE_STICKY_BITS_SIZE) + +#define SE_CONTEXT_SAVE_KEY_LENGTH 512 +#define SE_CONTEXT_ORIGINAL_IV_OFFSET (SE_CONTEXT_SAVE_KEYS_OFFSET + \ + SE_CONTEXT_SAVE_KEY_LENGTH) +#define SE11_CONTEXT_ORIGINAL_IV_OFFSET (SE11_CONTEXT_SAVE_KEYS_OFFSET + \ + SE_CONTEXT_SAVE_KEY_LENGTH) + +#define SE_CONTEXT_ORIGINAL_IV_LENGTH 256 + +#define SE_CONTEXT_UPDATED_IV_OFFSET (SE_CONTEXT_ORIGINAL_IV_OFFSET + \ + SE_CONTEXT_ORIGINAL_IV_LENGTH) +#define SE11_CONTEXT_UPDATED_IV_OFFSET (SE11_CONTEXT_ORIGINAL_IV_OFFSET + \ + SE_CONTEXT_ORIGINAL_IV_LENGTH) + +#define SE_CONTEXT_UPDATED_IV_LENGTH 256 + +#define SE_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET (SE_CONTEXT_UPDATED_IV_OFFSET + \ + SE_CONTEXT_UPDATED_IV_LENGTH) +#define SE11_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET \ + (SE11_CONTEXT_UPDATED_IV_OFFSET + \ + SE_CONTEXT_UPDATED_IV_LENGTH) + +#define SE_CONTEXT_SAVE_RSA_KEYS_OFFSET SE11_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET + +#define SE_CONTEXT_SAVE_RSA_KEY_LENGTH 1024 + +#define SE_CONTEXT_SAVE_RSA_KNOWN_PATTERN_OFFSET \ + (SE_CONTEXT_SAVE_RSA_KEYS_OFFSET + SE_CONTEXT_SAVE_RSA_KEY_LENGTH) + +#define SE_CONTEXT_KNOWN_PATTERN_SIZE 16 + +#define TEGRA_SE_RSA_KEYSLOT_COUNT 2 + +#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C +#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 + +#define SE_RSA_KEYTABLE_ADDR 0x420 +#define SE_RSA_KEYTABLE_DATA 0x424 +#define SE_RSA_OUTPUT 0x428 + +#define RSA_KEY_READ 0 +#define RSA_KEY_WRITE 1 +#define SE_RSA_KEY_OP_SHIFT 10 +#define SE_RSA_KEY_OP(x) (x << SE_RSA_KEY_OP_SHIFT) + +#define RSA_KEY_INPUT_MODE_REG 0 +#define RSA_KEY_INPUT_MODE_DMA 1 +#define RSA_KEY_INPUT_MODE_SHIFT 8 +#define RSA_KEY_INPUT_MODE(x) (x << RSA_KEY_INPUT_MODE_SHIFT) + +#define RSA_KEY_SLOT_ONE 0 +#define RSA_KEY_SLOT_TW0 1 +#define RSA_KEY_NUM_SHIFT 7 +#define RSA_KEY_NUM(x) (x << RSA_KEY_NUM_SHIFT) + +#define RSA_KEY_TYPE_EXP 0 +#define RSA_KEY_TYPE_MOD 1 +#define RSA_KEY_TYPE_SHIFT 6 +#define RSA_KEY_TYPE(x) (x << RSA_KEY_TYPE_SHIFT) + +#define SE_RSA_KEY_SIZE_REG_OFFSET 0x404 +#define SE_RSA_EXP_SIZE_REG_OFFSET 0x408 + +#define RSA_KEY_SLOT_SHIFT 24 +#define RSA_KEY_SLOT(x) (x << RSA_KEY_SLOT_SHIFT) +#define SE_RSA_CONFIG 0x400 + +#define RSA_KEY_PKT_WORD_ADDR_SHIFT 0 +#define RSA_KEY_PKT_WORD_ADDR(x) (x << RSA_KEY_PKT_WORD_ADDR_SHIFT) + +#define RSA_KEY_WORD_ADDR_SHIFT 0 +#define RSA_KEY_WORD_ADDR(x) (x << RSA_KEY_WORD_ADDR_SHIFT) + +#define SE_RSA_KEYTABLE_PKT_SHIFT 0 +#define SE_RSA_KEYTABLE_PKT(x) (x << SE_RSA_KEYTABLE_PKT_SHIFT) + +#endif /* _CRYPTO_TEGRA_SE_H */ diff --git a/ipl/start.S b/ipl/start.S new file mode 100755 index 0000000..534f963 --- /dev/null +++ b/ipl/start.S @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +.section .text._start +.arm + +.extern _reloc_ipl +.type _reloc_ipl, %function + +.extern memset +.type memset, %function + +.extern ipl_main +.type ipl_main, %function + +.globl _start +.type _start, %function +_start: + ADR R0, _start + LDR R1, =__ipl_start + CMP R0, R1 + BEQ _real_start + + /* If we are not in the right location already, copy a relocator to upper IRAM. */ + ADR R2, _reloc_ipl + LDR R3, =0x4003FF00 + MOV R4, #(_real_start - _reloc_ipl) +_copy_loop: + LDMIA R2!, {R5} + STMIA R3!, {R5} + SUBS R4, #4 + BNE _copy_loop + + /* Use the relocator to copy ourselves into the right place. */ + LDR R2, =__ipl_end + SUB R2, R2, R1 + LDR R3, =_real_start + LDR R4, =0x4003FF00 + BX R4 + +_reloc_ipl: + LDMIA R0!, {R4-R7} + STMIA R1!, {R4-R7} + SUBS R2, #0x10 + BNE _reloc_ipl + /* Jump to the relocated entry. */ + BX R3 + +_real_start: + /* Initially, we place our stack in IRAM but will move it to SDRAM later. */ + LDR SP, =0x4003FF00 + LDR R0, =__bss_start + EOR R1, R1, R1 + LDR R2, =__bss_end + SUB R2, R2, R0 + BL memset + BL ipl_main + B . + +.globl pivot_stack +.type pivot_stack, %function +pivot_stack: + MOV SP, R0 + BX LR diff --git a/hwinit/t210.h b/ipl/t210.h old mode 100644 new mode 100755 similarity index 82% rename from hwinit/t210.h rename to ipl/t210.h index 13b808a..64cb0e6 --- a/hwinit/t210.h +++ b/ipl/t210.h @@ -34,13 +34,20 @@ #define GPIO_1_BASE (GPIO_BASE) #define GPIO_2_BASE (GPIO_BASE + 0x100) #define GPIO_3_BASE (GPIO_BASE + 0x200) +#define GPIO_4_BASE (GPIO_BASE + 0x300) +#define GPIO_5_BASE (GPIO_BASE + 0x400) #define GPIO_6_BASE (GPIO_BASE + 0x500) +#define GPIO_7_BASE (GPIO_BASE + 0x600) +#define GPIO_8_BASE (GPIO_BASE + 0x700) #define EXCP_VEC_BASE 0x6000F000 +#define APB_MISC_BASE 0x70000000 #define PINMUX_AUX_BASE 0x70003000 #define UART_BASE 0x70006000 #define PMC_BASE 0x7000E400 #define SYSCTR0_BASE 0x7000F000 #define FUSE_BASE 0x7000F800 +#define KFUSE_BASE 0x7000FC00 +#define SE_BASE 0x70012000 #define MC_BASE 0x70019000 #define EMC_BASE 0x7001B000 #define MIPI_CAL_BASE 0x700E3000 @@ -59,15 +66,23 @@ #define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off) #define SYSREG(off) _REG(SYSREG_BASE, off) #define SB(off) _REG(SB_BASE, off) +#define GPIO(off) _REG(GPIO_BASE, off) #define GPIO_1(off) _REG(GPIO_1_BASE, off) #define GPIO_2(off) _REG(GPIO_2_BASE, off) #define GPIO_3(off) _REG(GPIO_3_BASE, off) +#define GPIO_4(off) _REG(GPIO_4_BASE, off) +#define GPIO_5(off) _REG(GPIO_5_BASE, off) #define GPIO_6(off) _REG(GPIO_6_BASE, off) +#define GPIO_7(off) _REG(GPIO_7_BASE, off) +#define GPIO_8(off) _REG(GPIO_8_BASE, off) #define EXCP_VEC(off) _REG(EXCP_VEC_BASE, off) +#define APB_MISC(off) _REG(APB_MISC_BASE, off) #define PINMUX_AUX(off) _REG(PINMUX_AUX_BASE, off) #define PMC(off) _REG(PMC_BASE, off) #define SYSCTR0(off) _REG(SYSCTR0_BASE, off) #define FUSE(off) _REG(FUSE_BASE, off) +#define KFUSE(off) _REG(KFUSE_BASE, off) +#define SE(off) _REG(SE_BASE, off) #define MC(off) _REG(MC_BASE, off) #define EMC(off) _REG(EMC_BASE, off) #define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off) @@ -77,7 +92,7 @@ #define AHB_ARBITRATION_XBAR_CTRL 0xE0 /*! Secure boot registers. */ -#define SB_CSR_0 0x0 +#define SB_CSR 0x0 #define SB_AA64_RESET_LOW 0x30 #define SB_AA64_RESET_HIGH 0x34 diff --git a/hwinit/tsec.c b/ipl/tsec.c old mode 100644 new mode 100755 similarity index 87% rename from hwinit/tsec.c rename to ipl/tsec.c index 8db957e..612a38a --- a/hwinit/tsec.c +++ b/ipl/tsec.c @@ -18,10 +18,7 @@ #include "tsec.h" #include "clock.h" #include "t210.h" - -static const u8 _tsec_fw[3840] __attribute__((aligned(0x100))) = { - /* ... */ -}; +#include "heap.h" static int _tsec_dma_wait_idle() { @@ -50,7 +47,7 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse return _tsec_dma_wait_idle(); } -int tsec_query(u32 carveout, u8 *dst, u32 rev) +int tsec_query(u8 *dst, u32 rev, void *fw) { int res = 0; @@ -74,13 +71,15 @@ int tsec_query(u32 carveout, u8 *dst, u32 rev) } //Load firmware. - memcpy((void *)carveout, _tsec_fw, 0xF00); - TSEC(0x1110) = carveout >> 8;// tsec_dmatrfbase_r + u8 *fwbuf = (u8 *)malloc(0x2000); + u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100); + memcpy(fwbuf_aligned, fw, 0xF00); + TSEC(0x1110) = (u32)fwbuf_aligned >> 8;// tsec_dmatrfbase_r for (u32 addr = 0; addr < 0xF00; addr += 0x100) if (!_tsec_dma_pa_to_internal_100(0, addr, addr)) { res = -2; - goto out; + goto out_free; } //Execute firmware. @@ -92,19 +91,19 @@ int tsec_query(u32 carveout, u8 *dst, u32 rev) if (!_tsec_dma_wait_idle()) { res = -3; - goto out; + goto out_free; } u32 timeout = TMR(0x10) + 2000000; while (!TSEC(0x1044)) if (TMR(0x10) > timeout) { res = -4; - goto out; + goto out_free; } if (TSEC(0x1044) != 0xB0B0B0B0) { res = -5; - goto out; + goto out_free; } //Fetch result. @@ -120,6 +119,9 @@ int tsec_query(u32 carveout, u8 *dst, u32 rev) SOR1(0x20C) = 0; memcpy(dst, &buf, 0x10); +out_free:; + free(fwbuf); + out:; //Disable clocks. diff --git a/hwinit/tsec.h b/ipl/tsec.h old mode 100644 new mode 100755 similarity index 93% rename from hwinit/tsec.h rename to ipl/tsec.h index 7aa112c..24cce84 --- a/hwinit/tsec.h +++ b/ipl/tsec.h @@ -19,6 +19,6 @@ #include "types.h" -int tsec_query(u32 carveout, u8 *dst, u32 rev); +int tsec_query(u8 *dst, u32 rev, void *fw); #endif diff --git a/ipl/tui.c b/ipl/tui.c new file mode 100755 index 0000000..ef3aff1 --- /dev/null +++ b/ipl/tui.c @@ -0,0 +1,98 @@ +/*{ +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "tui.h" +#include "btn.h" + +void tui_pbar(gfx_con_t *con, int x, int y, u32 val) +{ + u32 cx, cy; + + gfx_con_getpos(con, &cx, &cy); + + gfx_con_setpos(con, x, y); + + gfx_printf(con, "[%3d%%]", val); + + x += 7 * 8; + + for (int i = 0; i < 6; i++) + { + gfx_line(con->gfx_ctxt, x, y + i + 1, x + 3 * val, y + i + 1, 0xFFFFFFFF); + gfx_line(con->gfx_ctxt, x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, 0xFF888888); + } + + gfx_con_setpos(con, cx, cy); +} + +void *tui_do_menu(gfx_con_t *con, menu_t *menu) +{ + int idx = 0, cnt; + + gfx_clear(con->gfx_ctxt, 0xFF000000); + + while (1) + { + gfx_con_setcol(con, 0xFFFFFFFF, 1, 0xFF000000); + gfx_con_setpos(con, menu->x, menu->y); + gfx_printf(con, "[%s]\n\n", menu->caption); + + for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++) + { + if (cnt == idx) + gfx_con_setcol(con, 0xFF000000, 1, 0xFFCCCCCC); + else + gfx_con_setcol(con, 0xFFFFFFFF, 1, 0xFF000000); + con->x += 8; + gfx_printf(con, "%s", menu->ents[cnt].caption); + if(menu->ents[cnt].type == MENT_MENU) + gfx_printf(con, "%k...", 0xFFEE9900); + gfx_putc(con, '\n'); + } + + gfx_con_setcol(con, 0xFFFFFFFF, 1, 0xFF000000); + gfx_putc(con, '\n'); + + u32 btn = btn_wait(); + + if (btn & BTN_VOL_DOWN && idx < cnt - 1) + idx++; + if (btn & BTN_VOL_UP && idx > 0) + idx--; + if (btn & BTN_POWER) + { + ment_t *ent = &menu->ents[idx]; + switch (ent->type) + { + case MENT_HANDLER: + ent->handler(ent->data); + break; + case MENT_MENU: + return tui_do_menu(con, ent->menu); + break; + case MENT_CHOICE: + return ent->data; + break; + case MENT_BACK: + return NULL; + break; + } + gfx_clear(con->gfx_ctxt, 0xFF000000); + } + } + + return NULL; +} diff --git a/ipl/tui.h b/ipl/tui.h new file mode 100755 index 0000000..6b1f2df --- /dev/null +++ b/ipl/tui.h @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _TUI_H_ +#define _TUI_H_ + +#include "types.h" +#include "gfx.h" + +#define MENT_END 0 +#define MENT_HANDLER 1 +#define MENT_MENU 2 +#define MENT_CHOICE 3 +#define MENT_BACK 4 + +typedef struct _ment_t +{ + u32 type; + const char *caption; + void *data; + union + { + void(*handler)(void *); + struct _menu_t *menu; + }; +} ment_t; + +typedef struct _menu_t +{ + ment_t *ents; + const char *caption; + u32 x; + u32 y; +} menu_t; + +#define MDEF_END() {MENT_END} +#define MDEF_HANDLER(caption, _handler) { MENT_HANDLER, caption, NULL, { .handler = _handler } } +#define MDEF_HANDLER_EX(caption, data, _handler) { MENT_HANDLER, caption, data, { .handler = _handler } } +#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, NULL, { .menu = _menu } } +#define MDEF_BACK() { MENT_BACK, "Back" } + +void tui_pbar(gfx_con_t *con, int x, int y, u32 val); +void *tui_do_menu(gfx_con_t *con, menu_t *menu); + +#endif diff --git a/ipl/types.h b/ipl/types.h new file mode 100755 index 0000000..56dd81e --- /dev/null +++ b/ipl/types.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +#define NULL ((void *)0) + +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) +#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long int u64; +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; + +#endif diff --git a/hwinit/uart.c b/ipl/uart.c old mode 100644 new mode 100755 similarity index 100% rename from hwinit/uart.c rename to ipl/uart.c diff --git a/hwinit/uart.h b/ipl/uart.h old mode 100644 new mode 100755 similarity index 100% rename from hwinit/uart.h rename to ipl/uart.h diff --git a/hwinit/util.c b/ipl/util.c old mode 100644 new mode 100755 similarity index 95% rename from hwinit/util.c rename to ipl/util.c index 4a3b879..ef009a1 --- a/hwinit/util.c +++ b/ipl/util.c @@ -17,6 +17,11 @@ #include "util.h" #include "t210.h" +u32 get_tmr() +{ + return TMR(0x10); +} + void sleep(u32 ticks) { u32 start = TMR(0x10); diff --git a/hwinit/util.h b/ipl/util.h old mode 100644 new mode 100755 similarity index 98% rename from hwinit/util.h rename to ipl/util.h index ad78f88..a1fc7dd --- a/hwinit/util.h +++ b/ipl/util.h @@ -25,6 +25,7 @@ typedef struct _cfg_op_t u32 val; } cfg_op_t; +u32 get_tmr(); void sleep(u32 ticks); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); diff --git a/tools/emc.def b/tools/emc.def new file mode 100755 index 0000000..ddcb5af --- /dev/null +++ b/tools/emc.def @@ -0,0 +1,641 @@ +EMC_DBG 8 +EMC_CFG C +EMC_CONFIG_SAMPLE_DELAY 5f0 +EMC_CFG_UPDATE 5f4 +EMC_ADR_CFG 10 +EMC_REFCTRL 20 +EMC_PIN 24 +EMC_TIMING_CONTROL 28 +EMC_RC 2c +EMC_RFC 30 +EMC_RFCPB 590 +EMC_RAS 34 +EMC_RP 38 +EMC_R2W 3c +EMC_W2R 40 +EMC_R2P 44 +EMC_W2P 48 +EMC_CCDMW 5c0 +EMC_RD_RCD 4c +EMC_WR_RCD 50 +EMC_RRD 54 +EMC_REXT 58 +EMC_WDV 5c +EMC_QUSE 60 +EMC_QRST 64 +EMC_ISSUE_QRST 428 +EMC_QSAFE 68 +EMC_RDV 6c +EMC_REFRESH 70 +EMC_BURST_REFRESH_NUM 74 +EMC_PDEX2WR 78 +EMC_PDEX2RD 7c +EMC_PDEX2CKE 118 +EMC_PCHG2PDEN 80 +EMC_ACT2PDEN 84 +EMC_AR2PDEN 88 +EMC_RW2PDEN 8c +EMC_CKE2PDEN 11c +EMC_TXSR 90 +EMC_TCKE 94 +EMC_TFAW 98 +EMC_TRPAB 9c +EMC_TCLKSTABLE a0 +EMC_TCLKSTOP a4 +EMC_TREFBW a8 +EMC_TPPD ac +EMC_PDEX2MRR b4 +EMC_ODT_WRITE b0 +EMC_WEXT b8 +EMC_RFC_SLR c0 +EMC_MRS_WAIT_CNT2 c4 +EMC_MRS_WAIT_CNT c8 +EMC_MRS cc +EMC_EMRS d0 +EMC_REF d4 +EMC_PRE d8 +EMC_NOP dc +EMC_SELF_REF e0 +EMC_DPD e4 +EMC_MRW e8 +EMC_MRR ec +EMC_CMDQ f0 +EMC_MC2EMCQ f4 +EMC_FBIO_SPARE 100 +EMC_FBIO_CFG5 104 +EMC_CFG_RSV 120 +EMC_ACPD_CONTROL 124 +EMC_MPC 128 +EMC_EMRS2 12c +EMC_EMRS3 130 +EMC_MRW2 134 +EMC_MRW3 138 +EMC_MRW4 13c +EMC_MRW5 4a0 +EMC_MRW6 4a4 +EMC_MRW7 4a8 +EMC_MRW8 4ac +EMC_MRW9 4b0 +EMC_MRW10 4b4 +EMC_MRW11 4b8 +EMC_MRW12 4bc +EMC_MRW13 4c0 +EMC_MRW14 4c4 +EMC_MRW15 4d0 +EMC_CFG_SYNC 4d4 +EMC_CLKEN_OVERRIDE 140 +EMC_R2R 144 +EMC_W2W 148 +EMC_EINPUT 14c +EMC_EINPUT_DURATION 150 +EMC_PUTERM_EXTRA 154 +EMC_TCKESR 158 +EMC_TPD 15c +EMC_STAT_CONTROL 160 +EMC_STAT_STATUS 164 +EMC_STAT_DRAM_CLOCK_LIMIT_LO 19c +EMC_STAT_DRAM_CLOCK_LIMIT_HI 1a0 +EMC_STAT_DRAM_CLOCKS_LO 1a4 +EMC_STAT_DRAM_CLOCKS_HI 1a8 +EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO 1ac +EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI 1b0 +EMC_STAT_DRAM_DEV0_READ_CNT_LO 1b4 +EMC_STAT_DRAM_DEV0_READ_CNT_HI 1b8 +EMC_STAT_DRAM_DEV0_READ8_CNT_LO 1bc +EMC_STAT_DRAM_DEV0_READ8_CNT_HI 1c0 +EMC_STAT_DRAM_DEV0_WRITE_CNT_LO 1c4 +EMC_STAT_DRAM_DEV0_WRITE_CNT_HI 1c8 +EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO 1cc +EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI 1d0 +EMC_STAT_DRAM_DEV0_REF_CNT_LO 1d4 +EMC_STAT_DRAM_DEV0_REF_CNT_HI 1d8 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 1dc +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 1e0 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 1e4 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 1e8 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 1ec +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 1f0 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 1f4 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 1f8 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 1fc +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 200 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 204 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 208 +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 20c +EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 210 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 214 +EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 218 +EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO 21c +EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI 220 +EMC_STAT_DRAM_DEV0_DSR 224 +EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO 228 +EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI 22c +EMC_STAT_DRAM_DEV1_READ_CNT_LO 230 +EMC_STAT_DRAM_DEV1_READ_CNT_HI 234 +EMC_STAT_DRAM_DEV1_READ8_CNT_LO 238 +EMC_STAT_DRAM_DEV1_READ8_CNT_HI 23c +EMC_STAT_DRAM_DEV1_WRITE_CNT_LO 240 +EMC_STAT_DRAM_DEV1_WRITE_CNT_HI 244 +EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO 248 +EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI 24c +EMC_STAT_DRAM_DEV1_REF_CNT_LO 250 +EMC_STAT_DRAM_DEV1_REF_CNT_HI 254 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 258 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 25c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 260 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 264 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 268 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 26c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 270 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 274 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 278 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 27c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 280 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 284 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 288 +EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 28c +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 290 +EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 294 +EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO 298 +EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI 29c +EMC_STAT_DRAM_DEV1_DSR 2a0 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO c8c +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI c90 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO c94 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI c98 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO c9c +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI ca0 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO ca4 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI ca8 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO cac +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI cb0 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO cb4 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI cb8 +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO cbc +EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI cc0 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO cc4 +EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI cc8 +EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO ccc +EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI cd0 +EMC_STAT_DRAM_IO_DSR cd4 +EMC_AUTO_CAL_CONFIG 2a4 +EMC_AUTO_CAL_CONFIG2 458 +EMC_AUTO_CAL_CONFIG3 45c +EMC_AUTO_CAL_CONFIG4 5b0 +EMC_AUTO_CAL_CONFIG5 5b4 +EMC_AUTO_CAL_CONFIG6 5cc +EMC_AUTO_CAL_CONFIG7 574 +EMC_AUTO_CAL_CONFIG8 2dc +EMC_AUTO_CAL_VREF_SEL_0 2f8 +EMC_AUTO_CAL_VREF_SEL_1 300 +EMC_AUTO_CAL_INTERVAL 2a8 +EMC_AUTO_CAL_STATUS 2ac +EMC_AUTO_CAL_STATUS2 3d4 +EMC_AUTO_CAL_CHANNEL 464 +EMC_PMACRO_RX_TERM c48 +EMC_PMACRO_DQ_TX_DRV c70 +EMC_PMACRO_CA_TX_DRV c74 +EMC_PMACRO_CMD_TX_DRV c4c +EMC_PMACRO_AUTOCAL_CFG_0 700 +EMC_PMACRO_AUTOCAL_CFG_1 704 +EMC_PMACRO_AUTOCAL_CFG_2 708 +EMC_PMACRO_AUTOCAL_CFG_COMMON c78 +EMC_PMACRO_ZCTRL c44 +EMC_XM2COMPPADCTRL 30c +EMC_XM2COMPPADCTRL2 578 +EMC_XM2COMPPADCTRL3 2f4 +EMC_COMP_PAD_SW_CTRL 57c +EMC_REQ_CTRL 2b0 +EMC_EMC_STATUS 2b4 +EMC_CFG_2 2b8 +EMC_CFG_DIG_DLL 2bc +EMC_CFG_DIG_DLL_PERIOD 2c0 +EMC_DIG_DLL_STATUS 2c4 +EMC_CFG_DIG_DLL_1 2c8 +EMC_RDV_MASK 2cc +EMC_WDV_MASK 2d0 +EMC_RDV_EARLY_MASK 2d4 +EMC_RDV_EARLY 2d8 +EMC_WDV_CHK 4e0 +EMC_ZCAL_INTERVAL 2e0 +EMC_ZCAL_WAIT_CNT 2e4 +EMC_ZCAL_MRW_CMD 2e8 +EMC_ZQ_CAL 2ec +EMC_SCRATCH0 324 +EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE 3c8 +EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 3cc +EMC_UNSTALL_RW_AFTER_CLKCHANGE 3d0 +EMC_FDPD_CTRL_CMD_NO_RAMP 4d8 +EMC_SEL_DPD_CTRL 3d8 +EMC_FDPD_CTRL_DQ 310 +EMC_FDPD_CTRL_CMD 314 +EMC_PRE_REFRESH_REQ_CNT 3dc +EMC_REFCTRL2 580 +EMC_FBIO_CFG7 584 +EMC_DATA_BRLSHFT_0 588 +EMC_DATA_BRLSHFT_1 58c +EMC_DQS_BRLSHFT_0 594 +EMC_DQS_BRLSHFT_1 598 +EMC_CMD_BRLSHFT_0 59c +EMC_CMD_BRLSHFT_1 5a0 +EMC_CMD_BRLSHFT_2 5a4 +EMC_CMD_BRLSHFT_3 5a8 +EMC_QUSE_BRLSHFT_0 5ac +EMC_QUSE_BRLSHFT_1 5b8 +EMC_QUSE_BRLSHFT_2 5bc +EMC_QUSE_BRLSHFT_3 5c4 +EMC_FBIO_CFG8 5c8 +EMC_CMD_MAPPING_CMD0_0 380 +EMC_CMD_MAPPING_CMD0_1 384 +EMC_CMD_MAPPING_CMD0_2 388 +EMC_CMD_MAPPING_CMD1_0 38c +EMC_CMD_MAPPING_CMD1_1 390 +EMC_CMD_MAPPING_CMD1_2 394 +EMC_CMD_MAPPING_CMD2_0 398 +EMC_CMD_MAPPING_CMD2_1 39c +EMC_CMD_MAPPING_CMD2_2 3a0 +EMC_CMD_MAPPING_CMD3_0 3a4 +EMC_CMD_MAPPING_CMD3_1 3a8 +EMC_CMD_MAPPING_CMD3_2 3ac +EMC_CMD_MAPPING_BYTE 3b0 +EMC_DYN_SELF_REF_CONTROL 3e0 +EMC_TXSRDLL 3e4 +EMC_CCFIFO_ADDR 3e8 +EMC_CCFIFO_DATA 3ec +EMC_CCFIFO_STATUS 3f0 +EMC_SWIZZLE_RANK0_BYTE0 404 +EMC_SWIZZLE_RANK0_BYTE1 408 +EMC_SWIZZLE_RANK0_BYTE2 40c +EMC_SWIZZLE_RANK0_BYTE3 410 +EMC_SWIZZLE_RANK1_BYTE0 418 +EMC_SWIZZLE_RANK1_BYTE1 41c +EMC_SWIZZLE_RANK1_BYTE2 420 +EMC_SWIZZLE_RANK1_BYTE3 424 +EMC_TR_TIMING_0 3b4 +EMC_TR_CTRL_0 3b8 +EMC_TR_CTRL_1 3bc +EMC_TR_DVFS 460 +EMC_SWITCH_BACK_CTRL 3c0 +EMC_TR_RDV 3c4 +EMC_TR_QPOP 3f4 +EMC_TR_RDV_MASK 3f8 +EMC_TR_QSAFE 3fc +EMC_TR_QRST 400 +EMC_IBDLY 468 +EMC_OBDLY 46c +EMC_TXDSRVTTGEN 480 +EMC_WE_DURATION 48c +EMC_WS_DURATION 490 +EMC_WEV 494 +EMC_WSV 498 +EMC_CFG_3 49c +EMC_CFG_PIPE_2 554 +EMC_CFG_PIPE_CLK 558 +EMC_CFG_PIPE_1 55c +EMC_CFG_PIPE 560 +EMC_QPOP 564 +EMC_QUSE_WIDTH 568 +EMC_PUTERM_WIDTH 56c +EMC_PROTOBIST_CONFIG_ADR_1 5d0 +EMC_PROTOBIST_CONFIG_ADR_2 5d4 +EMC_PROTOBIST_MISC 5d8 +EMC_PROTOBIST_WDATA_LOWER 5dc +EMC_PROTOBIST_WDATA_UPPER 5e0 +EMC_PROTOBIST_RDATA 5ec +EMC_DLL_CFG_0 5e4 +EMC_DLL_CFG_1 5e8 +EMC_TRAINING_CMD e00 +EMC_TRAINING_CTRL e04 +EMC_TRAINING_STATUS e08 +EMC_TRAINING_QUSE_CORS_CTRL e0c +EMC_TRAINING_QUSE_FINE_CTRL e10 +EMC_TRAINING_QUSE_CTRL_MISC e14 +EMC_TRAINING_WRITE_FINE_CTRL e18 +EMC_TRAINING_WRITE_CTRL_MISC e1c +EMC_TRAINING_WRITE_VREF_CTRL e20 +EMC_TRAINING_READ_FINE_CTRL e24 +EMC_TRAINING_READ_CTRL_MISC e28 +EMC_TRAINING_READ_VREF_CTRL e2c +EMC_TRAINING_CA_FINE_CTRL e30 +EMC_TRAINING_CA_CTRL_MISC e34 +EMC_TRAINING_CA_CTRL_MISC1 e38 +EMC_TRAINING_CA_VREF_CTRL e3c +EMC_TRAINING_CA_TADR_CTRL e40 +EMC_TRAINING_SETTLE e44 +EMC_TRAINING_DEBUG_CTRL e48 +EMC_TRAINING_DEBUG_DQ0 e4c +EMC_TRAINING_DEBUG_DQ1 e50 +EMC_TRAINING_DEBUG_DQ2 e54 +EMC_TRAINING_DEBUG_DQ3 e58 +EMC_TRAINING_MPC e5c +EMC_TRAINING_PATRAM_CTRL e60 +EMC_TRAINING_PATRAM_DQ e64 +EMC_TRAINING_PATRAM_DMI e68 +EMC_TRAINING_VREF_SETTLE e6c +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0 e70 +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1 e74 +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2 e78 +EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3 e7c +EMC_TRAINING_RW_EYE_CENTER_IB_MISC e80 +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0 e84 +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1 e88 +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2 e8c +EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3 e90 +EMC_TRAINING_RW_EYE_CENTER_OB_MISC e94 +EMC_TRAINING_RW_OFFSET_IB_BYTE0 e98 +EMC_TRAINING_RW_OFFSET_IB_BYTE1 e9c +EMC_TRAINING_RW_OFFSET_IB_BYTE2 ea0 +EMC_TRAINING_RW_OFFSET_IB_BYTE3 ea4 +EMC_TRAINING_RW_OFFSET_IB_MISC ea8 +EMC_TRAINING_RW_OFFSET_OB_BYTE0 eac +EMC_TRAINING_RW_OFFSET_OB_BYTE1 eb0 +EMC_TRAINING_RW_OFFSET_OB_BYTE2 eb4 +EMC_TRAINING_RW_OFFSET_OB_BYTE3 eb8 +EMC_TRAINING_RW_OFFSET_OB_MISC ebc +EMC_TRAINING_OPT_CA_VREF ec0 +EMC_TRAINING_OPT_DQ_OB_VREF ec4 +EMC_TRAINING_OPT_DQ_IB_VREF_RANK0 ec8 +EMC_TRAINING_OPT_DQ_IB_VREF_RANK1 ecc +EMC_TRAINING_QUSE_VREF_CTRL ed0 +EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 ed4 +EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 ed8 +EMC_TRAINING_DRAMC_TIMING edc +EMC_PMACRO_QUSE_DDLL_RANK0_0 600 +EMC_PMACRO_QUSE_DDLL_RANK0_1 604 +EMC_PMACRO_QUSE_DDLL_RANK0_2 608 +EMC_PMACRO_QUSE_DDLL_RANK0_3 60c +EMC_PMACRO_QUSE_DDLL_RANK0_4 610 +EMC_PMACRO_QUSE_DDLL_RANK0_5 614 +EMC_PMACRO_QUSE_DDLL_RANK1_0 620 +EMC_PMACRO_QUSE_DDLL_RANK1_1 624 +EMC_PMACRO_QUSE_DDLL_RANK1_2 628 +EMC_PMACRO_QUSE_DDLL_RANK1_3 62c +EMC_PMACRO_QUSE_DDLL_RANK1_4 630 +EMC_PMACRO_QUSE_DDLL_RANK1_5 634 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 640 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 644 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 648 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 64c +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 650 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 654 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 660 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 664 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 668 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 66c +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 670 +EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 674 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 680 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 684 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 688 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 68c +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 690 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 694 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 6a0 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 6a4 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 6a8 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 6ac +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 6b0 +EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 6b4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 6c0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 6c4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 6c8 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 6cc +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4 6d0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5 6d4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 6e0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 6e4 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 6e8 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 6ec +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4 6f0 +EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5 6f4 +EMC_PMACRO_TX_PWRD_0 720 +EMC_PMACRO_TX_PWRD_1 724 +EMC_PMACRO_TX_PWRD_2 728 +EMC_PMACRO_TX_PWRD_3 72c +EMC_PMACRO_TX_PWRD_4 730 +EMC_PMACRO_TX_PWRD_5 734 +EMC_PMACRO_TX_SEL_CLK_SRC_0 740 +EMC_PMACRO_TX_SEL_CLK_SRC_1 744 +EMC_PMACRO_TX_SEL_CLK_SRC_3 74c +EMC_PMACRO_TX_SEL_CLK_SRC_2 748 +EMC_PMACRO_TX_SEL_CLK_SRC_4 750 +EMC_PMACRO_TX_SEL_CLK_SRC_5 754 +EMC_PMACRO_DDLL_BYPASS 760 +EMC_PMACRO_DDLL_PWRD_0 770 +EMC_PMACRO_DDLL_PWRD_1 774 +EMC_PMACRO_DDLL_PWRD_2 778 +EMC_PMACRO_CMD_CTRL_0 780 +EMC_PMACRO_CMD_CTRL_1 784 +EMC_PMACRO_CMD_CTRL_2 788 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 800 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 804 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 808 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 80c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 810 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 814 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 818 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 81c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 820 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 824 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 828 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 82c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 830 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 834 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 838 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 83c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 840 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 844 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 848 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 84c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 850 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 854 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 858 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 85c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 860 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 864 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 868 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 86c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 870 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 874 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 878 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 87c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 880 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 884 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 888 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 88c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 890 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 894 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 898 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 89c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 8a0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 8a4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 8a8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 8ac +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 8b0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 8b4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 8b8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 8bc +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 900 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 904 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 908 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 90c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 910 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 914 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 918 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 91c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 920 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 924 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 928 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 92c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 930 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 934 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 938 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 93c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 940 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 944 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 948 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 94c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 950 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 954 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 958 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 95c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 960 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 964 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 968 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 96c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 970 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 974 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 978 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 97c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 980 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 984 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 988 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 98c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 990 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 994 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 998 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 99c +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 9a0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 9a4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 9a8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 9ac +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 9b0 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 9b4 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 9b8 +EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 9bc +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 a00 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 a04 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 a08 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 a10 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 a14 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 a18 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 a20 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 a24 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 a28 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 a30 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 a34 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 a38 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 a40 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 a44 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 a48 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 a50 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 a54 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 a58 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 a60 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 a64 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 a68 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 a70 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 a74 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 a78 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0 a80 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1 a84 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2 a88 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0 a90 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1 a94 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2 a98 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0 aa0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1 aa4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2 aa8 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0 ab0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1 ab4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2 ab8 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 b00 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 b04 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 b08 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 b10 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 b14 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 b18 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 b20 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 b24 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 b28 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 b30 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 b34 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 b38 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 b40 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 b44 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 b48 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 b50 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 b54 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 b58 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 b60 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 b64 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 b68 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 b70 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 b74 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 b78 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0 b80 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1 b84 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2 b88 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0 b90 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1 b94 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2 b98 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0 ba0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1 ba4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2 ba8 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0 bb0 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1 bb4 +EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2 bb8 +EMC_PMACRO_IB_VREF_DQ_0 be0 +EMC_PMACRO_IB_VREF_DQ_1 be4 +EMC_PMACRO_IB_VREF_DQ_2 be8 +EMC_PMACRO_IB_VREF_DQS_0 bf0 +EMC_PMACRO_IB_VREF_DQS_1 bf4 +EMC_PMACRO_IB_VREF_DQS_2 bf8 +EMC_PMACRO_IB_RXRT cf4 +EMC_PMACRO_DDLL_LONG_CMD_0 c00 +EMC_PMACRO_DDLL_LONG_CMD_1 c04 +EMC_PMACRO_DDLL_LONG_CMD_2 c08 +EMC_PMACRO_DDLL_LONG_CMD_3 c0c +EMC_PMACRO_DDLL_LONG_CMD_4 c10 +EMC_PMACRO_DDLL_LONG_CMD_5 c14 +EMC_PMACRO_DDLL_SHORT_CMD_0 c20 +EMC_PMACRO_DDLL_SHORT_CMD_1 c24 +EMC_PMACRO_DDLL_SHORT_CMD_2 c28 +EMC_PMACRO_CFG_PM_GLOBAL_0 c30 +EMC_PMACRO_VTTGEN_CTRL_0 c34 +EMC_PMACRO_VTTGEN_CTRL_1 c38 +EMC_PMACRO_VTTGEN_CTRL_2 cf0 +EMC_PMACRO_BG_BIAS_CTRL_0 c3c +EMC_PMACRO_PAD_CFG_CTRL c40 +EMC_PMACRO_CMD_PAD_RX_CTRL c50 +EMC_PMACRO_DATA_PAD_RX_CTRL c54 +EMC_PMACRO_CMD_RX_TERM_MODE c58 +EMC_PMACRO_DATA_RX_TERM_MODE c5c +EMC_PMACRO_CMD_PAD_TX_CTRL c60 +EMC_PMACRO_DATA_PAD_TX_CTRL c64 +EMC_PMACRO_COMMON_PAD_TX_CTRL c68 +EMC_PMACRO_BRICK_MAPPING_0 c80 +EMC_PMACRO_BRICK_MAPPING_1 c84 +EMC_PMACRO_BRICK_MAPPING_2 c88 +EMC_PMACRO_DDLLCAL_CAL ce0 +EMC_PMACRO_DDLL_OFFSET ce4 +EMC_PMACRO_DDLL_PERIODIC_OFFSET ce8 +EMC_PMACRO_BRICK_CTRL_RFU1 330 +EMC_PMACRO_BRICK_CTRL_RFU2 334 +EMC_PMACRO_CMD_BRICK_CTRL_FDPD 318 +EMC_PMACRO_DATA_BRICK_CTRL_FDPD 31c +EMC_PMACRO_TRAINING_CTRL_0 cf8 +EMC_PMACRO_TRAINING_CTRL_1 cfc +EMC_PMC_SCRATCH1 440 +EMC_PMC_SCRATCH2 444 +EMC_PMC_SCRATCH3 448 diff --git a/tools/fix_regs.py b/tools/fix_regs.py new file mode 100755 index 0000000..3a24a3f --- /dev/null +++ b/tools/fix_regs.py @@ -0,0 +1,35 @@ +import re + +def parse_defs(fname): + f = open(fname, "r") + lines = f.readlines() + f.close() + res = {} + for l in lines: + p = [str(_.strip()) for _ in l.strip().split(" ", 1)] + res[int(p[1], 16)] = p[0] + return res + +mc = parse_defs("mc.def") +emc = parse_defs("emc.def") + +f = open(sys.argv[1], "r") +buf = f.read() +f.close() + +def fix(m): + what = m.groups()[0] + off = int(m.groups()[1], 16) + if what == "MC": + if off in mc: + return "MC({0})".format(mc[off]) + elif what == "EMC": + if off in emc: + return "EMC({0})".format(emc[off]) + return "{0}(0x{1:X})".format(what, off) + +buf = re.sub(r'([A-Z]+)\(0x([0-9a-fA-F]+)\)', fix, buf) + +f = open(sys.argv[2], "w") +f.write(buf) +f.close() diff --git a/tools/mc.def b/tools/mc.def new file mode 100755 index 0000000..62f3835 --- /dev/null +++ b/tools/mc.def @@ -0,0 +1,448 @@ +MC_INTSTATUS 0 +MC_INTMASK 4 +MC_ERR_STATUS 8 +MC_ERR_ADR c +MC_PCFIFO_CLIENT_CONFIG0 dd0 +MC_PCFIFO_CLIENT_CONFIG1 dd4 +MC_PCFIFO_CLIENT_CONFIG2 dd8 +MC_PCFIFO_CLIENT_CONFIG3 ddc +MC_PCFIFO_CLIENT_CONFIG4 de0 +MC_EMEM_CFG 50 +MC_EMEM_ADR_CFG 54 +MC_EMEM_ADR_CFG_DEV0 58 +MC_EMEM_ADR_CFG_DEV1 5c +MC_EMEM_ADR_CFG_CHANNEL_MASK 60 +MC_EMEM_ADR_CFG_BANK_MASK_0 64 +MC_EMEM_ADR_CFG_BANK_MASK_1 68 +MC_EMEM_ADR_CFG_BANK_MASK_2 6c +MC_SECURITY_CFG0 70 +MC_SECURITY_CFG1 74 +MC_SECURITY_CFG3 9bc +MC_SECURITY_RSV 7c +MC_EMEM_ARB_CFG 90 +MC_EMEM_ARB_OUTSTANDING_REQ 94 +MC_EMEM_ARB_TIMING_RCD 98 +MC_EMEM_ARB_TIMING_RP 9c +MC_EMEM_ARB_TIMING_RC a0 +MC_EMEM_ARB_TIMING_RAS a4 +MC_EMEM_ARB_TIMING_FAW a8 +MC_EMEM_ARB_TIMING_RRD ac +MC_EMEM_ARB_TIMING_RAP2PRE b0 +MC_EMEM_ARB_TIMING_WAP2PRE b4 +MC_EMEM_ARB_TIMING_R2R b8 +MC_EMEM_ARB_TIMING_W2W bc +MC_EMEM_ARB_TIMING_R2W c0 +MC_EMEM_ARB_TIMING_W2R c4 +MC_EMEM_ARB_TIMING_RFCPB 6c0 +MC_EMEM_ARB_TIMING_CCDMW 6c4 +MC_EMEM_ARB_REFPB_HP_CTRL 6f0 +MC_EMEM_ARB_REFPB_BANK_CTRL 6f4 +MC_EMEM_ARB_DA_TURNS d0 +MC_EMEM_ARB_DA_COVERS d4 +MC_EMEM_ARB_MISC0 d8 +MC_EMEM_ARB_MISC1 dc +MC_EMEM_ARB_MISC2 c8 +MC_EMEM_ARB_RING1_THROTTLE e0 +MC_EMEM_ARB_RING3_THROTTLE e4 +MC_EMEM_ARB_NISO_THROTTLE 6b0 +MC_EMEM_ARB_OVERRIDE e8 +MC_EMEM_ARB_RSV ec +MC_CLKEN_OVERRIDE f4 +MC_TIMING_CONTROL_DBG f8 +MC_TIMING_CONTROL fc +MC_STAT_CONTROL 100 +MC_STAT_STATUS 104 +MC_STAT_EMC_CLOCK_LIMIT 108 +MC_STAT_EMC_CLOCK_LIMIT_MSBS 10c +MC_STAT_EMC_CLOCKS 110 +MC_STAT_EMC_CLOCKS_MSBS 114 +MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 118 +MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 158 +MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 11c +MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 15c +MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER a20 +MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER a24 +MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 198 +MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 1a8 +MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 19c +MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 1ac +MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER a28 +MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER a2c +MC_STAT_EMC_FILTER_SET0_ASID 1a0 +MC_STAT_EMC_FILTER_SET1_ASID 1b0 +MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 120 +MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 160 +MC_STAT_EMC_FILTER_SET0_CLIENT_0 128 +MC_STAT_EMC_FILTER_SET1_CLIENT_0 168 +MC_STAT_EMC_FILTER_SET0_CLIENT_1 12c +MC_STAT_EMC_FILTER_SET1_CLIENT_1 16c +MC_STAT_EMC_FILTER_SET0_CLIENT_2 130 +MC_STAT_EMC_FILTER_SET1_CLIENT_2 170 +MC_STAT_EMC_FILTER_SET0_CLIENT_3 134 +MC_STAT_EMC_FILTER_SET0_CLIENT_4 b88 +MC_STAT_EMC_FILTER_SET1_CLIENT_3 174 +MC_STAT_EMC_FILTER_SET1_CLIENT_4 b8c +MC_STAT_EMC_SET0_COUNT 138 +MC_STAT_EMC_SET0_COUNT_MSBS 13c +MC_STAT_EMC_SET1_COUNT 178 +MC_STAT_EMC_SET1_COUNT_MSBS 17c +MC_STAT_EMC_SET0_SLACK_ACCUM 140 +MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 144 +MC_STAT_EMC_SET1_SLACK_ACCUM 180 +MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 184 +MC_STAT_EMC_SET0_HISTO_COUNT 148 +MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 14c +MC_STAT_EMC_SET1_HISTO_COUNT 188 +MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 18c +MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 150 +MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 190 +MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 1b8 +MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 1bc +MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 1c8 +MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 1cc +MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 1c0 +MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 1d0 +MC_CLIENT_HOTRESET_CTRL 200 +MC_CLIENT_HOTRESET_CTRL_1 970 +MC_CLIENT_HOTRESET_STATUS 204 +MC_CLIENT_HOTRESET_STATUS_1 974 +MC_EMEM_ARB_ISOCHRONOUS_0 208 +MC_EMEM_ARB_ISOCHRONOUS_1 20c +MC_EMEM_ARB_ISOCHRONOUS_2 210 +MC_EMEM_ARB_ISOCHRONOUS_3 214 +MC_EMEM_ARB_ISOCHRONOUS_4 b94 +MC_EMEM_ARB_HYSTERESIS_0 218 +MC_EMEM_ARB_HYSTERESIS_1 21c +MC_EMEM_ARB_HYSTERESIS_2 220 +MC_EMEM_ARB_HYSTERESIS_3 224 +MC_EMEM_ARB_HYSTERESIS_4 b84 +MC_EMEM_ARB_DHYSTERESIS_0 bb0 +MC_EMEM_ARB_DHYSTERESIS_1 bb4 +MC_EMEM_ARB_DHYSTERESIS_2 bb8 +MC_EMEM_ARB_DHYSTERESIS_3 bbc +MC_EMEM_ARB_DHYSTERESIS_4 bc0 +MC_EMEM_ARB_DHYST_CTRL bcc +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 bd0 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 bd4 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 bd8 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 bdc +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 be0 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 be4 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 be8 +MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 bec +MC_RESERVED_RSV 3fc +MC_DISB_EXTRA_SNAP_LEVELS 408 +MC_APB_EXTRA_SNAP_LEVELS 2a4 +MC_AHB_EXTRA_SNAP_LEVELS 2a0 +MC_USBD_EXTRA_SNAP_LEVELS a18 +MC_ISP_EXTRA_SNAP_LEVELS a08 +MC_AUD_EXTRA_SNAP_LEVELS a10 +MC_MSE_EXTRA_SNAP_LEVELS 40c +MC_GK2_EXTRA_SNAP_LEVELS a40 +MC_A9AVPPC_EXTRA_SNAP_LEVELS 414 +MC_FTOP_EXTRA_SNAP_LEVELS 2bc +MC_JPG_EXTRA_SNAP_LEVELS a3c +MC_HOST_EXTRA_SNAP_LEVELS a14 +MC_SAX_EXTRA_SNAP_LEVELS 2c0 +MC_DIS_EXTRA_SNAP_LEVELS 2ac +MC_VICPC_EXTRA_SNAP_LEVELS a1c +MC_HDAPC_EXTRA_SNAP_LEVELS a48 +MC_AVP_EXTRA_SNAP_LEVELS 2a8 +MC_USBX_EXTRA_SNAP_LEVELS 404 +MC_PCX_EXTRA_SNAP_LEVELS 2b8 +MC_SD_EXTRA_SNAP_LEVELS a04 +MC_DFD_EXTRA_SNAP_LEVELS a4c +MC_VE_EXTRA_SNAP_LEVELS 2d8 +MC_GK_EXTRA_SNAP_LEVELS a00 +MC_VE2_EXTRA_SNAP_LEVELS 410 +MC_SDM_EXTRA_SNAP_LEVELS a44 +MC_VIDEO_PROTECT_BOM 648 +MC_VIDEO_PROTECT_SIZE_MB 64c +MC_VIDEO_PROTECT_BOM_ADR_HI 978 +MC_VIDEO_PROTECT_REG_CTRL 650 +MC_ERR_VPR_STATUS 654 +MC_ERR_VPR_ADR 658 +MC_VIDEO_PROTECT_VPR_OVERRIDE 418 +MC_VIDEO_PROTECT_VPR_OVERRIDE1 590 +MC_IRAM_BOM 65c +MC_IRAM_TOM 660 +MC_IRAM_ADR_HI 980 +MC_IRAM_REG_CTRL 964 +MC_EMEM_CFG_ACCESS_CTRL 664 +MC_TZ_SECURITY_CTRL 668 +MC_EMEM_ARB_OUTSTANDING_REQ_RING3 66c +MC_EMEM_ARB_OUTSTANDING_REQ_NISO 6b4 +MC_EMEM_ARB_RING0_THROTTLE_MASK 6bc +MC_EMEM_ARB_NISO_THROTTLE_MASK 6b8 +MC_EMEM_ARB_NISO_THROTTLE_MASK_1 b80 +MC_SEC_CARVEOUT_BOM 670 +MC_SEC_CARVEOUT_SIZE_MB 674 +MC_SEC_CARVEOUT_ADR_HI 9d4 +MC_SEC_CARVEOUT_REG_CTRL 678 +MC_ERR_SEC_STATUS 67c +MC_ERR_SEC_ADR 680 +MC_PC_IDLE_CLOCK_GATE_CONFIG 684 +MC_STUTTER_CONTROL 688 +MC_RESERVED_RSV_1 958 +MC_DVFS_PIPE_SELECT 95c +MC_AHB_PTSA_MIN 4e0 +MC_AUD_PTSA_MIN 54c +MC_MLL_MPCORER_PTSA_RATE 44c +MC_RING2_PTSA_RATE 440 +MC_USBD_PTSA_RATE 530 +MC_USBX_PTSA_MIN 528 +MC_USBD_PTSA_MIN 534 +MC_APB_PTSA_MAX 4f0 +MC_JPG_PTSA_RATE 584 +MC_DIS_PTSA_MIN 420 +MC_AVP_PTSA_MAX 4fc +MC_AVP_PTSA_RATE 4f4 +MC_RING1_PTSA_MIN 480 +MC_DIS_PTSA_MAX 424 +MC_SD_PTSA_MAX 4d8 +MC_MSE_PTSA_RATE 4c4 +MC_VICPC_PTSA_MIN 558 +MC_PCX_PTSA_MAX 4b4 +MC_ISP_PTSA_RATE 4a0 +MC_A9AVPPC_PTSA_MIN 48c +MC_RING2_PTSA_MAX 448 +MC_AUD_PTSA_RATE 548 +MC_HOST_PTSA_MIN 51c +MC_MLL_MPCORER_PTSA_MAX 454 +MC_SD_PTSA_MIN 4d4 +MC_RING1_PTSA_RATE 47c +MC_JPG_PTSA_MIN 588 +MC_HDAPC_PTSA_MIN 62c +MC_AVP_PTSA_MIN 4f8 +MC_JPG_PTSA_MAX 58c +MC_VE_PTSA_MAX 43c +MC_DFD_PTSA_MAX 63c +MC_VICPC_PTSA_RATE 554 +MC_GK_PTSA_MAX 544 +MC_VICPC_PTSA_MAX 55c +MC_SDM_PTSA_MAX 624 +MC_SAX_PTSA_RATE 4b8 +MC_PCX_PTSA_MIN 4b0 +MC_APB_PTSA_MIN 4ec +MC_GK2_PTSA_MIN 614 +MC_PCX_PTSA_RATE 4ac +MC_RING1_PTSA_MAX 484 +MC_HDAPC_PTSA_RATE 628 +MC_MLL_MPCORER_PTSA_MIN 450 +MC_GK2_PTSA_MAX 618 +MC_AUD_PTSA_MAX 550 +MC_GK2_PTSA_RATE 610 +MC_ISP_PTSA_MAX 4a8 +MC_DISB_PTSA_RATE 428 +MC_VE2_PTSA_MAX 49c +MC_DFD_PTSA_MIN 638 +MC_FTOP_PTSA_RATE 50c +MC_A9AVPPC_PTSA_RATE 488 +MC_VE2_PTSA_MIN 498 +MC_USBX_PTSA_MAX 52c +MC_DIS_PTSA_RATE 41c +MC_USBD_PTSA_MAX 538 +MC_A9AVPPC_PTSA_MAX 490 +MC_USBX_PTSA_RATE 524 +MC_FTOP_PTSA_MAX 514 +MC_HDAPC_PTSA_MAX 630 +MC_SD_PTSA_RATE 4d0 +MC_DFD_PTSA_RATE 634 +MC_FTOP_PTSA_MIN 510 +MC_SDM_PTSA_RATE 61c +MC_AHB_PTSA_RATE 4dc +MC_SMMU_SMMU_PTSA_MAX 460 +MC_RING2_PTSA_MIN 444 +MC_SDM_PTSA_MIN 620 +MC_APB_PTSA_RATE 4e8 +MC_MSE_PTSA_MIN 4c8 +MC_HOST_PTSA_RATE 518 +MC_VE_PTSA_RATE 434 +MC_AHB_PTSA_MAX 4e4 +MC_SAX_PTSA_MIN 4bc +MC_SMMU_SMMU_PTSA_MIN 45c +MC_ISP_PTSA_MIN 4a4 +MC_HOST_PTSA_MAX 520 +MC_SAX_PTSA_MAX 4c0 +MC_VE_PTSA_MIN 438 +MC_GK_PTSA_MIN 540 +MC_MSE_PTSA_MAX 4cc +MC_DISB_PTSA_MAX 430 +MC_DISB_PTSA_MIN 42c +MC_SMMU_SMMU_PTSA_RATE 458 +MC_VE2_PTSA_RATE 494 +MC_GK_PTSA_RATE 53c +MC_PTSA_GRANT_DECREMENT 960 +MC_LATENCY_ALLOWANCE_AVPC_0 2e4 +MC_LATENCY_ALLOWANCE_AXIAP_0 3a0 +MC_LATENCY_ALLOWANCE_XUSB_1 380 +MC_LATENCY_ALLOWANCE_ISP2B_0 384 +MC_LATENCY_ALLOWANCE_SDMMCAA_0 3bc +MC_LATENCY_ALLOWANCE_SDMMCA_0 3b8 +MC_LATENCY_ALLOWANCE_ISP2_0 370 +MC_LATENCY_ALLOWANCE_SE_0 3e0 +MC_LATENCY_ALLOWANCE_ISP2_1 374 +MC_LATENCY_ALLOWANCE_DC_0 2e8 +MC_LATENCY_ALLOWANCE_VIC_0 394 +MC_LATENCY_ALLOWANCE_DCB_1 2f8 +MC_LATENCY_ALLOWANCE_NVDEC_0 3d8 +MC_LATENCY_ALLOWANCE_DCB_2 2fc +MC_LATENCY_ALLOWANCE_TSEC_0 390 +MC_LATENCY_ALLOWANCE_DC_2 2f0 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 694 +MC_LATENCY_ALLOWANCE_PPCS_1 348 +MC_LATENCY_ALLOWANCE_XUSB_0 37c +MC_LATENCY_ALLOWANCE_PPCS_0 344 +MC_LATENCY_ALLOWANCE_TSECB_0 3f0 +MC_LATENCY_ALLOWANCE_AFI_0 2e0 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 698 +MC_LATENCY_ALLOWANCE_DC_1 2ec +MC_LATENCY_ALLOWANCE_APE_0 3dc +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 6a0 +MC_LATENCY_ALLOWANCE_A9AVP_0 3a4 +MC_LATENCY_ALLOWANCE_GPU2_0 3e8 +MC_LATENCY_ALLOWANCE_DCB_0 2f4 +MC_LATENCY_ALLOWANCE_HC_1 314 +MC_LATENCY_ALLOWANCE_SDMMC_0 3c0 +MC_LATENCY_ALLOWANCE_NVJPG_0 3e4 +MC_LATENCY_ALLOWANCE_PTC_0 34c +MC_LATENCY_ALLOWANCE_ETR_0 3ec +MC_LATENCY_ALLOWANCE_MPCORE_0 320 +MC_LATENCY_ALLOWANCE_VI2_0 398 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 69c +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 6a4 +MC_LATENCY_ALLOWANCE_SATA_0 350 +MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 690 +MC_LATENCY_ALLOWANCE_HC_0 310 +MC_LATENCY_ALLOWANCE_DC_3 3c8 +MC_LATENCY_ALLOWANCE_GPU_0 3ac +MC_LATENCY_ALLOWANCE_SDMMCAB_0 3c4 +MC_LATENCY_ALLOWANCE_ISP2B_1 388 +MC_LATENCY_ALLOWANCE_NVENC_0 328 +MC_LATENCY_ALLOWANCE_HDA_0 318 +MC_MIN_LENGTH_APE_0 b34 +MC_MIN_LENGTH_DCB_2 8a8 +MC_MIN_LENGTH_A9AVP_0 950 +MC_MIN_LENGTH_TSEC_0 93c +MC_MIN_LENGTH_DC_1 898 +MC_MIN_LENGTH_AXIAP_0 94c +MC_MIN_LENGTH_ISP2B_0 930 +MC_MIN_LENGTH_VI2_0 944 +MC_MIN_LENGTH_DCB_0 8a0 +MC_MIN_LENGTH_DCB_1 8a4 +MC_MIN_LENGTH_PPCS_1 8f4 +MC_MIN_LENGTH_NVJPG_0 b3c +MC_MIN_LENGTH_HDA_0 8c4 +MC_MIN_LENGTH_NVENC_0 8d4 +MC_MIN_LENGTH_SDMMC_0 b18 +MC_MIN_LENGTH_ISP2B_1 934 +MC_MIN_LENGTH_HC_1 8c0 +MC_MIN_LENGTH_DC_3 b20 +MC_MIN_LENGTH_AVPC_0 890 +MC_MIN_LENGTH_VIC_0 940 +MC_MIN_LENGTH_ISP2_0 91c +MC_MIN_LENGTH_HC_0 8bc +MC_MIN_LENGTH_SE_0 b38 +MC_MIN_LENGTH_NVDEC_0 b30 +MC_MIN_LENGTH_SATA_0 8fc +MC_MIN_LENGTH_DC_0 894 +MC_MIN_LENGTH_XUSB_1 92c +MC_MIN_LENGTH_DC_2 89c +MC_MIN_LENGTH_SDMMCAA_0 b14 +MC_MIN_LENGTH_GPU_0 b04 +MC_MIN_LENGTH_ETR_0 b44 +MC_MIN_LENGTH_AFI_0 88c +MC_MIN_LENGTH_PPCS_0 8f0 +MC_MIN_LENGTH_ISP2_1 920 +MC_MIN_LENGTH_XUSB_0 928 +MC_MIN_LENGTH_MPCORE_0 8cc +MC_MIN_LENGTH_TSECB_0 b48 +MC_MIN_LENGTH_SDMMCA_0 b10 +MC_MIN_LENGTH_GPU2_0 b40 +MC_MIN_LENGTH_SDMMCAB_0 b1c +MC_MIN_LENGTH_PTC_0 8f8 +MC_EMEM_ARB_OVERRIDE_1 968 +MC_VIDEO_PROTECT_GPU_OVERRIDE_0 984 +MC_VIDEO_PROTECT_GPU_OVERRIDE_1 988 +MC_EMEM_ARB_STATS_0 990 +MC_EMEM_ARB_STATS_1 994 +MC_MTS_CARVEOUT_BOM 9a0 +MC_MTS_CARVEOUT_SIZE_MB 9a4 +MC_MTS_CARVEOUT_ADR_HI 9a8 +MC_MTS_CARVEOUT_REG_CTRL 9ac +MC_ERR_MTS_STATUS 9b0 +MC_ERR_MTS_ADR 9b4 +MC_ERR_GENERALIZED_CARVEOUT_STATUS c00 +MC_ERR_GENERALIZED_CARVEOUT_ADR c04 +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 d74 +MC_SECURITY_CARVEOUT4_CFG0 cf8 +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 d10 +MC_SECURITY_CARVEOUT4_SIZE_128KB d04 +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 c28 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 c30 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 c8c +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 d1c +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 d70 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 c2c +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 d7c +MC_SECURITY_CARVEOUT3_SIZE_128KB cb4 +MC_SECURITY_CARVEOUT2_CFG0 c58 +MC_SECURITY_CARVEOUT1_CFG0 c08 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 c84 +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 c68 +MC_SECURITY_CARVEOUT3_BOM cac +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 c70 +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 d78 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 c7c +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 d18 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 cbc +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 c38 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 c34 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 cc0 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 d60 +MC_SECURITY_CARVEOUT3_CFG0 ca8 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 cb8 +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 c88 +MC_SECURITY_CARVEOUT2_SIZE_128KB c64 +MC_SECURITY_CARVEOUT5_BOM_HI d50 +MC_SECURITY_CARVEOUT1_SIZE_128KB c14 +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 d14 +MC_SECURITY_CARVEOUT1_BOM c0c +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 d2c +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 d68 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 cc8 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 d58 +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 d24 +MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 cc4 +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 c78 +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 c1c +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 c18 +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 d28 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 d5c +MC_SECURITY_CARVEOUT3_BOM_HI cb0 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 cd8 +MC_SECURITY_CARVEOUT2_BOM_HI c60 +MC_SECURITY_CARVEOUT4_BOM_HI d00 +MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 d64 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 cdc +MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 c80 +MC_SECURITY_CARVEOUT5_SIZE_128KB d54 +MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 d20 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 cd4 +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 d0c +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 c74 +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 ccc +MC_SECURITY_CARVEOUT4_BOM cfc +MC_SECURITY_CARVEOUT5_CFG0 d48 +MC_SECURITY_CARVEOUT2_BOM c5c +MC_SECURITY_CARVEOUT5_BOM d4c +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 c24 +MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 d6c +MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 cd0 +MC_SECURITY_CARVEOUT1_BOM_HI c10 +MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 c20 +MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 c3c +MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 c6c +MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 d08 +MC_ERR_APB_ASID_UPDATE_STATUS 9d0 +MC_DA_CONFIG0 9dc