diff --git a/.gitignore b/.gitignore index 30e95f0..de2d046 100755 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,9 @@ .vscode build/* output/* +loader/payload_00.h +loader/payload_01.h +tools/bin2c/bin2c +tools/bin2c/bin2c.exe +tools/lz/lz77 +tools/lz/lz77.exe diff --git a/Makefile b/Makefile index b860e7a..be95d5c 100755 --- a/Makefile +++ b/Makefile @@ -16,21 +16,26 @@ TARGET := hekate BUILDDIR := build OUTPUTDIR := output SOURCEDIR = bootloader -VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) +BDKDIR := bdk +BDKINC := -I./$(BDKDIR) +VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) +VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) # Main and graphics. OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ - start.o \ + start.o exception_handlers.o \ main.o heap.o \ - gfx.o tui.o \ - fe_emmc_tools.o fe_info.o fe_tools.o \ + gfx.o logos.o tui.o \ + l4t.o fe_info.o fe_tools.o \ ) # Hardware. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ - bpmp.o clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \ - fuse.o kfuse.o minerva.o \ - sdmmc.o sdmmc_driver.o emummc.o nx_emmc.o \ + bpmp.o ccplex.o clock.o di.o i2c.o irq.o timer.o \ + mc.o sdram.o minerva.o \ + gpio.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \ + fuse.o kfuse.o \ + sdmmc.o sdmmc_driver.o emmc.o sd.o emummc.o \ bq24193.o max17050.o max7762x.o max77620-rtc.o \ hw_init.o \ ) @@ -43,67 +48,113 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ # Horizon. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ - hos.o hos_config.o pkg1.o pkg2.o pkg2_ini_kippatch.o fss.o secmon_exo.o sept.o \ + hos.o hos_config.o pkg1.o pkg2.o pkg3.o pkg2_ini_kippatch.o secmon_exo.o \ ) # Libraries. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ - lz.o blz.o \ + lz.o lz4.o blz.o \ diskio.o ff.o ffunicode.o ffsystem.o \ elfload.o elfreloc_arm.o \ ) +GFX_INC := '"../$(SOURCEDIR)/gfx/gfx.h"' +FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"' + ################################################################################ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC) -CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD) -CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_RESERVED=$(NYXVERSION_RSVD) -#CUSTOMDEFINES += -DMENU_LOGO_ENABLE +CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_VER_RL=$(BLVERSION_REL) +CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_VER_RL=$(NYXVERSION_REL) -# 0: UART_A, 1: UART_B. -#CUSTOMDEFINES += -DDEBUG_UART_PORT=0 +# BDK defines. +CUSTOMDEFINES += -DBDK_MALLOC_NO_DEFRAG -DBDK_MC_ENABLE_AHB_REDIRECT -DBDK_EMUMMC_ENABLE +CUSTOMDEFINES += -DBDK_WATCHDOG_FIQ_ENABLE -DBDK_RESTART_BL_ON_WDT +CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) #CUSTOMDEFINES += -DDEBUG -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) +# UART Logging: Max baudrate 12.5M. +# DEBUG_UART_PORT - 0: UART_A, 1: UART_B, 2: UART_C. +#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=1 + +#TODO: Considering reinstating some of these when pointer warnings have been fixed. +WARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow +#-fno-delete-null-pointer-checks +#-Wstack-usage=byte-size -fstack-usage + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork $(WARNINGS) +CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) MODULEDIRS := $(wildcard modules/*) NYXDIR := $(wildcard nyx) +LDRDIR := $(wildcard loader) +TOOLSLZ := $(wildcard tools/lz) +TOOLSB2C := $(wildcard tools/bin2c) +TOOLS := $(TOOLSLZ) $(TOOLSB2C) ################################################################################ -.PHONY: all clean $(MODULEDIRS) $(NYXDIR) +.PHONY: all clean $(MODULEDIRS) $(NYXDIR) $(LDRDIR) $(TOOLS) -all: $(TARGET).bin - @echo -n "Payload size is " - @wc -c < $(OUTPUTDIR)/$(TARGET).bin - @echo "Max size is 126296 Bytes." +all: $(TARGET).bin $(LDRDIR) + @printf ICTC49 >> $(OUTPUTDIR)/$(TARGET).bin + @echo "--------------------------------------" + @echo "$(TARGET) size:" + @echo -n "Uncompr: " + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET)_unc.bin)) + @echo $(BIN_SIZE)" Bytes" + @if [ ${BIN_SIZE} -gt 140288 ]; then echo "\e[1;33mUncompr size exceeds limit!\e[0m"; fi + @echo -n "Payload: " + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) + @echo $(BIN_SIZE)" Bytes" + @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi + @echo "--------------------------------------" -clean: +clean: $(TOOLS) @rm -rf $(OBJS) @rm -rf $(BUILDDIR) @rm -rf $(OUTPUTDIR) $(MODULEDIRS): - $(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) $(NYXDIR): - $(MAKE) -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) -$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR) - $(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@ - @printf ICTC49 >> $(OUTPUTDIR)/$@ +$(LDRDIR): $(TARGET).bin + @$(TOOLSLZ)/lz77 $(OUTPUTDIR)/$(TARGET).bin + @mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(TARGET)_unc.bin + @mv $(OUTPUTDIR)/$(TARGET).bin.00.lz payload_00 + @mv $(OUTPUTDIR)/$(TARGET).bin.01.lz payload_01 + @$(TOOLSB2C)/bin2c payload_00 > $(LDRDIR)/payload_00.h + @$(TOOLSB2C)/bin2c payload_01 > $(LDRDIR)/payload_01.h + @rm payload_00 + @rm payload_01 + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) PAYLOAD_NAME=$(TARGET) + +$(TOOLS): + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) + +$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR) $(TOOLS) + @$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) - $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + @printf "$(TARGET) was built with the following flags:\nCFLAGS: $(CFLAGS)\nLDFLAGS: $(LDFLAGS)\n" $(BUILDDIR)/$(TARGET)/%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ + @echo Building $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(BUILDDIR)/$(TARGET)/%.o: %.S + @echo Building $@ + @$(CC) $(CFLAGS) -c $< -o $@ + +$(OBJS): $(BUILDDIR)/$(TARGET) + +$(BUILDDIR)/$(TARGET): @mkdir -p "$(BUILDDIR)" @mkdir -p "$(BUILDDIR)/$(TARGET)" @mkdir -p "$(OUTPUTDIR)" - $(CC) $(CFLAGS) -c $< -o $@ diff --git a/README.md b/README.md index 4627cf6..6101ca1 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,38 @@ -# hekate - CTCaer mod +# hekate - Nyx ![Image of Hekate](https://user-images.githubusercontent.com/3665130/60391760-bc1e8c00-9afe-11e9-8b7a-b065873081b2.png) -Custom Nintendo Switch bootloader, firmware patcher, and more. +Custom Graphical Nintendo Switch bootloader, firmware patcher, tools, and many more. + + + +- [Features](#features) +- [Bootloader folders and files](#bootloader-folders-and-files) +- [Bootloader configuration](#bootloader-configuration) + * [hekate global Configuration keys/values](#hekate-global-configuration-keysvalues-when-entry-is-config) + * [Boot entry key/value combinations](#boot-entry-keyvalue-combinations) + * [Boot entry key/value combinations for Exosphère](#boot-entry-keyvalue-combinations-for-exosphère) + * [Payload storage](#payload-storage) + * [Nyx Configuration keys/values](#nyx-configuration-keysvalues-nyxini) + + + +## Features + +- **Fully Configurable and Graphical** with Touchscreen and Joycon input support +- **Launcher Style, Background and Color Themes** +- **HOS (Switch OS) Bootloader** -- For CFW Sys/Emu, OFW Sys and Stock Sys +- **Android & Linux Bootloader** +- **Payload Launcher** +- **eMMC/emuMMC Backup/Restore Tools** +- **SD Card Partition Manager** -- Prepares and formats SD Card for any combo of HOS (Sys/emuMMC), Android and Linux +- **emuMMC Creation & Manager** -- Can also migrate and fix existing emuMMC +- **Switch Android & Linux flasher** +- **USB Mass Storage (UMS) for SD/eMMC/emuMMC** -- Converts Switch into a SD Card Reader +- **USB Gamepad** -- Converts Switch with Joycon into a USB HID Gamepad +- **Hardware and Peripherals info** (SoC, Fuses, RAM, Display, Touch, eMMC, SD, Battery, PSU, Charger) +- **Many other tools** like Archive Bit Fixer, Touch Calibration, SD/eMMC Benchmark, AutoRCM enabler and more ## Bootloader folders and files @@ -11,28 +40,28 @@ Custom Nintendo Switch bootloader, firmware patcher, and more. | Folder/File | Description | | ------------------------ | --------------------------------------------------------------------- | | bootloader | Main folder. | -| \|__ bootlogo.bmp | It is used when custom is on and no logopath found. Can be skipped. | -| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries. | +| \|__ bootlogo.bmp | It is used if no `logopath` key is found. User provided. Can be skipped. | +| \|__ hekate_ipl.ini | Main bootloader configuration and boot entries in `Launch` menu. | +| \|__ nyx.ini | Nyx GUI configuration | | \|__ patches.ini | Add external patches. Can be skipped. A template can be found [here](./res/patches_template.ini) | -| \|__ update.bin | If newer, it is loaded at boot. For modchips. Auto updated. Can be skipped. | -| bootloader/ini/ | For individual inis. 'More configs...' menu. Autoboot is supported. | +| \|__ update.bin | If newer, it is loaded at boot. Normally for modchips. Auto updated and created at first boot. | +| bootloader/ini/ | For individual inis. `More configs` menu. Autoboot is supported. | | bootloader/res/ | Nyx user resources. Icons and more. | -| \|__ background.bmp | Nyx - custom background. | +| \|__ background.bmp | Nyx - Custom background. User provided. | | \|__ icon_switch.bmp | Nyx - Default icon for CFWs. | | \|__ icon_payload.bmp | Nyx - Default icon for Payloads. | -| \|__ icon_lakka.bmp | Nyx - Default icon for Lakka. | -| bootloader/sys/ | For system modules. | -| \|__ emummc.kipm | emuMMC KIP1 module. Important! | -| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! | -| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. Important! | -| \|__ nyx.bin | Nyx - Our GUI. Important! | -| \|__ res.pak | Nyx resources package. Important! | +| bootloader/sys/ | hekate and Nyx system modules folder. !Important! | +| \|__ emummc.kipm | emuMMC KIP1 module. | +| \|__ libsys_lp0.bso | LP0 (sleep mode) module. | +| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. | +| \|__ nyx.bin | Nyx - hekate's GUI. | +| \|__ res.pak | Nyx resources package. | +| \|__ thk.bin | Atmosphère Tsec Hovi Keygen. | +| \|__ /l4t/ | Folder with firmware relevant to L4T (Linux/Android). | | bootloader/screenshots/ | Folder where Nyx screenshots are saved | -| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. | -| bootloader/libtools/ | Future reserved | -| sept | Sept folder. This must be always get updated via the Atmosphère release zip. Needed for tools and booting HOS on 7.0.0 and up. Unused for booting HOS if `fss0=` key is defined. | +| bootloader/payloads/ | For the `Payloads` menu. All CFW bootloaders, tools, Linux payloads are supported. Autoboot only supported by including them into an ini. | +| bootloader/libtools/ | Reserved | -**Note**: Sept files for booting 7.0.0 and up are expected at /sept folder at root of sd card. ## Bootloader configuration @@ -43,85 +72,146 @@ The bootloader can be configured via 'bootloader/hekate_ipl.ini' (if it is prese There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Caption, "**#**": Comment, "*newline*": .ini cosmetic newline. -You can find a template [Here](./res/hekate_ipl_template.ini) +**You can find a template [Here](./res/hekate_ipl_template.ini)** -### Global Configuration keys/values when boot entry is **config**: +### hekate Global Configuration keys/values (when entry is *[config]*): -| Config option | Description | -| ------------------ | ---------------------------------------------------------- | -| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. | +| Config option | Description | +| ------------------ | -------------------------------------------------------------- | +| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. | | autoboot_list=0 | 0: Read `autoboot` boot entry from hekate_ipl.ini, 1: Read from ini folder (ini files are ASCII ordered). | -| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. | -| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). | +| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. Max: 20s. | +| noticker=0 | 0: Animated line is drawn during custom bootlogo, signifying time left to skip to menu. 1: Disable. | | autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.| | autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. | +| bootprotect=0 | 0: Disable, 1: Protect bootloader folder from being corrupted by disallowing reading or editing in HOS. | | updater2p=0 | 0: Disable, 1: Force updates (if needed) the reboot2payload binary to be hekate. | -| backlight=100 | Screen backlight level. 0-255. | +| backlight=100 | Screen backlight level. 0-255. | -### Possible boot entry key/value combinations: +### Boot entry key/value combinations: | Config option | Description | | ---------------------- | ---------------------------------------------------------- | -| warmboot={SD path} | Replaces the warmboot binary | -| secmon={SD path} | Replaces the security monitor binary | -| kernel={SD path} | Replaces the kernel binary | -| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. | -| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. | -| fss0={SD path} | Takes a fusee-secondary binary and `extracts` all needed parts from it. kips, exosphere, warmboot and sept. | -| kip1patch=patchname | Enables a kip1 patch. Specify with multiple lines and/or as CSV. If not found, an error will show up | -| fullsvcperm=1 | Disables SVC verification (full services permission) | +| warmboot={FILE path} | Replaces the warmboot binary | +| secmon={FILE path} | Replaces the security monitor binary | +| kernel={FILE path} | Replaces the kernel binary | +| kip1={FILE path} | Replaces/Adds kernel initial process. Multiple can be set. | +| kip1={FOLDER path}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. | +| pkg3={FILE path} | Takes an Atmosphere `package3` binary and `extracts` all needed parts from it. kips, exosphere, warmboot and mesophere. | +| fss0={FILE path} | Same as above. !Deprecated! | +| pkg3ex=1 | Enables loading of experimental content from a PKG3/FSS0 storage | +| pkg3kip1skip={KIP name} | Skips loading a kip from `pkg3`/`fss0`. Allows multiple and `,` as separator. The name must exactly match the name in `PKG3`. | +| exofatal={FILE path} | Replaces the exosphere fatal binary for Mariko | +| ---------------------- | ---------------------------------------------------------- | +| kip1patch=patchname | Enables a kip1 patch. Allows multiple and `,` as separator. If actual patch is not found, a warning will show up. | +| emupath={FOLDER path} | Forces emuMMC to use the selected one. (=emuMMC/RAW1, =emuMMC/SD00, etc). emuMMC must be created by hekate because it uses the raw_based/file_based files. | +| emummcforce=1 | Forces the use of emuMMC. If emummc.ini is disabled or not found, then it causes an error. | +| emummc_force_disable=1 | Disables emuMMC, if it's enabled. | +| stock=1 | OFW via hekate bootloader. Disables unneeded kernel patching and CFW kips when running stock. `If emuMMC is enabled, emummc_force_disable=1` is required. emuMMC is not supported on stock. If additional KIPs are needed other than OFW's, you can define them with `kip1` key. No kip should be used that relies on Atmosphère patching, because it will hang. If `NOGC` is needed, use `kip1patch=nogc`. | +| fullsvcperm=1 | Disables SVC verification (full services permission). Doesn't work with Mesosphere as kernel. | | debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. | -| atmosphere=1 | Enables Atmosphère patching. | -| nouserexceptions=1 | Disables usermode exception handlers when paired with Exosphère. | -| userpmu=1 | Allows user access to PMU when paired with Exosphère. | -| emummc_force_disable=1 | Disabled emuMMC if it's enabled. | -| stock=1 | Disables unneeded kernel patching when running stock or semi-stock. `If emuMMC is enabled, emummc_force_disabled=1` is required to run completely stock. | -| id=idname | Identifies boot entry for forced boot via id. Max 7 chars. | -| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. | -| logopath={SD path} | If no logopath, `bootloader/bootlogo.bmp` will be used if exists. If logopath exists, it will load the specified bitmap. | -| icon={SD path} | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise default will be used. | +| kernelprocid=1 | Enables stock kernel process id send/recv patching. Not needed when `pkg3`/`fss0` is used. | +| ---------------------- | ---------------------------------------------------------- | +| payload={FILE path} | Payload launching. Tools, Android/Linux, CFW bootloaders, etc. Any key above when used with that, doesn't get into account. | +| ---------------------- | ---------------------------------------------------------- | +| l4t=1 | L4T Linux/Android native launching. | +| boot_prefixes={FOLDER path} | L4T bootstack directory. | +| ram_oc=0 | L4T RAM Overclocking. Check README_CONFIG.txt for more info. | +| ram_oc_vdd2=1100 | L4T RAM VDD2 Voltage. Set VDD2 (T210B01) or VDD2/VDDQ (T210) voltage. 1050-1175. | +| ram_oc_vddq=600 | L4T RAM VDDQ Voltage. Set VDDQ (T210B01). 550-650. | +| uart_port=0 | Enables logging on serial port for L4T uboot/kernel. | +| sld_type=0x31444C53 | Controls the type of seamless display support. 0x0: Disable, 0x31444C53: L4T seamless display. | +| Additional keys | Each distro supports more keys. Check README_CONFIG.txt for more info. | +| ---------------------- | ---------------------------------------------------------- | +| bootwait=3 | Overrides global bootwait from `[config]`. | +| id=IDNAME | Identifies boot entry for forced boot via id. Max 7 chars. | +| logopath={FILE path} | If it exists, it will load the specified bitmap. Otherwise `bootloader/bootlogo.bmp` will be used if exists | +| icon={FILE path} | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise defaults will be used. | + **Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra single kips. -**Note2**: When using FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `fss0`. +**Note2**: When using PKG3/FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `pkg3`/`fss0`. You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage. -**Warning**: Never define *fss0 core* kips when using `fss0` and make sure that the folder (when using `/*`), does not include them. -This is in case the kips are incompatible between them. If compatible, you can override `fss0` kips with no issues (useful for testing with intermediate kip changes). +**Warning**: Careful when you override *pkg3/fss core* kips with `kip1`. +That's in case the kips are incompatible between them. If compatible, you can override `pkg3`/`fss0` kips with no issues (useful for testing with intermediate kip changes). In such cases, the `kip1` line must be **after** `pkg3`/`fss0` line. + + +### Boot entry key/value combinations for Exosphère: + +| Config option | Description | +| ---------------------- | ---------------------------------------------------------- | +| nouserexceptions=1 | Disables usermode exception handlers when paired with Exosphère. | +| userpmu=1 | Enables user access to PMU when paired with Exosphère. | +| cal0blank=1 | Overrides Exosphère config `blank_prodinfo_{sys/emu}mmc`. If that key doesn't exist, `exosphere.ini` will be used. | +| cal0writesys=1 | Overrides Exosphère config `allow_writing_to_cal_sysmmc`. If that key doesn't exist, `exosphere.ini` will be used. | +| usb3force=1 | Overrides system settings mitm config `usb30_force_enabled`. If that key doesn't exist, `system_settings.ini` will be used. | + + +**Note**: `cal0blank`, `cal0writesys`, `usb3force`, as stated override the `exosphere.ini` or `system_settings.ini`. 0: Disable, 1: Enable, Key Missing: Use original value. + + +**Note2**: `blank_prodinfo_{sys/emu}mmc`, `allow_writing_to_cal_sysmmc` and `usb30_force_enabled` in `exosphere.ini` and `system_settings.ini` respectively, are the only atmosphere config keys that can affect hekate booting configuration externally, **if** the equivalent keys in hekate config are missing. ### Payload storage: -hekate has a boot storage in the binary that helps it configure it outside of BPMP enviroment: +hekate has a boot storage in the binary that helps it configure it outside of BPMP environment: -| Offset / Name | Description | -| -------------------- | ----------------------------------------------------------------- | -| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: Boot from ID, bit7: sept run. | -| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. | -| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. | -| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2`. | -| '0x98' id[8] | When Boot from ID is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. | -| '0x98' xt_str[128] | Depends on the set cfg bits. | +| Offset / Name | Description | +| ----------------------- | ----------------------------------------------------------------- | +| '0x94' boot_cfg | bit0: `Force AutoBoot`, bit1: `Show launch log`, bit2: `Boot from ID`, bit3: `Boot to emuMMC`. | +| '0x95' autoboot | If `Force AutoBoot`, 0: Force go to menu, else boot that entry. | +| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. | +| '0x97' extra_cfg | When menu is forced: bit5: `Run UMS`. | +| '0x98' xt_str[128] | Depends on the set cfg bits. | +| '0x98' ums[1] | When `Run UMS` is set, it will launch the selected UMS. 0: SD, 1: eMMC BOOT0, 2: eMMC BOOT1, 3: eMMC GPP, 4: emuMMC BOOT0, 5: emuMMC BOOT1, 6: emuMMC GPP, | +| '0x98' id[8] | When `Boot from ID` is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. | +| '0xA0' emummc_path[120] | When `Boot to emuMMC` is set, it will override the current emuMMC (boot entry or emummc.ini). Must be NULL terminated. | -If the main .ini is not found, it is created on the first hekate boot. +### Nyx Configuration keys/values (nyx.ini): + +| Config option | Description | +| ------------------ | ---------------------------------------------------------- | +| themebg=2d2d2d | Sets Nyx background color in HEX. EXPERIMENTAL. | +| themecolor=167 | Sets Nyx color of text highlights. | +| entries5col=0 | 1: Sets Launch entry columns from 4 to 5 per line. For a total of 10 entries. | +| timeoff=100 | Sets time offset in HEX. Must be in HOS epoch format | +| homescreen=0 | Sets home screen. 0: Home menu, 1: All configs (merges Launch and More configs), 2: Launch, 3: More Configs. | +| verification=1 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and mostly reliable), 2: Full (sha256 based, slow and 100% reliable). | +| ------------------ | ------- The following options can only be edited in nyx.ini ------- | +| umsemmcrw=0 | 1: eMMC/emuMMC UMS will be mounted as writable by default. | +| jcdisable=0 | 1: Disables Joycon driver completely. | +| jcforceright=0 | 1: Forces right joycon to be used as main mouse control. | +| bpmpclock=1 | 0: Auto, 1: Fastest, 2: Faster, 3: Fast. Use 2 or 3 if Nyx hangs or some functions like UMS/Backup Verification fail. | ``` -hekate (C) 2018 naehrwert, st4rk -CTCaer mod (C) 2018 CTCaer. +hekate (c) 2018, naehrwert, st4rk. + (c) 2018-2025, CTCaer. + +Nyx GUI (c) 2019-2025, CTCaer. Thanks to: derrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8. Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute. Open source and free packages used: - - FatFs R0.13a, Copyright (C) 2017, ChaN - - bcl-1.2.0, Copyright (C) 2003-2006, Marcus Geelnard - - Atmosphère (Exosphere types/panic, prc id kernel patches), - Copyright (C) 2018-2019, Atmosphère-NX - - elfload, Copyright (C) 2014 Owen Shepherd, Copyright (C) 2018 M4xw + - Littlev Graphics Library, + Copyright (c) 2016-2018 Gabor Kiss-Vamosi + - FatFs R0.13c, + Copyright (c) 2006-2018, ChaN + Copyright (c) 2018-2022, CTCaer + - bcl-1.2.0, + Copyright (c) 2003-2006, Marcus Geelnard + - blz, + Copyright (c) 2018, SciresM + - elfload, + Copyright (c) 2014 Owen Shepherd, + Copyright (c) 2018 M4xw ___ .-' `'. diff --git a/README_BOOTLOGO.md b/README_BOOTLOGO.md index 40d81f8..0a2b2bc 100644 --- a/README_BOOTLOGO.md +++ b/README_BOOTLOGO.md @@ -4,13 +4,16 @@ The bootlogo can be any size with a maximum of 720 x 1280. When it's smaller than 720 x 1280, it is automatically centered and the background takes the color of the first pixel. -When saving a landscape bootlogo, it should be rotated 90 degrees counterclockwise. +The process is to create a landscape bootlogo and then rotate it 90 degrees counterclockwise. Lastly, the supported format is 32-bit (ARGB) BMP. Classic 24-bit (RGB) BMPs are not supported for performance reasons. ## How to configure -If the custom logo option is enabled, it will try to load /bootlogo.bmp. If this is not found, the default hekate's logo will be used. +If a boot entry specifies a custom logo path (`logopath=`), this one will be loaded. -If a boot entry specifies a custom logo path, this is one will be loaded. Again if this is not found, bootlogo.bmp will be loaded and if that fails, hekate's built-in will be used. \ No newline at end of file +If the above is not found or the format is not correct, it will try to load `bootloader/bootlogo.bmp`. +If this is not found, the default hekate logo will be used. + +(`bootloader/bootlogo.bmp` is basically like a global bootlogo.) diff --git a/Versions.inc b/Versions.inc index 0d3805f..c2278c1 100644 --- a/Versions.inc +++ b/Versions.inc @@ -1,11 +1,11 @@ # IPL Version. -BLVERSION_MAJOR := 5 -BLVERSION_MINOR := 1 -BLVERSION_HOTFX := 2 -BLVERSION_RSVD := 0 +BLVERSION_MAJOR := 6 +BLVERSION_MINOR := 3 +BLVERSION_HOTFX := 1 +BLVERSION_REL := 0 # Nyx Version. -NYXVERSION_MAJOR := 0 -NYXVERSION_MINOR := 8 -NYXVERSION_HOTFX := 5 -NYXVERSION_RSVD := 0 +NYXVERSION_MAJOR := 1 +NYXVERSION_MINOR := 7 +NYXVERSION_HOTFX := 0 +NYXVERSION_REL := 0 diff --git a/bdk/bdk.h b/bdk/bdk.h new file mode 100644 index 0000000..1d8a05e --- /dev/null +++ b/bdk/bdk.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 CTCaer + * + * 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 BDK_H +#define BDK_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#endif diff --git a/bdk/display/di.c b/bdk/display/di.c new file mode 100644 index 0000000..3eaf922 --- /dev/null +++ b/bdk/display/di.c @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 "di.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "di.inl" + +extern volatile nyx_storage_t *nyx_str; + +static u32 _display_id = 0; +static u32 _dsi_bl = -1; +static bool _nx_aula = false; + +static void _display_panel_and_hw_end(bool no_panel_deinit); + +void display_enable_interrupt(u32 intr) +{ + DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) |= intr; +} + +void display_disable_interrupt(u32 intr) +{ + DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) &= ~intr; + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = intr; +} + +void display_wait_interrupt(u32 intr) +{ + DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = intr; + + // Interrupts are masked. Poll status register for checking if fired. + while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & intr)) + ; +} + +static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) +{ + u32 end = get_tmr_us() + timeout; + while (get_tmr_us() < end && DSI(off) & mask) + ; + usleep(5); +} + +static void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait) +{ + DSI(_DSIREG(DSI_WR_DATA)) = (param << 8) | cmd; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + + if (wait) + usleep(wait); +} + +static void _display_dsi_wait_vblank(bool enable) +{ + if (enable) + { + // Enable vblank interrupt. + display_enable_interrupt(DC_CMD_INT_FRAME_END_INT); + + // Use the 4th line to transmit the host cmd packet. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE | DSI_DSI_LINE_TYPE(4); + + // Wait for vblank before starting the transfer. + display_wait_interrupt(DC_CMD_INT_FRAME_END_INT); + } + else + { + // Wait for vblank before resetting sync points. + display_wait_interrupt(DC_CMD_INT_FRAME_END_INT); + usleep(14); + + // Reset all states of syncpt block. + DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = DSI_INCR_SYNCPT_SOFT_RESET; + usleep(300); // Stabilization delay. + + // Clear syncpt block reset. + DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = 0; + usleep(300); // Stabilization delay. + + // Restore video mode and host control. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + + // Disable and clear vblank interrupt. + display_disable_interrupt(DC_CMD_INT_FRAME_END_INT); + } +} + +static void _display_dsi_read_rx_fifo(u32 *data) +{ + u32 fifo_count = DSI(_DSIREG(DSI_STATUS)) & DSI_STATUS_RX_FIFO_SIZE; + if (fifo_count) + DSI(_DSIREG(DSI_TRIGGER)) = 0; + + for (u32 i = 0; i < fifo_count; i++) + { + // Read or Drain RX FIFO. + if (data) + data[i] = DSI(_DSIREG(DSI_RD_DATA)); + else + (void)DSI(_DSIREG(DSI_RD_DATA)); + } +} + +int display_dsi_read(u8 cmd, u32 len, void *data) +{ + int res = 0; + u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0}; + + // Drain RX FIFO. + _display_dsi_read_rx_fifo(NULL); + + // Set reply size. + _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); + _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + // Request register read. + _display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0); + _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + // Transfer bus control to device for transmitting the reply. + DSI(_DSIREG(DSI_HOST_CONTROL)) |= DSI_HOST_CONTROL_IMM_BTA; + + // Wait for reply to complete. DSI_HOST_CONTROL_IMM_BTA bit acts as a DSI host read busy. + _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); + + // Wait a bit for the reply. + usleep(5000); + + // Read RX FIFO. + _display_dsi_read_rx_fifo(fifo); + + // Parse packet and copy over the data. + if ((fifo[0] & 0xFF) == DSI_ESCAPE_CMD) + { + // Act based on reply type. + switch (fifo[1] & 0xFF) + { + case GEN_LONG_RD_RES: + case DCS_LONG_RD_RES: + memcpy(data, &fifo[2], MIN((fifo[1] >> 8) & 0xFFFF, len)); + break; + + case GEN_1_BYTE_SHORT_RD_RES: + case DCS_1_BYTE_SHORT_RD_RES: + memcpy(data, &fifo[2], 1); + break; + + case GEN_2_BYTE_SHORT_RD_RES: + case DCS_2_BYTE_SHORT_RD_RES: + memcpy(data, &fifo[2], 2); + break; + + case ACK_ERROR_RES: + default: + res = 1; + break; + } + } + else + res = 1; + + return res; +} + +int display_dsi_vblank_read(u8 cmd, u32 len, void *data) +{ + int res = 0; + u32 host_control = 0; + u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0}; + + // Drain RX FIFO. + _display_dsi_read_rx_fifo(NULL); + + // Save host control and enable host cmd packets during video. + host_control = DSI(_DSIREG(DSI_HOST_CONTROL)); + + _display_dsi_wait_vblank(true); + + // Set reply size. + _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); + _display_dsi_wait(0, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + // Request register read. + _display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0); + _display_dsi_wait(0, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + _display_dsi_wait_vblank(false); + + // Transfer bus control to device for transmitting the reply. + DSI(_DSIREG(DSI_HOST_CONTROL)) |= DSI_HOST_CONTROL_IMM_BTA; + + // Wait for reply to complete. DSI_HOST_CONTROL_IMM_BTA bit acts as a DSI host read busy. + _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); + + // Wait a bit for the reply. + usleep(5000); + + // Read RX FIFO. + _display_dsi_read_rx_fifo(fifo); + + // Parse packet and copy over the data. + if ((fifo[0] & 0xFF) == DSI_ESCAPE_CMD) + { + // Act based on reply type. + switch (fifo[1] & 0xFF) + { + case GEN_LONG_RD_RES: + case DCS_LONG_RD_RES: + memcpy(data, &fifo[2], MIN((fifo[1] >> 8) & 0xFFFF, len)); + break; + + case GEN_1_BYTE_SHORT_RD_RES: + case DCS_1_BYTE_SHORT_RD_RES: + memcpy(data, &fifo[2], 1); + break; + + case GEN_2_BYTE_SHORT_RD_RES: + case DCS_2_BYTE_SHORT_RD_RES: + memcpy(data, &fifo[2], 2); + break; + + case ACK_ERROR_RES: + default: + res = 1; + break; + } + } + else + res = 1; + + // Restore host control. + DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control; + + return res; +} + +void display_dsi_write(u8 cmd, u32 len, void *data) +{ + u32 host_control; + u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0}; + u8 *fifo8 = (u8 *)fifo32; + + // Prepare data for long write. + if (len >= 2) + { + memcpy(&fifo8[5], data, len); + memset(&fifo8[5] + len, 0, len % sizeof(u32)); + len++; // Increase length by CMD. + } + + // Save host control. + host_control = DSI(_DSIREG(DSI_HOST_CONTROL)); + + // Enable host transfer trigger. + DSI(_DSIREG(DSI_HOST_CONTROL)) = (host_control & ~(DSI_HOST_CONTROL_TX_TRIG_MASK)) | DSI_HOST_CONTROL_TX_TRIG_HOST; + + switch (len) + { + case 0: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, cmd, 0); + break; + + case 1: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd | (*(u8 *)data << 8), 0); + break; + + default: + fifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE; + fifo8[4] = cmd; + len += sizeof(u32); // Increase length by length word and DCS CMD. + for (u32 i = 0; i < (ALIGN(len, sizeof(u32)) / sizeof(u32)); i++) + DSI(_DSIREG(DSI_WR_DATA)) = fifo32[i]; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + break; + } + + // Wait for the write to happen. + _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST); + + // Restore host control. + DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control; +} + +void display_dsi_vblank_write(u8 cmd, u32 len, void *data) +{ + u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0}; + u8 *fifo8 = (u8 *)fifo32; + + // Prepare data for long write. + if (len >= 2) + { + memcpy(&fifo8[5], data, len); + memset(&fifo8[5] + len, 0, len % sizeof(u32)); + len++; // Increase length by CMD. + } + + _display_dsi_wait_vblank(true); + + switch (len) + { + case 0: + DSI(_DSIREG(DSI_WR_DATA)) = (cmd << 8) | MIPI_DSI_DCS_SHORT_WRITE; + break; + + case 1: + DSI(_DSIREG(DSI_WR_DATA)) = ((cmd | (*(u8 *)data << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + + default: + fifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE; + fifo8[4] = cmd; + len += sizeof(u32); // Increase length by length word and DCS CMD. + for (u32 i = 0; i < (ALIGN(len, sizeof(u32)) / sizeof(u32)); i++) + DSI(_DSIREG(DSI_WR_DATA)) = fifo32[i]; + break; + } + + _display_dsi_wait_vblank(false); +} + +void display_init() +{ + // Get Hardware type, as it's used in various DI functions. + _nx_aula = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA; + + // Check if display is already initialized. + if (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_DISP1)) + _display_panel_and_hw_end(true); + + // Get Chip ID. + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + + // Enable DSI AVDD. + max7762x_regulator_set_voltage(REGULATOR_LDO0, 1200000); + max7762x_regulator_enable(REGULATOR_LDO0, true); + + // Enable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_DISP1); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_DISP1); + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_UART_FST_MIPI_CAL); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = CLK_SRC_DIV(6); // Set PLLP_OUT3 and div 6 (68MHz). + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_DSIA_LP); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = CLK_SRC_DIV(6); // Set PLLP_OUT and div 6 (68MHz). + + // Bring every IO rail out of deep power down. + PMC(APBDEV_PMC_IO_DPD_REQ) = PMC_IO_DPD_REQ_DPD_OFF; + PMC(APBDEV_PMC_IO_DPD2_REQ) = PMC_IO_DPD_REQ_DPD_OFF; + + // Configure LCD/BL pins. + if (!_nx_aula) + { + // Configure LCD pins. + PINMUX_AUX(PINMUX_AUX_NFC_EN) = PINMUX_PULL_DOWN; + PINMUX_AUX(PINMUX_AUX_NFC_INT) = PINMUX_PULL_DOWN; + + // Configure Backlight pins. + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = PINMUX_PULL_DOWN; + PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) = PINMUX_PULL_DOWN; + + // Enable LCD AVDD. + gpio_direction_output(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_HIGH); + usleep(10000); // Wait minimum 4.2ms to stabilize. + + // Configure Backlight PWM/EN pins (BL PWM, BL EN). + gpio_direction_output(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1, GPIO_LOW); + + // Enable Backlight power. + gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); + } + + // Configure LCD RST pin. + PINMUX_AUX(PINMUX_AUX_LCD_RST) = PINMUX_PULL_DOWN; + gpio_direction_output(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); + + // Power up supply regulator for display interface. + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0; + + if (!tegra_t210) + { + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG0)) = 0; + APB_MISC(APB_MISC_GP_DSI_PAD_CONTROL) = 0; + } + + // Set DISP1 clock source, parent clock and DSI/PCLK to low power mode. + // T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-PCLK): 50.0 MHz. (PCLK: 16.66 MHz) + // T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 97.8 MHz, PLLD_OUT0 (DSI-PCLK): 48.9 MHz. (PCLK: 16.30 MHz) + clock_enable_plld(3, 20, true, tegra_t210); + + // Setup Display Interface initial window configuration. + reg_write_array((u32 *)DISPLAY_A_BASE, _di_dc_setup_win_config, ARRAY_SIZE(_di_dc_setup_win_config)); + + // Setup dsi init sequence packets. + reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config0, ARRAY_SIZE(_di_dsi_seq_pkt_reset_config0)); + DSI(_DSIREG(tegra_t210 ? DSI_INIT_SEQ_DATA_15 : DSI_INIT_SEQ_DATA_15_B01)) = 0; + reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config1, ARRAY_SIZE(_di_dsi_seq_pkt_reset_config1)); + + // Reset pad trimmers for T210B01. + if (!tegra_t210) + reg_write_array((u32 *)DSI_BASE, _di_dsi_init_pads_t210b01, ARRAY_SIZE(_di_dsi_init_pads_t210b01)); + + // Setup init seq packet lengths, timings and power on DSI. + reg_write_array((u32 *)DSI_BASE, _di_dsi_init_config, ARRAY_SIZE(_di_dsi_init_config)); + usleep(10000); + + // Enable LCD Reset. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); + usleep(60000); + + // Setup DSI device takeover timeout. + DSI(_DSIREG(DSI_BTA_TIMING)) = _nx_aula ? 0x40103 : 0x50204; + + // Get Display ID. + _display_id = 0xCCCCCC; + for (u32 i = 0; i < 3; i++) + { + if (!display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id)) + break; + + usleep(10000); + } + + // Save raw Display ID to Nyx storage. + nyx_str->info.disp_id = _display_id; + + // Decode Display ID. + _display_id = ((_display_id >> 8) & 0xFF00) | (_display_id & 0xFF); + + if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) + _display_id = PANEL_JDI_XXX062M; + + // For Aula ensure that we have a compatible panel id. + if (_nx_aula && _display_id == 0xCCCC) + _display_id = PANEL_SAM_AMS699VC01; + + // Initialize display panel. + switch (_display_id) + { + case PANEL_SAM_AMS699VC01: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + // Set color mode to basic (natural). Stock is Saturated (0x00). (Reset value is 0x20). + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, + MIPI_DCS_PRIV_SM_SET_COLOR_MODE | (DCS_SM_COLOR_MODE_BASIC << 8), 0); + // Enable backlight and smooth PWM. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, + MIPI_DCS_SET_CONTROL_DISPLAY | ((DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL | DCS_CONTROL_DISPLAY_DIMMING_CTRL) << 8), 0); + + // Unlock Level 2 registers. + DSI(_DSIREG(DSI_WR_DATA)) = 0x539; // MIPI_DSI_DCS_LONG_WRITE: 5 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x5A5A5AE2; // MIPI_DCS_PRIV_SM_SET_REGS_LOCK: Unlock Level 2 registers. + DSI(_DSIREG(DSI_WR_DATA)) = 0x5A; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + + // Set registers offset and set PWM transition to 6 frames (100ms). + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DCS_PRIV_SM_SET_REG_OFFSET | (7 << 8), 0); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DCS_PRIV_SM_SET_ELVSS | (6 << 8), 0); + + // Relock Level 2 registers. + DSI(_DSIREG(DSI_WR_DATA)) = 0x539; // MIPI_DSI_DCS_LONG_WRITE: 5 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0xA55A5AE2; // MIPI_DCS_PRIV_SM_SET_REGS_LOCK: Lock Level 2 registers. + DSI(_DSIREG(DSI_WR_DATA)) = 0xA5; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + + // Set backlight to 0%. + DSI(_DSIREG(DSI_WR_DATA)) = 0x339; // MIPI_DSI_DCS_LONG_WRITE: 3 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x000051; // MIPI_DCS_SET_BRIGHTNESS 0000: 0%. FF07: 100%. + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + _dsi_bl = 0; + break; + + case PANEL_JDI_XXX062M: + reg_write_array((u32 *)DSI_BASE, _di_dsi_panel_init_config_jdi, ARRAY_SIZE(_di_dsi_panel_init_config_jdi)); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + break; + + case PANEL_INL_P062CCA_AZ1: + case PANEL_AUO_A062TAN01: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + + // Unlock extension cmds. + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + + // Set Power control. + DSI(_DSIREG(DSI_WR_DATA)) = 0x739; // MIPI_DSI_DCS_LONG_WRITE: 7 bytes. + if (_display_id == PANEL_INL_P062CCA_AZ1) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else // PANEL_AUO_A062TAN01. + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + DSI(_DSIREG(DSI_WR_DATA)) = 0x143209; // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + + case PANEL_INL_2J055IA_27A: + case PANEL_AUO_A055TAN01: + case PANEL_SHP_LQ055T1SW10: + default: // Allow spare part displays to work. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 120000); + break; + } + + // Unblank display. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); + + // Setup final dsi clock. + // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 468.0 MHz, PLLD_OUT0 (DSI): 234.0 MHz. + clock_enable_plld(1, 24, false, tegra_t210); + + // Finalize DSI init packet sequence configuration. + reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_video_non_burst_no_eot_config, ARRAY_SIZE(_di_dsi_seq_pkt_video_non_burst_no_eot_config)); + + // Set 1-by-1 pixel/clock and pixel clock to 234 / 3 = 78 MHz. For 60 Hz refresh rate. + DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4); // 4: div3. + + // Set DSI mode to HOST. + reg_write_array((u32 *)DSI_BASE, _di_dsi_host_mode_config, ARRAY_SIZE(_di_dsi_host_mode_config)); + usleep(10000); + + /* + * Calibrate display communication pads. + * When switching to the 16ff pad brick, the clock lane termination control + * is separated from data lane termination. This change of the mipi cal + * brings in a bug that the DSI pad clock termination code can't be loaded + * in one time calibration on T210B01. Trigger calibration twice. + */ + reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, ARRAY_SIZE(_di_mipi_pad_cal_config)); + for (u32 i = 0; i < 2; i++) + { + // Set MIPI bias pad config. + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0x10010; + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG1)) = tegra_t210 ? 0x300 : 0; + + // Set pad trimmers and set MIPI DSI cal offsets. + if (tegra_t210) + { + reg_write_array((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210, ARRAY_SIZE(_di_dsi_pad_cal_config_t210)); + reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210, ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210)); + } + else + { + reg_write_array((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210b01, ARRAY_SIZE(_di_dsi_pad_cal_config_t210b01)); + reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210b01, ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210b01)); + } + + // Reset all unused MIPI cal offsets. + reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_unused_config, ARRAY_SIZE(_di_mipi_dsi_cal_unused_config)); + + // Set Prescale/filter and start calibration. + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_CAL_CTRL)) = 0x2A000001; + } + usleep(10000); + + // Enable video display controller. + reg_write_array((u32 *)DISPLAY_A_BASE, _di_dc_video_enable_config, ARRAY_SIZE(_di_dc_video_enable_config)); +} + +void display_backlight_pwm_init() +{ + if (_display_id == PANEL_SAM_AMS699VC01) + return; + + // Enable PWM clock. + clock_enable_pwm(); + + // Enable PWM and set it to 25KHz PFM. 29.5KHz is stock. + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; + + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode. + usleep(2); + + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. +} + +void display_backlight(bool enable) +{ + // Backlight PWM GPIO. + gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); +} + +static void _display_dsi_backlight_brightness(u32 duty) +{ + if (_dsi_bl == duty) + return; + + // Convert duty to candela. + u32 candela = duty * PANEL_SM_BL_CANDELA_MAX / 255; + + u16 bl_ctrl = byte_swap_16((u16)candela); + display_dsi_vblank_write(MIPI_DCS_SET_BRIGHTNESS, 2, &bl_ctrl); + + // Wait for backlight to completely turn off. 6 frames. + if (!duty) + usleep(100000); + + _dsi_bl = duty; +} + +static void _display_pwm_backlight_brightness(u32 duty, u32 step_delay) +{ + u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF; + if (duty == old_value) + return; + + if (old_value < duty) + { + for (u32 i = old_value; i < duty + 1; i++) + { + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); + usleep(step_delay); + } + } + else + { + for (u32 i = old_value; i > duty; i--) + { + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); + usleep(step_delay); + } + } + if (!duty) + PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; +} + +void display_backlight_brightness(u32 brightness, u32 step_delay) +{ + if (brightness > 255) + brightness = 255; + + if (_display_id != PANEL_SAM_AMS699VC01) + _display_pwm_backlight_brightness(brightness, step_delay); + else + _display_dsi_backlight_brightness(brightness); +} + +u32 display_get_backlight_brightness() +{ + if (_display_id != PANEL_SAM_AMS699VC01) + return ((PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF); + else + return _dsi_bl; +} + +static void _display_panel_and_hw_end(bool no_panel_deinit) +{ + if (no_panel_deinit) + goto skip_panel_deinit; + + display_backlight_brightness(0, 1000); + + // Enable host cmd packets during video. + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE; + + // Blank display. + DSI(_DSIREG(DSI_WR_DATA)) = (MIPI_DCS_SET_DISPLAY_OFF << 8) | MIPI_DSI_DCS_SHORT_WRITE; + + // Wait for 5 frames (HOST1X_CH0_SYNC_SYNCPT_9). + // Not here. Wait for 1 frame manually. + usleep(20000); + + // Propagate changes to all register buffers and disable host cmd packets during video. + DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX_ACTIVE | WRITE_MUX_ACTIVE; + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + + // De-initialize video controller. + reg_write_array((u32 *)DISPLAY_A_BASE, _di_dc_video_disable_config, ARRAY_SIZE(_di_dc_video_disable_config)); + + // Set DISP1 clock source, parent clock and DSI/PCLK to low power mode. + // T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-PCLK): 50.0 MHz. (PCLK: 16.66 MHz) + // T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 97.8 MHz, PLLD_OUT0 (DSI-PCLK): 48.9 MHz. (PCLK: 16.30 MHz) + clock_enable_plld(3, 20, true, hw_get_chip_id() == GP_HIDREV_MAJOR_T210); + + // Set timings for lowpower clocks. + reg_write_array((u32 *)DSI_BASE, _di_dsi_timing_deinit_config, ARRAY_SIZE(_di_dsi_timing_deinit_config)); + + if (_display_id != PANEL_SAM_AMS699VC01) + usleep(10000); + + // De-initialize display panel. + switch (_display_id) + { + case PANEL_JDI_XXX062M: + reg_write_array((u32 *)DSI_BASE, _di_dsi_panel_deinit_config_jdi, ARRAY_SIZE(_di_dsi_panel_deinit_config_jdi)); + break; + + case PANEL_AUO_A062TAN01: + reg_write_array((u32 *)DSI_BASE, _di_dsi_panel_deinit_config_auo, ARRAY_SIZE(_di_dsi_panel_deinit_config_auo)); + usleep(5000); + break; + + case PANEL_INL_2J055IA_27A: + case PANEL_AUO_A055TAN01: + case PANEL_SHP_LQ055T1SW10: + // Unlock extension cmds. + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + + // Set Power control. + DSI(_DSIREG(DSI_WR_DATA)) = 0xB39; // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + if (_display_id == PANEL_INL_2J055IA_27A) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else if (_display_id == PANEL_AUO_A055TAN01) + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + else // PANEL_SHP_LQ055T1SW10. + DSI(_DSIREG(DSI_WR_DATA)) = 0x731348B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT3 / XDK, VRH gamma volt adj 51 / x40). + if (_display_id == PANEL_INL_2J055IA_27A || _display_id == PANEL_AUO_A055TAN01) + { + // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + DSI(_DSIREG(DSI_WR_DATA)) = 0x71143209; + DSI(_DSIREG(DSI_WR_DATA)) = 0x114D31; // (Unknown). + } + else // PANEL_SHP_LQ055T1SW10. + { + // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/48, Enter standby / PON / VCOMG). + DSI(_DSIREG(DSI_WR_DATA)) = 0x71243209; + DSI(_DSIREG(DSI_WR_DATA)) = 0x004C31; // (Unknown). + } + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + + case PANEL_INL_P062CCA_AZ1: + case PANEL_SAM_AMS699VC01: + default: + break; + } + + // Blank - powerdown. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, + (_display_id == PANEL_SAM_AMS699VC01) ? 120000 : 50000); + +skip_panel_deinit: + // Disable LCD power pins. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); // LCD Reset disable. + usleep(10000); + + if (!_nx_aula) // HOS uses panel id. + { + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); // LCD AVDD -5.4V disable. + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); // LCD AVDD +5.4V disable. + + // Make sure LCD PWM backlight pin is in PWM0 mode. + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = PINMUX_TRISTATE | PINMUX_PULL_DOWN | 1; // Set PWM0 mode. + } + usleep(10000); + + // Disable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_DISP1); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_DISP1); + + // Power down pads. + DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | + DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); + DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; + + // Disable DSI AVDD. + max7762x_regulator_enable(REGULATOR_LDO0, false); +} + +void display_end() { _display_panel_and_hw_end(false); }; + +u16 display_get_decoded_panel_id() +{ + return _display_id; +} + +void display_set_decoded_panel_id(u32 id) +{ + // Get Hardware type, as it's used in various DI functions. + _nx_aula = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA; + + // Decode Display ID. + _display_id = ((id >> 8) & 0xFF00) | (id & 0xFF); + + if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) + _display_id = PANEL_JDI_XXX062M; + + // For Aula ensure that we have a compatible panel id. + if (_nx_aula && _display_id == 0xCCCC) + _display_id = PANEL_SAM_AMS699VC01; +} + +void display_color_screen(u32 color) +{ + // Disable all windows. + reg_write_array((u32 *)DISPLAY_A_BASE, _di_win_one_color, ARRAY_SIZE(_di_win_one_color)); + + // Configure display to show single color. + DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ; + usleep(35000); // Wait 2 frames. No need on Aula. + + if (_display_id != PANEL_SAM_AMS699VC01) + display_backlight(true); + else + display_backlight_brightness(150, 0); +} + +u32 *display_init_window_a_pitch() +{ + // Sanitize framebuffer area. + memset((u32 *)IPL_FB_ADDRESS, 0, IPL_FB_SZ); + + // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 720x1280 (line stride 720). + reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_pitch, ARRAY_SIZE(_di_winA_pitch)); + //usleep(35000); // Wait 2 frames. No need on Aula. + + return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); +} + +u32 *display_init_window_a_pitch_vic() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720). + if (_display_id != PANEL_SAM_AMS699VC01) + usleep(8000); // Wait half frame for PWM to apply. + reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_pitch_vic, ARRAY_SIZE(_di_winA_pitch_vic)); + if (_display_id != PANEL_SAM_AMS699VC01) + usleep(35000); // Wait 2 frames. + + return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); +} + +u32 *display_init_window_a_pitch_inv() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720). + reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_pitch_inv, ARRAY_SIZE(_di_winA_pitch_inv)); + usleep(35000); // Wait 2 frames. No need on Aula. + + return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); +} + +u32 *display_init_window_a_block() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280. + reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_block, ARRAY_SIZE(_di_winA_block)); + usleep(35000); // Wait 2 frames. No need on Aula. + + return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); +} + +u32 *display_init_window_d_console() +{ + // This configures the framebuffer @ LOG_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + reg_write_array((u32 *)DISPLAY_A_BASE, _di_winD_log, ARRAY_SIZE(_di_winD_log)); + + return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); +} + +void display_window_disable(u32 window) +{ + // Select window C. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window); + + // Disable window C. + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | BIT(WIN_UPDATE + window); + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window); +} + +void display_set_framebuffer(u32 window, void *fb) +{ + // Select window. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window); + + // Set new fb address. + DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)) = (u32)fb; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | BIT(WIN_UPDATE + window); + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window); +} + +void display_move_framebuffer(u32 window, void *fb) +{ + // Select window. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window); + + // Get current framebuffer address. + const void *fb_curr = (void *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); + u32 win_size = DISPLAY_A(_DIREG(DC_WIN_PRESCALED_SIZE)); + win_size = (win_size & 0x7FFF) * ((win_size >> 16) & 0x1FFF); + + // Copy fb over. + memcpy(fb, fb_curr, win_size); + + // Set new fb address. + DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)) = (u32)fb; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | BIT(WIN_UPDATE + window); + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window); +} + +void display_window_d_console_enable() +{ + // Only update active registers on vsync. + DISPLAY_A(_DIREG(DC_CMD_REG_ACT_CONTROL)) = DISPLAY_A(_DIREG(DC_CMD_REG_ACT_CONTROL)) & ~WIN_D_ACT_HCNTR_SEL; + + // Select window D. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; + + // Enable and setup window D. + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = WIN_ENABLE; + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0xFF80; // X: -128. + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + + // Pull-down effect. + for (u32 i = 0xFF80; i < 0x10000; i++) + { + // Set window position. + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = i & 0xFFFF; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + usleep(1000); + } + + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; +} + +void display_window_d_console_disable() +{ + // Select window D. + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; + + // Pull-up effect. + for (u32 i = 0xFFFF; i > 0xFF7F; i--) + { + // Set window position. + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = i & 0xFFFF; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + usleep(500); + } + + // Disable window D. + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0; + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; +} + +void display_cursor_init(void *crs_fb, u32 size) +{ + // Setup cursor. + DISPLAY_A(_DIREG(DC_DISP_CURSOR_START_ADDR)) = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10); + DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = CURSOR_BLEND_R8G8B8A8 | + CURSOR_BLEND_DST_FACTOR(CURSOR_BLEND_K1) | + CURSOR_BLEND_SRC_FACTOR(CURSOR_BLEND_K1) | 0xFF; + + // Enable cursor window. + DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) |= CURSOR_ENABLE; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} + +void display_cursor_set_pos(u32 x, u32 y) +{ + // Set cursor position. + DISPLAY_A(_DIREG(DC_DISP_CURSOR_POSITION)) = x | (y << 16); + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} + +void display_cursor_deinit() +{ + DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = 0; + DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) &= ~CURSOR_ENABLE; + + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} diff --git a/bdk/display/di.h b/bdk/display/di.h new file mode 100644 index 0000000..9a35d4f --- /dev/null +++ b/bdk/display/di.h @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 _DI_H_ +#define _DI_H_ + +#include +#include + +#define DSI_VIDEO_DISABLED 0 +#define DSI_VIDEO_ENABLED 1 + +#define WINDOW_A 0 +#define WINDOW_B 1 +#define WINDOW_C 2 +#define WINDOW_D 3 + +/*! Display registers. */ +#define _DIREG(reg) ((reg) * 4) + +// Display controller scratch registers. +#define DC_D_WINBUF_DD_SCRATCH_REGISTER_0 0xED +#define DC_D_WINBUF_DD_SCRATCH_REGISTER_1 0xEE +#define DC_T_WINBUF_TD_SCRATCH_REGISTER_0 0x16D +#define DC_T_WINBUF_TD_SCRATCH_REGISTER_1 0x16E +#define DC_COM_SCRATCH_REGISTER_A 0x325 +#define DC_COM_SCRATCH_REGISTER_B 0x326 +#define DC_A_WINBUF_AD_SCRATCH_REGISTER_0 0xBED +#define DC_A_WINBUF_AD_SCRATCH_REGISTER_1 0xBEE +#define DC_B_WINBUF_BD_SCRATCH_REGISTER_0 0xDED +#define DC_B_WINBUF_BD_SCRATCH_REGISTER_1 0xDEE +#define DC_C_WINBUF_CD_SCRATCH_REGISTER_0 0xFED +#define DC_C_WINBUF_CD_SCRATCH_REGISTER_1 0xFEE + +// DC_CMD non-shadowed command/sync registers. +#define DC_CMD_GENERAL_INCR_SYNCPT 0x00 +#define SYNCPT_GENERAL_INDX(x) (((x) & 0xFF) << 0) +#define SYNCPT_GENERAL_COND(x) (((x) & 0xFF) << 8) +#define COND_REG_WR_SAFE 3 + +#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 +#define SYNCPT_CNTRL_SOFT_RESET BIT(0) +#define SYNCPT_CNTRL_NO_STALL BIT(8) + +#define DC_CMD_CONT_SYNCPT_VSYNC 0x28 +#define SYNCPT_VSYNC_INDX(x) (((x) & 0xFF) << 0) +#define SYNCPT_VSYNC_ENABLE BIT(8) + +#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 + +#define DC_CMD_DISPLAY_COMMAND 0x32 +#define DISP_CTRL_MODE_STOP (0 << 5) +#define DISP_CTRL_MODE_C_DISPLAY (1 << 5) +#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) +#define DISP_CTRL_MODE_MASK (3 << 5) + +#define DC_CMD_DISPLAY_POWER_CONTROL 0x36 +#define PW0_ENABLE BIT(0) +#define PW1_ENABLE BIT(2) +#define PW2_ENABLE BIT(4) +#define PW3_ENABLE BIT(6) +#define PW4_ENABLE BIT(8) +#define PM0_ENABLE BIT(16) +#define PM1_ENABLE BIT(18) + +#define DC_CMD_INT_STATUS 0x37 +#define DC_CMD_INT_MASK 0x38 +#define DC_CMD_INT_ENABLE 0x39 +#define DC_CMD_INT_FRAME_END_INT BIT(1) +#define DC_CMD_INT_V_BLANK_INT BIT(2) +#define DC_CMD_INT_POLARITY 0x3B + +#define DC_CMD_STATE_ACCESS 0x40 +#define READ_MUX_ASSEMBLY 0x0 +#define WRITE_MUX_ASSEMBLY 0x0 +#define READ_MUX_ACTIVE BIT(0) +#define WRITE_MUX_ACTIVE BIT(2) + +#define DC_CMD_STATE_CONTROL 0x41 +#define GENERAL_ACT_REQ BIT(0) +#define WIN_ACT_REQ 1 +#define WIN_A_ACT_REQ BIT(1) +#define WIN_B_ACT_REQ BIT(2) +#define WIN_C_ACT_REQ BIT(3) +#define WIN_D_ACT_REQ BIT(4) +#define CURSOR_ACT_REQ BIT(7) +#define GENERAL_UPDATE BIT(8) +#define WIN_UPDATE 9 +#define WIN_A_UPDATE BIT(9) +#define WIN_B_UPDATE BIT(10) +#define WIN_C_UPDATE BIT(11) +#define WIN_D_UPDATE BIT(12) +#define CURSOR_UPDATE BIT(15) +#define NC_HOST_TRIG BIT(24) + +#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 +#define WINDOW_SELECT 4 +#define WINDOW_A_SELECT BIT(4) +#define WINDOW_B_SELECT BIT(5) +#define WINDOW_C_SELECT BIT(6) +#define WINDOW_D_SELECT BIT(7) + +#define DC_CMD_REG_ACT_CONTROL 0x43 +#define GENERAL_ACT_HCNTR_SEL BIT(0) +#define WIN_A_ACT_HCNTR_SEL BIT(2) +#define WIN_B_ACT_HCNTR_SEL BIT(4) +#define WIN_C_ACT_HCNTR_SEL BIT(6) +#define CURSOR_ACT_HCNTR_SEL BIT(7) +#define WIN_D_ACT_HCNTR_SEL BIT(10) + +// DC_D_WIN_DD window D instance of DC_WIN +#define DC_D_WIN_DD_WIN_OPTIONS 0x80 +#define DC_D_WIN_DD_COLOR_DEPTH 0x83 +#define DC_D_WIN_DD_POSITION 0x84 +#define DC_D_WIN_DD_SIZE 0x85 +#define DC_D_WIN_DD_LINE_STRIDE 0x8A +#define DC_D_WIN_DD_BLEND_LAYER_CONTROL 0x96 +#define DC_D_WIN_DD_BLEND_MATCH_SELECT 0x97 +#define DC_D_WIN_DD_BLEND_ALPHA_1BIT 0x99 + +// DC_D_WINBUF_DD window D instance of DC_WINBUF +#define DC_D_WINBUF_DD_START_ADDR 0xC0 +#define DC_D_WINBUF_DD_ADDR_H_OFFSET 0xC6 +#define DC_D_WINBUF_DD_ADDR_V_OFFSET 0xC8 +#define DC_D_WINBUF_DD_START_ADDR_HI 0xCD +#define DC_D_WINBUF_DD_MEMFETCH_CONTROL 0xEB + +// DC_T_WIN_TD macro for using DD defines. +#define _DC_T(reg) ((reg) + 0x80) + +// DC_COM non-shadowed registers. +#define DC_COM_CRC_CONTROL 0x300 +#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) +#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) +#define LSC0_OUTPUT_POLARITY_LOW BIT(24) + +// CMU registers. +#define DC_COM_CMU_CSC_KRR 0x32A +#define DC_COM_CMU_CSC_KGR 0x32B +#define DC_COM_CMU_CSC_KBR 0x32C +#define DC_COM_CMU_CSC_KRG 0x32D +#define DC_COM_CMU_CSC_KGG 0x32E +#define DC_COM_CMU_CSC_KBG 0x32F +#define DC_COM_CMU_CSC_KRB 0x330 +#define DC_COM_CMU_CSC_KGB 0x331 +#define DC_COM_CMU_CSC_KBB 0x332 +#define DC_COM_CMU_LUT1 0x336 +#define LUT1_ADDR(x) ((x) & 0xFF) +#define LUT1_DATA(x) (((x) & 0xFFF) << 16) +#define LUT1_READ_DATA(x) (((x) >> 16) & 0xFFF) +#define DC_COM_CMU_LUT2 0x337 +#define LUT2_ADDR(x) ((x) & 0x3FF) +#define LUT2_DATA(x) (((x) & 0xFF) << 16) +#define LUT2_READ_DATA(x) (((x) >> 16) & 0xFF) +#define DC_COM_CMU_LUT1_READ 0x338 +#define LUT1_READ_ADDR(x) (((x) & 0xFF) << 8) +#define LUT1_READ_EN BIT(0) +#define DC_COM_CMU_LUT2_READ 0x339 +#define LUT2_READ_ADDR(x) (((x) & 0x3FF) << 8) +#define LUT2_READ_EN BIT(0) + +#define DC_COM_DSC_TOP_CTL 0x33E + +// DC_DISP shadowed registers. +#define DC_DISP_DISP_WIN_OPTIONS 0x402 +#define CURSOR_ENABLE BIT(16) +#define SOR_ENABLE BIT(25) +#define SOR1_ENABLE BIT(26) +#define SOR1_TIMING_CYA BIT(27) +#define DSI_ENABLE BIT(29) +#define HDMI_ENABLE BIT(30) + + +#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 +#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 + +#define DC_DISP_DISP_TIMING_OPTIONS 0x405 +#define VSYNC_H_POSITION(x) (((x) & 0x1FFF) << 0) + +#define DC_DISP_REF_TO_SYNC 0x406 +#define H_REF_TO_SYNC(x) (((x) & 0x1FFF) << 0) // Min 0 pixel clock. +#define V_REF_TO_SYNC(x) (((x) & 0x1FFF) << 16) // Min 1 line clock. + +#define DC_DISP_SYNC_WIDTH 0x407 +#define H_SYNC_WIDTH(x) (((x) & 0x1FFF) << 0) // Min 1 pixel clock. +#define V_SYNC_WIDTH(x) (((x) & 0x1FFF) << 16) // Min 1 line clock. + +#define DC_DISP_BACK_PORCH 0x408 +#define H_BACK_PORCH(x) (((x) & 0x1FFF) << 0) +#define V_BACK_PORCH(x) (((x) & 0x1FFF) << 16) + +#define DC_DISP_ACTIVE 0x409 +#define H_DISP_ACTIVE(x) (((x) & 0x1FFF) << 0) // Min 16 pixel clock. +#define V_DISP_ACTIVE(x) (((x) & 0x1FFF) << 16) // Min 16 line clock. + +#define DC_DISP_FRONT_PORCH 0x40A +#define H_FRONT_PORCH(x) (((x) & 0x1FFF) << 0) // Min -=PS_=-H_REF_TO_SYNC + 1 +#define V_FRONT_PORCH(x) (((x) & 0x1FFF) << 16) // Min -=PS_=-V_REF_TO_SYNC + 1 + +#define DC_DISP_DISP_CLOCK_CONTROL 0x42E +#define SHIFT_CLK_DIVIDER(x) ((x) & 0xFF) +#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) +#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) +#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) +#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) +#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) +#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) +#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) +#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) +#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) +#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) +#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) +#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) +#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) + +#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F +#define DISP_DATA_FORMAT_DF1P1C (0 << 0) +#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) +#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) +#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) +#define DISP_DATA_FORMAT_DF2S (4 << 0) +#define DISP_DATA_FORMAT_DF3S (5 << 0) +#define DISP_DATA_FORMAT_DFSPI (6 << 0) +#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) +#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) +#define DISP_ALIGNMENT_MSB (0 << 8) +#define DISP_ALIGNMENT_LSB (1 << 8) +#define DISP_ORDER_RED_BLUE (0 << 9) +#define DISP_ORDER_BLUE_RED (1 << 9) + +#define DC_DISP_DISP_COLOR_CONTROL 0x430 +#define BASE_COLOR_SIZE_MASK (0xF << 0) +#define BASE_COLOR_SIZE_666 (0 << 0) +#define BASE_COLOR_SIZE_111 (1 << 0) +#define BASE_COLOR_SIZE_222 (2 << 0) +#define BASE_COLOR_SIZE_333 (3 << 0) +#define BASE_COLOR_SIZE_444 (4 << 0) +#define BASE_COLOR_SIZE_555 (5 << 0) +#define BASE_COLOR_SIZE_565 (6 << 0) +#define BASE_COLOR_SIZE_332 (7 << 0) +#define BASE_COLOR_SIZE_888 (8 << 0) +#define DITHER_CONTROL_MASK (3 << 8) +#define DITHER_CONTROL_DISABLE (0 << 8) +#define DITHER_CONTROL_ORDERED (2 << 8) +#define DITHER_CONTROL_ERRDIFF (3 << 8) +#define DISP_COLOR_SWAP BIT(16) +#define BLANK_COLOR_WHITE BIT(17) +#define CMU_ENABLE BIT(20) + +#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 +#define SC0_H_QUALIFIER_NONE BIT(0) +#define SC1_H_QUALIFIER_NONE BIT(16) + +#define DC_DISP_DATA_ENABLE_OPTIONS 0x432 +#define DE_SELECT_ACTIVE_BLANK (0 << 0) +#define DE_SELECT_ACTIVE (1 << 0) +#define DE_SELECT_ACTIVE_IS (2 << 0) +#define DE_CONTROL_ONECLK (0 << 2) +#define DE_CONTROL_NORMAL (1 << 2) +#define DE_CONTROL_EARLY_EXT (2 << 2) +#define DE_CONTROL_EARLY (3 << 2) +#define DE_CONTROL_ACTIVE_BLANK (4 << 2) + +// Cursor configuration registers. +#define DC_DISP_CURSOR_FOREGROUND 0x43C +#define DC_DISP_CURSOR_BACKGROUND 0x43D +#define CURSOR_COLOR(r,g,b) (((r) & 0xFF) | (((g) & 0xFF) << 8) | (((b) & 0xFF) << 16)) + +#define DC_DISP_CURSOR_START_ADDR 0x43E +#define DC_DISP_CURSOR_START_ADDR_NS 0x43F +#define CURSOR_CLIPPING(w) ((w) << 28) +#define CURSOR_CLIP_WIN_A 1 +#define CURSOR_CLIP_WIN_B 2 +#define CURSOR_CLIP_WIN_C 3 +#define CURSOR_SIZE_32 (0 << 24) +#define CURSOR_SIZE_64 (1 << 24) +#define CURSOR_SIZE_128 (2 << 24) +#define CURSOR_SIZE_256 (3 << 24) +#define DC_DISP_CURSOR_POSITION 0x440 +#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 +#define DC_DISP_CURSOR_START_ADDR_HI 0x4EC +#define DC_DISP_CURSOR_START_ADDR_HI_NS 0x4ED +#define DC_DISP_BLEND_CURSOR_CONTROL 0x4F1 +#define CURSOR_BLEND_2BIT (0 << 24) +#define CURSOR_BLEND_R8G8B8A8 (1 << 24) +#define CURSOR_BLEND_SRC_FACTOR(n) ((n) << 8) +#define CURSOR_BLEND_DST_FACTOR(n) ((n) << 16) +#define CURSOR_BLEND_ZRO 0 +#define CURSOR_BLEND_K1 1 +#define CURSOR_BLEND_NK1 2 +// End of cursor cfg regs. + +#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 +#define DC_DISP_SD_BL_PARAMETERS 0x4D7 +#define DC_DISP_SD_BL_CONTROL 0x4DC +#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 + +#define DC_WINC_COLOR_PALETTE 0x500 +#define COLOR_PALETTE_IDX(off) (DC_WINC_COLOR_PALETTE + (off)) +#define COLOR_PALETTE_RGB(rgb) (byte_swap_32(rgb) >> 8) +#define DC_WINC_PALETTE_COLOR_EXT 0x600 + +#define DC_WINC_H_FILTER_P(p) (0x601 + (p)) +#define DC_WINC_V_FILTER_P(p) (0x619 + (p)) +#define DC_WINC_H_FILTER_HI_P(p) (0x629 + (p)) + +#define DC_WINC_CSC_YOF 0x611 +#define DC_WINC_CSC_KYRGB 0x612 +#define DC_WINC_CSC_KUR 0x613 +#define DC_WINC_CSC_KVR 0x614 +#define DC_WINC_CSC_KUG 0x615 +#define DC_WINC_CSC_KVG 0x616 +#define DC_WINC_CSC_KUB 0x617 +#define DC_WINC_CSC_KVB 0x618 +#define DC_WIN_AD_WIN_OPTIONS 0xB80 +#define DC_WIN_BD_WIN_OPTIONS 0xD80 +#define DC_WIN_CD_WIN_OPTIONS 0xF80 + +// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). +#define DC_WIN_WIN_OPTIONS 0x700 +#define H_DIRECTION BIT(0) +#define V_DIRECTION BIT(2) +#define SCAN_COLUMN BIT(4) +#define COLOR_EXPAND BIT(6) +#define H_FILTER_ENABLE BIT(8) +#define V_FILTER_ENABLE BIT(10) +#define COLOR_PALETTE_ENABLE BIT(16) +#define CSC_ENABLE BIT(18) +#define DV_ENABLE BIT(20) +#define WIN_ENABLE BIT(30) +#define H_FILTER_EXPAND BIT(31) + +#define DC_WIN_BUFFER_CONTROL 0x702 +#define BUFFER_CONTROL_HOST 0 +#define BUFFER_CONTROL_VI 1 +#define BUFFER_CONTROL_SB2D 4 + +#define DC_WIN_COLOR_DEPTH 0x703 +#define WIN_COLOR_DEPTH_P1 0x0 +#define WIN_COLOR_DEPTH_P2 0x1 +#define WIN_COLOR_DEPTH_P4 0x2 +#define WIN_COLOR_DEPTH_P8 0x3 +#define WIN_COLOR_DEPTH_B4G4R4A4 0x4 +#define WIN_COLOR_DEPTH_B5G5R5A 0x5 +#define WIN_COLOR_DEPTH_B5G6R5 0x6 +#define WIN_COLOR_DEPTH_AB5G5R5 0x7 +#define WIN_COLOR_DEPTH_B8G8R8A8 0xC +#define WIN_COLOR_DEPTH_R8G8B8A8 0xD +#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE +#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF +#define WIN_COLOR_DEPTH_YCbCr422 0x10 +#define WIN_COLOR_DEPTH_YUV422 0x11 +#define WIN_COLOR_DEPTH_YCbCr420P 0x12 +#define WIN_COLOR_DEPTH_YUV420P 0x13 +#define WIN_COLOR_DEPTH_YCbCr422P 0x14 +#define WIN_COLOR_DEPTH_YUV422P 0x15 +#define WIN_COLOR_DEPTH_YCbCr422R 0x16 +#define WIN_COLOR_DEPTH_YUV422R 0x17 +#define WIN_COLOR_DEPTH_YCbCr422RA 0x18 +#define WIN_COLOR_DEPTH_YUV422RA 0x19 +#define WIN_COLOR_DEPTH_X1R5G5B5 0x1E +#define WIN_COLOR_DEPTH_R5G5B5X1 0x1F +#define WIN_COLOR_DEPTH_X1B5G5R5 0x20 +#define WIN_COLOR_DEPTH_B5G5R5X1 0x21 +#define WIN_COLOR_DEPTH_YCbCr444P 0x29 +#define WIN_COLOR_DEPTH_YCrCb420SP 0x2A +#define WIN_COLOR_DEPTH_YCbCr420SP 0x2B +#define WIN_COLOR_DEPTH_YCrCb422SP 0x2C +#define WIN_COLOR_DEPTH_YCbCr422SP 0x2D +#define WIN_COLOR_DEPTH_YUV444P 0x34 +#define WIN_COLOR_DEPTH_YVU420SP 0x35 +#define WIN_COLOR_DEPTH_YUV420SP 0x36 +#define WIN_COLOR_DEPTH_YVU422SP 0x37 +#define WIN_COLOR_DEPTH_YUV422SP 0x38 +#define WIN_COLOR_DEPTH_YVU444SP 0x3B +#define WIN_COLOR_DEPTH_YUV444SP 0x3C + +#define DC_WIN_POSITION 0x704 +#define H_POSITION(x) (((x) & 0xFFFF) << 0) // Support negative. +#define V_POSITION(x) (((x) & 0xFFFF) << 16) // Support negative. + +#define DC_WIN_SIZE 0x705 +#define H_SIZE(x) (((x) & 0x1FFF) << 0) +#define V_SIZE(x) (((x) & 0x1FFF) << 16) + +#define DC_WIN_PRESCALED_SIZE 0x706 +#define H_PRESCALED_SIZE(x) (((x) & 0x7FFF) << 0) +#define V_PRESCALED_SIZE(x) (((x) & 0x1FFF) << 16) + +#define DC_WIN_H_INITIAL_DDA 0x707 +#define DC_WIN_V_INITIAL_DDA 0x708 + +#define DC_WIN_DDA_INC 0x709 +#define H_DDA_INC(x) (((x) & 0xFFFF) << 0) +#define V_DDA_INC(x) (((x) & 0xFFFF) << 16) + +#define DC_WIN_LINE_STRIDE 0x70A +#define LINE_STRIDE(x) (x) +#define UV_LINE_STRIDE(x) (((x) & 0xFFFF) << 16) + +#define DC_WIN_DV_CONTROL 0x70E +#define DV_CTRL_R(r) (((r) & 7) << 16) +#define DV_CTRL_G(g) (((g) & 7) << 8) +#define DV_CTRL_B(b) (((b) & 7) << 0) + +#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716 +#define WIN_BLEND_DEPTH(x) (((x) & 0xFF) << 0) +#define WIN_K1(x) (((x) & 0xFF) << 8) +#define WIN_K2(x) (((x) & 0xFF) << 16) +#define WIN_BLEND_ENABLE (0 << 24) +#define WIN_BLEND_BYPASS (1 << 24) + +#define DC_WINBUF_BLEND_MATCH_SELECT 0x717 +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ZERO (0 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ONE (1 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 (2 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_DST (3 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (4 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC (5 << 0) + +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ZERO (0 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ONE (1 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1 (2 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K2 (3 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1_TIMES_DST (4 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (5 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC (6 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1 (7 << 4) + +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_ZERO (0 << 8) +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K1 (1 << 8) +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 (2 << 8) + +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO (0 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ONE (1 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_NEG_K1_TIMES_SRC (2 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12) + +#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719 +#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xFF) << 0) +#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xFF) << 8) + +/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ +#define DC_WINBUF_START_ADDR 0x800 +#define DC_WINBUF_ADDR_H_OFFSET 0x806 +#define DC_WINBUF_ADDR_V_OFFSET 0x808 +#define DC_WINBUF_SURFACE_KIND 0x80B +#define PITCH (0 << 0) +#define TILED (1 << 0) +#define BLOCK (2 << 0) +#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) + +#define DC_WINBUF_MEMFETCH_CONTROL 0x82B + +/*! Display serial interface registers. */ +#define _DSIREG(reg) ((reg) * 4) + +#define DSI_INCR_SYNCPT_CNTRL 0x1 +#define DSI_INCR_SYNCPT_SOFT_RESET BIT(0) +#define DSI_INCR_SYNCPT_NO_STALL BIT(8) + +#define DSI_RD_DATA 0x9 +#define DSI_WR_DATA 0xA + +#define DSI_POWER_CONTROL 0xB +#define DSI_POWER_CONTROL_ENABLE 1 + +#define DSI_INT_ENABLE 0xC +#define DSI_INT_STATUS 0xD +#define DSI_INT_MASK 0xE + +#define DSI_HOST_CONTROL 0xF +#define DSI_HOST_CONTROL_ECC BIT(0) +#define DSI_HOST_CONTROL_CS BIT(1) +#define DSI_HOST_CONTROL_PKT_BTA BIT(2) +#define DSI_HOST_CONTROL_IMM_BTA BIT(3) +#define DSI_HOST_CONTROL_FIFO_SEL BIT(4) +#define DSI_HOST_CONTROL_HS BIT(5) +#define DSI_HOST_CONTROL_RAW BIT(6) +#define DSI_HOST_CONTROL_TX_TRIG_MASK (3 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) +#define DSI_HOST_CONTROL_CRC_RESET BIT(20) +#define DSI_HOST_CONTROL_FIFO_RESET BIT(21) + +#define DSI_CONTROL 0x10 +#define DSI_CONTROL_HOST_ENABLE BIT(0) +#define DSI_CONTROL_VIDEO_ENABLE BIT(1) +#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) +#define DSI_CONTROL_DCS_ENABLE BIT(3) +#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) +#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) +#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) +#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) +#define DSI_CONTROL_HS_CLK_CTRL BIT(20) + +#define DSI_SOL_DELAY 0x11 +#define DSI_MAX_THRESHOLD 0x12 + +#define DSI_TRIGGER 0x13 +#define DSI_TRIGGER_VIDEO BIT(0) +#define DSI_TRIGGER_HOST BIT(1) + +#define DSI_TX_CRC 0x14 + +#define DSI_STATUS 0x15 +#define DSI_STATUS_RX_FIFO_SIZE 0x1F +#define DSI_STATUS_TX_FIFO_SIZE 0x20 // Actual depth is 64. + +#define DSI_INIT_SEQ_CONTROL 0x1A +#define DSI_INIT_SEQ_DATA_0 0x1B +#define DSI_INIT_SEQ_DATA_1 0x1C +#define DSI_INIT_SEQ_DATA_2 0x1D +#define DSI_INIT_SEQ_DATA_3 0x1E +#define DSI_PKT_SEQ_0_LO 0x23 +#define DSI_PKT_SEQ_0_HI 0x24 +#define DSI_PKT_SEQ_1_LO 0x25 +#define DSI_PKT_SEQ_1_HI 0x26 +#define DSI_PKT_SEQ_2_LO 0x27 +#define DSI_PKT_SEQ_2_HI 0x28 +#define DSI_PKT_SEQ_3_LO 0x29 +#define DSI_PKT_SEQ_3_HI 0x2A +#define DSI_PKT_SEQ_4_LO 0x2B +#define DSI_PKT_SEQ_4_HI 0x2C +#define DSI_PKT_SEQ_5_LO 0x2D +#define DSI_PKT_SEQ_5_HI 0x2E +#define DSI_DCS_CMDS 0x33 + +#define DSI_PKT_LEN_0_1 0x34 +#define DSI_PKT_LEN_2_3 0x35 +#define DSI_PKT_LEN_4_5 0x36 +#define DSI_PKT_LEN_6_7 0x37 +#define PKT0_LEN(x) (((x) & 0xFFFF) << 0) +#define PKT1_LEN(x) (((x) & 0xFFFF) << 16) + +#define DSI_PHY_TIMING_0 0x3C +#define DSI_PHY_TIMING_1 0x3D +#define DSI_PHY_TIMING_2 0x3E +#define DSI_BTA_TIMING 0x3F + +#define DSI_TIMEOUT_0 0x44 +#define DSI_TIMEOUT_HTX(x) (((x) & 0xFFFF) << 0) +#define DSI_TIMEOUT_LRX(x) (((x) & 0xFFFF) << 16) + +#define DSI_TIMEOUT_1 0x45 +#define DSI_TIMEOUT_TA(x) (((x) & 0xFFFF) << 0) +#define DSI_TIMEOUT_PR(x) (((x) & 0xFFFF) << 16) + +#define DSI_TO_TALLY 0x46 + +#define DSI_PAD_CONTROL_0 0x4B +#define DSI_PAD_CONTROL_VS1_PDIO_CLK BIT(8) +#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xF) << 0) +#define DSI_PAD_CONTROL_VS1_PULLDN_CLK BIT(24) +#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xF) << 16) + +#define DSI_PAD_CONTROL_CD 0x4C +#define DSI_VIDEO_MODE_CONTROL 0x4E +#define DSI_CMD_PKT_VID_ENABLE 1 +#define DSI_DSI_LINE_TYPE(x) ((x) << 1) + +#define DSI_PAD_CONTROL_1 0x4F +#define DSI_PAD_CONTROL_2 0x50 + +#define DSI_PAD_CONTROL_3 0x51 +#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) +#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) +#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) +#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) + +#define DSI_PAD_CONTROL_4 0x52 +#define DSI_PAD_CONTROL_5_B01 0x53 +#define DSI_PAD_CONTROL_6_B01 0x54 +#define DSI_PAD_CONTROL_7_B01 0x55 +#define DSI_INIT_SEQ_DATA_15 0x5F +#define DSI_INIT_SEQ_DATA_15_B01 0x62 + +/*! DSI packet defines */ +#define DSI_ESCAPE_CMD 0x87 +#define DSI_ACK_NO_ERR 0x84 + +#define ACK_ERROR_RES 0x02 +#define GEN_LONG_RD_RES 0x1A +#define DCS_LONG_RD_RES 0x1C +#define GEN_1_BYTE_SHORT_RD_RES 0x11 +#define DCS_1_BYTE_SHORT_RD_RES 0x21 +#define GEN_2_BYTE_SHORT_RD_RES 0x12 +#define DCS_2_BYTE_SHORT_RD_RES 0x22 + +/*! MIPI registers. */ +#define MIPI_CAL_MIPI_CAL_CTRL (0x00 / 0x4) +#define MIPI_CAL_CIL_MIPI_CAL_STATUS (0x08 / 0x4) +#define MIPI_CAL_CILA_MIPI_CAL_CONFIG (0x14 / 0x4) +#define MIPI_CAL_CILB_MIPI_CAL_CONFIG (0x18 / 0x4) +#define MIPI_CAL_CILC_MIPI_CAL_CONFIG (0x1C / 0x4) +#define MIPI_CAL_CILD_MIPI_CAL_CONFIG (0x20 / 0x4) +#define MIPI_CAL_CILE_MIPI_CAL_CONFIG (0x24 / 0x4) +#define MIPI_CAL_CILF_MIPI_CAL_CONFIG (0x28 / 0x4) +#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG (0x38 / 0x4) +#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG (0x3C / 0x4) +#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG (0x40 / 0x4) +#define MIPI_CAL_DSID_MIPI_CAL_CONFIG (0x44 / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 (0x58 / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 (0x5C / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 (0x60 / 0x4) +#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 (0x64 / 0x4) +#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 (0x68 / 0x4) +#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 (0x70 / 0x4) +#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 (0x74 / 0x4) + +/*! MIPI CMDs. */ +#define MIPI_DSI_V_SYNC_START 0x01 +#define MIPI_DSI_COLOR_MODE_OFF 0x02 +#define MIPI_DSI_END_OF_TRANSMISSION 0x08 +#define MIPI_DSI_NULL_PACKET 0x09 +#define MIPI_DSI_V_SYNC_END 0x11 +#define MIPI_DSI_COLOR_MODE_ON 0x12 +#define MIPI_DSI_BLANKING_PACKET 0x19 +#define MIPI_DSI_H_SYNC_START 0x21 +#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22 +#define MIPI_DSI_H_SYNC_END 0x31 +#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32 +#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37 + +#define MIPI_DSI_DCS_SHORT_WRITE 0x05 +#define MIPI_DSI_DCS_READ 0x06 +#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15 +#define MIPI_DSI_DCS_LONG_WRITE 0x39 + +#define MIPI_DSI_GENERIC_LONG_WRITE 0x29 +#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03 +#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13 +#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23 +#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04 +#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14 +#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24 + +/*! MIPI DCS CMDs. */ +#define MIPI_DCS_NOP 0x00 +#define MIPI_DCS_SOFT_RESET 0x01 +#define MIPI_DCS_GET_COMPRESSION_MODE 0x03 +#define MIPI_DCS_GET_DISPLAY_ID 0x04 +#define MIPI_DCS_GET_DISPLAY_ID1 0xDA // GET_DISPLAY_ID Byte0, Module Manufacturer ID. +#define MIPI_DCS_GET_DISPLAY_ID2 0xDB // GET_DISPLAY_ID Byte1, Module/Driver Version ID. +#define MIPI_DCS_GET_DISPLAY_ID3 0xDC // GET_DISPLAY_ID Byte2, Module/Driver ID. +#define MIPI_DCS_GET_NUM_ERRORS 0x05 // 1 byte. +#define MIPI_DCS_GET_RED_CHANNEL 0x06 +#define MIPI_DCS_GET_GREEN_CHANNEL 0x07 +#define MIPI_DCS_GET_BLUE_CHANNEL 0x08 +#define MIPI_DCS_GET_DISPLAY_STATUS 0x09 // 4 bytes. +#define MIPI_DCS_GET_POWER_MODE 0x0A // 1 byte. 2: DISON, 3: NORON, 4: SLPOUT, 7: BSTON. +#define MIPI_DCS_GET_ADDRESS_MODE 0x0B // Display Access Control. 1 byte. 0: GS, 1: SS, 3: BGR. +#define MIPI_DCS_GET_PIXEL_FORMAT 0x0C // 1 byte. 4-6: DPI. +#define MIPI_DCS_GET_DISPLAY_MODE 0x0D // 1 byte. 0-2: GCS, 3: ALLPOFF, 4: ALLPON, 5: INVON. +#define MIPI_DCS_GET_SIGNAL_MODE 0x0E // 1 byte. 0: EODSI, 2: DEON, 3: PCLKON, 4: VSON, 5: HSON, 7: TEON. +#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0F // 1 byte. 6: FUNDT, 7: REGLD. +#define MIPI_DCS_ENTER_SLEEP_MODE 0x10 +#define MIPI_DCS_EXIT_SLEEP_MODE 0x11 +#define MIPI_DCS_ENTER_PARTIAL_MODE 0x12 +#define MIPI_DCS_ENTER_NORMAL_MODE 0x13 +#define MIPI_DCS_EXIT_INVERT_MODE 0x20 +#define MIPI_DCS_ENTER_INVERT_MODE 0x21 +#define MIPI_DCS_ALL_PIXELS_OFF 0x22 +#define MIPI_DCS_ALL_PIXELS_ON 0x23 +#define MIPI_DCS_SET_CONTRAST 0x25 // VCON in 40mV steps. 7-bit integer. +#define MIPI_DCS_SET_GAMMA_CURVE 0x26 // 1 byte. 0-7: GC. +#define MIPI_DCS_SET_DISPLAY_OFF 0x28 +#define MIPI_DCS_SET_DISPLAY_ON 0x29 +#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2A +#define MIPI_DCS_SET_PAGE_ADDRESS 0x2B +#define MIPI_DCS_WRITE_MEMORY_START 0x2C +#define MIPI_DCS_WRITE_LUT 0x2D // 24-bit: 192 bytes. +#define MIPI_DCS_READ_MEMORY_START 0x2E +#define MIPI_DCS_SET_PARTIAL_ROWS 0x30 +#define MIPI_DCS_SET_PARTIAL_COLUMNS 0x31 +#define MIPI_DCS_SET_SCROLL_AREA 0x33 +#define MIPI_DCS_SET_TEAR_OFF 0x34 +#define MIPI_DCS_SET_TEAR_ON 0x35 +#define MIPI_DCS_SET_ADDRESS_MODE 0x36 // Display Access Control. 1 byte. 0: GS, 1: SS, 3: BGR. +#define MIPI_DCS_SET_SCROLL_START 0x37 +#define MIPI_DCS_EXIT_IDLE_MODE 0x38 +#define MIPI_DCS_ENTER_IDLE_MODE 0x39 +#define MIPI_DCS_SET_PIXEL_FORMAT 0x3A // 1 byte. 4-6: DPI. +#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3C +#define MIPI_DCS_READ_MEMORY_CONTINUE 0x3E +#define MIPI_DCS_GET_3D_CONTROL 0x3F +#define MIPI_DCS_SET_VSYNC_TIMING 0x40 +#define MIPI_DCS_SET_TEAR_SCANLINE 0x44 +#define MIPI_DCS_GET_SCANLINE 0x45 +#define MIPI_DCS_SET_TEAR_SCANLINE_WIDTH 0x46 +#define MIPI_DCS_GET_SCANLINE_WIDTH 0x47 +#define MIPI_DSI_AREA_COLOR_MODE 0x4C +#define MIPI_DCS_SET_BRIGHTNESS 0x51 // DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL. 1 byte. 0-7: DBV. +#define MIPI_DCS_GET_BRIGHTNESS 0x52 // 1 byte. 0-7: DBV. +#define MIPI_DCS_SET_CONTROL_DISPLAY 0x53 // 1 byte. 2: BL, 3: DD, 5: BCTRL. +#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54 // 1 byte. 2: BL, 3: DD, 5: BCTRL. +#define MIPI_DCS_SET_CABC_VALUE 0x55 // 1 byte. 0-32: C, 4-7: C. +#define MIPI_DCS_GET_CABC_VALUE 0x56 // 1 byte. 0-32: C, 4-7: C. +#define MIPI_DCS_SET_CABC_MIN_BRI 0x5E // 1 byte. 0-7: CMB. +#define MIPI_DCS_GET_CABC_MIN_BRI 0x5F // 1 byte. 0-7: CMB. +#define MIPI_DCS_GET_AUTO_BRI_DIAG_RES 0x68 // 1 byte. 6-7: D. +#define MIPI_DCS_READ_DDB_START 0xA1 +#define MIPI_DCS_READ_DDB_CONTINUE 0xA8 // 0x100 size. + +/*! MIPI DCS Panel Private CMDs. */ +#define MIPI_DCS_PRIV_SM_SET_COLOR_MODE 0xA0 // 43 bytes. +#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0 +#define MIPI_DCS_PRIV_SM_SET_ELVSS 0xB1 // OLED backlight tuning. Byte7: PWM transition time in frames. +#define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1 +#define MIPI_DCS_PRIV_SET_EXTC 0xB9 // Enable extended commands. +#define MIPI_DCS_PRIV_UNK_BD 0xBD +#define MIPI_DCS_PRIV_UNK_D5 0xD5 +#define MIPI_DCS_PRIV_UNK_D6 0xD6 +#define MIPI_DCS_PRIV_UNK_D8 0xD8 +#define MIPI_DCS_PRIV_UNK_D9 0xD9 +#define MIPI_DCS_PRIV_SM_DISPLAY_ID 0xDD + // LVL1 LVL2 LVL3 UNK0 UNK1 +#define MIPI_DCS_PRIV_SM_SET_REGS_LOCK 0xE2 // Samsung: Lock (default): 5A5A A5A5 A5A5 A500 A500. Unlock: A5A5 5A5A 5A5A UNK UNK. +#define MIPI_DCS_PRIV_READ_EXTC_CMD_SPI 0xFE // Read EXTC Command In SPI. 1 byte. 0-6: EXT_SPI_CNT, 7:EXT_SP. +#define MIPI_DCS_PRIV_SET_EXTC_CMD_REG 0xFF // EXTC Command Set enable register. 5 bytes. Pass: FF 98 06 04, PAGE. + +/*! MIPI DCS Panel Private CMDs PAGE 1. */ +#define MIPI_DCS_PRIV_GET_DISPLAY_ID4 0x00 +#define MIPI_DCS_PRIV_GET_DISPLAY_ID5 0x01 +#define MIPI_DCS_PRIV_GET_DISPLAY_ID6 0x02 + +/*! MIPI DCS CMD Defines. */ +#define DCS_POWER_MODE_DISPLAY_ON BIT(2) +#define DCS_POWER_MODE_NORMAL_MODE BIT(3) +#define DCS_POWER_MODE_SLEEP_MODE BIT(4) +#define DCS_POWER_MODE_PARTIAL_MODE BIT(5) +#define DCS_POWER_MODE_IDLE_MODE BIT(6) + +#define DCS_ADDRESS_MODE_V_FLIP BIT(0) +#define DCS_ADDRESS_MODE_H_FLIP BIT(1) +#define DCS_ADDRESS_MODE_LATCH_RL BIT(2) // Latch Data Order. +#define DCS_ADDRESS_MODE_BGR_COLOR BIT(3) +#define DCS_ADDRESS_MODE_LINE_ORDER BIT(4) // Line Refresh Order. +#define DCS_ADDRESS_MODE_SWAP_XY BIT(5) // Page/Column Addressing Reverse Order. +#define DCS_ADDRESS_MODE_MIRROR_X BIT(6) // Column Address Order. +#define DCS_ADDRESS_MODE_MIRROR_Y BIT(7) // Page Address Order. +#define DCS_ADDRESS_MODE_ROTATION_MASK (0xF << 4) +#define DCS_ADDRESS_MODE_ROTATION_90 (DCS_ADDRESS_MODE_SWAP_XY | DCS_ADDRESS_MODE_LINE_ORDER) +#define DCS_ADDRESS_MODE_ROTATION_180 (DCS_ADDRESS_MODE_MIRROR_X | DCS_ADDRESS_MODE_LINE_ORDER) +#define DCS_ADDRESS_MODE_ROTATION_270 (DCS_ADDRESS_MODE_SWAP_XY) + +#define DCS_GAMMA_CURVE_NONE 0 +#define DCS_GAMMA_CURVE_GC0_1_8 BIT(0) +#define DCS_GAMMA_CURVE_GC1_2_5 BIT(1) +#define DCS_GAMMA_CURVE_GC2_1_0 BIT(2) +#define DCS_GAMMA_CURVE_GC3_1_0 BIT(3) // Are there more? + +#define DCS_CONTROL_DISPLAY_SM_FLASHLIGHT BIT(2) +#define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL BIT(2) +#define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3) // Transition fading. +#define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5) +#define DCS_CONTROL_DISPLAY_HBM_CTRL0 BIT(6) +#define DCS_CONTROL_DISPLAY_HBM_CTRL1 BIT(7) + +#define DCS_SM_COLOR_MODE_SATURATED 0x00 // Disabled. Based on Vivid but over-saturated. +#define DCS_SM_COLOR_MODE_WASHED 0x45 +#define DCS_SM_COLOR_MODE_BASIC 0x03 // Real natural profile. +#define DCS_SM_COLOR_MODE_POR_RESET 0x20 // Reset value on power on. +#define DCS_SM_COLOR_MODE_NATURAL 0x23 // Not actually natural.. Extra saturation. +#define DCS_SM_COLOR_MODE_VIVID 0x65 // Saturated. +#define DCS_SM_COLOR_MODE_NIGHT0 0x43 // Based on Washed Out. +#define DCS_SM_COLOR_MODE_NIGHT1 0x15 // Based on Basic. +#define DCS_SM_COLOR_MODE_NIGHT2 0x35 // Based on Natural. +#define DCS_SM_COLOR_MODE_NIGHT3 0x75 // Based on Vivid. + +#define DCS_SM_COLOR_MODE_ENABLE BIT(0) + +#define PANEL_SM_BL_CANDELA_MAX 2047 + +/* Switch Panels: + * + * 6.2" panels for Icosa and Iowa SKUs: + * [10] 81 [26]: JDI LPM062M326A + * [10] 96 [09]: JDI LAM062M109A + * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1) + * [20] 95 [0F]: InnoLux P062CCA-AZ2 (Rev B1) + * [20] 96 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV] + * [20] 97 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV] + * [20] 98 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV] + * [20] 99 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV] + * [30] 93 [0F]: AUO A062TAN00 (59.06A33.000) + * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) + * [30] 95 [0F]: AUO A062TAN02 (59.06A33.002) + * [30] 97 [0F]: AUO A062TAN02 (59.06A33.002) [From photo of assumed same panel] + * [30] 98 [0F]: AUO A062TAN0? [UNCONFIRMED MODEL] + * [30] XX [0F]: AUO A062TAN03 (59.06A33.003) [UNCONFIRMED ID] + * + * + * 5.5" panels for Hoag SKU: + * [20] 94 [10]: InnoLux 2J055IA-27A (Rev B1) (6203B001P4000) + * [20] 95 [10]: InnoLux 2J055IA-27A (Rev XX) [UNCONFIRMED MODEL+REV] + * [20] 96 [10]: InnoLux 2J055IA-27A (Rev XX) [UNCONFIRMED MODEL+REV] + * [30] 93 [10]: AUO A055TAN01 (59.05A30.001) + * [30] 94 [10]: AUO A055TAN02 (59.05A30.002) + * [30] 95 [10]: AUO A055TAN03 (59.05A30.003) + * [40] 94 [10]: Sharp LQ055T1SW10 (Rev P) + * + * + * 7.0" OLED panels for Aula SKU: + * [50] 9B [20]: Samsung AMS699VC01-0 (Rev 2.5) + */ + +/* Display ID Decoding: + * + * byte0: Vendor + * byte1: Model + * byte2: Board + * + * Vendors: + * 10h: Japan Display Inc. + * 20h: InnoLux Corporation + * 30h: AU Optronics + * 40h: Sharp + * 50h: Samsung + * + * Boards, Panel Size: + * 0Fh: Icosa/Iowa, 6.2" + * 10h: Hoag, 5.5" + * 20h: Aula, 7.0" + */ + +enum +{ + PANEL_JDI_XXX062M = 0x10, + PANEL_JDI_LAM062M109A = 0x0910, + PANEL_JDI_LPM062M326A = 0x2610, + PANEL_INL_P062CCA_AZ1 = 0x0F20, + PANEL_AUO_A062TAN01 = 0x0F30, + PANEL_INL_2J055IA_27A = 0x1020, + PANEL_AUO_A055TAN01 = 0x1030, + PANEL_SHP_LQ055T1SW10 = 0x1040, + PANEL_SAM_AMS699VC01 = 0x2050, + + // Found on 6/2" clones. Unknown markings. Quality seems JDI like. Has bad low backlight scaling. ID: [83] 94 [0F]. + PANEL_OEM_CLONE_6_2 = 0x0F83, + // Found on 5.5" clones with AUO A055TAN02 (59.05A30.001) fake markings. + PANEL_OEM_CLONE_5_5 = 0x00B3, + // Found on 5.5" clones with AUO A055TAN02 (59.05A30.001) fake markings. + PANEL_OEM_CLONE = 0x0000 +}; + +void display_init(); +void display_backlight_pwm_init(); +void display_end(); + +/*! Interrupt management. */ +void display_enable_interrupt(u32 intr); +void display_disable_interrupt(u32 intr); +void display_wait_interrupt(u32 intr); + +/*! Get/Set Display panel ID. */ +u16 display_get_decoded_panel_id(); +void display_set_decoded_panel_id(u32 id); + +/*! MIPI DCS register management */ +int display_dsi_read(u8 cmd, u32 len, void *data); +int display_dsi_vblank_read(u8 cmd, u32 len, void *data); +void display_dsi_write(u8 cmd, u32 len, void *data); +void display_dsi_vblank_write(u8 cmd, u32 len, void *data); + +/*! Show one single color on the display. */ +void display_color_screen(u32 color); + +/*! Switches screen backlight ON/OFF. */ +void display_backlight(bool enable); +void display_backlight_brightness(u32 brightness, u32 step_delay); +u32 display_get_backlight_brightness(); + +u32 *display_init_window_a_pitch(); +u32 *display_init_window_a_pitch_vic(); +u32 *display_init_window_a_pitch_inv(); +u32 *display_init_window_a_block(); +u32 *display_init_window_d_console(); + +void display_window_disable(u32 window); + +void display_set_framebuffer(u32 window, void *fb); +void display_move_framebuffer(u32 window, void *fb); + +void display_window_d_console_enable(); +void display_window_d_console_disable(); + +void display_cursor_init(void *crs_fb, u32 size); +void display_cursor_set_pos(u32 x, u32 y); +void display_cursor_deinit(); + +#endif diff --git a/bdk/display/di.inl b/bdk/display/di.inl new file mode 100644 index 0000000..d74130e --- /dev/null +++ b/bdk/display/di.inl @@ -0,0 +1,573 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2018-2024 CTCaer +* +* 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 . +*/ + +// Display A config. +static const reg_cfg_t _di_dc_setup_win_config[] = { + {DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + {DC_CMD_REG_ACT_CONTROL, WIN_A_ACT_HCNTR_SEL | WIN_B_ACT_HCNTR_SEL | WIN_C_ACT_HCNTR_SEL}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + {DC_DISP_DC_MCCIF_FIFOCTRL, 0}, + {DC_DISP_DISP_MEM_HIGH_PRIORITY, 0}, + {DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0}, + {DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE}, + {DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL}, + {DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | SYNCPT_VSYNC_INDX(9)}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ}, + + /* Setup Windows A/B/C */ + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT | WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_DV_CONTROL, 0}, + /* Setup default YUV colorspace conversion coefficients */ + {DC_WINC_CSC_YOF, 0xF0}, + {DC_WINC_CSC_KYRGB, 0x12A}, + {DC_WINC_CSC_KUR, 0}, + {DC_WINC_CSC_KVR, 0x198}, + {DC_WINC_CSC_KUG, 0x39B}, + {DC_WINC_CSC_KVG, 0x32F}, + {DC_WINC_CSC_KUB, 0x204}, + {DC_WINC_CSC_KVB, 0}, + /* End of color coefficients */ + + {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, + {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, + {DC_COM_PIN_OUTPUT_POLARITY(1), LSC0_OUTPUT_POLARITY_LOW}, + {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, + {DC_DISP_BLEND_BACKGROUND_COLOR, 0}, + {DC_COM_CRC_CONTROL, 0}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ}, + {DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_BYPASS | WIN_BLEND_DEPTH(255)}, + {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, + {DC_DISP_DISP_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ} +}; + +// DSI Init config. +static const reg_cfg_t _di_dsi_seq_pkt_reset_config0[] = { + {DSI_WR_DATA, 0}, + {DSI_INT_ENABLE, 0}, + {DSI_INT_STATUS, 0}, + {DSI_INT_MASK, 0}, + {DSI_INIT_SEQ_DATA_0, 0}, + {DSI_INIT_SEQ_DATA_1, 0}, + {DSI_INIT_SEQ_DATA_2, 0}, + {DSI_INIT_SEQ_DATA_3, 0} +}; +static const reg_cfg_t _di_dsi_seq_pkt_reset_config1[] = { + {DSI_DCS_CMDS, 0}, + {DSI_PKT_SEQ_0_LO, 0}, + {DSI_PKT_SEQ_1_LO, 0}, + {DSI_PKT_SEQ_2_LO, 0}, + {DSI_PKT_SEQ_3_LO, 0}, + {DSI_PKT_SEQ_4_LO, 0}, + {DSI_PKT_SEQ_5_LO, 0}, + {DSI_PKT_SEQ_0_HI, 0}, + {DSI_PKT_SEQ_1_HI, 0}, + {DSI_PKT_SEQ_2_HI, 0}, + {DSI_PKT_SEQ_3_HI, 0}, + {DSI_PKT_SEQ_4_HI, 0}, + {DSI_PKT_SEQ_5_HI, 0}, + {DSI_CONTROL, 0} +}; +static const reg_cfg_t _di_dsi_init_pads_t210b01[] = { + {DSI_PAD_CONTROL_1, 0}, + {DSI_PAD_CONTROL_2, 0}, + {DSI_PAD_CONTROL_3, 0}, + {DSI_PAD_CONTROL_4, 0}, + {DSI_PAD_CONTROL_5_B01, 0}, + {DSI_PAD_CONTROL_6_B01, 0}, + {DSI_PAD_CONTROL_7_B01, 0} +}; +static const reg_cfg_t _di_dsi_init_config[] = { + {DSI_PAD_CONTROL_CD, 0}, + {DSI_SOL_DELAY, 24}, + {DSI_MAX_THRESHOLD, 480}, + {DSI_TRIGGER, 0}, + {DSI_INIT_SEQ_CONTROL, 0}, + + {DSI_PKT_LEN_0_1, 0}, + {DSI_PKT_LEN_2_3, 0}, + {DSI_PKT_LEN_4_5, 0}, + {DSI_PKT_LEN_6_7, 0}, + + {DSI_PAD_CONTROL_1, 0}, + + /* DSI PHY timings */ + {DSI_PHY_TIMING_0, 0x6070603}, + {DSI_PHY_TIMING_1, 0x40A0E05}, + {DSI_PHY_TIMING_2, 0x30109}, + {DSI_BTA_TIMING, 0x190A14}, + /* DSI timeout */ + {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, + {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, + {DSI_TO_TALLY, 0}, + + {DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Power up. + {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, + {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, + {DSI_POWER_CONTROL, 0}, + {DSI_POWER_CONTROL, 0}, + {DSI_PAD_CONTROL_1, 0}, + + /* DSI PHY timings */ + {DSI_PHY_TIMING_0, 0x6070603}, + {DSI_PHY_TIMING_1, 0x40A0E05}, + {DSI_PHY_TIMING_2, 0x30118}, + {DSI_BTA_TIMING, 0x190A14}, + /* DSI timeout */ + {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, + {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, + {DSI_TO_TALLY, 0}, + + {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, + {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, + {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, + {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, + {DSI_MAX_THRESHOLD, 64}, + {DSI_TRIGGER, 0}, + {DSI_TX_CRC, 0}, + {DSI_INIT_SEQ_CONTROL, 0} +}; + +// DSI panel JDI config. +static const reg_cfg_t _di_dsi_panel_init_config_jdi[] = { + {DSI_WR_DATA, 0x0439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0xBD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x1939}, // MIPI_DSI_DCS_LONG_WRITE: 25 bytes. + {DSI_WR_DATA, 0xAAAAAAD8}, // Register: 0xD8. + {DSI_WR_DATA, 0xAAAAAAEB}, + {DSI_WR_DATA, 0xAAEBAAAA}, + {DSI_WR_DATA, 0xAAAAAAAA}, + {DSI_WR_DATA, 0xAAAAAAEB}, + {DSI_WR_DATA, 0xAAEBAAAA}, + {DSI_WR_DATA, 0xAA}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x01BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 1 to 0xBD. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2739}, // MIPI_DSI_DCS_LONG_WRITE: 39 bytes. + {DSI_WR_DATA, 0xFFFFFFD8}, // Register: 0xD8. + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFF}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x02BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 2 to 0xBD. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0xF39}, // MIPI_DSI_DCS_LONG_WRITE: 15 bytes. + {DSI_WR_DATA, 0xFFFFFFD8}, // Register: 0xD8. + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFFFF}, + {DSI_WR_DATA, 0xFFFFFF}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x06D915}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 6 to 0xD9. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable. + {DSI_TRIGGER, DSI_TRIGGER_HOST} +}; + +// DSI packet config. +static const reg_cfg_t _di_dsi_seq_pkt_video_non_burst_no_eot_config[] = { + {DSI_PAD_CONTROL_1, 0}, + + /* DSI PHY timings */ + {DSI_PHY_TIMING_0, 0x6070603}, + {DSI_PHY_TIMING_1, 0x40A0E05}, + {DSI_PHY_TIMING_2, 0x30172}, + {DSI_BTA_TIMING, 0x190A14}, + /* DSI timeout */ + {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)}, + {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)}, + {DSI_TO_TALLY, 0}, + + {DSI_PKT_SEQ_0_LO, 0x40000208}, + {DSI_PKT_SEQ_2_LO, 0x40000308}, + {DSI_PKT_SEQ_4_LO, 0x40000308}, + {DSI_PKT_SEQ_1_LO, 0x40000308}, + {DSI_PKT_SEQ_3_LO, 0x3F3B2B08}, + {DSI_PKT_SEQ_3_HI, 0x2CC}, + {DSI_PKT_SEQ_5_LO, 0x3F3B2B08}, + {DSI_PKT_SEQ_5_HI, 0x2CC}, + {DSI_PKT_LEN_0_1, PKT1_LEN(206) | PKT0_LEN(0)}, + {DSI_PKT_LEN_2_3, PKT1_LEN(2160) | PKT0_LEN(418)}, + {DSI_PKT_LEN_4_5, PKT1_LEN(0) | PKT0_LEN(400)}, + {DSI_PKT_LEN_6_7, PKT1_LEN(0) | PKT0_LEN(400)}, + {DSI_HOST_CONTROL, 0} +}; + +// DSI mode config. +static const reg_cfg_t _di_dsi_host_mode_config[] = { + {DSI_TRIGGER, 0}, + {DSI_CONTROL, 0}, + {DSI_SOL_DELAY, 6}, + {DSI_MAX_THRESHOLD, 480}, + {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, + {DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, + {DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, + {DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, + {DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_SOL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, + {DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_TX_TRIG_SOL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC} +}; + +// MIPI CAL config. +static const reg_cfg_t _di_mipi_pad_cal_config[] = { + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, + {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0} +}; + +// DSI pad config. +static const reg_cfg_t _di_dsi_pad_cal_config_t210[] = { + {DSI_PAD_CONTROL_1, 0}, + {DSI_PAD_CONTROL_2, 0}, + {DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, + {DSI_PAD_CONTROL_4, 0} +}; +static const reg_cfg_t _di_dsi_pad_cal_config_t210b01[] = { + {DSI_PAD_CONTROL_1, 0}, + {DSI_PAD_CONTROL_2, 0}, + {DSI_PAD_CONTROL_3, 0}, + {DSI_PAD_CONTROL_4, 0x77777}, + {DSI_PAD_CONTROL_5_B01, 0x77777}, + {DSI_PAD_CONTROL_6_B01, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)}, + {DSI_PAD_CONTROL_7_B01, 0} +}; + +// MIPI CAL config. +static const reg_cfg_t _di_mipi_dsi_cal_prod_config_t210[] = { + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002} +}; +static const reg_cfg_t _di_mipi_dsi_cal_prod_config_t210b01[] = { + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006}, + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000} +}; +static const reg_cfg_t _di_mipi_dsi_cal_unused_config[] = { + {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0} +}; + +// Display A enable config. +static const reg_cfg_t _di_dc_video_enable_config[] = { + /* Set panel timings */ + {DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(0)}, + {DC_DISP_REF_TO_SYNC, V_REF_TO_SYNC(1) | H_REF_TO_SYNC(0)}, + {DC_DISP_SYNC_WIDTH, V_SYNC_WIDTH(1) | H_SYNC_WIDTH(72)}, + {DC_DISP_BACK_PORCH, V_BACK_PORCH(9) | H_BACK_PORCH(72)}, + {DC_DISP_FRONT_PORCH, V_FRONT_PORCH(10) | H_FRONT_PORCH(136)}, + {DC_DISP_ACTIVE, V_DISP_ACTIVE(1280) | H_DISP_ACTIVE(720)}, + /* End of Display timings */ + + {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, + {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, + {DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, + {DC_DISP_DISP_CLOCK_CONTROL, 0}, + + /* Start continuous display. */ + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + {DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)}, + {DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + + {DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, // 4: div3. +}; + +// Display A disable config. +static const reg_cfg_t _di_dc_video_disable_config[] = { + {DC_CMD_INT_MASK, 0}, + {DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY}, + {DC_CMD_INT_ENABLE, 0}, + {DC_CMD_CONT_SYNCPT_VSYNC, 0}, + + /* Stop display. */ + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + {DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)}, + {DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, + // TODO: LCD panels should sleep for 40ms here. + {DC_CMD_DISPLAY_POWER_CONTROL, 0}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, +}; + +// DSI deinit config. +static const reg_cfg_t _di_dsi_timing_deinit_config[] = { + {DSI_POWER_CONTROL, 0}, + {DSI_PAD_CONTROL_1, 0}, + + /* DSI PHY timings */ + {DSI_PHY_TIMING_0, 0x6070603}, + {DSI_PHY_TIMING_1, 0x40A0E05}, + {DSI_PHY_TIMING_2, 0x30118}, + {DSI_BTA_TIMING, 0x190A14}, + /* DSI timeout */ + {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, + {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, + {DSI_TO_TALLY, 0}, + + {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, + {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, + {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, + {DSI_MAX_THRESHOLD, 64}, + {DSI_TRIGGER, 0}, + {DSI_TX_CRC, 0}, + {DSI_INIT_SEQ_CONTROL, 0} +}; + +// DSI panel JDI deinit config. +static const reg_cfg_t _di_dsi_panel_deinit_config_jdi[] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2139}, // MIPI_DSI_DCS_LONG_WRITE: 33 bytes. + {DSI_WR_DATA, 0x191919D5}, // Register: 0xD5. + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + {DSI_WR_DATA, 0x4F0F41B1}, // MIPI_DCS_PRIV_SET_POWER_CONTROL. + {DSI_WR_DATA, 0xF179A433}, + {DSI_WR_DATA, 0x002D81}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable. + {DSI_TRIGGER, DSI_TRIGGER_HOST} +}; + +// DSI panel AUO deinit config. +static const reg_cfg_t _di_dsi_panel_deinit_config_auo[] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. + {DSI_WR_DATA, 0x191919D5}, // Register: 0xD5. + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. + {DSI_WR_DATA, 0x191919D6}, // Register: 0xD6. + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + {DSI_WR_DATA, 0x711148B1}, // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + {DSI_WR_DATA, 0x71143209}, + {DSI_WR_DATA, 0x114D31}, // (Unknown). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable. + {DSI_TRIGGER, DSI_TRIGGER_HOST} +}; + +/* +static const reg_cfg_t _di_init_config_invert[] = { + {DSI_WR_DATA, 0x239}, + {DSI_WR_DATA, 0x02C1}, // INV_EN. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, +}; +*/ + +// Display A Window A one color config. +static const reg_cfg_t _di_win_one_color[] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT | WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display. +}; + +// Display A Window A linear pitch config. +static const reg_cfg_t _di_winA_pitch[] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, + {DC_WINBUF_ADDR_V_OFFSET, 0}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +// Display A Window A linear pitch + Win D support config. +static const reg_cfg_t _di_winA_pitch_vic[] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, + {DC_WINBUF_ADDR_V_OFFSET, 0}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +// Display A Window A linear pitch inverse + Win D support config. +static const reg_cfg_t _di_winA_pitch_inv[] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, // Linear: 0x383FFC, Block: 0x3813FC. + {DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0. + {DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +// Display A Window A block linear config. +static const reg_cfg_t _di_winA_block[] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(1280 * 2) | LINE_STRIDE(1280 * 4)}, //720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0x3813FC}, // Linear: 0x383FFC, Block: 0x3813FC. Block in HOS: 0x13FF. + {DC_WINBUF_ADDR_V_OFFSET, 0}, // Linear: 1279, Block: 0. + {DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, // Enable window AD. | SCAN_COLUMN | H_DIRECTION. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +// Display A Window D config. +static const reg_cfg_t _di_winD_log[] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(656 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(656)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(656 * 2) | LINE_STRIDE(656 * 4)}, //656*2x656*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, LOG_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, + {DC_WINBUF_ADDR_V_OFFSET, 0}, + {DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_ENABLE | WIN_K1(200) | WIN_BLEND_DEPTH(0)}, + {DC_WINBUF_BLEND_MATCH_SELECT, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1}, + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_D_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ}, +}; diff --git a/bdk/display/vic.c b/bdk/display/vic.c new file mode 100644 index 0000000..1044448 --- /dev/null +++ b/bdk/display/vic.c @@ -0,0 +1,560 @@ +/* + * VIC driver for Tegra X1 + * + * Copyright (c) 2018-2024 CTCaer + * + * 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 "vic.h" +#include +#include +#include +#include +#include +#include + +/* VIC Private registers */ +#define PVIC_FALCON_PA_OFFSET 0x1000 +#define PVIC_FALCON_ADDR 0x10AC +#define PVIC_FALCON_IDLESTATE 0x104C + +/* VIC Control and Status registers. */ +/* Fetch Control registers. */ +#define VIC_FC_COMPOSE 0x10000 +#define COMPOSE_START BIT(0) + +#define VIC_FC_CFG_STRUCT_SLOT_INDEX 0x10B00 + +#define VIC_FC_CFG_STRUCT_SLOT_CFG0 0x10B04 +#define SLOT_ENABLE BIT(0) +#define FIELD_CURRENT_ENABLE BIT(8) + +#define VIC_FC_CFG_STRUCT_SLOT_CFG2 0x10B0C +#define CACHE_WIDTH(n) ((n) << 16) +#define CACHE_WIDTH_16BX16 0 // Block Linear. +#define CACHE_WIDTH_32BX8 1 // Block Linear. Recommended for Block Linear. +#define CACHE_WIDTH_64BX4 2 // Block Linear, Pitch. Recommended for Pitch. +#define CACHE_WIDTH_128BX2 3 // Block Linear, Pitch. +#define OUTPUT_FLIP_X BIT(20) +#define OUTPUT_FLIP_Y BIT(21) +#define OUTPUT_TRANSPOSE BIT(22) + +#define VIC_FC_CFG_STRUCT_SLOT_SFC_SIZE 0x10B10 +#define VIC_FC_CFG_STRUCT_SLOT_LUMA_SIZE 0x10B14 +#define VIC_FC_CFG_STRUCT_SLOT_CHROMA_SIZE 0x10B18 +#define VIC_FC_CFG_STRUCT_SLOT_SRC_RECT_LR 0x10B1C +#define VIC_FC_CFG_STRUCT_SLOT_SRC_RECT_TB 0x10B20 +#define VIC_FC_CFG_STRUCT_SLOT_DST_RECT_LR 0x10B30 +#define VIC_FC_CFG_STRUCT_SLOT_DST_RECT_TB 0x10B34 +#define VIC_FC_CFG_STRUCT_TGT_RECT_LR 0x10B38 +#define VIC_FC_CFG_STRUCT_TGT_RECT_TB 0x10B3C +#define VIC_FC_SLOT_MAP 0x10C00 + +#define VIC_FC_FCE_CTRL 0x11000 +#define START_TRIGGER BIT(0) +#define HALT_TRIGGER BIT(1) +#define CLEAR_ERROR BIT(8) + +#define VIC_FC_FCE_UCODE_ADDR 0x11200 +#define VIC_FC_FCE_UCODE_INST 0x11300 + +/* Surface List registers. */ +#define VIC_SL_CFG_STRUCT_SLOT_INDEX 0x12100 +#define VIC_SL_CFG_STRUCT_SLOT_DST_RECT_LR 0x12200 +#define VIC_SL_CFG_STRUCT_SLOT_DST_RECT_TB 0x12300 +#define VIC_SL_CFG_STRUCT_TGT_RECT_LR 0x12400 +#define VIC_SL_CFG_STRUCT_TGT_RECT_TB 0x12500 +#define VIC_SL_CFG_STRUCT_SLOT_CFG0 0x12600 + +/* Surface Cache registers. */ +#define VIC_SC_PRAMBASE 0x14000 +#define VIC_SC_PRAMSIZE 0x14100 +#define VIC_SC_SFC0_BASE_LUMA(n) (0x14300 + (n) * 0x100) + +/* Blending Output registers. */ +#define VIC_BL_TARGET_BASADR 0x22000 +#define VIC_BL_CONFIG 0x22800 +#define SUBPARTITION_MODE BIT(0) +#define PROCESS_CFG_STRUCT_TRIGGER BIT(2) +#define SLOTMASK(n) ((n) << 8) + +#define VIC_BL_CFG_STRUCT_CFG0 0x22C00 +#define VIC_BL_CFG_STRUCT_SFC_SIZE 0x22C04 +#define VIC_BL_CFG_STRUCT_LUMA_SIZE 0x22C08 +#define VIC_BL_CFG_STRUCT_CHROMA_SIZE 0x22C0C +#define VIC_BL_CFG_STRUCT_TGT_RECT_LR 0x22C10 +#define VIC_BL_CFG_STRUCT_TGT_RECT_TB 0x22C14 + +// VIC_FC_CFG_STRUCT_SLOT_CFG2 & VIC_BL_CFG_STRUCT_CFG0. +#define BLK_KIND(n) ((n) << 8) +#define BLK_KIND_PITCH 0 +#define BLK_KIND_GENERIC_16BX2 1 +#define BLK_HEIGHT(n) ((n) << 12) +#define BLK_HEIGHT_ONE_GOB 0 +#define BLK_HEIGHT_SIXTEEN_GOBS 4 + +// Generic size macros. +#define SIZE_WIDTH(n) (((n) - 1) << 0) +#define SIZE_HEIGHT(n) (((n) - 1) << 16) +#define RECT_LEFT(n) ((n) << 0) +#define RECT_RIGHT(n) (((n) - 1) << 16) +#define RECT_TOP(n) ((n) << 0) +#define RECT_BOTTOM(n) (((n) - 1) << 16) + +#define FORMAT_PROGRESSIVE 0 +#define SOFT_CLAMP_MIN 0 +#define SOFT_CLAMP_MAX 0x3FFu +#define ALPHA_1_0 0x3FFu + +typedef struct _OutputConfig { + u64 AlphaFillMode:3; + u64 AlphaFillSlot:3; + u64 BackgroundAlpha:10; + u64 BackgroundR:10; + u64 BackgroundG:10; + u64 BackgroundB:10; + u64 RegammaMode:2; + u64 OutputFlipX:1; + u64 OutputFlipY:1; + u64 OutputTranspose:1; + u64 rsvd1:1; + u64 rsvd2:12; + u64 TargetRectLeft:14; + u64 rsvd3:2; + u64 TargetRectRight:14; + u64 rsvd4:2; + u64 TargetRectTop:14; + u64 rsvd5:2; + u64 TargetRectBottom:14; + u64 rsvd6:2; +} OutputConfig; + +typedef struct _OutputSurfaceConfig { + u64 OutPixelFormat:7; + u64 OutChromaLocHoriz:2; + u64 OutChromaLocVert:2; + u64 OutBlkKind:4; + u64 OutBlkHeight:4; + u64 rsvd0:3; + u64 rsvd1:10; + u64 OutSurfaceWidth:14; + u64 OutSurfaceHeight:14; + u64 rsvd2:4; + u64 OutLumaWidth:14; + u64 OutLumaHeight:14; + u64 rsvd3:4; + u64 OutChromaWidth:14; + u64 OutChromaHeight:14; + u64 rsvd4:4; +} OutputSurfaceConfig; + +typedef struct _SlotConfig { + u64 SlotEnable:1; + u64 DeNoise:1; + u64 AdvancedDenoise:1; + u64 CadenceDetect:1; + u64 MotionMap:1; + u64 MMapCombine:1; + u64 IsEven:1; + u64 ChromaEven:1; + u64 CurrentFieldEnable:1; + u64 PrevFieldEnable:1; + u64 NextFieldEnable:1; + u64 NextNrFieldEnable:1; + u64 CurMotionFieldEnable:1; + u64 PrevMotionFieldEnable:1; + u64 PpMotionFieldEnable:1; + u64 CombMotionFieldEnable:1; + u64 FrameFormat:4; + u64 FilterLengthY:2; + u64 FilterLengthX:2; + u64 Panoramic:12; + u64 rsvd1:22; + u64 DetailFltClamp:6; + u64 FilterNoise:10; + u64 FilterDetail:10; + u64 ChromaNoise:10; + u64 ChromaDetail:10; + u64 DeinterlaceMode:4; + u64 MotionAccumWeight:3; + u64 NoiseIir:11; + u64 LightLevel:4; + u64 rsvd4:2; + u64 SoftClampLow:10; + u64 SoftClampHigh:10; + u64 rsvd5:3; + u64 rsvd6:9; + u64 PlanarAlpha:10; + u64 ConstantAlpha:1; + u64 StereoInterleave:3; + u64 ClipEnabled:1; + u64 ClearRectMask:8; + u64 DegammaMode:2; + u64 rsvd7:1; + u64 DecompressEnable:1; + u64 rsvd9:5; + u64 DecompressCtbCount:8; + u64 DecompressZbcColor:32; + u64 rsvd12:24; + u64 SourceRectLeft:30; + u64 rsvd14:2; + u64 SourceRectRight:30; + u64 rsvd15:2; + u64 SourceRectTop:30; + u64 rsvd16:2; + u64 SourceRectBottom:30; + u64 rsvd17:2; + u64 DestRectLeft:14; + u64 rsvd18:2; + u64 DestRectRight:14; + u64 rsvd19:2; + u64 DestRectTop:14; + u64 rsvd20:2; + u64 DestRectBottom:14; + u64 rsvd21:2; + u64 rsvd22:32; + u64 rsvd23:32; +} SlotConfig; + +typedef struct _SlotSurfaceConfig { + u64 SlotPixelFormat:7; + u64 SlotChromaLocHoriz:2; + u64 SlotChromaLocVert:2; + u64 SlotBlkKind:4; + u64 SlotBlkHeight:4; + u64 SlotCacheWidth:3; + u64 rsvd0:10; + u64 SlotSurfaceWidth:14; + u64 SlotSurfaceHeight:14; + u64 rsvd1:4; + u64 SlotLumaWidth:14; + u64 SlotLumaHeight:14; + u64 rsvd2:4; + u64 SlotChromaWidth:14; + u64 SlotChromaHeight:14; + u64 rsvd3:4; +} SlotSurfaceConfig; + +typedef struct _SlotStruct { + SlotConfig slot_cfg; + SlotSurfaceConfig slot_sfc_cfg; + + // No need to configure. Reset to zeros. + u8 lumaKeyStruct[0x10]; + u8 colorMatrixStruct[0x20]; + u8 gamutMatrixStruct[0x20]; + u8 blendingSlotStruct[0x10]; +} SlotStruct; + +typedef struct _vic_config_t { + // No need to configure. Reset to zeros. + u8 pipeConfig[0x10]; + + OutputConfig out_cfg; + OutputSurfaceConfig out_sfc_cfg; + + // No need to configure. Reset to zeros. + u8 out_color_matrix[0x20]; + u8 clear_rect[0x10 * 4]; + + SlotStruct slots[8]; +} vic_config_t; + +// VIC Fetch Control Engine microcode. Dumped from L4T r33. +u8 vic_fce_ucode[] = { + 0x66, 0x00, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x42, 0x40, 0x10, 0x00, 0x4E, 0x01, 0x40, 0x00, + 0x6A, 0x07, 0x00, 0x00, 0x6E, 0x23, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x4E, 0x01, 0x04, 0x00, + 0x6A, 0x0B, 0x00, 0x00, 0x6E, 0x1F, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x4E, 0x01, 0x10, 0x00, + 0x6A, 0x0F, 0x00, 0x00, 0x6E, 0x1F, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x48, 0x80, 0x02, 0x00, + 0x0E, 0x11, 0x00, 0x00, 0x6A, 0x14, 0x00, 0x00, 0x6E, 0x08, 0x06, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x4E, 0x01, 0x08, 0x00, 0x6A, 0x18, 0x00, 0x00, 0x6E, 0x26, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x4E, 0x01, 0x20, 0x00, 0x6A, 0x1C, 0x00, 0x00, 0x6E, 0x26, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x4E, 0x01, 0x02, 0x00, 0x6A, 0x20, 0x00, 0x00, 0x6E, 0x24, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x10, 0x00, 0x56, 0x40, 0x10, 0x00, 0x22, 0x41, 0x01, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x62, 0x80, 0x01, 0x00, 0x60, 0x47, 0x00, 0x00, 0x60, 0x87, 0x00, 0x00, 0x01, 0x4A, 0x00, 0x00, + 0x55, 0xC0, 0x20, 0x00, 0x00, 0x59, 0x00, 0x00, 0x60, 0x87, 0x00, 0x00, 0x60, 0xC7, 0x00, 0x00, + 0x01, 0x93, 0x00, 0x00, 0x40, 0x82, 0x02, 0x00, 0x4E, 0x02, 0x00, 0x00, 0x6B, 0x34, 0x00, 0x00, + 0x43, 0xC1, 0x10, 0x00, 0x42, 0x02, 0x03, 0x00, 0x00, 0x23, 0x01, 0x00, 0x24, 0xD4, 0x00, 0x00, + 0x56, 0x40, 0x3D, 0x00, 0x04, 0xEB, 0x00, 0x00, 0x60, 0x07, 0x01, 0x00, 0x60, 0x47, 0x00, 0x00, + 0x6A, 0x3E, 0x00, 0x00, 0x55, 0xC0, 0x30, 0x00, 0x48, 0x00, 0x01, 0x00, 0x48, 0x40, 0x01, 0x00, + 0x48, 0x80, 0x01, 0x00, 0x6B, 0x28, 0x02, 0x00, 0x56, 0x40, 0x09, 0x00, 0x04, 0x4D, 0x01, 0x00, + 0x06, 0x4D, 0x00, 0x00, 0x42, 0xC0, 0x03, 0x00, 0x56, 0x80, 0x09, 0x00, 0x04, 0xFE, 0x01, 0x00, + 0x00, 0xF9, 0x01, 0x00, 0x4E, 0x02, 0x00, 0x00, 0x6B, 0x32, 0x02, 0x00, 0x55, 0x40, 0x2F, 0x00, + 0x56, 0x80, 0x0D, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x6A, 0x0D, 0x02, 0x00, 0x55, 0x40, 0x31, 0x00, + 0x56, 0x80, 0x0B, 0x00, 0x0C, 0x2B, 0x00, 0x00, 0x6A, 0x13, 0x02, 0x00, 0x43, 0x45, 0x03, 0x00, + 0x42, 0x86, 0x03, 0x00, 0x4D, 0x06, 0x02, 0x00, 0x6A, 0x0D, 0x02, 0x00, 0x42, 0x86, 0x03, 0x00, + 0x22, 0x7E, 0x01, 0x00, 0x4E, 0x04, 0x00, 0x00, 0x6B, 0x32, 0x02, 0x00, 0x55, 0x40, 0x17, 0x00, + 0x0D, 0x2C, 0x00, 0x00, 0x56, 0xC0, 0x09, 0x00, 0x6A, 0x1E, 0x02, 0x00, 0x48, 0xC0, 0x01, 0x00, + 0x43, 0x04, 0x03, 0x00, 0x6C, 0x20, 0x02, 0x00, 0x55, 0x40, 0x19, 0x00, 0x01, 0x2C, 0x01, 0x00, + 0x65, 0x23, 0x01, 0x00, 0x42, 0x42, 0x03, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x24, 0x14, 0x01, 0x00, + 0x00, 0x2C, 0x01, 0x00, 0x24, 0x14, 0x01, 0x00, 0x00, 0x3C, 0x01, 0x00, 0x42, 0x04, 0x09, 0x00, + 0x42, 0xC3, 0x02, 0x00, 0x65, 0x54, 0x01, 0x00, 0x65, 0x55, 0x01, 0x00, 0x42, 0x45, 0x0D, 0x00, + 0x62, 0x03, 0x00, 0x00, 0x62, 0x44, 0x00, 0x00, 0x62, 0x85, 0x00, 0x00, 0x62, 0xC2, 0x00, 0x00, + 0x22, 0x48, 0x1F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x48, 0x00, 0x01, 0x00, 0x6C, 0x28, 0x02, 0x00, + 0x62, 0x80, 0x01, 0x00, 0x60, 0x07, 0x00, 0x00, 0x60, 0x47, 0x00, 0x00, 0x60, 0x87, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x43, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x01, 0xCA, 0x01, 0x00, + 0x60, 0x03, 0x01, 0x00, 0x01, 0xA0, 0x01, 0x00, 0x60, 0x40, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, + 0x55, 0xC0, 0x2E, 0x00, 0x01, 0x18, 0x00, 0x00, 0x43, 0x00, 0x04, 0x00, 0x43, 0x41, 0x06, 0x00, + 0x6F, 0x00, 0x00, 0x00, 0x61, 0xC1, 0x00, 0x00, 0x61, 0x42, 0x01, 0x00, 0x65, 0xB5, 0x00, 0x00, + 0x65, 0x73, 0x01, 0x00, 0x65, 0x35, 0x01, 0x00, 0x65, 0x34, 0x01, 0x00, 0x42, 0x04, 0x0D, 0x00, + 0x01, 0x14, 0x01, 0x00, 0x42, 0x04, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x43, 0x03, 0x05, 0x00, + 0x43, 0x85, 0x02, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x48, 0x46, 0x01, 0x00, 0x65, 0xEB, 0x00, 0x00, + 0x00, 0x9A, 0x00, 0x00, 0x65, 0xB2, 0x01, 0x00, 0x00, 0xA6, 0x01, 0x00, 0x42, 0x86, 0x0D, 0x00, + 0x61, 0x42, 0x01, 0x00, 0x01, 0xAE, 0x01, 0x00, 0x00, 0x71, 0x00, 0x00, 0x42, 0x82, 0x08, 0x00, + 0x42, 0xC3, 0x08, 0x00, 0x48, 0x40, 0x01, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x34, 0x02, 0x00, + 0x65, 0x79, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x6C, 0x36, 0x04, 0x00, 0x6E, 0x34, 0x02, 0x00, + 0x48, 0x7F, 0x01, 0x00, 0x6C, 0x0A, 0x06, 0x00, 0x6E, 0x34, 0x02, 0x00, 0x6E, 0x05, 0x04, 0x00, + 0x65, 0x79, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x41, 0x87, 0x03, 0x00, 0x65, 0xBA, 0x00, 0x00, + 0x65, 0xB2, 0x00, 0x00, 0x42, 0x82, 0x02, 0x00, 0x00, 0x51, 0x00, 0x00, 0x61, 0xC1, 0x00, 0x00, + 0x65, 0xFB, 0x00, 0x00, 0x65, 0xF3, 0x00, 0x00, 0x41, 0x87, 0x05, 0x00, 0x65, 0xF3, 0x00, 0x00, + 0x42, 0xC3, 0x08, 0x00, 0x00, 0x59, 0x00, 0x00, 0x60, 0xC7, 0x00, 0x00, 0x60, 0xC7, 0x00, 0x00, + 0x56, 0xC0, 0x21, 0x00, 0x04, 0xDF, 0x01, 0x00, 0x43, 0xC7, 0x15, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x79, 0x00, 0x00, 0x42, 0xC3, 0x20, 0x00, 0x43, 0xC3, 0x04, 0x00, 0x42, 0x00, 0x30, 0x00, + 0x42, 0x41, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x60, 0xC7, 0x01, 0x00, + 0x22, 0x78, 0x01, 0x00, 0x22, 0x79, 0x03, 0x00, 0x22, 0x7F, 0x1F, 0x00, 0x6F, 0x00, 0x00, 0x00, + 0x6E, 0x34, 0x02, 0x00, 0x6E, 0x05, 0x04, 0x00, 0x4B, 0x41, 0x00, 0x00, 0x60, 0xC7, 0x01, 0x00, + 0x60, 0x87, 0x01, 0x00, 0x43, 0x86, 0x15, 0x00, 0x00, 0x30, 0x00, 0x00, 0x65, 0x39, 0x01, 0x00, + 0x42, 0x04, 0x05, 0x00, 0x4E, 0x05, 0x7E, 0x00, 0x6A, 0x1B, 0x06, 0x00, 0x55, 0xC0, 0x3D, 0x00, + 0x0A, 0x3C, 0x01, 0x00, 0x60, 0xC7, 0x01, 0x00, 0x22, 0x78, 0x01, 0x00, 0x22, 0x79, 0x03, 0x00, + 0x22, 0x7C, 0x09, 0x00, 0x22, 0x7F, 0x1F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x65, 0x7A, 0x01, 0x00, + 0x42, 0x45, 0x05, 0x00, 0x65, 0xBB, 0x01, 0x00, 0x42, 0x86, 0x05, 0x00, 0x55, 0xC0, 0x3D, 0x00, + 0x0A, 0x7D, 0x01, 0x00, 0x0A, 0xBE, 0x01, 0x00, 0x07, 0xC7, 0x01, 0x00, 0x0B, 0x7D, 0x01, 0x00, + 0x0B, 0xBE, 0x01, 0x00, 0x55, 0xC0, 0x3D, 0x00, 0x0A, 0x3C, 0x01, 0x00, 0x60, 0xC7, 0x01, 0x00, + 0x22, 0x78, 0x01, 0x00, 0x22, 0x79, 0x03, 0x00, 0x22, 0x7A, 0x05, 0x00, 0x22, 0x7B, 0x07, 0x00, + 0x22, 0x7C, 0x09, 0x00, 0x22, 0x7D, 0x0B, 0x00, 0x22, 0x7E, 0x0D, 0x00, 0x22, 0x7F, 0x1F, 0x00, + 0x6F, 0x00, 0x00, 0x00 +}; + +vic_config_t __attribute__((aligned (0x100))) vic_cfg = {0}; + +u32 _vic_read_priv(u32 addr) +{ + u32 addr_lsb = addr & 0xFF; + + // Set address LSB. + if (addr_lsb) + VIC(PVIC_FALCON_ADDR) = addr_lsb >> 2; + + // Set address. + u32 val = VIC(PVIC_FALCON_PA_OFFSET + (addr >> 6)); + + // Unset address LSB. + if (addr_lsb) + VIC(PVIC_FALCON_ADDR) = 0; + + return val; +} + +static void _vic_write_priv(u32 addr, u32 data) +{ + u32 addr_lsb = addr & 0xFF; + + // Set address LSB. + if (addr_lsb) + VIC(PVIC_FALCON_ADDR) = addr_lsb >> 2; + + // Set address. + VIC(PVIC_FALCON_PA_OFFSET + (addr >> 6)) = data; + + // Unset address LSB. + if (addr_lsb) + VIC(PVIC_FALCON_ADDR) = 0; +} + +static int _vic_wait_idle() +{ + u32 timeout_count = 15000; // 150ms. + + while (VIC(PVIC_FALCON_IDLESTATE)) + { + usleep(10); + + timeout_count--; + if (!timeout_count) + return -1; + }; + + return 0; +} + +void vic_set_surface(const vic_surface_t *sfc) +{ + u32 flip_x = 0; + u32 flip_y = 0; + u32 swap_xy = 0; + u32 const_alpha = 0; + + u32 width = sfc->width; + u32 height = sfc->height; + u32 pix_fmt = sfc->pix_fmt; + u32 src_buf = sfc->src_buf; + u32 dst_buf = sfc->dst_buf; + + // Get format alpha type. + switch (sfc->pix_fmt) + { + case VIC_PIX_FORMAT_L8: + case VIC_PIX_FORMAT_X1B5G5R5: + case VIC_PIX_FORMAT_B5G5R5X1: + case VIC_PIX_FORMAT_X8B8G8R8: + case VIC_PIX_FORMAT_X8R8G8B8: + case VIC_PIX_FORMAT_B8G8R8X8: + case VIC_PIX_FORMAT_R8G8B8X8: + const_alpha = 1; + break; + + case VIC_PIX_FORMAT_A8B8G8R8: + case VIC_PIX_FORMAT_A8R8G8B8: + case VIC_PIX_FORMAT_B8G8R8A8: + case VIC_PIX_FORMAT_R8G8B8A8: + default: + break; + } + + // Get rotation parameters. + switch (sfc->rotation) + { + case VIC_ROTATION_90: + swap_xy = 1; + break; + + case VIC_ROTATION_180: + flip_x = 1; + flip_y = 1; + break; + + case VIC_ROTATION_270: + flip_x = 1; + swap_xy = 1; + break; + + case VIC_ROTATION_0: + default: + break; + } + + // Set output surface format. + vic_cfg.out_sfc_cfg.OutPixelFormat = pix_fmt; + vic_cfg.out_sfc_cfg.OutBlkKind = BLK_KIND_PITCH; + vic_cfg.out_sfc_cfg.OutBlkHeight = 0; + + // Set output rotation/flip. + vic_cfg.out_cfg.OutputFlipX = flip_x; + vic_cfg.out_cfg.OutputFlipY = flip_y; + vic_cfg.out_cfg.OutputTranspose = swap_xy; + + // Set output surface resolution. + vic_cfg.out_sfc_cfg.OutSurfaceWidth = width - 1; + vic_cfg.out_sfc_cfg.OutSurfaceHeight = height - 1; + vic_cfg.out_sfc_cfg.OutLumaWidth = width - 1; + vic_cfg.out_sfc_cfg.OutLumaHeight = height - 1; + + // Set output destination rectangle. Anything outside will not be touched at output buffer. + vic_cfg.out_cfg.TargetRectLeft = 0; + vic_cfg.out_cfg.TargetRectRight = width - 1; + vic_cfg.out_cfg.TargetRectTop = 0; + vic_cfg.out_cfg.TargetRectBottom = height - 1; + + // Initialize slot parameters. + vic_cfg.slots[0].slot_cfg.SlotEnable = 1; + vic_cfg.slots[0].slot_cfg.SoftClampLow = SOFT_CLAMP_MIN; + vic_cfg.slots[0].slot_cfg.SoftClampHigh = SOFT_CLAMP_MAX; + vic_cfg.slots[0].slot_cfg.PlanarAlpha = ALPHA_1_0; + vic_cfg.slots[0].slot_cfg.ConstantAlpha = const_alpha; + vic_cfg.slots[0].slot_cfg.FrameFormat = FORMAT_PROGRESSIVE; + + // Set input source rectangle. + vic_cfg.slots[0].slot_cfg.SourceRectLeft = 0; + vic_cfg.slots[0].slot_cfg.SourceRectRight = (width - 1) << 16; + vic_cfg.slots[0].slot_cfg.SourceRectTop = 0; + vic_cfg.slots[0].slot_cfg.SourceRectBottom = (height - 1) << 16; + + // Set input destination rectangle. + vic_cfg.slots[0].slot_cfg.DestRectLeft = 0; + vic_cfg.slots[0].slot_cfg.DestRectRight = (width - 1); + vic_cfg.slots[0].slot_cfg.DestRectTop = 0; + vic_cfg.slots[0].slot_cfg.DestRectBottom = (height - 1); + + // Set input surface format. + vic_cfg.slots[0].slot_sfc_cfg.SlotPixelFormat = pix_fmt; + vic_cfg.slots[0].slot_sfc_cfg.SlotBlkKind = BLK_KIND_PITCH; + vic_cfg.slots[0].slot_sfc_cfg.SlotBlkHeight = 0; + vic_cfg.slots[0].slot_sfc_cfg.SlotCacheWidth = CACHE_WIDTH_64BX4; + + // Set input surface resolution. + vic_cfg.slots[0].slot_sfc_cfg.SlotSurfaceWidth = width - 1; + vic_cfg.slots[0].slot_sfc_cfg.SlotSurfaceHeight = height - 1; + vic_cfg.slots[0].slot_sfc_cfg.SlotLumaWidth = width - 1; + vic_cfg.slots[0].slot_sfc_cfg.SlotLumaHeight = height - 1; + + // Flush data. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false); + + // Set parameters base and size. Causes a parse by surface cache. + _vic_write_priv(VIC_SC_PRAMBASE, (u32)&vic_cfg >> 8); + _vic_write_priv(VIC_SC_PRAMSIZE, sizeof(vic_config_t) >> 6); + + // Wait for surface cache to get ready. + _vic_wait_idle(); + + // Set slot mapping. + _vic_write_priv(VIC_FC_SLOT_MAP, 0xFFFFFFF0); + + // Set input surface buffer. + _vic_write_priv(VIC_SC_SFC0_BASE_LUMA(0), src_buf >> 8); + + // Set output surface buffer. + _vic_write_priv(VIC_BL_TARGET_BASADR, dst_buf >> 8); + + // Set blending config and push changes to surface cache. + _vic_write_priv(VIC_BL_CONFIG, SLOTMASK(0x1F) | PROCESS_CFG_STRUCT_TRIGGER | SUBPARTITION_MODE); + + // Wait for surface cache to get ready. + _vic_wait_idle(); +} + +int vic_compose() +{ + // Wait for surface cache to get ready. Otherwise VIC will hang. + int res = _vic_wait_idle(); + + // Start composition of a single frame. + _vic_write_priv(VIC_FC_COMPOSE, COMPOSE_START); + + return res; +} + +int vic_init() +{ + clock_enable_vic(); + + // Load Fetch Control Engine microcode. + for (u32 i = 0; i < sizeof(vic_fce_ucode) / sizeof(u32); i++) + { + _vic_write_priv(VIC_FC_FCE_UCODE_ADDR, (i * sizeof(u32))); + _vic_write_priv(VIC_FC_FCE_UCODE_INST, *(u32 *)&vic_fce_ucode[i * sizeof(u32)]); + } + + // Start Fetch Control Engine. + _vic_write_priv(VIC_FC_FCE_CTRL, START_TRIGGER); + + return _vic_wait_idle(); +} + +void vic_end() +{ + clock_disable_vic(); +} diff --git a/bdk/display/vic.h b/bdk/display/vic.h new file mode 100644 index 0000000..20fbe6c --- /dev/null +++ b/bdk/display/vic.h @@ -0,0 +1,66 @@ +/* + * VIC driver for Tegra X1 + * + * Copyright (c) 2018-2019 CTCaer + * + * 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 _VIC_H_ +#define _VIC_H_ + +#include + +#define VIC_THI_SLCG_OVERRIDE_LOW_A 0x8C + +typedef enum _vic_rotation_t +{ + VIC_ROTATION_0 = 0, + VIC_ROTATION_90 = 1, + VIC_ROTATION_180 = 2, + VIC_ROTATION_270 = 3, +} vic_rotation_t; + +typedef enum _vic_pix_format_t +{ + VIC_PIX_FORMAT_L8 = 1, // 8-bit LUT. + VIC_PIX_FORMAT_X1B5G5R5 = 21, // 16-bit XBGR. + VIC_PIX_FORMAT_B5G5R5X1 = 23, // 16-bit BGRX. + + VIC_PIX_FORMAT_A8B8G8R8 = 31, // 32-bit ABGR. + VIC_PIX_FORMAT_A8R8G8B8 = 32, // 32-bit ARGB. + VIC_PIX_FORMAT_B8G8R8A8 = 33, // 32-bit BGRA. + VIC_PIX_FORMAT_R8G8B8A8 = 34, // 32-bit RGBA. + + VIC_PIX_FORMAT_X8B8G8R8 = 35, // 32-bit XBGR. + VIC_PIX_FORMAT_X8R8G8B8 = 36, // 32-bit XRGB. + VIC_PIX_FORMAT_B8G8R8X8 = 37, // 32-bit BGRX. + VIC_PIX_FORMAT_R8G8B8X8 = 38, // 32-bit RGBX. +} vic_pix_format_t; + +typedef struct _vic_surface_t +{ + u32 src_buf; + u32 dst_buf; + u32 width; + u32 height; + u32 pix_fmt; + u32 rotation; +} vic_surface_t; + +void vic_set_surface(const vic_surface_t *sfc); +int vic_compose(); +int vic_init(); +void vic_end(); + +#endif diff --git a/bdk/exception_handlers.S b/bdk/exception_handlers.S new file mode 100644 index 0000000..2f38bb3 --- /dev/null +++ b/bdk/exception_handlers.S @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2019 CTCaer + * + * 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 . + */ + +/* + * Armv7tdmi Status register. + * + * bit0: Mode 0. + * bit1: Mode 1. + * bit2: Mode 2. + * bit3: Mode 3. + * bit4: Mode 4. + * bit5: Thumb state. + * bit6: FIQ disable. + * bit7: IRQ disable. + * bit8-27: Reserved. + * bit28: Overflow condition. + * bit29: Carry/Borrow/Extend condition. + * bit30: Zero condition. + * bit31: Negative/Less than condition. + * + * M[4:0] | Mode | Visible Thumb-state registers | Visible ARM-state registers + * 10000 | USER | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR + * 10001 | FIQ | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7, r8_fiq–r14_fiq, PC, CPSR, SPSR_fiq + * 10010 | IRQ | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq + * 10011 | SVC | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc + * 10111 | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt + * 11011 | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und + * 11111 | SYS | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR + */ + +#define EXCP_EN_ADDR 0x4003FFFC +#define EXCP_TYPE_ADDR 0x4003FFF8 +#define EXCP_LR_ADDR 0x4003FFF4 + +#define EXCP_VEC_BASE 0x6000F000 +#define EVP_COP_RESET_VECTOR 0x200 +#define EVP_COP_UNDEF_VECTOR 0x204 +#define EVP_COP_SWI_VECTOR 0x208 +#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C +#define EVP_COP_DATA_ABORT_VECTOR 0x210 +#define EVP_COP_RSVD_VECTOR 0x214 +#define EVP_COP_IRQ_VECTOR 0x218 +#define EVP_COP_FIQ_VECTOR 0x21C + +#define MODE_USR 0x10 +#define MODE_FIQ 0x11 +#define MODE_IRQ 0x12 +#define MODE_SVC 0x13 +#define MODE_ABT 0x17 +#define MODE_UDF 0x1B +#define MODE_SYS 0x1F +#define MODE_MASK 0x1F + +#define FIQ 0x40 +#define IRQ 0x80 + +.section .text._irq_setup +.arm + +.extern ipl_main +.type ipl_main, %function + +.extern svc_handler +.type svc_handler, %function + +.extern irq_handler +.type irq_handler, %function + +.extern fiq_setup +.type fiq_setup, %function + +.extern fiq_handler +.type fiq_handler, %function + +.globl _irq_setup +.type _irq_setup, %function +_irq_setup: + MRS R0, CPSR + BIC R0, R0, #MODE_MASK /* Clear mode bits */ + ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */ + MSR CPSR, R0 + + /* Setup IRQ stack pointer */ + MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */ + LDR SP, =0x40040000 + + /* Setup FIQ stack pointer */ + MSR CPSR, #(MODE_FIQ | IRQ | FIQ) /* FIQ mode, IRQ/FIQ disabled */ + LDR SP, =0x40040000 + + /* Setup SYS stack pointer */ + MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */ + LDR SP, =0x4003FF00 /* Will be changed later to DRAM */ + + MOV LR, PC + BL setup_vectors + /*BL fiq_setup*/ + + /* Enable interrupts */ + BL irq_enable_cpu_irq_exceptions + + B ipl_main + B . + +.globl excp_reset +.type excp_reset, %function +excp_reset: + LDR R0, =EXCP_EN_ADDR + LDR R1, =0x30505645 /* EVP0 */ + STR R1, [R0] /* EVP0 in EXCP_EN_ADDR */ + LDR R0, =EXCP_LR_ADDR + MOV R1, LR + STR R1, [R0] /* Save LR in EXCP_LR_ADDR */ + LDR R0, =__bss_start + EOR R1, R1, R1 + LDR R2, =__bss_end + SUB R2, R2, R0 + BL memset + B _irq_setup + +_reset_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x545352 /* RST */ + STR R1, [R0] /* RST in EXCP_TYPE_ADDR */ + B excp_reset + +_undefined_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x464455 /* UDF */ + STR R1, [R0] /* UDF in EXCP_TYPE_ADDR */ + B excp_reset + +_prefetch_abort_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x54424150 /* PABT */ + STR R1, [R0] /* PABT in EXCP_TYPE_ADDR */ + B excp_reset + +_data_abort_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x54424144 /* DABT */ + STR R1, [R0] /* DABT in EXCP_TYPE_ADDR */ + B excp_reset + +.globl irq_enable_cpu_irq_exceptions +.type irq_enable_cpu_irq_exceptions, %function +irq_enable_cpu_irq_exceptions: + MRS R12, CPSR + BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */ + MSR CPSR, R12 + BX LR + +.globl irq_disable_cpu_irq_exceptions +.type irq_disable_cpu_irq_exceptions, %function +irq_disable_cpu_irq_exceptions: + MRS R12, CPSR + ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */ + MSR CPSR, R12 + BX LR + +_irq_handler: + MOV R13, R0 /* Save R0 in R13_IRQ */ + SUB R0, LR, #4 /* Put return address in R0_SYS */ + MOV LR, R1 /* Save R1 in R14_IRQ (LR) */ + MRS R1, SPSR /* Put the SPSR in R1_SYS */ + + MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */ + STMFD SP!, {R0, R1} /* SPSR and PC */ + STMFD SP!, {R2-R3, R12, LR} /* AAPCS-clobbered registers */ + MOV R0, SP /* Make SP_SYS visible to IRQ mode */ + SUB SP, SP, #8 /* Make room for stacking R0 and R1 */ + + MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */ + STMFD R0!, {R13, R14} /* Finish saving the context (R0, R1) */ + + MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */ + LDR R12, =irq_handler + MOV LR, PC /* Copy the return address to link register */ + BX R12 /* Call the C IRQ handler (ARM/THUMB) */ + + MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */ + MOV R0, SP /* Make SP_SYS visible to IRQ mode */ + ADD SP, SP, #32 /* Fake unstacking 8 registers from SP_SYS */ + + MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */ + MOV SP, R0 /* Copy SP_SYS to SP_IRQ */ + LDR R0, [SP, #28] /* Load the saved SPSR from the stack */ + MSR SPSR_cxsf, R0 /* Copy it into SPSR_IRQ */ + + LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */ + NOP /* Cant access barked registers immediately */ + LDR LR, [SP, #24] /* Load return address from the SYS stack */ + MOVS PC, LR /* Return restoring CPSR from SPSR */ + +_fiq_handler: + BL fiq_handler + +setup_vectors: + /* Setup vectors */ + LDR R0, =EXCP_VEC_BASE + + LDR R1, =_reset_handler + STR R1, [R0, #EVP_COP_RESET_VECTOR] + + LDR R1, =_undefined_handler + STR R1, [R0, #EVP_COP_UNDEF_VECTOR] + + LDR R1, =_reset_handler + STR R1, [R0, #EVP_COP_SWI_VECTOR] + + LDR R1, =_prefetch_abort_handler + STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR] + + LDR R1, =_data_abort_handler + STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR] + + LDR R1, =_reset_handler + STR R1, [R0, #EVP_COP_RSVD_VECTOR] + + LDR R1, =_irq_handler + STR R1, [R0, #EVP_COP_IRQ_VECTOR] + + LDR R1, =_fiq_handler + STR R1, [R0, #EVP_COP_FIQ_VECTOR] + + BX LR diff --git a/bootloader/hos/sept.h b/bdk/fatfs_cfg.h similarity index 68% rename from bootloader/hos/sept.h rename to bdk/fatfs_cfg.h index 8cfc8af..77b26dd 100644 --- a/bootloader/hos/sept.h +++ b/bdk/fatfs_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,12 +14,15 @@ * along with this program. If not, see . */ -#ifndef _SEPT_H_ -#define _SEPT_H_ +#ifndef _FATFS_CFG_H_ +#define _FATFS_CFG_H_ -#include "../utils/types.h" - -void check_sept(ini_sec_t *cfg_sec); -int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec); +// define FFCFG_INC in a project to use a specific FatFS configuration. +// Example: FFCFG_INC := '"../$(PROJECT_DIR)/libs/fatfs/ffconf.h"' +#ifdef FFCFG_INC +#include FFCFG_INC +#else +#include "fatfs_conf.h" +#endif #endif diff --git a/bdk/fatfs_conf.h b/bdk/fatfs_conf.h new file mode 100644 index 0000000..e87219d --- /dev/null +++ b/bdk/fatfs_conf.h @@ -0,0 +1,305 @@ +/*---------------------------------------------------------------------------/ +/ FatFs Functional Configurations +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 86604 /* 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 1 +/* 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) */ + +#if FF_USE_MKFS +#define FF_MKFS_LABEL "SWITCH SD " +#endif +/* This sets FAT/FAT32 label. Exactly 11 characters, all caps. */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + +#define FF_FASTFS 0 +#if FF_FASTFS +#undef FF_USE_FASTSEEK +#define FF_USE_FASTSEEK 1 +#endif +/* This option switches fast access to chained clusters. (0:Disable or 1:Enable) */ + + +#define FF_SIMPLE_GPT 1 +/* This option switches support for the first GPT partition. (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 1 +/* 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 3 +#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) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) +/ +/ 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 support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table needs to be defined as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +/ Order is important. Any change to order, must also be reflected to diskio drive enum. +*/ + + +#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 1 +/* 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 1 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ 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 2022 +/* The option FF_FS_NORTC switches timestamp function. 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. Every object 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. */ + + +/* #include // O/S definitions */ +#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. */ + + + +/*--- End of configuration options ---*/ diff --git a/nyx/nyx_gui/soc/cluster.h b/bdk/gfx_utils.h similarity index 81% rename from nyx/nyx_gui/soc/cluster.h rename to bdk/gfx_utils.h index 428c046..ca81a7f 100644 --- a/nyx/nyx_gui/soc/cluster.h +++ b/bdk/gfx_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,11 +14,11 @@ * along with this program. If not, see . */ -#ifndef _CLUSTER_H_ -#define _CLUSTER_H_ +#ifndef _GFX_UTILS_H_ +#define _GFX_UTILS_H_ -#include "../utils/types.h" - -void cluster_boot_cpu0(u32 entry); +#ifdef GFX_INC +#include GFX_INC +#endif #endif diff --git a/nyx/nyx_gui/libs/elfload/elf.h b/bdk/ianos/elfload/elf.h similarity index 96% rename from nyx/nyx_gui/libs/elfload/elf.h rename to bdk/ianos/elfload/elf.h index 196cf87..2a7111e 100644 --- a/nyx/nyx_gui/libs/elfload/elf.h +++ b/bdk/ianos/elfload/elf.h @@ -29,33 +29,34 @@ #ifndef ELF_H #define ELF_H -#include -typedef uint8_t Elf_Byte; +#include -typedef uint32_t Elf32_Addr; /* Unsigned program address */ -typedef uint32_t Elf32_Off; /* Unsigned file offset */ -typedef int32_t Elf32_Sword; /* Signed large integer */ -typedef uint32_t Elf32_Word; /* Unsigned large integer */ -typedef uint16_t Elf32_Half; /* Unsigned medium integer */ +typedef u8 Elf_Byte; -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Shalf; +typedef u32 Elf32_Addr; /* Unsigned program address */ +typedef u32 Elf32_Off; /* Unsigned file offset */ +typedef s32 Elf32_Sword; /* Signed large integer */ +typedef u32 Elf32_Word; /* Unsigned large integer */ +typedef u16 Elf32_Half; /* Unsigned medium integer */ + +typedef u64 Elf64_Addr; +typedef u64 Elf64_Off; +typedef s32 Elf64_Shalf; #ifdef __alpha__ -typedef int64_t Elf64_Sword; -typedef uint64_t Elf64_Word; +typedef s64 Elf64_Sword; +typedef u64 Elf64_Word; #else -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; +typedef s32 Elf64_Sword; +typedef u32 Elf64_Word; #endif -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Xword; +typedef s64 Elf64_Sxword; +typedef u64 Elf64_Xword; -typedef uint32_t Elf64_Half; -typedef uint16_t Elf64_Quarter; +typedef u32 Elf64_Half; +typedef u16 Elf64_Quarter; /* * e_ident[] identification indexes @@ -376,7 +377,7 @@ typedef struct #define ELF64_R_SYM(info) ((info) >> 32) #define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF) -#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t)) +#define ELF64_R_INFO(s, t) (((s) << 32) + (u32)(t)) #if defined(__mips64__) && defined(__MIPSEL__) /* @@ -389,7 +390,7 @@ typedef struct #undef ELF64_R_INFO #define ELF64_R_TYPE(info) (swap32((info) >> 32)) #define ELF64_R_SYM(info) ((info)&0xFFFFFFFF) -#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s)) +#define ELF64_R_INFO(s, t) (((u64)swap32(t) << 32) + (u32)(s)) #endif /* __mips64__ && __MIPSEL__ */ /* Program Header */ @@ -444,7 +445,7 @@ typedef struct /* Dynamic structure */ typedef struct { - Elf32_Sword d_tag; /* controls meaning of d_val */ + Elf32_Word d_tag; /* controls meaning of d_val */ union { Elf32_Word d_val; /* Multiple meanings - see d_tag */ Elf32_Addr d_ptr; /* program virtual address */ diff --git a/bootloader/libs/elfload/elfarch.h b/bdk/ianos/elfload/elfarch.h similarity index 100% rename from bootloader/libs/elfload/elfarch.h rename to bdk/ianos/elfload/elfarch.h diff --git a/bootloader/libs/elfload/elfload.c b/bdk/ianos/elfload/elfload.c similarity index 95% rename from bootloader/libs/elfload/elfload.c rename to bdk/ianos/elfload/elfload.c index 16f8200..daf561a 100644 --- a/bootloader/libs/elfload/elfload.c +++ b/bdk/ianos/elfload/elfload.c @@ -25,7 +25,7 @@ el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset) } #define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize)) -el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i) +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, u32 type, unsigned *i) { el_status rv = EL_OK; for (; *i < ctx->ehdr.e_phnum; (*i)++) @@ -44,7 +44,7 @@ el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i) } #define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize)) -el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i) +el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, u32 type, unsigned *i) { el_status rv = EL_OK; @@ -213,7 +213,7 @@ el_status el_load(el_ctx *ctx, el_alloc_cb alloc) return rv; } -el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag) +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, u32 tag) { el_status rv = EL_OK; size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn); @@ -231,7 +231,7 @@ el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag) return EL_OK; } -el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type) +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, u32 type) { el_status rv = EL_OK; diff --git a/nyx/nyx_gui/libs/elfload/elfload.h b/bdk/ianos/elfload/elfload.h similarity index 90% rename from nyx/nyx_gui/libs/elfload/elfload.h rename to bdk/ianos/elfload/elfload.h index 3a15dc2..0a73e05 100644 --- a/nyx/nyx_gui/libs/elfload/elfload.h +++ b/bdk/ianos/elfload/elfload.h @@ -22,10 +22,8 @@ #include "elfarch.h" #include "elf.h" -#include "../../utils/types.h" - #ifdef DEBUG -#include "../../gfx/gfx.h" +#include #define EL_DEBUG(format, ...) \ gfx_printf(format __VA_OPT__(, ) __VA_ARGS__) #else @@ -100,7 +98,7 @@ el_status el_load(el_ctx *ctx, el_alloc_cb alloccb); * If the end of the phdrs table was reached, *i is set to -1 and the contents * of *phdr are undefined */ -el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i); +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, u32 type, unsigned *i); /* Relocate the loaded executable */ el_status el_relocate(el_ctx *ctx); @@ -108,7 +106,7 @@ el_status el_relocate(el_ctx *ctx); /* find a dynamic table entry * returns the entry on success, dyn->d_tag = DT_NULL on failure */ -el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type); +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, u32 type); typedef struct { @@ -122,6 +120,6 @@ typedef struct * pass DT_REL or DT_RELA for type * sets ri->entrysize = 0 if not found */ -el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type); +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, u32 type); #endif diff --git a/nyx/nyx_gui/libs/elfload/elfreloc_aarch64.c b/bdk/ianos/elfload/elfreloc_aarch64.c similarity index 85% rename from nyx/nyx_gui/libs/elfload/elfreloc_aarch64.c rename to bdk/ianos/elfload/elfreloc_aarch64.c index bbb0ce4..736ad46 100644 --- a/nyx/nyx_gui/libs/elfload/elfreloc_aarch64.c +++ b/bdk/ianos/elfload/elfreloc_aarch64.c @@ -23,9 +23,9 @@ el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel) { - uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); - uint32_t type = ELF_R_TYPE(rel->r_info); - uint32_t sym = ELF_R_SYM(rel->r_info); + uptr *p = (uptr *)(rel->r_offset + ctx->base_load_paddr); + u32 type = ELF_R_TYPE(rel->r_info); + u32 sym = ELF_R_SYM(rel->r_info); switch (type) { @@ -53,9 +53,9 @@ el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel) el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) { - uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); - uint32_t type = ELF_R_TYPE(rel->r_info); - uint32_t sym = ELF_R_SYM(rel->r_info); + uptr *p = (uptr *)(rel->r_offset + ctx->base_load_paddr); + u32 type = ELF_R_TYPE(rel->r_info); + u32 sym = ELF_R_SYM(rel->r_info); switch (type) { diff --git a/nyx/nyx_gui/libs/elfload/elfreloc_arm.c b/bdk/ianos/elfload/elfreloc_arm.c similarity index 86% rename from nyx/nyx_gui/libs/elfload/elfreloc_arm.c rename to bdk/ianos/elfload/elfreloc_arm.c index 8b905cb..77ce654 100644 --- a/nyx/nyx_gui/libs/elfload/elfreloc_arm.c +++ b/bdk/ianos/elfload/elfreloc_arm.c @@ -20,9 +20,9 @@ el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) { - uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset - uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type - uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr + u32 sym = ELF_R_SYM(rel->r_info); // Symbol offset + u32 type = ELF_R_TYPE(rel->r_info); // Relocation Type + uptr *p = (uptr *)(rel->r_offset + ctx->base_load_paddr); // Target Addr #if 0 // For later symbol usage Elf32_Sym *elfSym; diff --git a/bootloader/ianos/ianos.c b/bdk/ianos/ianos.c similarity index 77% rename from bootloader/ianos/ianos.c rename to bdk/ianos/ianos.c index 18d4165..99a996d 100644 --- a/bootloader/ianos/ianos.c +++ b/bdk/ianos/ianos.c @@ -18,33 +18,36 @@ #include #include "ianos.h" -#include "../utils/types.h" -#include "../libs/elfload/elfload.h" -#include "../../common/common_module.h" -#include "../mem/heap.h" -#include "../gfx/gfx.h" +#include "elfload/elfload.h" +#include +#include +#include +#include +#include + +#include #define IRAM_LIB_ADDR 0x4002B000 #define DRAM_LIB_ADDR 0xE0000000 extern heap_t _heap; -extern void *sd_file_read(const char *path, u32 *fsize); -extern bool sd_mount(); -extern void sd_unmount(); - void *elfBuf = NULL; void *fileBuf = NULL; static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig) { bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t)); - bdkParameters->gfxCon = &gfx_con; - bdkParameters->gfxCtx = &gfx_ctxt; + bdkParameters->gfxCon = (void *)&gfx_con; + bdkParameters->gfxCtx = (void *)&gfx_ctxt; bdkParameters->memcpy = (memcpy_t)&memcpy; bdkParameters->memset = (memset_t)&memset; bdkParameters->sharedHeap = &_heap; + // Extra functions. + bdkParameters->extension_magic = IANOS_EXT0; + bdkParameters->reg_voltage_set = (reg_voltage_set_t)&max7762x_regulator_set_voltage; + entrypoint(moduleConfig, bdkParameters); } @@ -66,30 +69,21 @@ static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t o } //TODO: Support shared libraries. -uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig) +uintptr_t ianos_loader(char *path, elfType_t type, void *moduleConfig) { + el_ctx ctx; uintptr_t epaddr = 0; - if (sdmount) - { - if (!sd_mount()) - goto elfLoadFinalOut; - } - + // Read library. fileBuf = sd_file_read(path, NULL); - if (sdmount) - sd_unmount(); - if (!fileBuf) - goto elfLoadFinalOut; + goto out; - - el_ctx ctx; ctx.pread = _ianos_read_cb; if (el_init(&ctx)) - goto elfLoadFinalOut; + goto out; // Set our relocated library's buffer. switch (type & 0xFFFF) @@ -97,22 +91,21 @@ uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleCon case EXEC_ELF: case AR64_ELF: elfBuf = (void *)DRAM_LIB_ADDR; - sd_unmount(); break; default: elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default. } if (!elfBuf) - goto elfLoadFinalOut; + goto out; // Load and relocate library. ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf; if (el_load(&ctx, _ianos_alloc_cb)) - goto elfFreeOut; + goto out_free; if (el_relocate(&ctx)) - goto elfFreeOut; + goto out_free; // Launch. epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf; @@ -120,12 +113,11 @@ uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleCon _ianos_call_ep(ep, moduleConfig); -elfFreeOut: +out_free: free(fileBuf); elfBuf = NULL; fileBuf = NULL; -elfLoadFinalOut: - +out: return epaddr; } \ No newline at end of file diff --git a/nyx/nyx_gui/ianos/ianos.h b/bdk/ianos/ianos.h similarity index 89% rename from nyx/nyx_gui/ianos/ianos.h rename to bdk/ianos/ianos.h index 74d02c1..5ebec64 100644 --- a/nyx/nyx_gui/ianos/ianos.h +++ b/bdk/ianos/ianos.h @@ -18,7 +18,7 @@ #ifndef IANOS_H #define IANOS_H -#include "../utils/types.h" +#include typedef enum { @@ -29,6 +29,6 @@ typedef enum KEEP_IN_RAM = (1 << 31) // Shared library mask. } elfType_t; -uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config); +uintptr_t ianos_loader(char *path, elfType_t type, void* config); #endif \ No newline at end of file diff --git a/bdk/input/als.c b/bdk/input/als.c new file mode 100644 index 0000000..277f0d5 --- /dev/null +++ b/bdk/input/als.c @@ -0,0 +1,154 @@ +/* + * Ambient light sensor driver for Nintendo Switch's Rohm BH1730 + * + * Copyright (c) 2018 CTCaer + * + * 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 "als.h" +#include +#include +#include +#include +#include + +#define BH1730_DEFAULT_GAIN BH1730_GAIN_64X +#define BH1730_DEFAULT_ICYCLE 38 + +#define BH1730_INTERNAL_CLOCK_NS 2800 +#define BH1730_ADC_CALC_DELAY_US 2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */ +#define BH1730_ITIME_CYCLE_TO_US 2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */ + +#define BH1730_DEFAULT_ITIME_MS 100 + +#define BH1730_LUX_MULTIPLIER 3600 +#define BH1730_LUX_MULTIPLIER_AULA 1410 + +#define BH1730_LUX_MAX 100000 + +typedef struct _opt_win_cal_t +{ + u32 rc; + u32 cv; + u32 ci; +} opt_win_cal_t; + +// Nintendo Switch Icosa/Iowa Optical Window calibration. +static const opt_win_cal_t opt_win_cal_default[] = { + { 500, 5002, 7502 }, + { 754, 2250, 2000 }, + { 1029, 1999, 1667 }, + { 1373, 884, 583 }, + { 1879, 309, 165 } +}; + +// Nintendo Switch Aula Optical Window calibration. +static const opt_win_cal_t opt_win_cal_aula[] = { + { 231, 9697, 30300 }, + { 993, 3333, 2778 }, + { 1478, 1621, 1053 }, + { 7500, 81, 10 } +}; + +static const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 }; + +void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle) +{ + if (gain > BH1730_GAIN_128X) + gain = BH1730_GAIN_128X; + + if (!cycle) + cycle = 1; + + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle)); + + als_ctxt->gain = gain; + als_ctxt->cycle = cycle; +} + +void get_als_lux(als_ctxt_t *als_ctxt) +{ + u32 data[2]; + u32 vi_light; + u32 ir_light; + u64 lux = 0; + u32 itime_us = BH1730_ITIME_CYCLE_TO_US * als_ctxt->cycle; + + // Get visible and ir light raw data. Mode is continuous so waiting for new values doesn't matter. + data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) + + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8); + data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) + + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8); + + vi_light = data[0]; + ir_light = data[1]; + + als_ctxt->vi_light = vi_light; + als_ctxt->ir_light = ir_light; + als_ctxt->over_limit = vi_light > 65534 || ir_light > 65534; + + if (!vi_light) + { + als_ctxt->lux = 0; + + return; + } + + // Set calibration parameters. + u32 lux_multiplier = BH1730_LUX_MULTIPLIER; + u32 opt_win_cal_count = ARRAY_SIZE(opt_win_cal_default); + const opt_win_cal_t *opt_win_cal = opt_win_cal_default; + + // Apply optical window calibration coefficients. + for (u32 i = 0; i < opt_win_cal_count; i++) + { + if (1000 * ir_light / vi_light < opt_win_cal[i].rc) + { + lux = ((u64)opt_win_cal[i].cv * data[0]) - (opt_win_cal[i].ci * data[1]); + break; + } + } + + lux *= BH1730_DEFAULT_ITIME_MS * lux_multiplier; + lux /= als_gain_idx_tbl[als_ctxt->gain] * itime_us; + lux /= 1000; + + if (lux > BH1730_LUX_MAX) + lux = BH1730_LUX_MAX; + + als_ctxt->lux = lux; +} + +u8 als_power_on(als_ctxt_t *als_ctxt) +{ + // Enable power to ALS IC. + max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000); + max7762x_regulator_enable(REGULATOR_LDO6, true); + + // Init I2C2. + pinmux_config_i2c(I2C_2); + clock_enable_i2c(I2C_2); + i2c_init(I2C_2); + + // Initialize ALS. + u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); + + set_als_cfg(als_ctxt, BH1730_DEFAULT_GAIN, BH1730_DEFAULT_ICYCLE); + + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN); + + return id; +} diff --git a/nyx/nyx_gui/input/als.h b/bdk/input/als.h similarity index 84% rename from nyx/nyx_gui/input/als.h rename to bdk/input/als.h index 11f1e5e..0ce0956 100644 --- a/nyx/nyx_gui/input/als.h +++ b/bdk/input/als.h @@ -19,7 +19,7 @@ #ifndef __ALS_H_ #define __ALS_H_ -#include "../utils/types.h" +#include #define BH1730_I2C_ADDR 0x29 @@ -45,21 +45,21 @@ #define BH1730_DATA1LOW_REG 0x16 #define BH1730_DATA1HIGH_REG 0x17 -#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | reg) -#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | cmd) +#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg)) +#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd)) -typedef struct _als_table_t +typedef struct _als_ctxt_t { - float lux; + u32 lux; bool over_limit; - u32 vi_light; - u32 ir_light; - u8 gain; - u8 itime; -} als_table_t; + u32 vi_light; + u32 ir_light; + u8 gain; + u8 cycle; +} als_ctxt_t; -void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime); -void get_als_lux(als_table_t *als_val); -u8 als_init(als_table_t *als_val); +void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle); +void get_als_lux(als_ctxt_t *als_ctxt); +u8 als_power_on(als_ctxt_t *als_ctxt); #endif /* __ALS_H_ */ diff --git a/bdk/input/joycon.c b/bdk/input/joycon.c new file mode 100644 index 0000000..5e3243e --- /dev/null +++ b/bdk/input/joycon.c @@ -0,0 +1,1274 @@ +/* + * Joy-Con UART driver for Nintendo Switch + * + * Copyright (c) 2019-2024 CTCaer + * + * 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 "joycon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// For disabling driver when logging is enabled. +#include + +#define JC_WIRED_CMD 0x91 +#define JC_WIRED_HID 0x92 +#define JC_WIRED_INIT_REPLY 0x94 +#define JC_INIT_HANDSHAKE 0xA5 + +#define JC_HORI_INPUT_RPT_CMD 0x9A +#define JC_HORI_INPUT_RPT 0x00 + +#define JC_WIRED_CMD_GET_INFO 0x01 +#define JC_WIRED_CMD_SET_CHARGER 0x02 +#define JC_WIRED_CMD_GET_CHARGER 0x03 +#define JC_WIRED_CMD_BATT_VOLT 0x06 +#define JC_WIRED_CMD_WAKE_REASON 0x07 +#define JC_WIRED_CMD_HID_CONN 0x10 +#define JC_WIRED_CMD_HID_DISC 0x11 +#define JC_WIRED_CMD_SET_HIDRATE 0x12 // Output report rate. +#define JC_WIRED_CMD_SET_BRATE 0x20 + +#define JC_HID_OUTPUT_RPT 0x01 +#define JC_HID_RUMBLE_RPT 0x10 + +#define JC_HID_INPUT_RPT 0x30 +#define JC_HID_SUBMCD_RPT 0x21 + +#define JC_HID_SUBCMD_HCI_STATE 0x06 +#define HCI_STATE_SLEEP 0x00 +#define HCI_STATE_RECONNECT 0x01 +#define HCI_STATE_PAIR 0x02 +#define HCI_STATE_HOME 0x04 +#define JC_HID_SUBCMD_SPI_READ 0x10 +#define SPI_READ_OFFSET 0x20 +#define JC_HID_SUBCMD_RUMBLE_CTL 0x48 +#define JC_HID_SUBCMD_SND_RUMBLE 0xFF + +#define JC_SIO_OUTPUT_RPT 0x91 +#define JC_SIO_INPUT_RPT 0x92 +#define JC_SIO_CMD_ACK 0x80 + +#define JC_SIO_CMD_INIT 0x01 +#define JC_SIO_CMD_UNK02 0x02 +#define JC_SIO_CMD_VER_RPT 0x03 +#define JC_SIO_CMD_UNK20 0x20 // JC_WIRED_CMD_SET_BRATE +#define JC_SIO_CMD_UNK21 0x21 +#define JC_SIO_CMD_UNK22 0x22 +#define JC_SIO_CMD_UNK40 0x40 +#define JC_SIO_CMD_STATUS 0x41 +#define JC_SIO_CMD_IAP_VER 0x42 + + +#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status. +#define JC_BTN_MASK_R 0x0056FF + +#define JC_ID_L 0x01 // Joycon (L). Mask for Hori (L). +#define JC_ID_R 0x02 // Joycon (R). Mask for Hori (R). +#define JC_ID_HORI 0x20 // Mask for Hori. Actual ids: 0x21, 0x22. + +#define JC_CRC8_POLY 0x8D + +enum +{ + JC_STATE_START = 0, + JC_STATE_HANDSHAKED = 1, + JC_STATE_BRATE_CHANGED = 2, + JC_STATE_BRATE_OK = 3, + JC_STATE_INIT_DONE = 4 +}; + +enum +{ + JC_BATT_EMTPY = 0, + JC_BATT_CRIT = 1, + JC_BATT_LOW = 2, + JC_BATT_MID = 3, + JC_BATT_FULL = 4 +}; + +static const u8 sio_init[] = { + JC_SIO_OUTPUT_RPT, JC_SIO_CMD_INIT, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x95 +}; + +static const u8 sio_set_rpt_version[] = { + JC_SIO_OUTPUT_RPT, JC_SIO_CMD_VER_RPT, + // old fw: 0x00, 0x0D (0.13). New 3.4. + // force_update_en: 0x01 + 0x00, 0x00, 0x03, 0x04, 0x00, 0xDA +}; + +// Every 8ms. +static const u8 sio_pad_status[] = { + JC_SIO_OUTPUT_RPT, JC_SIO_CMD_STATUS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0 +}; + +static const u8 init_wake[] = { + 0xA1, 0xA2, 0xA3, 0xA4 +}; + +static const u8 init_handshake[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_INIT_HANDSHAKE, 0x02, // Wired cmd and wired subcmd. + 0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data and crc. +}; + +static const u8 init_get_info[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_GET_INFO, // Wired cmd and subcmd. + 0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data and crc. +}; + +static const u8 init_switch_brate[] = { + 0x19, 0x01, 0x03, 0x0F, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_SET_BRATE, // Wired cmd and subcmd. + 0x08, 0x00, 0x00, 0xBD, 0xB1, // Wired subcmd data, data crc and crc. + // Baudrate 3 megabaud. + 0xC0, 0xC6, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 init_hid_disconnect[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_HID_DISC, // Wired cmd and subcmd. + 0x00, 0x00, 0x00, 0x00, 0x0E // Wired subcmd data and crc. +}; + +static const u8 init_set_hid_rate[] = { + 0x19, 0x01, 0x03, 0x0B, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_SET_HIDRATE, // Wired cmd and subcmd. + 0x04, 0x00, 0x00, 0x12, 0xA6, // Wired subcmd data, data crc and crc. + // Output report rate 15 ms. + 0x0F, 0x00, 0x00, 0x00 + + // 5 ms. + // 0x04, 0x00, 0x00, 0x0E, 0xD5, + // 0x05, 0x00, 0x00, 0x00 +}; + +static const u8 init_hid_connect[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_HID_CONN, // Wired cmd and subcmd. + 0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data and crc. +}; + +static const u8 nx_pad_status[] = { + 0x19, 0x01, 0x03, 0x08, 0x00, // Uart header. + JC_WIRED_HID, 0x00, // Wired cmd and hid cmd. + 0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data, data crc and crc. +}; + +static const u8 hori_pad_status[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_HORI_INPUT_RPT_CMD, 0x01, // Hori cmd and hori subcmd. + 0x00, 0x00, 0x00, 0x00, 0x48 // Hori cmd data and crc. +}; + +typedef struct _jc_uart_hdr_t +{ + u8 magic[3]; + u8 total_size_lsb; + u8 total_size_msb; +} jc_uart_hdr_t; + +typedef struct _jc_wired_hdr_t +{ + jc_uart_hdr_t uart_hdr; + u8 cmd; + u8 data[5]; + u8 crc; + u8 payload[]; +} jc_wired_hdr_t; + +typedef struct _jc_hid_out_rpt_t +{ + u8 cmd; + u8 pkt_id; + u8 rumble[8]; + u8 subcmd; + u8 subcmd_data[]; +} jc_hid_out_rpt_t; + +typedef struct _jc_hid_out_spi_read_t +{ + u32 addr; + u8 size; +} jc_hid_out_spi_read_t; + +typedef struct _jc_hid_in_rpt_t +{ + u8 cmd; + u8 pkt_id; + u8 conn_info:4; // Connection detect. + u8 batt_info:4; // Power info. + u8 btn_right; + u8 btn_shared; + u8 btn_left; + u8 stick_h_left; + u8 stick_m_left; + u8 stick_v_left; + u8 stick_h_right; + u8 stick_m_right; + u8 stick_v_right; + u8 vib_decider; // right:4, left:4 (bit3 en, bit2-0 buffer avail). + u8 submcd_ack; + u8 subcmd; + u8 subcmd_data[]; +} jc_hid_in_rpt_t; + +typedef struct _jc_hid_in_spi_read_t +{ + u32 addr; + u8 size; + u8 data[]; +} jc_hid_in_spi_read_t; + +typedef struct _jc_hid_in_pair_data_t +{ + u8 magic; + u8 size; + u16 checksum; + u8 mac[6]; + u8 ltk[16]; + u8 pad0[10]; + u8 bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported + u8 pad1; +} jc_hid_in_pair_data_t; + +typedef struct _jc_sio_out_rpt_t +{ + u8 cmd; + u8 subcmd; + u16 payload_size; + u8 data[2]; + u8 crc_payload; + u8 crc_hdr; + u8 payload[]; +} jc_sio_out_rpt_t; + +typedef struct _jc_sio_in_rpt_t +{ + u8 cmd; + u8 ack; + u16 payload_size; + u8 status; + u8 unk; + u8 crc_payload; + u8 crc_hdr; + u8 payload[]; +} jc_sio_in_rpt_t; + +typedef struct _jc_hid_in_sixaxis_rpt_t +{ + s16 acc_x; + s16 acc_y; + s16 acc_z; + s16 gyr_x; + s16 gyr_y; + s16 gyr_z; +} __attribute__((packed)) jc_hid_in_sixaxis_rpt_t; + +typedef struct _jc_sio_hid_in_rpt_t +{ + u8 type; + u8 pkt_id; + u8 unk; + u8 btn_right; + u8 btn_shared; + u8 btn_left; + u8 stick_h_left; + u8 stick_m_left; + u8 stick_v_left; + u8 stick_h_right; + u8 stick_m_right; + u8 stick_v_right; + u8 siaxis_rpt; // bit0-3: report num. bit4-7: imu type. + // Each report is 800 us? + jc_hid_in_sixaxis_rpt_t sixaxis[15]; +} jc_sio_hid_in_rpt_t; + +typedef struct _joycon_ctxt_t +{ + u8 buf[0x100]; //FIXME: If heap is used, dumping breaks. + u8 uart; + u8 type; + u8 state; + u32 last_received_time; + u32 last_status_req_time; + u8 mac[6]; + u8 pkt_id; + u8 rumble_sent; + u8 connected; + u8 detected; + u8 sio_mode; +} joycon_ctxt_t; + +static joycon_ctxt_t jc_l = {0}; +static joycon_ctxt_t jc_r = {0}; + +static bool jc_init_done = false; + +static jc_gamepad_rpt_t jc_gamepad; + +static u8 _jc_crc(const u8 *data, u16 len, u8 init) +{ + u8 crc = init; + for (u16 i = 0; i < len; i++) + { + crc ^= data[i]; + for (u16 j = 0; j < 8; j++) + { + if ((crc & 0x80) != 0) + crc = (u8)((crc << 1) ^ JC_CRC8_POLY); + else + crc <<= 1; + } + } + return crc; +} + +static void _jc_power_supply(u8 uart, bool enable) +{ + if (enable) + { + if (regulator_5v_get_dev_enabled(1 << uart)) + return; + + regulator_5v_enable(1 << uart); + + if (jc_gamepad.sio_mode) + return; + + if (jc_init_done) + { + if (uart == UART_C) + gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH); + else + gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH); + return; + } + + if (uart == UART_C) + { + // Joy-Con(L) Charge Enable. + PINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1; + gpio_direction_output(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH); + } + else + { + // Joy-Con(R) Charge Enable. + PINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2; + gpio_direction_output(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH); + } + } + else + { + if (!regulator_5v_get_dev_enabled(1 << uart)) + return; + + regulator_5v_disable(1 << uart); + + if (jc_gamepad.sio_mode) + return; + + if (uart == UART_C) + gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW); + else + gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW); + } +} + +static void _jc_detect() +{ + if (!jc_gamepad.sio_mode) + { + // Turn on Joy-Con detect. (UARTB/C TX). UART CTS also if HW flow control and irq is enabled. + PINMUX_AUX(PINMUX_AUX_UART2_TX) = PINMUX_INPUT_ENABLE; + PINMUX_AUX(PINMUX_AUX_UART3_TX) = PINMUX_INPUT_ENABLE; + gpio_direction_input(GPIO_PORT_G, GPIO_PIN_0); + gpio_direction_input(GPIO_PORT_D, GPIO_PIN_1); + usleep(20); + + //! HW BUG: Unlatch gpio buffer. + (void)gpio_read(GPIO_PORT_H, GPIO_PIN_6); + (void)gpio_read(GPIO_PORT_E, GPIO_PIN_6); + + // Read H6/E6 which are shared with UART TX pins. + jc_r.detected = !gpio_read(GPIO_PORT_H, GPIO_PIN_6); + jc_l.detected = !gpio_read(GPIO_PORT_E, GPIO_PIN_6); + + // Turn off Joy-Con detect. (UARTB/C TX). + PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; + PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + usleep(20); + } + else + { + //! TODO: Is there a way to detect a broken Sio? + jc_l.detected = true; + } +} + +static void _jc_conn_check() +{ + _jc_detect(); + + if (jc_gamepad.sio_mode) + return; + + // Check if a Joy-Con was disconnected. + if (!jc_l.detected) + { + if (jc_l.connected) + _jc_power_supply(UART_C, false); + + jc_l.pkt_id = 0; + + jc_l.connected = false; + jc_l.rumble_sent = false; + + jc_gamepad.conn_l = false; + + jc_gamepad.batt_info_l = 0; + jc_gamepad.bt_conn_l.type = 0; + jc_gamepad.buttons &= ~JC_BTN_MASK_L; + } + + if (!jc_r.detected) + { + if (jc_r.connected) + _jc_power_supply(UART_B, false); + + jc_r.pkt_id = 0; + + jc_r.connected = false; + jc_r.rumble_sent = false; + + jc_gamepad.conn_r = false; + + jc_gamepad.batt_info_r = 0; + jc_gamepad.bt_conn_r.type = 0; + jc_gamepad.buttons &= ~JC_BTN_MASK_R; + } +} + +static void _joycon_send_raw(u8 uart_port, const u8 *buf, u16 size) +{ + uart_send(uart_port, buf, size); + uart_wait_xfer(uart_port, UART_TX_IDLE); +} + +static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, const u8 *data, u16 size, bool crc) +{ + out->uart_hdr.magic[0] = 0x19; + out->uart_hdr.magic[1] = 0x01; + out->uart_hdr.magic[2] = 0x3; + + out->uart_hdr.total_size_lsb = sizeof(jc_wired_hdr_t) - sizeof(jc_uart_hdr_t); + out->uart_hdr.total_size_msb = 0; + out->cmd = wired_cmd; + + if (data) + memcpy(out->data, data, size); + + out->crc = crc ? _jc_crc(&out->uart_hdr.total_size_msb, + sizeof(out->uart_hdr.total_size_msb) + + sizeof(out->cmd) + sizeof(out->data), 0) : 0; + + return sizeof(jc_wired_hdr_t); +} + +static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, const u8 *payload, u16 size, bool crc) +{ + u16 pkt_size = _jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0, crc); + pkt_size += size; + + rpt->uart_hdr.total_size_lsb += size; + rpt->data[0] = size >> 8; + rpt->data[1] = size & 0xFF; + + if (payload) + memcpy(rpt->payload, payload, size); + + return pkt_size; +} + +static void _jc_send_hid_output_rpt(joycon_ctxt_t *jc, jc_hid_out_rpt_t *hid_pkt, u16 size, bool crc) +{ + u8 rpt[0x50]; + memset(rpt, 0, sizeof(rpt)); + + hid_pkt->pkt_id = (jc->pkt_id++ & 0xF); + u32 rpt_size = _jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, (u8 *)hid_pkt, size, crc); + + _joycon_send_raw(jc->uart, rpt, rpt_size); +} + +static void _jc_send_hid_cmd(joycon_ctxt_t *jc, u8 subcmd, const u8 *data, u16 size) +{ + static const u8 rumble_neutral[8] = { 0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40 }; + static const u8 rumble_init[8] = { 0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72 }; + + u8 temp[0x30] = {0}; + + jc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp; + memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral)); + + if (subcmd == JC_HID_SUBCMD_SND_RUMBLE) + { + bool send_r_rumble = jc_r.connected && !jc_r.rumble_sent; + bool send_l_rumble = jc_l.connected && !jc_l.rumble_sent; + + // Enable rumble. + hid_pkt->cmd = JC_HID_OUTPUT_RPT; + hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL; + hid_pkt->subcmd_data[0] = 1; + if (send_r_rumble) + _jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false); + if (send_l_rumble) + _jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false); + + // Send rumble. + hid_pkt->cmd = JC_HID_RUMBLE_RPT; + memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init)); + if (send_r_rumble) + _jc_send_hid_output_rpt(&jc_r, hid_pkt, 10, false); + if (send_l_rumble) + _jc_send_hid_output_rpt(&jc_l, hid_pkt, 10, false); + + msleep(15); + + // Disable rumble. + hid_pkt->cmd = JC_HID_OUTPUT_RPT; + hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL; + hid_pkt->subcmd_data[0] = 0; + memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral)); + if (send_r_rumble) + _jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false); + if (send_l_rumble) + _jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false); + } + else + { + bool crc_needed = jc->type & JC_ID_HORI; + + hid_pkt->cmd = JC_HID_OUTPUT_RPT; + hid_pkt->subcmd = subcmd; + if (data) + memcpy(hid_pkt->subcmd_data, data, size); + + _jc_send_hid_output_rpt(jc, hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed); + } +} + +static void _jc_charging_decider(u8 batt, u8 uart) +{ + u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000; + + // Power supply control based on battery levels and charging. + if ((batt >> 1) < JC_BATT_LOW) // Level without checking charging. + _jc_power_supply(uart, true); + else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID) << 1) // Addresses the charging bit. + _jc_power_supply(uart, false); +} + +static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8 *packet, int size) +{ + u32 btn_tmp; + jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet; + + switch (hid_pkt->cmd) + { + case JC_HORI_INPUT_RPT: + if (!(jc->type & JC_ID_HORI)) + return; + + case JC_HID_INPUT_RPT: + // Discard incomplete hid packets. + if (size < 12) + break; + + btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16; + + if (jc->type & JC_ID_L) + { + jc_gamepad.buttons &= ~JC_BTN_MASK_L; + jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L); + + jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8); + jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4); + + jc_gamepad.batt_info_l = hid_pkt->batt_info; + } + else if (jc->type & JC_ID_R) + { + jc_gamepad.buttons &= ~JC_BTN_MASK_R; + jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R); + + jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8); + jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4); + + jc_gamepad.batt_info_r = hid_pkt->batt_info; + } + + jc_gamepad.conn_l = jc_l.connected; + jc_gamepad.conn_r = jc_r.connected; + + if (hid_pkt->cmd == JC_HID_INPUT_RPT) + _jc_charging_decider(hid_pkt->batt_info, jc->uart); + break; + case JC_HID_SUBMCD_RPT: + if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ) + { + jc_bt_conn_t *bt_conn; + + if (jc->type & JC_ID_L) + bt_conn = &jc_gamepad.bt_conn_l; + else + bt_conn = &jc_gamepad.bt_conn_r; + + jc_hid_in_spi_read_t *spi_info = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data; + jc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data; + + // Check if the reply is pairing info. + if (spi_info->size == 0x1A && pair_data->magic == 0x95 && pair_data->size == 0x22) + { + bt_conn->type = jc->type; + + memcpy(bt_conn->mac, jc->mac, 6); + memcpy(bt_conn->host_mac, pair_data->mac, 6); + for (u32 i = 16; i > 0; i--) + bt_conn->ltk[16 - i] = pair_data->ltk[i - 1]; + } + } + break; + default: + break; + } +} + +static void _jc_parse_wired_init(joycon_ctxt_t *jc, const u8 *data, int size) +{ + // Discard empty packets. + if (size <= 0) + return; + + switch (data[0]) + { + case JC_WIRED_CMD_GET_INFO: + for (int i = 12; i > 6; i--) + jc->mac[12 - i] = data[i]; + jc->type = data[6]; + jc->connected = true; + break; + case JC_WIRED_CMD_SET_BRATE: + jc->state = JC_STATE_BRATE_CHANGED; + break; + case JC_WIRED_CMD_HID_DISC: + jc->state = JC_STATE_BRATE_OK; + break; + case JC_WIRED_CMD_HID_CONN: + case JC_WIRED_CMD_SET_HIDRATE: + // done. + default: + break; + } +} + +static void _jc_uart_pkt_parse(joycon_ctxt_t *jc, const jc_wired_hdr_t *pkt, int size) +{ + switch (pkt->cmd) + { + case JC_HORI_INPUT_RPT_CMD: + case JC_WIRED_HID: + _jc_parse_wired_hid(jc, pkt->payload, size - sizeof(jc_wired_hdr_t)); + break; + case JC_WIRED_INIT_REPLY: + _jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1); + break; + case JC_INIT_HANDSHAKE: + jc->state = JC_STATE_HANDSHAKED; + break; + default: + break; + } + + jc->last_received_time = get_tmr_ms(); +} + +static void _jc_sio_parse_payload(joycon_ctxt_t *jc, u8 cmd, const u8 *payload, int size) +{ + switch (cmd) + { + case JC_SIO_CMD_STATUS: + // Discard incomplete packets. + if (size < 12) + break; + + jc_sio_hid_in_rpt_t *hid_pkt = (jc_sio_hid_in_rpt_t *)payload; + jc_gamepad.buttons = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16; + jc_gamepad.home = !gpio_read(GPIO_PORT_V, GPIO_PIN_3); + + jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8); + jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4); + jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8); + jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4); + + jc_gamepad.batt_info_l = jc_l.connected; + jc_gamepad.batt_info_r = gpio_read(GPIO_PORT_E, GPIO_PIN_7); // Set IRQ status. + + jc_gamepad.conn_l = jc_l.connected; + jc_gamepad.conn_r = jc_l.connected; + break; + default: + break; + } +} + +static void _jc_sio_uart_pkt_parse(joycon_ctxt_t *jc, const jc_sio_in_rpt_t *pkt, int size) +{ + if (pkt->crc_hdr != _jc_crc((u8 *)pkt, sizeof(jc_sio_in_rpt_t) - 1, 0)) + return; + + u8 cmd = pkt->ack & (~JC_SIO_CMD_ACK); + switch (cmd) + { + case JC_SIO_CMD_INIT: + jc->connected = pkt->status == 0; + break; + case JC_SIO_CMD_VER_RPT: + if (jc->connected) + jc->connected = pkt->status == 0; + break; + case JC_SIO_CMD_IAP_VER: + case JC_SIO_CMD_STATUS: + _jc_sio_parse_payload(jc, cmd, pkt->payload, size - sizeof(jc_sio_in_rpt_t)); + break; + case JC_SIO_CMD_UNK02: + case JC_SIO_CMD_UNK20: + case JC_SIO_CMD_UNK21: + case JC_SIO_CMD_UNK22: + case JC_SIO_CMD_UNK40: + default: + break; + } + + jc->last_received_time = get_tmr_ms(); +} + +static void _jc_rcv_pkt(joycon_ctxt_t *jc) +{ + if (!jc->detected) + return; + + u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0x100); + if (len < 8) + return; + + // For Joycon, check uart reply magic. + jc_wired_hdr_t *jc_pkt = (jc_wired_hdr_t *)jc->buf; + if (!jc->sio_mode && !memcmp(jc_pkt->uart_hdr.magic, "\x19\x81\x03", 3)) + { + _jc_uart_pkt_parse(jc, jc_pkt, len); + + return; + } + + // For Sio, check uart output report and command ack. + jc_sio_in_rpt_t *sio_pkt = (jc_sio_in_rpt_t *)(jc->buf); + if (jc->sio_mode && sio_pkt->cmd == JC_SIO_INPUT_RPT && (sio_pkt->ack & JC_SIO_CMD_ACK) == JC_SIO_CMD_ACK) + { + _jc_sio_uart_pkt_parse(jc, sio_pkt, len); + + return; + } +} + +static bool _jc_send_init_rumble(joycon_ctxt_t *jc) +{ + // Send init rumble or request nx pad status report. + if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent)) + { + _jc_send_hid_cmd(jc, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0); + + if (jc_l.connected) + jc_l.rumble_sent = true; + if (jc_r.connected) + jc_r.rumble_sent = true; + + return 1; + } + + return 0; +} + +static void _jc_req_nx_pad_status(joycon_ctxt_t *jc) +{ + if (!jc->detected) + return; + + bool is_nxpad = !(jc->type & JC_ID_HORI) && !jc->sio_mode; + + if (jc->last_status_req_time > get_tmr_ms() || !jc->connected) + return; + + if (is_nxpad) + { + bool sent_rumble = _jc_send_init_rumble(jc); + + if (sent_rumble) + return; + } + + if (is_nxpad) + _joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status)); + else if (jc->sio_mode) + _joycon_send_raw(jc->uart, sio_pad_status, sizeof(sio_pad_status)); + else + _joycon_send_raw(jc->uart, hori_pad_status, sizeof(hori_pad_status)); + + jc->last_status_req_time = get_tmr_ms() + (!jc->sio_mode ? 15 : 7); +} + +static bool _jc_validate_pairing_info(const u8 *buf, bool *is_hos) +{ + u8 crc = 0; + for (u32 i = 0; i < 0x22; i++) + crc += buf[4 + i]; + + crc += 0x68; // Host is Switch. + + if ((crc ^ 0x55) == buf[2]) + *is_hos = true; + + crc -= 0x68; + crc += 0x08; // Host is PC. + + if (*is_hos || (crc ^ 0x55) == buf[2]) + return true; + + return false; +} + +jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos) +{ + u8 retries; + jc_bt_conn_t *bt_conn; + + if (!jc_init_done || jc_gamepad.sio_mode) + return NULL; + + bt_conn = &jc_gamepad.bt_conn_l; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + + bt_conn = &jc_gamepad.bt_conn_r; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + + _jc_conn_check(); + + while (jc_l.last_status_req_time > get_tmr_ms()) + { + _jc_rcv_pkt(&jc_r); + _jc_rcv_pkt(&jc_l); + } + + jc_hid_in_spi_read_t subcmd_data_l; + subcmd_data_l.addr = 0x2000; + subcmd_data_l.size = 0x1A; + + jc_hid_in_spi_read_t subcmd_data_r; + subcmd_data_r.addr = 0x2000; + subcmd_data_r.size = 0x1A; + + bool jc_r_found = jc_r.connected ? false : true; + bool jc_l_found = jc_l.connected ? false : true; + + // Set mode to HW controlled RTS. + uart_set_mode(jc_l.uart, UART_AO_TX_HW_RX); + uart_set_mode(jc_r.uart, UART_AO_TX_HW_RX); + + u32 total_retries = 10; +retry: + retries = 10; + while (retries) + { + u32 time_now = get_tmr_ms(); + if ((!jc_l_found && jc_l.last_status_req_time < time_now) || (!jc_r_found && jc_r.last_status_req_time < time_now)) + { + if (!jc_l_found) + { + _jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5); + jc_l.last_status_req_time = get_tmr_ms() + 15; + } + + if (!jc_r_found) + { + _jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5); + jc_r.last_status_req_time = get_tmr_ms() + 15; + } + + retries--; + } + + // Wait for the first 36 bytes to arrive. + msleep(5); + + if (!jc_l_found) + { + memset(jc_l.buf, 0, 0x100); + _jc_rcv_pkt(&jc_l); + + bool is_hos = false; + if (_jc_validate_pairing_info(&jc_l.buf[SPI_READ_OFFSET], &is_hos)) + { + bool is_active = jc_l.buf[SPI_READ_OFFSET] == 0x95; + + if (!is_active) + subcmd_data_l.addr += 0x26; // Get next slot. + else + jc_l_found = true; // Entry is active. + + if (jc_l_found && is_hos) + *is_l_hos = true; + } + } + + if (!jc_r_found) + { + memset(jc_r.buf, 0, 0x100); + _jc_rcv_pkt(&jc_r); + + bool is_hos = false; + if (_jc_validate_pairing_info(&jc_r.buf[SPI_READ_OFFSET], &is_hos)) + { + bool is_active = jc_r.buf[SPI_READ_OFFSET] == 0x95; + + if (!is_active) + subcmd_data_r.addr += 0x26; // Get next slot. + else + jc_r_found = true; // Entry is active. + + if (jc_r_found && is_hos) + *is_r_hos = true; + } + } + + if (jc_l_found && jc_r_found) + break; + } + + if (!jc_l_found || !jc_r_found) + { + if (total_retries) + { + total_retries--; + goto retry; + } + + if (!jc_l_found) + { + bt_conn = &jc_gamepad.bt_conn_l; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + } + + if (!jc_r_found) + { + bt_conn = &jc_gamepad.bt_conn_r; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + } + } + + // Restore mode to manual RTS. + uart_set_mode(jc_l.uart, UART_AO_TX_MN_RX); + uart_set_mode(jc_r.uart, UART_AO_TX_MN_RX); + + return &jc_gamepad; +} + +static void _jc_init_conn(joycon_ctxt_t *jc) +{ + if (!jc->detected) + return; + + if (((u32)get_tmr_ms() - jc->last_received_time) > 1000) + { + _jc_power_supply(jc->uart, true); + + // Mask out buttons and set connected to false. + if (jc->uart == UART_B) + { + jc_gamepad.buttons &= ~JC_BTN_MASK_R; + jc_gamepad.conn_r = false; + } + else + { + jc_gamepad.buttons &= ~JC_BTN_MASK_L; + jc_gamepad.conn_l = false; + } + + // Initialize uart to 1 megabaud and manual RTS. + uart_init(jc->uart, 1000000, UART_AO_TX_MN_RX); + + if (!jc->sio_mode) + { + jc->state = JC_STATE_START; + + // Set TX and RTS inversion for Joycon. + uart_invert(jc->uart, true, UART_INVERT_TXD | UART_INVERT_RTS); + + // Wake up the controller. + _joycon_send_raw(jc->uart, init_wake, sizeof(init_wake)); + _jc_rcv_pkt(jc); // Clear RX FIFO. + + // Do a handshake. + u32 retries = 10; + while (retries && jc->state != JC_STATE_HANDSHAKED) + { + _joycon_send_raw(jc->uart, init_handshake, sizeof(init_handshake)); + msleep(5); + _jc_rcv_pkt(jc); + retries--; + } + + if (jc->state != JC_STATE_HANDSHAKED) + goto out; + + // Get info about the controller. + _joycon_send_raw(jc->uart, init_get_info, sizeof(init_get_info)); + msleep(2); + _jc_rcv_pkt(jc); + + if (!(jc->type & JC_ID_HORI)) + { + // Request 3 megabaud change. + _joycon_send_raw(jc->uart, init_switch_brate, sizeof(init_switch_brate)); + msleep(2); + _jc_rcv_pkt(jc); + + if (jc->state == JC_STATE_BRATE_CHANGED) + { + // Reinitialize uart to 3 megabaud and manual RTS. + uart_init(jc->uart, 3000000, UART_AO_TX_MN_RX); + uart_invert(jc->uart, true, UART_INVERT_TXD | UART_INVERT_RTS); + + // Disconnect HID. + retries = 10; + while (retries && jc->state != JC_STATE_BRATE_OK) + { + _joycon_send_raw(jc->uart, init_hid_disconnect, sizeof(init_hid_disconnect)); + msleep(5); + _jc_rcv_pkt(jc); + retries--; + } + + if (jc->state != JC_STATE_BRATE_OK) + goto out; + } + + // Create HID connection with the new rate. + _joycon_send_raw(jc->uart, init_hid_connect, sizeof(init_hid_connect)); + msleep(2); + _jc_rcv_pkt(jc); + + // Set hid packet rate. + _joycon_send_raw(jc->uart, init_set_hid_rate, sizeof(init_set_hid_rate)); + msleep(2); + _jc_rcv_pkt(jc); + } + else // Hori. Unset RTS inversion. + uart_invert(jc->uart, false, UART_INVERT_RTS); + } + else + { + // Set Sio NPOR low to configure BOOT0 mode. + gpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW); + usleep(300); + gpio_write(GPIO_PORT_T, GPIO_PIN_0, GPIO_LOW); + gpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_HIGH); + msleep(100); + + // Clear RX FIFO. + _jc_rcv_pkt(jc); + + // Initialize the controller. + u32 retries = 10; + while (!jc->connected && retries) + { + _joycon_send_raw(jc->uart, sio_init, sizeof(sio_init)); + msleep(5); + _jc_rcv_pkt(jc); + retries--; + } + + if (!jc->connected) + goto out; + + // Set output report version. + _joycon_send_raw(jc->uart, sio_set_rpt_version, sizeof(sio_set_rpt_version)); + msleep(5); + _jc_rcv_pkt(jc); + } + + // Initialization done. + jc->state = JC_STATE_INIT_DONE; + +out: + jc->last_received_time = get_tmr_ms(); + + if (!jc->sio_mode && jc->connected && !(jc->type & JC_ID_HORI)) + _jc_power_supply(jc->uart, false); + } +} + +void jc_init_hw() +{ + jc_l.uart = UART_C; + jc_r.uart = UART_B; + + jc_l.sio_mode = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG; + jc_gamepad.sio_mode = jc_l.sio_mode; + +#if !defined(DEBUG_UART_PORT) || !(DEBUG_UART_PORT) + _jc_power_supply(UART_C, true); + _jc_power_supply(UART_B, true); + + // Sio Initialization. + if (jc_gamepad.sio_mode) + { + // Enable 4 MHz clock to Sio. + clock_enable_extperiph2(); + PINMUX_AUX(PINMUX_AUX_TOUCH_CLK) = PINMUX_PULL_DOWN; + + // Configure Sio HOME BUTTON. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO1) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 1; + gpio_direction_input(GPIO_PORT_V, GPIO_PIN_3); + + // Configure Sio IRQ + PINMUX_AUX(PINMUX_AUX_GPIO_PE7) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP; + gpio_direction_input(GPIO_PORT_E, GPIO_PIN_7); + + // Configure Sio NRST and BOOT0. + PINMUX_AUX(PINMUX_AUX_CAM1_STROBE) = PINMUX_PULL_DOWN | 1; + PINMUX_AUX(PINMUX_AUX_CAM2_PWDN) = PINMUX_PULL_DOWN | 1; + + // Set BOOT0 to flash mode. (output high is sram mode). + gpio_direction_output(GPIO_PORT_T, GPIO_PIN_0, GPIO_LOW); + + // NRST to pull down. + gpio_direction_input(GPIO_PORT_T, GPIO_PIN_1); + + // Configure Sio NPOR. + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) = PINMUX_IO_HV | PINMUX_LPDR | 1; + gpio_direction_output(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW); + } + +#if 0 // Already set by hw init. + // Set Joy-Con IsAttached pinmux. Shared with UARTB/UARTC TX. + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + + // Set Joy-Con IsAttached mode. Shared with UARTB/UARTC TX. + gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); +#endif + + // Configure pinmuxing for UART B and C. + if (!jc_gamepad.sio_mode) + pinmux_config_uart(UART_B); + pinmux_config_uart(UART_C); + + // Enable UART B and C clocks. + if (!jc_gamepad.sio_mode) + clock_enable_uart(UART_B); + clock_enable_uart(UART_C); + + jc_init_done = true; +#endif +} + +void jc_deinit() +{ + if (!jc_init_done) + return; + + // Disable power. + _jc_power_supply(UART_B, false); + _jc_power_supply(UART_C, false); + + if (!jc_gamepad.sio_mode) + { + // Send sleep command. + u8 data = HCI_STATE_SLEEP; + if (jc_r.connected && !(jc_r.type & JC_ID_HORI)) + { + _jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_HCI_STATE, &data, 1); + _jc_rcv_pkt(&jc_r); + } + if (jc_l.connected && !(jc_l.type & JC_ID_HORI)) + { + _jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_HCI_STATE, &data, 1); + _jc_rcv_pkt(&jc_l); + } + } + else + { + // Disable Sio NPOR. + gpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW); + + // Disable 4 MHz clock to Sio. + clock_disable_extperiph2(); + } + + // Disable UART B and C clocks. + if (!jc_gamepad.sio_mode) + clock_disable_uart(UART_B); + clock_disable_uart(UART_C); +} + +jc_gamepad_rpt_t *joycon_poll() +{ + if (!jc_init_done) + return NULL; + + _jc_conn_check(); + + _jc_init_conn(&jc_r); + _jc_init_conn(&jc_l); + + _jc_req_nx_pad_status(&jc_r); + _jc_req_nx_pad_status(&jc_l); + + _jc_rcv_pkt(&jc_r); + _jc_rcv_pkt(&jc_l); + + return &jc_gamepad; +} diff --git a/bdk/input/joycon.h b/bdk/input/joycon.h new file mode 100644 index 0000000..fbb789f --- /dev/null +++ b/bdk/input/joycon.h @@ -0,0 +1,108 @@ +/* + * Ambient light sensor driver for Nintendo Switch's Rohm BH1730 + * + * Copyright (c) 2018 CTCaer + * + * 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 __JOYCON_H_ +#define __JOYCON_H_ + +#include + +#define JC_BTNS_DIRECTION_PAD 0xF0000 +#define JC_BTNS_PREV_NEXT 0x800080 +#define JC_BTNS_ENTER 0x400008 +#define JC_BTNS_ESC 0x4 + +#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC) + +typedef struct _jc_bt_conn_t +{ + u8 type; + u8 mac[6]; + u8 host_mac[6]; + u8 ltk[16]; +} jc_bt_conn_t; + +typedef struct _jc_gamepad_rpt_t +{ + union + { + struct + { + // Joy-Con (R). +/*00*/ u32 y:1; +/*01*/ u32 x:1; +/*02*/ u32 b:1; +/*03*/ u32 a:1; +/*04*/ u32 sr_r:1; +/*05*/ u32 sl_r:1; +/*06*/ u32 r:1; +/*07*/ u32 zr:1; + + // Shared +/*08*/ u32 minus:1; +/*09*/ u32 plus:1; +/*10*/ u32 r3:1; +/*11*/ u32 l3:1; +/*12*/ u32 home:1; +/*13*/ u32 cap:1; +/*14*/ u32 pad:1; +/*15*/ u32 wired:1; + + // Joy-Con (L). +/*16*/ u32 down:1; +/*17*/ u32 up:1; +/*18*/ u32 right:1; +/*19*/ u32 left:1; +/*20*/ u32 sr_l:1; +/*21*/ u32 sl_l:1; +/*22*/ u32 l:1; +/*23*/ u32 zl:1; + }; + u32 buttons; + }; + + u16 lstick_x; + u16 lstick_y; + u16 rstick_x; + u16 rstick_y; + bool center_stick_l; + bool center_stick_r; + bool conn_l; + bool conn_r; + bool sio_mode; + u8 batt_info_l; // Also Sio Connected status. + u8 batt_info_r; // Also Sio IRQ. + jc_bt_conn_t bt_conn_l; + jc_bt_conn_t bt_conn_r; +} jc_gamepad_rpt_t; + +typedef struct _jc_calib_t +{ + u16 x_max:12; + u16 y_max:12; + u16 x_center:12; + u16 y_center:12; + u16 x_min:12; + u16 y_min:12; +} __attribute__((packed)) jc_calib_t; + +void jc_init_hw(); +void jc_deinit(); +jc_gamepad_rpt_t *joycon_poll(); +jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos); + +#endif diff --git a/bdk/input/touch.c b/bdk/input/touch.c new file mode 100644 index 0000000..f5b5098 --- /dev/null +++ b/bdk/input/touch.c @@ -0,0 +1,461 @@ +/* + * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller + * + * Copyright (c) 2018 langerhans + * Copyright (c) 2018-2023 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "touch.h" + + +#include +#define DPRINTF(...) gfx_printf(__VA_ARGS__) + +static touch_panel_info_t _panels[] = +{ + { 0, 1, 1, 1, "NISSHA NFT-K12D" },// 0. + { 1, 0, 1, 1, "GiS GGM6 B2X" },// 1. + { 2, 0, 0, 0, "NISSHA NBF-K9A" },// 3. + { 3, 1, 0, 0, "GiS 5.5\"" },// 4. + { 4, 0, 0, 1, "Samsung TSP" },// 5? + { -1, 1, 0, 1, "GiS VA 6.2\"" } // 2. +}; + +static int touch_command(u8 cmd, u8 *buf, u8 size) +{ + int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd, buf, size); + if (!res) + return 1; + return 0; +} + +static int touch_read_reg(u8 *cmd, u32 csize, u8 *buf, u32 size) +{ + int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd[0], &cmd[1], csize - 1); + if (res) + res = i2c_recv_buf(buf, size, I2C_3, STMFTS_I2C_ADDR); + if (!res) + return 1; + + return 0; +} + +static int touch_wait_event(u8 event, u8 status, u32 timeout, u8 *buf) +{ + u32 timer = get_tmr_ms() + timeout; + while (true) + { + u8 tmp[8] = {0}; + i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); + if (tmp[1] == event && tmp[2] == status) + { + if (buf) + memcpy(buf, &tmp[3], 5); + return 0; + } + + if (get_tmr_ms() > timer) + return 1; + } +} + +#define X_REAL_MAX 1264 +#define Y_REAL_MAX 704 +#define EDGE_OFFSET 15 + +static void _touch_compensate_limits(touch_event *event, bool touching) +{ + event->x = MAX(event->x, EDGE_OFFSET); + event->x = MIN(event->x, X_REAL_MAX); + event->x -= EDGE_OFFSET; + u32 x_adj = (1280 * 1000) / (X_REAL_MAX - EDGE_OFFSET); + event->x = ((u32)event->x * x_adj) / 1000; + + if (touching) + { + event->y = MAX(event->y, EDGE_OFFSET); + event->y = MIN(event->y, Y_REAL_MAX); + event->y -= EDGE_OFFSET; + u32 y_adj = (720 * 1000) / (Y_REAL_MAX - EDGE_OFFSET); + event->y = ((u32)event->y * y_adj) / 1000; + } +} + +static void _touch_process_contact_event(touch_event *event, bool touching) +{ + event->x = (event->raw[2] << 4) | ((event->raw[4] & STMFTS_MASK_Y_LSB) >> 4); + + // Normally, GUI elements have bigger horizontal estate. + // Avoid parsing y axis when finger is removed to minimize touch noise. + if (touching) + { + event->y = (event->raw[3] << 4) | (event->raw[4] & STMFTS_MASK_X_MSB); + + event->z = event->raw[5] | (event->raw[6] << 8); + event->z = event->z << 6; + + u16 tmp = 0x40; + if ((event->raw[7] & 0x3F) != 1 && (event->raw[7] & 0x3F) != 0x3F) + tmp = event->raw[7] & 0x3F; + event->z /= tmp + 0x40; + + event->fingers = ((event->raw[1] & STMFTS_MASK_TOUCH_ID) >> 4) + 1; + } + else + event->fingers = 0; + + _touch_compensate_limits(event, touching); +} + +static void _touch_parse_event(touch_event *event) +{ + event->type = event->raw[1] & STMFTS_MASK_EVENT_ID; + + switch (event->type) + { + case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + _touch_process_contact_event(event, true); + if (event->z < 255) // Reject palm rest. + event->touch = true; + else + { + event->touch = false; + event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; + } + break; + case STMFTS_EV_MULTI_TOUCH_LEAVE: + event->touch = false; + _touch_process_contact_event(event, false); + break; + case STMFTS_EV_NO_EVENT: + if (event->touch) + event->type = STMFTS_EV_MULTI_TOUCH_MOTION; + break; + default: + if (event->touch && event->raw[0] == STMFTS_EV_MULTI_TOUCH_MOTION) + event->type = STMFTS_EV_MULTI_TOUCH_MOTION; + else + event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; + } + + // gfx_con_setpos(0, 300); + // DPRINTF("x = %d \ny = %d \nz = %d \n", event->x, event->y, event->z); + // DPRINTF("0 = %02X\n1 = %02X\n2 = %02X\n3 = %02X\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]); + // DPRINTF("4 = %02X\n5 = %02X\n6 = %02X\n7 = %02X\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]); +} + +void touch_poll(touch_event *event) +{ + i2c_recv_buf_small(event->raw, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_LATEST_EVENT); + + _touch_parse_event(event); +} + +touch_event touch_poll_wait() +{ + touch_event event; + do + { + touch_poll(&event); + } while (event.type != STMFTS_EV_MULTI_TOUCH_LEAVE); + + return event; +} + +touch_info touch_get_info() +{ + touch_info info; + u8 buf[8]; + memset(&buf, 0, 8); + i2c_recv_buf_small(buf, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_INFO); + + info.chip_id = buf[0] << 8 | buf[1]; + info.fw_ver = buf[2] << 8 | buf[3]; + info.config_id = buf[4]; + info.config_ver = buf[5]; + + //DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02X, Cfg Ver: %d\n", + // info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver); + + return info; +} + +touch_panel_info_t *touch_get_panel_vendor() +{ + u8 buf[5] = {0}; + u8 cmd = STMFTS_VENDOR_GPIO_STATE; + static touch_panel_info_t panel_info = { -2, 0, 0, 0, ""}; + + if (touch_command(STMFTS_VENDOR, &cmd, 1)) + return NULL; + + if (touch_wait_event(STMFTS_EV_VENDOR, STMFTS_VENDOR_GPIO_STATE, 2000, buf)) + return NULL; + + for (u32 i = 0; i < ARRAY_SIZE(_panels); i++) + { + touch_panel_info_t *panel = &_panels[i]; + if (buf[0] == panel->gpio0 && buf[1] == panel->gpio1 && buf[2] == panel->gpio2) + return panel; + } + + // Touch panel not found, return current gpios. + panel_info.gpio0 = buf[0]; + panel_info.gpio1 = buf[1]; + panel_info.gpio2 = buf[2]; + + return &panel_info; +} + +int touch_get_fw_info(touch_fw_info_t *fw) +{ + u8 buf[8] = {0}; + + memset(fw, 0, sizeof(touch_fw_info_t)); + + // Get fw address info. + u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0x60 }; + int res = touch_read_reg(cmd, 3, buf, 3); + if (!res) + { + // Get fw info. + cmd[1] = buf[2]; cmd[2] = buf[1]; + res = touch_read_reg(cmd, 3, buf, 8); + if (!res) + { + fw->fw_id = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4]; + fw->ftb_ver = (buf[6] << 8) | buf[5]; + } + + cmd[2]++; + res = touch_read_reg(cmd, 3, buf, 8); + if (!res) + fw->fw_rev = (buf[7] << 8) | buf[6]; + } + + return res; +} + +int touch_sys_reset() +{ + u8 cmd[3] = { 0, 0x28, 0x80 }; // System reset cmd. + for (u8 retries = 0; retries < 3; retries++) + { + if (touch_command(STMFTS_WRITE_REG, cmd, 3)) + { + msleep(10); + continue; + } + msleep(10); + if (touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL)) + continue; + else + return 0; + } + + return 1; +} + +int touch_panel_ito_test(u8 *err) +{ + int res = 0; + + // Reset touchscreen module. + if (touch_sys_reset()) + return res; + + // Do ITO Production test. + u8 cmd[2] = { 1, 0 }; + if (touch_command(STMFTS_ITO_CHECK, cmd, 2)) + return res; + + u32 timer = get_tmr_ms() + 2000; + while (true) + { + u8 tmp[8] = {0}; + i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); + if (tmp[1] == 0xF && tmp[2] == 0x5) + { + if (err) + { + err[0] = tmp[3]; + err[1] = tmp[4]; + } + + res = 1; + break; + } + + if (get_tmr_ms() > timer) + break; + } + + // Reset touchscreen module. + touch_sys_reset(); + + return res; +} + +int touch_get_fb_info(u8 *buf) +{ + u8 tmp[5]; + + u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0 }; + int res = 0; + + + for (u32 i = 0; i < 0x10000; i += 4) + { + if (!res) + { + cmd[1] = (i >> 8) & 0xFF; + cmd[2] = i & 0xFF; + memset(tmp, 0xCC, 5); + res = touch_read_reg(cmd, 3, tmp, 5); + memcpy(&buf[i], tmp + 1, 4); + } + } + + return res; +} + +int touch_sense_enable() +{ + // Switch sense mode and enable multi-touch sensing. + u8 cmd = STMFTS_FINGER_MODE; + if (touch_command(STMFTS_SWITCH_SENSE_MODE, &cmd, 1)) + return 0; + + if (touch_command(STMFTS_MS_MT_SENSE_ON, NULL, 0)) + return 0; + + if (touch_command(STMFTS_CLEAR_EVENT_STACK, NULL, 0)) + return 0; + + return 1; +} + +int touch_execute_autotune() +{ + // Reset touchscreen module. + if (touch_sys_reset()) + return 0; + + // Trim low power oscillator. + if (touch_command(STMFTS_LP_TIMER_CALIB, NULL, 0)) + return 0; + msleep(200); + + // Apply Mutual Sense Compensation tuning. + if (touch_command(STMFTS_MS_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_MS_CX_TUNING_DONE, 2000, NULL)) + return 0; + + // Apply Self Sense Compensation tuning. + if (touch_command(STMFTS_SS_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_SS_CX_TUNING_DONE, 2000, NULL)) + return 0; + + // Save Compensation data to EEPROM. + if (touch_command(STMFTS_SAVE_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE, 2000, NULL)) + return 0; + + return touch_sense_enable(); +} + +static int touch_init() +{ + // Initialize touchscreen module. + if (touch_sys_reset()) + return 0; + + return touch_sense_enable(); +} + +int touch_power_on() +{ + // Configure Touscreen and GCAsic shared GPIO. + PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2; + PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; // Unused. + gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); // GC detect. + + // Configure touchscreen Touch Reset pin. + PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1; + gpio_direction_output(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW); + usleep(20); + + // Enable LDO6 for touchscreen AVDD and DVDD supply. + max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000); + max7762x_regulator_enable(REGULATOR_LDO6, true); + + // Initialize I2C3. + pinmux_config_i2c(I2C_3); + clock_enable_i2c(I2C_3); + i2c_init(I2C_3); + usleep(1000); + + // Set Touch Reset pin. + gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH); + usleep(10000); + + // Wait for the touchscreen module to get ready. + touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL); + + // Check for forced boot time calibration. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + u8 err[2]; + if (touch_panel_ito_test(err)) + if (!err[0] && !err[1]) + return touch_execute_autotune(); + } + + // Initialize touchscreen. + u32 retries = 3; + while (retries) + { + if (touch_init()) + return 1; + retries--; + } + + return 0; +} + +void touch_power_off() +{ + // Disable touchscreen power. + gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW); + + // Disables LDO6 for touchscreen VDD, AVDD supply + max7762x_regulator_enable(REGULATOR_LDO6, false); + + clock_disable_i2c(I2C_3); +} \ No newline at end of file diff --git a/nyx/nyx_gui/input/touch.h b/bdk/input/touch.h similarity index 65% rename from nyx/nyx_gui/input/touch.h rename to bdk/input/touch.h index f38d41e..871659e 100644 --- a/nyx/nyx_gui/input/touch.h +++ b/bdk/input/touch.h @@ -1,8 +1,8 @@ /* - * Touch driver for Nintendo Switch's STMicroelectronics FingerTip S touch controller + * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller * * Copyright (c) 2018 langerhans - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -20,7 +20,7 @@ #ifndef __TOUCH_H_ #define __TOUCH_H_ -#include "../utils/types.h" +#include #define STMFTS_I2C_ADDR 0x49 @@ -44,20 +44,30 @@ #define STMFTS_FULL_FORCE_CALIBRATION 0xA2 #define STMFTS_MS_CX_TUNING 0xA3 #define STMFTS_SS_CX_TUNING 0xA4 +#define STMFTS_ITO_CHECK 0xA7 #define STMFTS_RELEASEINFO 0xAA #define STMFTS_WRITE_REG 0xB6 +#define STMFTS_SWITCH_SENSE_MODE 0xC3 #define STMFTS_NOISE_WRITE 0xC7 #define STMFTS_NOISE_READ 0xC8 -#define STMFTS_RW_FB_REG 0xD0 // read data +#define STMFTS_RW_FRAMEBUFFER_REG 0xD0 #define STMFTS_SAVE_CX_TUNING 0xFC -#define STMFTS_UNK0 0xB8 //Request compensation -#define STMFTS_UNK1 0xCF -#define STMFTS_UNK2 0xF7 -#define STMFTS_UNK3 0xFA -#define STMFTS_UNK4 0xF9 +#define STMFTS_DETECTION_CONFIG 0xB0 +#define STMFTS_REQU_COMP_DATA 0xB8 +#define STMFTS_VENDOR 0xCF +#define STMFTS_FLASH_UNLOCK 0xF7 +#define STMFTS_FLASH_WRITE_64K 0xF8 +#define STMFTS_FLASH_STATUS 0xF9 +#define STMFTS_FLASH_OP 0xFA #define STMFTS_UNK5 0x62 +/* cmd parameters */ +#define STMFTS_VENDOR_GPIO_STATE 0x01 +#define STMFTS_VENDOR_SENSE_MODE 0x02 +#define STMFTS_STYLUS_MODE 0x00 +#define STMFTS_FINGER_MODE 0x01 +#define STMFTS_HOVER_MODE 0x02 /* events */ #define STMFTS_EV_NO_EVENT 0x00 @@ -72,12 +82,16 @@ #define STMFTS_EV_ERROR 0x0f #define STMFTS_EV_NOISE_READ 0x17 #define STMFTS_EV_NOISE_WRITE 0x18 +#define STMFTS_EV_VENDOR 0x20 #define STMFTS_EV_CONTROLLER_READY 0x10 -#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY 0x11 #define STMFTS_EV_STATUS 0x16 #define STMFTS_EV_DEBUG 0xDB +#define STMFTS_EV_STATUS_MS_CX_TUNING_DONE 1 +#define STMFTS_EV_STATUS_SS_CX_TUNING_DONE 2 +#define STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE 4 + /* multi touch related event masks */ #define STMFTS_MASK_EVENT_ID 0x0F #define STMFTS_MASK_TOUCH_ID 0xF0 @@ -95,16 +109,46 @@ #define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH) #define STMFTS_MAX_FINGERS 10 +typedef enum _touch_ito_error { + ITO_NO_ERROR = 0, + ITO_FORCE_OPEN, + ITO_SENSE_OPEN, + ITO_FORCE_SHRT_GND, + ITO_SENSE_SHRT_GND, + ITO_FORCE_SHRT_VCM, + ITO_SENSE_SHRT_VCM, + ITO_FORCE_SHRT_FORCE, + ITO_SENSE_SHRT_SENSE, + ITO_F2E_SENSE, + ITO_FPC_FORCE_OPEN, + ITO_FPC_SENSE_OPEN, + ITO_KEY_FORCE_OPEN, + ITO_KEY_SENSE_OPEN, + ITO_RESERVED0, + ITO_RESERVED1, + ITO_RESERVED2, + ITO_MAX_ERR_REACHED = 0xFF +} touch_ito_error; + typedef struct _touch_event { u8 raw[8]; u16 type; // Event type. u16 x; // Horizontal coordinates. u16 y; // Vertical coordinates. - u8 z; + u32 z; u8 fingers; bool touch; } touch_event; +typedef struct _touch_panel_info_t +{ + u8 idx; + u8 gpio0; + u8 gpio1; + u8 gpio2; + char *vendor; +} touch_panel_info_t; + typedef struct _touch_info { u16 chip_id; u16 fw_ver; @@ -112,10 +156,21 @@ typedef struct _touch_info { u16 config_ver; } touch_info; -int touch_power_on(); -void touch_power_off(); +typedef struct _touch_fw_info_t { + u32 fw_id; + u16 ftb_ver; + u16 fw_rev; +} touch_fw_info_t; + void touch_poll(touch_event *event); touch_event touch_poll_wait(); +touch_panel_info_t *touch_get_panel_vendor(); +int touch_get_fw_info(touch_fw_info_t *fw); touch_info touch_get_info(); +int touch_panel_ito_test(u8 *err); +int touch_execute_autotune(); +int touch_sense_enable(); +int touch_power_on(); +void touch_power_off(); #endif /* __TOUCH_H_ */ \ No newline at end of file diff --git a/bdk/libs/compr/blz.c b/bdk/libs/compr/blz.c new file mode 100644 index 0000000..5bc9e49 --- /dev/null +++ b/bdk/libs/compr/blz.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 rajkosto + * Copyright (c) 2018 SciresM + * + * 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 + +#include "blz.h" + +const blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer) +{ + if (comp_data_size < sizeof(blz_footer)) + return NULL; + + const blz_footer *src_footer = (const blz_footer *)&comp_data[comp_data_size - sizeof(blz_footer)]; + if (out_footer) + memcpy(out_footer, src_footer, sizeof(blz_footer)); // Must be a memcpy because no unaligned accesses on ARMv4. + + return src_footer; +} + +// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM! +int blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer) +{ + u32 addl_size = footer->addl_size; + u32 header_size = footer->header_size; + u32 cmp_and_hdr_size = footer->cmp_and_hdr_size; + + u8 *cmp_start = &data[comp_size] - cmp_and_hdr_size; + u32 cmp_ofs = cmp_and_hdr_size - header_size; + u32 out_ofs = cmp_and_hdr_size + addl_size; + + while (out_ofs) + { + u8 control = cmp_start[--cmp_ofs]; + for (u32 i = 0; i < 8; i++) + { + if (control & 0x80) + { + if (cmp_ofs < 2) + return 0; // Out of bounds. + + cmp_ofs -= 2; + u16 seg_val = ((u32)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs]; + u32 seg_size = ((seg_val >> 12) & 0xF) + 3; + u32 seg_ofs = (seg_val & 0x0FFF) + 3; + + // Kernel restricts segment copy to stay in bounds. + if (out_ofs < seg_size) + seg_size = out_ofs; + + out_ofs -= seg_size; + + for (u32 j = 0; j < seg_size; j++) + cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; + } + else // Copy directly. + { + if (cmp_ofs < 1) + return 0; // Out of bounds. + + cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; + } + + control <<= 1; + + if (!out_ofs) // Blz works backwards, so if it reaches byte 0, it's done. + return 1; + } + } + + return 1; +} + +int blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size) +{ + blz_footer footer; + const blz_footer *comp_footer = blz_get_footer(comp_data, comp_data_size, &footer); + if (!comp_footer) + return 0; + + // Decompression happens in-place, so need to copy the relevant compressed data first. + u32 comp_bytes = (const u8 *)comp_footer - comp_data; + memcpy(dst_data, comp_data, comp_bytes); + memset(&dst_data[comp_bytes], 0, dst_size - comp_bytes); + + return blz_uncompress_inplace(dst_data, comp_data_size, &footer); +} diff --git a/bootloader/libs/compr/blz.h b/bdk/libs/compr/blz.h similarity index 63% rename from bootloader/libs/compr/blz.h rename to bdk/libs/compr/blz.h index 4171049..bb058d8 100644 --- a/bootloader/libs/compr/blz.h +++ b/bdk/libs/compr/blz.h @@ -17,7 +17,7 @@ #ifndef _BLZ_H_ #define _BLZ_H_ -#include "../../utils/types.h" +#include typedef struct _blz_footer { @@ -26,11 +26,11 @@ typedef struct _blz_footer u32 addl_size; } blz_footer; -// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL. -const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter); +// Returns pointer to footer in comp_data if present, additionally copies it to out_footer if not NULL. +const blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer); // Returns 0 on failure. -int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer); +int blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer); // Returns 0 on failure. -int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize); +int blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size); #endif diff --git a/bootloader/libs/compr/lz.c b/bdk/libs/compr/lz.c similarity index 98% rename from bootloader/libs/compr/lz.c rename to bdk/libs/compr/lz.c index a17c6e4..94b64c6 100644 --- a/bootloader/libs/compr/lz.c +++ b/bdk/libs/compr/lz.c @@ -125,7 +125,7 @@ static int _LZ_ReadVarSize( unsigned int * x, const unsigned char * buf ) * insize - Number of input bytes. *************************************************************************/ -void LZ_Uncompress( const unsigned char *in, unsigned char *out, +unsigned int LZ_Uncompress( const unsigned char *in, unsigned char *out, unsigned int insize ) { unsigned char marker, symbol; @@ -134,7 +134,7 @@ void LZ_Uncompress( const unsigned char *in, unsigned char *out, /* Do we have anything to uncompress? */ if( insize < 1 ) { - return; + return 0; } /* Get marker symbol from input stream */ @@ -176,4 +176,6 @@ void LZ_Uncompress( const unsigned char *in, unsigned char *out, } } while( inpos < insize ); + + return outpos; } diff --git a/bootloader/libs/compr/lz.h b/bdk/libs/compr/lz.h similarity index 95% rename from bootloader/libs/compr/lz.h rename to bdk/libs/compr/lz.h index 6f31b4a..ef67055 100644 --- a/bootloader/libs/compr/lz.h +++ b/bdk/libs/compr/lz.h @@ -41,7 +41,7 @@ extern "C" { * Function prototypes *************************************************************************/ -void LZ_Uncompress( const unsigned char *in, unsigned char *out, +unsigned int LZ_Uncompress( const unsigned char *in, unsigned char *out, unsigned int insize ); diff --git a/bdk/libs/compr/lz4.c b/bdk/libs/compr/lz4.c new file mode 100644 index 0000000..d6c22c6 --- /dev/null +++ b/bdk/libs/compr/lz4.c @@ -0,0 +1,1671 @@ +/* + LZ4 - Fast LZ compression algorithm + Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ + + +/*-************************************ +* Tuning parameters +**************************************/ +/* + * ACCELERATION_DEFAULT : + * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 + */ +#define ACCELERATION_DEFAULT 1 + + +/*-************************************ +* Dependency +**************************************/ +#define LZ4_STATIC_LINKING_ONLY +#include "lz4.h" +/* see also "memory routines" below */ + + +/*-************************************ +* Compiler Options +**************************************/ +#ifndef LZ4_FORCE_INLINE +# ifdef _MSC_VER /* Visual Studio */ +# define LZ4_FORCE_INLINE static __forceinline +# else +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define LZ4_FORCE_INLINE static inline +# endif +# else +# define LZ4_FORCE_INLINE static +# endif /* __STDC_VERSION__ */ +# endif /* _MSC_VER */ +#endif /* LZ4_FORCE_INLINE */ + +/* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE + * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy, + * together with a simple 8-byte copy loop as a fall-back path. + * However, this optimization hurts the decompression speed by >30%, + * because the execution does not go to the optimized loop + * for typical compressible data, and all of the preamble checks + * before going to the fall-back path become useless overhead. + * This optimization happens only with the -O3 flag, and -O2 generates + * a simple 8-byte copy loop. + * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy + * functions are annotated with __attribute__((optimize("O2"))), + * and also LZ4_wildCopy is forcibly inlined, so that the O2 attribute + * of LZ4_wildCopy does not affect the compression speed. + */ +#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) +# define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2"))) +# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE __attribute__((optimize("O2"))) LZ4_FORCE_INLINE +#else +# define LZ4_FORCE_O2_GCC_PPC64LE +# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static +#endif + +/*-************************************ +* Memory routines +**************************************/ +#include /* malloc, calloc, free */ +#define ALLOC(s) malloc(s) +#define ALLOC_AND_ZERO(s) zalloc(s) +#define FREEMEM free +#include /* memset, memcpy */ +#define MEM_INIT memset + + +/*-************************************ +* Basic Types +**************************************/ +typedef uint16_t U16; +typedef uint32_t U32; +typedef int32_t S32; +typedef uint64_t U64; +typedef uintptr_t uptrval; +typedef size_t reg_t; /* 32-bits in x32 mode */ + +/*-************************************ +* Reading and writing into memory +**************************************/ +static unsigned LZ4_isLittleEndian(void) +{ + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} + +static U16 LZ4_read16(const void* memPtr) +{ + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static U32 LZ4_read32(const void* memPtr) +{ + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static reg_t LZ4_read_ARCH(const void* memPtr) +{ + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static void LZ4_write16(void* memPtr, U16 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +static void LZ4_write32(void* memPtr, U32 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +static U16 LZ4_readLE16(const void* memPtr) +{ + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } +} + +static void LZ4_writeLE16(void* memPtr, U16 value) +{ + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } +} + +/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ +LZ4_FORCE_O2_INLINE_GCC_PPC64LE +void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) +{ + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; + + do { memcpy(d,s,8); d+=8; s+=8; } while (d=2) +# include +static int g_debuglog_enable = 1; +# define DEBUGLOG(l, ...) { \ + if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ + fprintf(stderr, __FILE__ ": "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } +#else +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif + + +/*-************************************ +* Common functions +**************************************/ +static unsigned LZ4_NbCommonBytes (reg_t val) +{ + if (LZ4_isLittleEndian()) { + if (sizeof(val)==8) { + return (__builtin_ctzll((U64)val) >> 3); + } else /* 32 bits */ { + return (__builtin_ctz((U32)val) >> 3); + } + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { /* 64-bits */ + return (__builtin_clzll((U64)val) >> 3); + } else /* 32 bits */ { + return (__builtin_clz((U32)val) >> 3); + } + } +} + +#define STEPSIZE sizeof(reg_t) +LZ4_FORCE_INLINE +unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) +{ + const BYTE* const pStart = pIn; + + if (likely(pIn < pInLimit-(STEPSIZE-1))) { + reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + if (!diff) { + pIn+=STEPSIZE; pMatch+=STEPSIZE; + } else { + return LZ4_NbCommonBytes(diff); + } } + + while (likely(pIn < pInLimit-(STEPSIZE-1))) { + reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; } + pIn += LZ4_NbCommonBytes(diff); + return (unsigned)(pIn - pStart); + } + + if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; } + if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; } + if ((pIn compression run slower on incompressible data */ + + +/*-************************************ +* Local Structures and types +**************************************/ +typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; +typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; + +/** + * This enum distinguishes several different modes of accessing previous + * content in the stream. + * + * - noDict : There is no preceding content. + * - withPrefix64k : Table entries up to ctx->dictSize before the current blob + * blob being compressed are valid and refer to the preceding + * content (of length ctx->dictSize), which is available + * contiguously preceding in memory the content currently + * being compressed. + * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere + * else in memory, starting at ctx->dictionary with length + * ctx->dictSize. + * - usingDictCtx : Like usingExtDict, but everything concerning the preceding + * content is in a separate context, pointed to by + * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table + * entries in the current context that refer to positions + * preceding the beginning of the current compression are + * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx + * ->dictSize describe the location and size of the preceding + * content, and matches are found by looking in the ctx + * ->dictCtx->hashTable. + */ +typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive; +typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; + +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; + + +/*-************************************ +* Local Utils +**************************************/ +int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } +int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } +int LZ4_sizeofState() { return LZ4_STREAMSIZE; } + + +/*-****************************** +* Compression functions +********************************/ +static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) +{ + if (tableType == byU16) + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) +{ + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); +} + +LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) +{ + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); +} + +static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) +{ + switch (tableType) + { + default: /* fallthrough */ + case clearedTable: /* fallthrough */ + case byPtr: { /* illegal! */ return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)idx; return; } + } +} + +static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) +{ + switch (tableType) + { + case clearedTable: { /* illegal! */ return; } + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } + } +} + +LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); +} + +/* LZ4_getIndexOnHash() : + * Index of match position registered in hash table. + * hash position must be calculated by using base+index, or dictBase+index. + * Assumption 1 : only valid if tableType == byU32 or byU16. + * Assumption 2 : h is presumed valid (within limits of hash table) + */ +static U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) +{ + LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); + if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h]; } + if (tableType == byU16) { const U16* const hashTable = (const U16*) tableBase; return hashTable[h]; } + return 0; /* forbidden case */ +} + +static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; } + if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; } + { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ +} + +LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, const void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); +} + +LZ4_FORCE_INLINE void LZ4_prepareTable( + LZ4_stream_t_internal* const cctx, + const int inputSize, + const tableType_t tableType) { + /* If the table hasn't been used, it's guaranteed to be zeroed out, and is + * therefore safe to use no matter what mode we're in. Otherwise, we figure + * out if it's safe to leave as is or whether it needs to be reset. + */ + if (cctx->tableType != clearedTable) { + if (cctx->tableType != tableType + || (tableType == byU16 && cctx->currentOffset + inputSize >= 0xFFFFU) + || (tableType == byU32 && cctx->currentOffset > 1 GB) + || tableType == byPtr + || inputSize >= 4 KB) + { + DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx); + MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE); + cctx->currentOffset = 0; + cctx->tableType = clearedTable; + } else { + DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)"); + } + } + + /* Adding a gap, so all previous entries are > MAX_DISTANCE back, is faster + * than compressing without a gap. However, compressing with + * currentOffset == 0 is faster still, so we preserve that case. + */ + if (cctx->currentOffset != 0 && tableType == byU32) { + DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset"); + cctx->currentOffset += 64 KB; + } + + /* Finally, clear history */ + cctx->dictCtx = NULL; + cctx->dictionary = NULL; + cctx->dictSize = 0; +} + +/** LZ4_compress_generic() : + inlined, to ensure branches are decided at compilation time */ +LZ4_FORCE_INLINE int LZ4_compress_generic( + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dictDirective, + const dictIssue_directive dictIssue, + const U32 acceleration) +{ + const BYTE* ip = (const BYTE*) source; + + U32 const startIndex = cctx->currentOffset; + const BYTE* base = (const BYTE*) source - startIndex; + const BYTE* lowLimit; + + const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx; + const BYTE* const dictionary = + dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary; + const U32 dictSize = + dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize; + const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with index in current context */ + + int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); + U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ + const BYTE* const dictEnd = dictionary + dictSize; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; + const BYTE* const matchlimit = iend - LASTLITERALS; + + /* the dictCtx currentOffset is indexed on the start of the dictionary, + * while a dictionary in the current context precedes the currentOffset */ + const BYTE* dictBase = dictDirective == usingDictCtx ? + dictionary + dictSize - dictCtx->currentOffset : /* is it possible that dictCtx->currentOffset != dictCtx->dictSize ? Yes if the dictionary context is not reset */ + dictionary + dictSize - startIndex; + + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; + + U32 offset = 0; + U32 forwardH; + + DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType); + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ + + lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0); + + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + + /* Update context state */ + if (dictDirective == usingDictCtx) { + /* Subsequent linked blocks can't use the dictionary. */ + /* Instead, they use the block we just compressed. */ + cctx->dictCtx = NULL; + cctx->dictSize = (U32)inputSize; + } else { + cctx->dictSize += (U32)inputSize; + } + cctx->currentOffset += (U32)inputSize; + cctx->tableType = tableType; + + if (inputSizehashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + if (tableType == byPtr) { + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + + } while ( (match+MAX_DISTANCE < ip) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + + } else { /* byU32, byU16 */ + + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + U32 const current = (U32)(forwardIp - base); + U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; + + if (dictDirective == usingDictCtx) { + if (matchIndex < startIndex) { + /* there was no match, try the dictionary */ + matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); + match = dictBase + matchIndex; + matchIndex += dictDelta; /* make dictCtx index comparable with current context */ + lowLimit = dictionary; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; + } + } else if (dictDirective==usingExtDict) { + if (matchIndex < startIndex) { + DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex); + match = dictBase + matchIndex; + lowLimit = dictionary; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; + } + } else { /* single continuous memory segment */ + match = base + matchIndex; + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); + + if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) continue; /* match outside of valid area */ + if ((tableType != byU16) && (current - matchIndex > MAX_DISTANCE)) continue; /* too far - note: works even if matchIndex overflows */ + + if (LZ4_read32(match) == LZ4_read32(ip)) { + if (maybe_extMem) offset = current - matchIndex; + break; /* match found */ + } + + } while(1); + } + + /* Catch up */ + while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { + int len = (int)litLength-RUN_MASK; + *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + DEBUGLOG(6, " with matchLength=%u starting in extDict", matchCode+MINMATCH); + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH); + } + + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) + return 0; + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) { + op+=4; + LZ4_write32(op, 0xFFFFFFFF); + matchCode -= 4*255; + } + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); + } + + anchor = ip; + + /* Test end of chunk */ + if (ip >= mflimitPlusOne) break; + + /* Fill table */ + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + + /* Test next position */ + if (tableType == byPtr) { + + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE >= ip) + && (LZ4_read32(match) == LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + } else { /* byU32, byU16 */ + + U32 const h = LZ4_hashPosition(ip, tableType); + U32 const current = (U32)(ip-base); + U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); + if (dictDirective == usingDictCtx) { + if (matchIndex < startIndex) { + /* there was no match, try the dictionary */ + matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); + match = dictBase + matchIndex; + lowLimit = dictionary; /* required for match length counter */ + matchIndex += dictDelta; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; /* required for match length counter */ + } + } else if (dictDirective==usingExtDict) { + if (matchIndex < startIndex) { + match = dictBase + matchIndex; + lowLimit = dictionary; /* required for match length counter */ + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; /* required for match length counter */ + } + } else { /* single memory segment */ + match = base + matchIndex; + } + LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); + if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) + && ((tableType==byU16) ? 1 : (current - matchIndex <= MAX_DISTANCE)) + && (LZ4_read32(match) == LZ4_read32(ip)) ) { + token=op++; + *token=0; + if (maybe_extMem) offset = current - matchIndex; + DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i", (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source)); + goto _next_match; + } + } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + + } + +_last_literals: + /* Encode Last Literals */ + { size_t const lastRun = (size_t)(iend - anchor); + if ( (outputLimited) && /* Check output buffer overflow */ + ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) + return 0; + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRun<internal_donotuse; + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + LZ4_resetStream((LZ4_stream_t*)state); + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > MAX_DISTANCE)) ? byPtr : byU32; + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + if (inputSize < LZ4_64Klimit) {; + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > MAX_DISTANCE)) ? byPtr : byU32; + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } +} + +/** + * LZ4_compress_fast_extState_fastReset() : + * A variant of LZ4_compress_fast_extState(). + * + * Using this variant avoids an expensive initialization step. It is only safe + * to call if the state buffer is known to be correctly initialized already + * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of + * "correctly initialized"). + */ +int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) +{ + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + if (dstCapacity >= LZ4_compressBound(srcSize)) { + if (srcSize < LZ4_64Klimit) { + const tableType_t tableType = byU16; + LZ4_prepareTable(ctx, srcSize, tableType); + if (ctx->currentOffset) { + return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, dictSmall, acceleration); + } else { + return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32; + LZ4_prepareTable(ctx, srcSize, tableType); + return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + if (srcSize < LZ4_64Klimit) { + const tableType_t tableType = byU16; + LZ4_prepareTable(ctx, srcSize, tableType); + if (ctx->currentOffset) { + return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration); + } else { + return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32; + LZ4_prepareTable(ctx, srcSize, tableType); + return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } +} + + +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + int result; + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_stream_t* const ctxPtr = ctx; + result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + + FREEMEM(ctx); + + return result; +} + + +int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); +} + + +/* hidden debug function */ +/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ +int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + int result; + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_resetStream(ctx); + + if (inputSize < LZ4_64Klimit) + result = LZ4_compress_generic(&ctx->internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + result = LZ4_compress_generic(&ctx->internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); + + FREEMEM(ctx); + + return result; +} + + +/*-****************************** +* *_destSize() variant +********************************/ + +static int LZ4_compress_destSize_generic( + LZ4_stream_t_internal* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + const int targetDstSize, + const tableType_t tableType) +{ + const BYTE* ip = (const BYTE*) src; + const BYTE* base = (const BYTE*) src; + const BYTE* lowLimit = (const BYTE*) src; + const BYTE* anchor = ip; + const BYTE* const iend = ip + *srcSizePtr; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + targetDstSize; + BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; + BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); + BYTE* const oMaxSeq = oMaxLit - 1 /* token */; + + U32 forwardH; + + + /* Init conditions */ + if (targetDstSize < 1) return 0; /* Impossible to store anything */ + if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (*srcSizePtrhashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = 1 << LZ4_skipTrigger; + + do { + U32 h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); + + } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literal length */ + { unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if (op + ((litLength+240)/255) + litLength > oMaxLit) { + /* Not enough space for a last match */ + op--; + goto _last_literals; + } + if (litLength>=RUN_MASK) { + unsigned len = litLength - RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< oMaxMatch) { + /* Match description too long : reduce it */ + matchLength = (15-1) + (oMaxMatch-op) * 255; + } + ip += MINMATCH + matchLength; + + if (matchLength>=ML_MASK) { + *token += ML_MASK; + matchLength -= ML_MASK; + while (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of block */ + if (ip > mflimit) break; + if (op > oMaxSeq) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } + +_last_literals: + /* Encode Last Literals */ + { size_t lastRunSize = (size_t)(iend - anchor); + if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { + /* adapt lastRunSize to fill 'dst' */ + lastRunSize = (oend-op) - 1; + lastRunSize -= (lastRunSize+240)/255; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); + } else { + if (*srcSizePtr < LZ4_64Klimit) { + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); + } else { + tableType_t const tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32; + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, tableType); + } } +} + + +int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) +{ + LZ4_stream_t* ctxBody = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));; + LZ4_stream_t* ctx = ctxBody; + + int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + + FREEMEM(ctxBody); + + return result; +} + + + +/*-****************************** +* Streaming functions +********************************/ + +LZ4_stream_t* LZ4_createStream(void) +{ + LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + DEBUGLOG(4, "LZ4_createStream %p", lz4s); + if (lz4s == NULL) return NULL; + LZ4_resetStream(lz4s); + return lz4s; +} + +void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +{ + DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); +} + +void LZ4_resetStream_fast(LZ4_stream_t* ctx) { + LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32); +} + +int LZ4_freeStream (LZ4_stream_t* LZ4_stream) +{ + if (!LZ4_stream) return 0; /* support free on NULL */ + DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream); + FREEMEM(LZ4_stream); + return (0); +} + + +#define HASH_UNIT sizeof(reg_t) +int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +{ + LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; + const tableType_t tableType = byU32; + const BYTE* p = (const BYTE*)dictionary; + const BYTE* const dictEnd = p + dictSize; + const BYTE* base; + + DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict); + + LZ4_prepareTable(dict, 0, tableType); + + /* We always increment the offset by 64 KB, since, if the dict is longer, + * we truncate it to the last 64k, and if it's shorter, we still want to + * advance by a whole window length so we can provide the guarantee that + * there are only valid offsets in the window, which allows an optimization + * in LZ4_compress_fast_continue() where it uses noDictIssue even when the + * dictionary isn't a full 64k. */ + + if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; + base = dictEnd - 64 KB - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += 64 KB; + dict->tableType = tableType; + + if (dictSize < (int)HASH_UNIT) { + return 0; + } + + while (p <= dictEnd-HASH_UNIT) { + LZ4_putPosition(p, dict->hashTable, tableType, base); + p+=3; + } + + return dict->dictSize; +} + +void LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream) { + if (dictionary_stream != NULL) { + /* If the current offset is zero, we will never look in the + * external dictionary context, since there is no value a table + * entry can take that indicate a miss. In that case, we need + * to bump the offset to something non-zero. + */ + if (working_stream->internal_donotuse.currentOffset == 0) { + working_stream->internal_donotuse.currentOffset = 64 KB; + } + working_stream->internal_donotuse.dictCtx = &(dictionary_stream->internal_donotuse); + } else { + working_stream->internal_donotuse.dictCtx = NULL; + } +} + + +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize) +{ + if (LZ4_dict->currentOffset + nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */ + /* rescale hash table */ + U32 const delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + DEBUGLOG(4, "LZ4_renormDictT"); + for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } +} + + +int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + const tableType_t tableType = byU32; + LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */ + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + /* Check overlapping input/dictionary space */ + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; + } + } + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) { + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration); + else + return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration); + } + + /* external dictionary mode */ + { int result; + if (streamPtr->dictCtx) { + /* We depend here on the fact that dictCtx'es (produced by + * LZ4_loadDict) guarantee that their tables contain no references + * to offsets between dictCtx->currentOffset - 64 KB and + * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe + * to use noDictIssue even when the dict isn't a full 64 KB. + */ + if (inputSize > 4 KB) { + /* For compressing large blobs, it is faster to pay the setup + * cost to copy the dictionary's tables into the active context, + * so that the compression loop is only looking into one table. + */ + memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t)); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); + } + } else { + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); + } + } + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + return result; + } +} + + +/* Hidden debug function, to force-test external dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize) +{ + LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; + int result; + + LZ4_renormDictT(streamPtr, srcSize); + + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { + result = LZ4_compress_generic(streamPtr, source, dest, srcSize, 0, notLimited, byU32, usingExtDict, dictSmall, 1); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, srcSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + } + + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)srcSize; + + return result; +} + + +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its memory location, + * save it into a safer place (char* safeBuffer). + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue(). + * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + */ +int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) +{ + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; + + return dictSize; +} + + + +/*-***************************** +* Decompression functions +*******************************/ +/*! LZ4_decompress_generic() : + * This generic decompression function covers all use cases. + * It shall be instantiated several times, using different sets of directives. + * Note that it is important for performance that this function really get inlined, + * in order to remove useless branches during compilation optimization. + */ +LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_INLINE int LZ4_decompress_generic( + const char* const src, + char* const dst, + int srcSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ + ) +{ + const BYTE* ip = (const BYTE*) src; + const BYTE* const iend = ip + srcSize; + + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4}; + const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; + + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + + /* Special cases */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => just decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((srcSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; + + unsigned const token = *ip++; + + /* shortcut for common case : + * in most circumstances, we expect to decode small matches (<= 18 bytes) separated by few literals (<= 14 bytes). + * this shortcut was tested on x86 and x64, where it improves decoding speed. + * it has not yet been benchmarked on ARM, Power, mips, etc. */ + if (((ip + 14 /*maxLL*/ + 2 /*offset*/ <= iend) + & (op + 14 /*maxLL*/ + 18 /*maxML*/ <= oend)) + & ((token < (15<> ML_BITS; + size_t const off = LZ4_readLE16(ip+ll); + const BYTE* const matchPtr = op + ll - off; /* pointer underflow risk ? */ + if ((off >= 8) /* do not deal with overlapping matches */ & (matchPtr >= lowPrefix)) { + size_t const ml = (token & ML_MASK) + MINMATCH; + memcpy(op, ip, 16); op += ll; ip += ll + 2 /*offset*/; + memcpy(op + 0, matchPtr + 0, 8); + memcpy(op + 8, matchPtr + 8, 8); + memcpy(op +16, matchPtr +16, 2); + op += ml; + continue; + } + } + + /* decode literal length */ + if ((length=(token>>ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) + { + if (partialDecoding) { + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ + } else { + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; op = cpy; + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + length += s; + } while (s==255); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + + if (length <= (size_t)(lowPrefix-match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + + /* copy match within block */ + cpy = op + length; + if (unlikely(offset<8)) { + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += inc32table[offset]; + memcpy(op+4, match, 4); + match -= dec64table[offset]; + } else { memcpy(op, match, 8); match+=8; } + op += 8; + + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op16) LZ4_wildCopy(op+8, match+8, cpy); + } + op = cpy; /* correction */ + } + + /* end of decoding */ + if (endOnInput) + return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ + else + return (int) (((const char*)ip)-src); /* Nb of input bytes read */ + + /* Overflow error detected */ +_output_error: + return (int) (-(((const char*)ip)-src))-1; +} + + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_fast(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); +} + + +/*===== streaming decompression functions =====*/ + +LZ4_streamDecode_t* LZ4_createStreamDecode(void) +{ + LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); + return lz4s; +} + +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) +{ + if (!LZ4_stream) return 0; /* support free on NULL */ + FREEMEM(LZ4_stream); + return 0; +} + +/*! + * LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. + * This function is not necessary if previous data is still available where it was decoded. + * Loading a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + lz4sd->prefixSize = (size_t) dictSize; + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->externalDict = NULL; + lz4sd->extDictSize = 0; + return 1; +} + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setStreamDecode() +*/ +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += result; + lz4sd->prefixEnd += result; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } + + return result; +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } + + return result; +} + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters +*/ + +LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + if (dictStart+dictSize == dest) { + if (dictSize >= (int)(64 KB - 1)) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + } + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); +} + +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); +} + +/* debug function */ +LZ4_FORCE_O2_GCC_PPC64LE +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + + +/*=************************************************* +* Obsolete Functions +***************************************************/ +/* obsolete compression functions */ +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } +int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); } +int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } +int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); } +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } + +/* +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ +int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + +/* Obsolete Streaming functions */ + +int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } + +int LZ4_resetStreamState(void* state, char* inputBuffer) +{ + (void)inputBuffer; + LZ4_resetStream((LZ4_stream_t*)state); + return 0; +} + +void* LZ4_create (char* inputBuffer) +{ + (void)inputBuffer; + return LZ4_createStream(); +} + +char* LZ4_slideInputBuffer (void* state) +{ + /* avoid const char * -> char * conversion warning */ + return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary; +} + +/* Obsolete streaming decompression functions */ + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +#endif /* LZ4_COMMONDEFS_ONLY */ diff --git a/bdk/libs/compr/lz4.h b/bdk/libs/compr/lz4.h new file mode 100644 index 0000000..0dfa19e --- /dev/null +++ b/bdk/libs/compr/lz4.h @@ -0,0 +1,569 @@ +/* + * LZ4 - Fast LZ compression algorithm + * Header File + * Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef LZ4_H_2983827168210 +#define LZ4_H_2983827168210 + +/* --- Dependency --- */ +#include /* size_t */ + + +/** + Introduction + + LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h provides block compression functions. It gives full buffer control to user. + Decompressing an lz4-compressed block also requires metadata (such as compressed size). + Each application is free to encode such metadata in whichever way it wants. + + An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md), + take care of encoding standard metadata alongside LZ4-compressed blocks. + If your application requires interoperability, it's recommended to use it. + A library is provided to take care of it, see lz4frame.h. +*/ + +/*^*************************************************************** +* Export parameters +*****************************************************************/ +/* +* LZ4_DLL_EXPORT : +* Enable exporting of functions when building a Windows DLL +* LZ4LIB_VISIBILITY : +* Control library symbols visibility. +*/ +#ifndef LZ4LIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define LZ4LIB_VISIBILITY +# endif +#endif +#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) +# define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY +#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) +# define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define LZ4LIB_API LZ4LIB_VISIBILITY +#endif + +/*------ Version ------*/ +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 8 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 2 /* for tweaks, bug-fixes, or development */ + +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) + +#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE +#define LZ4_QUOTE(str) #str +#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) + +LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version */ +LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; unseful to check dll version */ + + +/*-************************************ +* Tuning parameter +**************************************/ +/*! + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage may improve speed, thanks to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#ifndef LZ4_MEMORY_USAGE +# define LZ4_MEMORY_USAGE 14 +#endif + +/*-************************************ +* Simple Functions +**************************************/ +/*! LZ4_compress_default() : + Compresses 'srcSize' bytes from buffer 'src' + into already allocated 'dst' buffer of size 'dstCapacity'. + Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'src' into a more limited 'dst' budget, + compression stops *immediately*, and the function result is zero. + Note : as a consequence, 'dst' content is not valid. + Note 2 : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer). + srcSize : max supported value is LZ4_MAX_INPUT_SIZE. + dstCapacity : size of buffer 'dst' (which must be already allocated) + return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity) + or 0 if compression fails */ +LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity); + +/*! LZ4_decompress_safe() : + compressedSize : is the exact complete size of the compressed block. + dstCapacity : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity) + If destination buffer is not large enough, decoding will stop and output an error code (negative value). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against malicious data packets. +*/ +LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); + + +/*-************************************ +* Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) + +/*! +LZ4_compressBound() : + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is incorrect (too large or negative) +*/ +LZ4LIB_API int LZ4_compressBound(int inputSize); + +/*! +LZ4_compress_fast() : + Same as LZ4_compress_default(), but allows selection of "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c). +*/ +LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + + +/*! +LZ4_compress_fast_extState() : + Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. +*/ +LZ4LIB_API int LZ4_sizeofState(void); +LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + + +/*! +LZ4_compress_destSize() : + Reverse the logic : compresses as much data as possible from 'src' buffer + into already allocated buffer 'dst' of size 'targetDestSize'. + This function either compresses the entire 'src' content into 'dst' if it's large enough, + or fill 'dst' buffer completely with as much data as possible from 'src'. + *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'. + New value is necessarily <= old value. + return : Nb bytes written into 'dst' (necessarily <= targetDestSize) + or 0 if compression fails +*/ +LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize); + + +/*! +LZ4_decompress_fast() : **unsafe!** +This function is a bit faster than LZ4_decompress_safe(), +but doesn't provide any security guarantee. + originalSize : is the uncompressed size to regenerate + Destination buffer must be already allocated, and its size must be >= 'originalSize' bytes. + return : number of bytes read from source buffer (== compressed size). + If the source stream is detected malformed, the function stops decoding and return a negative result. + note : This function respects memory boundaries for *properly formed* compressed data. + However, it does not provide any protection against malicious input. + It also doesn't know 'src' size, and implies it's >= compressed size. + Use this function in trusted environment **only**. +*/ +LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize); + +/*! +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'srcSize' at position 'src' + into destination buffer 'dst' of size 'dstCapacity'. + The function will decompress a minimum of 'targetOutputSize' bytes, and stop after that. + However, it's not accurate, and may write more than 'targetOutputSize' (but always <= dstCapacity). + @return : the number of bytes decoded in the destination buffer (necessarily <= dstCapacity) + Note : this number can also be < targetOutputSize, if compressed block contains less data. + Therefore, always control how many bytes were decoded. + If source stream is detected malformed, function returns a negative result. + This function is protected against malicious data packets. +*/ +LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); + + +/*-********************************************* +* Streaming Compression Functions +***********************************************/ +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ + +/*! LZ4_createStream() and LZ4_freeStream() : + * LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. + * LZ4_freeStream() releases its memory. + */ +LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); +LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); + +/*! LZ4_resetStream() : + * An LZ4_stream_t structure can be allocated once and re-used multiple times. + * Use this function to start compressing a new stream. + */ +LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); + +/*! LZ4_loadDict() : + * Use this function to load a static dictionary into LZ4_stream_t. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed, and is the same as reset. + * @return : dictionary size, in bytes (necessarily <= 64 KB) + */ +LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); + +/*! LZ4_compress_fast_continue() : + * Compress 'src' content using data from previously compressed blocks, for better compression ratio. + * 'dst' buffer must be already allocated. + * If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. + * + * Important : The previous 64KB of compressed data is assumed to remain present and unmodified in memory! + * + * Special 1 : When input is a double-buffer, they can have any size, including < 64 KB. + * Make sure that buffers are separated by at least one byte. + * This way, each block only depends on previous block. + * Special 2 : If input buffer is a ring-buffer, it can have any size, including < 64 KB. + * + * @return : size of compressed block + * or 0 if there is an error (typically, cannot fit into 'dst'). + * After an error, the stream status is invalid, it can only be reset or freed. + */ +LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_saveDict() : + * If last 64KB data cannot be guaranteed to remain available at its current memory location, + * save it into a safer place (char* safeBuffer). + * This is schematically equivalent to a memcpy() followed by LZ4_loadDict(), + * but is much faster, because LZ4_saveDict() doesn't need to rebuild tables. + * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error. + */ +LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize); + + +/*-********************************************** +* Streaming Decompression Functions +* Bufferless synchronous API +************************************************/ +typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defined later) */ + +/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() : + * creation / destruction of streaming decompression tracking structure. + * A tracking structure can be re-used multiple times sequentially. */ +LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); +LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); + +/*! LZ4_setStreamDecode() : + * An LZ4_streamDecode_t structure can be allocated once and re-used multiple times. + * Use this function to start decompression of a new stream of blocks. + * A dictionary can optionnally be set. Use NULL or size 0 for a reset order. + * @return : 1 if OK, 0 if error + */ +LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); + +/*! LZ4_decompress_*_continue() : + * These decoding functions allow decompression of consecutive blocks in "streaming" mode. + * A block is an unsplittable entity, it must be presented entirely to a decompression function. + * Decompression functions only accept one block at a time. + * The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded. + * If less than 64KB of data has been decoded all the data must be present. + * + * Special : if application sets a ring buffer for decompression, it must respect one of the following conditions : + * - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + * In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + * - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + * maxBlockSize is implementation dependent. It's the maximum size of any single block. + * In which case, encoding and decoding buffers do not need to be synchronized, + * and encoding ring buffer can have any size, including small ones ( < 64 KB). + * - _At least_ 64 KB + 8 bytes + maxBlockSize. + * In which case, encoding and decoding buffers do not need to be synchronized, + * and encoding ring buffer can have any size, including larger than decoding buffer. + * Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + * and indicate where it is saved using LZ4_setStreamDecode() before decompressing next block. +*/ +LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity); +LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize); + + +/*! LZ4_decompress_*_usingDict() : + * These decoding functions work the same as + * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue() + * They are stand-alone, and don't need an LZ4_streamDecode_t structure. + */ +LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize); +LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize); + + +/*^********************************************** + * !!!!!! STATIC LINKING ONLY !!!!!! + ***********************************************/ + +/*-************************************ + * Unstable declarations + ************************************** + * Declarations in this section should be considered unstable. + * Use at your own peril, etc., etc. + * They may be removed in the future. + * Their signatures may change. + **************************************/ + +#ifdef LZ4_STATIC_LINKING_ONLY + +/*! LZ4_resetStream_fast() : + * When an LZ4_stream_t is known to be in a internally coherent state, + * it can often be prepared for a new compression with almost no work, only + * sometimes falling back to the full, expensive reset that is always required + * when the stream is in an indeterminate state (i.e., the reset performed by + * LZ4_resetStream()). + * + * LZ4_streams are guaranteed to be in a valid state when: + * - returned from LZ4_createStream() + * - reset by LZ4_resetStream() + * - memset(stream, 0, sizeof(LZ4_stream_t)) + * - the stream was in a valid state and was reset by LZ4_resetStream_fast() + * - the stream was in a valid state and was then used in any compression call + * that returned success + * - the stream was in an indeterminate state and was used in a compression + * call that fully reset the state (LZ4_compress_fast_extState()) and that + * returned success + */ +LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr); + +/*! LZ4_compress_fast_extState_fastReset() : + * A variant of LZ4_compress_fast_extState(). + * + * Using this variant avoids an expensive initialization step. It is only safe + * to call if the state buffer is known to be correctly initialized already + * (see above comment on LZ4_resetStream_fast() for a definition of "correctly + * initialized"). From a high level, the difference is that this function + * initializes the provided state with a call to LZ4_resetStream_fast() while + * LZ4_compress_fast_extState() starts with a call to LZ4_resetStream(). + */ +LZ4LIB_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_attach_dictionary() : + * This is an experimental API that allows for the efficient use of a + * static dictionary many times. + * + * Rather than re-loading the dictionary buffer into a working context before + * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a + * working LZ4_stream_t, this function introduces a no-copy setup mechanism, + * in which the working stream references the dictionary stream in-place. + * + * Several assumptions are made about the state of the dictionary stream. + * Currently, only streams which have been prepared by LZ4_loadDict() should + * be expected to work. + * + * Alternatively, the provided dictionary stream pointer may be NULL, in which + * case any existing dictionary stream is unset. + * + * If a dictionary is provided, it replaces any pre-existing stream history. + * The dictionary contents are the only history that can be referenced and + * logically immediately precede the data compressed in the first subsequent + * compression call. + * + * The dictionary will only remain attached to the working stream through the + * first compression call, at the end of which it is cleared. The dictionary + * stream (and source buffer) must remain in-place / accessible / unchanged + * through the completion of the first compression call on the stream. + */ +LZ4LIB_API void LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream); + +#endif + +/*-************************************ + * Private definitions + ************************************** + * Do not use these definitions. + * They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. + * Using these definitions will expose code to API and/or ABI break in future versions of the library. + **************************************/ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ + +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +#include + +typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; +struct LZ4_stream_t_internal { + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint16_t initCheck; + uint16_t tableType; + const uint8_t* dictionary; + const LZ4_stream_t_internal* dictCtx; + uint32_t dictSize; +}; + +typedef struct { + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#else + +typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; +struct LZ4_stream_t_internal { + unsigned int hashTable[LZ4_HASH_SIZE_U32]; + unsigned int currentOffset; + unsigned short initCheck; + unsigned short tableType; + const unsigned char* dictionary; + const LZ4_stream_t_internal* dictCtx; + unsigned int dictSize; +}; + +typedef struct { + const unsigned char* externalDict; + size_t extDictSize; + const unsigned char* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#endif + +/*! + * LZ4_stream_t : + * information structure to track an LZ4 stream. + * init this structure before first use. + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * it may change in a future version ! + */ +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +union LZ4_stream_u { + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_stream_t */ + + +/*! + * LZ4_streamDecode_t : + * information structure to track an LZ4 stream during decompression. + * init this structure using LZ4_setStreamDecode (or memset()) before first use + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * and may change in a future version ! + */ +#define LZ4_STREAMDECODESIZE_U64 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +union LZ4_streamDecode_u { + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_streamDecode_t */ + + +/*-************************************ +* Obsolete Functions +**************************************/ + +/*! Deprecation warnings + Should deprecation warnings be a problem, + it is generally possible to disable them, + typically with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */ +#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS +# define LZ4_DEPRECATED(message) /* disable deprecation warnings */ +#else +# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define LZ4_DEPRECATED(message) [[deprecated(message)]] +# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__) +# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (LZ4_GCC_VERSION >= 301) +# define LZ4_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") +# define LZ4_DEPRECATED(message) +# endif +#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ + +/* Obsolete compression functions */ +LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* source, char* dest, int sourceSize); +LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* Obsolete decompression functions */ +LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize); +LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); + +/* Obsolete streaming functions; degraded functionality; do not use! + * + * In order to perform streaming compression, these functions depended on data + * that is no longer tracked in the state. They have been preserved as well as + * possible: using them will still produce a correct output. However, they don't + * actually retain any history between compression calls. The compression ratio + * achieved will therefore be no better than compressing each chunk + * independently. + */ +LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer); +LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void); +LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer); +LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state); + +/* Obsolete streaming decoding functions */ +LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); +LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); + +#endif /* LZ4_H_2983827168210 */ + + +#if defined (__cplusplus) +} +#endif diff --git a/nyx/nyx_gui/libs/fatfs/diskio.h b/bdk/libs/fatfs/diskio.h similarity index 88% rename from nyx/nyx_gui/libs/fatfs/diskio.h rename to bdk/libs/fatfs/diskio.h index d6ae8f8..b5299c6 100644 --- a/nyx/nyx_gui/libs/fatfs/diskio.h +++ b/bdk/libs/fatfs/diskio.h @@ -9,7 +9,7 @@ extern "C" { #endif -#include "../../utils/types.h" +#include /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -23,6 +23,14 @@ typedef enum { RES_PARERR /* 4: Invalid Parameter */ } DRESULT; +typedef enum { + DRIVE_SD = 0, + DRIVE_RAM = 1, + DRIVE_EMMC = 2, + DRIVE_BIS = 3, + DRIVE_EMU = 4 +} DDRIVE; + /*---------------------------------------*/ /* Prototypes for disk control functions */ @@ -33,6 +41,7 @@ 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); +DRESULT disk_set_info (BYTE pdrv, BYTE cmd, void *buff); /* Disk Status Bits (DSTATUS) */ @@ -47,9 +56,11 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Generic command (Used by FatFs) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define SET_SECTOR_COUNT 1 /* Set media size (needed at FF_USE_MKFS == 1) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ +#define SET_SECTOR_OFFSET 5 /* Set media logical offset */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ diff --git a/nyx/nyx_gui/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c similarity index 98% rename from nyx/nyx_gui/libs/fatfs/ff.c rename to bdk/libs/fatfs/ff.c index f7fdf20..109e87b 100644 --- a/nyx/nyx_gui/libs/fatfs/ff.c +++ b/bdk/libs/fatfs/ff.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -38,7 +38,8 @@ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ -#include "../../gfx/gfx.h" +#include +#include #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); //#define EFSPRINTF(...) @@ -3273,7 +3274,6 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ 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 */ - EFSPRINTF("WPEN1"); return FR_WRITE_PROTECTED; } return FR_OK; /* The filesystem object is valid */ @@ -3284,14 +3284,13 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ + fs->part_type = 0; /* Clear the Partition 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 */ - EFSPRINTF("MDNR"); 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 */ - EFSPRINTF("WPEN2"); return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ @@ -3318,6 +3317,20 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ EFSPRINTF("BRNL"); return FR_DISK_ERR; /* An error occured in the disk I/O layer */ } +#if FF_SIMPLE_GPT + if (fmt >= 2) { + /* If GPT Check the first partition */ + gpt_header_t *gpt_header = (gpt_header_t *)fs->win; + if (move_window(fs, 1) != FR_OK) return FR_DISK_ERR; + if (!mem_cmp(&gpt_header->signature, "EFI PART", 8)) { + if (move_window(fs, gpt_header->part_ent_lba) != FR_OK) return FR_DISK_ERR; + gpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win; + fs->part_type = 1; + bsect = gpt_entry->lba_start; + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } + } +#endif if (fmt >= 2) { EFSPRINTF("NOFAT"); return FR_NO_FILESYSTEM; /* No FAT volume is found */ @@ -3906,11 +3919,11 @@ FRESULT f_read ( -#ifdef FF_FASTFS +#if FF_FASTFS && FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Fast Read Aligned Sized File Without a Cache */ /*-----------------------------------------------------------------------*/ -#if FF_USE_FASTSEEK + FRESULT f_read_fast ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ @@ -3988,7 +4001,6 @@ FRESULT f_read_fast ( LEAVE_FF(fs, FR_OK); } #endif -#endif @@ -4132,11 +4144,11 @@ FRESULT f_write ( -#ifdef FF_FASTFS +#if FF_FASTFS && FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Fast Write Aligned Sized File Without a Cache */ /*-----------------------------------------------------------------------*/ -#if FF_USE_FASTSEEK + FRESULT f_write_fast ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ @@ -4219,7 +4231,6 @@ FRESULT f_write_fast ( LEAVE_FF(fs, FR_OK); } #endif -#endif @@ -4680,35 +4691,40 @@ FRESULT f_lseek ( -#ifdef FF_FASTFS -#if FF_USE_FASTSEEK +#if FF_FASTFS && FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ DWORD *f_expand_cltbl ( FIL* fp, /* Pointer to the file object */ - UINT tblsz, /* Size of table */ + UINT tblsz, /* Size of table (2 DWORDs + 2 DWORDs per fragment) */ FSIZE_t ofs /* File pointer from top of file */ ) { + /* + * Cluster table structure: + * Size (DWORD) + * Padding (DWORD) + * (Cluster Offset (DWORD) + Sequential clusters (DWORD)) * Fragments + */ if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ if (!fp->cltbl) { /* Allocate memory for cluster link table */ fp->cltbl = (DWORD *)ff_memalloc(tblsz); + if (!fp->cltbl) return (void *)0; fp->cltbl[0] = tblsz; } if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ ff_memfree(fp->cltbl); - fp->cltbl = NULL; + fp->cltbl = (void *)0; EFSPRINTF("CLTBLSZ"); - return NULL; + return (void *)0; } f_lseek(fp, 0); return fp->cltbl; } #endif -#endif @@ -5842,7 +5858,7 @@ FRESULT f_mkfs ( 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_fats = 2; /* 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) */ @@ -5870,7 +5886,7 @@ FRESULT f_mkfs ( 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 (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 131072 || (sz_blk & (sz_blk - 1))) sz_blk = 2048; /* Erase block to align data area. 1MB minimum */ #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; @@ -5906,7 +5922,7 @@ FRESULT f_mkfs ( } 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 */ + b_vol = (opt & FM_SFD) ? 0 : sz_blk; /* Volume start sector */ if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } @@ -6130,6 +6146,9 @@ FRESULT f_mkfs ( if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT size */ + if (n % n_fats) { /* Adjust fractional error if needed */ + n--; sz_rsv++; b_fat++; + } sz_fat += n / n_fats; } @@ -6170,7 +6189,9 @@ FRESULT f_mkfs ( #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 */ + /* Boot jump code (x86), OEM name */ + if (!(opt & FM_PRF2)) mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "NYX1.0.0", 11); + else mem_cpy(buf + BS_JmpBoot, "\xEB\xE9\x90\x00\x00\x00\x00\x00\x00\x00\x00", 11); 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 */ @@ -6183,23 +6204,27 @@ FRESULT f_mkfs ( } 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_word(buf + BPB_NumHeads, (opt & FM_PRF2) ? 16 : 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 + BS_VolID32, (opt & FM_PRF2) ? 0 : 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 */ + /* Volume label, FAT signature */ + if (!(opt & FM_PRF2)) mem_cpy(buf + BS_VolLab32, FF_MKFS_LABEL "FAT32 ", 19); + else mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); } 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 */ + /* Volume label, FAT signature */ + if (!(opt & FM_PRF2)) mem_cpy(buf + BS_VolLab, FF_MKFS_LABEL "FAT ", 19); + else mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); } 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 */ @@ -6210,13 +6235,35 @@ FRESULT f_mkfs ( 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# */ + if (opt & FM_PRF2) { + st_dword(buf + FSI_Free_Count, 0xFFFFFFFF); /* Invalidate free count */ + st_dword(buf + FSI_Nxt_Free, 0xFFFFFFFF); /* Invalidate last allocated cluster */ + } else { + 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) */ } + /* Create PRF2SAFE info */ + if (fmt == FS_FAT32 && opt & FM_PRF2) { + mem_set(buf, 0, ss); + st_dword(buf + 0, 0x32465250); /* Magic PRF2 */ + st_dword(buf + 4, 0x45464153); /* Magic SAFE */ + buf[16] = 0x64; /* Record type */ + st_dword(buf + 32, 0x03); /* Unknown. SYSTEM: 0x3F00. USER: 0x03. Volatile. */ + if (sz_vol < 0x1000000) { + st_dword(buf + 36, 21 + 1); /* 22 Entries. */ + st_dword(buf + 508, 0x90BB2F39); /* Sector CRC32 */ + } else { + st_dword(buf + 36, 21 + 2); /* 23 Entries. */ + st_dword(buf + 508, 0x5EA8AFC8); /* Sector CRC32 */ + } + disk_write(pdrv, buf, b_vol + 3, 1); /* Write PRF2SAFE info (VBR + 3) */ + } + /* Initialize FAT area */ mem_set(buf, 0, (UINT)szb_buf); sect = b_fat; /* FAT start sector */ @@ -6706,6 +6753,8 @@ int f_puts ( putbuff pb; + if (str == (void *)0) return EOF; /* String is NULL */ + putc_init(&pb, fp); while (*str) putc_bfd(&pb, *str++); /* Put the string */ return putc_flush(&pb); @@ -6732,6 +6781,8 @@ int f_printf ( TCHAR c, d, str[32], *p; + if (fmt == (void *)0) return EOF; /* String is NULL */ + putc_init(&pb, fp); va_start(arp, fmt); diff --git a/nyx/nyx_gui/libs/fatfs/ff.h b/bdk/libs/fatfs/ff.h similarity index 96% rename from nyx/nyx_gui/libs/fatfs/ff.h rename to bdk/libs/fatfs/ff.h index bf6f39a..3a6c423 100644 --- a/nyx/nyx_gui/libs/fatfs/ff.h +++ b/bdk/libs/fatfs/ff.h @@ -26,8 +26,8 @@ extern "C" { #endif -#include "../../utils/types.h" /* Basic integer types */ -#include "ffconf.h" /* FatFs configuration options */ +#include /* Basic integer types */ +#include /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). @@ -95,8 +95,8 @@ typedef DWORD FSIZE_t; /* Filesystem object structure (FATFS) */ typedef struct { - BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE part_type; /* Partition type (0:MBR, 1:GPT) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ @@ -138,6 +138,7 @@ typedef struct { DWORD bitbase; /* Allocation bitmap base sector */ #endif DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[FF_MAX_SS] __attribute__((aligned(8))); /* Disk access window for Directory, FAT (and file data at tiny cfg). DMA aligned. */ } FATFS; @@ -168,9 +169,6 @@ typedef struct { /* File object structure (FIL) */ typedef struct { -#if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ -#endif 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) */ @@ -184,6 +182,9 @@ typedef struct { #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] __attribute__((aligned(8))); /* File private data read/write window. DMA aligned. */ +#endif } FIL; @@ -246,7 +247,7 @@ typedef enum { 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 */ -#ifdef FF_FASTFS +#if FF_FASTFS FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */ FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */ #else @@ -263,10 +264,8 @@ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a f 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 */ -#ifdef FF_FASTFS FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */ FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */ -#endif 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 */ @@ -288,9 +287,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe 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 */ -#ifdef FF_FASTFS DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */ -#endif FRESULT f_expand (FIL* fp, FSIZE_t fsz, 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 */ @@ -369,6 +366,7 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #define FM_EXFAT 0x04 #define FM_ANY 0x07 #define FM_SFD 0x08 +#define FM_PRF2 0x10 /* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 @@ -380,8 +378,11 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ +#define AM_DEV 0x40 /* Device */ +#define AM_RVD 0x80 /* Reserved */ #ifdef __cplusplus diff --git a/nyx/nyx_gui/libs/fatfs/ffsystem.c b/bdk/libs/fatfs/ffsystem.c similarity index 59% rename from nyx/nyx_gui/libs/fatfs/ffsystem.c rename to bdk/libs/fatfs/ffsystem.c index fa44f8e..b4af454 100644 --- a/nyx/nyx_gui/libs/fatfs/ffsystem.c +++ b/bdk/libs/fatfs/ffsystem.c @@ -1,14 +1,12 @@ /*------------------------------------------------------------------------*/ /* Sample Code of OS Dependent Functions for FatFs */ -/* (C) ChaN, 2018 */ -/* (C) CTCaer, 2018 */ +/* (C) ChaN, 2018 */ +/* (C) CTCaer, 2018-2024 */ /*------------------------------------------------------------------------*/ +#include -#include "ff.h" -#include "../../mem/heap.h" - - +#include #if FF_USE_LFN == 3 /* Dynamic memory allocation */ @@ -20,7 +18,8 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if no UINT msize /* Number of bytes to allocate */ ) { - return malloc(msize); /* Allocate a new memory block with POSIX API */ + // Ensure size is aligned to SDMMC block size. + return malloc(ALIGN(msize, SDMMC_DAT_BLOCKSIZE)); /* Allocate a new memory block with POSIX API */ } @@ -37,3 +36,22 @@ void ff_memfree ( #endif +#if FF_FS_NORTC == 0 + +/*------------------------------------------------------------------------*/ +/* Get real time clock */ +/*------------------------------------------------------------------------*/ + +DWORD get_fattime ( + void +) +{ + rtc_time_t time; + + max77620_rtc_get_time_adjusted(&time); + + return (((DWORD)(time.year - 1980) << 25) | ((DWORD)time.month << 21) | ((DWORD)time.day << 16) | + ((DWORD)time.hour << 11) | ((DWORD)time.min << 5) | (time.sec >> 1)); +} + +#endif diff --git a/bootloader/libs/fatfs/ffunicode.c b/bdk/libs/fatfs/ffunicode.c similarity index 100% rename from bootloader/libs/fatfs/ffunicode.c rename to bdk/libs/fatfs/ffunicode.c diff --git a/nyx/nyx_gui/libs/lv_conf.h b/bdk/libs/lv_conf.h similarity index 94% rename from nyx/nyx_gui/libs/lv_conf.h rename to bdk/libs/lv_conf.h index 70ce4ff..89dc555 100644 --- a/nyx/nyx_gui/libs/lv_conf.h +++ b/bdk/libs/lv_conf.h @@ -17,8 +17,8 @@ #ifndef LV_CONF_H #define LV_CONF_H -#include "../utils/types.h" -#include "../../../common/memory_map.h" +#include +#include /*=================== Dynamic memory *===================*/ @@ -32,7 +32,7 @@ # define LV_MEM_ADR NYX_LV_MEM_ADR /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ # define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ #else /*LV_MEM_CUSTOM*/ -# define LV_MEM_CUSTOM_INCLUDE "../../../mem/heap.h" /*Header for the dynamic memory function*/ +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ # define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ # define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ #endif /*LV_MEM_CUSTOM*/ @@ -147,15 +147,19 @@ #define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ /*HAL settings*/ -#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ #if LV_TICK_CUSTOM == 1 -#define LV_TICK_CUSTOM_INCLUDE "../../../utils/util.h" /*Header for the sys time function*/ -#define LV_TICK_CUSTOM_SYS_TIME_EXPR (get_tmr_ms()) /*Expression evaluating to current systime in ms*/ +#define LV_TICK_CUSTOM_INCLUDE /*Header for the sys time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR ((u32)get_tmr_ms()) /*Expression evaluating to current systime in ms*/ #endif /*LV_TICK_CUSTOM*/ /*Log settings*/ -#define USE_LV_LOG 0 /*Enable/disable the log module*/ +#ifdef DEBUG_UART_LV_LOG +# define USE_LV_LOG 1 /*Enable/disable the log module*/ +#else +# define USE_LV_LOG 0 /*Enable/disable the log module*/ +#endif #if USE_LV_LOG /* How important log should be added: * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information @@ -163,7 +167,7 @@ * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail */ -# define LV_LOG_LEVEL LV_LOG_LEVEL_ERROR +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN /* 1: Print the log with 'printf'; 0: user need to register a callback*/ # define LV_LOG_PRINTF 1 #endif /*USE_LV_LOG*/ @@ -292,6 +296,9 @@ /*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ #define USE_LV_MBOX 1 +#if USE_LV_MBOX != 0 +# define LV_MBOX_CLOSE_ANIM_TIME 200 /*ms*/ +#endif /*Text area (dependencies: lv_label, lv_page)*/ #define USE_LV_TA 1 diff --git a/nyx/nyx_gui/libs/lvgl/docs/CODE_OF_CONDUCT.md b/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md similarity index 100% rename from nyx/nyx_gui/libs/lvgl/docs/CODE_OF_CONDUCT.md rename to bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md diff --git a/nyx/nyx_gui/libs/lvgl/docs/CONTRIBUTING.md b/bdk/libs/lvgl/docs/CONTRIBUTING.md similarity index 100% rename from nyx/nyx_gui/libs/lvgl/docs/CONTRIBUTING.md rename to bdk/libs/lvgl/docs/CONTRIBUTING.md diff --git a/nyx/nyx_gui/libs/lvgl/docs/astyle_c b/bdk/libs/lvgl/docs/astyle_c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/docs/astyle_c rename to bdk/libs/lvgl/docs/astyle_c diff --git a/nyx/nyx_gui/libs/lvgl/docs/astyle_h b/bdk/libs/lvgl/docs/astyle_h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/docs/astyle_h rename to bdk/libs/lvgl/docs/astyle_h diff --git a/nyx/nyx_gui/libs/lvgl/licence.txt b/bdk/libs/lvgl/licence.txt similarity index 100% rename from nyx/nyx_gui/libs/lvgl/licence.txt rename to bdk/libs/lvgl/licence.txt diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_core.mk b/bdk/libs/lvgl/lv_core/lv_core.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_core.mk rename to bdk/libs/lvgl/lv_core/lv_core.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_group.c b/bdk/libs/lvgl/lv_core/lv_group.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_group.c rename to bdk/libs/lvgl/lv_core/lv_group.c index 3fd4120..cedef7f 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_core/lv_group.c +++ b/bdk/libs/lvgl/lv_core/lv_group.c @@ -546,8 +546,8 @@ static void obj_to_foreground(lv_obj_t * obj) /*Move the last_top object to the foreground*/ lv_obj_t * par = lv_obj_get_parent(last_top); /*After list change it will be the new head*/ - lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); - lv_obj_invalidate(last_top); + if (lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top)) + lv_obj_invalidate(last_top); /*Only invalidate if not top*/ } } diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_group.h b/bdk/libs/lvgl/lv_core/lv_group.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_group.h rename to bdk/libs/lvgl/lv_core/lv_group.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_indev.c b/bdk/libs/lvgl/lv_core/lv_indev.c similarity index 98% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_indev.c rename to bdk/libs/lvgl/lv_core/lv_indev.c index 24cc798..d1dc582 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_core/lv_indev.c +++ b/bdk/libs/lvgl/lv_core/lv_indev.c @@ -357,7 +357,10 @@ static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data) if(i->cursor != NULL && (i->proc.last_point.x != data->point.x || i->proc.last_point.y != data->point.y)) { - lv_obj_set_pos(i->cursor, data->point.x, data->point.y); + /*Use cursor's center as pointer*/ + uint32_t off_x = lv_obj_get_width(i->cursor) >> 1; + uint32_t off_y = lv_obj_get_height(i->cursor) >> 1; + lv_obj_set_pos(i->cursor, data->point.x - off_x, data->point.y - off_y); } i->proc.act_point.x = data->point.x; @@ -643,8 +646,8 @@ static void indev_proc_press(lv_indev_proc_t * proc) /*Move the last_top object to the foreground*/ lv_obj_t * par = lv_obj_get_parent(last_top); /*After list change it will be the new head*/ - lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); - lv_obj_invalidate(last_top); + if (lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top)) + lv_obj_invalidate(last_top); /*Only invalidate if not top*/ } /*Send a signal about the press*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_indev.h b/bdk/libs/lvgl/lv_core/lv_indev.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_indev.h rename to bdk/libs/lvgl/lv_core/lv_indev.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_lang.c b/bdk/libs/lvgl/lv_core/lv_lang.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_lang.c rename to bdk/libs/lvgl/lv_core/lv_lang.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_lang.h b/bdk/libs/lvgl/lv_core/lv_lang.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_lang.h rename to bdk/libs/lvgl/lv_core/lv_lang.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_obj.c b/bdk/libs/lvgl/lv_core/lv_obj.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_obj.c rename to bdk/libs/lvgl/lv_core/lv_obj.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_obj.h b/bdk/libs/lvgl/lv_core/lv_obj.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_obj.h rename to bdk/libs/lvgl/lv_core/lv_obj.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_refr.c b/bdk/libs/lvgl/lv_core/lv_refr.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_refr.c rename to bdk/libs/lvgl/lv_core/lv_refr.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_refr.h b/bdk/libs/lvgl/lv_core/lv_refr.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_refr.h rename to bdk/libs/lvgl/lv_core/lv_refr.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_style.c b/bdk/libs/lvgl/lv_core/lv_style.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_style.c rename to bdk/libs/lvgl/lv_core/lv_style.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_style.h b/bdk/libs/lvgl/lv_core/lv_style.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_style.h rename to bdk/libs/lvgl/lv_core/lv_style.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_vdb.c b/bdk/libs/lvgl/lv_core/lv_vdb.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_vdb.c rename to bdk/libs/lvgl/lv_core/lv_vdb.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_core/lv_vdb.h b/bdk/libs/lvgl/lv_core/lv_vdb.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_core/lv_vdb.h rename to bdk/libs/lvgl/lv_core/lv_vdb.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw.c b/bdk/libs/lvgl/lv_draw/lv_draw.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw.c rename to bdk/libs/lvgl/lv_draw/lv_draw.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw.h b/bdk/libs/lvgl/lv_draw/lv_draw.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw.h rename to bdk/libs/lvgl/lv_draw/lv_draw.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw.mk b/bdk/libs/lvgl/lv_draw/lv_draw.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw.mk rename to bdk/libs/lvgl/lv_draw/lv_draw.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_arc.c b/bdk/libs/lvgl/lv_draw/lv_draw_arc.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_arc.c rename to bdk/libs/lvgl/lv_draw/lv_draw_arc.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_arc.h b/bdk/libs/lvgl/lv_draw/lv_draw_arc.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_arc.h rename to bdk/libs/lvgl/lv_draw/lv_draw_arc.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_img.c b/bdk/libs/lvgl/lv_draw/lv_draw_img.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_img.c rename to bdk/libs/lvgl/lv_draw/lv_draw_img.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_img.h b/bdk/libs/lvgl/lv_draw/lv_draw_img.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_img.h rename to bdk/libs/lvgl/lv_draw/lv_draw_img.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_label.c b/bdk/libs/lvgl/lv_draw/lv_draw_label.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_label.c rename to bdk/libs/lvgl/lv_draw/lv_draw_label.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_label.h b/bdk/libs/lvgl/lv_draw/lv_draw_label.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_label.h rename to bdk/libs/lvgl/lv_draw/lv_draw_label.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_line.c b/bdk/libs/lvgl/lv_draw/lv_draw_line.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_line.c rename to bdk/libs/lvgl/lv_draw/lv_draw_line.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_line.h b/bdk/libs/lvgl/lv_draw/lv_draw_line.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_line.h rename to bdk/libs/lvgl/lv_draw/lv_draw_line.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rbasic.c b/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rbasic.c rename to bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rbasic.h b/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rbasic.h rename to bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rect.c b/bdk/libs/lvgl/lv_draw/lv_draw_rect.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rect.c rename to bdk/libs/lvgl/lv_draw/lv_draw_rect.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rect.h b/bdk/libs/lvgl/lv_draw/lv_draw_rect.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_rect.h rename to bdk/libs/lvgl/lv_draw/lv_draw_rect.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_triangle.c b/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_triangle.c rename to bdk/libs/lvgl/lv_draw/lv_draw_triangle.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_triangle.h b/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_triangle.h rename to bdk/libs/lvgl/lv_draw/lv_draw_triangle.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_vbasic.c b/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_vbasic.c rename to bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_vbasic.h b/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_draw/lv_draw_vbasic.h rename to bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_120.c b/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c similarity index 98% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_120.c rename to bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c index 9a27deb..c97eda6 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_120.c +++ b/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c @@ -16,7 +16,7 @@ #include "../lv_misc/lv_font.h" -#include "../../../../../common/memory_map.h" +#include #if USE_HEKATE_SYMBOL_120 != 0 /*Can be enabled in lv_conf.h*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_20.c b/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_20.c rename to bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c index 8ded987..426bde8 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_20.c +++ b/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c @@ -16,7 +16,7 @@ #include "../lv_misc/lv_font.h" -#include "../../../../../common/memory_map.h" +#include #if USE_HEKATE_SYMBOL_20 != 0 /*Can be enabled in lv_conf.h*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_30.c b/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_30.c rename to bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c index 08842d2..4e0da47 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_fonts/hekate_symbol_30.c +++ b/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c @@ -16,7 +16,7 @@ #include "../lv_misc/lv_font.h" -#include "../../../../../common/memory_map.h" +#include #if USE_HEKATE_SYMBOL_30 != 0 /*Can be enabled in lv_conf.h*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/interui_20.c b/bdk/libs/lvgl/lv_fonts/interui_20.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/interui_20.c rename to bdk/libs/lvgl/lv_fonts/interui_20.c index db0bbe5..5f50c6c 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_fonts/interui_20.c +++ b/bdk/libs/lvgl/lv_fonts/interui_20.c @@ -16,7 +16,7 @@ #include "../lv_misc/lv_font.h" -#include "../../../../../common/memory_map.h" +#include #if USE_INTERUI_20 != 0 /*Can be enabled in lv_conf.h*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/interui_30.c b/bdk/libs/lvgl/lv_fonts/interui_30.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/interui_30.c rename to bdk/libs/lvgl/lv_fonts/interui_30.c index 1f97abf..238bcb1 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_fonts/interui_30.c +++ b/bdk/libs/lvgl/lv_fonts/interui_30.c @@ -16,7 +16,7 @@ #include "../lv_misc/lv_font.h" -#include "../../../../../common/memory_map.h" +#include #if USE_INTERUI_30 != 0 /*Can be enabled in lv_conf.h*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/lv_font_builtin.c b/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/lv_font_builtin.c rename to bdk/libs/lvgl/lv_fonts/lv_font_builtin.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/lv_font_builtin.h b/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/lv_font_builtin.h rename to bdk/libs/lvgl/lv_fonts/lv_font_builtin.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/lv_fonts.mk b/bdk/libs/lvgl/lv_fonts/lv_fonts.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/lv_fonts.mk rename to bdk/libs/lvgl/lv_fonts/lv_fonts.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_fonts/ubuntu_mono.c b/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_fonts/ubuntu_mono.c rename to bdk/libs/lvgl/lv_fonts/ubuntu_mono.c index b88cb2c..4c988fc 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_fonts/ubuntu_mono.c +++ b/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c @@ -16,7 +16,7 @@ #include "../lv_misc/lv_font.h" -#include "../../../../../common/memory_map.h" +#include #if USE_UBUNTU_MONO != 0 /*Can be enabled in lv_conf.h*/ diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal.h b/bdk/libs/lvgl/lv_hal/lv_hal.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal.h rename to bdk/libs/lvgl/lv_hal/lv_hal.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal.mk b/bdk/libs/lvgl/lv_hal/lv_hal.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal.mk rename to bdk/libs/lvgl/lv_hal/lv_hal.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_disp.c b/bdk/libs/lvgl/lv_hal/lv_hal_disp.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_disp.c rename to bdk/libs/lvgl/lv_hal/lv_hal_disp.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_disp.h b/bdk/libs/lvgl/lv_hal/lv_hal_disp.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_disp.h rename to bdk/libs/lvgl/lv_hal/lv_hal_disp.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_indev.c b/bdk/libs/lvgl/lv_hal/lv_hal_indev.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_indev.c rename to bdk/libs/lvgl/lv_hal/lv_hal_indev.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_indev.h b/bdk/libs/lvgl/lv_hal/lv_hal_indev.h similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_indev.h rename to bdk/libs/lvgl/lv_hal/lv_hal_indev.h index b9d4255..2355baa 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_indev.h +++ b/bdk/libs/lvgl/lv_hal/lv_hal_indev.h @@ -17,7 +17,7 @@ extern "C" { *********************/ #include #include "lv_hal.h" -#include "../../../utils/types.h" +#include #include "../lv_misc/lv_area.h" #include "../lv_core/lv_obj.h" diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_tick.c b/bdk/libs/lvgl/lv_hal/lv_hal_tick.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_tick.c rename to bdk/libs/lvgl/lv_hal/lv_hal_tick.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_tick.h b/bdk/libs/lvgl/lv_hal/lv_hal_tick.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_hal/lv_hal_tick.h rename to bdk/libs/lvgl/lv_hal/lv_hal_tick.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_anim.c b/bdk/libs/lvgl/lv_misc/lv_anim.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_anim.c rename to bdk/libs/lvgl/lv_misc/lv_anim.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_anim.h b/bdk/libs/lvgl/lv_misc/lv_anim.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_anim.h rename to bdk/libs/lvgl/lv_misc/lv_anim.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_area.c b/bdk/libs/lvgl/lv_misc/lv_area.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_area.c rename to bdk/libs/lvgl/lv_misc/lv_area.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_area.h b/bdk/libs/lvgl/lv_misc/lv_area.h similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_area.h rename to bdk/libs/lvgl/lv_misc/lv_area.h index bae0753..63ea059 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_area.h +++ b/bdk/libs/lvgl/lv_misc/lv_area.h @@ -15,7 +15,7 @@ extern "C" { * INCLUDES *********************/ #include -#include "../../../utils/types.h" +#include /********************* * DEFINES diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_circ.c b/bdk/libs/lvgl/lv_misc/lv_circ.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_circ.c rename to bdk/libs/lvgl/lv_misc/lv_circ.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_circ.h b/bdk/libs/lvgl/lv_misc/lv_circ.h similarity index 98% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_circ.h rename to bdk/libs/lvgl/lv_misc/lv_circ.h index f0fbb3f..bc1c1dd 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_circ.h +++ b/bdk/libs/lvgl/lv_misc/lv_circ.h @@ -16,7 +16,7 @@ extern "C" { *********************/ #include #include "lv_area.h" -#include "../../../utils/types.h" +#include /********************* * DEFINES diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_color.c b/bdk/libs/lvgl/lv_misc/lv_color.c similarity index 62% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_color.c rename to bdk/libs/lvgl/lv_misc/lv_color.c index 81b20ed..8c12193 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_color.c +++ b/bdk/libs/lvgl/lv_misc/lv_color.c @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * 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 . + */ + /** * @file lv_color.c * @@ -12,6 +28,8 @@ * DEFINES *********************/ +#define HUE_DEGREE 512 + /********************** * TYPEDEFS **********************/ @@ -43,57 +61,68 @@ * @param v value [0..100] * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) */ -lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v) +lv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val) { - if(s == 0) - return LV_COLOR_MAKE(v, v, v); - - h = (uint32_t)((uint32_t)h * 255) / 360; - s = (uint16_t)((uint16_t)s * 255) / 100; - v = (uint16_t)((uint16_t)v * 255) / 100; - uint8_t r, g, b; - uint8_t region, remainder, p, q, t; + uint32_t h = (hue * 360 * HUE_DEGREE -1) / 360; + uint32_t s = sat * 255 / 100; + uint32_t v = val * 255 / 100; + uint32_t p = (256 * v - s * v) / 256; + uint32_t region = h / (60 * 512); + + if(sat == 0) + return LV_COLOR_MAKE(v, v, v); - region = h / 43; - remainder = (h - (region * 43)) * 6; + if (region & 1) + { + uint32_t q = (256 * 60 * HUE_DEGREE * v - h * s * v + 60 * HUE_DEGREE * s * v * region) / + (256 * 60 * HUE_DEGREE); - p = (v * (255 - s)) >> 8; - q = (v * (255 - ((s * remainder) >> 8))) >> 8; - t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; - - switch(region) { - case 0: - r = v; - g = t; - b = p; - break; + switch (region) + { case 1: r = q; g = v; b = p; break; + case 3: + r = p; + g = q; + b = v; + break; + case 5: + default: + r = v; + g = p; + b = q; + break; + } + } + else + { + uint32_t t = (256 * 60 * HUE_DEGREE * v + h * s * v - 60 * HUE_DEGREE * s * v * (region + 1)) / + (256 * 60 * HUE_DEGREE); + + switch (region) + { + case 0: + r = v; + g = t; + b = p; + break; case 2: r = p; g = v; b = t; break; - case 3: - r = p; - g = q; - b = v; - break; case 4: + default: r = t; g = p; b = v; break; - default: - r = v; - g = p; - b = q; - break; + } } return LV_COLOR_MAKE(r, g, b); diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_color.h b/bdk/libs/lvgl/lv_misc/lv_color.h similarity index 95% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_color.h rename to bdk/libs/lvgl/lv_misc/lv_color.h index 45f95db..59f038f 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_color.h +++ b/bdk/libs/lvgl/lv_misc/lv_color.h @@ -412,17 +412,17 @@ static inline uint8_t lv_color_brightness(lv_color_t color) #endif #if LV_COLOR_DEPTH == 32 // Concatenate into one 32-bit set. -#define LV_COLOR_HEX(c) ((lv_color_t){.full = (c | 0xFF000000)}) +#define LV_COLOR_HEX(c) ((lv_color_t){.full = ((c) | 0xFF000000)}) #else -#define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)c >> 16) & 0xFF), \ - ((uint32_t)((uint32_t)c >> 8) & 0xFF), \ - ((uint32_t) c & 0xFF)) +#define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)(c) >> 16) & 0xFF), \ + ((uint32_t)((uint32_t)(c) >> 8) & 0xFF), \ + ((uint32_t) (c) & 0xFF)) #endif /*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ -#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ - ((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ - ((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) +#define LV_COLOR_HEX3(c) LV_COLOR_MAKE(((((c) >> 4) & 0xF0) | (((c) >> 8) & 0xF)), \ + ((uint32_t)((c) & 0xF0) | (((c) & 0xF0) >> 4)), \ + ((uint32_t)((c) & 0xF) | (((c) & 0xF) << 4))) /** @@ -432,7 +432,7 @@ static inline uint8_t lv_color_brightness(lv_color_t color) * @param v value [0..100] * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) */ -lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v); +lv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val); /** * Convert an RGB color to HSV diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_font.c b/bdk/libs/lvgl/lv_misc/lv_font.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_font.c rename to bdk/libs/lvgl/lv_misc/lv_font.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_font.h b/bdk/libs/lvgl/lv_misc/lv_font.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_font.h rename to bdk/libs/lvgl/lv_misc/lv_font.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_fs.c b/bdk/libs/lvgl/lv_misc/lv_fs.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_fs.c rename to bdk/libs/lvgl/lv_misc/lv_fs.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_fs.h b/bdk/libs/lvgl/lv_misc/lv_fs.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_fs.h rename to bdk/libs/lvgl/lv_misc/lv_fs.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_gc.c b/bdk/libs/lvgl/lv_misc/lv_gc.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_gc.c rename to bdk/libs/lvgl/lv_misc/lv_gc.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_gc.h b/bdk/libs/lvgl/lv_misc/lv_gc.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_gc.h rename to bdk/libs/lvgl/lv_misc/lv_gc.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_ll.c b/bdk/libs/lvgl/lv_misc/lv_ll.c similarity index 98% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_ll.c rename to bdk/libs/lvgl/lv_misc/lv_ll.c index 43d8847..5583311 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_ll.c +++ b/bdk/libs/lvgl/lv_misc/lv_ll.c @@ -215,9 +215,12 @@ void lv_ll_clear(lv_ll_t * ll_p) * @param ll_ori_p pointer to the original (old) linked list * @param ll_new_p pointer to the new linked list * @param node pointer to a node + * @return head changed */ -void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node) +bool lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node) { + bool changed = ll_new_p->head != node; + lv_ll_rem(ll_ori_p, node); /*Set node as head*/ @@ -232,6 +235,8 @@ void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node) if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/ ll_new_p->tail = node; } + + return changed; } /** diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_ll.h b/bdk/libs/lvgl/lv_misc/lv_ll.h similarity index 97% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_ll.h rename to bdk/libs/lvgl/lv_misc/lv_ll.h index 086ba40..5bde7e5 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_ll.h +++ b/bdk/libs/lvgl/lv_misc/lv_ll.h @@ -89,8 +89,9 @@ void lv_ll_clear(lv_ll_t * ll_p); * @param ll_ori_p pointer to the original (old) linked list * @param ll_new_p pointer to the new linked list * @param node pointer to a node + * @return head changed */ -void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); +bool lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); /** * Return with head node of the linked list diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_log.c b/bdk/libs/lvgl/lv_misc/lv_log.c similarity index 91% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_log.c rename to bdk/libs/lvgl/lv_misc/lv_log.c index 79f8113..9cd3d49 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_log.c +++ b/bdk/libs/lvgl/lv_misc/lv_log.c @@ -11,9 +11,9 @@ #if LV_LOG_PRINTF #include -#include "../../../mem/heap.h" -#include "../../../soc/uart.h" -#include "../../../utils/sprintf.h" +#include +#include +#include #endif /********************* * DEFINES @@ -63,11 +63,11 @@ void lv_log_add(lv_log_level_t level, const char * file, int line, const char * if(level >= LV_LOG_LEVEL) { -#if LV_LOG_PRINTF +#if LV_LOG_PRINTF && defined(DEBUG_UART_PORT) static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"}; char *log = (char *)malloc(0x1000); s_printf(log, "%s: %s \t(%s #%d)\r\n", lvl_prefix[level], dsc, file, line); - uart_send(UART_B, (u8 *)log, strlen(log) + 1); + uart_send(DEBUG_UART_PORT, (u8 *)log, strlen(log) + 1); //gfx_printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line); #else if(print_cb) print_cb(level, file, line, dsc); diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_log.h b/bdk/libs/lvgl/lv_misc/lv_log.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_log.h rename to bdk/libs/lvgl/lv_misc/lv_log.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_math.c b/bdk/libs/lvgl/lv_misc/lv_math.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_math.c rename to bdk/libs/lvgl/lv_misc/lv_math.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_math.h b/bdk/libs/lvgl/lv_misc/lv_math.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_math.h rename to bdk/libs/lvgl/lv_misc/lv_math.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_mem.c b/bdk/libs/lvgl/lv_misc/lv_mem.c similarity index 90% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_mem.c rename to bdk/libs/lvgl/lv_misc/lv_mem.c index 9156e86..08f52d5 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_mem.c +++ b/bdk/libs/lvgl/lv_misc/lv_mem.c @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * 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 . + */ + /** * @file lv_mem.c * General and portable implementation of malloc and free. @@ -11,6 +27,8 @@ #include "lv_math.h" #include +#include + #if LV_MEM_CUSTOM != 0 #include LV_MEM_CUSTOM_INCLUDE #endif @@ -38,12 +56,14 @@ typedef union { struct { MEM_UNIT used: 1; //1: if the entry is used - MEM_UNIT d_size: 31; //Size off the data (1 means 4 bytes) + MEM_UNIT d_size: 31; //Size of the data }; MEM_UNIT header; //The header (used + d_size) - uint32_t align[7]; //Align header size to 32 bytes + MEM_UNIT align[8]; //Align header size to MEM_UNIT * 8 bytes } lv_mem_header_t; +static_assert(sizeof(lv_mem_header_t) == 32, "Node header must be 32 bytes!"); + typedef struct { lv_mem_header_t header; uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/ @@ -110,10 +130,10 @@ void * lv_mem_alloc(uint32_t size) return &zero_mem; } - /*Round the size up to 32*/ - if(size & 0x1F) { - size = size & (~0x1F); - size += 0x20; + /*Round the size to lv_mem_header_t*/ + if(size & (sizeof(lv_mem_header_t) - 1)) { + size = size & (~(sizeof(lv_mem_header_t) - 1)); + size += sizeof(lv_mem_header_t); } void * alloc = NULL; @@ -213,6 +233,12 @@ void lv_mem_free(const void * data) void * lv_mem_realloc(void * data_p, uint32_t new_size) { + /*Round the size to lv_mem_header_t*/ + if(new_size & (sizeof(lv_mem_header_t) - 1)) { + new_size = new_size & (~(sizeof(lv_mem_header_t) - 1)); + new_size += sizeof(lv_mem_header_t); + } + /*data_p could be previously freed pointer (in this case it is invalid)*/ if(data_p != NULL) { lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t)); @@ -424,13 +450,6 @@ static void * ent_alloc(lv_mem_ent_t * e, uint32_t size) */ static void ent_trunc(lv_mem_ent_t * e, uint32_t size) { - - /*Round the size up to 32*/ - if(size & 0x1F) { - size = size & (~0x1F); - size += 0x20; - } - /*Don't let empty space only for a header without data*/ if(e->header.d_size == size + sizeof(lv_mem_header_t)) { size = e->header.d_size; diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_mem.h b/bdk/libs/lvgl/lv_misc/lv_mem.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_mem.h rename to bdk/libs/lvgl/lv_misc/lv_mem.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_misc.mk b/bdk/libs/lvgl/lv_misc/lv_misc.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_misc.mk rename to bdk/libs/lvgl/lv_misc/lv_misc.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_symbol_def.h b/bdk/libs/lvgl/lv_misc/lv_symbol_def.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_symbol_def.h rename to bdk/libs/lvgl/lv_misc/lv_symbol_def.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_task.c b/bdk/libs/lvgl/lv_misc/lv_task.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_task.c rename to bdk/libs/lvgl/lv_misc/lv_task.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_task.h b/bdk/libs/lvgl/lv_misc/lv_task.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_task.h rename to bdk/libs/lvgl/lv_misc/lv_task.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_templ.c b/bdk/libs/lvgl/lv_misc/lv_templ.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_templ.c rename to bdk/libs/lvgl/lv_misc/lv_templ.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_templ.h b/bdk/libs/lvgl/lv_misc/lv_templ.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_templ.h rename to bdk/libs/lvgl/lv_misc/lv_templ.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_txt.c b/bdk/libs/lvgl/lv_misc/lv_txt.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_txt.c rename to bdk/libs/lvgl/lv_misc/lv_txt.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_txt.h b/bdk/libs/lvgl/lv_misc/lv_txt.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_txt.h rename to bdk/libs/lvgl/lv_misc/lv_txt.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_ufs.c b/bdk/libs/lvgl/lv_misc/lv_ufs.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_ufs.c rename to bdk/libs/lvgl/lv_misc/lv_ufs.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_misc/lv_ufs.h b/bdk/libs/lvgl/lv_misc/lv_ufs.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_misc/lv_ufs.h rename to bdk/libs/lvgl/lv_misc/lv_ufs.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_arc.c b/bdk/libs/lvgl/lv_objx/lv_arc.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_arc.c rename to bdk/libs/lvgl/lv_objx/lv_arc.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_arc.h b/bdk/libs/lvgl/lv_objx/lv_arc.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_arc.h rename to bdk/libs/lvgl/lv_objx/lv_arc.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_bar.c b/bdk/libs/lvgl/lv_objx/lv_bar.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_bar.c rename to bdk/libs/lvgl/lv_objx/lv_bar.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_bar.h b/bdk/libs/lvgl/lv_objx/lv_bar.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_bar.h rename to bdk/libs/lvgl/lv_objx/lv_bar.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_btn.c b/bdk/libs/lvgl/lv_objx/lv_btn.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_btn.c rename to bdk/libs/lvgl/lv_objx/lv_btn.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_btn.h b/bdk/libs/lvgl/lv_objx/lv_btn.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_btn.h rename to bdk/libs/lvgl/lv_objx/lv_btn.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_btnm.c b/bdk/libs/lvgl/lv_objx/lv_btnm.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_btnm.c rename to bdk/libs/lvgl/lv_objx/lv_btnm.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_btnm.h b/bdk/libs/lvgl/lv_objx/lv_btnm.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_btnm.h rename to bdk/libs/lvgl/lv_objx/lv_btnm.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_calendar.c b/bdk/libs/lvgl/lv_objx/lv_calendar.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_calendar.c rename to bdk/libs/lvgl/lv_objx/lv_calendar.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_calendar.h b/bdk/libs/lvgl/lv_objx/lv_calendar.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_calendar.h rename to bdk/libs/lvgl/lv_objx/lv_calendar.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_canvas.c b/bdk/libs/lvgl/lv_objx/lv_canvas.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_canvas.c rename to bdk/libs/lvgl/lv_objx/lv_canvas.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_canvas.h b/bdk/libs/lvgl/lv_objx/lv_canvas.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_canvas.h rename to bdk/libs/lvgl/lv_objx/lv_canvas.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_cb.c b/bdk/libs/lvgl/lv_objx/lv_cb.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_cb.c rename to bdk/libs/lvgl/lv_objx/lv_cb.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_cb.h b/bdk/libs/lvgl/lv_objx/lv_cb.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_cb.h rename to bdk/libs/lvgl/lv_objx/lv_cb.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_chart.c b/bdk/libs/lvgl/lv_objx/lv_chart.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_chart.c rename to bdk/libs/lvgl/lv_objx/lv_chart.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_chart.h b/bdk/libs/lvgl/lv_objx/lv_chart.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_chart.h rename to bdk/libs/lvgl/lv_objx/lv_chart.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_cont.c b/bdk/libs/lvgl/lv_objx/lv_cont.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_cont.c rename to bdk/libs/lvgl/lv_objx/lv_cont.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_cont.h b/bdk/libs/lvgl/lv_objx/lv_cont.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_cont.h rename to bdk/libs/lvgl/lv_objx/lv_cont.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_ddlist.c b/bdk/libs/lvgl/lv_objx/lv_ddlist.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_ddlist.c rename to bdk/libs/lvgl/lv_objx/lv_ddlist.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_ddlist.h b/bdk/libs/lvgl/lv_objx/lv_ddlist.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_ddlist.h rename to bdk/libs/lvgl/lv_objx/lv_ddlist.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_gauge.c b/bdk/libs/lvgl/lv_objx/lv_gauge.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_gauge.c rename to bdk/libs/lvgl/lv_objx/lv_gauge.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_gauge.h b/bdk/libs/lvgl/lv_objx/lv_gauge.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_gauge.h rename to bdk/libs/lvgl/lv_objx/lv_gauge.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_img.c b/bdk/libs/lvgl/lv_objx/lv_img.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_img.c rename to bdk/libs/lvgl/lv_objx/lv_img.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_img.h b/bdk/libs/lvgl/lv_objx/lv_img.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_img.h rename to bdk/libs/lvgl/lv_objx/lv_img.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_imgbtn.c b/bdk/libs/lvgl/lv_objx/lv_imgbtn.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_imgbtn.c rename to bdk/libs/lvgl/lv_objx/lv_imgbtn.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_imgbtn.h b/bdk/libs/lvgl/lv_objx/lv_imgbtn.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_imgbtn.h rename to bdk/libs/lvgl/lv_objx/lv_imgbtn.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_kb.c b/bdk/libs/lvgl/lv_objx/lv_kb.c similarity index 93% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_kb.c rename to bdk/libs/lvgl/lv_objx/lv_kb.c index 395fc8d..8548d55 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_kb.c +++ b/bdk/libs/lvgl/lv_objx/lv_kb.c @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * 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 . + */ /** * @file lv_kb.c @@ -59,6 +74,13 @@ static const char * kb_map_num[] = { "7", "8", "9", "\202Bksp", "\n", "+/-", "0", ".", SYMBOL_LEFT, SYMBOL_RIGHT, "" }; + +static const char * kb_map_hex[] = { + "1", "2", "3", "A", "D", "\212", "\n", + "4", "5", "6", "B", "E", "\202Bksp", "\n", + "7", "8", "9", "C", "F", "\202"SYMBOL_OK, "\n", + "\211", "0", "\213", SYMBOL_LEFT, SYMBOL_RIGHT, "" +}; /********************** * MACROS **********************/ @@ -183,6 +205,7 @@ void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode) ext->mode = mode; if(mode == LV_KB_MODE_TEXT) lv_btnm_set_map(kb, kb_map_lc); else if(mode == LV_KB_MODE_NUM) lv_btnm_set_map(kb, kb_map_num); + else if (mode == LV_KB_MODE_HEX) lv_btnm_set_map(kb, kb_map_hex); } diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_kb.h b/bdk/libs/lvgl/lv_objx/lv_kb.h similarity index 88% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_kb.h rename to bdk/libs/lvgl/lv_objx/lv_kb.h index c729a4e..027b121 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_kb.h +++ b/bdk/libs/lvgl/lv_objx/lv_kb.h @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * 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 . + */ + /** * @file lv_kb.h * @@ -44,6 +60,7 @@ extern "C" { enum { LV_KB_MODE_TEXT, LV_KB_MODE_NUM, + LV_KB_MODE_HEX }; typedef uint8_t lv_kb_mode_t; diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_label.c b/bdk/libs/lvgl/lv_objx/lv_label.c similarity index 99% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_label.c rename to bdk/libs/lvgl/lv_objx/lv_label.c index 77b087a..57ac2d0 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_label.c +++ b/bdk/libs/lvgl/lv_objx/lv_label.c @@ -156,7 +156,7 @@ void lv_label_set_text(lv_obj_t * label, const char * text) return; } - if(ext->text == text) { + if(ext->text == text && ext->static_txt == 0) { /*If set its own text then reallocate it (maybe its size changed)*/ ext->text = lv_mem_realloc(ext->text, strlen(ext->text) + 1); lv_mem_assert(ext->text); diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_label.h b/bdk/libs/lvgl/lv_objx/lv_label.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_label.h rename to bdk/libs/lvgl/lv_objx/lv_label.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_led.c b/bdk/libs/lvgl/lv_objx/lv_led.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_led.c rename to bdk/libs/lvgl/lv_objx/lv_led.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_led.h b/bdk/libs/lvgl/lv_objx/lv_led.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_led.h rename to bdk/libs/lvgl/lv_objx/lv_led.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_line.c b/bdk/libs/lvgl/lv_objx/lv_line.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_line.c rename to bdk/libs/lvgl/lv_objx/lv_line.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_line.h b/bdk/libs/lvgl/lv_objx/lv_line.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_line.h rename to bdk/libs/lvgl/lv_objx/lv_line.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_list.c b/bdk/libs/lvgl/lv_objx/lv_list.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_list.c rename to bdk/libs/lvgl/lv_objx/lv_list.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_list.h b/bdk/libs/lvgl/lv_objx/lv_list.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_list.h rename to bdk/libs/lvgl/lv_objx/lv_list.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_lmeter.c b/bdk/libs/lvgl/lv_objx/lv_lmeter.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_lmeter.c rename to bdk/libs/lvgl/lv_objx/lv_lmeter.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_lmeter.h b/bdk/libs/lvgl/lv_objx/lv_lmeter.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_lmeter.h rename to bdk/libs/lvgl/lv_objx/lv_lmeter.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_mbox.c b/bdk/libs/lvgl/lv_objx/lv_mbox.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_mbox.c rename to bdk/libs/lvgl/lv_objx/lv_mbox.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_mbox.h b/bdk/libs/lvgl/lv_objx/lv_mbox.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_mbox.h rename to bdk/libs/lvgl/lv_objx/lv_mbox.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_objx.mk b/bdk/libs/lvgl/lv_objx/lv_objx.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_objx.mk rename to bdk/libs/lvgl/lv_objx/lv_objx.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_objx_templ.c b/bdk/libs/lvgl/lv_objx/lv_objx_templ.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_objx_templ.c rename to bdk/libs/lvgl/lv_objx/lv_objx_templ.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_objx_templ.h b/bdk/libs/lvgl/lv_objx/lv_objx_templ.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_objx_templ.h rename to bdk/libs/lvgl/lv_objx/lv_objx_templ.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_page.c b/bdk/libs/lvgl/lv_objx/lv_page.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_page.c rename to bdk/libs/lvgl/lv_objx/lv_page.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_page.h b/bdk/libs/lvgl/lv_objx/lv_page.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_page.h rename to bdk/libs/lvgl/lv_objx/lv_page.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_preload.c b/bdk/libs/lvgl/lv_objx/lv_preload.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_preload.c rename to bdk/libs/lvgl/lv_objx/lv_preload.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_preload.h b/bdk/libs/lvgl/lv_objx/lv_preload.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_preload.h rename to bdk/libs/lvgl/lv_objx/lv_preload.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_roller.c b/bdk/libs/lvgl/lv_objx/lv_roller.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_roller.c rename to bdk/libs/lvgl/lv_objx/lv_roller.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_roller.h b/bdk/libs/lvgl/lv_objx/lv_roller.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_roller.h rename to bdk/libs/lvgl/lv_objx/lv_roller.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_slider.c b/bdk/libs/lvgl/lv_objx/lv_slider.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_slider.c rename to bdk/libs/lvgl/lv_objx/lv_slider.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_slider.h b/bdk/libs/lvgl/lv_objx/lv_slider.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_slider.h rename to bdk/libs/lvgl/lv_objx/lv_slider.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_spinbox.c b/bdk/libs/lvgl/lv_objx/lv_spinbox.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_spinbox.c rename to bdk/libs/lvgl/lv_objx/lv_spinbox.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_spinbox.h b/bdk/libs/lvgl/lv_objx/lv_spinbox.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_spinbox.h rename to bdk/libs/lvgl/lv_objx/lv_spinbox.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_sw.c b/bdk/libs/lvgl/lv_objx/lv_sw.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_sw.c rename to bdk/libs/lvgl/lv_objx/lv_sw.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_sw.h b/bdk/libs/lvgl/lv_objx/lv_sw.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_sw.h rename to bdk/libs/lvgl/lv_objx/lv_sw.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_ta.c b/bdk/libs/lvgl/lv_objx/lv_ta.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_ta.c rename to bdk/libs/lvgl/lv_objx/lv_ta.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_ta.h b/bdk/libs/lvgl/lv_objx/lv_ta.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_ta.h rename to bdk/libs/lvgl/lv_objx/lv_ta.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_table.c b/bdk/libs/lvgl/lv_objx/lv_table.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_table.c rename to bdk/libs/lvgl/lv_objx/lv_table.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_table.h b/bdk/libs/lvgl/lv_objx/lv_table.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_table.h rename to bdk/libs/lvgl/lv_objx/lv_table.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_tabview.c b/bdk/libs/lvgl/lv_objx/lv_tabview.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_tabview.c rename to bdk/libs/lvgl/lv_objx/lv_tabview.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_tabview.h b/bdk/libs/lvgl/lv_objx/lv_tabview.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_tabview.h rename to bdk/libs/lvgl/lv_objx/lv_tabview.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_tileview.c b/bdk/libs/lvgl/lv_objx/lv_tileview.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_tileview.c rename to bdk/libs/lvgl/lv_objx/lv_tileview.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_tileview.h b/bdk/libs/lvgl/lv_objx/lv_tileview.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_tileview.h rename to bdk/libs/lvgl/lv_objx/lv_tileview.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_win.c b/bdk/libs/lvgl/lv_objx/lv_win.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_win.c rename to bdk/libs/lvgl/lv_objx/lv_win.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_objx/lv_win.h b/bdk/libs/lvgl/lv_objx/lv_win.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_objx/lv_win.h rename to bdk/libs/lvgl/lv_objx/lv_win.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme.c b/bdk/libs/lvgl/lv_themes/lv_theme.c similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme.c rename to bdk/libs/lvgl/lv_themes/lv_theme.c diff --git a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme.h b/bdk/libs/lvgl/lv_themes/lv_theme.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme.h rename to bdk/libs/lvgl/lv_themes/lv_theme.h diff --git a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme_hekate.c b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c similarity index 86% rename from nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme_hekate.c rename to bdk/libs/lvgl/lv_themes/lv_theme_hekate.c index 423fcaf..f151dbe 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme_hekate.c +++ b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -25,16 +25,23 @@ * DEFINES *********************/ #define DEF_RADIUS 4 -#define COLOR_SHADOW_LIGHT LV_COLOR_HEX3(0xAAA) +#define COLOR_SHADOW_LIGHT LV_COLOR_HEX(0xAAAAAA) #define COLOR_SHADOW_DARK LV_COLOR_HEX(0x1F1F1F) -#define COLOR_HOS_TURQUOISE LV_COLOR_HEX(0x00FFC9) -#define COLOR_HOS_TEAL_LIGHTER LV_COLOR_HEX(0x00EDBA) -#define COLOR_HOS_TEAL_LIGHT LV_COLOR_HEX(0x00B78F) -#define COLOR_HOS_TEAL LV_COLOR_HEX(0x00A273) -#define COLOR_HOS_BG LV_COLOR_HEX(0x2D2D2D) -#define COLOR_HOS_BG_LIGHT LV_COLOR_HEX(0x3D3D3D) +#define COLOR_HOS_TURQUOISE (lv_color_hsv_to_rgb(_hue, 100, 100)) // 0x00FFC9 +#define COLOR_HOS_TEAL_LIGHTER (lv_color_hsv_to_rgb(_hue, 100, 93)) // 0x00EDBA +#define COLOR_HOS_TEAL_LIGHT (lv_color_hsv_to_rgb(_hue, 100, 72)) // 0x00B78F +#define COLOR_HOS_TEAL (lv_color_hsv_to_rgb(_hue, 100, 64)) // 0x00A273 +#define COLOR_HOS_ORANGE LV_COLOR_HEX(0xFF5500) #define COLOR_HOS_TXT_WHITE LV_COLOR_HEX(0xFBFBFB) +#define COLOR_BG_DARKER LV_COLOR_HEX(theme_bg_color ? (theme_bg_color - 0x121212) : 0x0B0B0B) // 0x1B1B1B. +#define COLOR_BG_DARK LV_COLOR_HEX(theme_bg_color ? (theme_bg_color - 0x0B0B0B) : 0x121212) // 0x222222. +#define COLOR_BG LV_COLOR_HEX(theme_bg_color) // 0x2D2D2D. +#define COLOR_BG_LIGHT LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D) // 0x3D3D3D. +#define COLOR_BG_LIGHTER LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x191919) : 0x363636) // 0x464646. +#define COLOR_LIGHT_BORDER LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x202020) : 0x3D3D3D) // 0x4D4D4D. + + /********************** * TYPEDEFS **********************/ @@ -53,8 +60,9 @@ static lv_style_t def; static lv_style_t sb; /*Saved input parameters*/ -static uint16_t _hue; +static uint16_t _hue; static lv_font_t * _font; +uint32_t theme_bg_color; /********************** * MACROS @@ -76,18 +84,17 @@ static void basic_init(void) //def.image.opa = LV_OPA_COVER; lv_style_copy(&bg, &def); - bg.body.main_color = COLOR_HOS_BG; - //bg.body.main_color = LV_COLOR_BLACK; + bg.body.main_color = COLOR_BG; bg.body.grad_color = bg.body.main_color; bg.body.radius = 0; bg.body.empty = 1; lv_style_copy(&panel, &def); panel.body.radius = DEF_RADIUS; - panel.body.main_color = COLOR_HOS_BG; - panel.body.grad_color = COLOR_HOS_BG; + panel.body.main_color = COLOR_BG; + panel.body.grad_color = COLOR_BG; panel.body.border.width = 1; - panel.body.border.color = LV_COLOR_HEX(0x4D4D4D); + panel.body.border.color = COLOR_LIGHT_BORDER; panel.body.border.opa = LV_OPA_COVER; panel.body.shadow.color = COLOR_SHADOW_LIGHT; panel.body.shadow.type = LV_SHADOW_BOTTOM; @@ -125,7 +132,7 @@ static void btn_init(void) static lv_style_t rel, pr, tgl_rel, tgl_pr, ina; lv_style_copy(&rel, &def); - rel.body.main_color = COLOR_HOS_BG_LIGHT; + rel.body.main_color = COLOR_BG_LIGHT; rel.body.grad_color = rel.body.main_color; rel.body.radius = 6; rel.body.padding.hor = LV_DPI / 3; @@ -135,7 +142,7 @@ static void btn_init(void) rel.body.shadow.type = LV_SHADOW_BOTTOM; rel.body.shadow.width = 6; rel.body.border.width = 0; - rel.body.border.color = COLOR_HOS_BG_LIGHT; + rel.body.border.color = COLOR_BG_LIGHT; rel.body.border.part = LV_BORDER_FULL; //rel.text.color = COLOR_HOS_TXT_WHITE; @@ -158,7 +165,7 @@ static void btn_init(void) tgl_pr.body.shadow.width = 0; lv_style_copy(&ina, &rel); - ina.body.main_color = LV_COLOR_HEX(0x1B1B1B); + ina.body.main_color = COLOR_BG_DARK; ina.body.grad_color = ina.body.main_color; //ina.body.shadow.width = 0; ina.text.color = LV_COLOR_HEX(0x888888); @@ -183,10 +190,10 @@ static void label_init(void) prim.text.color = COLOR_HOS_TXT_WHITE; lv_style_copy(&sec, &prim); - sec.text.color = LV_COLOR_HEX(0xFF5500); + sec.text.color = COLOR_HOS_ORANGE; lv_style_copy(&hint, &prim); - hint.text.color = LV_COLOR_HEX3(0xCCC); + hint.text.color = LV_COLOR_HEX(0xCCCCCC); theme.label.prim = &prim; theme.label.sec = &sec; @@ -199,11 +206,11 @@ static void img_init(void) #if USE_LV_IMG != 0 static lv_style_t img_light, img_dark; lv_style_copy(&img_light, &def); - img_light.image.color = LV_COLOR_HEX(0xffffff); + img_light.image.color = LV_COLOR_WHITE; img_light.image.intense = LV_OPA_80; lv_style_copy(&img_dark, &def); - img_dark.image.color = LV_COLOR_HEX(0x1B1B1B); + img_dark.image.color = COLOR_BG_DARKER; img_dark.image.intense = LV_OPA_80; @@ -246,7 +253,7 @@ static void bar_init(void) static lv_style_t bar_bg, bar_indic; lv_style_copy(&bar_bg, &def); - bar_bg.body.main_color = LV_COLOR_HEX(0x4D4D4D); + bar_bg.body.main_color = COLOR_LIGHT_BORDER; bar_bg.body.grad_color = bar_bg.body.main_color; bar_bg.body.radius = 3; bar_bg.body.border.width = 0; @@ -302,7 +309,7 @@ static void sw_init(void) sw_knob_off.body.main_color = LV_COLOR_HEX(0xDADADA); sw_knob_off.body.grad_color = sw_knob_off.body.main_color; sw_knob_off.body.border.width = 1; - sw_knob_off.body.border.color = LV_COLOR_HEX3(0x999); + sw_knob_off.body.border.color = LV_COLOR_HEX(0x999999); sw_knob_off.body.border.opa = LV_OPA_COVER; theme.sw.bg = &sw_bg; @@ -321,7 +328,7 @@ static void lmeter_init(void) lmeter.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 90); lmeter.body.grad_color = lmeter.body.main_color; lmeter.body.padding.hor = LV_DPI / 10; // Scale line length. - lmeter.line.color = LV_COLOR_HEX3(0x999); + lmeter.line.color = LV_COLOR_HEX(0x999999); lmeter.line.width = 2; theme.lmeter = &lmeter; @@ -338,8 +345,8 @@ static void gauge_init(void) gauge.body.grad_color = gauge.body.main_color; gauge.body.padding.hor = LV_DPI / 16; // Scale line length. gauge.body.padding.inner = LV_DPI / 8; - gauge.body.border.color = LV_COLOR_HEX3(0x999); - gauge.text.color = LV_COLOR_HEX3(0xddd); + gauge.body.border.color = LV_COLOR_HEX(0x999999); + gauge.text.color = LV_COLOR_HEX(0xDDDDDD); gauge.line.width = 3; gauge.line.color = lv_color_hsv_to_rgb(_hue, 95, 70); @@ -428,7 +435,7 @@ static void cb_init(void) rel.body.shadow.width = 3; lv_style_copy(&pr, &rel); - pr.body.main_color = LV_COLOR_HEX3(0xCCC); + pr.body.main_color = LV_COLOR_HEX(0xCCCCCC); pr.body.grad_color = pr.body.main_color; pr.body.shadow.width = 3; @@ -462,18 +469,18 @@ static void btnm_init(void) bg.body.padding.hor = 0; bg.body.padding.ver = 0; bg.body.padding.inner = 0; - bg.text.color = LV_COLOR_HEX3(0x555); + bg.text.color = LV_COLOR_HEX(0x555555); lv_style_copy(&rel, theme.panel); rel.body.border.part = LV_BORDER_FULL | LV_BORDER_INTERNAL; rel.body.border.width = 1; - rel.body.border.color = LV_COLOR_HEX3(0xBBB); + rel.body.border.color = LV_COLOR_HEX(0xBBBBBB); rel.body.empty = 1; rel.body.shadow.width = 0; lv_style_copy(&pr, &rel); pr.glass = 0; - pr.body.main_color = LV_COLOR_HEX3(0xDDD); + pr.body.main_color = LV_COLOR_HEX(0xDDDDDD); pr.body.grad_color = pr.body.main_color; pr.body.border.width = 0; pr.body.empty = 0; @@ -488,16 +495,14 @@ static void btnm_init(void) tgl_pr.body.grad_color = tgl_pr.body.main_color; tgl_pr.body.border.width = 0; - lv_style_copy(&ina, &pr); - ina.body.main_color = LV_COLOR_HEX3(0xCCC); - ina.body.grad_color = ina.body.main_color; + lv_style_copy(&ina, theme.btn.ina); theme.btnm.bg = &bg; theme.btnm.btn.rel = &rel; theme.btnm.btn.pr = ≺ theme.btnm.btn.tgl_rel = &tgl_rel; theme.btnm.btn.tgl_pr = &tgl_pr; - theme.btnm.btn.ina = &def; + theme.btnm.btn.ina = &ina; #endif } @@ -508,7 +513,12 @@ static void kb_init(void) static lv_style_t bg, rel; lv_style_copy(&bg, theme.btnm.bg); - bg.text.color = LV_COLOR_HEX3(0xCCC); + bg.text.color = LV_COLOR_HEX(0xCCCCCC); + bg.body.border.width = 0; + bg.body.radius = 0; + bg.body.shadow.color = COLOR_SHADOW_DARK; + bg.body.shadow.type = LV_SHADOW_BOTTOM; + bg.body.shadow.width = 4; lv_style_copy(&rel, &lv_style_transp); rel.text.font = _font; @@ -529,9 +539,9 @@ static void mbox_init(void) static lv_style_t bg; lv_style_copy(&bg, theme.panel); - bg.body.main_color = LV_COLOR_HEX(0x464646); + bg.body.main_color = COLOR_BG_LIGHTER; bg.body.grad_color = bg.body.main_color; - bg.body.shadow.color = COLOR_HOS_BG; + bg.body.shadow.color = COLOR_BG; bg.body.shadow.type = LV_SHADOW_FULL; bg.body.shadow.width = 8; @@ -558,18 +568,24 @@ static void page_init(void) static void ta_init(void) { #if USE_LV_TA - static lv_style_t oneline; + static lv_style_t panel, oneline; + + lv_style_copy(&panel, theme.panel); + panel.body.border.width = 0; + panel.body.shadow.color = COLOR_SHADOW_DARK; + panel.body.shadow.type = LV_SHADOW_FULL; + panel.body.shadow.width = 3; lv_style_copy(&oneline, &def); oneline.body.empty = 1; oneline.body.radius = 0; oneline.body.border.part = LV_BORDER_BOTTOM; oneline.body.border.width = 3; - oneline.body.border.color = LV_COLOR_HEX3(0x555); + oneline.body.border.color = LV_COLOR_HEX(0x555555); oneline.body.border.opa = LV_OPA_COVER; - oneline.text.color = LV_COLOR_HEX3(0x888); + oneline.text.color = LV_COLOR_HEX(0x888888); - theme.ta.area = theme.panel; + theme.ta.area = &panel; theme.ta.oneline = &oneline; theme.ta.cursor = NULL; // Let library to calculate the cursor's style. theme.ta.sb = &sb; @@ -615,7 +631,7 @@ static void list_init(void) // pr.text.font = _font; lv_style_copy(&tgl_rel, &pr); - tgl_rel.body.main_color = COLOR_HOS_BG_LIGHT; + tgl_rel.body.main_color = COLOR_BG_LIGHT; tgl_rel.body.grad_color = tgl_rel.body.main_color; //tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95); tgl_rel.text.color = COLOR_HOS_TEAL_LIGHTER; @@ -626,7 +642,7 @@ static void list_init(void) tgl_pr.body.border.width = 0; lv_style_copy(&ina, &pr); - ina.body.main_color = LV_COLOR_HEX(0x1B1B1B); + ina.body.main_color = COLOR_BG_DARK; ina.body.grad_color = ina.body.main_color; theme.list.sb = &sb; @@ -654,7 +670,7 @@ static void ddlist_init(void) bg.text.color = COLOR_HOS_TURQUOISE; lv_style_copy(&sel, &bg); - sel.body.main_color = COLOR_HOS_BG_LIGHT; + sel.body.main_color = COLOR_BG_LIGHT; sel.body.grad_color = sel.body.main_color; theme.ddlist.bg = &bg; @@ -676,7 +692,7 @@ static void roller_init(void) roller_bg.text.line_space = LV_DPI / 8; roller_bg.text.font = _font; roller_bg.glass = 0; - roller_bg.text.color = LV_COLOR_HEX3(0x444); + roller_bg.text.color = LV_COLOR_HEX(0x444444); lv_style_copy(&roller_sel, &roller_bg); roller_sel.text.color = COLOR_HOS_TURQUOISE; @@ -700,12 +716,12 @@ static void tabview_init(void) indic.body.opa = LV_OPA_0; lv_style_copy(&btn_bg, &def); - btn_bg.body.main_color = COLOR_HOS_BG; + btn_bg.body.main_color = COLOR_BG; btn_bg.body.grad_color = btn_bg.body.main_color; btn_bg.body.radius = 0; btn_bg.body.empty = 1; btn_bg.body.border.width = 0; - btn_bg.body.border.color = LV_COLOR_HEX3(0xDDD); + btn_bg.body.border.color = LV_COLOR_HEX(0xDDDDDD); btn_bg.body.border.part = LV_BORDER_BOTTOM; btn_bg.body.border.opa = LV_OPA_COVER; btn_bg.body.shadow.width = 0; @@ -721,12 +737,12 @@ static void tabview_init(void) rel.text.font = _font; lv_style_copy(&pr, &def); - pr.body.main_color = COLOR_HOS_BG_LIGHT; + pr.body.main_color = COLOR_BG_LIGHT; pr.body.grad_color = pr.body.main_color; pr.body.border.width = 0; pr.body.empty = 0; pr.body.radius = 0; - pr.body.border.color = LV_COLOR_HEX3(0x888); + pr.body.border.color = LV_COLOR_HEX(0x888888); pr.body.border.part = LV_BORDER_BOTTOM; pr.body.border.opa = LV_OPA_COVER; pr.text.color = COLOR_HOS_TURQUOISE; @@ -737,7 +753,7 @@ static void tabview_init(void) tgl_rel.text.color = COLOR_HOS_TURQUOISE; lv_style_copy(&tgl_pr, &def); - tgl_pr.body.main_color = COLOR_HOS_BG_LIGHT; + tgl_pr.body.main_color = COLOR_BG_LIGHT; tgl_pr.body.grad_color = tgl_pr.body.main_color; tgl_pr.body.border.width = 0; tgl_pr.body.empty = 0; @@ -784,11 +800,11 @@ static void win_init(void) static lv_style_t header, rel, pr; lv_style_copy(&header, &def); - header.body.main_color = COLOR_HOS_BG; + header.body.main_color = COLOR_BG; header.body.grad_color = header.body.main_color; header.body.radius = 0; header.body.border.width = 0; - header.body.border.color = LV_COLOR_HEX3(0xDDD); + header.body.border.color = LV_COLOR_HEX(0xDDDDDD); header.body.border.part = LV_BORDER_BOTTOM; header.body.border.opa = LV_OPA_COVER; header.body.shadow.width = 0; @@ -830,10 +846,11 @@ static void win_init(void) * @param font pointer to a font (NULL to use the default) * @return pointer to the initialized theme */ -lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t * font) +lv_theme_t * lv_theme_hekate_init(uint32_t bg_color, uint16_t hue, lv_font_t * font) { if(font == NULL) font = LV_FONT_DEFAULT; + theme_bg_color = bg_color; _hue = hue; _font = font; diff --git a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme_hekate.h b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h similarity index 75% rename from nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme_hekate.h rename to bdk/libs/lvgl/lv_themes/lv_theme_hekate.h index 0f906ea..45448b9 100644 --- a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_theme_hekate.h +++ b/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#ifndef LV_THEME_MATERIAL_H -#define LV_THEME_MATERIAL_H +#ifndef LV_THEME_HEKATE_H +#define LV_THEME_HEKATE_H #ifdef __cplusplus extern "C" { @@ -35,6 +35,14 @@ extern "C" { /********************* * DEFINES *********************/ +#define COLOR_HOS_BG_BASE_DEFAULT 0x1B1B1B +#define COLOR_HOS_BG_BASE_BLACK 0x000000 + +#define COLOR_HOS_BG_DARKER 0x1B1B1B +#define COLOR_HOS_BG_DARK 0x222222 +#define COLOR_HOS_BG 0x2D2D2D +#define COLOR_HOS_BG_LIGHT 0x3D3D3D +#define COLOR_HOS_LIGHT_BORDER 0x4D4D4D /********************** * TYPEDEFS @@ -44,13 +52,15 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ +extern uint32_t theme_bg_color; + /** * Initialize the material theme * @param hue [0..360] hue value from HSV color space to define the theme's base color * @param font pointer to a font (NULL to use the default) * @return pointer to the initialized theme */ -lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t *font); +lv_theme_t * lv_theme_hekate_init(uint32_t bg_color, uint16_t hue, lv_font_t *font); /** * Get a pointer to the theme diff --git a/nyx/nyx_gui/libs/lvgl/lv_themes/lv_themes.mk b/bdk/libs/lvgl/lv_themes/lv_themes.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_themes/lv_themes.mk rename to bdk/libs/lvgl/lv_themes/lv_themes.mk diff --git a/nyx/nyx_gui/libs/lvgl/lv_version.h b/bdk/libs/lvgl/lv_version.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lv_version.h rename to bdk/libs/lvgl/lv_version.h diff --git a/nyx/nyx_gui/libs/lvgl/lvgl.h b/bdk/libs/lvgl/lvgl.h similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lvgl.h rename to bdk/libs/lvgl/lvgl.h diff --git a/nyx/nyx_gui/libs/lvgl/lvgl.mk b/bdk/libs/lvgl/lvgl.mk similarity index 100% rename from nyx/nyx_gui/libs/lvgl/lvgl.mk rename to bdk/libs/lvgl/lvgl.mk diff --git a/nyx/nyx_gui/mem/emc.h b/bdk/mem/emc.h similarity index 94% rename from nyx/nyx_gui/mem/emc.h rename to bdk/mem/emc.h index bfce612..a1b4c3a 100644 --- a/nyx/nyx_gui/mem/emc.h +++ b/bdk/mem/emc.h @@ -2,6 +2,7 @@ * arch/arm/mach-tegra/tegra21_emc.h * * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019-2024, CTCaer. * * 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 @@ -22,6 +23,7 @@ #ifndef _EMC_H_ #define _EMC_H_ +#define EMC_INTSTATUS 0x0 #define EMC_DBG 0x8 #define EMC_CFG 0xC #define EMC_CONFIG_SAMPLE_DELAY 0x5f0 @@ -71,6 +73,7 @@ #define EMC_PDEX2MRR 0xb4 #define EMC_ODT_WRITE 0xb0 #define EMC_WEXT 0xb8 +#define EMC_CTT 0xBC #define EMC_RFC_SLR 0xc0 #define EMC_MRS_WAIT_CNT2 0xc4 #define EMC_MRS_WAIT_CNT 0xc8 @@ -85,8 +88,13 @@ #define EMC_MRR 0xec #define EMC_CMDQ 0xf0 #define EMC_MC2EMCQ 0xf4 +#define EMC_FBIO_TWTM 0xF8 +#define EMC_FBIO_TRATM 0xFC +#define EMC_FBIO_TWATM 0x108 +#define EMC_FBIO_TR2REF 0x10C #define EMC_FBIO_SPARE 0x100 #define EMC_FBIO_CFG5 0x104 +#define EMC_FBIO_CFG6 0x114 #define EMC_CFG_RSV 0x120 #define EMC_ACPD_CONTROL 0x124 #define EMC_MPC 0x128 @@ -210,6 +218,7 @@ #define EMC_AUTO_CAL_CONFIG6 0x5cc #define EMC_AUTO_CAL_CONFIG7 0x574 #define EMC_AUTO_CAL_CONFIG8 0x2dc +#define EMC_AUTO_CAL_CONFIG9 0x42C #define EMC_AUTO_CAL_VREF_SEL_0 0x2f8 #define EMC_AUTO_CAL_VREF_SEL_1 0x300 #define EMC_AUTO_CAL_INTERVAL 0x2a8 @@ -231,6 +240,7 @@ #define EMC_COMP_PAD_SW_CTRL 0x57c #define EMC_REQ_CTRL 0x2b0 #define EMC_EMC_STATUS 0x2b4 +#define EMC_STATUS_MRR_DIVLD BIT(20) #define EMC_CFG_2 0x2b8 #define EMC_CFG_DIG_DLL 0x2bc #define EMC_CFG_DIG_DLL_PERIOD 0x2c0 @@ -384,6 +394,8 @@ #define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xed4 #define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xed8 #define EMC_TRAINING_DRAMC_TIMING 0xedc +#define EMC_PMACRO_DATA_PI_CTRL 0x110 +#define EMC_PMACRO_CMD_PI_CTRL 0x114 #define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 #define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 #define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 @@ -648,6 +660,7 @@ #define EMC_PMACRO_CMD_PAD_TX_CTRL 0xc60 #define EMC_PMACRO_DATA_PAD_TX_CTRL 0xc64 #define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xc68 +#define EMC_PMACRO_DSR_VTTGEN_CTRL0 0xC6C #define EMC_PMACRO_BRICK_MAPPING_0 0xc80 #define EMC_PMACRO_BRICK_MAPPING_1 0xc84 #define EMC_PMACRO_BRICK_MAPPING_2 0xc88 @@ -660,8 +673,61 @@ #define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31c #define EMC_PMACRO_TRAINING_CTRL_0 0xcf8 #define EMC_PMACRO_TRAINING_CTRL_1 0xcfc +#define EMC_PMACRO_PERBIT_FGCG_CTRL_0 0xD40 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_1 0xD44 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_2 0xD48 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_3 0xD4C +#define EMC_PMACRO_PERBIT_FGCG_CTRL_4 0xD50 +#define EMC_PMACRO_PERBIT_FGCG_CTRL_5 0xD54 +#define EMC_PMACRO_PERBIT_RFU_CTRL_0 0xD60 +#define EMC_PMACRO_PERBIT_RFU_CTRL_1 0xD64 +#define EMC_PMACRO_PERBIT_RFU_CTRL_2 0xD68 +#define EMC_PMACRO_PERBIT_RFU_CTRL_3 0xD6C +#define EMC_PMACRO_PERBIT_RFU_CTRL_4 0xD70 +#define EMC_PMACRO_PERBIT_RFU_CTRL_5 0xD74 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_0 0xD80 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_1 0xD84 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_2 0xD88 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_3 0xD8C +#define EMC_PMACRO_PERBIT_RFU1_CTRL_4 0xD90 +#define EMC_PMACRO_PERBIT_RFU1_CTRL_5 0xD94 #define EMC_PMC_SCRATCH1 0x440 #define EMC_PMC_SCRATCH2 0x444 #define EMC_PMC_SCRATCH3 0x448 +#define EMC_STATUS_UPDATE_TIMEOUT 1000 + +typedef enum _emc_mr_t +{ + MR0_FEAT = 0, + MR4_TEMP = 4, + MR5_MAN_ID = 5, + MR6_REV_ID1 = 6, + MR7_REV_ID2 = 7, + MR8_DENSITY = 8, +} emc_mr_t; + +enum +{ + EMC_CHAN0 = 0, + EMC_CHAN1 = 1 +}; + +typedef struct _emc_mr_chip_data_t +{ + // Device 0. + u8 rank0_ch0; + u8 rank0_ch1; + + // Device 1. + u8 rank1_ch0; + u8 rank1_ch1; +} emc_mr_chip_data_t; + +typedef struct _emc_mr_data_t +{ + emc_mr_chip_data_t chip0; + emc_mr_chip_data_t chip1; +} emc_mr_data_t; + #endif diff --git a/bootloader/mem/heap.c b/bdk/mem/heap.c similarity index 66% rename from bootloader/mem/heap.c rename to bdk/mem/heap.c index 833c2d3..ad70729 100644 --- a/bootloader/mem/heap.c +++ b/bdk/mem/heap.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 M4xw + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,36 +17,46 @@ #include #include "heap.h" -#include "../gfx/gfx.h" -#include "../../common/common_heap.h" +#include -static void _heap_create(heap_t *heap, u32 start) +heap_t _heap; + +static void _heap_create(void *start) { - heap->start = start; - heap->first = NULL; + _heap.start = start; + _heap.first = NULL; + _heap.last = NULL; } // Node info is before node address. -static u32 _heap_alloc(heap_t *heap, u32 size) +static void *_heap_alloc(u32 size) { hnode_t *node, *new_node; // Align to cache line size. size = ALIGN(size, sizeof(hnode_t)); - if (!heap->first) + // First allocation. + if (!_heap.first) { - node = (hnode_t *)heap->start; + 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); + _heap.first = node; + _heap.last = node; + + return (void *)node + sizeof(hnode_t); } - node = heap->first; +#ifdef BDK_MALLOC_NO_DEFRAG + // Get the last allocated block. + node = _heap.last; +#else + // Get first block and find the first available one. + node = _heap.first; while (true) { // Check if there's available unused node. @@ -54,7 +64,7 @@ static u32 _heap_alloc(heap_t *heap, u32 size) { // Size and offset of the new unused node. u32 new_size = node->size - size; - new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size); + new_node = (hnode_t *)((void *)node + sizeof(hnode_t) + size); // If there's aligned unused space from the old node, // create a new one and set the leftover size. @@ -77,7 +87,7 @@ static u32 _heap_alloc(heap_t *heap, u32 size) node->size = size; node->used = 1; - return (u32)node + sizeof(hnode_t); + return (void *)node + sizeof(hnode_t); } // No unused node found, try the next one. @@ -86,23 +96,29 @@ static u32 _heap_alloc(heap_t *heap, u32 size) else break; } +#endif // No unused node found, create a new one. - new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); + new_node = (hnode_t *)((void *)node + sizeof(hnode_t) + node->size); new_node->used = 1; new_node->size = size; new_node->prev = node; new_node->next = NULL; - node->next = new_node; - return (u32)new_node + sizeof(hnode_t); + node->next = new_node; + _heap.last = new_node; + + return (void *)new_node + sizeof(hnode_t); } -static void _heap_free(heap_t *heap, u32 addr) +static void _heap_free(void *addr) { hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t)); node->used = 0; - node = heap->first; + node = _heap.first; + +#ifndef BDK_MALLOC_NO_DEFRAG + // Do simple defragmentation on next blocks. while (node) { if (!node->used) @@ -118,31 +134,42 @@ static void _heap_free(heap_t *heap, u32 addr) } node = node->next; } +#endif } -heap_t _heap; - -void heap_init(u32 base) +void heap_init(void *base) { - _heap_create(&_heap, base); + _heap_create(base); +} + +void heap_set(heap_t *heap) +{ + memcpy(&_heap, heap, sizeof(heap_t)); } void *malloc(u32 size) { - return (void *)_heap_alloc(&_heap, size); + return _heap_alloc(size); } void *calloc(u32 num, u32 size) { - void *res = (void *)_heap_alloc(&_heap, num * size); - memset(res, 0, num * size); + void *res = (void *)_heap_alloc(num * size); + memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size. + return res; +} + +void *zalloc(u32 size) +{ + void *res = (void *)_heap_alloc(size); + memset(res, 0, ALIGN(size, sizeof(hnode_t))); // Clear the aligned size. return res; } void free(void *buf) { - if ((u32)buf >= _heap.start) - _heap_free(&_heap, (u32)buf); + if (buf >= _heap.start) + _heap_free(buf); } void heap_monitor(heap_monitor_t *mon, bool print_node_stats) @@ -154,7 +181,10 @@ void heap_monitor(heap_monitor_t *mon, bool print_node_stats) while (true) { if (node->used) + { + mon->nodes_used++; mon->used += node->size + sizeof(hnode_t); + } else mon->total += node->size + sizeof(hnode_t); @@ -163,11 +193,12 @@ void heap_monitor(heap_monitor_t *mon, bool print_node_stats) count, node->used, (u32)node + sizeof(hnode_t), node->size); count++; - + if (node->next) node = node->next; else break; } mon->total += mon->used; + mon->nodes_total = count; } diff --git a/common/common_heap.h b/bdk/mem/heap.h similarity index 67% rename from common/common_heap.h rename to bdk/mem/heap.h index 110f013..c898ee0 100644 --- a/common/common_heap.h +++ b/bdk/mem/heap.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 M4xw + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -13,11 +13,12 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ -#pragma once -//TODO: Move it to BDK -#include "../bootloader/utils/types.h" +#ifndef _HEAP_H_ +#define _HEAP_H_ + +#include typedef struct _hnode { @@ -30,12 +31,25 @@ typedef struct _hnode typedef struct _heap { - u32 start; + void *start; hnode_t *first; + hnode_t *last; } heap_t; typedef struct { - u32 total; - u32 used; + u32 total; + u32 used; + u32 nodes_total; + u32 nodes_used; } heap_monitor_t; + +void heap_init(void *base); +void heap_set(heap_t *heap); +void *malloc(u32 size); +void *calloc(u32 num, u32 size); +void *zalloc(u32 size); +void free(void *buf); +void heap_monitor(heap_monitor_t *mon, bool print_node_stats); + +#endif diff --git a/bdk/mem/mc.c b/bdk/mem/mc.c new file mode 100644 index 0000000..4e6ede6 --- /dev/null +++ b/bdk/mem/mc.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer + * + * 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 +#include +#include +#include + +void mc_config_tzdram_carveout(u32 bom, u32 size1mb, bool 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() +{ + // Enable ACR GSR3. + *(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_REG_CTRL) = VPR_CTRL_LOCKED; + + // Configure TZDRAM carveout @ 0x90000000, 1MB. + //mc_config_tzdram_carveout(0x90000000, 1, false); + mc_config_tzdram_carveout(0, 0, true); + + MC(MC_MTS_CARVEOUT_BOM) = 0; + MC(MC_MTS_CARVEOUT_REG_CTRL) = 1; + + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_APERTURE_ID(0) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + + MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC; + + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT4_CFG0) = SEC_CARVEOUT_CFG_TZ_SECURE | + SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_WR_NS; + + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT5_CFG0) = SEC_CARVEOUT_CFG_TZ_SECURE | + SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_WR_NS; +} + +void mc_enable_ahb_redirect() +{ + // Enable ARC_CLK_OVR_ON. + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) |= BIT(19); + //MC(MC_IRAM_REG_CTRL) &= ~BIT(0); + MC(MC_IRAM_BOM) = IRAM_BASE; + MC(MC_IRAM_TOM) = DRAM_START; // Default is only IRAM: 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) |= BIT(0); + // Disable ARC_CLK_OVR_ON. + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= ~BIT(19); +} + +bool mc_client_has_access(void *address) +{ + // Check if address is in DRAM or if arbitration for IRAM is enabled. + if ((u32)address >= DRAM_START) + return true; // Access by default. + else if ((u32)address >= IRAM_BASE && MC(MC_IRAM_BOM) == IRAM_BASE) + return true; // Access by AHB arbitration. + + // No access to address space. + return false; +} + +void mc_enable() +{ + // Reset EMC source to PLLP. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | (2 << 29u); + // Enable and clear reset for memory clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); + usleep(5); + +#ifdef BDK_MC_ENABLE_AHB_REDIRECT + mc_enable_ahb_redirect(); +#else + mc_disable_ahb_redirect(); +#endif +} diff --git a/bootloader/soc/hw_init.h b/bdk/mem/mc.h similarity index 66% rename from bootloader/soc/hw_init.h rename to bdk/mem/mc.h index b92814b..300bbfd 100644 --- a/bootloader/soc/hw_init.h +++ b/bdk/mem/mc.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -15,12 +14,18 @@ * along with this program. If not, see . */ -#ifndef _HW_INIT_H_ -#define _HW_INIT_H_ +#ifndef _MC_H_ +#define _MC_H_ -#include "../utils/types.h" +#include +#include -void config_hw(); -void reconfig_hw_workaround(bool extra_reconfig, u32 magic); +void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); +void mc_config_carveout(); +void mc_config_carveout_finalize(); +void mc_enable_ahb_redirect(); +void mc_disable_ahb_redirect(); +bool mc_client_has_access(void *address); +void mc_enable(); #endif diff --git a/bootloader/mem/mc_t210.h b/bdk/mem/mc_t210.h similarity index 81% rename from bootloader/mem/mc_t210.h rename to bdk/mem/mc_t210.h index 602915f..ff96b9d 100644 --- a/bootloader/mem/mc_t210.h +++ b/bdk/mem/mc_t210.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2014, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2014, NVIDIA Corporation. + * Copyright (c) 2018-2023, CTCaer * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -14,6 +15,22 @@ #ifndef _MC_T210_H_ #define _MC_T210_H_ +/*! MC SMMU registers */ +#define MC_SMMU_CONFIG 0x10 +#define MC_SMMU_TLB_CONFIG 0x14 +#define MC_SMMU_PTC_CONFIG 0x18 +#define MC_SMMU_PTB_ASID 0x1c +#define MC_SMMU_PTB_DATA 0x20 +#define MC_SMMU_TLB_FLUSH 0x30 +#define MC_SMMU_PTC_FLUSH 0x34 +#define MC_SMMU_ASID_SECURITY 0x38 +#define MC_SMMU_TRANSLATION_ENABLE_0 0x228 +#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c +#define MC_SMMU_TRANSLATION_ENABLE_2 0x230 +#define MC_SMMU_TRANSLATION_ENABLE_3 0x234 +#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98 + +/*! MC General registers */ #define MC_INTSTATUS 0x0 #define MC_INTMASK 0x4 #define MC_ERR_STATUS 0x8 @@ -461,6 +478,158 @@ #define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c #define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08 #define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 +#define MC_UNTRANSLATED_REGION_CHECK 0x948 #define MC_DA_CONFIG0 0x9dc +/*! MC_SECURITY_CARVEOUTX_CLIENT_FORCE_INTERNAL_ACCESS0 */ +#define SEC_CARVEOUT_CA0_R_PTCR BIT(0) +#define SEC_CARVEOUT_CA0_R_DISPLAY0A BIT(1) +#define SEC_CARVEOUT_CA0_R_DISPLAY0AB BIT(2) +#define SEC_CARVEOUT_CA0_R_DISPLAY0B BIT(3) +#define SEC_CARVEOUT_CA0_R_DISPLAY0BB BIT(4) +#define SEC_CARVEOUT_CA0_R_DISPLAY0C BIT(5) +#define SEC_CARVEOUT_CA0_R_DISPLAY0CB BIT(6) +#define SEC_CARVEOUT_CA0_R_AFI BIT(14) +#define SEC_CARVEOUT_CA0_R_BPMP_C BIT(15) +#define SEC_CARVEOUT_CA0_R_DISPLAYHC BIT(16) +#define SEC_CARVEOUT_CA0_R_DISPLAYHCB BIT(17) +#define SEC_CARVEOUT_CA0_R_HDA BIT(21) +#define SEC_CARVEOUT_CA0_R_HOST1XDMA BIT(22) +#define SEC_CARVEOUT_CA0_R_HOST1X BIT(23) +#define SEC_CARVEOUT_CA0_R_NVENC BIT(28) +#define SEC_CARVEOUT_CA0_R_PPCSAHBDMA BIT(29) +#define SEC_CARVEOUT_CA0_R_PPCSAHBSLV BIT(30) +#define SEC_CARVEOUT_CA0_R_SATAR BIT(31) + +/*! MC_SECURITY_CARVEOUTX_CLIENT_FORCE_INTERNAL_ACCESS1 */ +#define SEC_CARVEOUT_CA1_R_VDEBSEV BIT(2) +#define SEC_CARVEOUT_CA1_R_VDEMBE BIT(3) +#define SEC_CARVEOUT_CA1_R_VDEMCE BIT(4) +#define SEC_CARVEOUT_CA1_R_VDETPE BIT(5) +#define SEC_CARVEOUT_CA1_R_CCPLEXLP_C BIT(6) +#define SEC_CARVEOUT_CA1_R_CCPLEX_C BIT(7) +#define SEC_CARVEOUT_CA1_W_NVENC BIT(11) +#define SEC_CARVEOUT_CA1_W_AFI BIT(17) +#define SEC_CARVEOUT_CA1_W_BPMP_C BIT(18) +#define SEC_CARVEOUT_CA1_W_HDA BIT(21) +#define SEC_CARVEOUT_CA1_W_HOST1X BIT(22) +#define SEC_CARVEOUT_CA1_W_CCPLEXLP_C BIT(24) +#define SEC_CARVEOUT_CA1_W_CCPLEX_C BIT(25) +#define SEC_CARVEOUT_CA1_W_PPCSAHBDMA BIT(27) +#define SEC_CARVEOUT_CA1_W_PPCSAHBSLV BIT(28) +#define SEC_CARVEOUT_CA1_W_SATA BIT(29) +#define SEC_CARVEOUT_CA1_W_VDEBSEV BIT(30) +#define SEC_CARVEOUT_CA1_W_VDEDBG BIT(31) + +/*! MC_SECURITY_CARVEOUTX_CLIENT_FORCE_INTERNAL_ACCESS2 */ +#define SEC_CARVEOUT_CA2_W_VDEMBE BIT(0) +#define SEC_CARVEOUT_CA2_W_VDETPM BIT(1) +#define SEC_CARVEOUT_CA2_R_ISPRA BIT(4) +#define SEC_CARVEOUT_CA2_W_ISPWA BIT(6) +#define SEC_CARVEOUT_CA2_W_ISPWB BIT(7) +#define SEC_CARVEOUT_CA2_R_XUSB_HOST BIT(10) +#define SEC_CARVEOUT_CA2_W_XUSB_HOST BIT(11) +#define SEC_CARVEOUT_CA2_R_XUSB_DEV BIT(12) +#define SEC_CARVEOUT_CA2_W_XUSB_DEV BIT(13) +#define SEC_CARVEOUT_CA2_R_SE2 BIT(14) +#define SEC_CARVEOUT_CA2_W_SE2 BIT(16) +#define SEC_CARVEOUT_CA2_R_TSEC BIT(20) +#define SEC_CARVEOUT_CA2_W_TSEC BIT(21) +#define SEC_CARVEOUT_CA2_R_ADSP_SC BIT(22) +#define SEC_CARVEOUT_CA2_W_ADSP_SC BIT(23) +#define SEC_CARVEOUT_CA2_R_GPU BIT(24) +#define SEC_CARVEOUT_CA2_W_GPU BIT(25) +#define SEC_CARVEOUT_CA2_R_DISPLAYT BIT(26) + +/*! MC_SECURITY_CARVEOUTX_CLIENT_FORCE_INTERNAL_ACCESS3 */ +#define SEC_CARVEOUT_CA3_R_SDMMCA BIT(0) +#define SEC_CARVEOUT_CA3_R_SDMMCAA BIT(1) +#define SEC_CARVEOUT_CA3_R_SDMMC BIT(2) +#define SEC_CARVEOUT_CA3_R_SDMMCAB BIT(3) +#define SEC_CARVEOUT_CA3_W_SDMMCA BIT(4) +#define SEC_CARVEOUT_CA3_W_SDMMCAA BIT(5) +#define SEC_CARVEOUT_CA3_W_SDMMC BIT(6) +#define SEC_CARVEOUT_CA3_W_SDMMCAB BIT(7) +#define SEC_CARVEOUT_CA3_R_VIC BIT(12) +#define SEC_CARVEOUT_CA3_W_VIC BIT(13) +#define SEC_CARVEOUT_CA3_W_VIW BIT(18) +#define SEC_CARVEOUT_CA3_R_DISPLAYD BIT(19) +#define SEC_CARVEOUT_CA3_R_NVDEC BIT(24) +#define SEC_CARVEOUT_CA3_W_NVDEC BIT(25) +#define SEC_CARVEOUT_CA3_R_APE BIT(26) +#define SEC_CARVEOUT_CA3_W_APE BIT(27) +#define SEC_CARVEOUT_CA3_R_NVJPG BIT(30) +#define SEC_CARVEOUT_CA3_W_NVJPG BIT(31) + +/*! MC_SECURITY_CARVEOUTX_CLIENT_FORCE_INTERNAL_ACCESS4 */ +#define SEC_CARVEOUT_CA4_R_SE BIT(0) +#define SEC_CARVEOUT_CA4_W_SE BIT(1) +#define SEC_CARVEOUT_CA4_R_AXIAP BIT(2) +#define SEC_CARVEOUT_CA4_W_AXIAP BIT(3) +#define SEC_CARVEOUT_CA4_R_ETR BIT(4) +#define SEC_CARVEOUT_CA4_W_ETR BIT(5) +#define SEC_CARVEOUT_CA4_R_TSECB BIT(6) +#define SEC_CARVEOUT_CA4_W_TSECB BIT(7) +#define SEC_CARVEOUT_CA4_R_GPU2 BIT(8) +#define SEC_CARVEOUT_CA4_W_GPU2 BIT(9) + +// MC_VIDEO_PROTECT_REG_CTRL +#define VPR_LOCK_MODE_SHIFT 0 +#define VPR_CTRL_UNLOCKED (0 << VPR_LOCK_MODE_SHIFT) +#define VPR_CTRL_LOCKED (1 << VPR_LOCK_MODE_SHIFT) +#define VPR_PROTECT_MODE_SHIFT 1 +#define SEC_CTRL_SECURE (0 << VPR_PROTECT_MODE_SHIFT) +#define VPR_CTRL_TZ_SECURE (1 << VPR_PROTECT_MODE_SHIFT) + +// MC_SECURITY_CARVEOUTX_CFG0 +// Mode of LOCK_MODE. +#define PROTECT_MODE_SHIFT 0 +#define SEC_CARVEOUT_CFG_ALL_SECURE (0 << PROTECT_MODE_SHIFT) +#define SEC_CARVEOUT_CFG_TZ_SECURE (1 << PROTECT_MODE_SHIFT) +// Enables PROTECT_MODE. +#define LOCK_MODE_SHIFT 1 +#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT) +#define SEC_CARVEOUT_CFG_LOCKED (1 << LOCK_MODE_SHIFT) + +#define ADDRESS_TYPE_SHIFT 2 +#define SEC_CARVEOUT_CFG_ANY_ADDRESS (0 << ADDRESS_TYPE_SHIFT) +#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT) + +#define READ_ACCESS_LEVEL_SHIFT 3 +#define SEC_CARVEOUT_CFG_RD_NS (1 << READ_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_RD_SEC (2 << READ_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT) + +#define WRITE_ACCESS_LEVEL_SHIFT 7 +#define SEC_CARVEOUT_CFG_WR_NS (1 << WRITE_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_WR_SEC (2 << WRITE_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT) + +#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11) +#define SEC_CARVEOUT_CFG_APERTURE_ID(id) ((id) << 11) + +#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14 +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_NS (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_SEC (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_FLCN_LS (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_FLCN_HS (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) + +#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18 +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_NS (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_SEC (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_FLCN_LS (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_FLCN_HS (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) + +#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU BIT(22) + +#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK BIT(23) +#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK BIT(24) + +#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH BIT(25) +#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH BIT(26) + +#define SEC_CARVEOUT_CFG_IS_WPR BIT(27) + #endif diff --git a/bdk/mem/minerva.c b/bdk/mem/minerva.c new file mode 100644 index 0000000..3fd05e4 --- /dev/null +++ b/bdk/mem/minerva.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2019-2024 CTCaer + * + * 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 + +#include "minerva.h" + +#include +#include +#include +#include +#include +#include +#include + +#define TABLE_FREQ_KHZ_OFFSET 0x40 +#define TABLE_LA_REGS_T210_OFFSET 0x1284 +#define TABLE_LA_REGS_T210B01_OFFSET 0xFA4 +#define LA_SDMMC1_INDEX 6 + +extern volatile nyx_storage_t *nyx_str; + +void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); + +u32 minerva_init() +{ + u32 tbl_idx = 0; + + minerva_cfg = NULL; + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + + //!TODO: Not supported on T210B01 yet. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + return 0; + +#ifdef BDK_MINERVA_CFG_FROM_RAM + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table; + + // Check if Minerva is already initialized. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + { + mtc_cfg->train_mode = OP_PERIODIC_TRAIN; // Retrain if needed. + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + minerva_cfg = (void *)ep_addr; + + return !minerva_cfg ? 1 : 0; + } + else + { + mtc_config_t mtc_tmp; + + mtc_tmp.mtc_table = mtc_cfg->mtc_table; + mtc_tmp.sdram_id = fuse_read_dramid(false); + mtc_tmp.init_done = MTC_NEW_MAGIC; + + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_tmp); + + // Ensure that Minerva is new. + if (mtc_tmp.init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; + + // Copy Minerva context to Nyx storage. + if (minerva_cfg) + memcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t)); + } +#else + memset(mtc_cfg, 0, sizeof(mtc_config_t)); + + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table; + + mtc_cfg->sdram_id = fuse_read_dramid(false); + mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. + + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + + // Ensure that Minerva is new. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; +#endif + + if (!minerva_cfg) + return 1; + + // Get current frequency + u32 current_emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC); + for (tbl_idx = 0; tbl_idx < mtc_cfg->table_entries; tbl_idx++) + { + if (current_emc_clk_src == mtc_cfg->mtc_table[tbl_idx].clk_src_emc) + break; + } + + mtc_cfg->rate_from = mtc_cfg->mtc_table[tbl_idx].rate_khz; + mtc_cfg->rate_to = FREQ_204; + mtc_cfg->train_mode = OP_TRAIN; + minerva_cfg(mtc_cfg, NULL); + mtc_cfg->rate_to = FREQ_800; + minerva_cfg(mtc_cfg, NULL); + mtc_cfg->rate_to = FREQ_1600; + minerva_cfg(mtc_cfg, NULL); + + // FSP WAR. + mtc_cfg->train_mode = OP_SWITCH; + mtc_cfg->rate_to = FREQ_800; + minerva_cfg(mtc_cfg, NULL); + + // Switch to max. + mtc_cfg->rate_to = FREQ_1600; + minerva_cfg(mtc_cfg, NULL); + + return 0; +} + +void minerva_change_freq(minerva_freq_t freq) +{ + if (!minerva_cfg) + return; + + // Check if requested frequency is different. Do not allow otherwise because it will hang. + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + if (mtc_cfg->rate_from != freq) + { + mtc_cfg->rate_to = freq; + mtc_cfg->train_mode = OP_SWITCH; + minerva_cfg(mtc_cfg, NULL); + } +} + +void minerva_sdmmc_la_program(void *table, bool t210b01) +{ + + u32 freq = *(u32 *)(table + TABLE_FREQ_KHZ_OFFSET); + u32 *la_scale_regs = (u32 *)(table + (t210b01 ? TABLE_LA_REGS_T210B01_OFFSET : TABLE_LA_REGS_T210_OFFSET)); + + // Adjust SDMMC1 latency allowance. + switch (freq) + { + case 204000: + la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 50; + break; + case 408000: + la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 25; + break; + default: + la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 20; + break; + } +} + +void minerva_prep_boot_freq() +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + + // Check if there's RAM OC. If not exit. + if (mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600) + return; + + // FSP WAR. + minerva_change_freq(FREQ_204); + // Scale down to 800 MHz boot freq. + minerva_change_freq(FREQ_800); +} + +void minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom) +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + + // Program SDMMC LA regs. + for (u32 i = 0; i < mtc_cfg->table_entries; i++) + minerva_sdmmc_la_program(&mtc_cfg->mtc_table[i], false); + + // Add OC frequency. + if (oc_freq && mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600) + { + memcpy(&mtc_cfg->mtc_table[mtc_cfg->table_entries], + &mtc_cfg->mtc_table[mtc_cfg->table_entries - 1], + sizeof(emc_table_t)); + + mtc_cfg->mtc_table[mtc_cfg->table_entries].opt_custom = opt_custom; + mtc_cfg->mtc_table[mtc_cfg->table_entries].rate_khz = oc_freq; + mtc_cfg->table_entries++; + } + + // Trim table. + int entries = 0; + for (u32 i = 0; i < mtc_cfg->table_entries; i++) + { + // Copy frequencies from 204/408/800 MHz and 1333+ MHz. + int rate = mtc_cfg->mtc_table[i].rate_khz; + if (rate == FREQ_204 || + rate == FREQ_408 || + rate == FREQ_800 || + rate >= FREQ_1333) + { + memcpy(&mtc_cfg->mtc_table[entries], &mtc_cfg->mtc_table[i], sizeof(emc_table_t)); + entries++; + } + } + mtc_cfg->table_entries = entries; + + // Set init frequency. + minerva_change_freq(FREQ_204); + + // Train the rest of the frequencies. + mtc_cfg->train_mode = OP_TRAIN; + for (u32 i = 0; i < mtc_cfg->table_entries; i++) + { + // Skip already trained frequencies and OC freq (Arachne handles it). + if (mtc_cfg->mtc_table[i].trained || mtc_cfg->rate_to == oc_freq) + continue; + + // Train frequency. + mtc_cfg->rate_to = mtc_cfg->mtc_table[i].rate_khz; + minerva_cfg(mtc_cfg, NULL); + } + + // Do FSP WAR and scale to 800 MHz as boot freq. + bool fsp_opwr_disabled = !(EMC(EMC_MRW3) & 0xC0); + if (fsp_opwr_disabled) + minerva_change_freq(FREQ_1333); + minerva_change_freq(FREQ_800); + + // Do not let other mtc ops. + mtc_cfg->init_done = 0; +} + +void minerva_periodic_training() +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + if (mtc_cfg->rate_from == FREQ_1600) + { + mtc_cfg->train_mode = OP_PERIODIC_TRAIN; + minerva_cfg(mtc_cfg, NULL); + } +} + +emc_table_t *minerva_get_mtc_table() +{ + if (!minerva_cfg) + return NULL; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + return mtc_cfg->mtc_table; +} + +int minerva_get_mtc_table_entries() +{ + if (!minerva_cfg) + return 0; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + return mtc_cfg->table_entries; +} diff --git a/bootloader/mem/minerva.h b/bdk/mem/minerva.h similarity index 76% rename from bootloader/mem/minerva.h rename to bdk/mem/minerva.h index 00228f4..e78bb41 100644 --- a/bootloader/mem/minerva.h +++ b/bdk/mem/minerva.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,7 +18,7 @@ #define _FE_MINERVA_H_ #include "mtc_table.h" -#include "../utils/types.h" +#include #define MTC_INIT_MAGIC 0x3043544D #define MTC_NEW_MAGIC 0x5243544D @@ -27,8 +27,8 @@ typedef struct { - s32 rate_to; - s32 rate_from; + u32 rate_to; + u32 rate_from; emc_table_t *mtc_table; u32 table_entries; emc_table_t *current_emc_table; @@ -38,7 +38,7 @@ typedef struct bool emc_2X_clk_src_is_pllmb; bool fsp_for_src_freq; bool train_ram_patterns; - bool init_done; + u32 init_done; } mtc_config_t; enum train_mode_t @@ -53,13 +53,20 @@ enum train_mode_t typedef enum { FREQ_204 = 204000, + FREQ_408 = 408000, FREQ_800 = 800000, + FREQ_1333 = 1331200, FREQ_1600 = 1600000 } minerva_freq_t; -void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); +extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); u32 minerva_init(); void minerva_change_freq(minerva_freq_t freq); +void minerva_sdmmc_la_program(void *table, bool t210b01); +void minerva_prep_boot_freq(); +void minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom); void minerva_periodic_training(); +emc_table_t *minerva_get_mtc_table(); +int minerva_get_mtc_table_entries(); #endif diff --git a/nyx/nyx_gui/mem/mtc_table.h b/bdk/mem/mtc_table.h similarity index 99% rename from nyx/nyx_gui/mem/mtc_table.h rename to bdk/mem/mtc_table.h index 38a3e2f..7802280 100644 --- a/nyx/nyx_gui/mem/mtc_table.h +++ b/bdk/mem/mtc_table.h @@ -20,7 +20,7 @@ #ifndef _MTC_TABLE_H_ #define _MTC_TABLE_H_ -#include "../utils/types.h" +#include typedef struct { @@ -481,7 +481,8 @@ typedef struct u32 rate_khz; u32 min_volt; u32 gpu_min_volt; - char clock_src[32]; + char clock_src[28]; + u32 opt_custom; u32 clk_src_emc; u32 needs_training; u32 training_pattern; diff --git a/bdk/mem/sdram.c b/bdk/mem/sdram.c new file mode 100644 index 0000000..4aa98fa --- /dev/null +++ b/bdk/mem/sdram.c @@ -0,0 +1,1582 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 balika011 + * Copyright (c) 2019-2023 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRAM_ID(x) BIT(x) +#define DRAM_CC(x) BIT(x) + +typedef struct _sdram_vendor_patch_t +{ + u32 val; + u32 dramcf:16; + u32 offset:16; +} sdram_vendor_patch_t; + +static const u8 dram_encoding_t210b01[] = { +/* 00 */ LPDDR4X_UNUSED, +/* 01 */ LPDDR4X_UNUSED, +/* 02 */ LPDDR4X_UNUSED, +/* 03 */ LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, +/* 04 */ LPDDR4X_UNUSED, +/* 05 */ LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, +/* 06 */ LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, +/* 07 */ LPDDR4X_UNUSED, +/* 08 */ LPDDR4X_NO_PATCH, +/* 09 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, +/* 10 */ LPDDR4X_NO_PATCH, +/* 11 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE, +/* 12 */ LPDDR4X_NO_PATCH, +/* 13 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ, +/* 14 */ LPDDR4X_NO_PATCH, +/* 15 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE, +/* 16 */ LPDDR4X_UNUSED, +/* 17 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, +/* 18 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, +/* 19 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, +/* 20 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL, +/* 21 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL, +/* 22 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL, +/* 23 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, +/* 24 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, +/* 25 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, +/* 26 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, +/* 27 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, +/* 28 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, +/* 29 */ LPDDR4X_4GB_HYNIX_H54G46CYRBX267, +/* 30 */ LPDDR4X_4GB_HYNIX_H54G46CYRBX267, +/* 31 */ LPDDR4X_4GB_HYNIX_H54G46CYRBX267, +/* 32 */ LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB, +/* 33 */ LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB, +/* 34 */ LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB, +}; + +#include "sdram_config.inl" +#include "sdram_config_t210b01.inl" + +static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) +{ + bool err = true; + + for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++) + { + if (emc_channel) + { + if (emc_channel != 1) + goto done; + + if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state) + { + err = false; + break; + } + } + else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state) + { + err = false; + break; + } + usleep(1); + } + +done: + return err; +} + +static void _sdram_req_mrr_data(u32 data, bool dual_channel) +{ + EMC(EMC_MRR) = data; + _sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0); + if (dual_channel) + _sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1); +} + +emc_mr_data_t sdram_read_mrx(emc_mr_t mrx) +{ + emc_mr_data_t data; + u32 mrr; + bool dual_rank = EMC(EMC_ADR_CFG) & 1; + bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 2) & 1; // Each EMC channel is a RAM chip module. + + // Clear left overs. + for (u32 i = 0; i < 16; i++) + { + (void)EMC(EMC_MRR); + usleep(1); + } + + memset(&data, 0xFF, sizeof(emc_mr_data_t)); + + /* + * When a dram chip has only one rank, then the info from the 2 ranks differs. + * Info not matching is only allowed on different channels. + */ + + // Get Device 0 (Rank 0) info from both dram chips (channels). + _sdram_req_mrr_data((2u << 30) | (mrx << 16), dual_channel); + + // Ram module 0 info. + mrr = EMC_CH0(EMC_MRR); + data.chip0.rank0_ch0 = mrr & 0xFF; + data.chip0.rank0_ch1 = (mrr & 0xFF00 >> 8); + + // Ram module 1 info. + if (dual_channel) + { + mrr = EMC_CH1(EMC_MRR); + data.chip1.rank0_ch0 = mrr & 0xFF; + data.chip1.rank0_ch1 = (mrr & 0xFF00 >> 8); + } + + // If Rank 1 exists, get info. + if (dual_rank) + { + // Get Device 1 (Rank 1) info from both dram chips (channels). + _sdram_req_mrr_data((1u << 30) | (mrx << 16), dual_channel); + + // Ram module 0 info. + mrr = EMC_CH0(EMC_MRR); + data.chip0.rank1_ch0 = mrr & 0xFF; + data.chip0.rank1_ch1 = (mrr & 0xFF00 >> 8); + + // Ram module 1 info. + if (dual_channel) + { + mrr = EMC_CH1(EMC_MRR); + data.chip1.rank1_ch0 = mrr & 0xFF; + data.chip1.rank1_ch1 = (mrr & 0xFF00 >> 8); + } + } + + return data; +} + +void sdram_src_pllc(bool enable) +{ + static bool enabled = false; + + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210 || enable == enabled) + return; + + enabled = enable; + + // Clear CC interrupt. + EMC(EMC_INTSTATUS) = BIT(4); + (void)EMC(EMC_INTSTATUS); + + u32 clk_src_emc = _dram_cfg_08_10_12_14_samsung_hynix_4gb.emc_clock_source; + + if (enable) + { + // Check if clock source is not the expected one. + if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) != clk_src_emc) + return; + + // Set source as PLLC_OUT0. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = 0x20188004; + } + else + { + // Restore MC/EMC clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = clk_src_emc; + } + + // Wait for CC interrupt. + while (!(EMC(EMC_INTSTATUS) & BIT(4))) + usleep(1); +} + +static void _sdram_config_t210(const sdram_params_t210_t *params) +{ + // VDDP Select. + PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; + usleep(params->pmc_vddp_sel_wait); + + // Set DDR pad voltage. + PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); // Normally params->pmc_ddr_pwr. + + // Turn on MEM IO Power. + PMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_SDMMC1; // Only keep SDMMC1 state. (Was params->pmc_no_io_power). + PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + + // Patch 1 using BCT spare variables + if (params->emc_bct_spare0) + *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; + + // Program DPD3/DPD4 regs (coldboot path). + // Enable sel_dpd on unused pins. + u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON; + PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; + usleep(params->pmc_io_dpd3_req_wait); + + // Disable e_dpd_vttgen. + dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON; + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; + usleep(params->pmc_io_dpd4_req_wait); + + // Disable e_dpd_bg. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; + usleep(params->pmc_io_dpd4_req_wait); + + PMC(APBDEV_PMC_WEAK_BIAS) = 0; + usleep(1); + + // Start PLLM. + CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; + CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; + + u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); + CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div; + CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE; + + u32 wait_end = get_tmr_us() + 300; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & BIT(27))) + { + if (get_tmr_us() >= wait_end) + goto lock_timeout; + } + usleep(10); + +lock_timeout: + // Set clock sources. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF); + if (params->emc_clock_source_dll) + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; + if (params->clear_clock2_mc1) + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_MC1); // Clear Reset to MC1. + + // Enable and clear reset for memory clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); + + // Set pad vtt levels. + 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; + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + usleep(10); // Ensure the regulators settle. + + // Select EMC write mux. + EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + + // Patch 2 using BCT spare variables. + if (params->emc_bct_spare2) + *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + + // Program CMD mapping. Required before brick mapping, else + // we can't guarantee CK will be differential at all times. + 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; + + // Program brick mapping. + 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; + + // This is required to do any reads from the pad macros. + EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + + // Set data pipes mode. + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + + // Set swizzle for Rank 0. + 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; + // Set swizzle for Rank 1. + 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; + + // Patch 3 using BCT spare variables. + if (params->emc_bct_spare6) + *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + + // Program calibration impedance. + 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; + + // Program Autocal controls. + 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; + + // Program termination and drive strength + 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; + + // Program dll config. + 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; + + // Program barrelshift. + 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; + + // Program pad macros controls and termination. + 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; + + // Program pad macro pins/bytes. + 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; + + // Program inbound vref setting. + 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; + + // Program quse trimmers. + 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; + + // Program outbound trimmers. + 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; + + // Program clock trimmers. + 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; + + // Common pad macro (cpm). + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; + + // Patch 4 using BCT spare variables. + if (params->emc_bct_spare4) + *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + + // Initialize MC VPR settings. + 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; + + // Program SDRAM geometry parameters. + 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; + + // Program bank swizzling. + 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; + + // Program external memory aperture (base and size). + MC(MC_EMEM_CFG) = params->mc_emem_cfg; + + // Program SEC carveout (base and size). + 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; + + // Program MTS carveout (base and size). + 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; + + // Program the memory arbiter. + 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; + + // Trigger MC timing update. + MC(MC_TIMING_CONTROL) = 1; + + // Program second-level clock enable overrides. + MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + + // Program statistics gathering. + MC(MC_STAT_CONTROL) = params->mc_stat_control; + + // Program SDRAM geometry parameters. + EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + + // Program second-level clock enable overrides. + EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + + // Program EMC pad auto calibration. + 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; + + // Program/Start auto calibration. + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; + usleep(params->emc_auto_cal_wait); + + // Patch 5 using BCT spare variables. + if (params->emc_bct_spare8) + *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + + // Program EMC timing configuration. + 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; + + // Clear read fifo. + EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 1; + EMC(EMC_ISSUE_QRST) = 0; + + // Program the rest of EMC timing configuration. + 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; + + // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. + 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; + + // Set pipe bypass enable bits before sending any DRAM commands. + EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; + + // Patch BootROM. + if (params->boot_rom_patch_control & BIT(31)) + { + *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; + + // Trigger MC timing update. + MC(MC_TIMING_CONTROL) = 1; + } + + // Release SEL_DPD_CMD. + PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF; + usleep(params->pmc_io_dpd3_req_wait); + + // Stall auto call measurements if periodic calibration is disabled. + 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; + + // ZQ CAL setup (not actually issuing ZQ CAL now). + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + usleep(params->emc_timing_control_wait); + + // Deassert HOLD_CKE_LOW. + PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F; + usleep(params->pmc_ddr_ctrl_wait); + + // Set clock enable signal. + u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + EMC(EMC_PIN) = pin_gpio_cfg; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_extra_wait + 200); + EMC(EMC_PIN) = pin_gpio_cfg | 0x100; + (void)EMC(EMC_PIN); + + usleep(params->emc_pin_extra_wait + 2000); + + // Enable clock enable signal. + EMC(EMC_PIN) = pin_gpio_cfg | 0x101; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_program_wait); + + // Init zq calibration, + // Patch 6 using BCT spare variables. + if (params->emc_bct_spare10) + *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + + // Write mode registers. + 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) + { + // Issue ZQCAL start, device 0. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; + usleep(params->emc_zcal_init_wait); + + // Issue ZQCAL latch. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + // Same for device 1. + if (!(params->emc_dev_select & 2)) + { + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; + usleep(params->emc_zcal_init_wait); + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; + } + } + + // Set package and DPD pad control. + PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; + + // Start periodic ZQ calibration (LPDDRx only). + 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; + + // Patch 7 using BCT spare variables. + if (params->emc_bct_spare12) + *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + + if (params->emc_extra_refresh_num) + EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; + + // Enable refresh. + EMC(EMC_REFCTRL) = params->emc_dev_select | BIT(31); + + 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; + + // Write addr swizzle lock bit. + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | BIT(1); + + // Re-trigger timing to latch power saving functions. + EMC(EMC_TIMING_CONTROL) = 1; + + // Enable EMC pipe clock gating. + EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + + // Depending on freqency, enable CMD/CLK fdpd. + EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; + + // Enable arbiter. + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); + + // Lock carveouts per BCT cfg. + 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; + + // Disable write access to a bunch of EMC registers. + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; +} + +static void _sdram_config_t210b01(const sdram_params_t210b01_t *params) +{ + // VDDP Select. + PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; + usleep(params->pmc_vddp_sel_wait); + + // Turn on MEM IO Power. + PMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_SDMMC1; // Only keep SDMMC1 state. (Was params->pmc_no_io_power). + PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + + // Patch 1 using BCT spare variables + if (params->emc_bct_spare0) + *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; + + // Override HW FSM if needed. + if (params->clk_rst_pllm_misc20_override_enable) + CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = params->clk_rst_pllm_misc20_override; + + // Program DPD3/DPD4 regs (coldboot path). + // Enable sel_dpd on unused pins. + u32 pmc_scratch1 = ~params->emc_pmc_scratch1; + PMC(APBDEV_PMC_WEAK_BIAS) = (pmc_scratch1 & 0x1000) << 19 | (pmc_scratch1 & 0xFFF) << 18 | (pmc_scratch1 & 0x8000) << 15; + PMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) | PMC_IO_DPD_REQ_DPD_ON; + usleep(params->pmc_io_dpd3_req_wait); + + // Disable e_dpd_vttgen. + u32 pmc_scratch2 = ~params->emc_pmc_scratch2; + PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x3FFF0000) | PMC_IO_DPD_REQ_DPD_ON; + usleep(params->pmc_io_dpd4_req_wait); + + // Disable e_dpd_bg. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | PMC_IO_DPD_REQ_DPD_ON; + usleep(1); + + // Program CMD mapping. Required before brick mapping, else + // we can't guarantee CK will be differential at all times. + 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; + + // Program brick mapping. + 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; + + // Set pad macros. + 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; + + // Set pad macros bias. + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = params->emc_pmacro_bg_bias_ctrl0; + + // Patch 1 to 3 using BCT spare secure variables. + if (params->emc_bct_spare_secure0) + *(vu32 *)params->emc_bct_spare_secure0 = params->emc_bct_spare_secure1; + if (params->emc_bct_spare_secure2) + *(vu32 *)params->emc_bct_spare_secure2 = params->emc_bct_spare_secure3; + if (params->emc_bct_spare_secure4) + *(vu32 *)params->emc_bct_spare_secure4 = params->emc_bct_spare_secure5; + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + usleep(params->pmc_vddp_sel_wait + 2); // Ensure the regulators settle. + + // Set clock sources. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = params->emc_clock_source; + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; + + // Select EMC write mux. + EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + + // Patch 2 using BCT spare variables. + if (params->emc_bct_spare2) + *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + + // This is required to do any reads from the pad macros. + EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + + // Set data pipes mode. + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + + // Set swizzle for Rank 0. + 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; + // Set swizzle for Rank 1. + 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; + + // Patch 3 using BCT spare variables. + if (params->emc_bct_spare6) + *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + + // Program calibration impedance. + 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; + + // Program Autocal controls. + 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; + + // Program termination and drive strength + 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; + + // Program dll config. + 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; + + // Program barrelshift. + 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; + + // Program pad macros controls and termination. + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1; + 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; + EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd; + 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 & 0xEFFFFFFF; + + // Program pad macro pins/bytes. + 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; + + // Program per bit pad macros. + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_0) = params->emc_pmacro_perbit_fgcg_ctrl0; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_1) = params->emc_pmacro_perbit_fgcg_ctrl1; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_2) = params->emc_pmacro_perbit_fgcg_ctrl2; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_3) = params->emc_pmacro_perbit_fgcg_ctrl3; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_4) = params->emc_pmacro_perbit_fgcg_ctrl4; + EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_5) = params->emc_pmacro_perbit_fgcg_ctrl5; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_0) = params->emc_pmacro_perbit_rfu_ctrl0; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_1) = params->emc_pmacro_perbit_rfu_ctrl1; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_2) = params->emc_pmacro_perbit_rfu_ctrl2; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_3) = params->emc_pmacro_perbit_rfu_ctrl3; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_4) = params->emc_pmacro_perbit_rfu_ctrl4; + EMC(EMC_PMACRO_PERBIT_RFU_CTRL_5) = params->emc_pmacro_perbit_rfu_ctrl5; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_0) = params->emc_pmacro_perbit_rfu1_ctrl0; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_1) = params->emc_pmacro_perbit_rfu1_ctrl1; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_2) = params->emc_pmacro_perbit_rfu1_ctrl2; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_3) = params->emc_pmacro_perbit_rfu1_ctrl3; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_4) = params->emc_pmacro_perbit_rfu1_ctrl4; + EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_5) = params->emc_pmacro_perbit_rfu1_ctrl5; + EMC(EMC_PMACRO_DATA_PI_CTRL) = params->emc_pmacro_data_pi_ctrl; + EMC(EMC_PMACRO_CMD_PI_CTRL) = params->emc_pmacro_cmd_pi_ctrl; + + 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; + + // Program inbound vref setting. + 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; + + // Program quse trimmers. + 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; + + // Program outbound trimmers. + 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; + + // Program clock trimmers. + 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; + + // Set DLL periodic offset. + EMC(EMC_PMACRO_DDLL_PERIODIC_OFFSET) = params->emc_pmacro_ddll_periodic_offset; + + // Patch 4 using BCT spare variables. + if (params->emc_bct_spare4) + *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; + + // Patch 4 to 6 using BCT spare secure variables. + if (params->emc_bct_spare_secure6) + *(vu32 *)params->emc_bct_spare_secure6 = params->emc_bct_spare_secure7; + if (params->emc_bct_spare_secure8) + *(vu32 *)params->emc_bct_spare_secure8 = params->emc_bct_spare_secure9; + if (params->emc_bct_spare_secure10) + *(vu32 *)params->emc_bct_spare_secure10 = params->emc_bct_spare_secure11; + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + + // Initialize MC VPR settings. + 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; + + // Program SDRAM geometry parameters. + 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; + + // Program bank swizzling. + 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; + + // Program external memory aperture (base and size). + MC(MC_EMEM_CFG) = params->mc_emem_cfg; + + // Program SEC carveout (base and size). + 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; + + // Program MTS carveout (base and size). + 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; + + // Program the memory arbiter. + 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; + + // Trigger MC timing update. + MC(MC_TIMING_CONTROL) = 1; + + // Program second-level clock enable overrides. + MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + + // Program statistics gathering. + MC(MC_STAT_CONTROL) = params->mc_stat_control; + + // Program SDRAM geometry parameters. + EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + + // Program second-level clock enable overrides. + EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + + // Program EMC pad auto calibration. + 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; + + // Program/Start auto calibration. + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; + usleep(params->emc_auto_cal_wait); + + // Patch 5 using BCT spare variables. + if (params->emc_bct_spare8) + *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + + EMC(EMC_AUTO_CAL_CONFIG9) = params->emc_auto_cal_config9; + + // Program EMC timing configuration. + 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_CTT) = params->emc_trtm; + EMC(EMC_FBIO_TWTM) = params->emc_twtm; + EMC(EMC_FBIO_TRATM) = params->emc_tratm; + EMC(EMC_FBIO_TWATM) = params->emc_twatm; + EMC(EMC_FBIO_TR2REF) = params->emc_tr2ref; + 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_DBG) = params->emc_dbg; + + // Clear read fifo. + EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 1; + EMC(EMC_ISSUE_QRST) = 0; + + // Program the rest of EMC timing configuration. + 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; + + // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. + 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_PMACRO_DSR_VTTGEN_CTRL0) = params->emc_pmacro_dsr_vttgen_ctrl0; + + // Set pipe bypass enable bits before sending any DRAM commands. + EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; + + // BootROM patching is used as a generic patch here. + if (params->boot_rom_patch_control) + { + *(vu32 *)params->boot_rom_patch_control = params->boot_rom_patch_data; + + // Trigger MC timing update. + MC(MC_TIMING_CONTROL) = 1; + } + + // Patch 7 to 9 using BCT spare secure variables. + if (params->emc_bct_spare_secure12) + *(vu32 *)params->emc_bct_spare_secure12 = params->emc_bct_spare_secure13; + if (params->emc_bct_spare_secure14) + *(vu32 *)params->emc_bct_spare_secure14 = params->emc_bct_spare_secure15; + if (params->emc_bct_spare_secure16) + *(vu32 *)params->emc_bct_spare_secure16 = params->emc_bct_spare_secure17; + + // Release SEL_DPD_CMD. + PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF; + usleep(params->pmc_io_dpd3_req_wait); + + // Set transmission pad control parameters. + EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl; + + // ZQ CAL setup (not actually issuing ZQ CAL now). + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + usleep(params->emc_timing_control_wait); + + // Deassert HOLD_CKE_LOW. + PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFF78007F; + usleep(params->pmc_ddr_ctrl_wait); + + // Set clock enable signal. + u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + EMC(EMC_PIN) = pin_gpio_cfg; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_extra_wait + 200); + EMC(EMC_PIN) = pin_gpio_cfg | 0x100; + (void)EMC(EMC_PIN); + + usleep(params->emc_pin_extra_wait + 2000); + + // Enable clock enable signal. + EMC(EMC_PIN) = pin_gpio_cfg | 0x101; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_program_wait); + + // Init zq calibration, + // Patch 6 using BCT spare variables. + if (params->emc_bct_spare10) + *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + + // Write mode registers. + 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) + { + // Issue ZQCAL start, device 0. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; + usleep(params->emc_zcal_init_wait); + + // Issue ZQCAL latch. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + // Same for device 1. + if (!(params->emc_dev_select & 2)) + { + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; + usleep(params->emc_zcal_init_wait); + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; + } + } + + // Patch 10 to 12 using BCT spare secure variables. + if (params->emc_bct_spare_secure18) + *(vu32 *)params->emc_bct_spare_secure18 = params->emc_bct_spare_secure19; + if (params->emc_bct_spare_secure20) + *(vu32 *)params->emc_bct_spare_secure20 = params->emc_bct_spare_secure21; + if (params->emc_bct_spare_secure22) + *(vu32 *)params->emc_bct_spare_secure22 = params->emc_bct_spare_secure23; + + // Set package and DPD pad control. + PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; + + // Start periodic ZQ calibration (LPDDRx only). + 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; + + // Patch 7 using BCT spare variables. + if (params->emc_bct_spare12) + *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; + + // Trigger timing update so above writes take place. + EMC(EMC_TIMING_CONTROL) = 1; + + if (params->emc_extra_refresh_num) + EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 253) | (params->emc_dev_select << 30); + + // Enable refresh. + EMC(EMC_REFCTRL) = params->emc_dev_select | BIT(31); + + EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; + 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; + + // Write addr swizzle lock bit. + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | BIT(1); + + // Re-trigger timing to latch power saving functions. + EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; + + // Enable EMC pipe clock gating. + EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + + // Depending on freqency, enable CMD/CLK fdpd. + EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; + + // Set untranslated region requirements. + MC(MC_UNTRANSLATED_REGION_CHECK) = params->mc_untranslated_region_check; + + // Lock carveouts per BCT cfg. + 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; + + // Disable write access to a bunch of EMC registers. + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; + + // Enable arbiter. + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); +} + +static void *_sdram_get_params_t210() +{ + // Check if id is proper. + u32 dramid = fuse_read_dramid(false); + + // Copy base parameters. + u32 *params = (u32 *)SDRAM_PARAMS_ADDR; + memcpy(params, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t210_t)); + + // Patch parameters if needed. + for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210); i++) + if (sdram_cfg_vendor_patches_t210[i].dramcf & DRAM_ID(dramid)) + params[sdram_cfg_vendor_patches_t210[i].offset] = sdram_cfg_vendor_patches_t210[i].val; + + return (void *)params; +} + +void *sdram_get_params_t210b01() +{ + // Check if id is proper. + u32 dramid = fuse_read_dramid(false); + + // Copy base parameters. + u32 *params = (u32 *)SDRAM_PARAMS_ADDR; + memcpy(params, &_dram_cfg_08_10_12_14_samsung_hynix_4gb, sizeof(sdram_params_t210b01_t)); + + // Patch parameters if needed. + u8 dram_code = dram_encoding_t210b01[dramid]; + if (!dram_code) + return (void *)params; + + for (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210b01); i++) + if (sdram_cfg_vendor_patches_t210b01[i].dramcf & DRAM_CC(dram_code)) + params[sdram_cfg_vendor_patches_t210b01[i].offset] = sdram_cfg_vendor_patches_t210b01[i].val; + + return (void *)params; +} + +/* + * Function: sdram_get_params_patched + * + * This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again. + * If the boot_rom_patch_control's MSB is set, it uses it as an index to + * APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data. + * (The MSB falls out when it gets multiplied by sizeof(u32)). + * Because the bootrom does not do any boundary checks, it lets us write anywhere and anything. + * Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time. + * The first patch is not needed any more when the exploit is triggered, so we overwrite that. + * 0x10459E is the address where it returns an error when the signature is not valid. + * We change that to MOV R0, #0, so we pass the check. + * + * Note: The modulus in the header must match and validated. + */ + +void *sdram_get_params_patched() +{ + #define IPATCH_CONFIG(addr, data) ((((addr) - 0x100000) / 2) << 16 | ((data) & 0xffff)) + sdram_params_t210_t *sdram_params = _sdram_get_params_t210(); + + // Disable Warmboot signature check. + sdram_params->boot_rom_patch_control = BIT(31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); + sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); +/* + // Disable SBK lock. + sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4); + sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000); + + // Disable bootrom read lock. + sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4); + sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000); + sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); + sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); +*/ + return (void *)sdram_params; +} + +void sdram_init() +{ + // Disable remote sense for SD1. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0 | MAX77620_SD_CNF2_RSVD); + + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + const sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210(); + if (params->memory_type != MEMORY_TYPE_LPDDR4) + return; + + // Set DRAM voltage. + max7762x_regulator_set_voltage(REGULATOR_SD1, 1125000); // HOS: 1.125V. Bootloader: 1.1V. + + _sdram_config_t210(params); + } + else + { + const sdram_params_t210b01_t *params = (const sdram_params_t210b01_t *)sdram_get_params_t210b01(); + if (params->memory_type != MEMORY_TYPE_LPDDR4) + return; + + _sdram_config_t210b01(params); + } +} diff --git a/bdk/mem/sdram.h b/bdk/mem/sdram.h new file mode 100644 index 0000000..10fb705 --- /dev/null +++ b/bdk/mem/sdram.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2020-2024 CTCaer + * + * 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 _SDRAM_H_ +#define _SDRAM_H_ + +#include + +/* + * Tegra X1/X1+ EMC/DRAM Bandwidth Chart: + * + * Note: Max BWbits = Hz x ddr x bus width x channels = Hz x 2 x 32 x 2. + * Max BWbits = Hz x ddr x bus width x channels = Hz x 2 x 64 x 1. + * Configurations supported: 1x32, 2x32, 1x64. + * x64 ram modules can be used by combining the 2 32-bit channels into one. + * + * 204.0 MHz: 3.04 <-- Tegra X1/X1+ Init/SC7 Frequency + * 408.0 MHz: 6.08 + * 665.6 MHz: 9.92 + * 800.0 MHz: 11.92 <-- Tegra X1/X1+ Nvidia OS Boot Frequency + * 1065.6 MHz: 15.89 + * 1331.2 MHz: 19.84 + * 1600.0 MHz: 23.84 + * 1862.4 MHz: 27.75 <-- Tegra X1 Official Max Frequency + * 2131.2 MHz: 31.76 <-- Tegra X1+ Official Max Frequency. Not all regs have support for > 2046 MHz. + */ + +enum sdram_ids_erista +{ + // LPDDR4 3200Mbps. + LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, // Die-B. (2y-01). + LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, // Die-M. (2y-01). + LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2, // Die-C. (2y-01). + + LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, // Die-C. (2y-01). + + /* + * Custom hekate/L4T supported 8GB. 7 dram id can be easily applied in fuses. + * + * 4GB modules: + * Samsung K4FBE3D4HM-MGCH/CJ/CL. MG/TF/GF/TH/GH: Package + Temperature. + * Hynix H9HCNNNCPUMLXR-NME/NEE/NEI. E/I: Temperature. + * Hynix H54G56BYYVX046/QX046/PX046. V/Q/P: Package + Temperature. + */ + LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX = 7, // XX: CH/CJ/CL. +}; + +enum sdram_ids_mariko +{ + /* + * Nintendo Switch LPDRR4X generations: + * - 1x nm are 1st-gen + * - 1y nm are 2nd-gen + * - 1z/a nm are 3rd-gen + */ + + // LPDDR4X 4266Mbps. + LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 3, // Die-M. (1y-01). + LPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 5, // Die-M. (1y-01). + LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 6, // Die-M. (1y-01). + + // LPDDR4X 3733Mbps. + LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, // Die-M. (1x-03). + LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, // Die-M. (1x-03). + LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, // Die-M. (1x-03). + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11, // Die-E. (1x-03). D9WGB. 4266Mbps. + + LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, // Die-M. (1x-03). + LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, // Die-M. (1x-03). + LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, // Die-M. (1x-03). + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15, // Die-E. (1x-03). D9WGB. 4266Mbps. + + // LPDDR4X 4266Mbps. + LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 17, // Die-A. (1y-X03). + LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 18, // Die-A. (1y-X03). + LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 19, // Die-A. (1y-X03). + + LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 20, // Die-B. (1z-01). 40% lp. + LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 21, // Die-B. (1z-01). 40% lp. + LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 22, // Die-B. (1z-01). 40% lp. + + LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, // Die-A. (1y-X03). + LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, // Die-A. (1y-X03). + + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25, // Die-F. (1y-01). D9XRR. + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26, // Die-F. (1y-01). D9XRR. + LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27, // Die-F. (1y-01). D9XRR. + + LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28, // Die-A. (1y-X03). 2nd gen. + + // Old naming scheme: H9HCNNNBKMCLXR-NEE + LPDDR4X_IOWA_4GB_HYNIX_H54G46CYRBX267 = 29, // Die-C. (1a-01). 61% lp. + LPDDR4X_HOAG_4GB_HYNIX_H54G46CYRBX267 = 30, // Die-C. (1a-01). 61% lp. + LPDDR4X_AULA_4GB_HYNIX_H54G46CYRBX267 = 31, // Die-C. (1a-01). 61% lp. + + LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 32, // Die-B. (1a-01). D8BQM. 61% lp. + LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB = 33, // Die-B. (1a-01). D8BQM. 61% lp. + LPDDR4X_AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 34, // Die-B. (1a-01). D8BQM. 61% lp. +}; + +enum sdram_codes_mariko +{ + LPDDR4X_NO_PATCH = 0, + LPDDR4X_UNUSED = 0, + + // LPDDR4X_4GB_SAMSUNG_K4U6E3S4AM_MGCJ DRAM IDs: 08, 12. + // LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLHR_NME DRAM IDs: 10, 14. + + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 1, // DRAM IDs: 09, 13. + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE = 2, // DRAM IDs: 11, 15. + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 3, // DRAM IDs: 17, 19, 24. + LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 4, // DRAM IDs: 18, 23, 28. + LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 5, // DRAM IDs: 20, 21, 22. + LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF = 6, // DRAM IDs: 25, 26, 27. + LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 7, // DRAM IDs: 03, 05, 06. + LPDDR4X_4GB_HYNIX_H54G46CYRBX267 = 8, // DRAM IDs: 29, 30, 31. + LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB = 9, // DRAM IDs: 32, 33, 34. +}; + +void sdram_init(); +void *sdram_get_params_patched(); +void *sdram_get_params_t210b01(); +void sdram_lp0_save_params(const void *params); +void sdram_src_pllc(bool enable); +emc_mr_data_t sdram_read_mrx(emc_mr_t mrx); + +#endif diff --git a/bdk/mem/sdram_config.inl b/bdk/mem/sdram_config.inl new file mode 100644 index 0000000..e6d6f0b --- /dev/null +++ b/bdk/mem/sdram_config.inl @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2020-2024 CTCaer + * + * 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 . + */ + +#define DRAM_CFG_T210_SIZE 1896 + +static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = { + /* Specifies the type of memory device */ + .memory_type = MEMORY_TYPE_LPDDR4, + + /* MC/EMC clock source configuration */ + .pllm_input_divider = 0x00000001, // M div. + .pllm_feedback_divider = 0x00000022, // N div. + .pllm_stable_time = 0x0000012C, + .pllm_setup_control = 0x00000000, + .pllm_post_divider = 0x00000000, // P div. + .pllm_kcp = 0x00000000, + .pllm_kvco = 0x00000000, + + /* Spare BCT params */ + .emc_bct_spare0 = 0x00000000, + .emc_bct_spare1 = 0x00000000, + .emc_bct_spare2 = 0x00000000, + .emc_bct_spare3 = 0x00000000, + .emc_bct_spare4 = 0x7001BC68, // EMC_PMACRO_COMMON_PAD_TX_CTRL. + .emc_bct_spare5 = 0x0000000A, + .emc_bct_spare6 = 0x7001B404, // EMC_SWIZZLE_RANK0_BYTE0. + .emc_bct_spare7 = 0x76543201, + .emc_bct_spare8 = 0x7000E6C8, // APBDEV_PMC_WEAK_BIAS. + .emc_bct_spare9 = 0x00000000, + .emc_bct_spare10 = 0x00000000, + .emc_bct_spare11 = 0x00000000, + .emc_bct_spare12 = 0x00000000, // Used to hold EMC_PMACRO_BG_BIAS_CTRL. + .emc_bct_spare13 = 0x00000034, + + /* EMC clock configuration */ + .emc_clock_source = 0x40188002, + .emc_clock_source_dll = 0x40000000, + + .clk_rst_pllm_misc20_override = 0x00000000, + .clk_rst_pllm_misc20_override_enable = 0x00000000, + + .clear_clock2_mc1 = 0x00000000, + + /* Auto-calibration of EMC pads */ + .emc_auto_cal_interval = 0x001FFFFF, + + .emc_auto_cal_config = 0xA01A51D8, + .emc_auto_cal_config2 = 0x05500000, + .emc_auto_cal_config3 = 0x00770000, + + .emc_auto_cal_config4 = 0x00770000, + .emc_auto_cal_config5 = 0x00770000, + .emc_auto_cal_config6 = 0x00770000, + .emc_auto_cal_config7 = 0x00770000, + .emc_auto_cal_config8 = 0x00770000, + + .emc_auto_cal_vref_sel0 = 0xB3AFA6A6, + .emc_auto_cal_vref_sel1 = 0x00009E3C, + + .emc_auto_cal_channel = 0xC1E00303, + + .emc_pmacro_auto_cal_cfg0 = 0x04040404, + .emc_pmacro_auto_cal_cfg1 = 0x04040404, + .emc_pmacro_auto_cal_cfg2 = 0x00000000, + + .emc_pmacro_rx_term = 0x1F1F1F1F, + .emc_pmacro_dq_tx_drive = 0x1F1F1F1F, + .emc_pmacro_ca_tx_drive = 0x1F1F1F1F, + .emc_pmacro_cmd_tx_drive = 0x00001F1F, + .emc_pmacro_auto_cal_common = 0x00000804, + .emc_pmacro_zcrtl = 0x00000550, + + /* Specifies the time for the calibration to stabilize (in microseconds) */ + .emc_auto_cal_wait = 0x000001A1, + + .emc_xm2_comp_pad_ctrl = 0x00000032, + .emc_xm2_comp_pad_ctrl2 = 0x00000000, + .emc_xm2_comp_pad_ctrl3 = 0x00000000, + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + .emc_adr_cfg = 0x00000001, // 2 Ranks. + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + .emc_pin_program_wait = 0x00000002, + /* Specifies the extra delay before/after pin RESET/CKE command */ + .emc_pin_extra_wait = 0x00000000, + + .emc_pin_gpio_enable = 0x00000003, + .emc_pin_gpio = 0x00000003, + + /* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */ + .emc_timing_control_wait = 0x0000001E, + + /* Timing parameters required for the SDRAM */ + .emc_rc = 0x0000000D, + .emc_rfc = 0x00000025, + .emc_rfc_pb = 0x00000013, + .emc_ref_ctrl2 = 0x00000000, + .emc_rfc_slr = 0x00000000, + .emc_ras = 0x00000009, + .emc_rp = 0x00000004, + .emc_r2r = 0x00000000, + .emc_w2w = 0x00000000, + .emc_r2w = 0x0000000B, + .emc_w2r = 0x0000000D, + .emc_r2p = 0x00000008, + .emc_w2p = 0x0000000B, + .emc_tppd = 0x00000004, + .emc_ccdmw = 0x00000020, + .emc_rd_rcd = 0x00000006, + .emc_wr_rcd = 0x00000006, + .emc_rrd = 0x00000006, + .emc_rext = 0x00000003, + .emc_wext = 0x00000000, + .emc_wdv = 0x00000004, + .emc_wdv_chk = 0x00000006, + .emc_wsv = 0x00000002, + .emc_wev = 0x00000000, + .emc_wdv_mask = 0x00000004, + .emc_ws_duration = 0x00000008, + .emc_we_duration = 0x0000000D, + .emc_quse = 0x00000005, + .emc_quse_width = 0x00000006, + .emc_ibdly = 0x00000000, + .emc_obdly = 0x00000000, + .emc_einput = 0x00000002, + .emc_einput_duration = 0x0000000D, + .emc_puterm_extra = 0x00000000, + .emc_puterm_width = 0x0000000B, + .emc_qrst = 0x00010000, + .emc_qsafe = 0x00000012, + .emc_rdv = 0x00000014, + .emc_rdv_mask = 0x00000016, + .emc_rdv_early = 0x00000012, + .emc_rdv_early_mask = 0x00000014, + .emc_qpop = 0x0000000A, + .emc_refresh = 0x00000304, + .emc_burst_refresh_num = 0x00000000, + .emc_prerefresh_req_cnt = 0x000000C1, + .emc_pdex2wr = 0x00000008, + .emc_pdex2rd = 0x00000008, + .emc_pchg2pden = 0x00000003, + .emc_act2pden = 0x00000003, + .emc_ar2pden = 0x00000003, + .emc_rw2pden = 0x00000014, + .emc_cke2pden = 0x00000005, + .emc_pdex2che = 0x00000002, + .emc_pdex2mrr = 0x0000000D, + .emc_txsr = 0x00000027, + .emc_txsr_dll = 0x00000027, + .emc_tcke = 0x00000005, + .emc_tckesr = 0x00000005, + .emc_tpd = 0x00000004, + .emc_tfaw = 0x00000009, + .emc_trpab = 0x00000005, + .emc_tclkstable = 0x00000004, + .emc_tclkstop = 0x00000009, + .emc_trefbw = 0x0000031C, + + /* FBIO configuration values */ + .emc_fbio_cfg5 = 0x9160A00D, + .emc_fbio_cfg7 = 0x00003BBF, + .emc_fbio_cfg8 = 0x0CF30000, + + /* Command mapping for CMD brick 0 */ + .emc_cmd_mapping_cmd0_0 = 0x061B0504, + .emc_cmd_mapping_cmd0_1 = 0x1C070302, + .emc_cmd_mapping_cmd0_2 = 0x05252523, + .emc_cmd_mapping_cmd1_0 = 0x0A091D08, + .emc_cmd_mapping_cmd1_1 = 0x0D1E0B24, + .emc_cmd_mapping_cmd1_2 = 0x0326260C, + .emc_cmd_mapping_cmd2_0 = 0x231C1B02, + .emc_cmd_mapping_cmd2_1 = 0x05070403, + .emc_cmd_mapping_cmd2_2 = 0x02252506, + .emc_cmd_mapping_cmd3_0 = 0x0D1D0B0A, + .emc_cmd_mapping_cmd3_1 = 0x1E090C08, + .emc_cmd_mapping_cmd3_2 = 0x08262624, + .emc_cmd_mapping_byte = 0x9A070624, + + .emc_fbio_spare = 0x00000012, + .emc_cfg_rsv = 0xFF00FF00, + + /* MRS command values */ + .emc_mrs = 0x00000000, + .emc_emrs = 0x00000000, + .emc_emrs2 = 0x00000000, + .emc_emrs3 = 0x00000000, + .emc_mrw1 = 0x08010004, + .emc_mrw2 = 0x08020000, + .emc_mrw3 = 0x080D0000, + .emc_mrw4 = 0xC0000000, + .emc_mrw6 = 0x08037171, + .emc_mrw8 = 0x080B0000, + .emc_mrw9 = 0x0C0E7272, + .emc_mrw10 = 0x00000000, + .emc_mrw12 = 0x0C0D0808, + .emc_mrw13 = 0x0C0D0000, + .emc_mrw14 = 0x08161414, + .emc_mrw_extra = 0x08010004, + .emc_warm_boot_mrw_extra = 0x08110000, + .emc_warm_boot_extramode_reg_write_enable = 0x00000001, + .emc_extramode_reg_write_enable = 0x00000000, + .emc_mrw_reset_command = 0x00000000, + .emc_mrw_reset_ninit_wait = 0x00000000, + .emc_mrs_wait_cnt = 0x00CC0015, + .emc_mrs_wait_cnt2 = 0x0033000A, + + /* EMC miscellaneous configurations */ + .emc_cfg = 0xF3200000, + .emc_cfg2 = 0x00110805, + .emc_cfg_pipe = 0x0FFF0FFF, + .emc_cfg_pipe_clk = 0x00000000, + .emc_fdpd_ctrl_cmd_no_ramp = 0x00000001, + .emc_cfg_update = 0x70000301, + .emc_dbg = 0x01000C00, + .emc_dbg_write_mux = 0x00000001, + .emc_cmd_q = 0x10004408, + .emc_mc2emc_q = 0x06000404, + .emc_dyn_self_ref_control = 0x80000713, + .ahb_arbitration_xbar_ctrl_meminit_done = 0x00000001, + .emc_cfg_dig_dll = 0x002C00A0, + .emc_cfg_dig_dll_1 = 0x00003701, + .emc_cfg_dig_dll_period = 0x00008000, + .emc_dev_select = 0x00000000, // Both Ranks. + .emc_sel_dpd_ctrl = 0x00040008, + + /* Pads trimmer delays */ + .emc_fdpd_ctrl_dq = 0x8020221F, + .emc_fdpd_ctrl_cmd = 0x0220F40F, + .emc_pmacro_ib_vref_dq_0 = 0x28282828, + .emc_pmacro_ib_vref_dq_1 = 0x28282828, + .emc_pmacro_ib_vref_dqs_0 = 0x11111111, + .emc_pmacro_ib_vref_dqs_1 = 0x11111111, + .emc_pmacro_ib_rxrt = 0x000000BE, + .emc_cfg_pipe1 = 0x0FFF0FFF, + .emc_cfg_pipe2 = 0x0FFF0FFF, + + .emc_pmacro_quse_ddll_rank0_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_5 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_5 = 0x00000000, + + .emc_pmacro_ob_ddll_long_dq_rank0_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_4 = 0x00120014, + .emc_pmacro_ob_ddll_long_dq_rank0_5 = 0x00140010, + .emc_pmacro_ob_ddll_long_dq_rank1_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_4 = 0x00120014, + .emc_pmacro_ob_ddll_long_dq_rank1_5 = 0x00140010, + + .emc_pmacro_ob_ddll_long_dqs_rank0_0 = 0x002E0030, + .emc_pmacro_ob_ddll_long_dqs_rank0_1 = 0x00300033, + .emc_pmacro_ob_ddll_long_dqs_rank0_2 = 0x00350033, + .emc_pmacro_ob_ddll_long_dqs_rank0_3 = 0x00320030, + .emc_pmacro_ob_ddll_long_dqs_rank0_4 = 0x00000005, + .emc_pmacro_ob_ddll_long_dqs_rank0_5 = 0x00000000, + .emc_pmacro_ob_ddll_long_dqs_rank1_0 = 0x002E0030, + .emc_pmacro_ob_ddll_long_dqs_rank1_1 = 0x00300033, + .emc_pmacro_ob_ddll_long_dqs_rank1_2 = 0x00350033, + .emc_pmacro_ob_ddll_long_dqs_rank1_3 = 0x00320030, + .emc_pmacro_ob_ddll_long_dqs_rank1_4 = 0x00000005, + .emc_pmacro_ob_ddll_long_dqs_rank1_5 = 0x00000000, + + .emc_pmacro_ib_ddll_long_dqs_rank0_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_3 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_3 = 0x00280028, + + .emc_pmacro_ddll_long_cmd_0 = 0x00140014, + .emc_pmacro_ddll_long_cmd_1 = 0x00120012, + .emc_pmacro_ddll_long_cmd_2 = 0x00100010, + .emc_pmacro_ddll_long_cmd_3 = 0x00140014, + .emc_pmacro_ddll_long_cmd_4 = 0x00000014, + .emc_pmacro_ddll_short_cmd_0 = 0x00000000, + .emc_pmacro_ddll_short_cmd_1 = 0x00000000, + .emc_pmacro_ddll_short_cmd_2 = 0x00000000, + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + .warm_boot_wait = 0x00000001, + + .emc_odt_write = 0x00000000, + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + .emc_zcal_interval = 0x00064000, + .emc_zcal_wait_cnt = 0x000900CC, + .emc_zcal_mrw_cmd = 0x0051004F, + + /* DRAM initialization sequence flow control */ + .emc_mrs_reset_dll = 0x00000000, + .emc_zcal_init_dev0 = 0x80000001, + .emc_zcal_init_dev1 = 0x40000001, + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + .emc_zcal_init_wait = 0x00000001, + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + .emc_zcal_warm_cold_boot_enables = 0x00000003, + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + .emc_mrw_lpddr2zcal_warm_boot = 0x040A00AB, + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + .emc_zqcal_ddr3_warm_boot = 0x00000011, + .emc_zqcal_lpddr4_warm_boot = 0x00000001, + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + .emc_zcal_warm_boot_wait = 0x00000001, + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + .emc_mrs_warm_boot_enable = 0x00000001, + .emc_mrs_reset_dll_wait = 0x00000000, + .emc_mrs_extra = 0x00000000, + .emc_warm_boot_mrs_extra = 0x00000000, + .emc_emrs_ddr2_dll_enable = 0x00000000, + .emc_mrs_ddr2_dll_reset = 0x00000000, + .emc_emrs_ddr2_ocd_calib = 0x00000000, + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + .emc_ddr2_wait = 0x00000000, + .emc_clken_override = 0x00000000, + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + .emc_extra_refresh_num = 0x00000002, + .emc_clken_override_allwarm_boot = 0x00000000, + .mc_clken_override_allwarm_boot = 0x00000000, + /* Specifies digital dll period, choosing between 4 to 64 ms */ + .emc_cfg_dig_dll_period_warm_boot = 0x00000003, + + /* Pad controls */ + .pmc_vddp_sel = 0x00000001, + .pmc_vddp_sel_wait = 0x00000002, + .pmc_ddr_pwr = 0x0000000F, + .pmc_ddr_cfg = 0x04220100, + .pmc_io_dpd3_req = 0x4FAFFFFF, + .pmc_io_dpd3_req_wait = 0x00000001, + .pmc_io_dpd4_req_wait = 0x00000002, + .pmc_reg_short = 0x00000000, + .pmc_no_io_power = 0x00000000, + .pmc_ddr_ctrl_wait = 0x00000000, + .pmc_ddr_ctrl = 0x0007FF8B, + .emc_acpd_control = 0x00000000, + + .emc_swizzle_rank0_byte0 = 0x76543201, // Overridden to 0x76543201 by spare6/7. + .emc_swizzle_rank0_byte1 = 0x65324710, + .emc_swizzle_rank0_byte2 = 0x25763410, + .emc_swizzle_rank0_byte3 = 0x25673401, + .emc_swizzle_rank1_byte0 = 0x32647501, + .emc_swizzle_rank1_byte1 = 0x34567201, + .emc_swizzle_rank1_byte2 = 0x56742310, + .emc_swizzle_rank1_byte3 = 0x67324501, + + .emc_txdsrvttgen = 0x00000000, + + .emc_data_brlshft0 = 0x00249249, + .emc_data_brlshft1 = 0x00249249, + + .emc_dqs_brlshft0 = 0x00000000, + .emc_dqs_brlshft1 = 0x00000000, + + .emc_cmd_brlshft0 = 0x00000000, + .emc_cmd_brlshft1 = 0x00000000, + .emc_cmd_brlshft2 = 0x0000001B, + .emc_cmd_brlshft3 = 0x0000001B, + + .emc_quse_brlshft0 = 0x00000000, + .emc_quse_brlshft1 = 0x00000000, + .emc_quse_brlshft2 = 0x00000000, + .emc_quse_brlshft3 = 0x00000000, + + .emc_dll_cfg0 = 0x1F13412F, + .emc_dll_cfg1 = 0x00010014, + + .emc_pmc_scratch1 = 0x4FAFFFFF, // APBDEV_PMC_IO_DPD3_REQ. + .emc_pmc_scratch2 = 0x7FFFFFFF, + .emc_pmc_scratch3 = 0x4006D70B, // APBDEV_PMC_DDR_CNTRL. + + .emc_pmacro_pad_cfg_ctrl = 0x00020000, + .emc_pmacro_vttgen_ctrl0 = 0x00030808, + .emc_pmacro_vttgen_ctrl1 = 0x00015C00, + .emc_pmacro_vttgen_ctrl2 = 0x00101010, + .emc_pmacro_brick_ctrl_rfu1 = 0x00001600, + .emc_pmacro_cmd_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_brick_ctrl_rfu2 = 0x00000000, + .emc_pmacro_data_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_bg_bias_ctrl0 = 0x00000034, + .emc_pmacro_data_pad_rx_ctrl = 0x00050037, + .emc_pmacro_cmd_pad_rx_ctrl = 0x00000000, + .emc_pmacro_data_rx_term_mode = 0x00000010, + .emc_pmacro_cmd_rx_term_mode = 0x00003000, + .emc_pmacro_data_pad_tx_ctrl = 0x02000111, + .emc_pmacro_common_pad_tx_ctrl = 0x00000008, // Overridden to 0x0000000A by spare4/5. + .emc_pmacro_cmd_pad_tx_ctrl = 0x0A000000, + + .emc_cfg3 = 0x00000040, + + .emc_pmacro_tx_pwrd0 = 0x10000000, + .emc_pmacro_tx_pwrd1 = 0x08000000, + .emc_pmacro_tx_pwrd2 = 0x08000000, + .emc_pmacro_tx_pwrd3 = 0x00000000, + .emc_pmacro_tx_pwrd4 = 0x00000000, + .emc_pmacro_tx_pwrd5 = 0x00001000, + + .emc_config_sample_delay = 0x00000020, + + .emc_pmacro_brick_mapping0 = 0x28091081, + .emc_pmacro_brick_mapping1 = 0x44A53293, + .emc_pmacro_brick_mapping2 = 0x76678A5B, + + .emc_pmacro_tx_sel_clk_src0 = 0x00000000, + .emc_pmacro_tx_sel_clk_src1 = 0x00000000, + .emc_pmacro_tx_sel_clk_src2 = 0x00000000, + .emc_pmacro_tx_sel_clk_src3 = 0x00000000, + .emc_pmacro_tx_sel_clk_src4 = 0x00000000, + .emc_pmacro_tx_sel_clk_src5 = 0x00000000, + + .emc_pmacro_ddll_bypass = 0xEFFFEFFF, + + .emc_pmacro_ddll_pwrd0 = 0xC0C0C0C0, + .emc_pmacro_ddll_pwrd1 = 0xC0C0C0C0, + .emc_pmacro_ddll_pwrd2 = 0xDCDCDCDC, + + .emc_pmacro_cmd_ctrl0 = 0x0A0A0A0A, + .emc_pmacro_cmd_ctrl1 = 0x0A0A0A0A, + .emc_pmacro_cmd_ctrl2 = 0x0A0A0A0A, + + /* DRAM size information */ + .mc_emem_adr_cfg = 0x00000001, // 2 Ranks. + .mc_emem_adr_cfg_dev0 = 0x00070302, // Chip 0 Density 512MB. + .mc_emem_adr_cfg_dev1 = 0x00070302, // Chip 1 Density 512MB. + .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, + .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, + .mc_emem_adr_cfg_bank_mask1 = 0x39722800, + .mc_emem_adr_cfg_bank_mask2 = 0x4B9C1000, + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + .mc_emem_cfg = 0x00001000, // 4GB total density. Max 8GB. + + /* MC arbitration configuration */ + .mc_emem_arb_cfg = 0x08000001, + .mc_emem_arb_outstanding_req = 0x8000004C, + .emc_emem_arb_refpb_hp_ctrl = 0x000A1020, + .emc_emem_arb_refpb_bank_ctrl = 0x80001028, + + .mc_emem_arb_timing_rcd = 0x00000001, + .mc_emem_arb_timing_rp = 0x00000000, + .mc_emem_arb_timing_rc = 0x00000003, + .mc_emem_arb_timing_ras = 0x00000001, + .mc_emem_arb_timing_faw = 0x00000002, + .mc_emem_arb_timing_rrd = 0x00000001, + .mc_emem_arb_timing_rap2pre = 0x00000002, + .mc_emem_arb_timing_wap2pre = 0x00000005, + .mc_emem_arb_timing_r2r = 0x00000002, + .mc_emem_arb_timing_w2w = 0x00000001, + .mc_emem_arb_timing_r2w = 0x00000004, + .mc_emem_arb_timing_w2r = 0x00000005, + .mc_emem_arb_timing_rfcpb = 0x00000004, + + .mc_emem_arb_da_turns = 0x02020001, + .mc_emem_arb_da_covers = 0x00030201, + .mc_emem_arb_misc0 = 0x71C30504, + .mc_emem_arb_misc1 = 0x70000F0F, + .mc_emem_arb_misc2 = 0x00000000, + + .mc_emem_arb_ring1_throttle = 0x001F0000, + .mc_emem_arb_override = 0x10000000, + .mc_emem_arb_override1 = 0x00000000, + .mc_emem_arb_rsv = 0xFF00FF00, + + .mc_da_cfg0 = 0x00000001, + .mc_emem_arb_timing_ccdmw = 0x00000008, + + .mc_clken_override = 0x00008000, + + .mc_stat_control = 0x00000000, + .mc_video_protect_bom = 0xFFF00000, + .mc_video_protect_bom_adr_hi = 0x00000000, + .mc_video_protect_size_mb = 0x00000000, + + // AFI, BPMP, HC, ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1, SDMMC1A, SDMMC2A, SDMMC3A. Plus TSEC, NVENC. + .mc_video_protect_vpr_override = 0xE4FACB43, // Default: 0xE4BAC343. New: 0xE4FACB43. + TSEC, NVENC. + // SDMMC4A, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR. Plus TSECB, TSEC1, TSECB1. + .mc_video_protect_vpr_override1 = 0x0000FED3, // Default: 0x00001ED3. New: 0x0000FED3. + TSECB, TSEC1, TSECB1. + + .mc_video_protect_gpu_override0 = 0x2A800000, // Default: 0x00000000. Forced to 1 by HOS Secmon. + .mc_video_protect_gpu_override1 = 0x00000002, // Default: 0x00000000. Forced to 0 by HOS Secmon. + + .mc_sec_carveout_bom = 0xFFF00000, + .mc_sec_carveout_adr_hi = 0x00000000, + .mc_sec_carveout_size_mb = 0x00000000, + + .mc_video_protect_write_access = 0x00000000, + .mc_sec_carveout_protect_write_access = 0x00000000, + + .mc_generalized_carveout1_bom = 0x00000000, + .mc_generalized_carveout1_bom_hi = 0x00000000, + .mc_generalized_carveout1_size_128kb = 0x00000008, + .mc_generalized_carveout1_access0 = 0x00000000, + .mc_generalized_carveout1_access1 = 0x00000000, + .mc_generalized_carveout1_access2 = 0x00300000, + .mc_generalized_carveout1_access3 = 0x03000000, + .mc_generalized_carveout1_access4 = 0x00000000, + .mc_generalized_carveout1_force_internal_access0 = 0x00000000, + .mc_generalized_carveout1_force_internal_access1 = 0x00000000, + .mc_generalized_carveout1_force_internal_access2 = 0x00000000, + .mc_generalized_carveout1_force_internal_access3 = 0x00000000, + .mc_generalized_carveout1_force_internal_access4 = 0x00000000, + .mc_generalized_carveout1_cfg0 = 0x04000C76, + + .mc_generalized_carveout2_bom = 0x00000000, + .mc_generalized_carveout2_bom_hi = 0x00000000, + .mc_generalized_carveout2_size_128kb = 0x00000002, + .mc_generalized_carveout2_access0 = 0x00000000, + .mc_generalized_carveout2_access1 = 0x00000000, + .mc_generalized_carveout2_access2 = 0x03000000, + .mc_generalized_carveout2_access3 = 0x00000000, + .mc_generalized_carveout2_access4 = 0x00000300, + .mc_generalized_carveout2_force_internal_access0 = 0x00000000, + .mc_generalized_carveout2_force_internal_access1 = 0x00000000, + .mc_generalized_carveout2_force_internal_access2 = 0x00000000, + .mc_generalized_carveout2_force_internal_access3 = 0x00000000, + .mc_generalized_carveout2_force_internal_access4 = 0x00000000, + .mc_generalized_carveout2_cfg0 = 0x0440167E, + + .mc_generalized_carveout3_bom = 0x00000000, + .mc_generalized_carveout3_bom_hi = 0x00000000, + .mc_generalized_carveout3_size_128kb = 0x00000000, + .mc_generalized_carveout3_access0 = 0x00000000, + .mc_generalized_carveout3_access1 = 0x00000000, + .mc_generalized_carveout3_access2 = 0x03000000, + .mc_generalized_carveout3_access3 = 0x00000000, + .mc_generalized_carveout3_access4 = 0x00000300, + .mc_generalized_carveout3_force_internal_access0 = 0x00000000, + .mc_generalized_carveout3_force_internal_access1 = 0x00000000, + .mc_generalized_carveout3_force_internal_access2 = 0x00000000, + .mc_generalized_carveout3_force_internal_access3 = 0x00000000, + .mc_generalized_carveout3_force_internal_access4 = 0x00000000, + .mc_generalized_carveout3_cfg0 = 0x04401E7E, + + .mc_generalized_carveout4_bom = 0x00000000, + .mc_generalized_carveout4_bom_hi = 0x00000000, + .mc_generalized_carveout4_size_128kb = 0x00000008, + .mc_generalized_carveout4_access0 = 0x00000000, + .mc_generalized_carveout4_access1 = 0x00000000, + .mc_generalized_carveout4_access2 = 0x00300000, + .mc_generalized_carveout4_access3 = 0x00000000, + .mc_generalized_carveout4_access4 = 0x000000C0, + .mc_generalized_carveout4_force_internal_access0 = 0x00000000, + .mc_generalized_carveout4_force_internal_access1 = 0x00000000, + .mc_generalized_carveout4_force_internal_access2 = 0x00000000, + .mc_generalized_carveout4_force_internal_access3 = 0x00000000, + .mc_generalized_carveout4_force_internal_access4 = 0x00000000, + .mc_generalized_carveout4_cfg0 = 0x04002446, + + .mc_generalized_carveout5_bom = 0x00000000, + .mc_generalized_carveout5_bom_hi = 0x00000000, + .mc_generalized_carveout5_size_128kb = 0x00000008, + .mc_generalized_carveout5_access0 = 0x00000000, + .mc_generalized_carveout5_access1 = 0x00000000, + .mc_generalized_carveout5_access2 = 0x00300000, + .mc_generalized_carveout5_access3 = 0x00000000, + .mc_generalized_carveout5_access4 = 0x00000000, + .mc_generalized_carveout5_force_internal_access0 = 0x00000000, + .mc_generalized_carveout5_force_internal_access1 = 0x00000000, + .mc_generalized_carveout5_force_internal_access2 = 0x00000000, + .mc_generalized_carveout5_force_internal_access3 = 0x00000000, + .mc_generalized_carveout5_force_internal_access4 = 0x00000000, + .mc_generalized_carveout5_cfg0 = 0x04002C46, + + /* Specifies enable for CA training */ + .emc_ca_training_enable = 0x00000000, + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + .swizzle_rank_byte_encode = 0x000000EC, + + /* Specifies enable and offset for patched boot rom write */ + .boot_rom_patch_control = 0x00000000, + /* Specifies data for patched boot rom write */ + .boot_rom_patch_data = 0x00000000, + + .mc_mts_carveout_bom = 0xFFF00000, + .mc_mts_carveout_adr_hi = 0x00000000, + .mc_mts_carveout_size_mb = 0x00000000, + .mc_mts_carveout_reg_ctrl = 0x00000000 +}; + +#define DCFG_OFFSET_OF(m) (OFFSET_OF(sdram_params_t210_t, m) / 4) +static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = { + // Hynix timing config. + { 0x0000000D, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_r2w) }, + { 0x00000001, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_puterm_extra) }, + { 0x80000000, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_puterm_width) }, + { 0x00000210, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_pmacro_data_rx_term_mode) }, + { 0x00000005, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(mc_emem_arb_timing_r2w) }, + + // Samsung 6GB density config. + { 0x000C0302, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev0) }, // 768MB Chip 0 density. + { 0x000C0302, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev1) }, // 768MB Chip 1 density. + { 0x00001800, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH), DCFG_OFFSET_OF(mc_emem_cfg) }, // 6GB total density. Max 8GB. + + // Samsung 8GB density config. + { 0x0000003A, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_rfc) }, + { 0x0000001D, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_rfc_pb) }, + { 0x0000003B, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_txsr) }, + { 0x0000003B, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_txsr_dll) }, + { 0x00080302, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev0) }, // 1024MB Chip 0 density. + { 0x00080302, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev1) }, // 1024MB Chip 1 density. + { 0x00002000, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(mc_emem_cfg) }, // 8GB total density. Max 8GB. +}; +#undef DCFG_OFFSET_OF diff --git a/bdk/mem/sdram_config_t210b01.inl b/bdk/mem/sdram_config_t210b01.inl new file mode 100644 index 0000000..3879e0c --- /dev/null +++ b/bdk/mem/sdram_config_t210b01.inl @@ -0,0 +1,812 @@ +/* + * Copyright (c) 2020-2024 CTCaer + * + * 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 . + */ + +#define DRAM_CFG_T210B01_SIZE 2104 + +static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = { + /* Specifies the type of memory device */ + .memory_type = MEMORY_TYPE_LPDDR4, + + /* MC/EMC clock source configuration */ + .pllm_input_divider = 0x00000001, // M div. + .pllm_feedback_divider = 0x00000022, // N div. + .pllm_stable_time = 0x0000012C, + .pllm_setup_control = 0x00000000, + .pllm_post_divider = 0x00000000, // P div. + .pllm_kcp = 0x00000000, + .pllm_kvco = 0x00000000, + + /* Spare BCT params */ + .emc_bct_spare0 = 0x00000000, + .emc_bct_spare1 = 0x00000000, + .emc_bct_spare2 = 0x00000000, + .emc_bct_spare3 = 0x00000000, + .emc_bct_spare4 = 0x00000000, + .emc_bct_spare5 = 0x00000000, + .emc_bct_spare6 = 0x00000000, + .emc_bct_spare7 = 0x00000000, + .emc_bct_spare8 = 0x00000000, + .emc_bct_spare9 = 0x00000000, + .emc_bct_spare10 = 0x00000000, + .emc_bct_spare11 = 0x00000000, + .emc_bct_spare12 = 0x00000000, + .emc_bct_spare13 = 0x00000000, + + .emc_bct_spare_secure0 = 0x00000000, + .emc_bct_spare_secure1 = 0x00000000, + .emc_bct_spare_secure2 = 0x00000000, + .emc_bct_spare_secure3 = 0x00000000, + .emc_bct_spare_secure4 = 0x00000000, + .emc_bct_spare_secure5 = 0x00000000, + .emc_bct_spare_secure6 = 0x00000000, + .emc_bct_spare_secure7 = 0x00000000, + .emc_bct_spare_secure8 = 0x00000000, + .emc_bct_spare_secure9 = 0x00000000, + .emc_bct_spare_secure10 = 0x00000000, + .emc_bct_spare_secure11 = 0x00000000, + .emc_bct_spare_secure12 = 0x00000000, + .emc_bct_spare_secure13 = 0x00000000, + .emc_bct_spare_secure14 = 0x00000000, + .emc_bct_spare_secure15 = 0x00000000, + .emc_bct_spare_secure16 = 0x00000000, + .emc_bct_spare_secure17 = 0x00000000, + .emc_bct_spare_secure18 = 0x00000000, + .emc_bct_spare_secure19 = 0x00000000, + .emc_bct_spare_secure20 = 0x00000000, + .emc_bct_spare_secure21 = 0x00000000, + .emc_bct_spare_secure22 = 0x00000000, + .emc_bct_spare_secure23 = 0x00000000, + + /* EMC clock configuration */ + .emc_clock_source = 0x40188002, + .emc_clock_source_dll = 0x40000000, + + .clk_rst_pllm_misc20_override = 0x00000000, + .clk_rst_pllm_misc20_override_enable = 0x00000000, + + .clear_clock2_mc1 = 0x00000000, + + /* Auto-calibration of EMC pads */ + .emc_auto_cal_interval = 0x001FFFFF, + + .emc_auto_cal_config = 0xA01A51D8, + .emc_auto_cal_config2 = 0x00000000, + .emc_auto_cal_config3 = 0x00880000, + + .emc_auto_cal_config4 = 0x00880000, + .emc_auto_cal_config5 = 0x00001220, + .emc_auto_cal_config6 = 0x00880000, + .emc_auto_cal_config7 = 0x00880000, + .emc_auto_cal_config8 = 0x00880000, + .emc_auto_cal_config9 = 0x00000000, + + .emc_auto_cal_vref_sel0 = 0xB3C5BCBC, + .emc_auto_cal_vref_sel1 = 0x00009E3C, + + .emc_auto_cal_channel = 0xC1E00302, + + .emc_pmacro_auto_cal_cfg0 = 0x04040404, + .emc_pmacro_auto_cal_cfg1 = 0x04040404, + .emc_pmacro_auto_cal_cfg2 = 0x04040404, + + .emc_pmacro_rx_term = 0x3F3F3F3F, + .emc_pmacro_dq_tx_drive = 0x3F3F3F3F, + .emc_pmacro_ca_tx_drive = 0x3F3F3F3F, + .emc_pmacro_cmd_tx_drive = 0x00001220, + .emc_pmacro_auto_cal_common = 0x00000804, + .emc_pmacro_zcrtl = 0x00505050, + + /* Specifies the time for the calibration to stabilize (in microseconds) */ + .emc_auto_cal_wait = 0x000001A1, + + .emc_xm2_comp_pad_ctrl = 0x00000030, + .emc_xm2_comp_pad_ctrl2 = 0x16001000, + .emc_xm2_comp_pad_ctrl3 = 0x00901000, + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + .emc_adr_cfg = 0x00000000, // 1 Rank. + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + .emc_pin_program_wait = 0x00000002, + /* Specifies the extra delay before/after pin RESET/CKE command */ + .emc_pin_extra_wait = 0x00000000, + + .emc_pin_gpio_enable = 0x00000003, + .emc_pin_gpio = 0x00000003, + + /* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */ + .emc_timing_control_wait = 0x0000001E, + + /* Timing parameters required for the SDRAM */ + .emc_rc = 0x0000000D, + .emc_rfc = 0x0000003A, + .emc_rfc_pb = 0x0000001D, + .emc_ref_ctrl2 = 0x00000000, + .emc_rfc_slr = 0x00000000, + .emc_ras = 0x00000009, + .emc_rp = 0x00000004, + .emc_r2r = 0x00000000, + .emc_w2w = 0x00000000, + .emc_r2w = 0x0000000B, + .emc_w2r = 0x0000000D, + .emc_r2p = 0x00000008, + .emc_w2p = 0x0000000B, + .emc_tppd = 0x00000004, + .emc_trtm = 0x00000017, + .emc_twtm = 0x00000015, + .emc_tratm = 0x00000017, + .emc_twatm = 0x0000001B, + .emc_tr2ref = 0x00000000, + .emc_ccdmw = 0x00000020, + .emc_rd_rcd = 0x00000006, + .emc_wr_rcd = 0x00000006, + .emc_rrd = 0x00000006, + .emc_rext = 0x00000003, + .emc_wext = 0x00000000, + .emc_wdv = 0x00000004, + .emc_wdv_chk = 0x00000006, + .emc_wsv = 0x00000002, + .emc_wev = 0x00000000, + .emc_wdv_mask = 0x00000004, + .emc_ws_duration = 0x00000008, + .emc_we_duration = 0x0000000E, + .emc_quse = 0x00000005, + .emc_quse_width = 0x00000006, + .emc_ibdly = 0x00000000, + .emc_obdly = 0x00000000, + .emc_einput = 0x00000002, + .emc_einput_duration = 0x0000000D, + .emc_puterm_extra = 0x00000001, + .emc_puterm_width = 0x80000000, + .emc_qrst = 0x00010000, + .emc_qsafe = 0x00000012, + .emc_rdv = 0x00000018, + .emc_rdv_mask = 0x0000001A, + .emc_rdv_early = 0x00000016, + .emc_rdv_early_mask = 0x00000018, + .emc_qpop = 0x0000000A, + .emc_refresh = 0x00000304, + .emc_burst_refresh_num = 0x00000000, + .emc_prerefresh_req_cnt = 0x000000C1, + .emc_pdex2wr = 0x00000008, + .emc_pdex2rd = 0x00000008, + .emc_pchg2pden = 0x00000003, + .emc_act2pden = 0x0000000A, + .emc_ar2pden = 0x00000003, + .emc_rw2pden = 0x00000014, + .emc_cke2pden = 0x00000005, + .emc_pdex2che = 0x00000002, + .emc_pdex2mrr = 0x0000000D, + .emc_txsr = 0x0000003B, + .emc_txsr_dll = 0x0000003B, + .emc_tcke = 0x00000005, + .emc_tckesr = 0x00000005, + .emc_tpd = 0x00000004, + .emc_tfaw = 0x00000009, + .emc_trpab = 0x00000005, + .emc_tclkstable = 0x00000004, + .emc_tclkstop = 0x00000009, + .emc_trefbw = 0x0000031C, + + /* FBIO configuration values */ + .emc_fbio_cfg5 = 0x9160A00D, + .emc_fbio_cfg7 = 0x00003A3F, + .emc_fbio_cfg8 = 0x0CF30000, + + /* Command mapping for CMD brick 0 */ + .emc_cmd_mapping_cmd0_0 = 0x061B0504, + .emc_cmd_mapping_cmd0_1 = 0x1C070302, + .emc_cmd_mapping_cmd0_2 = 0x05252523, + .emc_cmd_mapping_cmd1_0 = 0x0A091D08, + .emc_cmd_mapping_cmd1_1 = 0x0D1E0B24, + .emc_cmd_mapping_cmd1_2 = 0x0326260C, + .emc_cmd_mapping_cmd2_0 = 0x231C1B02, + .emc_cmd_mapping_cmd2_1 = 0x05070403, + .emc_cmd_mapping_cmd2_2 = 0x02252506, + .emc_cmd_mapping_cmd3_0 = 0x0D1D0B0A, + .emc_cmd_mapping_cmd3_1 = 0x1E090C08, + .emc_cmd_mapping_cmd3_2 = 0x08262624, + .emc_cmd_mapping_byte = 0x9A070624, + + .emc_fbio_spare = 0x00000012, + .emc_cfg_rsv = 0xFF00FF00, + + /* MRS command values */ + .emc_mrs = 0x00000000, + .emc_emrs = 0x00000000, + .emc_emrs2 = 0x00000000, + .emc_emrs3 = 0x00000000, + .emc_mrw1 = 0x88010004, + .emc_mrw2 = 0x88020000, + .emc_mrw3 = 0x880D0000, + .emc_mrw4 = 0xC0000000, + .emc_mrw6 = 0x88033131, + .emc_mrw8 = 0x880B0000, + .emc_mrw9 = 0x8C0E5D5D, + .emc_mrw10 = 0x880C5D5D, + .emc_mrw12 = 0x8C0D0808, + .emc_mrw13 = 0x8C0D0000, + .emc_mrw14 = 0x88161616, + .emc_mrw_extra = 0x88010004, + .emc_warm_boot_mrw_extra = 0x08110000, + .emc_warm_boot_extramode_reg_write_enable = 0x00000001, + .emc_extramode_reg_write_enable = 0x00000000, + .emc_mrw_reset_command = 0x00000000, + .emc_mrw_reset_ninit_wait = 0x00000000, + .emc_mrs_wait_cnt = 0x00CC0010, + .emc_mrs_wait_cnt2 = 0x0033000A, + + /* EMC miscellaneous configurations */ + .emc_cfg = 0xF3200000, + .emc_cfg2 = 0x00110825, + .emc_cfg_pipe = 0x0FFF0000, + .emc_cfg_pipe_clk = 0x00000000, + .emc_fdpd_ctrl_cmd_no_ramp = 0x00000001, + .emc_cfg_update = 0x70000301, + .emc_dbg = 0x01000C00, + .emc_dbg_write_mux = 0x00000001, + .emc_cmd_q = 0x10004408, + .emc_mc2emc_q = 0x06000404, + .emc_dyn_self_ref_control = 0x00000713, + .ahb_arbitration_xbar_ctrl_meminit_done = 0x00000001, + .emc_cfg_dig_dll = 0x002C00A0, + .emc_cfg_dig_dll_1 = 0x000F3701, + .emc_cfg_dig_dll_period = 0x00008000, + .emc_dev_select = 0x00000002, // Rank 0 only. + .emc_sel_dpd_ctrl = 0x0004000C, + + /* Pads trimmer delays */ + .emc_fdpd_ctrl_dq = 0x8020221F, + .emc_fdpd_ctrl_cmd = 0x0220F40F, + .emc_pmacro_ib_vref_dq_0 = 0x29292929, + .emc_pmacro_ib_vref_dq_1 = 0x29292929, + .emc_pmacro_ib_vref_dqs_0 = 0x29292929, + .emc_pmacro_ib_vref_dqs_1 = 0x29292929, + .emc_pmacro_ib_rxrt = 0x00000078, + .emc_cfg_pipe1 = 0x0FFF0000, + .emc_cfg_pipe2 = 0x00000000, + + .emc_pmacro_quse_ddll_rank0_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_5 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_5 = 0x00000000, + + .emc_pmacro_ob_ddll_long_dq_rank0_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_4 = 0x000D0016, + .emc_pmacro_ob_ddll_long_dq_rank0_5 = 0x0017000B, + .emc_pmacro_ob_ddll_long_dq_rank1_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_4 = 0x000D0016, + .emc_pmacro_ob_ddll_long_dq_rank1_5 = 0x0017000B, + + .emc_pmacro_ob_ddll_long_dqs_rank0_0 = 0x00450043, + .emc_pmacro_ob_ddll_long_dqs_rank0_1 = 0x00430045, + .emc_pmacro_ob_ddll_long_dqs_rank0_2 = 0x00470046, + .emc_pmacro_ob_ddll_long_dqs_rank0_3 = 0x00460041, + .emc_pmacro_ob_ddll_long_dqs_rank0_4 = 0x0003000C, + .emc_pmacro_ob_ddll_long_dqs_rank0_5 = 0x000D0000, + .emc_pmacro_ob_ddll_long_dqs_rank1_0 = 0x00450043, + .emc_pmacro_ob_ddll_long_dqs_rank1_1 = 0x00430045, + .emc_pmacro_ob_ddll_long_dqs_rank1_2 = 0x00470046, + .emc_pmacro_ob_ddll_long_dqs_rank1_3 = 0x00460041, + .emc_pmacro_ob_ddll_long_dqs_rank1_4 = 0x0003000C, + .emc_pmacro_ob_ddll_long_dqs_rank1_5 = 0x000D0000, + + .emc_pmacro_ib_ddll_long_dqs_rank0_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_3 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_3 = 0x00280028, + + .emc_pmacro_ddll_long_cmd_0 = 0x00160016, + .emc_pmacro_ddll_long_cmd_1 = 0x000D000D, + .emc_pmacro_ddll_long_cmd_2 = 0x000B000B, + .emc_pmacro_ddll_long_cmd_3 = 0x00170017, + .emc_pmacro_ddll_long_cmd_4 = 0x00000016, + .emc_pmacro_ddll_short_cmd_0 = 0x00000000, + .emc_pmacro_ddll_short_cmd_1 = 0x00000000, + .emc_pmacro_ddll_short_cmd_2 = 0x00000000, + + .emc_pmacro_ddll_periodic_offset = 0x00000000, + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + .warm_boot_wait = 0x00000001, + + .emc_odt_write = 0x00000000, + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + .emc_zcal_interval = 0x00064000, + .emc_zcal_wait_cnt = 0x000900CC, + .emc_zcal_mrw_cmd = 0x8051004F, + + /* DRAM initialization sequence flow control */ + .emc_mrs_reset_dll = 0x00000000, + .emc_zcal_init_dev0 = 0x80000001, + .emc_zcal_init_dev1 = 0x00000000, + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + .emc_zcal_init_wait = 0x00000001, + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + .emc_zcal_warm_cold_boot_enables = 0x00000003, + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + .emc_mrw_lpddr2zcal_warm_boot = 0x040A00AB, + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + .emc_zqcal_ddr3_warm_boot = 0x00000011, + .emc_zqcal_lpddr4_warm_boot = 0x00000001, + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + .emc_zcal_warm_boot_wait = 0x00000001, + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + .emc_mrs_warm_boot_enable = 0x00000001, + .emc_mrs_reset_dll_wait = 0x00000000, + .emc_mrs_extra = 0x00000000, + .emc_warm_boot_mrs_extra = 0x00000000, + .emc_emrs_ddr2_dll_enable = 0x00000000, + .emc_mrs_ddr2_dll_reset = 0x00000000, + .emc_emrs_ddr2_ocd_calib = 0x00000000, + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + .emc_ddr2_wait = 0x00000000, + .emc_clken_override = 0x00000000, + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + .emc_extra_refresh_num = 0x00000002, + .emc_clken_override_allwarm_boot = 0x00000000, + .mc_clken_override_allwarm_boot = 0x00000000, + /* Specifies digital dll period, choosing between 4 to 64 ms */ + .emc_cfg_dig_dll_period_warm_boot = 0x00000003, + + /* Pad controls */ + .pmc_vddp_sel = 0x00000001, + .pmc_vddp_sel_wait = 0x00000002, + .pmc_ddr_cfg = 0x04220100, + .pmc_io_dpd3_req = 0x4FAF9FFF, + .pmc_io_dpd3_req_wait = 0x00000001, + .pmc_io_dpd4_req_wait = 0x00000002, + .pmc_reg_short = 0x00000000, + .pmc_no_io_power = 0x00000000, + .pmc_ddr_ctrl_wait = 0x00000000, + .pmc_ddr_ctrl = 0x0037FF9F, + .emc_acpd_control = 0x00000000, + + .emc_swizzle_rank0_byte0 = 0x76543201, + .emc_swizzle_rank0_byte1 = 0x65324710, + .emc_swizzle_rank0_byte2 = 0x25763410, + .emc_swizzle_rank0_byte3 = 0x25673401, + .emc_swizzle_rank1_byte0 = 0x32647501, + .emc_swizzle_rank1_byte1 = 0x34567201, + .emc_swizzle_rank1_byte2 = 0x56742310, + .emc_swizzle_rank1_byte3 = 0x67324501, + + .emc_txdsrvttgen = 0x00000000, + + .emc_data_brlshft0 = 0x00249249, + .emc_data_brlshft1 = 0x00249249, + + .emc_dqs_brlshft0 = 0x00000000, + .emc_dqs_brlshft1 = 0x00000000, + + .emc_cmd_brlshft0 = 0x00000000, + .emc_cmd_brlshft1 = 0x00000000, + .emc_cmd_brlshft2 = 0x00000012, + .emc_cmd_brlshft3 = 0x00000012, + + .emc_quse_brlshft0 = 0x00000000, + .emc_quse_brlshft1 = 0x00000000, + .emc_quse_brlshft2 = 0x00000000, + .emc_quse_brlshft3 = 0x00000000, + + .emc_dll_cfg0 = 0x1F134120, + .emc_dll_cfg1 = 0x00010014, + + .emc_pmc_scratch1 = 0x4FAF9FFF, + .emc_pmc_scratch2 = 0x7FFFFFFF, + .emc_pmc_scratch3 = 0x4036D71F, + + .emc_pmacro_pad_cfg_ctrl = 0x00000000, + .emc_pmacro_vttgen_ctrl0 = 0x00090000, + .emc_pmacro_vttgen_ctrl1 = 0x00103400, + .emc_pmacro_vttgen_ctrl2 = 0x00000000, + .emc_pmacro_dsr_vttgen_ctrl0 = 0x00000009, + .emc_pmacro_brick_ctrl_rfu1 = 0x00000000, + .emc_pmacro_cmd_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_brick_ctrl_rfu2 = 0x00000000, + .emc_pmacro_data_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_bg_bias_ctrl0 = 0x00000000, + .emc_pmacro_data_pad_rx_ctrl = 0x05050003, + .emc_pmacro_cmd_pad_rx_ctrl = 0x05000000, + .emc_pmacro_data_rx_term_mode = 0x00000210, + .emc_pmacro_cmd_rx_term_mode = 0x00002000, + .emc_pmacro_data_pad_tx_ctrl = 0x00000421, + .emc_pmacro_cmd_pad_tx_ctrl = 0x00000000, + + .emc_cfg3 = 0x00000040, + + .emc_pmacro_tx_pwrd0 = 0x10000000, + .emc_pmacro_tx_pwrd1 = 0x00000000, + .emc_pmacro_tx_pwrd2 = 0x00000000, + .emc_pmacro_tx_pwrd3 = 0x00000000, + .emc_pmacro_tx_pwrd4 = 0x00400080, + .emc_pmacro_tx_pwrd5 = 0x00801004, + + .emc_config_sample_delay = 0x00000020, + + .emc_pmacro_brick_mapping0 = 0x28091081, + .emc_pmacro_brick_mapping1 = 0x44A53293, + .emc_pmacro_brick_mapping2 = 0x76678A5B, + + .emc_pmacro_tx_sel_clk_src0 = 0x00000000, + .emc_pmacro_tx_sel_clk_src1 = 0x00000000, + .emc_pmacro_tx_sel_clk_src2 = 0x00000000, + .emc_pmacro_tx_sel_clk_src3 = 0x00000000, + .emc_pmacro_tx_sel_clk_src4 = 0x00000000, + .emc_pmacro_tx_sel_clk_src5 = 0x00000000, + + .emc_pmacro_perbit_fgcg_ctrl0 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl1 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl2 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl3 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl4 = 0x00000000, + .emc_pmacro_perbit_fgcg_ctrl5 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl0 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl1 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl2 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl3 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl4 = 0x00000000, + .emc_pmacro_perbit_rfu_ctrl5 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl0 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl1 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl2 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl3 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl4 = 0x00000000, + .emc_pmacro_perbit_rfu1_ctrl5 = 0x00000000, + + .emc_pmacro_data_pi_ctrl = 0x00001010, + .emc_pmacro_cmd_pi_ctrl = 0x00001010, + + .emc_pmacro_ddll_bypass = 0xEF00EF00, + + .emc_pmacro_ddll_pwrd0 = 0x00000000, + .emc_pmacro_ddll_pwrd1 = 0x00000000, + .emc_pmacro_ddll_pwrd2 = 0x1C1C1C1C, + + .emc_pmacro_cmd_ctrl0 = 0x00000000, + .emc_pmacro_cmd_ctrl1 = 0x00000000, + .emc_pmacro_cmd_ctrl2 = 0x00000000, + + /* DRAM size information */ + .mc_emem_adr_cfg = 0x00000000, // 1 Rank. + .mc_emem_adr_cfg_dev0 = 0x00080302, // Chip 0 Density 1024MB. + .mc_emem_adr_cfg_dev1 = 0x00080302, // Chip 1 Density 1024MB. + .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, + .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, + .mc_emem_adr_cfg_bank_mask1 = 0x39722800, + .mc_emem_adr_cfg_bank_mask2 = 0x4B9C1000, + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + .mc_emem_cfg = 0x00001000, // 4GB total density. Max 8GB. + + /* MC arbitration configuration */ + .mc_emem_arb_cfg = 0x08000001, + .mc_emem_arb_outstanding_req = 0x8000004C, + .emc_emem_arb_refpb_hp_ctrl = 0x000A1020, + .emc_emem_arb_refpb_bank_ctrl = 0x80001028, + + .mc_emem_arb_timing_rcd = 0x00000001, + .mc_emem_arb_timing_rp = 0x00000000, + .mc_emem_arb_timing_rc = 0x00000003, + .mc_emem_arb_timing_ras = 0x00000001, + .mc_emem_arb_timing_faw = 0x00000002, + .mc_emem_arb_timing_rrd = 0x00000001, + .mc_emem_arb_timing_rap2pre = 0x00000002, + .mc_emem_arb_timing_wap2pre = 0x00000005, + .mc_emem_arb_timing_r2r = 0x00000001, + .mc_emem_arb_timing_w2w = 0x00000001, + .mc_emem_arb_timing_r2w = 0x00000004, + .mc_emem_arb_timing_w2r = 0x00000005, + .mc_emem_arb_timing_rfcpb = 0x00000007, + + .mc_emem_arb_da_turns = 0x02020000, + .mc_emem_arb_da_covers = 0x00030201, + .mc_emem_arb_misc0 = 0x72A30504, + .mc_emem_arb_misc1 = 0x70000F0F, + .mc_emem_arb_misc2 = 0x00000000, + + .mc_emem_arb_ring1_throttle = 0x001F0000, + .mc_emem_arb_override = 0x10000000, + .mc_emem_arb_override1 = 0x00000000, + .mc_emem_arb_rsv = 0xFF00FF00, + + .mc_da_cfg0 = 0x00000001, + .mc_emem_arb_timing_ccdmw = 0x00000008, + + .mc_clken_override = 0x00008000, + + .mc_stat_control = 0x00000000, + .mc_video_protect_bom = 0xFFF00000, + .mc_video_protect_bom_adr_hi = 0x00000000, + .mc_video_protect_size_mb = 0x00000000, + + // AFI, BPMP, HC, ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1, SDMMC1A, SDMMC2A, SDMMC3A. Plus TSEC, NVENC. + .mc_video_protect_vpr_override = 0xE4FACB43, // Default: 0xE4BAC343. + // SDMMC4A, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR. Plus SE2, SE2B and TSECB, TSEC1, TSECB1. + .mc_video_protect_vpr_override1 = 0x0600FED3, // Default: 0x06001ED3. + + .mc_video_protect_gpu_override0 = 0x2A800000, // Default: 0x00000000. Forced to 1 by HOS Secmon. + .mc_video_protect_gpu_override1 = 0x00000002, // Default: 0x00000000. Forced to 0 by HOS Secmon. + + .mc_sec_carveout_bom = 0xFFF00000, + .mc_sec_carveout_adr_hi = 0x00000000, + .mc_sec_carveout_size_mb = 0x00000000, + + .mc_video_protect_write_access = 0x00000000, + .mc_sec_carveout_protect_write_access = 0x00000000, + + .mc_generalized_carveout1_bom = 0x00000000, + .mc_generalized_carveout1_bom_hi = 0x00000000, + .mc_generalized_carveout1_size_128kb = 0x00000008, + .mc_generalized_carveout1_access0 = 0x00000000, + .mc_generalized_carveout1_access1 = 0x00000000, + .mc_generalized_carveout1_access2 = 0x00300000, + .mc_generalized_carveout1_access3 = 0x03000000, + .mc_generalized_carveout1_access4 = 0x00000000, + .mc_generalized_carveout1_force_internal_access0 = 0x00000000, + .mc_generalized_carveout1_force_internal_access1 = 0x00000000, + .mc_generalized_carveout1_force_internal_access2 = 0x00000000, + .mc_generalized_carveout1_force_internal_access3 = 0x00000000, + .mc_generalized_carveout1_force_internal_access4 = 0x00000000, + .mc_generalized_carveout1_cfg0 = 0x04000C76, + + .mc_generalized_carveout2_bom = 0x00000000, + .mc_generalized_carveout2_bom_hi = 0x00000000, + .mc_generalized_carveout2_size_128kb = 0x00000002, + .mc_generalized_carveout2_access0 = 0x00000000, + .mc_generalized_carveout2_access1 = 0x00000000, + .mc_generalized_carveout2_access2 = 0x03000000, + .mc_generalized_carveout2_access3 = 0x00000000, + .mc_generalized_carveout2_access4 = 0x00000300, + .mc_generalized_carveout2_force_internal_access0 = 0x00000000, + .mc_generalized_carveout2_force_internal_access1 = 0x00000000, + .mc_generalized_carveout2_force_internal_access2 = 0x00000000, + .mc_generalized_carveout2_force_internal_access3 = 0x00000000, + .mc_generalized_carveout2_force_internal_access4 = 0x00000000, + .mc_generalized_carveout2_cfg0 = 0x0440167E, + + .mc_generalized_carveout3_bom = 0x00000000, + .mc_generalized_carveout3_bom_hi = 0x00000000, + .mc_generalized_carveout3_size_128kb = 0x00000000, + .mc_generalized_carveout3_access0 = 0x00000000, + .mc_generalized_carveout3_access1 = 0x00000000, + .mc_generalized_carveout3_access2 = 0x03000000, + .mc_generalized_carveout3_access3 = 0x00000000, + .mc_generalized_carveout3_access4 = 0x00000300, + .mc_generalized_carveout3_force_internal_access0 = 0x00000000, + .mc_generalized_carveout3_force_internal_access1 = 0x00000000, + .mc_generalized_carveout3_force_internal_access2 = 0x00000000, + .mc_generalized_carveout3_force_internal_access3 = 0x00000000, + .mc_generalized_carveout3_force_internal_access4 = 0x00000000, + .mc_generalized_carveout3_cfg0 = 0x04401E7E, + + .mc_generalized_carveout4_bom = 0x00000000, + .mc_generalized_carveout4_bom_hi = 0x00000000, + .mc_generalized_carveout4_size_128kb = 0x00000008, + .mc_generalized_carveout4_access0 = 0x00000000, + .mc_generalized_carveout4_access1 = 0x00000000, + .mc_generalized_carveout4_access2 = 0x00300000, + .mc_generalized_carveout4_access3 = 0x00000000, + .mc_generalized_carveout4_access4 = 0x000000C0, + .mc_generalized_carveout4_force_internal_access0 = 0x00000000, + .mc_generalized_carveout4_force_internal_access1 = 0x00000000, + .mc_generalized_carveout4_force_internal_access2 = 0x00000000, + .mc_generalized_carveout4_force_internal_access3 = 0x00000000, + .mc_generalized_carveout4_force_internal_access4 = 0x00000000, + .mc_generalized_carveout4_cfg0 = 0x04002446, + + .mc_generalized_carveout5_bom = 0x00000000, + .mc_generalized_carveout5_bom_hi = 0x00000000, + .mc_generalized_carveout5_size_128kb = 0x00000008, + .mc_generalized_carveout5_access0 = 0x00000000, + .mc_generalized_carveout5_access1 = 0x00000000, + .mc_generalized_carveout5_access2 = 0x00300000, + .mc_generalized_carveout5_access3 = 0x00000000, + .mc_generalized_carveout5_access4 = 0x00000000, + .mc_generalized_carveout5_force_internal_access0 = 0x00000000, + .mc_generalized_carveout5_force_internal_access1 = 0x00000000, + .mc_generalized_carveout5_force_internal_access2 = 0x00000000, + .mc_generalized_carveout5_force_internal_access3 = 0x00000000, + .mc_generalized_carveout5_force_internal_access4 = 0x00000000, + .mc_generalized_carveout5_cfg0 = 0x04002C46, + + /* Specifies enable for CA training */ + .emc_ca_training_enable = 0x00000000, + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + .swizzle_rank_byte_encode = 0x000000EC, + + /* Specifies enable and offset for patched boot rom write */ + .boot_rom_patch_control = 0x00000000, + /* Specifies data for patched boot rom write */ + .boot_rom_patch_data = 0x00000000, + + .mc_mts_carveout_bom = 0xFFF00000, + .mc_mts_carveout_adr_hi = 0x00000000, + .mc_mts_carveout_size_mb = 0x00000000, + .mc_mts_carveout_reg_ctrl = 0x00000000, + + /* Specifies the untranslated memory access control */ + .mc_untranslated_region_check = 0x00000000, + + /* Just a place holder for special usage when there is no BCT for certain registers */ + .bct_na = 0x00000000, +}; + +#define DRAM_CC_LPDDR4X_PMACRO_IB (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ)) + +#define DRAM_CC_LPDDR4X_PUPD_VPR (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \ + DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL)) + +#define DRAM_CC_LPDDR4X_DSR (DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL)) + +#define DRAM_CC_LPDDR4X_QUSE (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \ + DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL)) + +#define DRAM_CC_LPDDR4X_FAW (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB)) + +#define DRAM_CC_LPDDR4X_VPR (DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ + DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \ + DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \ + DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL)) + +#define DRAM_CC_LPDDR4X_8GB (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \ + DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL)) + +#define DCFG_OFFSET_OF(m) (OFFSET_OF(sdram_params_t210b01_t, m) / 4) +static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { + + // Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ Die-M for SDEV Iowa and Hoag. + { 0x35353535, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_vref_dq_0) }, + { 0x35353535, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_vref_dq_1) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_0) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_1) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_2) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_3) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_0) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_1) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_2) }, + { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_3) }, + + /*! Shared patched between DRAM Codes. */ + { 0x05500000, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(emc_auto_cal_config2) }, + { 0xC9AFBCBC, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(emc_auto_cal_vref_sel0) }, + + // Moved to default config. + // { 0x2A800000, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(mc_video_protect_gpu_override0) }, + // { 0x00000002, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(mc_video_protect_gpu_override1) }, + + { 0x88161414, DRAM_CC_LPDDR4X_DSR, DCFG_OFFSET_OF(emc_mrw14) }, + { 0x80000713, DRAM_CC_LPDDR4X_DSR, DCFG_OFFSET_OF(emc_dyn_self_ref_control) }, + + { 0x00000006, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_quse) }, + { 0x00000005, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_quse_width) }, + { 0x00000003, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_einput) }, + { 0x0000000C, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_einput_duration) }, + + { 0x00000008, DRAM_CC_LPDDR4X_FAW, DCFG_OFFSET_OF(emc_tfaw) }, + { 0x00000001, DRAM_CC_LPDDR4X_FAW, DCFG_OFFSET_OF(mc_emem_arb_timing_faw) }, + + // Moved to default config. + // { 0xE4FACB43, DRAM_CC_LPDDR4X_VPR, DCFG_OFFSET_OF(mc_video_protect_vpr_override) }, // + TSEC, NVENC. + // { 0x0600FED3, DRAM_CC_LPDDR4X_VPR, DCFG_OFFSET_OF(mc_video_protect_vpr_override1) }, // + TSECB, TSEC1, TSECB1. + + { 0x00000001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_adr_cfg) }, // 2 Ranks. + { 0x08010004, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw1) }, + { 0x08020000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw2) }, + { 0x080D0000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw3) }, + { 0x08033131, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw6) }, + { 0x080B0000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw8) }, + { 0x0C0E5D5D, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw9) }, + { 0x080C5D5D, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw10) }, + { 0x0C0D0808, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw12) }, + { 0x0C0D0000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw13) }, + { 0x08161414, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw14) }, + { 0x08010004, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw_extra) }, + { 0x00000000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_dev_select) }, // Both devices. + { 0x0051004F, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_zcal_mrw_cmd) }, + { 0x40000001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_zcal_init_dev1) }, + { 0x00000000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_pmacro_tx_pwrd4) }, + { 0x00001000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_pmacro_tx_pwrd5) }, + { 0x00000001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_adr_cfg) }, // 2 Ranks. + { 0x00002000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_cfg) }, // 8GB total density. Max 8GB. + { 0x00000002, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_arb_timing_r2r) }, + { 0x02020001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_arb_da_turns) }, +}; +#undef DCFG_OFFSET_OF diff --git a/bootloader/mem/sdram_param_t210.h b/bdk/mem/sdram_param_t210.h similarity index 99% rename from bootloader/mem/sdram_param_t210.h rename to bdk/mem/sdram_param_t210.h index d926fa4..ed3341b 100644 --- a/bootloader/mem/sdram_param_t210.h +++ b/bdk/mem/sdram_param_t210.h @@ -26,18 +26,18 @@ #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_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_DDR3L 2 #define MEMORY_TYPE_LPDDR4 3 /** * Defines the SDRAM parameter structure */ -typedef struct _sdram_params +typedef struct _sdram_params_t210_t { /* Specifies the type of memory device */ u32 memory_type; @@ -113,7 +113,6 @@ typedef struct _sdram_params /* 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; @@ -926,6 +925,6 @@ typedef struct _sdram_params u32 mc_mts_carveout_size_mb; /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ u32 mc_mts_carveout_reg_ctrl; -} sdram_params_t; +} sdram_params_t210_t; #endif diff --git a/bdk/mem/sdram_param_t210b01.h b/bdk/mem/sdram_param_t210b01.h new file mode 100644 index 0000000..f7b956c --- /dev/null +++ b/bdk/mem/sdram_param_t210b01.h @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2020 CTCaer + * + * 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 _SDRAM_PARAM_T210B01_H_ +#define _SDRAM_PARAM_T210B01_H_ + +typedef struct _sdram_params_t210b01_t +{ + /* 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; + /* Spare BCT param */ + u32 emc_bct_spare_secure0; + /* Spare BCT param */ + u32 emc_bct_spare_secure1; + /* Spare BCT param */ + u32 emc_bct_spare_secure2; + /* Spare BCT param */ + u32 emc_bct_spare_secure3; + /* Spare BCT param */ + u32 emc_bct_spare_secure4; + /* Spare BCT param */ + u32 emc_bct_spare_secure5; + /* Spare BCT param */ + u32 emc_bct_spare_secure6; + /* Spare BCT param */ + u32 emc_bct_spare_secure7; + /* Spare BCT param */ + u32 emc_bct_spare_secure8; + /* Spare BCT param */ + u32 emc_bct_spare_secure9; + /* Spare BCT param */ + u32 emc_bct_spare_secure10; + /* Spare BCT param */ + u32 emc_bct_spare_secure11; + /* Spare BCT param */ + u32 emc_bct_spare_secure12; + /* Spare BCT param */ + u32 emc_bct_spare_secure13; + /* Spare BCT param */ + u32 emc_bct_spare_secure14; + /* Spare BCT param */ + u32 emc_bct_spare_secure15; + /* Spare BCT param */ + u32 emc_bct_spare_secure16; + /* Spare BCT param */ + u32 emc_bct_spare_secure17; + /* Spare BCT param */ + u32 emc_bct_spare_secure18; + /* Spare BCT param */ + u32 emc_bct_spare_secure19; + /* Spare BCT param */ + u32 emc_bct_spare_secure20; + /* Spare BCT param */ + u32 emc_bct_spare_secure21; + /* Spare BCT param */ + u32 emc_bct_spare_secure22; + /* Spare BCT param */ + u32 emc_bct_spare_secure23; + + /* 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; + u32 emc_auto_cal_config9; + + /* 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; + + u32 emc_tppd; + u32 emc_trtm; + u32 emc_twtm; + u32 emc_tratm; + u32 emc_twatm; + u32 emc_tr2ref; + u32 emc_ccdmw; + + /* Specifies the value for EMC_RD_RCD */ + 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; + + u32 emc_pmacro_ddll_periodic_offset; + + /* + * 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_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_dsr_vttgen_ctrl0; + 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_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_perbit_fgcg_ctrl0; + u32 emc_pmacro_perbit_fgcg_ctrl1; + u32 emc_pmacro_perbit_fgcg_ctrl2; + u32 emc_pmacro_perbit_fgcg_ctrl3; + u32 emc_pmacro_perbit_fgcg_ctrl4; + u32 emc_pmacro_perbit_fgcg_ctrl5; + u32 emc_pmacro_perbit_rfu_ctrl0; + u32 emc_pmacro_perbit_rfu_ctrl1; + u32 emc_pmacro_perbit_rfu_ctrl2; + u32 emc_pmacro_perbit_rfu_ctrl3; + u32 emc_pmacro_perbit_rfu_ctrl4; + u32 emc_pmacro_perbit_rfu_ctrl5; + u32 emc_pmacro_perbit_rfu1_ctrl0; + u32 emc_pmacro_perbit_rfu1_ctrl1; + u32 emc_pmacro_perbit_rfu1_ctrl2; + u32 emc_pmacro_perbit_rfu1_ctrl3; + u32 emc_pmacro_perbit_rfu1_ctrl4; + u32 emc_pmacro_perbit_rfu1_ctrl5; + + u32 emc_pmacro_data_pi_ctrl; + u32 emc_pmacro_cmd_pi_ctrl; + + 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; + + /* Specifies the clients that are allowed to access untranslated memory */ + u32 mc_untranslated_region_check; + + /* Just a place holder for special usage when there is no BCT for certain registers */ + u32 bct_na; +} sdram_params_t210b01_t; + +#endif diff --git a/bdk/mem/smmu.c b/bdk/mem/smmu.c new file mode 100644 index 0000000..65b85aa --- /dev/null +++ b/bdk/mem/smmu.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 balika011 + * Copyright (c) 2018-2024 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include + +/*! SMMU register defines */ +#define SMMU_ASID(asid) (((asid) << 24u) | ((asid) << 16u) | ((asid) << 8u) | (asid)) +#define SMMU_ENABLE BIT(31) +#define SMMU_TLB_ACTIVE_LINES(l) ((l) << 0u) +#define SMMU_TLB_RR_ARBITRATION BIT(28) +#define SMMU_TLB_HIT_UNDER_MISS BIT(29) +#define SMMU_TLB_STATS_ENABLE BIT(31) +#define SMUU_PTC_INDEX_MAP(m) ((m) << 0u) +#define SMUU_PTC_LINE_MASK(m) ((m) << 8u) +#define SMUU_PTC_REQ_LIMIT(l) ((l) << 24u) +#define SMUU_PTC_CACHE_ENABLE BIT(29) +#define SMUU_PTC_STATS_ENABLE BIT(31) + +/*! Page table defines */ +#define SMMU_4MB_REGION 0 +#define SMMU_PAGE_TABLE 1 +#define SMMU_PDIR_COUNT 1024 +#define SMMU_PTBL_COUNT 1024 +#define SMMU_PAGE_SHIFT 12u +#define SMMU_PTN_SHIFT SMMU_PAGE_SHIFT +#define SMMU_PDN_SHIFT 22u +#define SMMU_ADDR_TO_PFN(addr) ((addr) >> SMMU_PAGE_SHIFT) +#define SMMU_ADDR_TO_PTN(addr) ((addr) >> SMMU_PTN_SHIFT) +#define SMMU_ADDR_TO_PDN(addr) ((addr) >> SMMU_PDN_SHIFT) +#define SMMU_PTN_TO_ADDR(ptn) ((ptn) << SMMU_PTN_SHIFT) +#define SMMU_PDN_TO_ADDR(pdn) ((pdn) << SMMU_PDN_SHIFT) +#define SMMU_PTB(page, attr) (((attr) << 29u) | ((page) >> SMMU_PAGE_SHIFT)) + +static void *smmu_heap = (void *)SMMU_HEAP_ADDR; + +// Enabling SMMU requires a TZ (EL3) secure write. MC(MC_SMMU_CONFIG) = 1; +static const u8 smmu_enable_payload[] = { + 0xC1, 0x00, 0x00, 0x18, // 0x00: LDR W1, =0x70019010 + 0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1 + 0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1] + 0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS + 0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH + 0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop + 0x10, 0x90, 0x01, 0x70, // 0x18: MC_SMMU_CONFIG +}; + +void *smmu_page_zalloc(u32 num) +{ + void *page = smmu_heap; + memset(page, 0, SZ_PAGE * num); + + smmu_heap += SZ_PAGE * num; + + return page; +} + +static pde_t *_smmu_pdir_alloc() +{ + pde_t *pdir = (pde_t *)smmu_page_zalloc(1); + + // Initialize pdes with no permissions. + for (u32 pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) + pdir[pdn].huge.page = pdn; + + return pdir; +} + +static void _smmu_flush_regs() +{ + (void)MC(MC_SMMU_PTB_DATA); +} + +void smmu_flush_all() +{ + + // Flush the entire page table cache. + MC(MC_SMMU_PTC_FLUSH) = 0; + _smmu_flush_regs(); + + // Flush the entire table. + MC(MC_SMMU_TLB_FLUSH) = 0; + _smmu_flush_regs(); +} + +void smmu_init() +{ + MC(MC_SMMU_PTB_ASID) = 0; + MC(MC_SMMU_PTB_DATA) = 0; + MC(MC_SMMU_TLB_CONFIG) = SMMU_TLB_HIT_UNDER_MISS | SMMU_TLB_RR_ARBITRATION | SMMU_TLB_ACTIVE_LINES(48); + MC(MC_SMMU_PTC_CONFIG) = SMUU_PTC_CACHE_ENABLE | SMUU_PTC_REQ_LIMIT(8) | SMUU_PTC_LINE_MASK(0xF) | SMUU_PTC_INDEX_MAP(0x3F); + MC(MC_SMMU_PTC_FLUSH) = 0; + MC(MC_SMMU_TLB_FLUSH) = 0; +} + +void smmu_enable() +{ + static bool enabled = false; + + if (enabled) + return; + + // Launch payload on CCPLEX in order to set SMMU enable bit. + ccplex_boot_cpu0((u32)smmu_enable_payload, false); + msleep(100); + ccplex_powergate_cpu0(); + + smmu_flush_all(); + + enabled = true; +} + +void smmu_reset_heap() +{ + smmu_heap = (void *)SMMU_HEAP_ADDR; +} + +void *smmu_init_domain(u32 dev_base, u32 asid) +{ + void *ptb = _smmu_pdir_alloc(); + + MC(MC_SMMU_PTB_ASID) = asid; + MC(MC_SMMU_PTB_DATA) = SMMU_PTB((u32)ptb, SMMU_ATTR_ALL); + _smmu_flush_regs(); + + // Use the same macro for both quad and single domains. Reserved bits are not set anyway. + MC(dev_base) = SMMU_ENABLE | SMMU_ASID(asid); + _smmu_flush_regs(); + + return ptb; +} + +void smmu_deinit_domain(u32 dev_base, u32 asid) +{ + MC(MC_SMMU_PTB_ASID) = asid; + MC(MC_SMMU_PTB_DATA) = 0; + MC(dev_base) = 0; + _smmu_flush_regs(); +} + +void smmu_domain_bypass(u32 dev_base, bool bypass) +{ + if (bypass) + { + smmu_flush_all(); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + MC(dev_base) &= ~SMMU_ENABLE; + } + else + { + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + MC(dev_base) |= SMMU_ENABLE; + smmu_flush_all(); + } + _smmu_flush_regs(); +} + +static pte_t *_smmu_get_pte(pde_t *pdir, u32 iova) +{ + u32 pdn = SMMU_ADDR_TO_PDN(iova); + pte_t *ptbl; + + // Get 4MB page table or initialize one. + if (pdir[pdn].tbl.attr) + ptbl = (pte_t *)(SMMU_PTN_TO_ADDR(pdir[pdn].tbl.table)); + else + { + // Allocate page table. + ptbl = (pte_t *)smmu_page_zalloc(1); + + // Get address. + u32 addr = SMMU_PDN_TO_ADDR(pdn); + + // Initialize page table with no permissions. + for (u32 pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SZ_PAGE) + ptbl[pn].page = SMMU_ADDR_TO_PFN(addr); + + // Set page table to the page directory. + pdir[pdn].tbl.table = SMMU_ADDR_TO_PTN((u32)ptbl); + pdir[pdn].tbl.next = SMMU_PAGE_TABLE; + pdir[pdn].tbl.attr = SMMU_ATTR_ALL; + + smmu_flush_all(); + } + + return &ptbl[SMMU_ADDR_TO_PTN(iova) % SMMU_PTBL_COUNT]; +} + +void smmu_map(void *ptb, u32 iova, u64 iopa, u32 pages, u32 attr) +{ + // Map pages to page table entries. VA/PA should be aligned to 4KB. + for (u32 i = 0; i < pages; i++) + { + pte_t *pte = _smmu_get_pte((pde_t *)ptb, iova); + + pte->page = SMMU_ADDR_TO_PFN(iopa); + pte->attr = attr; + + iova += SZ_PAGE; + iopa += SZ_PAGE; + } + + smmu_flush_all(); +} + +void smmu_map_huge(void *ptb, u32 iova, u64 iopa, u32 regions, u32 attr) +{ + pde_t *pdir = (pde_t *)ptb; + + // Map 4MB regions to page directory entries. VA/PA should be aligned to 4MB. + for (u32 i = 0; i < regions; i++) + { + u32 pdn = SMMU_ADDR_TO_PDN(iova); + pdir[pdn].huge.page = SMMU_ADDR_TO_PDN(iopa); + pdir[pdn].huge.next = SMMU_4MB_REGION; + pdir[pdn].huge.attr = attr; + + iova += SZ_4M; + iopa += SZ_4M; + } + + smmu_flush_all(); +} diff --git a/bdk/mem/smmu.h b/bdk/mem/smmu.h new file mode 100644 index 0000000..e45a672 --- /dev/null +++ b/bdk/mem/smmu.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer + * + * 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 + +#define MC_SMMU_AVPC_ASID 0x23C +#define MC_SMMU_TSEC_ASID 0x294 + +#define SMMU_NS BIT(0) +#define SMMU_WRITE BIT(1) +#define SMMU_READ BIT(2) +#define SMMU_ATTR_ALL (SMMU_READ | SMMU_WRITE | SMMU_NS) + +typedef struct _pde_t { + union { + union { + struct { + u32 table:22; + u32 rsvd:6; + u32 next:1; + u32 attr:3; + } tbl; + + struct { + u32 rsvd_:10; + u32 page:12; + u32 rsvd:6; + u32 next:1; + u32 attr:3; + } huge; + }; + + u32 pde; + }; +} pde_t; + +typedef struct _pte_t { + u32 page:22; + u32 rsvd:7; + u32 attr:3; +} pte_t; + +static_assert(sizeof(pde_t) == sizeof(u32), "pde_t size is wrong!"); +static_assert(sizeof(pte_t) == sizeof(u32), "pte_t size is wrong!"); + +void *smmu_page_zalloc(u32 num); +void smmu_flush_all(); +void smmu_init(); +void smmu_enable(); +void smmu_reset_heap(); +void *smmu_init_domain(u32 dev_base, u32 asid); +void smmu_deinit_domain(u32 dev_base, u32 asid); +void smmu_domain_bypass(u32 dev_base, bool bypass); +void smmu_map(void *ptb, u32 iova, u64 iopa, u32 pages, u32 attr); +void smmu_map_huge(void *ptb, u32 iova, u64 iopa, u32 regions, u32 attr); diff --git a/bdk/memory_map.h b/bdk/memory_map.h new file mode 100644 index 0000000..c687f2c --- /dev/null +++ b/bdk/memory_map.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2021 CTCaer + * + * 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 _MEMORY_MAP_H_ +#define _MEMORY_MAP_H_ + +/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ +/* --- IPL: 0x40008000 - 0x40028000 --- */ +#define LDR_LOAD_ADDR 0x40007000 + +#define IPL_LOAD_ADDR 0x40008000 +#define IPL_SZ_MAX SZ_128K + +#define XUSB_RING_ADDR 0x40020000 // XUSB EP context and TRB ring buffers. + +#define SECMON_MIN_START 0x4002B000 // Minimum reserved address for secmon. + +#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. + +/* start.S / exception_handlers.S */ +#define SYS_STACK_TOP_INIT 0x4003FF00 +#define FIQ_STACK_TOP 0x40040000 +#define IRQ_STACK_TOP 0x40040000 +#define IPL_RELOC_ADDR 0x4003FF00 +#define IPL_RELOC_SZ 0x10 +#define EXCP_STORAGE_ADDR 0x4003FFF0 +#define EXCP_STORAGE_SZ 0x10 + +/* --- DRAM START --- */ +#define DRAM_START 0x80000000 +#define HOS_RSVD SZ_16M // Do not write anything in this area. + +#define NYX_LOAD_ADDR 0x81000000 +#define NYX_SZ_MAX SZ_16M +/* --- Gap: 0x82000000 - 0x82FFFFFF --- */ + +/* Stack theoretical max: 33MB */ +#define IPL_STACK_TOP 0x83100000 +#define IPL_HEAP_START 0x84000000 +#define IPL_HEAP_SZ (SZ_512M - SZ_64M) + +#define SMMU_HEAP_ADDR 0xA0000000 +/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */ + +// Virtual disk / Chainloader buffers. +#define RAM_DISK_ADDR 0xA4000000 +#define RAM_DISK_SZ 0x41000000 // 1040MB. +#define RAM_DISK2_SZ 0x21000000 // 528MB. + +// NX BIS driver sector cache. +#define NX_BIS_CACHE_ADDR 0xC5000000 +#define NX_BIS_CACHE_SZ 0x10020000 // 256MB. +#define NX_BIS_LOOKUP_ADDR 0xD6000000 +#define NX_BIS_LOOKUP_SZ 0xF000000 // 240MB. + +// L4T Kernel Panic Storage (PSTORE). +#define PSTORE_ADDR 0xB0000000 +#define PSTORE_SZ SZ_2M + +//#define DRAM_LIB_ADDR 0xE0000000 +/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. + +// SDMMC DMA buffers 1 +#define SDMMC_UPPER_BUFFER 0xE5000000 +#define SDMMC_UP_BUF_SZ SZ_128M + +// Nyx buffers. +#define NYX_STORAGE_ADDR 0xED000000 +#define NYX_RES_ADDR 0xEE000000 +#define NYX_RES_SZ SZ_16M + +// SDMMC DMA buffers 2 +#define SDXC_BUF_ALIGNED 0xEF000000 +#define MIXD_BUF_ALIGNED 0xF0000000 +#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED +#define SDMMC_DMA_BUF_SZ SZ_16M // 4MB currently used. + +// Nyx LvGL buffers. +#define NYX_LV_VDB_ADR 0xF1000000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. +#define NYX_LV_MEM_ADR 0xF1400000 +#define NYX_LV_MEM_SZ 0x6600000 // 70MB. + +// Framebuffer addresses. +#define IPL_FB_ADDRESS 0xF5A00000 +#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. +#define LOG_FB_ADDRESS 0xF5E00000 +#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. +#define NYX_FB_ADDRESS 0xF6200000 +#define NYX_FB2_ADDRESS 0xF6600000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. + +/* OBSOLETE: Very old hwinit based payloads were setting a carveout here. */ +#define DRAM_MEM_HOLE_ADR 0xF6A00000 +#define DRAM_MEM_HOLE_SZ 0x8140000 +/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */ +#define DRAM_START2 0xFEB40000 + +// USB buffers. +#define USBD_ADDR 0xFEF00000 +#define USB_DESCRIPTOR_ADDR 0xFEF40000 +#define USB_EP_CONTROL_BUF_ADDR 0xFEF80000 +#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000 +#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000 +#define USB_EP_BULK_OUT_MAX_XFER SZ_8M + +// #define EXT_PAYLOAD_ADDR 0xC0000000 +// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +// #define COREBOOT_ADDR (0xD0000000 - rom_size) + +#endif diff --git a/common/common_module.h b/bdk/module.h similarity index 81% rename from common/common_module.h rename to bdk/module.h index 93a1541..acc048c 100644 --- a/common/common_module.h +++ b/bdk/module.h @@ -15,25 +15,32 @@ * along with this program. If not, see . */ -#pragma once +#ifndef _MODULE_H_ +#define _MODULE_H_ + #include -//TODO: Move it to BDK -#include "common_gfx.h" -#include "common_heap.h" +#include + +#define IANOS_EXT0 0x304E4149 // Module Callback typedef void (*cbMainModule_t)(const char *s); typedef void (*memcpy_t)(void *, void *, size_t); typedef void (*memset_t)(void *, int, size_t); +typedef int (*reg_voltage_set_t)(u32, u32); typedef struct _bdkParams_t { - gfx_con_t *gfxCon; - gfx_ctxt_t *gfxCtx; + void *gfxCon; + void *gfxCtx; heap_t *sharedHeap; memcpy_t memcpy; memset_t memset; + u32 extension_magic; + reg_voltage_set_t reg_voltage_set; } *bdkParams_t; // Module Entrypoint typedef void (*moduleEntrypoint_t)(void *, bdkParams_t); + +#endif diff --git a/bdk/power/bm92t36.c b/bdk/power/bm92t36.c new file mode 100644 index 0000000..371ed04 --- /dev/null +++ b/bdk/power/bm92t36.c @@ -0,0 +1,104 @@ +/* + * USB-PD driver for Nintendo Switch's TI BM92T36 + * + * Copyright (c) 2020-2023 CTCaer + * + * 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 "bm92t36.h" +#include +#include + +#define ALERT_STATUS_REG 0x2 +#define STATUS1_REG 0x3 +#define STATUS2_REG 0x4 +#define COMMAND_REG 0x5 +#define CONFIG1_REG 0x6 +#define DEV_CAPS_REG 0x7 +#define READ_PDOS_SRC_REG 0x8 +#define CONFIG2_REG 0x17 +#define DP_STATUS_REG 0x18 +#define DP_ALERT_EN_REG 0x19 +#define VENDOR_CONFIG_REG 0x1A +#define AUTO_NGT_FIXED_REG 0x20 +#define AUTO_NGT_BATT_REG 0x23 +#define SYS_CONFIG1_REG 0x26 +#define SYS_CONFIG2_REG 0x27 +#define CURRENT_PDO_REG 0x28 +#define CURRENT_RDO_REG 0x2B +#define ALERT_ENABLE_REG 0x2E +#define SYS_CONFIG3_REG 0x2F +#define SET_RDO_REG 0x30 +#define PDOS_SNK_REG 0x33 +#define PDOS_SRC_PROV_REG 0x3C +#define FW_TYPE_REG 0x4B +#define FW_REVISION_REG 0x4C +#define MAN_ID_REG 0x4D +#define DEV_ID_REG 0x4E +#define REV_ID_REG 0x4F +#define INCOMING_VDM_REG 0x50 +#define OUTGOING_VDM_REG 0x60 + +#define STATUS1_INSERT BIT(7) // Cable inserted. + +typedef struct _pd_object_t { + unsigned int amp:10; + unsigned int volt:10; + unsigned int info:10; + unsigned int type:2; +} __attribute__((packed)) pd_object_t; + +static int _bm92t36_read_reg(u8 *buf, u32 size, u32 reg) +{ + return i2c_recv_buf_big(buf, size, I2C_1, BM92T36_I2C_ADDR, reg); +} + +void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd) +{ + u8 buf[32]; + pd_object_t pdos[7]; + + if (inserted) + { + memset(buf, 0, sizeof(buf)); + _bm92t36_read_reg(buf, 2, STATUS1_REG); + *inserted = (buf[0] & STATUS1_INSERT) ? true : false; + } + + if (usb_pd) + { + memset(buf, 0, sizeof(buf)); + _bm92t36_read_reg(buf, 29, READ_PDOS_SRC_REG); + memcpy(pdos, &buf[1], 28); + + memset(usb_pd, 0, sizeof(usb_pd_objects_t)); + usb_pd->pdo_no = buf[0] / sizeof(pd_object_t); + + if (usb_pd->pdo_no > 7) + usb_pd->pdo_no = 7; + + for (u32 i = 0; i < usb_pd->pdo_no; i++) + { + usb_pd->pdos[i].amperage = pdos[i].amp * 10; + usb_pd->pdos[i].voltage = (pdos[i].volt * 50) / 1000; + } + + _bm92t36_read_reg(buf, 5, CURRENT_PDO_REG); + memcpy(pdos, &buf[1], 4); + usb_pd->selected_pdo.amperage = pdos[0].amp * 10; + usb_pd->selected_pdo.voltage = (pdos[0].volt * 50) / 1000; + } +} diff --git a/bootloader/mem/heap.h b/bdk/power/bm92t36.h similarity index 57% rename from bootloader/mem/heap.h rename to bdk/power/bm92t36.h index 4ec3fb0..e6740d8 100644 --- a/bootloader/mem/heap.h +++ b/bdk/power/bm92t36.h @@ -1,5 +1,7 @@ /* - * Copyright (c) 2018 naehrwert + * USB-PD driver for Nintendo Switch's TI BM92T36 + * + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,16 +16,26 @@ * along with this program. If not, see . */ -#ifndef _HEAP_H_ -#define _HEAP_H_ +#ifndef __BM92T36_H_ +#define __BM92T36_H_ -#include "../utils/types.h" -#include "../../common/common_heap.h" +#include -void heap_init(u32 base); -void *malloc(u32 size); -void *calloc(u32 num, u32 size); -void free(void *buf); -void heap_monitor(heap_monitor_t *mon, bool print_node_stats); +#define BM92T36_I2C_ADDR 0x18 + +typedef struct _usb_pd_object_t +{ + u32 amperage; + u32 voltage; +} usb_pd_object_t; + +typedef struct _usb_pd_objects_t +{ + u32 pdo_no; + usb_pd_object_t pdos[7]; + usb_pd_object_t selected_pdo; +} usb_pd_objects_t; + +void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd); #endif diff --git a/bdk/power/bq24193.c b/bdk/power/bq24193.c new file mode 100644 index 0000000..5194279 --- /dev/null +++ b/bdk/power/bq24193.c @@ -0,0 +1,179 @@ +/* + * Battery charger driver for Nintendo Switch's TI BQ24193 + * + * Copyright (c) 2018 CTCaer + * + * 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 "bq24193.h" +#include +#include + +static u8 bq24193_get_reg(u8 reg) +{ + return i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, reg); +} + +int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) +{ + u8 data; + + switch (prop) + { + case BQ24193_InputVoltageLimit: // Input voltage limit (mV). + data = bq24193_get_reg(BQ24193_InputSource); + data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; + *value = 0; + *value += ((data >> 0) & 1) ? 80 : 0; + *value += ((data >> 1) & 1) ? 160 : 0; + *value += ((data >> 2) & 1) ? 320 : 0; + *value += ((data >> 3) & 1) ? 640 : 0; + *value += 3880; + break; + case BQ24193_InputCurrentLimit: // Input current limit (mA). + data = bq24193_get_reg(BQ24193_InputSource); + data &= BQ24193_INCONFIG_INLIMIT_MASK; + switch (data) + { + case 0: + *value = 100; + break; + case 1: + *value = 150; + break; + case 2: + *value = 500; + break; + case 3: + *value = 900; + break; + case 4: + *value = 1200; + break; + case 5: + *value = 1500; + break; + case 6: + *value = 2000; + break; + case 7: + *value = 3000; + break; + } + break; + case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). + data = bq24193_get_reg(BQ24193_PORConfig); + *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; + *value *= 100; + *value += 3000; + break; + case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). + data = bq24193_get_reg(BQ24193_ChrgCurr); + data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2; + *value = 0; + *value += ((data >> 0) & 1) ? 64 : 0; + *value += ((data >> 1) & 1) ? 128 : 0; + *value += ((data >> 2) & 1) ? 256 : 0; + *value += ((data >> 3) & 1) ? 512 : 0; + *value += ((data >> 4) & 1) ? 1024 : 0; + *value += ((data >> 5) & 1) ? 2048 : 0; + *value += 512; + data = bq24193_get_reg(BQ24193_ChrgCurr); + data &= BQ24193_CHRGCURR_20PCT_MASK; + if (data) + *value = *value * 20 / 100; // Fast charge current limit is 20%. + break; + case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). + data = bq24193_get_reg(BQ24193_ChrgVolt); + data = (data & BQ24193_CHRGVOLT_VREG) >> 2; + *value = 0; + *value += ((data >> 0) & 1) ? 16 : 0; + *value += ((data >> 1) & 1) ? 32 : 0; + *value += ((data >> 2) & 1) ? 64 : 0; + *value += ((data >> 3) & 1) ? 128 : 0; + *value += ((data >> 4) & 1) ? 256 : 0; + *value += ((data >> 5) & 1) ? 512 : 0; + *value += 3504; + break; + case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). + data = bq24193_get_reg(BQ24193_ChrgVolt); + data &= BQ24193_IRTHERMAL_THERM_MASK; + if (data) + *value = 300; + else + *value = 100; + break; + case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). + data = bq24193_get_reg(BQ24193_IRCompThermal); + data &= BQ24193_IRTHERMAL_THERM_MASK; + switch (data) + { + case 0: + *value = 60; + break; + case 1: + *value = 80; + break; + case 2: + *value = 100; + break; + case 3: + *value = 120; + break; + } + break; + case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done + data = bq24193_get_reg(BQ24193_Status); + *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; + break; + case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. + data = bq24193_get_reg(BQ24193_FaultReg); + *value = data & BQ24193_FAULT_THERM_MASK; + break; + case BQ24193_DevID: // Dev ID. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = data & BQ24193_VENDORPART_DEV_MASK; + break; + case BQ24193_ProductNumber: // Product number. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; + break; + default: + return -1; + } + return 0; +} + +void bq24193_enable_charger() +{ + u8 reg = bq24193_get_reg(BQ24193_PORConfig); + + reg &= ~BQ24193_PORCONFIG_CHGCONFIG_MASK; + reg |= BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN; + + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg); +} + +void bq24193_fake_battery_removal() +{ + // Disable watchdog to keep BATFET disabled. + u8 value = bq24193_get_reg(BQ24193_ChrgTermTimer); + value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK; + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value); + + // Force BATFET to disabled state. This disconnects the battery from the system. + value = bq24193_get_reg(BQ24193_Misc); + value |= BQ24193_MISC_BATFET_DI_MASK; + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value); +} diff --git a/bootloader/power/bq24193.h b/bdk/power/bq24193.h similarity index 95% rename from bootloader/power/bq24193.h rename to bdk/power/bq24193.h index 34e9fbf..399e225 100644 --- a/bootloader/power/bq24193.h +++ b/bdk/power/bq24193.h @@ -28,8 +28,9 @@ // REG 1 masks. #define BQ24193_PORCONFIG_BOOST_MASK (1<<0) -#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1) +#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1) // 3000uV HOS default. #define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4) +#define BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN (1<<4) #define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6) #define BQ24193_PORCONFIG_RESET_MASK (1<<7) @@ -114,6 +115,7 @@ enum BQ24193_reg_prop { }; int bq24193_get_property(enum BQ24193_reg_prop prop, int *value); +void bq24193_enable_charger(); void bq24193_fake_battery_removal(); #endif /* __BQ24193_H_ */ diff --git a/bootloader/power/max17050.c b/bdk/power/max17050.c similarity index 70% rename from bootloader/power/max17050.c rename to bdk/power/max17050.c index 635a437..8c4f658 100644 --- a/bootloader/power/max17050.c +++ b/bdk/power/max17050.c @@ -23,28 +23,42 @@ */ #include "max17050.h" -#include "../soc/i2c.h" -#include "../utils/util.h" +#include +#include + +#define BASE_SNS_UOHM 5000 /* Status register bits */ -#define STATUS_POR_BIT (1 << 1) -#define STATUS_BST_BIT (1 << 3) -#define STATUS_VMN_BIT (1 << 8) -#define STATUS_TMN_BIT (1 << 9) -#define STATUS_SMN_BIT (1 << 10) -#define STATUS_BI_BIT (1 << 11) -#define STATUS_VMX_BIT (1 << 12) -#define STATUS_TMX_BIT (1 << 13) -#define STATUS_SMX_BIT (1 << 14) -#define STATUS_BR_BIT (1 << 15) +#define STATUS_POR_BIT BIT(1) +#define STATUS_BST_BIT BIT(3) +#define STATUS_VMN_BIT BIT(8) +#define STATUS_TMN_BIT BIT(9) +#define STATUS_SMN_BIT BIT(10) +#define STATUS_BI_BIT BIT(11) +#define STATUS_VMX_BIT BIT(12) +#define STATUS_TMX_BIT BIT(13) +#define STATUS_SMX_BIT BIT(14) +#define STATUS_BR_BIT BIT(15) #define VFSOC0_LOCK 0x0000 #define VFSOC0_UNLOCK 0x0080 #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ -#pragma GCC push_options -#pragma GCC optimize ("Os") +static u32 battery_voltage = 0; +u32 max17050_get_cached_batt_volt() +{ + return battery_voltage; +} + +static u16 max17050_get_reg(u8 reg) +{ + u16 data = 0; + + i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, reg); + + return data; +} int max17050_get_property(enum MAX17050_reg reg, int *value) { @@ -53,68 +67,66 @@ int max17050_get_property(enum MAX17050_reg reg, int *value) switch (reg) { case MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap). - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Age); + data = max17050_get_reg(MAX17050_Age); *value = data >> 8; /* Show MSB. 1% increments */ break; case MAX17050_Cycles: // Cycle count. - i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Cycles); + *value = max17050_get_reg(MAX17050_Cycles); break; case MAX17050_MinVolt: // Voltage max/min - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt); + data = max17050_get_reg(MAX17050_MinMaxVolt); *value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */ break; case MAX17050_MaxVolt: // Voltage max/min - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt); + data = max17050_get_reg(MAX17050_MinMaxVolt); *value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */ break; case MAX17050_V_empty: // Voltage min design. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_V_empty); + data = max17050_get_reg(MAX17050_V_empty); *value = (data >> 7) * 10; /* Units of LSB = 10mV */ break; case MAX17050_VCELL: // Voltage now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL); - *value = data * 625 / 8 / 1000; + data = max17050_get_reg(MAX17050_VCELL); + *value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */ + battery_voltage = *value; break; case MAX17050_AvgVCELL: // Voltage avg. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL); - *value = data * 625 / 8 / 1000; + data = max17050_get_reg(MAX17050_AvgVCELL); + *value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */ break; case MAX17050_OCVInternal: // Voltage ocv. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_OCVInternal); - *value = data * 625 / 8 / 1000; + data = max17050_get_reg(MAX17050_OCVInternal); + *value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */ break; case MAX17050_RepSOC: // Capacity %. - i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC); + *value = max17050_get_reg(MAX17050_RepSOC); break; case MAX17050_DesignCap: // Charge full design. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap); - data = data * 5 / 10; - *value = data; + data = max17050_get_reg(MAX17050_DesignCap); + *value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN; break; case MAX17050_FullCAP: // Charge full. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullCAP); - data = data * 5 / 10; - *value = data; + data = max17050_get_reg(MAX17050_FullCAP); + *value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN; break; case MAX17050_RepCap: // Charge now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepCap); - data = data * 5 / 10; - *value = data; + data = max17050_get_reg(MAX17050_RepCap); + *value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN; break; case MAX17050_TEMP: // Temp. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_TEMP); + data = max17050_get_reg(MAX17050_TEMP); *value = (s16)data; *value = *value * 10 / 256; break; case MAX17050_Current: // Current now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Current); + data = max17050_get_reg(MAX17050_Current); *value = (s16)data; - *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; + *value *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN); break; case MAX17050_AvgCurrent: // Current avg. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgCurrent); + data = max17050_get_reg(MAX17050_AvgCurrent); *value = (s16)data; - *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; + *value *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN); break; default: return -1; @@ -131,7 +143,7 @@ static int _max17050_write_verify_reg(u8 reg, u16 value) do { ret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2); - i2c_recv_buf_small((u8 *)&read_value, 2, I2C_1, MAXIM17050_I2C_ADDR, reg); + read_value = max17050_get_reg(reg); if (read_value != value) { ret = -1; @@ -268,4 +280,25 @@ int max17050_fix_configuration() return 0; } -#pragma GCC pop_options \ No newline at end of file +void max17050_dump_regs(void *buf) +{ + u16 *buff = (u16 *)buf; + + // Unlock model table. + u16 unlock = 0x59; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2); + unlock = 0xC4; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2); + + // Dump all battery fuel gauge registers. + for (u32 i = 0; i < 0x100; i++) + { + buff[i] = max17050_get_reg(i); + msleep(1); + } + + // Lock model table. + unlock = 0; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2); + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2); +} diff --git a/nyx/nyx_gui/power/max17050.h b/bdk/power/max17050.h similarity index 88% rename from nyx/nyx_gui/power/max17050.h rename to bdk/power/max17050.h index 6104e5c..438f55a 100644 --- a/nyx/nyx_gui/power/max17050.h +++ b/bdk/power/max17050.h @@ -1,10 +1,9 @@ /* * Fuel gauge driver for Nintendo Switch's Maxim 17050 - * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. * * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * 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 @@ -24,8 +23,13 @@ #ifndef __MAX17050_H_ #define __MAX17050_H_ -#define MAX17050_STATUS_BattAbsent (1 << 3) -#define MAX17050_DEFAULT_SNS_RESISTOR 10000 +#include + +/* Board default values */ +#define MAX17050_BOARD_CGAIN 2 /* Actual: 1.99993 */ +#define MAX17050_BOARD_SNS_RESISTOR_UOHM 5000 /* 0.005 Ohm */ + +#define MAX17050_STATUS_BattAbsent BIT(3) /* Consider RepCap which is less then 10 units below FullCAP full */ #define MAX17050_FULL_THRESHOLD 10 @@ -126,7 +130,9 @@ enum MAX17050_reg { MAX17050_VFSOC = 0xFF, }; -int max17050_get_property(enum MAX17050_reg reg, int *value); -int max17050_fix_configuration(); +int max17050_get_property(enum MAX17050_reg reg, int *value); +int max17050_fix_configuration(); +void max17050_dump_regs(void *buf); +u32 max17050_get_cached_batt_volt(); #endif /* __MAX17050_H_ */ diff --git a/bootloader/power/max77620.h b/bdk/power/max77620.h similarity index 56% rename from bootloader/power/max77620.h rename to bdk/power/max77620.h index 26ea855..3d41459 100644 --- a/bootloader/power/max77620.h +++ b/bdk/power/max77620.h @@ -1,8 +1,7 @@ /* * Defining registers address and its bit definitions of MAX77620 and MAX20024 * - * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,13 +15,7 @@ /* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ #define MAX77620_REG_CNFGGLBL1 0x00 -#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) -#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) -#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) -#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBRSTEN BIT(0) #define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E #define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) #define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) @@ -32,30 +25,45 @@ #define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) -#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_MPPLD BIT(6) +#define MAX77620_CNFGGLBL1_LBDAC_EN BIT(7) #define MAX77620_REG_CNFGGLBL2 0x01 -#define MAX77620_REG_CNFGGLBL3 0x02 -#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_WDTEN BIT(2) +#define MAX77620_WDTSLPC BIT(3) +#define MAX77620_WDTOFFC BIT(4) +#define MAX77620_GLBL_LPM BIT(5) +#define MAX77620_I2CTWD_MASK 0xC0 +#define MAX77620_I2CTWD_DISABLED 0x00 +#define MAX77620_I2CTWD_1_33ms 0x40 +#define MAX77620_I2CTWD_35_7ms 0x80 +#define MAX77620_I2CTWD_41_7ms 0xC0 + +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_WDTC_MASK 0x3 #define MAX77620_REG_CNFG1_32K 0x03 -#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) +#define MAX77620_CNFG1_PWR_MD_32K_MASK 0x3 +#define MAX77620_CNFG1_32K_OUT0_EN BIT(2) +#define MAX77620_CNFG1_32KLOAD_MASK 0x30 +#define MAX77620_CNFG1_32K_OK BIT(7) #define MAX77620_REG_CNFGBBC 0x04 -#define MAX77620_CNFGBBC_ENABLE (1 << 0) +#define MAX77620_CNFGBBC_ENABLE BIT(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_LOW_CURRENT_DISABLE BIT(5) #define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 #define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 #define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) @@ -64,37 +72,63 @@ #define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_REG_IRQTOP 0x05 -#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_REG_IRQTOPM 0x0D +#define MAX77620_IRQ_TOP_ONOFF_MASK BIT(1) +#define MAX77620_IRQ_TOP_32K_MASK BIT(2) +#define MAX77620_IRQ_TOP_RTC_MASK BIT(3) +#define MAX77620_IRQ_TOP_GPIO_MASK BIT(4) +#define MAX77620_IRQ_TOP_LDO_MASK BIT(5) +#define MAX77620_IRQ_TOP_SD_MASK BIT(6) +#define MAX77620_IRQ_TOP_GLBL_MASK BIT(7) #define MAX77620_REG_INTLBT 0x06 -#define MAX77620_REG_IRQTOPM 0x0D -#define MAX77620_IRQ_LBM_MASK (1 << 3) -#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) -#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_IRQ_GLBLM_MASK BIT(0) +#define MAX77620_IRQ_TJALRM2_MASK BIT(1) +#define MAX77620_IRQ_TJALRM1_MASK BIT(2) +#define MAX77620_IRQ_LBM_MASK BIT(3) #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_INTENLBT 0x0E -#define MAX77620_GLBLM_MASK (1 << 0) - #define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_IRQSD_PFI_SD3 BIT(4) +#define MAX77620_IRQSD_PFI_SD2 BIT(5) +#define MAX77620_IRQSD_PFI_SD1 BIT(6) +#define MAX77620_IRQSD_PFI_SD0 BIT(7) + +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 // LDO number that irq occurred. #define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_LVL2_L8 0x09 // LDO number that irq occurred. Only bit0: LDO8 is valid. #define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A // Edge detection interrupt. + +#define MAX77620_REG_ONOFFIRQ 0x0B #define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_ONOFFIRQ_MRWRN BIT(0) +#define MAX77620_ONOFFIRQ_EN0_1SEC BIT(1) +#define MAX77620_ONOFFIRQ_EN0_F BIT(2) +#define MAX77620_ONOFFIRQ_EN0_R BIT(3) +#define MAX77620_ONOFFIRQ_LID_F BIT(4) +#define MAX77620_ONOFFIRQ_LID_R BIT(5) +#define MAX77620_ONOFFIRQ_ACOK_F BIT(6) +#define MAX77620_ONOFFIRQ_ACOK_R BIT(7) + +#define MAX77620_REG_NVERC 0x0C // Shutdown reason (non-volatile). +#define MAX77620_NVERC_SHDN BIT(0) +#define MAX77620_NVERC_WTCHDG BIT(1) +#define MAX77620_NVERC_HDRST BIT(2) +#define MAX77620_NVERC_TOVLD BIT(3) +#define MAX77620_NVERC_MBLSD BIT(4) +#define MAX77620_NVERC_MBO BIT(5) +#define MAX77620_NVERC_MBU BIT(6) +#define MAX77620_NVERC_RSTIN BIT(7) + #define MAX77620_REG_STATLBT 0x13 #define MAX77620_REG_STATSD 0x14 + #define MAX77620_REG_ONOFFSTAT 0x15 +#define MAX77620_ONOFFSTAT_LID BIT(0) +#define MAX77620_ONOFFSTAT_ACOK BIT(1) +#define MAX77620_ONOFFSTAT_EN0 BIT(2) /* SD and LDO Registers */ #define MAX77620_REG_SD0 0x16 @@ -102,18 +136,42 @@ #define MAX77620_REG_SD2 0x18 #define MAX77620_REG_SD3 0x19 #define MAX77620_REG_SD4 0x1A -#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_DVSSD0 0x1B #define MAX77620_REG_DVSSD1 0x1C +#define MAX77620_SDX_VOLT_MASK 0xFF +#define MAX77620_SD0_VOLT_MASK 0x7F // Max is 0x40. +#define MAX77620_SD1_VOLT_MASK 0x7F // Max is 0x4C. +#define MAX77620_LDO_VOLT_MASK 0x3F + #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_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 BIT(3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE BIT(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 BIT(2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2) +#define MAX77620_SD_CFG1_MPOK_MASK BIT(1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0) + #define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_SD_CNF2_RSVD BIT(0) +#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2) + #define MAX77620_REG_LDO0_CFG 0x23 #define MAX77620_REG_LDO0_CFG2 0x24 #define MAX77620_REG_LDO1_CFG 0x25 @@ -132,25 +190,35 @@ #define MAX77620_REG_LDO7_CFG2 0x32 #define MAX77620_REG_LDO8_CFG 0x33 #define MAX77620_REG_LDO8_CFG2 0x34 -#define MAX77620_LDO_POWER_MODE_MASK 0xC0 +/*! LDO CFG */ #define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX77620_LDO_POWER_MODE_MASK (3 << MAX77620_LDO_POWER_MODE_SHIFT) #define MAX77620_POWER_MODE_NORMAL 3 #define MAX77620_POWER_MODE_LPM 2 #define MAX77620_POWER_MODE_GLPM 1 #define MAX77620_POWER_MODE_DISABLE 0 -#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) +/*! LDO CFG2 */ +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (0 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW (1 << 0) #define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) #define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) #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_LDO_CFG2_MPOK_MASK BIT(2) +#define MAX77620_LDO_CFG2_POK_MASK BIT(3) +#define MAX77620_LDO_CFG2_COMP_SHIFT 4 +#define MAX77620_LDO_CFG2_COMP_MASK (3 << MAX77620_LDO_COMP_SHIFT) +#define MAX77620_LDO_CFG2_COMP_SLOW 3 +#define MAX77620_LDO_CFG2_COMP_MID_SLOW 2 +#define MAX77620_LDO_CFG2_COMP_MID_FAST 1 +#define MAX77620_LDO_CFG2_COMP_FAST 0 +#define MAX77620_LDO_CFG2_ALPM_EN_MASK BIT(6) +#define MAX77620_LDO_CFG2_OVCLMP_MASK BIT(7) #define MAX77620_REG_LDO_CFG3 0x35 -#define MAX77620_TRACK4_MASK (1 << 5) +#define MAX77620_LDO_BIAS_EN BIT(0) #define MAX77620_TRACK4_SHIFT 5 - -#define MAX77620_LDO_SLEW_RATE_MASK 0x1 +#define MAX77620_TRACK4_MASK (1 << MAX77620_TRACK4_SHIFT) #define MAX77620_REG_GPIO0 0x36 #define MAX77620_REG_GPIO1 0x37 @@ -160,9 +228,6 @@ #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_CNFG_GPIO_DRV_MASK (1 << 0) #define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) #define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) @@ -181,26 +246,44 @@ #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_GPIO_OUTPUT_DISABLE 0 +#define MAX77620_GPIO_OUTPUT_ENABLE 1 + +#define MAX77620_REG_PUE_GPIO 0x3E // Gpio Pullup resistor enable. +#define MAX77620_REG_PDE_GPIO 0x3F // Gpio Pulldown resistor enable. + +#define MAX77620_REG_AME_GPIO 0x40 // Gpio pinmuxing. Clear bits are Standard GPIO. #define MAX77620_REG_ONOFFCNFG1 0x41 -#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_ONOFFCNFG1_PWR_OFF BIT(1) +#define MAX77620_ONOFFCNFG1_SLPEN BIT(2) +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_RSVD BIT(6) +#define MAX77620_ONOFFCNFG1_SFT_RST BIT(7) #define MAX77620_REG_ONOFFCNFG2 0x42 -#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_ONOFFCNFG2_WK_EN0 BIT(0) +#define MAX77620_ONOFFCNFG2_WK_ALARM2 BIT(1) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 BIT(2) +#define MAX77620_ONOFFCNFG2_WK_MBATT BIT(3) // MBATT event generates a wakeup signal. use it in android/l4t? +#define MAX77620_ONOFFCNFG2_WK_ACOK BIT(4) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK BIT(5) +#define MAX77620_ONOFFCNFG2_WD_RST_WK BIT(6) +#define MAX77620_ONOFFCNFG2_SFT_RST_WK BIT(7) /* FPS Registers */ -#define MAX77620_REG_FPS_CFG0 0x43 -#define MAX77620_REG_FPS_CFG1 0x44 -#define MAX77620_REG_FPS_CFG2 0x45 +#define MAX77620_REG_FPS_CFG0 0x43 // FPS0. +#define MAX77620_REG_FPS_CFG1 0x44 // FPS1. +#define MAX77620_REG_FPS_CFG2 0x45 // FPS2. +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 + #define MAX77620_REG_FPS_LDO0 0x46 #define MAX77620_REG_FPS_LDO1 0x47 #define MAX77620_REG_FPS_LDO2 0x48 @@ -215,86 +298,48 @@ #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 - -/* Minimum and maximum FPS period time (in microseconds) are - * different for MAX77620 and Max20024. - */ -#define MAX77620_FPS_COUNT 3 - -#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_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 - #define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_SRC_MASK 0xC0 + +#define MAX77620_FPS_COUNT 3 +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX77620_FPS_PERIOD_MAX_US 2560 + #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) +#define MAX77620_REG_CID4 0x5C // OTP version. +#define MAX77620_REG_CID5 0x5D // ES version. +#define MAX77620_CID_DIDO_MASK 0xF +#define MAX77620_CID_DIDO_SHIFT 0 +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 /* 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) +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 -#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_IRQ_LVL2_GPIO_EDGE0 BIT(0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 BIT(1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 BIT(2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 BIT(3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 BIT(4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 BIT(5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 BIT(6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 BIT(7) /* Interrupts */ enum { @@ -332,9 +377,4 @@ enum max77620_fps_src { MAX77620_FPS_SRC_DEF, }; -enum max77620_chip_id { - MAX77620, - MAX20024, -}; - #endif /* _MFD_MAX77620_H_ */ diff --git a/bdk/power/max7762x.c b/bdk/power/max7762x.c new file mode 100644 index 0000000..f0aefb5 --- /dev/null +++ b/bdk/power/max7762x.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2020 CTCaer + * + * 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 +#include +#include +#include +#include +#include + +#define REGULATOR_SD 0 +#define REGULATOR_LDO 1 +#define REGULATOR_BC0 2 +#define REGULATOR_BC1 3 + +typedef struct _max77620_fps_t +{ + u8 fps_addr; + u8 fps_src; + u8 pd_period; + u8 pu_period; +} max77620_fps_t; + +typedef struct _max77621_ctrl_t +{ + u8 ctrl1_por; + u8 ctrl1_hos; + u8 ctrl2_por; + u8 ctrl2_hos; +} max77621_ctrl_t; + +typedef struct _max77812_ctrl_t +{ + u8 mask; + u8 shift; + u8 rsvd0; + u8 rsvd1; +} max77812_en_t; + +typedef struct _max77620_regulator_t +{ + const char *name; + + u32 uv_step; + u32 uv_min; + u32 uv_default; + u32 uv_max; + + u8 type; + u8 volt_addr; + u8 cfg_addr; + u8 volt_mask; + + union { + max77620_fps_t fps; + max77621_ctrl_t ctrl; + max77812_en_t enable; + }; +} max77620_regulator_t; + +static const max77620_regulator_t _pmic_regulators[] = { + { "sd0", 12500, 600000, 625000, 1400000, REGULATOR_SD, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, {{ MAX77620_REG_FPS_SD0, 1, 7, 1 }} }, + { "sd1", 12500, 600000, 1125000, 1237500, REGULATOR_SD, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, {{ MAX77620_REG_FPS_SD1, 0, 1, 5 }} }, + { "sd2", 12500, 600000, 1325000, 1350000, REGULATOR_SD, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD2, 1, 5, 2 }} }, + { "sd3", 12500, 600000, 1800000, 1800000, REGULATOR_SD, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD3, 0, 3, 3 }} }, + { "ldo0", 25000, 800000, 1200000, 1200000, REGULATOR_LDO, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO0, 3, 7, 0 }} }, + { "ldo1", 25000, 800000, 1050000, 1050000, REGULATOR_LDO, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO1, 3, 7, 0 }} }, + { "ldo2", 50000, 800000, 1800000, 3300000, REGULATOR_LDO, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO2, 3, 7, 0 }} }, + { "ldo3", 50000, 800000, 3100000, 3100000, REGULATOR_LDO, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO3, 3, 7, 0 }} }, + { "ldo4", 12500, 800000, 850000, 1000000, REGULATOR_LDO, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO4, 0, 7, 1 }} }, + { "ldo5", 50000, 800000, 1800000, 1800000, REGULATOR_LDO, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO5, 3, 7, 0 }} }, + { "ldo6", 50000, 800000, 2900000, 2900000, REGULATOR_LDO, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO6, 3, 7, 0 }} }, + { "ldo7", 50000, 800000, 1050000, 1050000, REGULATOR_LDO, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO7, 1, 4, 3 }} }, + { "ldo8", 50000, 800000, 1050000, 2800000, REGULATOR_LDO, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO8, 3, 7, 0 }} }, + + { "max77621_CPU", 6250, 606250, 1000000, 1400000, REGULATOR_BC0, MAX77621_REG_VOUT, MAX77621_REG_VOUT_DVS, MAX77621_DVC_DVS_VOLT_MASK, {{ MAX77621_CPU_CTRL1_POR_DEFAULT, MAX77621_CPU_CTRL1_HOS_DEFAULT, MAX77621_CPU_CTRL2_POR_DEFAULT, MAX77621_CPU_CTRL2_HOS_DEFAULT }} }, + { "max77621_GPU", 6250, 606250, 1200000, 1400000, REGULATOR_BC0, MAX77621_REG_VOUT, MAX77621_REG_VOUT_DVS, MAX77621_DVC_DVS_VOLT_MASK, {{ MAX77621_CPU_CTRL1_POR_DEFAULT, MAX77621_CPU_CTRL1_HOS_DEFAULT, MAX77621_CPU_CTRL2_POR_DEFAULT, MAX77621_CPU_CTRL2_HOS_DEFAULT }} }, + { "max77812_CPU", 5000, 250000, 600000, 1525000, REGULATOR_BC1, MAX77812_REG_M4_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M4_MASK, MAX77812_EN_CTRL_EN_M4_SHIFT, 0, 0 }} }, + { "max77812_RAM", 5000, 250000, 600000, 650000, REGULATOR_BC1, MAX77812_REG_M3_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M3_MASK, MAX77812_EN_CTRL_EN_M3_SHIFT, 0, 0 }} } // Only on PHASE211 configuration. + //{ "max77812_GPU", 5000, 250000, 600000, 1525000, REGULATOR_BC1, MAX77812_REG_M1_VOUT, MAX77812_REG_EN_CTRL, MAX77812_BUCK_VOLT_MASK, {{ MAX77812_EN_CTRL_EN_M1_MASK, MAX77812_EN_CTRL_EN_M1_SHIFT, 0, 0 }} }, +}; + +static u8 _max77812_get_address() +{ + static u8 max77812_i2c_addr = 0; + + if (max77812_i2c_addr) + return max77812_i2c_addr; + + max77812_i2c_addr = + !(FUSE(FUSE_RESERVED_ODM28_B01) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR; + + return max77812_i2c_addr; +} + +static u8 _max7762x_get_i2c_address(u32 id) +{ + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + // Choose the correct i2c address. + switch (reg->type) + { + case REGULATOR_SD: + case REGULATOR_LDO: + return MAX77620_I2C_ADDR; + case REGULATOR_BC0: + return (id == REGULATOR_CPU0 ? MAX77621_CPU_I2C_ADDR : MAX77621_GPU_I2C_ADDR); + case REGULATOR_BC1: + { + u8 reg_addr = _max77812_get_address(); + if (id == REGULATOR_RAM0 && reg_addr == MAX77812_PHASE31_CPU_I2C_ADDR) + reg_addr = 0; + return reg_addr; + } + default: + return 0; + } +} + +static void _max7762x_set_reg(u8 addr, u8 reg, u8 val) +{ + u32 retries = 100; + while (retries) + { + if (i2c_send_byte(I2C_5, addr, reg, val)) + break; + + usleep(50); + retries--; + } +} + +int max77620_regulator_get_status(u32 id) +{ + if (id > REGULATOR_LDO8) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + // SD power OK status. + if (reg->type == REGULATOR_SD) + { + u8 mask = 1u << (7 - id); + return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & mask) ? 0 : 1; + } + + // LDO power OK status. + return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & MAX77620_LDO_CFG2_POK_MASK) ? 1 : 0; +} + +int max77620_regulator_config_fps(u32 id) +{ + if (id > REGULATOR_LDO8) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + // Set FPS configuration. + _max7762x_set_reg(MAX77620_I2C_ADDR, + reg->fps.fps_addr, + (reg->fps.fps_src << MAX77620_FPS_SRC_SHIFT) | + (reg->fps.pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | + (reg->fps.pd_period << MAX77620_FPS_PD_PERIOD_SHIFT)); + + return 1; +} + +int max7762x_regulator_set_voltage(u32 id, u32 uv) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (uv < reg->uv_min || uv > reg->uv_max) + return 0; + + u8 addr = _max7762x_get_i2c_address(id); + if (!addr) + return 0; + + // Calculate voltage multiplier. + u32 mult = (uv + reg->uv_step - 1 - reg->uv_min) / reg->uv_step; + u8 val = i2c_recv_byte(I2C_5, addr, reg->volt_addr); + val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); + + // Set voltage. + _max7762x_set_reg(addr, reg->volt_addr, val); + + // If max77621 set DVS voltage also. + if (reg->type == REGULATOR_BC0) + _max7762x_set_reg(addr, reg->cfg_addr, MAX77621_VOUT_ENABLE_MASK | val); + + // Wait for ramp up/down delay. + usleep(1000); + + return 1; +} + +int max7762x_regulator_enable(u32 id, bool enable) +{ + u8 reg_addr; + u8 enable_val; + u8 enable_mask; + u8 enable_shift; + + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + // Choose the correct i2c and register addresses and mask/shift for each type. + switch (reg->type) + { + case REGULATOR_SD: + reg_addr = reg->cfg_addr; + enable_val = MAX77620_POWER_MODE_NORMAL; + enable_mask = MAX77620_SD_POWER_MODE_MASK; + enable_shift = MAX77620_SD_POWER_MODE_SHIFT; + break; + case REGULATOR_LDO: + reg_addr = reg->volt_addr; + enable_val = MAX77620_POWER_MODE_NORMAL; + enable_mask = MAX77620_LDO_POWER_MODE_MASK; + enable_shift = MAX77620_LDO_POWER_MODE_SHIFT; + break; + case REGULATOR_BC0: + reg_addr = reg->volt_addr; + enable_val = MAX77621_VOUT_ENABLE; + enable_mask = MAX77621_DVC_DVS_ENABLE_MASK; + enable_shift = MAX77621_DVC_DVS_ENABLE_SHIFT; + break; + case REGULATOR_BC1: + reg_addr = reg->cfg_addr; + enable_val = MAX77812_EN_CTRL_ENABLE; + enable_mask = reg->enable.mask; + enable_shift = reg->enable.shift; + break; + default: + return 0; + } + + u8 addr = _max7762x_get_i2c_address(id); + if (!addr) + return 0; + + // Read and enable/disable. + u8 val = i2c_recv_byte(I2C_5, addr, reg_addr); + val &= ~enable_mask; + + if (enable) + val |= (enable_val << enable_shift); + + // Set enable. + _max7762x_set_reg(addr, reg_addr, val); + + // Wait for enable/disable ramp delay. + usleep(1000); + + return 1; +} + +void max77620_config_gpio(u32 gpio_id, bool enable) +{ + if (gpio_id > 7) + return; + + // Configure as standard GPIO. + u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, val & ~BIT(gpio_id)); + + // Set GPIO configuration. + if (enable) + val = MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DIR_OUTPUT | MAX77620_CNFG_GPIO_DRV_PUSHPULL; + else + val = MAX77620_CNFG_GPIO_DIR_INPUT | MAX77620_CNFG_GPIO_DRV_OPENDRAIN; + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO0 + gpio_id, val); +} + +void max77621_config_default(u32 id, bool por) +{ + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (reg->type != REGULATOR_BC0) + return; + + u8 addr = _max7762x_get_i2c_address(id); + if (!addr) + return; + + if (por) + { + // Set voltage and disable power before changing the inductor. + max7762x_regulator_set_voltage(id, 1000000); + max7762x_regulator_enable(id, false); + + // Configure to default. + i2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL1, reg->ctrl.ctrl1_por); + i2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL2, reg->ctrl.ctrl2_por); + } + else + { + i2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL1, reg->ctrl.ctrl1_hos); + i2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL2, reg->ctrl.ctrl2_hos); + } +} + +void max77620_config_default() +{ + // Check if Erista OTP. + if (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4) != 0x35) + return; + + // Set default voltages and enable regulators. + for (u32 i = REGULATOR_SD1; i <= REGULATOR_LDO8; i++) + { + max77620_regulator_config_fps(i); + max7762x_regulator_set_voltage(i, _pmic_regulators[i].uv_default); + if (_pmic_regulators[i].fps.fps_src != MAX77620_FPS_SRC_NONE) + max7762x_regulator_enable(i, true); + } + + // Enable SD0 output voltage sense and disable for SD1. Additionally disable the reserved bit. + _max7762x_set_reg(MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0); +} + +// Stock HOS: disabled. +void max77620_low_battery_monitor_config(bool enable) +{ + _max7762x_set_reg(MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1, + MAX77620_CNFGGLBL1_LBDAC_EN | + (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | + MAX77620_CNFGGLBL1_LBHYST_200 | + MAX77620_CNFGGLBL1_LBDAC_2800); +} diff --git a/bdk/power/max7762x.h b/bdk/power/max7762x.h new file mode 100644 index 0000000..342f40b --- /dev/null +++ b/bdk/power/max7762x.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2020 CTCaer + * + * 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 + +/* + * SDx actual min is 625 mV. Multipliers 0/1 reserved. + * SD0 max is 1400 mV + * SD1 max is 1550 mV + * SD2 max is 3787.5 mV + * SD3 max is 3787.5 mV + */ + +/* +* Switch Power domains (max77620): +* Name | Usage | uV step | uV min | uV default | uV max | Init +*-------+---------------+---------+--------+------------+---------+------------------ +* sd0 | SoC | 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, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) +* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | +* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) +* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | 0.85V (AO, pcv) +* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V (pcv) +* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) +* ldo8 | XUSB, DP, MCU | 50000 | 800000 | 1050000 | 2800000 | 1.05V/2.8V (pcv) +*/ + + +// GPIOs T210: 3: 3.3V, 5: CPU PMIC, 6: GPU PMIC, 7: DSI/VI 1.2V powered by ldo0. + +/* + * OTP: T210 - T210B01: + * SD0: 1.0V 1.05V - SoC. EN Based on FPSSRC. + * SD1: 1.15V 1.1V - DRAM for T210. EN Based on FPSSRC. + * SD2: 1.35V 1.35V + * SD3: 1.8V 1.8V + * All powered off? + * LDO0: -- -- - Display + * LDO1: 1.05V 1.05V + * LDO2: -- -- - SD + * LDO3: 3.1V 3.1V - GC ASIC + * LDO4: 1.0V 0.8V - Needed for RTC domain on T210. + * LDO5: 3.1V 3.1V + * LDO6: 2.8V 2.9V - Touch. + * LDO7: 1.05V 1.0V + * LDO8: 1.05V 1.0V + */ + +/* +* 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_CPU0 13 // T210 CPU. +#define REGULATOR_GPU0 14 // T210 CPU. +#define REGULATOR_CPU1 15 // T210B01 CPU. +#define REGULATOR_RAM0 16 // T210B01 RAM for PHASE211. +//#define REGULATOR_GPU1 17 // T210B01 CPU. +#define REGULATOR_MAX REGULATOR_RAM0 + +#define MAX77621_CPU_I2C_ADDR 0x1B +#define MAX77621_GPU_I2C_ADDR 0x1C + +#define MAX77621_REG_VOUT 0x00 +#define MAX77621_REG_VOUT_DVS 0x01 +#define MAX77621_REG_CONTROL1 0x02 +#define MAX77621_REG_CONTROL2 0x03 +#define MAX77621_REG_CHIPID1 0x04 +#define MAX77621_REG_CHIPID2 0x05 + +/* MAX77621_VOUT_DVC_DVS */ +#define MAX77621_DVC_DVS_VOLT_MASK 0x7F +#define MAX77621_DVC_DVS_ENABLE_SHIFT 7 +#define MAX77621_DVC_DVS_ENABLE_MASK (1 << MAX77621_DVC_DVS_ENABLE_SHIFT) + +/* MAX77621_VOUT */ +#define MAX77621_VOUT_DISABLE 0 +#define MAX77621_VOUT_ENABLE 1 +#define MAX77621_VOUT_ENABLE_MASK (MAX77621_VOUT_ENABLE << MAX77621_DVC_DVS_ENABLE_SHIFT) + +/* MAX77621_CONTROL1 */ +#define MAX77621_RAMP_12mV_PER_US 0x0 +#define MAX77621_RAMP_25mV_PER_US 0x1 +#define MAX77621_RAMP_50mV_PER_US 0x2 +#define MAX77621_RAMP_200mV_PER_US 0x3 +#define MAX77621_RAMP_MASK 0x3 + +#define MAX77621_FREQSHIFT_9PER BIT(2) +#define MAX77621_BIAS_ENABLE BIT(3) +#define MAX77621_AD_ENABLE BIT(4) +#define MAX77621_NFSR_ENABLE BIT(5) +#define MAX77621_FPWM_EN_M BIT(6) +#define MAX77621_SNS_ENABLE BIT(7) + +/* MAX77621_CONTROL2 */ +#define MAX77621_INDUCTOR_MIN_30_PER 0 +#define MAX77621_INDUCTOR_NOMINAL 1 +#define MAX77621_INDUCTOR_PLUS_30_PER 2 +#define MAX77621_INDUCTOR_PLUS_60_PER 3 +#define MAX77621_INDUCTOR_MASK 3 + +#define MAX77621_CKKADV_TRIP_75mV_PER_US (0 << 2) +#define MAX77621_CKKADV_TRIP_150mV_PER_US (1u << 2) +#define MAX77621_CKKADV_TRIP_DISABLE (3u << 2) +#define MAX77621_CKKADV_TRIP_MASK (3u << 2) + +#define MAX77621_FT_ENABLE BIT(4) +#define MAX77621_DISCH_ENABLE BIT(5) +#define MAX77621_WDTMR_ENABLE BIT(6) +#define MAX77621_T_JUNCTION_120 BIT(7) + +#define MAX77621_CPU_CTRL1_POR_DEFAULT (MAX77621_RAMP_50mV_PER_US) +#define MAX77621_CPU_CTRL1_HOS_DEFAULT (MAX77621_AD_ENABLE | \ + MAX77621_NFSR_ENABLE | \ + MAX77621_SNS_ENABLE | \ + MAX77621_RAMP_12mV_PER_US) +#define MAX77621_CPU_CTRL2_POR_DEFAULT (MAX77621_T_JUNCTION_120 | \ + MAX77621_FT_ENABLE | \ + MAX77621_CKKADV_TRIP_DISABLE | \ + MAX77621_INDUCTOR_NOMINAL) +#define MAX77621_CPU_CTRL2_HOS_DEFAULT (MAX77621_T_JUNCTION_120 | \ + MAX77621_WDTMR_ENABLE | \ + MAX77621_CKKADV_TRIP_75mV_PER_US | \ + MAX77621_INDUCTOR_NOMINAL) + +#define MAX77621_CTRL_HOS_CFG 0 +#define MAX77621_CTRL_POR_CFG 1 + +int max77620_regulator_get_status(u32 id); +int max77620_regulator_config_fps(u32 id); +int max7762x_regulator_set_voltage(u32 id, u32 uv); +int max7762x_regulator_enable(u32 id, bool enable); +void max77620_config_gpio(u32 id, bool enable); +void max77620_config_default(); +void max77620_low_battery_monitor_config(bool enable); + +void max77621_config_default(u32 id, bool por); + +#endif diff --git a/bdk/power/max77812.h b/bdk/power/max77812.h new file mode 100644 index 0000000..b58e3ae --- /dev/null +++ b/bdk/power/max77812.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 CTCaer + * + * 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 _MAX77812_H_ +#define _MAX77812_H_ + +#define MAX77812_PHASE31_CPU_I2C_ADDR 0x31 // High power GPU. 2 Outputs: 3-phase M1 + 1-phase M4. +#define MAX77812_PHASE211_CPU_I2C_ADDR 0x33 // Low power GPU. 3 Outputs: 2-phase M1 + 1-phase M3 + 1-phase M4. + +#define MAX77812_REG_RSET 0x00 +#define MAX77812_REG_INT_SRC 0x01 +#define MAX77812_REG_INT_SRC_M 0x02 +#define MAX77812_REG_TOPSYS_INT 0x03 +#define MAX77812_REG_TOPSYS_INT_M 0x04 +#define MAX77812_REG_TOPSYS_STAT 0x05 +#define MAX77812_REG_EN_CTRL 0x06 +#define MAX77812_EN_CTRL_ENABLE 1 +#define MAX77812_EN_CTRL_EN_M1_SHIFT 0 +#define MAX77812_EN_CTRL_EN_M1_MASK (1 << MAX77812_EN_CTRL_EN_M1_SHIFT) +#define MAX77812_EN_CTRL_EN_M2_SHIFT 2 +#define MAX77812_EN_CTRL_EN_M2_MASK (1 << MAX77812_EN_CTRL_EN_M2_SHIFT) +#define MAX77812_EN_CTRL_EN_M3_SHIFT 4 +#define MAX77812_EN_CTRL_EN_M3_MASK (1 << MAX77812_EN_CTRL_EN_M3_SHIFT) +#define MAX77812_EN_CTRL_EN_M4_SHIFT 6 +#define MAX77812_EN_CTRL_EN_M4_MASK (1 << MAX77812_EN_CTRL_EN_M4_SHIFT) +#define MAX77812_REG_STUP_DLY2 0x07 +#define MAX77812_REG_STUP_DLY3 0x08 +#define MAX77812_REG_STUP_DLY4 0x09 +#define MAX77812_REG_SHDN_DLY1 0x0A +#define MAX77812_REG_SHDN_DLY2 0x0B +#define MAX77812_REG_SHDN_DLY3 0x0C +#define MAX77812_REG_SHDN_DLY4 0x0D +#define MAX77812_REG_WDTRSTB_DEB 0x0E +#define MAX77812_REG_GPI_FUNC 0x0F +#define MAX77812_REG_GPI_DEB1 0x10 +#define MAX77812_REG_GPI_DEB2 0x11 +#define MAX77812_REG_GPI_PD_CTRL 0x12 +#define MAX77812_REG_PROT_CFG 0x13 +#define MAX77812_REG_VERSION 0x14 +#define MAX77812_REG_I2C_CFG 0x15 +#define MAX77812_REG_BUCK_INT 0x20 +#define MAX77812_REG_BUCK_INT_M 0x21 +#define MAX77812_REG_BUCK_STAT 0x22 +#define MAX77812_REG_M1_VOUT 0x23 // GPU. +#define MAX77812_REG_M2_VOUT 0x24 +#define MAX77812_REG_M3_VOUT 0x25 // DRAM on PHASE211. +#define MAX77812_REG_M4_VOUT 0x26 // CPU. +#define MAX77812_REG_M1_VOUT_D 0x27 +#define MAX77812_REG_M2_VOUT_D 0x28 +#define MAX77812_REG_M3_VOUT_D 0x29 +#define MAX77812_REG_M4_VOUT_D 0x2A +#define MAX77812_REG_M1_VOUT_S 0x2B +#define MAX77812_REG_M2_VOUT_S 0x2C +#define MAX77812_REG_M3_VOUT_S 0x2D +#define MAX77812_REG_M4_VOUT_S 0x2E +#define MAX77812_REG_M1_CFG 0x2F // HOS: M1_ILIM - 7.2A/4.8A. +#define MAX77812_REG_M2_CFG 0x30 // HOS: M2_ILIM - 7.2A/4.8A. +#define MAX77812_REG_M3_CFG 0x31 // HOS: M3_ILIM - 7.2A/4.8A. +#define MAX77812_REG_M4_CFG 0x32 // HOS: M4_ILIM - 7.2A/4.8A. +#define MAX77812_REG_GLB_CFG1 0x33 // HOS: B_SD_SR/B_SS_SR - 5mV/us. +#define MAX77812_REG_GLB_CFG2 0x34 // HOS: B_RD_SR/B_RU_SR - 5mV/us +#define MAX77812_REG_GLB_CFG3 0x35 + +/*! Protected area and settings only for MAX77812_ES2_VERSION */ +#define MAX77812_REG_GLB_CFG4 0x36 // QS: 0xBB. +#define MAX77812_REG_GLB_CFG5 0x37 // QS: 0x39. ES2: Set to 0x3E. +#define MAX77812_REG_GLB_CFG6 0x38 // QS: 0x88. ES2: Set to 0x90. +#define MAX77812_REG_GLB_CFG7 0x39 // QS: 0x04. +#define MAX77812_REG_GLB_CFG8 0x3A // QS: 0x3A. ES2: Set to 0x3A. + +#define MAX77812_REG_PROT_ACCESS 0xFD // 0x00: Lock, 0x5A: Unlock. +#define MAX77812_REG_UNKNOWN 0xFE + +#define MAX77812_REG_EN_CTRL_MASK(n) BIT(n) +#define MAX77812_START_SLEW_RATE_MASK 0x07 +#define MAX77812_SHDN_SLEW_RATE_MASK 0x70 +#define MAX77812_RAMPUP_SLEW_RATE_MASK 0x07 +#define MAX77812_RAMPDOWN_SLEW_RATE_MASK 0x70 +#define MAX77812_SLEW_RATE_SHIFT 4 + +#define MAX77812_OP_ACTIVE_DISCHARGE_MASK BIT(7) +#define MAX77812_PEAK_CURRENT_LMT_MASK 0x70 +#define MAX77812_SWITCH_FREQ_MASK 0x0C +#define MAX77812_FORCED_PWM_MASK BIT(1) +#define MAX77812_SLEW_RATE_CNTRL_MASK BIT(0) +#define MAX77812_START_SHD_DELAY_MASK 0x1F +#define MAX77812_VERSION_MASK 0x07 +#define MAX77812_ES2_VERSION 0x04 +#define MAX77812_QS_VERSION 0x05 + +#define MAX77812_BUCK_VOLT_MASK 0xFF + +#endif diff --git a/bdk/power/regulator_5v.c b/bdk/power/regulator_5v.c new file mode 100644 index 0000000..55f81f7 --- /dev/null +++ b/bdk/power/regulator_5v.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019-2023 CTCaer + * + * 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 +#include +#include +#include +#include +#include + +static u8 reg_5v_dev = 0; +static bool usb_src = false; + +void regulator_5v_enable(u8 dev) +{ + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + + // The power supply selection from battery or USB is automatic. + if (!reg_5v_dev) + { + // Fan and Rail power from battery 5V regulator EN. + PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1; + gpio_direction_output(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH); + + // Only Icosa has USB 5V VBUS rails. + if (tegra_t210) + { + // Fan and Rail power from USB 5V VBUS EN. + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1; + gpio_direction_output(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); + } + + // Make sure GPIO IO power is enabled. + PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO; + (void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write. + + // Inform GPIO IO pads that we switched to 1.8V. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_33V_GPIO; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + + usb_src = false; + } + reg_5v_dev |= dev; +} + +void regulator_5v_disable(u8 dev) +{ + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + + reg_5v_dev &= ~dev; + + if (!reg_5v_dev) + { + // Rail power from battery 5V regulator. + gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW); + + // Only Icosa has USB 5V VBUS rails. + if (tegra_t210) + { + // Rail power from USB 5V VBUS. + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); + usb_src = false; + + } + } +} + +bool regulator_5v_get_dev_enabled(u8 dev) +{ + return (reg_5v_dev & dev); +} + +void regulator_5v_usb_src_enable(bool enable) +{ + // Only for Icosa. + if (hw_get_chip_id() != GP_HIDREV_MAJOR_T210) + return; + + if (enable && !usb_src) + { + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH); + usb_src = true; + } + else if (!enable && usb_src) + { + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); + usb_src = false; + } +} diff --git a/nyx/nyx_gui/power/regulator_5v.h b/bdk/power/regulator_5v.h similarity index 72% rename from nyx/nyx_gui/power/regulator_5v.h rename to bdk/power/regulator_5v.h index 7608881..527c18a 100644 --- a/nyx/nyx_gui/power/regulator_5v.h +++ b/bdk/power/regulator_5v.h @@ -17,18 +17,19 @@ #ifndef _REGULATOR_5V_H_ #define _REGULATOR_5V_H_ -#include "../utils/types.h" +#include enum { - REGULATOR_5V_FAN = (1 << 0), - REGULATOR_5V_JC_R = (1 << 1), - REGULATOR_5V_JC_L = (1 << 2), + REGULATOR_5V_FAN = BIT(0), + REGULATOR_5V_JC_R = BIT(1), + REGULATOR_5V_JC_L = BIT(2), REGULATOR_5V_ALL = 0xFF }; -void regulator_enable_5v(u8 dev); -void regulator_disable_5v(u8 dev); -bool regulator_get_5v_dev_enabled(u8 dev); +void regulator_5v_enable(u8 dev); +void regulator_5v_disable(u8 dev); +bool regulator_5v_get_dev_enabled(u8 dev); +void regulator_5v_usb_src_enable(bool enable); #endif \ No newline at end of file diff --git a/nyx/nyx_gui/rtc/max77620-rtc.c b/bdk/rtc/max77620-rtc.c similarity index 52% rename from nyx/nyx_gui/rtc/max77620-rtc.c rename to bdk/rtc/max77620-rtc.c index 98243d2..6f813c0 100644 --- a/nyx/nyx_gui/rtc/max77620-rtc.c +++ b/bdk/rtc/max77620-rtc.c @@ -1,7 +1,7 @@ /* * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * Copyright (c) 2019 shchmue * * This program is free software; you can redistribute it and/or modify it @@ -17,9 +17,18 @@ * along with this program. If not, see . */ -#include "max77620-rtc.h" -#include "../soc/i2c.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include + +int epoch_offset = 0; + +void max77620_rtc_prep_read() +{ + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); +} void max77620_rtc_get_time(rtc_time_t *time) { @@ -35,10 +44,10 @@ void max77620_rtc_get_time(rtc_time_t *time) // Get time. time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; + u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG); + time->hour = hour & 0x1F; - time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F; - - if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK) + if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK)) time->hour = (time->hour & 0xF) + 12; // Get day of week. 1: Monday to 7: Sunday. @@ -53,7 +62,7 @@ void max77620_rtc_get_time(rtc_time_t *time) } // Get date. - time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; + time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; } @@ -64,6 +73,7 @@ void max77620_rtc_stop_alarm() // Update RTC regs from RTC clock. i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); + msleep(16); // Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2. for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++) @@ -82,9 +92,9 @@ void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) u32 tmp, edays, year, month, day; // Set time. - time->sec = epoch % 60; + time->sec = epoch % 60; epoch /= 60; - time->min = epoch % 60; + time->min = epoch % 60; epoch /= 60; time->hour = epoch % 24; epoch /= 24; @@ -99,14 +109,14 @@ void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) day = edays - month * 30 - month * 601 / 1000; // Month/Year offset. - if(month < 14) + if (month < 14) { year -= 4716; month--; } else { - year -= 4715; + year -= 4715; month -= 13; } @@ -119,7 +129,7 @@ void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) time->weekday = 0; //! TODO. } -u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding) +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time) { u32 year, month, epoch; @@ -128,42 +138,77 @@ u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding) //Month of year month = time->month; - if (!hos_encoding) + // Month/Year offset. + if (month < 3) { - // Month/Year offset. - if(month < 3) - { - month += 12; - year--; - } - } - else - { - year -= 2000; - month++; - - // Month/Year offset. - if(month < 3) - { - month += 9; - year--; - } - else - month -= 3; + month += 12; + year--; } - epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days. + epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days. - if (!hos_encoding) - { - epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days. - epoch -= 719561; // Epoch time is 1/1/1970. - } - else - epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days. + epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days. + epoch -= 719561; // Epoch time is 1/1/1970. epoch *= 86400; // Days to seconds. epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds. return epoch; } + +void max77620_rtc_get_time_adjusted(rtc_time_t *time) +{ + max77620_rtc_get_time(time); + if (epoch_offset) + { + u32 epoch = (u32)((s64)max77620_rtc_date_to_epoch(time) + epoch_offset); + max77620_rtc_epoch_to_date(epoch, time); + } +} + +void max77620_rtc_set_epoch_offset(int offset) +{ + epoch_offset = offset; +} + +void max77620_rtc_set_reboot_reason(rtc_reboot_reason_t *rr) +{ + max77620_rtc_stop_alarm(); + + // Set reboot reason. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_YEAR_REG, rr->enc.val1); + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_YEAR_REG, rr->enc.val2); + + // Set reboot reason magic. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_WEEKDAY_REG, RTC_REBOOT_REASON_MAGIC); + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_WEEKDAY_REG, RTC_REBOOT_REASON_MAGIC); + + // Update RTC clock from RTC regs. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); + msleep(16); +} + +bool max77620_rtc_get_reboot_reason(rtc_reboot_reason_t *rr) +{ + u8 magic[2]; + + // Get reboot reason magic. + magic[0] = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_WEEKDAY_REG); + magic[1] = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_WEEKDAY_REG); + + // Magic must be correct and match on both registers. + if (magic[0] != RTC_REBOOT_REASON_MAGIC || magic[0] != magic[1]) + return false; + + // Reboot reason setter is expected to have updated the actual regs already. + rr->enc.val1 = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_YEAR_REG); + rr->enc.val2 = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_YEAR_REG); + + // Clear magic and update actual regs. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_WEEKDAY_REG, 0); + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_WEEKDAY_REG, 0); + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); + + // Return reboot reason. False if [config] was selected. + return true; +} diff --git a/bootloader/rtc/max77620-rtc.h b/bdk/rtc/max77620-rtc.h similarity index 56% rename from bootloader/rtc/max77620-rtc.h rename to bdk/rtc/max77620-rtc.h index 99199d2..b82c3e6 100644 --- a/bootloader/rtc/max77620-rtc.h +++ b/bdk/rtc/max77620-rtc.h @@ -1,7 +1,7 @@ /* * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,25 +19,30 @@ #ifndef _MFD_MAX77620_RTC_H_ #define _MFD_MAX77620_RTC_H_ -#include "../utils/types.h" +#include #define MAX77620_RTC_I2C_ADDR 0x68 #define MAX77620_RTC_NR_TIME_REGS 7 +#define MAX77620_RTC_RTCINT_REG 0x00 +#define MAX77620_RTC_RTCINTM_REG 0x01 #define MAX77620_RTC_CONTROLM_REG 0x02 #define MAX77620_RTC_CONTROL_REG 0x03 -#define MAX77620_RTC_BIN_FORMAT (1 << 0) -#define MAX77620_RTC_24H (1 << 1) +#define MAX77620_RTC_BIN_FORMAT BIT(0) +#define MAX77620_RTC_24H BIT(1) #define MAX77620_RTC_UPDATE0_REG 0x04 -#define MAX77620_RTC_WRITE_UPDATE (1 << 0) -#define MAX77620_RTC_READ_UPDATE (1 << 4) +#define MAX77620_RTC_WRITE_UPDATE BIT(0) +#define MAX77620_RTC_READ_UPDATE BIT(4) + +#define MAX77620_RTC_UPDATE1_REG 0x05 +#define MAX77620_RTC_RTCSMPL_REG 0x06 #define MAX77620_RTC_SEC_REG 0x07 #define MAX77620_RTC_MIN_REG 0x08 #define MAX77620_RTC_HOUR_REG 0x09 -#define MAX77620_RTC_HOUR_PM_MASK (1 << 6) +#define MAX77620_RTC_HOUR_PM_MASK BIT(6) #define MAX77620_RTC_WEEKDAY_REG 0x0A #define MAX77620_RTC_MONTH_REG 0x0B #define MAX77620_RTC_YEAR_REG 0x0C @@ -57,7 +62,7 @@ #define MAX77620_ALARM2_MONTH_REG 0x19 #define MAX77620_ALARM2_YEAR_REG 0x1A #define MAX77620_ALARM2_DATE_REG 0x1B -#define MAX77620_RTC_ALARM_EN_MASK (1 << 7) +#define MAX77620_RTC_ALARM_EN_MASK BIT(7) typedef struct _rtc_time_t { u8 weekday; @@ -69,9 +74,47 @@ typedef struct _rtc_time_t { u16 year; } rtc_time_t; +#define RTC_REBOOT_REASON_MAGIC 0x77 // 7-bit reg. + +enum { + REBOOT_REASON_NOP = 0, // Use [config]. + REBOOT_REASON_SELF = 1, // Use autoboot_idx/autoboot_list. + REBOOT_REASON_MENU = 2, // Force menu. + REBOOT_REASON_UMS = 3, // Force selected UMS partition. + REBOOT_REASON_REC = 4, // Set PMC_SCRATCH0_MODE_RECOVERY and reboot to self. + REBOOT_REASON_PANIC = 5 // Inform bootloader that panic occured if T210B01. +}; + +typedef struct _rtc_rr_decoded_t +{ + u16 reason:4; + u16 autoboot_idx:4; + u16 autoboot_list:1; + u16 ums_idx:3; +} rtc_rr_decoded_t; + +typedef struct _rtc_rr_encoded_t +{ + u16 val1:6; // 6-bit reg. + u16 val2:6; // 6-bit reg. +} rtc_rr_encoded_t; + +typedef struct _rtc_reboot_reason_t +{ + union { + rtc_rr_decoded_t dec; + rtc_rr_encoded_t enc; + }; +} rtc_reboot_reason_t; + +void max77620_rtc_prep_read(); void max77620_rtc_get_time(rtc_time_t *time); +void max77620_rtc_get_time_adjusted(rtc_time_t *time); +void max77620_rtc_set_epoch_offset(int offset); void max77620_rtc_stop_alarm(); void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time); -u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding); +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time); +void max77620_rtc_set_reboot_reason(rtc_reboot_reason_t *rr); +bool max77620_rtc_get_reboot_reason(rtc_reboot_reason_t *rr); #endif /* _MFD_MAX77620_RTC_H_ */ diff --git a/bdk/sec/se.c b/bdk/sec/se.c new file mode 100644 index 0000000..4ed04ec --- /dev/null +++ b/bdk/sec/se.c @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include +#include +#include +#include +#include + +typedef struct _se_ll_t +{ + vu32 num; + vu32 addr; + vu32 size; +} se_ll_t; + +se_ll_t ll_src, ll_dst; +se_ll_t *ll_src_ptr, *ll_dst_ptr; // Must be u32 aligned. + +static void _gf256_mul_x(void *block) +{ + u8 *pdata = (u8 *)block; + u32 carry = 0; + + for (int i = 0xF; i >= 0; i--) + { + u8 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 7; + } + + if (carry) + pdata[0xF] ^= 0x87; +} + +static void _gf256_mul_x_le(void *block) +{ + u32 *pdata = (u32 *)block; + u32 carry = 0; + + for (u32 i = 0; i < 4; i++) + { + u32 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 31; + } + + if (carry) + pdata[0x0] ^= 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 *src, se_ll_t *dst) +{ + SE(SE_IN_LL_ADDR_REG) = (u32)src; + SE(SE_OUT_LL_ADDR_REG) = (u32)dst; +} + +static int _se_wait() +{ + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + + // Wait for operation to be done. + while (!(SE(SE_INT_STATUS_REG) & SE_INT_OP_DONE)) + ; + + // Check for errors. + if ((SE(SE_INT_STATUS_REG) & SE_INT_ERR_STAT) || + (SE(SE_STATUS_REG) & SE_STATUS_STATE_MASK) != SE_STATUS_STATE_IDLE || + (SE(SE_ERR_STATUS_REG) != 0) + ) + { + return 0; + } + + // T210B01: IRAM/TZRAM/DRAM AHB coherency WAR. + if (!tegra_t210 && ll_dst_ptr) + { + u32 timeout = get_tmr_us() + 1000000; + // Ensure data is out from SE. + while (SE(SE_STATUS_REG) & SE_STATUS_MEM_IF_BUSY) + { + if (get_tmr_us() > timeout) + return 0; + usleep(1); + } + + // Ensure data is out from AHB. + if (ll_dst_ptr->addr >= DRAM_START) + { + timeout = get_tmr_us() + 200000; + while (AHB_GIZMO(AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID) & MEM_WRQUE_SE_MST_ID) + { + if (get_tmr_us() > timeout) + return 0; + usleep(1); + } + } + } + + return 1; +} + +static int _se_execute_finalize() +{ + int res = _se_wait(); + + // Invalidate data after OP is done. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + ll_src_ptr = NULL; + ll_dst_ptr = NULL; + + return res; +} + +static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot) +{ + ll_src_ptr = NULL; + ll_dst_ptr = NULL; + + if (src) + { + ll_src_ptr = &ll_src; + _se_ll_init(ll_src_ptr, (u32)src, src_size); + } + + if (dst) + { + ll_dst_ptr = &ll_dst; + _se_ll_init(ll_dst_ptr, (u32)dst, dst_size); + } + + _se_ll_set(ll_src_ptr, ll_dst_ptr); + + SE(SE_ERR_STATUS_REG) = SE(SE_ERR_STATUS_REG); + SE(SE_INT_STATUS_REG) = SE(SE_INT_STATUS_REG); + + // Flush data before starting OP. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false); + + SE(SE_OPERATION_REG) = op; + + if (is_oneshot) + return _se_execute_finalize(); + + return 1; +} + +static int _se_execute_oneshot(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + return _se_execute(op, dst, dst_size, src, src_size, true); +} + +static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (!src || !dst) + return 0; + + u32 block[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0}; + + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; + + memcpy(block, src, src_size); + int res = _se_execute_oneshot(op, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE); + memcpy(dst, block, dst_size); + + return res; +} + +static void _se_aes_ctr_set(const void *ctr) +{ + u32 data[SE_AES_IV_SIZE / 4]; + memcpy(data, ctr, SE_AES_IV_SIZE); + + for (u32 i = 0; i < SE_CRYPTO_LINEAR_CTR_REG_COUNT; i++) + SE(SE_CRYPTO_LINEAR_CTR_REG + (4 * i)) = data[i]; +} + +void se_rsa_acc_ctrl(u32 rs, u32 flags) +{ + if (flags & SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG) + SE(SE_RSA_KEYTABLE_ACCESS_REG + 4 * rs) = + (((flags >> 4) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | (flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG)) ^ + SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG; + if (flags & SE_RSA_KEY_LOCK_FLAG) + SE(SE_RSA_SECURITY_PERKEY_REG) &= ~BIT(rs); +} + +void se_key_acc_ctrl(u32 ks, u32 flags) +{ + if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) + SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks) = ~flags; + if (flags & SE_KEY_LOCK_FLAG) + SE(SE_CRYPTO_SECURITY_PERKEY_REG) &= ~BIT(ks); +} + +u32 se_key_acc_ctrl_get(u32 ks) +{ + return SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks); +} + +void se_aes_key_set(u32 ks, const void *key, u32 size) +{ + u32 data[SE_AES_MAX_KEY_SIZE / 4]; + memcpy(data, key, size); + + for (u32 i = 0; i < (size / 4); i++) + { + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_PKT(i); // QUAD is automatically set by PKT. + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i]; + } +} + +void se_aes_iv_set(u32 ks, const void *iv) +{ + u32 data[SE_AES_IV_SIZE / 4]; + memcpy(data, iv, SE_AES_IV_SIZE); + + for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++) + { + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i); + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i]; + } +} + +void se_aes_key_get(u32 ks, void *key, u32 size) +{ + u32 data[SE_AES_MAX_KEY_SIZE / 4]; + + for (u32 i = 0; i < (size / 4); i++) + { + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_PKT(i); // QUAD is automatically set by PKT. + data[i] = SE(SE_CRYPTO_KEYTABLE_DATA_REG); + } + + memcpy(key, data, size); +} + +void se_aes_key_clear(u32 ks) +{ + for (u32 i = 0; i < (SE_AES_MAX_KEY_SIZE / 4); i++) + { + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_PKT(i); // QUAD is automatically set by PKT. + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0; + } +} + +void se_aes_iv_clear(u32 ks) +{ + for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++) + { + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i); + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0; + } +} + +void se_aes_iv_updated_clear(u32 ks) +{ + for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++) + { + SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(UPDATED_IV) | SE_KEYTABLE_PKT(i); + SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0; + } +} + +int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input) +{ + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTABLE); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; + SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst) | SE_KEYTABLE_DST_WORD_QUAD(KEYS_0_3); + + return _se_execute_oneshot(SE_OP_START, NULL, 0, input, SE_KEY_128_SIZE); +} + +int se_aes_crypt_hash(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) | + SE_CRYPTO_HASH(HASH_ENABLE); + } + else + { + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) | + SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM) | + SE_CRYPTO_HASH(HASH_ENABLE); + } + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size); +} + +int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); + } + else + { + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + } + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size); +} + +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP); + } + else + { + SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) | + SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM); + } + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size); +} + +int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) +{ + return se_aes_crypt_ecb(ks, enc, dst, SE_AES_BLOCK_SIZE, src, SE_AES_BLOCK_SIZE); +} + +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr) +{ + SE(SE_SPARE_REG) = SE_ECO(SE_ERRATA_FIX_ENABLE); + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = 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_CNTN(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_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1; + if (!_se_execute_oneshot(SE_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(SE_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 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize) +{ + int res = 0; + u32 tmp[SE_AES_BLOCK_SIZE / sizeof(u32)]; + u8 *tweak = (u8 *)tmp; + 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(tweak_ks, ENCRYPT, tweak, tweak)) + goto out; + + // We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < secsize / SE_AES_BLOCK_SIZE; i++) + { + for (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++) + pdst[j] = psrc[j] ^ tweak[j]; + if (!se_aes_crypt_block_ecb(crypt_ks, enc, pdst, pdst)) + goto out; + for (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++) + pdst[j] = pdst[j] ^ tweak[j]; + _gf256_mul_x(tweak); + psrc += SE_AES_BLOCK_SIZE; + pdst += SE_AES_BLOCK_SIZE; + } + + res = 1; + +out: + return res; +} + +int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size) +{ + u32 *pdst = (u32 *)dst; + u32 *psrc = (u32 *)src; + u32 *ptweak = (u32 *)tweak; + + if (regen_tweak) + { + for (int i = 0xF; i >= 0; i--) + { + tweak[i] = sec & 0xFF; + sec >>= 8; + } + if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak)) + return 0; + } + + // tweak_exp allows using a saved tweak to reduce _gf256_mul_x_le calls. + for (u32 i = 0; i < (tweak_exp << 5); i++) + _gf256_mul_x_le(tweak); + + u8 orig_tweak[SE_KEY_128_SIZE] __attribute__((aligned(4))); + memcpy(orig_tweak, tweak, SE_KEY_128_SIZE); + + // We are assuming a 16 sector aligned size in this implementation. + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 4; j++) + pdst[j] = psrc[j] ^ ptweak[j]; + + _gf256_mul_x_le(tweak); + psrc += 4; + pdst += 4; + } + + if (!se_aes_crypt_ecb(crypt_ks, enc, dst, sec_size, dst, sec_size)) + return 0; + + pdst = (u32 *)dst; + ptweak = (u32 *)orig_tweak; + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 4; j++) + pdst[j] = pdst[j] ^ ptweak[j]; + + _gf256_mul_x_le(orig_tweak); + pdst += 4; + } + + return 1; +} + +int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, 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(tweak_ks, crypt_ks, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize)) + return 0; + + return 1; +} + +static void se_calc_sha256_get_hash(void *hash, u32 *msg_left) +{ + u32 hash32[SE_SHA_256_SIZE / 4]; + + // Backup message left. + if (msg_left) + { + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG); + } + + // Copy output hash. + for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4))); + memcpy(hash, hash32, SE_SHA_256_SIZE); +} + +int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot) +{ + int res; + u32 hash32[SE_SHA_256_SIZE / 4]; + + //! TODO: src_size must be 512 bit aligned if continuing and not last block for SHA256. + if (src_size > 0xFFFFFF || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer. + return 0; + + // Src size of 0 is not supported, so return null string sha256. + if (!src_size) + { + const u8 null_hash[SE_SHA_256_SIZE] = { + 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55 + }; + memcpy(hash, null_hash, SE_SHA_256_SIZE); + return 1; + } + + // Setup config for SHA256. + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); + SE(SE_SHA_CONFIG_REG) = sha_cfg; + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; + + // Set total size to current buffer size if empty. + if (!total_size) + total_size = src_size; + + // Set total size: BITS(src_size), up to 2 EB. + SE(SE_SHA_MSG_LENGTH_0_REG) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LENGTH_1_REG) = (u32)(total_size >> 29); + SE(SE_SHA_MSG_LENGTH_2_REG) = 0; + SE(SE_SHA_MSG_LENGTH_3_REG) = 0; + + // Set size left to hash. + SE(SE_SHA_MSG_LEFT_0_REG) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LEFT_1_REG) = (u32)(total_size >> 29); + SE(SE_SHA_MSG_LEFT_2_REG) = 0; + SE(SE_SHA_MSG_LEFT_3_REG) = 0; + + // If we hash in chunks, copy over the intermediate. + if (sha_cfg == SHA_CONTINUE && msg_left) + { + // Restore message left to process. + SE(SE_SHA_MSG_LEFT_0_REG) = msg_left[0]; + SE(SE_SHA_MSG_LEFT_1_REG) = msg_left[1]; + + // Restore hash reg. + memcpy(hash32, hash, SE_SHA_256_SIZE); + for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++) + SE(SE_HASH_RESULT_REG + (i * 4)) = byte_swap_32(hash32[i]); + } + + // Trigger the operation. + res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot); + + if (is_oneshot) + se_calc_sha256_get_hash(hash, msg_left); + + return res; +} + +int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size) +{ + return se_calc_sha256(hash, NULL, src, src_size, 0, SHA_INIT_HASH, true); +} + +int se_calc_sha256_finalize(void *hash, u32 *msg_left) +{ + int res = _se_execute_finalize(); + + se_calc_sha256_get_hash(hash, msg_left); + + return res; +} + +int se_gen_prng128(void *dst) +{ + // Setup config for X931 PRNG. + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_NORMAL); + //SE(SE_RNG_SRC_CONFIG_REG) = + // SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE) | SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(RO_ENTR_LOCK_ENABLE); + SE(SE_RNG_RESEED_INTERVAL_REG) = 1; + + SE(SE_CRYPTO_BLOCK_COUNT_REG) = (16 >> 4) - 1; + + // Trigger the operation. + return _se_execute_oneshot(SE_OP_START, dst, 16, NULL, 0); +} + +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) +{ + u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40); + + // Set Secure Random Key. + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_FORCE_RESEED); + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0); + + // Save AES keys. + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + + for (u32 i = 0; i < SE_AES_KEYSLOT_COUNT; i++) + { + SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) | + SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_0_3); + + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0); + memcpy(keys + i * keysize, aligned_buf, SE_AES_BLOCK_SIZE); + + if (keysize > SE_KEY_128_SIZE) + { + SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) | + SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_4_7); + + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0); + memcpy(keys + i * keysize + SE_AES_BLOCK_SIZE, aligned_buf, SE_AES_BLOCK_SIZE); + } + } + + // Save SRK to PMC secure scratches. + SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(SRK); + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(SE_OP_CTX_SAVE, NULL, 0, NULL, 0); + + // End context save. + SE(SE_CONFIG_REG) = 0; + _se_execute_oneshot(SE_OP_CTX_SAVE, NULL, 0, NULL, 0); + + // Get SRK. + u32 srk[4]; + srk[0] = PMC(APBDEV_PMC_SECURE_SCRATCH4); + srk[1] = PMC(APBDEV_PMC_SECURE_SCRATCH5); + srk[2] = PMC(APBDEV_PMC_SECURE_SCRATCH6); + srk[3] = PMC(APBDEV_PMC_SECURE_SCRATCH7); + + // Decrypt context. + se_aes_key_clear(3); + se_aes_key_set(3, srk, SE_KEY_128_SIZE); + se_aes_crypt_cbc(3, DECRYPT, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize); + se_aes_key_clear(3); +} + +int se_aes_cmac_128(u32 ks, void *dst, const void *src, u32 src_size) +{ + int res = 0; + + u32 tmp1[SE_KEY_128_SIZE / sizeof(u32)] = {0}; + u32 tmp2[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0}; + u8 *key = (u8 *)tmp1; + u8 *last_block = (u8 *)tmp2; + + se_aes_iv_clear(ks); + se_aes_iv_updated_clear(ks); + + // Generate sub key + if (!se_aes_crypt_hash(ks, ENCRYPT, key, SE_KEY_128_SIZE, key, SE_KEY_128_SIZE)) + goto out; + + _gf256_mul_x(key); + if (src_size & 0xF) + _gf256_mul_x(key); + + SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG); + SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_MEMORY) | + SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); + se_aes_iv_clear(ks); + se_aes_iv_updated_clear(ks); + + u32 num_blocks = (src_size + 0xf) >> 4; + if (num_blocks > 1) + { + SE(SE_CRYPTO_BLOCK_COUNT_REG) = num_blocks - 2; + if (!_se_execute_oneshot(SE_OP_START, NULL, 0, src, src_size)) + goto out; + SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED); + } + + if (src_size & 0xf) + { + memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf); + last_block[src_size & 0xf] = 0x80; + } + else if (src_size >= SE_AES_BLOCK_SIZE) + { + memcpy(last_block, src + src_size - SE_AES_BLOCK_SIZE, SE_AES_BLOCK_SIZE); + } + + for (u32 i = 0; i < SE_KEY_128_SIZE; i++) + last_block[i] ^= key[i]; + + SE(SE_CRYPTO_BLOCK_COUNT_REG) = 0; + res = _se_execute_oneshot(SE_OP_START, NULL, 0, last_block, SE_AES_BLOCK_SIZE); + + u32 *dst32 = (u32 *)dst; + for (u32 i = 0; i < (SE_KEY_128_SIZE / 4); i++) + dst32[i] = SE(SE_HASH_RESULT_REG + (i * 4)); + +out: + return res; +} diff --git a/bdk/sec/se.h b/bdk/sec/se.h new file mode 100644 index 0000000..36b057b --- /dev/null +++ b/bdk/sec/se.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2022 CTCaer + * + * 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 "se_t210.h" +#include + +void se_rsa_acc_ctrl(u32 rs, u32 flags); +void se_key_acc_ctrl(u32 ks, u32 flags); +u32 se_key_acc_ctrl_get(u32 ks); +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); +void se_aes_key_set(u32 ks, const void *key, u32 size); +void se_aes_iv_set(u32 ks, const void *iv); +void se_aes_key_get(u32 ks, void *key, u32 size); +void se_aes_key_clear(u32 ks); +void se_aes_iv_clear(u32 ks); +void se_aes_iv_updated_clear(u32 ks); +int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); +int se_aes_crypt_hash(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); +int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); +int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); +int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize); +int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size); +int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs); +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); +int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot); +int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size); +int se_calc_sha256_finalize(void *hash, u32 *msg_left); +int se_gen_prng128(void *dst); +int se_aes_cmac_128(u32 ks, void *dst, const void *src, u32 src_size); + +#endif diff --git a/bdk/sec/se_t210.h b/bdk/sec/se_t210.h new file mode 100644 index 0000000..317c4fa --- /dev/null +++ b/bdk/sec/se_t210.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2021 CTCaer + * + * 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_T210_H +#define _SE_T210_H + +#include + +#define SE_CRYPTO_QUEUE_LENGTH 50 +#define SE_MAX_SRC_SG_COUNT 50 +#define SE_MAX_DST_SG_COUNT 50 + +#define SE_AES_KEYSLOT_COUNT 16 +#define SE_RSA_KEYSLOT_COUNT 2 +#define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF + +#define SE_AES_BLOCK_SIZE 16 +#define SE_AES_IV_SIZE 16 +#define SE_AES_MIN_KEY_SIZE 16 +#define SE_AES_MAX_KEY_SIZE 32 +#define SE_KEY_128_SIZE 16 +#define SE_KEY_192_SIZE 24 +#define SE_KEY_256_SIZE 32 +#define SE_SHA_192_SIZE 24 +#define SE_SHA_256_SIZE 32 +#define SE_SHA_384_SIZE 48 +#define SE_SHA_512_SIZE 64 +#define SE_RNG_IV_SIZE 16 +#define SE_RNG_DT_SIZE 16 +#define SE_RNG_KEY_SIZE 16 +#define SE_RNG_SEED_SIZE (SE_RNG_IV_SIZE + SE_RNG_KEY_SIZE + SE_RNG_DT_SIZE) + +#define SE_AES_CMAC_DIGEST_SIZE 16 +#define SE_RSA512_DIGEST_SIZE 64 +#define SE_RSA1024_DIGEST_SIZE 128 +#define SE_RSA1536_DIGEST_SIZE 192 +#define SE_RSA2048_DIGEST_SIZE 256 + +#define DECRYPT 0 +#define ENCRYPT 1 + +/* SE register definitions */ +#define SE_SE_SECURITY_REG 0x000 +#define SE_HARD_SETTING BIT(0) +#define SE_ENG_DIS BIT(1) +#define SE_PERKEY_SETTING BIT(2) +#define SE_SOFT_SETTING BIT(16) + +#define SE_TZRAM_SECURITY_REG 0x004 +#define SE_TZRAM_HARD_SETTING BIT(0) +#define SE_TZRAM_ENG_DIS BIT(1) + +#define SE_OPERATION_REG 0x008 +#define SE_OP_ABORT 0 +#define SE_OP_START 1 +#define SE_OP_RESTART_OUT 2 +#define SE_OP_CTX_SAVE 3 +#define SE_OP_RESTART_IN 4 + +#define SE_INT_ENABLE_REG 0x00C +#define SE_INT_STATUS_REG 0x010 +#define SE_INT_IN_LL_BUF_RD BIT(0) +#define SE_INT_IN_DONE BIT(1) +#define SE_INT_OUT_LL_BUF_WR BIT(2) +#define SE_INT_OUT_DONE BIT(3) +#define SE_INT_OP_DONE BIT(4) +#define SE_INT_RESEED_NEEDED BIT(5) +#define SE_INT_ERR_STAT BIT(16) + +#define SE_CONFIG_REG 0x014 +#define DST_MEMORY 0 +#define DST_HASHREG 1 +#define DST_KEYTABLE 2 +#define DST_SRK 3 +#define DST_RSAREG 4 +#define SE_CONFIG_DST(x) ((x) << 2) +#define ALG_NOP 0 +#define ALG_AES_DEC 1 +#define SE_CONFIG_DEC_ALG(x) ((x) << 8) +#define ALG_NOP 0 +#define ALG_AES_ENC 1 +#define ALG_RNG 2 +#define ALG_SHA 3 +#define ALG_RSA 4 +#define SE_CONFIG_ENC_ALG(x) ((x) << 12) +#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_DEC_MODE(x) ((x) << 16) +#define SE_CONFIG_ENC_MODE(x) ((x) << 24) + +#define SE_IN_LL_ADDR_REG 0x018 +#define SE_IN_CUR_BYTE_ADDR_REG 0x01C +#define SE_IN_CUR_LL_ID_REG 0x020 +#define SE_OUT_LL_ADDR_REG 0x024 +#define SE_OUT_CUR_BYTE_ADDR_REG 0x028 +#define SE_OUT_CUR_LL_ID_REG 0x02C + +#define SE_HASH_RESULT_REG 0x030 +#define SE_HASH_RESULT_REG_COUNT 16 + +#define SE_CONTEXT_SAVE_CONFIG_REG 0x070 +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIGINAL_IV 2 +#define UPDATED_IV 3 +#define SE_CONTEXT_AES_WORD_QUAD(x) ((x) << 0) +#define SE_CONTEXT_AES_KEY_INDEX(x) ((x) << 8) +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define KEYS_8_11 2 +#define KEYS_12_15 3 +#define SE_CONTEXT_RSA_WORD_QUAD(x) ((x) << 12) +#define SLOT0_EXPONENT 0 +#define SLOT0_MODULUS 1 +#define SLOT1_EXPONENT 2 +#define SLOT1_MODULUS 3 +#define SE_CONTEXT_RSA_KEY_INDEX(x) ((x) << 16) +#define STICKY_0_3 0 +#define STICKY_4_7 1 +#define SE_CONTEXT_STICKY_WORD_QUAD(x) ((x) << 24) +#define STICKY_BITS 0 +#define RSA_KEYTABLE 1 +#define AES_KEYTABLE 2 +#define MEM 4 +#define SRK 6 +#define SE_CONTEXT_SRC(x) ((x) << 29) + +#define SE_CTX_SAVE_AUTO_T210B01_REG 0x074 +#define SE_CTX_SAVE_AUTO_ENABLE BIT(0) +#define SE_CTX_SAVE_AUTO_LOCK BIT(8) +#define SE_CTX_SAVE_AUTO_CURR_CNT_MASK (0x3FF << 16) + +#define SE_CRYPTO_LAST_BLOCK 0x080 + +#define SE_SHA_CONFIG_REG 0x200 +#define SHA_CONTINUE 0 +#define SHA_INIT_HASH 1 + +#define SE_SHA_MSG_LENGTH_0_REG 0x204 +#define SE_SHA_MSG_LENGTH_1_REG 0x208 +#define SE_SHA_MSG_LENGTH_2_REG 0x20C +#define SE_SHA_MSG_LENGTH_3_REG 0x210 +#define SE_SHA_MSG_LEFT_0_REG 0x214 +#define SE_SHA_MSG_LEFT_1_REG 0x218 +#define SE_SHA_MSG_LEFT_2_REG 0x21C +#define SE_SHA_MSG_LEFT_3_REG 0x220 + +#define SE_CRYPTO_SECURITY_PERKEY_REG 0x280 +#define SE_KEY_LOCK_FLAG 0x80 +#define SE_CRYPTO_KEYTABLE_ACCESS_REG 0x284 +#define SE_CRYPTO_KEYTABLE_ACCESS_REG_COUNT 16 +#define SE_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) +#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) +#define SE_KEY_TBL_DIS_OIVREAD_FLAG BIT(2) +#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG BIT(3) +#define SE_KEY_TBL_DIS_UIVREAD_FLAG BIT(4) +#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG BIT(5) +#define SE_KEY_TBL_DIS_KEYUSE_FLAG BIT(6) +#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F + +#define SE_CRYPTO_CONFIG_REG 0x304 +#define HASH_DISABLE 0 +#define HASH_ENABLE 1 +#define SE_CRYPTO_HASH(x) ((x) << 0) +#define XOR_BYPASS 0 +#define XOR_TOP 2 +#define XOR_BOTTOM 3 +#define SE_CRYPTO_XOR_POS(x) ((x) << 1) +#define INPUT_MEMORY 0 +#define INPUT_RANDOM 1 +#define INPUT_AESOUT 2 +#define INPUT_LNR_CTR 3 +#define SE_CRYPTO_INPUT_SEL(x) ((x) << 3) +#define VCTRAM_MEM 0 +#define VCTRAM_AESOUT 2 +#define VCTRAM_PREVMEM 3 +#define SE_CRYPTO_VCTRAM_SEL(x) ((x) << 5) +#define IV_ORIGINAL 0 +#define IV_UPDATED 1 +#define SE_CRYPTO_IV_SEL(x) ((x) << 7) +#define CORE_DECRYPT 0 +#define CORE_ENCRYPT 1 +#define SE_CRYPTO_CORE_SEL(x) ((x) << 8) +#define SE_CRYPTO_KEYSCH_BYPASS BIT(10) +#define SE_CRYPTO_CTR_CNTN(x) ((x) << 11) +#define SE_CRYPTO_KEY_INDEX(x) ((x) << 24) +#define MEMIF_AHB 0 +#define MEMIF_MCCIF 1 +#define SE_CRYPTO_MEMIF(x) ((x) << 31) + +#define SE_CRYPTO_LINEAR_CTR_REG 0x308 +#define SE_CRYPTO_LINEAR_CTR_REG_COUNT 4 + +#define SE_CRYPTO_BLOCK_COUNT_REG 0x318 + +#define SE_CRYPTO_KEYTABLE_ADDR_REG 0x31C +#define SE_KEYTABLE_PKT(x) ((x) << 0) +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIGINAL_IV 2 +#define UPDATED_IV 3 +#define SE_KEYTABLE_QUAD(x) ((x) << 2) +#define SE_KEYTABLE_SLOT(x) ((x) << 4) + +#define SE_CRYPTO_KEYTABLE_DATA_REG 0x320 + +#define SE_CRYPTO_KEYTABLE_DST_REG 0x330 +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIGINAL_IV 2 +#define UPDATED_IV 3 +#define SE_KEYTABLE_DST_WORD_QUAD(x) ((x) << 0) +#define SE_KEYTABLE_DST_KEY_INDEX(x) ((x) << 8) + +#define SE_RNG_CONFIG_REG 0x340 +#define MODE_NORMAL 0 +#define MODE_FORCE_INSTANTION 1 +#define MODE_FORCE_RESEED 2 +#define SE_RNG_CONFIG_MODE(x) ((x) << 0) +#define SRC_NONE 0 +#define SRC_ENTROPY 1 +#define SRC_LFSR 2 +#define SE_RNG_CONFIG_SRC(x) ((x) << 2) + +#define SE_RNG_SRC_CONFIG_REG 0x344 +#define RO_ENTR_LOCK_DISABLE 0 +#define RO_ENTR_LOCK_ENABLE 1 +#define SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(x) ((x) << 0) +#define RO_ENTR_DISABLE 0 +#define RO_ENTR_ENABLE 1 +#define SE_RNG_SRC_CONFIG_ENTR_SRC(x) ((x) << 1) +#define RO_HW_DIS_CYA_DISABLE 0 +#define RO_HW_DIS_CYA_ENABLE 1 +#define SE_RNG_SRC_CONFIG_HW_DIS_CYA(x) ((x) << 2) +#define SE_RNG_SRC_CONFIG_ENTR_SUBSMPL(x) ((x) << 4) +#define SE_RNG_SRC_CONFIG_ENTR_DATA_FLUSH BIT(8) + +#define SE_RNG_RESEED_INTERVAL_REG 0x348 + +#define SE_RSA_CONFIG 0x400 +#define RSA_KEY_SLOT_ONE 0 +#define RSA_KEY_SLOT_TW0 1 +#define RSA_KEY_SLOT(x) ((x) << 24) + +#define SE_RSA_KEY_SIZE_REG 0x404 +#define RSA_KEY_WIDTH_512 0 +#define RSA_KEY_WIDTH_1024 1 +#define RSA_KEY_WIDTH_1536 2 +#define RSA_KEY_WIDTH_2048 3 + +#define SE_RSA_EXP_SIZE_REG 0x408 + +#define SE_RSA_SECURITY_PERKEY_REG 0x40C +#define SE_RSA_KEY_LOCK_FLAG 0x80 +#define SE_RSA_KEYTABLE_ACCESS_REG 0x410 +#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG BIT(0) +#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG BIT(1) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG BIT(2) +#define SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG | SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) + +#define SE_RSA_KEYTABLE_ADDR_REG 0x420 +#define SE_RSA_KEYTABLE_PKT(x) ((x) << 0) +#define RSA_KEY_TYPE_EXP 0 +#define RSA_KEY_TYPE_MOD 1 +#define SE_RSA_KEYTABLE_TYPE(x) ((x) << 6) +#define RSA_KEY_NUM(x) ((x) << 7) +#define RSA_KEY_INPUT_MODE_REG 0 +#define RSA_KEY_INPUT_MODE_DMA 1 +#define SE_RSA_KEYTABLE_INPUT_MODE(x) ((x) << 8) +#define RSA_KEY_READ 0 +#define RSA_KEY_WRITE 1 +#define SE_RSA_KEY_OP(x) ((x) << 10) + +#define SE_RSA_KEYTABLE_DATA_REG 0x424 + +#define SE_RSA_OUTPUT_REG 0x428 +#define SE_RSA_OUTPUT_REG_COUNT 64 + +#define SE_STATUS_REG 0x800 +#define SE_STATUS_STATE_IDLE 0 +#define SE_STATUS_STATE_BUSY 1 +#define SE_STATUS_STATE_WAIT_OUT 2 +#define SE_STATUS_STATE_WAIT_IN 3 +#define SE_STATUS_STATE_MASK 3 +#define SE_STATUS_MEM_IF_IDLE (0 << 2) +#define SE_STATUS_MEM_IF_BUSY BIT(2) + +#define SE_ERR_STATUS_REG 0x804 +#define SE_ERR_STATUS_SE_NS_ACCESS BIT(0) +#define SE_ERR_STATUS_BUSY_REG_WR BIT(1) +#define SE_ERR_STATUS_DST BIT(2) +#define SE_ERR_STATUS_SRK_USAGE_LIMIT BIT(3) +#define SE_ERR_STATUS_TZRAM_NS_ACCESS BIT(24) +#define SE_ERR_STATUS_TZRAM_ADDRESS BIT(25) + +#define SE_MISC_REG 0x808 +#define SE_ENTROPY_NEXT_192BIT BIT(0) +#define SE_ENTROPY_VN_BYPASS BIT(1) +#define SE_CLK_OVR_ON BIT(2) + +#define SE_SPARE_REG 0x80C +#define SE_ERRATA_FIX_DISABLE 0 +#define SE_ERRATA_FIX_ENABLE 1 +#define SE_ECO(x) ((x) << 0) + +#endif diff --git a/nyx/nyx_gui/sec/tsec.c b/bdk/sec/tsec.c similarity index 51% rename from nyx/nyx_gui/sec/tsec.c rename to bdk/sec/tsec.c index 7c9f1e6..de2dbbb 100644 --- a/nyx/nyx_gui/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -18,20 +18,25 @@ #include -#include "../sec/tsec.h" -#include "../sec/tsec_t210.h" -#include "../sec/se_t210.h" -#include "../soc/bpmp.h" -#include "../soc/clock.h" -#include "../soc/kfuse.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../utils/util.h" -#include "../hos/hos.h" +#include "tsec.h" +#include "tsec_t210.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -// #include "../gfx/gfx.h" +// #include + +#define PKG11_MAGIC 0x31314B50 + +#define TSEC_HOS_KB_620 6 static int _tsec_dma_wait_idle() { @@ -53,48 +58,62 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse else cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory) - TSEC(TSEC_DMATRFMOFFS) = i_offset; + TSEC(TSEC_DMATRFMOFFS) = i_offset; TSEC(TSEC_DMATRFFBOFFS) = pa_offset; - TSEC(TSEC_DMATRFCMD) = cmd; + TSEC(TSEC_DMATRFCMD) = cmd; return _tsec_dma_wait_idle(); } -int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) +int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt) { int res = 0; u8 *fwbuf = NULL; - u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; + u32 type = tsec_ctxt->type; + u32 *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; u32 *pkg11_magic_off; + void *ptb; bpmp_mmu_disable(); - bpmp_clk_rate_set(BPMP_CLK_NORMAL); + bpmp_clk_rate_relaxed(true); // Enable clocks. - clock_enable_host1x(); - usleep(2); clock_enable_tsec(); clock_enable_sor_safe(); clock_enable_sor0(); clock_enable_sor1(); clock_enable_kfuse(); - kfuse_wait_ready(); + // Disable AHB aperture. + mc_disable_ahb_redirect(); + + if (type == TSEC_FW_TYPE_NEW) + { + // Disable all CCPLEX core rails. + pmc_enable_partition(POWER_RAIL_CE0, DISABLE); + pmc_enable_partition(POWER_RAIL_CE1, DISABLE); + pmc_enable_partition(POWER_RAIL_CE2, DISABLE); + pmc_enable_partition(POWER_RAIL_CE3, DISABLE); + + // Enable AHB aperture and set it to full mmio. + mc_enable_ahb_redirect(); + } + // Configure Falcon. TSEC(TSEC_DMACTL) = 0; TSEC(TSEC_IRQMSET) = TSEC_IRQMSET_EXT(0xFF) | - TSEC_IRQMSET_WDTMR | - TSEC_IRQMSET_HALT | - TSEC_IRQMSET_EXTERR | - TSEC_IRQMSET_SWGEN0 | + TSEC_IRQMSET_WDTMR | + TSEC_IRQMSET_HALT | + TSEC_IRQMSET_EXTERR | + TSEC_IRQMSET_SWGEN0 | TSEC_IRQMSET_SWGEN1; TSEC(TSEC_IRQDEST) = TSEC_IRQDEST_EXT(0xFF) | - TSEC_IRQDEST_HALT | - TSEC_IRQDEST_EXTERR | - TSEC_IRQDEST_SWGEN0 | + TSEC_IRQDEST_HALT | + TSEC_IRQDEST_EXTERR | + TSEC_IRQDEST_SWGEN0 | TSEC_IRQDEST_SWGEN1; TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN; if (!_tsec_dma_wait_idle()) @@ -104,13 +123,14 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } // Load firmware or emulate memio environment for newer TSEC fw. - if (kb == KB_FIRMWARE_VERSION_620) + if (type == TSEC_FW_TYPE_EMU) TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; else { - fwbuf = (u8 *)malloc(0x4000); + fwbuf = (u8 *)malloc(SZ_16K); u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100); memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size); + TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8; } @@ -123,94 +143,94 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } } - if (kb == KB_FIRMWARE_VERSION_620) + if (type == TSEC_FW_TYPE_EMU) { // Init SMMU translation for TSEC. - pdir = smmu_init_for_tsec(); - smmu_init(tsec_ctxt->secmon_base); - // Enable SMMU - if (!smmu_is_used()) - smmu_enable(); + ptb = smmu_init_domain(MC_SMMU_TSEC_ASID, 1); + smmu_init(); + + // Enable SMMU. + smmu_enable(); // Clock reset controller. - car = page_alloc(1); - memcpy(car, (void *)CLOCK_BASE, 0x1000); - car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; - smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); + car = smmu_page_zalloc(1); + memcpy(car, (void *)CLOCK_BASE, SZ_PAGE); + car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = CLK_SRC_DIV(2); + smmu_map(ptb, CLOCK_BASE, (u32)car, 1, SMMU_WRITE | SMMU_READ | SMMU_NS); // Fuse driver. - fuse = page_alloc(1); - memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); + fuse = smmu_page_zalloc(1); + memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, SZ_1K); fuse[0x82C / 4] = 0; - fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1; - fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1; - smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); + fuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; + fuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; + smmu_map(ptb, (FUSE_BASE - 0x800), (u32)fuse, 1, SMMU_READ | SMMU_NS); // Power management controller. - pmc = page_alloc(1); - smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); + pmc = smmu_page_zalloc(1); + smmu_map(ptb, RTC_BASE, (u32)pmc, 1, SMMU_READ | SMMU_NS); // Flow control. - flowctrl = page_alloc(1); - smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); + flowctrl = smmu_page_zalloc(1); + smmu_map(ptb, FLOW_CTLR_BASE, (u32)flowctrl, 1, SMMU_WRITE | SMMU_NS); // Security engine. - se = page_alloc(1); - memcpy(se, (void *)SE_BASE, 0x1000); - smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); + se = smmu_page_zalloc(1); + memcpy(se, (void *)SE_BASE, SZ_PAGE); + smmu_map(ptb, SE_BASE, (u32)se, 1, SMMU_READ | SMMU_WRITE | SMMU_NS); // Memory controller. - mc = page_alloc(1); - memcpy(mc, (void *)MC_BASE, 0x1000); + mc = smmu_page_zalloc(1); + memcpy(mc, (void *)MC_BASE, SZ_PAGE); mc[MC_IRAM_BOM / 4] = 0; - mc[MC_IRAM_TOM / 4] = 0x80000000; - smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); + mc[MC_IRAM_TOM / 4] = DRAM_START; + smmu_map(ptb, MC_BASE, (u32)mc, 1, SMMU_READ | SMMU_NS); // IRAM - iram = page_alloc(0x30); + iram = smmu_page_zalloc(0x30); memcpy(iram, tsec_ctxt->pkg1, 0x30000); // PKG1.1 magic offset. - pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)); - smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); + pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / sizeof(u32))); + smmu_map(ptb, 0x40010000, (u32)iram, 0x30, SMMU_READ | SMMU_WRITE | SMMU_NS); // Exception vectors - evec = page_alloc(1); - smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); + evec = smmu_page_zalloc(1); + smmu_map(ptb, EXCP_VEC_BASE, (u32)evec, 1, SMMU_READ | SMMU_WRITE | SMMU_NS); } // Execute firmware. HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; - TSEC(TSEC_STATUS) = 0; - TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. - TSEC(TSEC_BOOTVEC) = 0; - TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; + TSEC(TSEC_MAILBOX1) = 0; + TSEC(TSEC_MAILBOX0) = 1; // Set HOS key version. + TSEC(TSEC_BOOTVEC) = 0; + TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; - if (kb == KB_FIRMWARE_VERSION_620) + if (type == TSEC_FW_TYPE_EMU) { - u32 start = get_tmr_us(); - u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; + u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; + u32 timeout = get_tmr_us() + 125000; u32 key[16] = {0}; u32 kidx = 0; - while (*pkg11_magic_off != HOS_PKG11_MAGIC) + while (*pkg11_magic_off != PKG11_MAGIC) { smmu_flush_all(); - if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]) + if (k != se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]) { - k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; + k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; key[kidx++] = k; } // Failsafe. - if ((u32)get_tmr_us() - start > 125000) + if ((u32)get_tmr_us() > timeout) break; } if (kidx != 8) { res = -6; - smmu_deinit_for_tsec(); + smmu_deinit_domain(MC_SMMU_TSEC_ASID, 1); goto out_free; } @@ -221,12 +241,12 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) memcpy(tsec_keys, &key, 0x20); memcpy(tsec_ctxt->pkg1, iram, 0x30000); - smmu_deinit_for_tsec(); + smmu_deinit_domain(MC_SMMU_TSEC_ASID, 1); // for (int i = 0; i < kidx; i++) // gfx_printf("key %08X\n", key[i]); - // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); + // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_MAILBOX1)); // u32 errst = MC(MC_ERR_STATUS); // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); @@ -242,14 +262,18 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) res = -3; goto out_free; } + u32 timeout = get_tmr_ms() + 2000; - while (!TSEC(TSEC_STATUS)) + while (!TSEC(TSEC_MAILBOX1)) + { if (get_tmr_ms() > timeout) { res = -4; goto out_free; } - if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) + } + + if (TSEC(TSEC_MAILBOX1) != 0xB0B0B0B0) { res = -5; goto out_free; @@ -258,23 +282,22 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) // Fetch result. HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; u32 buf[4]; - buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); - buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); - buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); - buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); - SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; + buf[0] = SOR1(SOR_DP_HDCP_BKSV_LSB); + buf[1] = SOR1(SOR_TMDS_HDCP_BKSV_LSB); + buf[2] = SOR1(SOR_TMDS_HDCP_CN_MSB); + buf[3] = SOR1(SOR_TMDS_HDCP_CN_LSB); + SOR1(SOR_DP_HDCP_BKSV_LSB) = 0; + SOR1(SOR_TMDS_HDCP_BKSV_LSB) = 0; + SOR1(SOR_TMDS_HDCP_CN_MSB) = 0; + SOR1(SOR_TMDS_HDCP_CN_LSB) = 0; - memcpy(tsec_keys, &buf, 0x10); + memcpy(tsec_keys, &buf, SE_KEY_128_SIZE); } -out_free:; +out_free: free(fwbuf); -out:; - +out: // Disable clocks. clock_disable_kfuse(); clock_disable_sor1(); @@ -282,7 +305,12 @@ out:; clock_disable_sor_safe(); clock_disable_tsec(); bpmp_mmu_enable(); - bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + bpmp_clk_rate_relaxed(false); + +#ifdef BDK_MC_ENABLE_AHB_REDIRECT + // Re-enable AHB aperture. + mc_enable_ahb_redirect(); +#endif return res; } diff --git a/bootloader/sec/tsec.h b/bdk/sec/tsec.h similarity index 71% rename from bootloader/sec/tsec.h rename to bdk/sec/tsec.h index 45d994c..16aa4b7 100644 --- a/bootloader/sec/tsec.h +++ b/bdk/sec/tsec.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer +* Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,17 +18,25 @@ #ifndef _TSEC_H_ #define _TSEC_H_ -#include "../utils/types.h" +#include + +enum tsec_fw_type +{ + // Retail Hovi Keygen. + TSEC_FW_TYPE_OLD = 0, // 1.0.0 - 6.1.0. + TSEC_FW_TYPE_EMU = 1, // 6.2.0 emulated environment. + TSEC_FW_TYPE_NEW = 2, // 7.0.0+. +}; typedef struct _tsec_ctxt_t { void *fw; u32 size; + u32 type; void *pkg1; u32 pkg11_off; - u32 secmon_base; } tsec_ctxt_t; -int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); +int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt); #endif diff --git a/bootloader/sec/tsec_t210.h b/bdk/sec/tsec_t210.h similarity index 61% rename from bootloader/sec/tsec_t210.h rename to bdk/sec/tsec_t210.h index befe269..96624e2 100644 --- a/bootloader/sec/tsec_t210.h +++ b/bdk/sec/tsec_t210.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018 CTCaer +* Copyright (c) 2018-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,33 +17,33 @@ #ifndef _TSEC_T210_H_ #define _TSEC_T210_H_ -#define TSEC_BOOTKEYVER 0x1040 -#define TSEC_STATUS 0x1044 +#define TSEC_MAILBOX0 0x1040 +#define TSEC_MAILBOX1 0x1044 #define TSEC_ITFEN 0x1048 -#define TSEC_ITFEN_CTXEN (1 << 0) -#define TSEC_ITFEN_MTHDEN (1 << 1) +#define TSEC_ITFEN_CTXEN BIT(0) +#define TSEC_ITFEN_MTHDEN BIT(1) #define TSEC_IRQMSET 0x1010 -#define TSEC_IRQMSET_WDTMR (1 << 1) -#define TSEC_IRQMSET_HALT (1 << 4) -#define TSEC_IRQMSET_EXTERR (1 << 5) -#define TSEC_IRQMSET_SWGEN0 (1 << 6) -#define TSEC_IRQMSET_SWGEN1 (1 << 7) +#define TSEC_IRQMSET_WDTMR BIT(1) +#define TSEC_IRQMSET_HALT BIT(4) +#define TSEC_IRQMSET_EXTERR BIT(5) +#define TSEC_IRQMSET_SWGEN0 BIT(6) +#define TSEC_IRQMSET_SWGEN1 BIT(7) #define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8) #define TSEC_IRQDEST 0x101C -#define TSEC_IRQDEST_HALT (1 << 4) -#define TSEC_IRQDEST_EXTERR (1 << 5) -#define TSEC_IRQDEST_SWGEN0 (1 << 6) -#define TSEC_IRQDEST_SWGEN1 (1 << 7) +#define TSEC_IRQDEST_HALT BIT(4) +#define TSEC_IRQDEST_EXTERR BIT(5) +#define TSEC_IRQDEST_SWGEN0 BIT(6) +#define TSEC_IRQDEST_SWGEN1 BIT(7) #define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) #define TSEC_CPUCTL 0x1100 -#define TSEC_CPUCTL_STARTCPU (1 << 1) +#define TSEC_CPUCTL_STARTCPU BIT(1) #define TSEC_BOOTVEC 0x1104 #define TSEC_DMACTL 0x110C #define TSEC_DMATRFBASE 0x1110 #define TSEC_DMATRFMOFFS 0x1114 #define TSEC_DMATRFCMD 0x1118 -#define TSEC_DMATRFCMD_IDLE (1 << 1) -#define TSEC_DMATRFCMD_IMEM (1 << 4) +#define TSEC_DMATRFCMD_IDLE BIT(1) +#define TSEC_DMATRFCMD_IMEM BIT(4) #define TSEC_DMATRFCMD_SIZE_256B (6 << 8) #define TSEC_DMATRFFBOFFS 0x111C diff --git a/bdk/soc/actmon.c b/bdk/soc/actmon.c new file mode 100644 index 0000000..568f82e --- /dev/null +++ b/bdk/soc/actmon.c @@ -0,0 +1,172 @@ +/* + * Activity Monitor driver for Tegra X1 + * + * Copyright (c) 2021 CTCaer + * + * 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 "actmon.h" +#include "clock.h" +#include "t210.h" + +/* Global registers */ +#define ACTMON_GLB_STATUS 0x0 +#define ACTMON_MCCPU_MON_ACT BIT(8) +#define ACTMON_MCALL_MON_ACT BIT(9) +#define ACTMON_CPU_FREQ_MON_ACT BIT(10) +#define ACTMON_APB_MON_ACT BIT(12) +#define ACTMON_AHB_MON_ACT BIT(13) +#define ACTMON_BPMP_MON_ACT BIT(14) +#define ACTMON_CPU_MON_ACT BIT(15) +#define ACTMON_MCCPU_INTR BIT(25) +#define ACTMON_MCALL_INTR BIT(26) +#define ACTMON_CPU_FREQ_INTR BIT(27) +#define ACTMON_APB_INTR BIT(28) +#define ACTMON_AHB_INTR BIT(29) +#define ACTMON_BPMP_INTR BIT(30) +#define ACTMON_CPU_INTR BIT(31) +#define ACTMON_GLB_PERIOD_CTRL 0x4 +#define ACTMON_GLB_PERIOD_USEC BIT(8) +#define ACTMON_GLB_PERIOD_SAMPLE(n) (((n) - 1) & 0xFF) + +/* Device Registers */ +#define ACTMON_DEV_BASE ACTMON_BASE + 0x80 +#define ACTMON_DEV_SIZE 0x40 +/* CTRL */ +#define ACTMON_DEV_CTRL_K_VAL(k) (((k) & 7) << 10) +#define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18) +#define ACTMON_DEV_CTRL_AT_END_EN BIT(19) +#define ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN BIT(20) +#define ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN BIT(21) +#define ACTMON_DEV_CTRL_WHEN_OVERFLOW_EN BIT(22) +#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM(n) (((n) & 7) << 23) +#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM(n) (((n) & 7) << 26) +#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN BIT(29) +#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN BIT(30) +#define ACTMON_DEV_CTRL_ENB BIT(31) +/* INTR_STATUS */ +#define ACTMON_DEV_ISTS_AVG_ABOVE_WMARK BIT(24) +#define ACTMON_DEV_ISTS_AVG_BELOW_WMARK BIT(25) +#define ACTMON_DEV_ISTS_WHEN_OVERFLOW BIT(26) +#define ACTMON_DEV_ISTS_AT_END BIT(29) +#define ACTMON_DEV_ISTS_CONSECUTIVE_LOWER BIT(30) +#define ACTMON_DEV_ISTS_CONSECUTIVE_UPPER BIT(31) + +/* Histogram Registers */ +#define ACTMON_HISTOGRAM_CONFIG 0x300 +#define ACTMON_HIST_CFG_ACTIVE BIT(0) +#define ACTMON_HIST_CFG_LINEAR_MODE BIT(1) +#define ACTMON_HIST_CFG_NO_UNDERFLOW_BUCKET BIT(2) +#define ACTMON_HIST_CFG_STALL_ON_SINGLE_SATURATE BIT(3) +#define ACTMON_HIST_CFG_SHIFT(s) (((s) & 0x1F) << 4) +#define ACTMON_HIST_CFG_SOURCE(s) (((s) & 0xF) << 12) +#define ACTMON_HISTOGRAM_CTRL 0x304 +#define ACTMON_HIST_CTRL_CLEAR_ALL BIT(0) +#define ACTMON_HISTOGRAM_DATA_BASE 0x380 +#define ACTMON_HISTOGRAM_DATA_NUM 32 + +#define ACTMON_FREQ 19200000 +#define ACTMON_PERIOD_MS 20 +#define DEV_COUNT_WEIGHT 5 + +typedef struct _actmon_dev_reg_t +{ + vu32 ctrl; + vu32 upper_wnark; + vu32 lower_wmark; + vu32 init_avg; + vu32 avg_upper_wmark; + vu32 avg_lower_wmark; + vu32 count_weight; + vu32 count; + vu32 avg_count; + vu32 intr_status; + vu32 ctrl2; + vu32 rsvd[5]; +} actmon_dev_reg_t; + +void actmon_hist_enable(actmon_hist_src_t src) +{ + ACTMON(ACTMON_HISTOGRAM_CONFIG) = ACTMON_HIST_CFG_SOURCE(src) | ACTMON_HIST_CFG_ACTIVE; + ACTMON(ACTMON_HISTOGRAM_CTRL) = ACTMON_HIST_CTRL_CLEAR_ALL; +} + +void actmon_hist_disable() +{ + ACTMON(ACTMON_HISTOGRAM_CONFIG) = 0; +} + +void actmon_hist_get(u32 *histogram) +{ + if (histogram) + { + for (u32 i = 0; i < ACTMON_HISTOGRAM_DATA_NUM; i++) + histogram[i] = ACTMON(ACTMON_HISTOGRAM_DATA_BASE + i * sizeof(u32)); + } +} + +void actmon_dev_enable(actmon_dev_t dev) +{ + actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); + + regs->init_avg = ACTMON_FREQ * ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT / 100; + regs->count_weight = DEV_COUNT_WEIGHT; + + regs->ctrl = ACTMON_DEV_CTRL_ENB | ACTMON_DEV_CTRL_ENB_PERIODIC | ACTMON_DEV_CTRL_K_VAL(7); // 128 samples average. +} + +void actmon_dev_disable(actmon_dev_t dev) +{ + actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); + + regs->ctrl = 0; +} + +u32 actmon_dev_get_load(actmon_dev_t dev) +{ + actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); + + // Get load-based sampling. 1 decimal point precision. + u32 load = regs->count * 100 / (ACTMON_FREQ / (ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT)); + + return load; +} + +u32 actmon_dev_get_load_avg(actmon_dev_t dev) +{ + actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); + + // Get load-based sampling. 1 decimal point precision. + u32 avg_load = regs->avg_count * 100 / (ACTMON_FREQ / (ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT)); + + return avg_load; +} + +void atmon_dev_all_disable() +{ + // TODO: do a global reset? +} + +void actmon_init() +{ + clock_enable_actmon(); + + // Set period. + ACTMON(ACTMON_GLB_PERIOD_CTRL) = ACTMON_GLB_PERIOD_SAMPLE(ACTMON_PERIOD_MS); +} + +void actmon_end() +{ + clock_disable_actmon(); +} \ No newline at end of file diff --git a/bdk/soc/actmon.h b/bdk/soc/actmon.h new file mode 100644 index 0000000..dc9d0c5 --- /dev/null +++ b/bdk/soc/actmon.h @@ -0,0 +1,62 @@ +/* + * Activity Monitor driver for Tegra X1 + * + * Copyright (c) 2021 CTCaer + * + * 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 __ACTMON_H_ +#define __ACTMON_H_ + +#include + +typedef enum _actmon_dev_t +{ + ACTMON_DEV_CPU, + ACTMON_DEV_BPMP, + ACTMON_DEV_AHB, + ACTMON_DEV_APB, + ACTMON_DEV_CPU_FREQ, + ACTMON_DEV_MC_ALL, + ACTMON_DEV_MC_CPU, + + ACTMON_DEV_NUM, +} actmon_dev_t; + +typedef enum _actmon_hist_src_t +{ + ACTMON_HIST_SRC_NONE = 0, + ACTMON_HIST_SRC_AHB = 1, + ACTMON_HIST_SRC_APB = 2, + ACTMON_HIST_SRC_BPMP = 3, + ACTMON_HIST_SRC_CPU = 4, + ACTMON_HIST_SRC_MC_ALL = 5, + ACTMON_HIST_SRC_MC_CPU = 6, + ACTMON_HIST_SRC_CPU_FREQ = 7, + ACTMON_HIST_SRC_NA = 8, + ACTMON_HIST_SRC_APB_MMIO = 9, +} actmon_hist_src_t; + +void actmon_hist_enable(actmon_hist_src_t src); +void actmon_hist_disable(); +void actmon_hist_get(u32 *histogram); +void actmon_dev_enable(actmon_dev_t dev); +void actmon_dev_disable(actmon_dev_t dev); +u32 actmon_dev_get_load(actmon_dev_t dev); +u32 actmon_dev_get_load_avg(actmon_dev_t dev); +void atmon_dev_all_disable(); +void actmon_init(); +void actmon_end(); + +#endif \ No newline at end of file diff --git a/nyx/nyx_gui/soc/bpmp.c b/bdk/soc/bpmp.c similarity index 61% rename from nyx/nyx_gui/soc/bpmp.c rename to bdk/soc/bpmp.c index 3784b21..3979c2a 100644 --- a/nyx/nyx_gui/soc/bpmp.c +++ b/bdk/soc/bpmp.c @@ -1,7 +1,7 @@ /* * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,47 +16,47 @@ * along with this program. If not, see . */ -#include "bpmp.h" -#include "clock.h" -#include "t210.h" -#include "../../../common/memory_map.h" -#include "../utils/util.h" +#include +#include +#include +#include +#include #define BPMP_MMU_CACHE_LINE_SIZE 0x20 #define BPMP_CACHE_CONFIG 0x0 -#define CFG_ENABLE_CACHE (1 << 0) -#define CFG_ENABLE_SKEW_ASSOC (1 << 1) -#define CFG_DISABLE_RANDOM_ALLOC (1 << 2) -#define CFG_FORCE_WRITE_THROUGH (1 << 3) -#define CFG_NEVER_ALLOCATE (1 << 6) -#define CFG_ENABLE_INTERRUPT (1 << 7) -#define CFG_MMU_TAG_MODE(x) (x << 8) +#define CFG_ENABLE_CACHE BIT(0) +#define CFG_ENABLE_SKEW_ASSOC BIT(1) +#define CFG_DISABLE_RANDOM_ALLOC BIT(2) +#define CFG_FORCE_WRITE_THROUGH BIT(3) +#define CFG_NEVER_ALLOCATE BIT(6) +#define CFG_ENABLE_INTERRUPT BIT(7) +#define CFG_MMU_TAG_MODE(x) ((x) << 8) #define TAG_MODE_PARALLEL 0 #define TAG_MODE_TAG_FIRST 1 #define TAG_MODE_MMU_FIRST 2 -#define CFG_DISABLE_WRITE_BUFFER (1 << 10) -#define CFG_DISABLE_READ_BUFFER (1 << 11) -#define CFG_ENABLE_HANG_DETECT (1 << 12) -#define CFG_FULL_LINE_DIRTY (1 << 13) -#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14) -#define CFG_TAG_CHK_CLR_ERR (1 << 15) -#define CFG_DISABLE_SAMELINE (1 << 16) -#define CFG_OBS_BUS_EN (1 << 31) +#define CFG_DISABLE_WRITE_BUFFER BIT(10) +#define CFG_DISABLE_READ_BUFFER BIT(11) +#define CFG_ENABLE_HANG_DETECT BIT(12) +#define CFG_FULL_LINE_DIRTY BIT(13) +#define CFG_TAG_CHK_ABRT_ON_ERR BIT(14) +#define CFG_TAG_CHK_CLR_ERR BIT(15) +#define CFG_DISABLE_SAMELINE BIT(16) +#define CFG_OBS_BUS_EN BIT(31) #define BPMP_CACHE_LOCK 0x4 -#define LOCK_LINE(x) (1 << x) +#define LOCK_LINE(x) BIT((x)) #define BPMP_CACHE_SIZE 0xC #define BPMP_CACHE_LFSR 0x10 #define BPMP_CACHE_TAG_STATUS 0x14 -#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0) +#define TAG_STATUS_TAG_CHECK_ERROR BIT(0) #define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0 #define BPMP_CACHE_CLKEN_OVERRIDE 0x18 -#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0) -#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1) +#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN BIT(0) +#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN BIT(1) #define BPMP_CACHE_MAINT_ADDR 0x20 #define BPMP_CACHE_MAINT_DATA 0x24 @@ -68,8 +68,8 @@ #define BPMP_CACHE_INT_CLEAR 0x44 #define BPMP_CACHE_INT_RAW_EVENT 0x48 #define BPMP_CACHE_INT_STATUS 0x4C -#define INT_MAINT_DONE (1 << 0) -#define INT_MAINT_ERROR (1 << 1) +#define INT_MAINT_DONE BIT(0) +#define INT_MAINT_ERROR BIT(1) #define BPMP_CACHE_RB_CFG 0x80 #define BPMP_CACHE_WB_CFG 0x84 @@ -78,12 +78,12 @@ #define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 #define BPMP_CACHE_MMU_CFG 0xAC -#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0) -#define MMU_CFG_SEQ_EN (1 << 1) -#define MMU_CFG_TLB_EN (1 << 2) -#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3) -#define MMU_CFG_ABORT_STORE_LAST (1 << 4) -#define MMU_CFG_CLR_ABORT (1 << 5) +#define MMU_CFG_BLOCK_MAIN_ENTRY_WR BIT(0) +#define MMU_CFG_SEQ_EN BIT(1) +#define MMU_CFG_TLB_EN BIT(2) +#define MMU_CFG_SEG_CHECK_ALL_ENTRIES BIT(3) +#define MMU_CFG_ABORT_STORE_LAST BIT(4) +#define MMU_CFG_CLR_ABORT BIT(5) #define BPMP_CACHE_MMU_CMD 0xB0 #define MMU_CMD_NOP 0 @@ -98,27 +98,27 @@ #define ABORT_STAT_UNIT_TLB 3 #define ABORT_STAT_UNIT_SEG 4 #define ABORT_STAT_UNIT_FALLBACK 5 -#define ABORT_STAT_OVERLAP (1 << 3) +#define ABORT_STAT_OVERLAP BIT(3) #define ABORT_STAT_ENTRY (0x1F << 4) #define ABORT_STAT_TYPE_MASK (3 << 16) #define ABORT_STAT_TYPE_EXE (0 << 16) #define ABORT_STAT_TYPE_RD (1 << 16) #define ABORT_STAT_TYPE_WR (2 << 16) #define ABORT_STAT_SIZE (3 << 18) -#define ABORT_STAT_SEQ (1 << 20) -#define ABORT_STAT_PROT (1 << 21) +#define ABORT_STAT_SEQ BIT(20) +#define ABORT_STAT_PROT BIT(21) #define BPMP_CACHE_MMU_ABORT_ADDR 0xB8 #define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC #define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) #define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) -#define MMU_EN_CACHED (1 << 0) -#define MMU_EN_EXEC (1 << 1) -#define MMU_EN_READ (1 << 2) -#define MMU_EN_WRITE (1 << 3) +#define MMU_EN_CACHED BIT(0) +#define MMU_EN_EXEC BIT(1) +#define MMU_EN_READ BIT(2) +#define MMU_EN_WRITE BIT(3) -bpmp_mmu_entry_t mmu_entries[] = +static const bpmp_mmu_entry_t mmu_entries[] = { { DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }, { IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true } @@ -134,13 +134,13 @@ void bpmp_mmu_maintenance(u32 op, bool force) // This is a blocking operation. BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op; - while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE)) + while (!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE)) ; BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT); } -void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) +void bpmp_mmu_set_entry(int idx, const bpmp_mmu_entry_t *entry, bool apply) { if (idx > 31) return; @@ -150,10 +150,10 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) if (entry->enable) { mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE); - mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE); - mmu_entry->attr = entry->attr; + mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE); + mmu_entry->attr = entry->attr; - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx); + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= BIT(idx); if (apply) BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; @@ -166,13 +166,13 @@ void bpmp_mmu_enable() return; // Init BPMP MMU. - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT; + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT; BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions. - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST; + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST; // Init BPMP MMU entries. BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0; - for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++) + for (u32 idx = 0; idx < ARRAY_SIZE(mmu_entries); idx++) bpmp_mmu_set_entry(idx, &mmu_entries[idx], false); BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; @@ -200,36 +200,70 @@ void bpmp_mmu_disable() BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; } + +/* + * CLK_RST_CONTROLLER_SCLK_BURST_POLICY: + * 0 = CLKM + * 1 = PLLC_OUT1 + * 2 = PLLC4_OUT3 + * 3 = PLLP_OUT0 + * 4 = PLLP_OUT2 + * 5 = PLLC4_OUT1 + * 6 = CLK_S + * 7 = PLLC4_OUT2 + */ + +bpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL; + +void bpmp_clk_rate_relaxed(bool enable) +{ + // This is a glitch-free way to reduce the SCLK timings. + if (enable) + { + // Restore to PLLP source during PLLC configuration. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT. + usleep(100); // Wait a bit for clock source change. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK. + } + else if (bpmp_fid_current) + { + // Restore to PLLC_OUT1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 and CLKM for idle. + usleep(100); // Wait a bit for clock source change. + } +} + // APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM, // I2C host, DC/DSI/DISP. UART gives extra stress. // 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less. -const u8 pll_divn[] = { +// APB clock max is supposed to be 204 MHz though. +static const u8 pll_divn[] = { 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB. 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. + 88, // BPMP_CLK_HIGH2_BOOST: 563MHz 38% - 141MHz APB. 90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB. 92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB. // Do not use for public releases! //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB. }; -bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; - void bpmp_clk_rate_get() { bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3; if (clk_src_is_pllp) - bpmp_clock_set = BPMP_CLK_NORMAL; + bpmp_fid_current = BPMP_CLK_NORMAL; else { - bpmp_clock_set = BPMP_CLK_HIGH_BOOST; + bpmp_fid_current = BPMP_CLK_HIGH_BOOST; u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; for (u32 i = 1; i < sizeof(pll_divn); i++) { if (pll_divn[i] == pll_divn_curr) { - bpmp_clock_set = i; + bpmp_fid_current = i; break; } } @@ -241,35 +275,37 @@ void bpmp_clk_rate_set(bpmp_freq_t fid) if (fid > (BPMP_CLK_MAX - 1)) fid = BPMP_CLK_MAX - 1; - if (bpmp_clock_set == fid) + if (bpmp_fid_current == fid) return; + bpmp_fid_current = fid; + if (fid) { - if (bpmp_clock_set) - { - // Restore to PLLP source during PLLC4 configuration. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. - msleep(1); // Wait a bit for clock source change. - } + // Use default SCLK / HCLK / PCLK clocks. + bpmp_clk_rate_relaxed(true); // Configure and enable PLLC. clock_enable_pllc(pll_divn[fid]); - // Set SCLK / HCLK / PCLK. - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle. + // Set new source and SCLK / HCLK / PCLK dividers. + bpmp_clk_rate_relaxed(false); } else { - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle. - msleep(1); // Wait a bit for clock source change. - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK. + // Use default SCLK / HCLK / PCLK clocks. + bpmp_clk_rate_relaxed(true); // Disable PLLC to save power. clock_disable_pllc(); } - bpmp_clock_set = fid; +} + +// State is reset to RUN on any clock or source set via SW. +void bpmp_state_set(bpmp_state_t state) +{ + u32 cfg = CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & ~0xF0000000u; + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = cfg | (state << 28u); } // The following functions halt BPMP to reduce power while sleeping. @@ -281,10 +317,10 @@ void bpmp_usleep(u32 us) // Each iteration takes 1us. while (us) { - delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; + delay = (us > HALT_MAX_CNT) ? HALT_MAX_CNT : us; us -= delay; - FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_USEC | delay; } } @@ -295,15 +331,14 @@ void bpmp_msleep(u32 ms) // Iteration time is variable. ~200 - 1000us. while (ms) { - delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; + delay = (ms > HALT_MAX_CNT) ? HALT_MAX_CNT : ms; ms -= delay; - FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_MSEC | delay; } } void bpmp_halt() { - FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_JTAG; } - diff --git a/nyx/nyx_gui/soc/bpmp.h b/bdk/soc/bpmp.h similarity index 77% rename from nyx/nyx_gui/soc/bpmp.h rename to bdk/soc/bpmp.h index dce62cc..ace1290 100644 --- a/nyx/nyx_gui/soc/bpmp.h +++ b/bdk/soc/bpmp.h @@ -1,7 +1,7 @@ /* * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,7 +19,7 @@ #ifndef _BPMP_H_ #define _BPMP_H_ -#include "../utils/types.h" +#include typedef enum { @@ -47,20 +47,35 @@ typedef enum { BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB. BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB. + BPMP_CLK_HIGH2_BOOST, // 563MHz 38% - 141MHz APB. BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB. BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB. //BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB. BPMP_CLK_MAX } bpmp_freq_t; +typedef enum +{ + BPMP_STATE_STANDBY = 0, // 32KHz. + BPMP_STATE_IDLE = 1, + BPMP_STATE_RUN = 2, + + BPMP_STATE_IRQ = BIT(2), + BPMP_STATE_FIQ = BIT(3), +} bpmp_state_t; + +#define BPMP_CLK_LOWEST_BOOST BPMP_CLK_HIGH2_BOOST +#define BPMP_CLK_LOWER_BOOST BPMP_CLK_SUPER_BOOST #define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST void bpmp_mmu_maintenance(u32 op, bool force); -void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); +void bpmp_mmu_set_entry(int idx, const bpmp_mmu_entry_t *entry, bool apply); void bpmp_mmu_enable(); void bpmp_mmu_disable(); +void bpmp_clk_rate_relaxed(bool enable); void bpmp_clk_rate_get(); void bpmp_clk_rate_set(bpmp_freq_t fid); +void bpmp_state_set(bpmp_state_t state); void bpmp_usleep(u32 us); void bpmp_msleep(u32 ms); void bpmp_halt(); diff --git a/bdk/soc/ccplex.c b/bdk/soc/ccplex.c new file mode 100644 index 0000000..c01a892 --- /dev/null +++ b/bdk/soc/ccplex.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CCPLEX_FLOWCTRL_POWERGATING 0 + +static void _ccplex_enable_power_t210() +{ + // Configure GPIO5 and enable output in order to power CPU pmic. + max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_ENABLE); + + // Configure CPU pmic. + // 1-3.x: MAX77621_NFSR_ENABLE. + // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. + max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_HOS_CFG); + + // Set voltage and enable cluster power. + max7762x_regulator_set_voltage(REGULATOR_CPU0, 950000); + max7762x_regulator_enable(REGULATOR_CPU0, true); +} + +static void _ccplex_enable_power_t210b01() +{ + // Set voltage and enable cluster power. + max7762x_regulator_set_voltage(REGULATOR_CPU1, 800000); + max7762x_regulator_enable(REGULATOR_CPU1, true); +} + +static void _ccplex_disable_power() +{ + // Disable cluster power. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + max7762x_regulator_enable(REGULATOR_CPU0, false); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 0); + } + else + max7762x_regulator_enable(REGULATOR_CPU1, false); +} + +void ccplex_boot_cpu0(u32 entry, bool lock) +{ + // Set ACTIVE_CLUSER to FAST. + FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= ~CLUSTER_CTRL_ACTIVE_SLOW; + + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + _ccplex_enable_power_t210(); + else + _ccplex_enable_power_t210b01(); + + clock_enable_pllx(); + + // Configure MSELECT source and enable clock to 102MHz. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (0 << 29) | CLK_SRC_DIV(4); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_MSELECT); + + // Configure initial CPU clock frequency and enable clock. + CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; // PLLX_OUT0_LJ. + CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = BIT(31); // SUPER_CDIV_ENB. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_CPUG); + + clock_enable_coresight(); + + // CAR2PMC_CPU_ACK_WIDTH should be set to 0. + CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; + + // Enable CPU main rail. + pmc_enable_partition(POWER_RAIL_CRAIL, ENABLE); + // Enable cluster 0 non-CPU rail. + pmc_enable_partition(POWER_RAIL_C0NC, ENABLE); + // Enable CPU0 rail. + pmc_enable_partition(POWER_RAIL_CE0, ENABLE); + + // Request and wait for RAM repair. Needed for the Fast cluster. + FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = RAM_REPAIR_REQ; + while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & RAM_REPAIR_STS)) + ; + + EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; + + // Set reset vector. + SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; + SB(SB_AA64_RESET_HIGH) = 0; + + // Non-secure reset vector write disable. + if (lock) + { + SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; + (void)SB(SB_CSR); + } + + // Tighten up the security aperture. + // MC(MC_TZ_SECURITY_CTRL) = 1; + + // Clear MSELECT reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_CLR) = BIT(CLK_V_MSELECT); + // Clear NONCPU reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = BIT(29); // CLR_NONCPURESET. + // Clear CPU0 reset. + // < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = BIT(30) | BIT(24) | BIT(16) | BIT(0); +} + +void ccplex_powergate_cpu0() +{ +#if CCPLEX_FLOWCTRL_POWERGATING + // Halt CPU0. + FLOW_CTLR(FLOW_CTLR_HALT_CPU0_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ; + + // Powergate cluster via flow control without waiting for WFI. + FLOW_CTLR(FLOW_CTLR_CPU0_CSR) = CSR_INTR_FLAG | CSR_EVENT_FLAG | CSR_ENABLE_EXT_CPU_RAIL | CSR_WAIT_WFI_NONE | CSR_ENABLE; + + // Wait for the rail power off to finish. + while((FLOW_CTLR(FLOW_CTLR_CPU_PWR_CSR) & CPU_PWR_RAIL_STS_MASK) != CPU_PWR_RAIL_OFF); + + // Set CPU0 to waitevent. + FLOW_CTLR(FLOW_CTLR_HALT_CPU0_EVENTS) = HALT_MODE_WAITEVENT; +#endif + + // Set CPU0 POR and CORE, CX0, L2, and DBG reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET) = BIT(30) | BIT(24) | BIT(16) | BIT(0); + // Set NONCPU reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET) = BIT(29); + // Set MSELECT reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_SET) = BIT(CLK_V_MSELECT); + + // Disable CE0. + pmc_enable_partition(POWER_RAIL_CE0, DISABLE); + // Disable cluster 0 non-CPU. + pmc_enable_partition(POWER_RAIL_C0NC, DISABLE); + // Disable CPU rail. + pmc_enable_partition(POWER_RAIL_CRAIL, DISABLE); + + clock_disable_coresight(); + + // Clear out MSELECT and CPU clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_CLR) = BIT(CLK_V_MSELECT) | BIT(CLK_V_CPUG); + + _ccplex_disable_power(); +} diff --git a/bootloader/soc/cluster.h b/bdk/soc/ccplex.h similarity index 82% rename from bootloader/soc/cluster.h rename to bdk/soc/ccplex.h index 428c046..496da43 100644 --- a/bootloader/soc/cluster.h +++ b/bdk/soc/ccplex.h @@ -14,11 +14,12 @@ * along with this program. If not, see . */ -#ifndef _CLUSTER_H_ -#define _CLUSTER_H_ +#ifndef _CCPLEX_H_ +#define _CCPLEX_H_ -#include "../utils/types.h" +#include -void cluster_boot_cpu0(u32 entry); +void ccplex_boot_cpu0(u32 entry, bool lock); +void ccplex_powergate_cpu0(); #endif diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c new file mode 100644 index 0000000..b3a48fa --- /dev/null +++ b/bdk/soc/clock.c @@ -0,0 +1,996 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer + * + * 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 +#include +#include +#include +#include +#include + +typedef struct _clock_osc_t +{ + u32 freq; + u16 min; + u16 max; +} clock_osc_t; + +static const clock_osc_t _clock_osc_cnt[] = { + { 12000, 706, 757 }, + { 13000, 766, 820 }, + { 16800, 991, 1059 }, + { 19200, 1133, 1210 }, + { 26000, 1535, 1638 }, + { 38400, 2268, 2418 }, + { 48000, 2836, 3023 } +}; + +/* clk_rst_t: reset, enable, source, index, clk_src, clk_div */ + +static const clk_rst_t _clock_uart[] = { + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, CLK_L_UARTA, 0, CLK_SRC_DIV(2) }, + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, CLK_L_UARTB, 0, CLK_SRC_DIV(2) }, + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, CLK_H_UARTC, 0, CLK_SRC_DIV(2) }, + { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, CLK_U_UARTD, 0, CLK_SRC_DIV(2) }, + { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, CLK_Y_UARTAPE, 0, CLK_SRC_DIV(2) } +}; + +//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26. +static const clk_rst_t _clock_i2c[] = { + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, CLK_L_I2C1, 0, CLK_SRC_DIV(10.5) }, //20.4MHz -> 100KHz + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, CLK_H_I2C2, 0, CLK_SRC_DIV(3) }, //81.6MHz -> 400KHz + { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, CLK_U_I2C3, 0, CLK_SRC_DIV(3) }, //81.6MHz -> 400KHz + { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, CLK_V_I2C4, 0, CLK_SRC_DIV(10.5) }, //20.4MHz -> 100KHz + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_H_I2C5, 0, CLK_SRC_DIV(3) }, //81.6MHz -> 400KHz + { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, CLK_X_I2C6, 0, CLK_SRC_DIV(10.5) } //20.4MHz -> 100KHz +}; + +static clk_rst_t _clock_se = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_V_SE, 0, CLK_SRC_DIV(1) // 408MHz. Default: 408MHz. Max: 627.2 MHz. +}; +static clk_rst_t _clock_tzram = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, CLK_V_TZRAM, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_host1x = { + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_L_HOST1X, 4, CLK_SRC_DIV(2.5) // 163.2MHz. Max: 408MHz. +}; +static clk_rst_t _clock_tsec = { + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, CLK_U_TSEC, 0, CLK_SRC_DIV(2) // 204MHz. Max: 408MHz. +}; +static clk_rst_t _clock_nvdec = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC, CLK_Y_NVDEC, 4, CLK_SRC_DIV(1) // 408 MHz. Max: 716.8/979.2MHz. +}; +static clk_rst_t _clock_nvjpg = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG, CLK_Y_NVJPG, 4, CLK_SRC_DIV(1) // 408 MHz. Max: 627.2/652.8MHz. +}; +static clk_rst_t _clock_vic = { + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_VIC, CLK_X_VIC, 2, CLK_SRC_DIV(1) // 408 MHz. Max: 627.2/652.8MHz. +}; +static clk_rst_t _clock_sor_safe = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, CLK_Y_SOR_SAFE, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_sor0 = { + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NOT_USED, CLK_X_SOR0, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_sor1 = { + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_X_SOR1, 0, CLK_SRC_DIV(2) // 204MHz. +}; +static clk_rst_t _clock_kfuse = { + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_KFUSE, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_cl_dvfs = { + CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, CLK_W_DVFS, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_coresight = { + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, CLK_U_CSITE, 0, CLK_SRC_DIV(3) // 136MHz. +}; +static clk_rst_t _clock_pwm = { + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, CLK_L_PWM, 6, CLK_SRC_DIV(3) // Fref: 6.4MHz. HOS: PLLP / 54 = 7.55MHz. +}; +static clk_rst_t _clock_sdmmc_legacy_tm = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, CLK_Y_SDMMC_LEGACY_TM, 4, CLK_SRC_DIV(34) // 12MHz. +}; +static clk_rst_t _clock_apbdma = { + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_APBDMA, 0, CLK_SRC_DIV(1) // Max: 204MHz. +}; +static clk_rst_t _clock_ahbdma = { + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_AHBDMA, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_actmon = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON, CLK_V_ACTMON, 6, CLK_SRC_DIV(1) // 19.2MHz. +}; +static clk_rst_t _clock_extperiph1 = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1, CLK_V_EXTPERIPH1, 0, CLK_SRC_DIV(1) +}; +static clk_rst_t _clock_extperiph2 = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2, CLK_V_EXTPERIPH2, 2, CLK_SRC_DIV(102) // 4.0MHz +}; + +void clock_enable(const clk_rst_t *clk) +{ + // Put clock into reset. + CLOCK(clk->reset) = (CLOCK(clk->reset) & ~BIT(clk->index)) | BIT(clk->index); + // Disable. + CLOCK(clk->enable) &= ~BIT(clk->index); + // Configure clock source if required. + if (clk->source) + CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29u); + // Enable. + CLOCK(clk->enable) = (CLOCK(clk->enable) & ~BIT(clk->index)) | BIT(clk->index); + usleep(2); + + // Take clock off reset. + CLOCK(clk->reset) &= ~BIT(clk->index); +} + +void clock_disable(const clk_rst_t *clk) +{ + // Put clock into reset. + CLOCK(clk->reset) = (CLOCK(clk->reset) & ~BIT(clk->index)) | BIT(clk->index); + // Disable. + CLOCK(clk->enable) &= ~BIT(clk->index); +} + +void clock_enable_fuse(bool enable) +{ + // Enable Fuse registers visibility. + CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28); +} + +void clock_enable_uart(u32 idx) +{ + // Ease the stress to APB. + bpmp_clk_rate_relaxed(true); + + clock_enable(&_clock_uart[idx]); + + // Restore OC. + bpmp_clk_rate_relaxed(false); +} + +void clock_disable_uart(u32 idx) +{ + clock_disable(&_clock_uart[idx]); +} + +#define UART_SRC_CLK_DIV_EN BIT(24) + +int clock_uart_use_src_div(u32 idx, u32 baud) +{ + u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000; + + if (baud == 3000000) + CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | CLK_SRC_DIV(8.5); + else if (baud == 1000000) + CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | CLK_SRC_DIV(25.5); + else + { + CLOCK(_clock_uart[idx].source) = clk_src_div | CLK_SRC_DIV(2); + + return 1; + } + + return 0; +} + +void clock_enable_i2c(u32 idx) +{ + clock_enable(&_clock_i2c[idx]); +} + +void clock_disable_i2c(u32 idx) +{ + clock_disable(&_clock_i2c[idx]); +} + +void clock_enable_se() +{ + clock_enable(&_clock_se); + + // Lock clock to always enabled if T210B01. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SE) |= 0x100; +} + +void clock_enable_tzram() +{ + clock_enable(&_clock_tzram); +} + +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_nvdec() +{ + clock_enable(&_clock_nvdec); +} + +void clock_disable_nvdec() +{ + clock_disable(&_clock_nvdec); +} + +void clock_enable_nvjpg() +{ + clock_enable(&_clock_nvjpg); +} + +void clock_disable_nvjpg() +{ + clock_disable(&_clock_nvjpg); +} + +void clock_enable_vic() +{ + // Ease the stress to APB. + bpmp_clk_rate_relaxed(true); + + clock_enable(&_clock_vic); + + // Restore sys clock. + bpmp_clk_rate_relaxed(false); +} + +void clock_disable_vic() +{ + clock_disable(&_clock_vic); +} + +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(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_KFUSE); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = BIT(CLK_H_KFUSE); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_KFUSE); + usleep(10); // Wait 10s to prevent glitching. + + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_KFUSE); + usleep(20); // Wait 20s fo kfuse hw to init. +} + +void clock_disable_kfuse() +{ + clock_disable(&_clock_kfuse); +} + +void clock_enable_cl_dvfs() +{ + clock_enable(&_clock_cl_dvfs); +} + +void clock_disable_cl_dvfs() +{ + clock_disable(&_clock_cl_dvfs); +} + +void clock_enable_coresight() +{ + clock_enable(&_clock_coresight); +} + +void clock_disable_coresight() +{ + clock_disable(&_clock_coresight); +} + +void clock_enable_pwm() +{ + // Ease the stress to APB. + bpmp_clk_rate_relaxed(true); + + clock_enable(&_clock_pwm); + + // Restore OC. + bpmp_clk_rate_relaxed(false); +} + +void clock_disable_pwm() +{ + clock_disable(&_clock_pwm); +} + +void clock_enable_apbdma() +{ + clock_enable(&_clock_apbdma); +} + +void clock_disable_apbdma() +{ + clock_disable(&_clock_apbdma); +} + +void clock_enable_ahbdma() +{ + clock_enable(&_clock_ahbdma); +} + +void clock_disable_ahbdma() +{ + clock_disable(&_clock_ahbdma); +} + +void clock_enable_actmon() +{ + clock_enable(&_clock_actmon); +} + +void clock_disable_actmon() +{ + clock_disable(&_clock_actmon); +} + +void clock_enable_extperiph1() +{ + clock_enable(&_clock_extperiph1); + + PMC(APBDEV_PMC_CLK_OUT_CNTRL) |= PMC_CLK_OUT_CNTRL_CLK1_SRC_SEL(OSC_CAR) | PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN; + usleep(5); +} + +void clock_disable_extperiph1() +{ + PMC(APBDEV_PMC_CLK_OUT_CNTRL) &= ~((PMC_CLK_OUT_CNTRL_CLK1_SRC_SEL(OSC_CAR)) | PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN); + clock_disable(&_clock_extperiph1); +} + +void clock_enable_extperiph2() +{ + clock_enable(&_clock_extperiph2); + + PMC(APBDEV_PMC_CLK_OUT_CNTRL) |= PMC_CLK_OUT_CNTRL_CLK2_SRC_SEL(OSC_CAR) | PMC_CLK_OUT_CNTRL_CLK2_FORCE_EN; + usleep(5); +} + +void clock_disable_extperiph2() +{ + PMC(APBDEV_PMC_CLK_OUT_CNTRL) &= ~((PMC_CLK_OUT_CNTRL_CLK2_SRC_SEL(OSC_CAR)) | PMC_CLK_OUT_CNTRL_CLK2_FORCE_EN); + clock_disable(&_clock_extperiph2); +} + +void clock_enable_plld(u32 divp, u32 divn, bool lowpower, bool tegra_t210) +{ + u32 plld_div = (divp << 20) | (divn << 11) | 1; + + // N divider is fractional, so N = DIVN + 1/2 + PLLD_SDM_DIN/8192. + u32 misc = 0x2D0000 | 0xFC00; // Clock enable and PLLD_SDM_DIN: -1024 -> DIVN + 0.375. + if (lowpower && tegra_t210) + misc = 0x2D0000 | 0x0AAA; // Clock enable and PLLD_SDM_DIN: 2730 -> DIVN + 0.833. + + // Set DISP1 clock source. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 2 << 29u; // PLLD_OUT0. + + // Set dividers and enable PLLD. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = tegra_t210 ? 0x20 : 0; // Keep default PLLD_SETUP. + + // Set PLLD_SDM_DIN and enable PLLD to DSI pads. + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = misc; +} + +void clock_enable_pllx() +{ + // Configure and enable PLLX if disabled. + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_ENABLE)) // PLLX_ENABLE. + { + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~PLLX_MISC3_IDDQ; // Disable IDDQ. + usleep(2); + + // Set div configuration. + const u32 pllx_div_cfg = (2 << 20) | (156 << 8) | 2; // P div: 2 (3), N div: 156, M div: 2. 998.4 MHz. + + // Bypass dividers. + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_BYPASS | pllx_div_cfg; + // Disable bypass + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = pllx_div_cfg; + // Set PLLX_LOCK_ENABLE. + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) |= PLLX_MISC_LOCK_EN; + // Enable PLLX. + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_ENABLE | pllx_div_cfg; + } + + // Wait for PLL to stabilize. + while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_LOCK)) + ; +} + +void clock_enable_pllc(u32 divn) +{ + u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; + + // Check if already enabled and configured. + if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn)) + return; + + // Take PLLC out of reset and set basic misc parameters. + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = + ((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x8000 << 4); // PLLC_EXT_FRU. + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM. + + // Disable PLL and IDDQ in case they are on. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; + usleep(10); + + // Set PLLC dividers. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. + + // Enable PLLC and wait for Phase and Frequency lock. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) + ; + + // Disable PLLC_OUT1, enable reset and set div to 1.5. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = 1 << 8; + + // Enable PLLC_OUT1 and bring it out of reset. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR; + msleep(1); // Wait a bit for PLL to stabilize. +} + +void clock_disable_pllc() +{ + // Disable PLLC and PLLC_OUT1. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~PLLC_OUT1_RSTN_CLR; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = PLLC_MISC_RESET; + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) &= ~(0xFF << 8); // PLLC_FLL_LD_MEM. + usleep(10); +} + +#define PLLC4_ENABLED BIT(31) +#define PLLC4_IN_USE (~PLLC4_ENABLED) + +u32 pllc4_enabled = 0; + +static void _clock_enable_pllc4(u32 mask) +{ + pllc4_enabled |= mask; + + if (pllc4_enabled & PLLC4_ENABLED) + return; + + // Enable Phase and Frequency lock detection. + //CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; + + // Disable PLL and IDDQ in case they are on. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ; + usleep(10); + + // Set PLLC4 dividers. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (0 << 19) | (104 << 8) | 4; // DIVP: 1, DIVN: 104, DIVM: 4. 998MHz OUT0, 199MHz OUT2. + + // Enable PLLC4 and wait for Phase and Frequency lock. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_ENABLE; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLCX_BASE_LOCK)) + ; + + msleep(1); // Wait a bit for PLL to stabilize. + + pllc4_enabled |= PLLC4_ENABLED; +} + +static void _clock_disable_pllc4(u32 mask) +{ + pllc4_enabled &= ~mask; + + // Check if currently in use or disabled. + if ((pllc4_enabled & PLLC4_IN_USE) || !(pllc4_enabled & PLLC4_ENABLED)) + return; + + // Disable PLLC4. + msleep(1); // Wait at least 1ms to prevent glitching. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLC4_BASE_IDDQ; + usleep(10); + + pllc4_enabled = 0; +} + +void clock_enable_pllu() +{ + // Configure PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) |= BIT(29); // Disable reference clock. + u32 pllu_cfg = (CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & 0xFFE00000) | BIT(24) | (1 << 16) | (0x19 << 8) | 2; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | PLLCX_BASE_ENABLE; // Enable. + + // Wait for PLL to stabilize. + u32 timeout = get_tmr_us() + 1300; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & PLLCX_BASE_LOCK)) // PLL_LOCK. + if (get_tmr_us() > timeout) + break; + usleep(10); + + // Enable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) |= 0x2E00000; +} + +void clock_disable_pllu() +{ + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x2E00000; // Disable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~BIT(30); // Disable PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) &= ~BIT(29); // Enable reference clock. +} + +void clock_enable_utmipll() +{ + // Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) & 0xFF0000FF) | (25 << 16) | (1 << 8); // 38.4Mhz * (25 / 1) = 960 MHz. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFF00003F) | (24 << 18); // Set delay count for 38.4Mhz osc crystal. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) & 0x7FFA000) | (1 << 15) | 375; + + // Wait for UTMIPLL to stabilize. + u32 retries = 10; // Wait 20us + while (!(CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & UTMIPLL_LOCK) && retries) + { + usleep(1); + retries--; + } +} + +static int _clock_sdmmc_is_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC1); + case SDMMC_2: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC2); + case SDMMC_3: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & BIT(CLK_U_SDMMC3); + case SDMMC_4: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC4); + } + return 0; +} + +static void _clock_sdmmc_set_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC1); + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC2); + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_SDMMC3); + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC4); + break; + } +} + +static void _clock_sdmmc_clear_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC1); + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC2); + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = BIT(CLK_U_SDMMC3); + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC4); + break; + } +} + +static int _clock_sdmmc_is_enabled(u32 id) +{ + switch (id) + { + case SDMMC_1: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC1); + case SDMMC_2: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC2); + case SDMMC_3: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & BIT(CLK_U_SDMMC3); + case SDMMC_4: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC4); + } + return 0; +} + +static void _clock_sdmmc_set_enable(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC1); + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC2); + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = BIT(CLK_U_SDMMC3); + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC4); + break; + } +} + +static void _clock_sdmmc_clear_enable(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC1); + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC2); + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_SDMMC3); + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC4); + break; + } +} + +static void _clock_sdmmc_config_legacy_tm() +{ + const clk_rst_t *clk = &_clock_sdmmc_legacy_tm; + if (!(CLOCK(clk->enable) & BIT(clk->index))) + clock_enable(clk); +} + +typedef struct _clock_sdmmc_t +{ + u32 clock; + u32 real_clock; +} clock_sdmmc_t; + +static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 }; + +#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0 +#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3 +#define SDMMC_CLOCK_SRC_PLLC4_OUT0 0x7 +#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1 + +static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) +{ + u32 divisor = 0; + u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; + + if (id > SDMMC_4) + return 0; + + // Get IO clock divisor. + switch (val) + { + case 25000: + *pclock = 24728; + divisor = CLK_SRC_DIV(16.5); + break; + + case 26000: + *pclock = 25500; + divisor = CLK_SRC_DIV(16); + break; + + case 50000: + *pclock = 48000; + divisor = CLK_SRC_DIV(8.5); + break; + + case 52000: + *pclock = 51000; + divisor = CLK_SRC_DIV(8); + break; + + case 82000: + *pclock = 81600; + divisor = CLK_SRC_DIV(5); + break; + + case 100000: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + *pclock = 99840; + divisor = CLK_SRC_DIV(2); + break; + + case 164000: + *pclock = 163200; + divisor = CLK_SRC_DIV(2.5); + break; + + case 200000: + switch (id) + { + case SDMMC_1: + case SDMMC_3: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_2: + case SDMMC_4: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; // div is ignored. + break; + } + *pclock = 199680; + divisor = CLK_SRC_DIV(1); + break; + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + case 400000: + source = SDMMC_CLOCK_SRC_PLLC4_OUT0; + *pclock = 399360; + divisor = CLK_SRC_DIV(2.5); + break; +#endif + } + + _clock_sdmmc_table[id].clock = val; + _clock_sdmmc_table[id].real_clock = *pclock; + + // Enable PLLC4 if in use by any SDMMC. + if (source != SDMMC_CLOCK_SRC_PLLP_OUT0) + _clock_enable_pllc4(BIT(id)); + + // Set SDMMC legacy timeout clock. + _clock_sdmmc_config_legacy_tm(); + + // Set SDMMC clock. + u32 src_div = (source << 29u) | divisor; + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = src_div; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = src_div; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = src_div; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = src_div; + break; + } + + return 1; +} + +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val) +{ + if (_clock_sdmmc_table[id].clock == val) + { + *pclock = _clock_sdmmc_table[id].real_clock; + } + else + { + int is_enabled = _clock_sdmmc_is_enabled(id); + if (is_enabled) + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_config_clock_host(pclock, id, val); + if (is_enabled) + _clock_sdmmc_set_enable(id); + _clock_sdmmc_is_reset(id); + } +} + +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type) +{ + // Get Card clock divisor. + switch (type) + { + case SDHCI_TIMING_MMC_ID: // Actual card clock: 386.36 KHz. + *pclock = 26000; + *pdivisor = 66; + break; + + case SDHCI_TIMING_MMC_LS26: + *pclock = 26000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_MMC_HS52: + *pclock = 52000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + *pclock = 200000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_SD_ID: // Actual card clock: 386.38 KHz. + *pclock = 25000; + *pdivisor = 64; + break; + + case SDHCI_TIMING_SD_DS12: + case SDHCI_TIMING_UHS_SDR12: + *pclock = 25000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_SD_HS25: + case SDHCI_TIMING_UHS_SDR25: + *pclock = 50000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_UHS_SDR50: + *pclock = 100000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_UHS_SDR82: + *pclock = 164000; + *pdivisor = 1; + break; + + case SDHCI_TIMING_UHS_DDR50: // Actual card clock: 40.80 MHz. + *pclock = 82000; + *pdivisor = 2; + break; + + case SDHCI_TIMING_MMC_HS100: // Actual card clock: 99.84 MHz. + *pclock = 200000; + *pdivisor = 2; + break; + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + case SDHCI_TIMING_UHS_DDR200: // Actual card clock: 199.68 KHz. + *pclock = 400000; + *pdivisor = 2; + break; +#endif + } +} + +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 clock = 0; + + if (_clock_sdmmc_is_enabled(id)) + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_set_reset(id); + _clock_sdmmc_config_clock_host(&clock, id, val); + _clock_sdmmc_set_enable(id); + _clock_sdmmc_is_reset(id); + // Wait 100 cycles for reset and for clocks to stabilize. + usleep((100 * 1000 + clock - 1) / clock); + _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); + _clock_disable_pllc4(BIT(id)); +} + +u32 clock_get_osc_freq() +{ + CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET) = OSC_FREQ_DET_TRIG | (2 - 1); // 2 periods of 32.76KHz window. + while (CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY) + ; + u32 cnt = (CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_CNT); + CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET) = 0; + + // Return frequency in KHz. + for (u32 i = 0; i < ARRAY_SIZE(_clock_osc_cnt); i++) + if (cnt >= _clock_osc_cnt[i].min && cnt <= _clock_osc_cnt[i].max) + return _clock_osc_cnt[i].freq; + + return 0; +} + +u32 clock_get_dev_freq(clock_pto_id_t id) +{ + const u32 pto_win = 16; + const u32 pto_osc = 32768; + + u32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (pto_win - 1); + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep(2); + + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_RST; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep(2); + + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep(2); + + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_EN; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep((1000000 * pto_win / pto_osc) + 12 + 2); + + while (CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT_BUSY) + ; + + u32 cnt = CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT; + + CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = 0; + (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); + usleep(2); + + u32 freq_khz = (u64)cnt * pto_osc / pto_win / 1000; + + return freq_khz; +} + diff --git a/bdk/soc/clock.h b/bdk/soc/clock.h new file mode 100644 index 0000000..14d1df7 --- /dev/null +++ b/bdk/soc/clock.h @@ -0,0 +1,802 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer + * + * 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 _CLOCK_H_ +#define _CLOCK_H_ + +#include + +/*! Clock registers. */ +#define CLK_RST_CONTROLLER_RST_SOURCE 0x0 +#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 +#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 +#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_OSC_FREQ_DET 0x58 +#define CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS 0x5C +#define CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL 0x60 +#define CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS 0x64 +#define CLK_RST_CONTROLLER_PLLC_BASE 0x80 +#define CLK_RST_CONTROLLER_PLLC_OUT 0x84 +#define CLK_RST_CONTROLLER_PLLC_MISC 0x88 +#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C +#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 +#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 +#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C +#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 +#define CLK_RST_CONTROLLER_PLLP_OUTB 0xA8 +#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0 +#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4 +#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8 +#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC +#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0 +#define CLK_RST_CONTROLLER_PLLU_OUTA 0xC4 +#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC +#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 +#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 +#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC +#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 +#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 +#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 +#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100 +#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 +#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 +#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 +#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_UARTA 0x178 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C +#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 +#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 +#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 +#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C +#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290 +#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 +#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C +#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0 +#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4 +#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8 +#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC +#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_H_CLR 0x30C +#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_H_CLR 0x32C +#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_RST_DEVICES_W 0x35C +#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_LVL2_CLK_GATE_OVRC 0x3A0 +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_AHUB 0x3D0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON 0x3E8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC +#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2 0x3F0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C +#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430 +#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 +#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438 +#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C +#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 +#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 +#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 +#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C +#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 +#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 +#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C +#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG3 0x4C0 +#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 +#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 +#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C +#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 +#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 +#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 +#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 +#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 +#define CLK_RST_CONTROLLER_PLLMB_MISC1 0x5EC +#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS 0x608 +#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C +#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610 +#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C +#define CLK_RST_CONTROLLER_CLK_SOURCE_VIC 0x678 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 +#define CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC 0x698 +#define CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG 0x69C +#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_APE 0x6C0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC +#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 + +#define CLK_NO_SOURCE 0x0 +#define CLK_NOT_USED 0x0 + +/*! PLL control and status bits */ +#define PLLX_BASE_LOCK BIT(27) +#define PLLX_BASE_REF_DIS BIT(29) +#define PLLX_BASE_ENABLE BIT(30) +#define PLLX_BASE_BYPASS BIT(31) +#define PLLX_MISC_LOCK_EN BIT(18) +#define PLLX_MISC3_IDDQ BIT(3) + +#define PLLCX_BASE_LOCK BIT(27) +#define PLLCX_BASE_REF_DIS BIT(29) +#define PLLCX_BASE_ENABLE BIT(30) +#define PLLCX_BASE_BYPASS BIT(31) + +#define PLLA_OUT0_RSTN_CLR BIT(0) +#define PLLA_OUT0_CLKEN BIT(1) +#define PLLA_BASE_IDDQ BIT(25) + +#define PLLC_OUT1_RSTN_CLR BIT(0) +#define PLLC_OUT1_CLKEN BIT(1) +#define PLLC_MISC1_IDDQ BIT(27) +#define PLLC_MISC_RESET BIT(30) + +#define PLLC4_OUT3_RSTN_CLR BIT(0) +#define PLLC4_OUT3_CLKEN BIT(1) +#define PLLC4_BASE_IDDQ BIT(18) +#define PLLC4_MISC_EN_LCKDET BIT(30) + +#define UTMIPLL_LOCK BIT(31) + +/*! Clock source */ +#define CLK_SRC_DIV(d) ((d) ? ((u32)(((d) - 1) * 2)) : 0) + +/*! PTO_CLK_CNT */ +#define PTO_REF_CLK_WIN_CFG_MASK 0xF +#define PTO_REF_CLK_WIN_CFG_16P 0xF +#define PTO_CNT_EN BIT(9) +#define PTO_CNT_RST BIT(10) +#define PTO_CLK_ENABLE BIT(13) +#define PTO_SRC_SEL_SHIFT 14 +#define PTO_SRC_SEL_MASK 0x1FF +#define PTO_DIV_SEL_MASK (3 << 23) +#define PTO_DIV_SEL_GATED (0 << 23) +#define PTO_DIV_SEL_DIV1 (1 << 23) +#define PTO_DIV_SEL_DIV2_RISING (2 << 23) +#define PTO_DIV_SEL_DIV2_FALLING (3 << 23) +#define PTO_DIV_SEL_CPU_EARLY (0 << 23) +#define PTO_DIV_SEL_CPU_LATE (1 << 23) + +#define PTO_CLK_CNT_BUSY BIT(31) +#define PTO_CLK_CNT 0xFFFFFF + +/*! OSC_FREQ_DET */ +#define OSC_REF_CLK_WIN_CFG_MASK 0xF +#define OSC_FREQ_DET_TRIG BIT(31) + +#define OSC_FREQ_DET_BUSY BIT(31) +#define OSC_FREQ_DET_CNT 0xFFFF + +/*! PTO IDs. */ +typedef enum _clock_pto_id_t +{ + CLK_PTO_PCLK_SYS = 0x06, + CLK_PTO_HCLK_SYS = 0x07, + CLK_PTO_DMIC1 = 0x08, + CLK_PTO_DMIC2 = 0x09, + CLK_PTO_HDMI_SLOWCLK_DIV2 = 0x0A, + CLK_PTO_JTAG_REG = 0x0B, + CLK_PTO_UTMIP_240_A = 0x0C, + CLK_PTO_UTMIP_240_B = 0x0D, + + CLK_PTO_CCLK_G = 0x12, + CLK_PTO_CCLK_G_DIV2 = 0x13, + CLK_PTO_MIPIBIF = 0x14, + + CLK_PTO_SPI1 = 0x17, + CLK_PTO_SPI2 = 0x18, + CLK_PTO_SPI3 = 0x19, + CLK_PTO_SPI4 = 0x1A, + CLK_PTO_MAUD = 0x1B, + CLK_PTO_SCLK = 0x1C, + + CLK_PTO_SDMMC1 = 0x20, + CLK_PTO_SDMMC2 = 0x21, + CLK_PTO_SDMMC3 = 0x22, + CLK_PTO_SDMMC4 = 0x23, + CLK_PTO_EMC = 0x24, + + CLK_PTO_DMIC3 = 0x2A, + CLK_PTO_CCLK_LP = 0x2B, + CLK_PTO_CCLK_LP_DIV2 = 0x2C, + + CLK_PTO_MSELECT = 0x2F, + + CLK_PTO_VI_SENSOR2 = 0x33, + CLK_PTO_VI_SENSOR = 0x34, + CLK_PTO_VIC = 0x35, + CLK_PTO_VIC_SKIP = 0x36, + CLK_PTO_ISP_SKIP = 0x37, + CLK_PTO_ISPB_SE2_SKIP = 0x38, + CLK_PTO_NVDEC_SKIP = 0x39, + CLK_PTO_NVENC_SKIP = 0x3A, + CLK_PTO_NVJPG_SKIP = 0x3B, + CLK_PTO_TSEC_SKIP = 0x3C, + CLK_PTO_TSECB_SKIP = 0x3D, + CLK_PTO_SE_SKIP = 0x3E, + CLK_PTO_VI_SKIP = 0x3F, + + CLK_PTO_PLLX_OBS = 0x40, + CLK_PTO_PLLC_OBS = 0x41, + CLK_PTO_PLLM_OBS = 0x42, + CLK_PTO_PLLP_OBS = 0x43, + CLK_PTO_PLLA_OBS = 0x44, + CLK_PTO_PLLMB_OBS = 0x45, + CLK_PTO_SATA_OOB = 0x46, + + CLK_PTO_FCPU_DVFS_DIV12_CPU = 0x48, + + CLK_PTO_EQOS_AXI = 0x4C, + CLK_PTO_EQOS_PTP_REF = 0x4D, + CLK_PTO_EQOS_TX = 0x4E, + CLK_PTO_EQOS_RX = 0x4F, + + CLK_PTO_CILAB = 0x52, + CLK_PTO_CILCD = 0x53, + + CLK_PTO_CILEF = 0x55, + CLK_PTO_PLLA1_PTO_OBS = 0x56, + CLK_PTO_PLLC4_PTO_OBS = 0x57, + + CLK_PTO_PLLC2_PTO_OBS = 0x59, + CLK_PTO_PLLC3_PTO_OBS = 0x5B, + + CLK_PTO_DSIA_LP = 0x62, + CLK_PTO_DSIB_LP = 0x63, + CLK_PTO_ISP = 0x64, + CLK_PTO_PEX_PAD = 0x65, + + CLK_PTO_MC = 0x6A, + + CLK_PTO_ACTMON = 0x6B, + CLK_PTO_CSITE = 0x6C, + CLK_PTO_VI_I2C = 0x6D, + + CLK_PTO_HOST1X = 0x6F, + + CLK_PTO_QSPI_2X = 0x71, + CLK_PTO_NVDEC = 0x72, + CLK_PTO_NVJPG = 0x73, + CLK_PTO_SE = 0x74, + CLK_PTO_SOC_THERM = 0x75, + + CLK_PTO_TSEC = 0x77, + CLK_PTO_TSECB = 0x78, + CLK_PTO_VI = 0x79, + CLK_PTO_LA = 0x7A, + CLK_PTO_SCLK_SKIP = 0x7B, + + CLK_PTO_ADSP_SKIP = 0x7C, + CLK_PTO_QSPI = 0x7D, + + CLK_PTO_SDMMC2_SHAPER = 0x7E, + CLK_PTO_SDMMC4_SHAPER = 0x7F, + CLK_PTO_I2S1 = 0x80, + CLK_PTO_I2S2 = 0x81, + CLK_PTO_I2S3 = 0x82, + CLK_PTO_I2S4 = 0x83, + CLK_PTO_I2S5 = 0x84, + CLK_PTO_AHUB = 0x85, + CLK_PTO_APE = 0x86, + + CLK_PTO_DVFS_SOC = 0x88, + CLK_PTO_DVFS_REF = 0x89, + CLK_PTO_ADSP_CLK = 0x8A, + CLK_PTO_ADSP_DIV2_CLK = 0x8B, + + CLK_PTO_SPDIF_OUT = 0x8F, + CLK_PTO_SPDIF_IN = 0x90, + CLK_PTO_UART_FST_MIPI_CAL = 0x91, + CLK_PTO_SYS2HSIO_SATA_CLK = 0x92, + CLK_PTO_PWM = 0x93, + CLK_PTO_I2C1 = 0x94, + CLK_PTO_I2C2 = 0x95, + CLK_PTO_I2C3 = 0x96, + CLK_PTO_I2C4 = 0x97, + CLK_PTO_I2C5 = 0x98, + CLK_PTO_I2C6 = 0x99, + CLK_PTO_I2C_SLOW = 0x9A, + CLK_PTO_UARTAPE = 0x9B, + + CLK_PTO_EXTPERIPH1 = 0x9D, + CLK_PTO_EXTPERIPH2 = 0x9E, + CLK_PTO_EXTPERIPH3 = 0x9F, + CLK_PTO_ENTROPY = 0xA0, + CLK_PTO_UARTA = 0xA1, + CLK_PTO_UARTB = 0xA2, + CLK_PTO_UARTC = 0xA3, + CLK_PTO_UARTD = 0xA4, + CLK_PTO_OWR = 0xA5, + CLK_PTO_TSENSOR = 0xA6, + CLK_PTO_HDA2CODEC_2X = 0xA7, + CLK_PTO_HDA = 0xA8, + CLK_PTO_EMC_LATENCY = 0xA9, + CLK_PTO_EMC_DLL = 0xAA, + CLK_PTO_SDMMC_LEGACY_TM = 0xAB, + CLK_PTO_DBGAPB = 0xAC, + + CLK_PTO_SOR0 = 0xC0, + CLK_PTO_SOR1 = 0xC1, + CLK_PTO_HDMI = 0xC2, + + CLK_PTO_DISP2 = 0xC4, + CLK_PTO_DISP1 = 0xC5, + + CLK_PTO_PLLD_OBS = 0xCA, + CLK_PTO_PLLD2_PTO_OBS = 0xCC, + CLK_PTO_PLLDP_OBS = 0xCE, + CLK_PTO_PLLE_OBS = 0x10A, + CLK_PTO_PLLU_OBS = 0x10C, + CLK_PTO_PLLREFE_OBS = 0x10E, + + CLK_PTO_XUSB_FALCON = 0x110, + CLK_PTO_XUSB_CLK480M_HSIC = 0x111, + CLK_PTO_USB_L0_RX = 0x112, + CLK_PTO_USB_L3_RX = 0x113, + CLK_PTO_USB_RX = 0x114, + CLK_PTO_USB3_L0_TXCLKREF = 0x115, + CLK_PTO_PEX_TXCLKREF_SWITCH_TMS = 0x116, + CLK_PTO_PEX_TXCLKREF_SWITCH_GRP0 = 0x117, + CLK_PTO_PEX_TXCLKREF_SWITCH_GRP1 = 0x118, + CLK_PTO_PEX_TXCLKREF_SWITCH_GRP2 = 0x119, + CLK_PTO_PEX_L4_RX = 0x11A, + CLK_PTO_PEX_TXCLKREF = 0x11B, + CLK_PTO_PEX_TXCLKREF_DIV2 = 0x11C, + CLK_PTO_PEX_TXCLKREF2 = 0x11D, + CLK_PTO_PEX_L0_RX = 0x11E, + CLK_PTO_PEX_L1_RX = 0x11F, + CLK_PTO_PEX_L2_RX = 0x120, + CLK_PTO_PEX_L3_RX = 0x121, + CLK_PTO_SATA_TXCLKREF = 0x122, + CLK_PTO_SATA_TXCLKREF_DIV2 = 0x123, + CLK_PTO_USB_L5_RX = 0x124, + CLK_PTO_SATA_TX = 0x125, + CLK_PTO_SATA_L0_RX = 0x126, + + CLK_PTO_USB3_L1_TXCLKREF = 0x129, + CLK_PTO_USB3_L7_TXCLKREF = 0x12A, + CLK_PTO_USB3_L7_RX = 0x12B, + CLK_PTO_USB3_TX = 0x12C, + CLK_PTO_UTMIP_PLL_PAD = 0x12D, + + CLK_PTO_XUSB_FS = 0x136, + CLK_PTO_XUSB_SS_HOST_DEV = 0x137, + CLK_PTO_XUSB_CORE_HOST = 0x138, + CLK_PTO_XUSB_CORE_DEV = 0x139, + + CLK_PTO_USB3_L2_TXCLKREF = 0x13C, + CLK_PTO_USB3_L3_TXCLKREF = 0x13D, + CLK_PTO_USB_L4_RX = 0x13E, + CLK_PTO_USB_L6_RX = 0x13F, + + /* + * PLL need PTO enabled in MISC registers. + * Normal div is 2 so result is multiplied with it. + */ + CLK_PTO_PLLC_DIV2 = 0x01, + CLK_PTO_PLLM_DIV2 = 0x02, + CLK_PTO_PLLP_DIV2 = 0x03, + CLK_PTO_PLLA_DIV2 = 0x04, + CLK_PTO_PLLX_DIV2 = 0x05, + + CLK_PTO_PLLMB_DIV2 = 0x25, + + CLK_PTO_PLLC4_DIV2 = 0x51, + + CLK_PTO_PLLA1_DIV2 = 0x55, + CLK_PTO_PLLC2_DIV2 = 0x58, + CLK_PTO_PLLC3_DIV2 = 0x5A, + + CLK_PTO_PLLD_DIV2 = 0xCB, + CLK_PTO_PLLD2_DIV2 = 0xCD, + CLK_PTO_PLLDP_DIV2 = 0xCF, + + CLK_PTO_PLLE_DIV2 = 0x10B, + + CLK_PTO_PLLU_DIV2 = 0x10D, + + CLK_PTO_PLLREFE_DIV2 = 0x10F, +} clock_pto_id_t; + +/* + * CLOCK Peripherals: + * L 0 - 31 + * H 32 - 63 + * U 64 - 95 + * V 96 - 127 + * W 128 - 159 + * X 160 - 191 + * Y 192 - 223 + */ + +enum CLK_L_DEV +{ + CLK_L_CPU = 0, // Only reset. Deprecated. + CLK_L_BPMP = 1, // Only reset. + CLK_L_SYS = 2, // Only reset. + CLK_L_ISPB = 3, + CLK_L_RTC = 4, + CLK_L_TMR = 5, + CLK_L_UARTA = 6, + CLK_L_UARTB = 7, + CLK_L_GPIO = 8, + CLK_L_SDMMC2 = 9, + CLK_L_SPDIF = 10, + CLK_L_I2S2 = 11, // I2S1 + CLK_L_I2C1 = 12, + CLK_L_NDFLASH = 13, // HIDDEN. + CLK_L_SDMMC1 = 14, + CLK_L_SDMMC4 = 15, + CLK_L_TWC = 16, // HIDDEN. + CLK_L_PWM = 17, + CLK_L_I2S3 = 18, + CLK_L_EPP = 19, // HIDDEN. + CLK_L_VI = 20, + CLK_L_2D = 21, // HIDDEN. + CLK_L_USBD = 22, + CLK_L_ISP = 23, + CLK_L_3D = 24, // HIDDEN. + CLK_L_IDE = 25, // RESERVED. + CLK_L_DISP2 = 26, + CLK_L_DISP1 = 27, + CLK_L_HOST1X = 28, + CLK_L_VCP = 29, // HIDDEN. + CLK_L_I2S1 = 30, // I2S0 + CLK_L_BPMP_CACHE_CTRL = 31, // CONTROLLER +}; + +enum CLK_H_DEV +{ + CLK_H_MEM = 0, // MC. + CLK_H_AHBDMA = 1, + CLK_H_APBDMA = 2, + //CLK_H_ = 3, + CLK_H_KBC = 4, // HIDDEN. + CLK_H_STAT_MON = 5, + CLK_H_PMC = 6, + CLK_H_FUSE = 7, + CLK_H_KFUSE = 8, + CLK_H_SPI1 = 9, + CLK_H_SNOR = 10, // HIDDEN. + CLK_H_JTAG2TBC = 11, + CLK_H_SPI2 = 12, + CLK_H_XIO = 13, // HIDDEN. + CLK_H_SPI3 = 14, + CLK_H_I2C5 = 15, + CLK_H_DSI = 16, + CLK_H_TVO = 17, // RESERVED. + CLK_H_HSI = 18, // HIDDEN. + CLK_H_HDMI = 19, // HIDDEN. + CLK_H_CSI = 20, + CLK_H_TVDAC = 21, // RESERVED. + CLK_H_I2C2 = 22, + CLK_H_UARTC = 23, + CLK_H_MIPI_CAL = 24, + CLK_H_EMC = 25, + CLK_H_USB2 = 26, + CLK_H_USB3 = 27, // HIDDEN. + CLK_H_MPE = 28, // HIDDEN. + CLK_H_VDE = 29, // HIDDEN. + CLK_H_BSEA = 30, // HIDDEN. + CLK_H_BSEV = 31, +}; + +enum CLK_U_DEV +{ + CLK_U_SPEEDO = 0, // RESERVED. + CLK_U_UARTD = 1, + CLK_U_UARTE = 2, // HIDDEN. + CLK_U_I2C3 = 3, + CLK_U_SPI4 = 4, + CLK_U_SDMMC3 = 5, + CLK_U_PCIE = 6, + CLK_U_OWR = 7, // RESERVED. + CLK_U_AFI = 8, + CLK_U_CSITE = 9, + CLK_U_PCIEXCLK = 10, // Only reset. + CLK_U_BPMPUCQ = 11, // HIDDEN. + CLK_U_LA = 12, + CLK_U_TRACECLKIN = 13, // HIDDEN. + CLK_U_SOC_THERM = 14, + CLK_U_DTV = 15, + CLK_U_NAND_SPEED = 16, // HIDDEN. + CLK_U_I2C_SLOW = 17, + CLK_U_DSIB = 18, + CLK_U_TSEC = 19, + CLK_U_IRAMA = 20, + CLK_U_IRAMB = 21, + CLK_U_IRAMC = 22, + CLK_U_IRAMD = 23, // EMUCIF ON RESET + CLK_U_BPMP_CACHE_RAM = 24, + CLK_U_XUSB_HOST = 25, + CLK_U_CLK_M_DOUBLER = 26, + CLK_U_MSENC = 27, // HIDDEN. + CLK_U_SUS_OUT = 28, + CLK_U_DEV2_OUT = 29, + CLK_U_DEV1_OUT = 30, + CLK_U_XUSB_DEV = 31, +}; + +enum CLK_V_DEV +{ + CLK_V_CPUG = 0, + CLK_V_CPULP = 1, // Reserved. + CLK_V_3D2 = 2, // HIDDEN. + CLK_V_MSELECT = 3, + CLK_V_TSENSOR = 4, + CLK_V_I2S4 = 5, + CLK_V_I2S5 = 6, + CLK_V_I2C4 = 7, + CLK_V_SPI5 = 8, // HIDDEN. + CLK_V_SPI6 = 9, // HIDDEN. + CLK_V_AHUB = 10, // AUDIO. + CLK_V_APB2APE = 11, // APBIF. + CLK_V_DAM0 = 12, // HIDDEN. + CLK_V_DAM1 = 13, // HIDDEN. + CLK_V_DAM2 = 14, // HIDDEN. + CLK_V_HDA2CODEC_2X = 15, + CLK_V_ATOMICS = 16, + //CLK_V_ = 17, + //CLK_V_ = 18, + //CLK_V_ = 19, + //CLK_V_ = 20, + //CLK_V_ = 21, + CLK_V_SPDIF_DOUBLER = 22, + CLK_V_ACTMON = 23, + CLK_V_EXTPERIPH1 = 24, + CLK_V_EXTPERIPH2 = 25, + CLK_V_EXTPERIPH3 = 26, + CLK_V_SATA_OOB = 27, + CLK_V_SATA = 28, + CLK_V_HDA = 29, + CLK_V_TZRAM = 30, // HIDDEN. + CLK_V_SE = 31, // HIDDEN. +}; + +enum CLK_W_DEV +{ + CLK_W_HDA2HDMICODEC = 0, + CLK_W_RESERVED0 = 1, //satacoldrstn + CLK_W_PCIERX0 = 2, + CLK_W_PCIERX1 = 3, + CLK_W_PCIERX2 = 4, + CLK_W_PCIERX3 = 5, + CLK_W_PCIERX4 = 6, + CLK_W_PCIERX5 = 7, + CLK_W_CEC = 8, + CLK_W_PCIE2_IOBIST = 9, + CLK_W_EMC_IOBIST = 10, + CLK_W_HDMI_IOBIST = 11, // HIDDEN. + CLK_W_SATA_IOBIST = 12, + CLK_W_MIPI_IOBIST = 13, + CLK_W_XUSB_PADCTL = 14, // Only reset. + CLK_W_XUSB = 15, + CLK_W_CILAB = 16, + CLK_W_CILCD = 17, + CLK_W_CILEF = 18, + CLK_W_DSIA_LP = 19, + CLK_W_DSIB_LP = 20, + CLK_W_ENTROPY = 21, + CLK_W_DDS = 22, // HIDDEN. + //CLK_W_ = 23, + CLK_W_DP2 = 24, // HIDDEN. + CLK_W_AMX0 = 25, // HIDDEN. + CLK_W_ADX0 = 26, // HIDDEN. + CLK_W_DVFS = 27, + CLK_W_XUSB_SS = 28, + CLK_W_EMC_LATENCY = 29, + CLK_W_MC1 = 30, + //CLK_W_ = 31, +}; + +enum CLK_X_DEV +{ + CLK_X_SPARE = 0, + CLK_X_DMIC1 = 1, + CLK_X_DMIC2 = 2, + CLK_X_ETR = 3, + CLK_X_CAM_MCLK = 4, + CLK_X_CAM_MCLK2 = 5, + CLK_X_I2C6 = 6, + CLK_X_MC_CAPA = 7, // MC DAISY CHAIN1 + CLK_X_MC_CBPA = 8, // MC DAISY CHAIN2 + CLK_X_MC_CPU = 9, + CLK_X_MC_BBC = 10, + CLK_X_VIM2_CLK = 11, + //CLK_X_ = 12, + CLK_X_MIPIBIF = 13, //RESERVED + CLK_X_EMC_DLL = 14, + //CLK_X_ = 15, + CLK_X_HDMI_AUDIO = 16, // HIDDEN. + CLK_X_UART_FST_MIPI_CAL = 17, + CLK_X_VIC = 18, + //CLK_X_ = 19, + CLK_X_ADX1 = 20, // HIDDEN. + CLK_X_DPAUX = 21, + CLK_X_SOR0 = 22, + CLK_X_SOR1 = 23, + CLK_X_GPU = 24, + CLK_X_DBGAPB = 25, + CLK_X_HPLL_ADSP = 26, + CLK_X_PLLP_ADSP = 27, + CLK_X_PLLA_ADSP = 28, + CLK_X_PLLG_REF = 29, + //CLK_X_ = 30, + //CLK_X_ = 31, +}; + +enum CLK_Y_DEV +{ + CLK_Y_SPARE1 = 0, + CLK_Y_SDMMC_LEGACY_TM = 1, + CLK_Y_NVDEC = 2, + CLK_Y_NVJPG = 3, + CLK_Y_AXIAP = 4, + CLK_Y_DMIC3 = 5, + CLK_Y_APE = 6, + CLK_Y_ADSP = 7, + CLK_Y_MC_CDPA = 8, // MC DAISY CHAIN4 + CLK_Y_MC_CCPA = 9, // MC DAISY CHAIN3 + CLK_Y_MAUD = 10, + //CLK_Y_ = 11, + CLK_Y_SATA_USB_UPHY = 12, // Only reset. + CLK_Y_PEX_USB_UPHY = 13, // Only reset. + CLK_Y_TSECB = 14, + CLK_Y_DPAUX1 = 15, + CLK_Y_VI_I2C = 16, + CLK_Y_HSIC_TRK = 17, + CLK_Y_USB2_TRK = 18, + CLK_Y_QSPI = 19, + CLK_Y_UARTAPE = 20, + CLK_Y_ADSPINTF = 21, // Only reset. + CLK_Y_ADSPPERIPH = 22, // Only reset. + CLK_Y_ADSPDBG = 23, // Only reset. + CLK_Y_ADSPWDT = 24, // Only reset. + CLK_Y_ADSPSCU = 25, // Only reset. + CLK_Y_ADSPNEON = 26, + CLK_Y_NVENC = 27, + CLK_Y_IQC2 = 28, + CLK_Y_IQC1 = 29, + CLK_Y_SOR_SAFE = 30, + CLK_Y_PLLP_OUT_CPU = 31, +}; + +/*! Generic clock descriptor. */ +typedef struct _clk_rst_t +{ + u16 reset; + u16 enable; + u16 source; + u8 index; + u8 clk_src; + u8 clk_div; +} clk_rst_t; + +/*! Generic clock enable/disable. */ +void clock_enable(const clk_rst_t *clk); +void clock_disable(const clk_rst_t *clk); + +/*! Clock control for specific hardware portions. */ +void clock_enable_fuse(bool enable); +void clock_enable_uart(u32 idx); +void clock_disable_uart(u32 idx); +int clock_uart_use_src_div(u32 idx, u32 baud); +void clock_enable_i2c(u32 idx); +void clock_disable_i2c(u32 idx); +void clock_enable_se(); +void clock_enable_tzram(); +void clock_enable_host1x(); +void clock_disable_host1x(); +void clock_enable_tsec(); +void clock_disable_tsec(); +void clock_enable_nvdec(); +void clock_disable_nvdec(); +void clock_enable_nvjpg(); +void clock_disable_nvjpg(); +void clock_enable_vic(); +void clock_disable_vic(); +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_disable_cl_dvfs(); +void clock_enable_coresight(); +void clock_disable_coresight(); +void clock_enable_pwm(); +void clock_disable_pwm(); +void clock_enable_apbdma(); +void clock_disable_apbdma(); +void clock_enable_ahbdma(); +void clock_disable_ahbdma(); +void clock_enable_actmon(); +void clock_disable_actmon(); +void clock_enable_extperiph1(); +void clock_disable_extperiph1(); +void clock_enable_extperiph2(); +void clock_disable_extperiph2(); + +void clock_enable_plld(u32 divp, u32 divn, bool lowpower, bool tegra_t210); +void clock_enable_pllx(); +void clock_enable_pllc(u32 divn); +void clock_disable_pllc(); +void clock_enable_pllu(); +void clock_disable_pllu(); +void clock_enable_utmipll(); + +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val); +void clock_sdmmc_get_card_clock_div(u32 *pclock, 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); + +u32 clock_get_osc_freq(); +u32 clock_get_dev_freq(clock_pto_id_t id); + +#endif diff --git a/nyx/nyx_gui/soc/fuse.c b/bdk/soc/fuse.c similarity index 62% rename from nyx/nyx_gui/soc/fuse.c rename to bdk/soc/fuse.c index 04d3612..9668196 100644 --- a/nyx/nyx_gui/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * Copyright (c) 2018 balika011 - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,10 +19,15 @@ #include -#include "../soc/fuse.h" -#include "../soc/t210.h" - -#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) +#include +#include +#include +#include +#include +#include +#include +#include +#include static const u32 evp_thunk_template[] = { 0xe92d0007, // STMFD SP!, {R0-R2} @@ -40,12 +45,19 @@ static const u32 evp_thunk_template[] = { 0xe3822001, // ORR R2, R2, #1 0xe8bd0003, // LDMFD SP!, {R0,R1} 0xe12fff12, // BX R2 + // idx: 15: 0x001007b0, // off_1007EC DCD evp_thunk_template 0x001007f8, // off_1007F0 DCD thunk_end 0x40004c30, // off_1007F4 DCD iram_evp_thunks // thunk_end is here }; -static const u32 evp_thunk_template_len = sizeof(evp_thunk_template); + +static const u32 evp_thunk_func_offsets_t210b01[] = { + 0x0010022c, // off_100268 DCD evp_thunk_template + 0x00100174, // off_10026C DCD thunk_end + 0x40004164, // off_100270 DCD iram_evp_thunks + // thunk_end is here +}; // treated as 12bit values static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11}; @@ -60,13 +72,105 @@ u32 fuse_read_odm(u32 idx) return FUSE(FUSE_RESERVED_ODMX(idx)); } +u32 fuse_read_odm_keygen_rev() +{ + bool has_new_keygen; + + // Check if it has new keygen. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + has_new_keygen = true; + else + has_new_keygen = (fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2; + + if (has_new_keygen) + return (fuse_read_odm(2) & 0x1F); + + return 0; +} + +u32 fuse_read_dramid(bool raw_id) +{ + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + u32 odm4 = fuse_read_odm(4); + + u32 dramid = (odm4 & 0xF8) >> 3; + + // Get extended dram id info. + if (!tegra_t210) + dramid |= (odm4 & 0x7000) >> 7; + + if (raw_id) + return dramid; + + if (tegra_t210) + { + if (dramid > 7) + dramid = 0; + } + else + { + if (dramid > 34) + dramid = 8; + } + + return dramid; +} + +u32 fuse_read_hw_state() +{ + if ((fuse_read_odm(4) & 3) != 3) + return FUSE_NX_HW_STATE_PROD; + else + return FUSE_NX_HW_STATE_DEV; +} + +u32 fuse_read_hw_type() +{ + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) + { + switch ((fuse_read_odm(4) & 0xF0000) >> 16) + { + case 2: + return FUSE_NX_HW_TYPE_HOAG; + case 4: + return FUSE_NX_HW_TYPE_AULA; + case 1: + default: + return FUSE_NX_HW_TYPE_IOWA; + } + } + + return FUSE_NX_HW_TYPE_ICOSA; +} + +int fuse_set_sbk() +{ + if (FUSE(FUSE_PRIVATE_KEY0) != 0xFFFFFFFF) + { + // Read SBK from fuses. + u32 sbk[4] = { + FUSE(FUSE_PRIVATE_KEY0), + FUSE(FUSE_PRIVATE_KEY1), + FUSE(FUSE_PRIVATE_KEY2), + FUSE(FUSE_PRIVATE_KEY3) + }; + + // Set SBK to slot 14. + se_aes_key_set(14, sbk, SE_KEY_128_SIZE); + + // Lock SBK from being read. + se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG); + + return 1; + } + + return 0; +} + void fuse_wait_idle() { - u32 ctrl; - do - { - ctrl = FUSE(FUSE_CTRL); - } while (((ctrl >> 16) & 0x1f) != 4); + while (((FUSE(FUSE_CTRL) >> 16) & 0x1F) != FUSE_STATUS_IDLE) + ; } u32 fuse_read(u32 addr) @@ -74,22 +178,25 @@ u32 fuse_read(u32 addr) FUSE(FUSE_ADDR) = addr; FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; fuse_wait_idle(); + return FUSE(FUSE_RDATA); } void fuse_read_array(u32 *words) { - for (u32 i = 0; i < 192; i++) + u32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ? + FUSE_ARRAY_WORDS_NUM_B01 : FUSE_ARRAY_WORDS_NUM; + + for (u32 i = 0; i < array_size; i++) words[i] = fuse_read(i); } -static u32 _parity32_even(u32 *words, u32 count) +static u32 _parity32_even(const u32 *words, u32 count) { u32 acc = words[0]; for (u32 i = 1; i < count; i++) - { acc ^= words[i]; - } + u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff; u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8; u32 x = hi ^ lo; @@ -105,27 +212,27 @@ static int _patch_hash_one(u32 *word) u32 bits20_31 = *word & 0xfff00000; u32 parity_bit = _parity32_even(&bits20_31, 1); u32 hash = 0; + for (u32 i = 0; i < 12; i++) { if (*word & (1 << (20 + i))) - { hash ^= hash_vals[i]; - } } + if (hash == 0) { if (parity_bit == 0) - { return 0; - } + *word ^= 1 << 24; + return 1; } + if (parity_bit == 0) - { return 3; - } - for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++) + + for (u32 i = 0; i < ARRAY_SIZE(hash_vals); i++) { if (hash_vals[i] == hash) { @@ -133,6 +240,7 @@ static int _patch_hash_one(u32 *word) return 1; } } + return 2; } @@ -153,9 +261,7 @@ static int _patch_hash_multi(u32 *words, u32 count) for (u32 bitpos = 0; bitpos < 32; bitpos++) { if ((w >> bitpos) & 1) - { hash ^= 0x4000 + i * 32 + bitpos; - } } } } @@ -167,16 +273,14 @@ static int _patch_hash_multi(u32 *words, u32 count) if (hash == 0) { if (parity_bit == 0) - { return 0; - } + words[0] ^= 0x8000; return 1; } if (parity_bit == 0) - { return 3; - } + u32 bitcount = hash - 0x4000; if (bitcount < 16 || bitcount >= count * 32) { @@ -184,14 +288,11 @@ static int _patch_hash_multi(u32 *words, u32 count) for (u32 bitpos = 0; bitpos < 15; bitpos++) { if ((hash >> bitpos) & 1) - { num_set++; - } } if (num_set != 1) - { return 2; - } + words[0] ^= hash; return 1; } @@ -204,29 +305,35 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) u32 words[80]; u32 word_count; u32 word_addr; - u32 word0 = 0; + u32 word0; u32 total_read = 0; word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); word_count &= 0x7F; - word_addr = 191; + word_addr = FUSE_ARRAY_WORDS_NUM - 1; while (word_count) { total_read += word_count; - if (total_read >= ARRAYSIZE(words)) - { + if (total_read >= ARRAY_SIZE(words)) break; - } for (u32 i = 0; i < word_count; i++) + { words[i] = fuse_read(word_addr--); + // Parse extra T210B01 fuses when the difference is reached. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 && + word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) - + (FUSE_ARRAY_WORDS_NUM_B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32))) + { + word_addr = FUSE_ARRAY_WORDS_NUM_B01 - 1; + } + } word0 = words[0]; if (_patch_hash_multi(words, word_count) >= 2) - { return 1; - } + u32 ipatch_count = (words[0] >> 16) & 0xF; if (ipatch_count) { @@ -239,13 +346,14 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) ipatch(addr, data); } } + words[0] = word0; if ((word0 >> 25) == 0) break; + if (_patch_hash_one(&word0) >= 2) - { return 3; - } + word_count = word0 >> 25; } @@ -257,33 +365,48 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) u32 words[80]; u32 word_count; u32 word_addr; - u32 word0 = 0; + u32 word0; u32 total_read = 0; int evp_thunk_written = 0; void *evp_thunk_dst_addr = 0; + bool t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; + u32 *evp_thunk_tmp = (u32 *)malloc(sizeof(evp_thunk_template)); + memcpy(evp_thunk_tmp, evp_thunk_template, sizeof(evp_thunk_template)); memset(iram_evp_thunks, 0, *iram_evp_thunks_len); + if (t210b01) + memcpy(&evp_thunk_tmp[15], evp_thunk_func_offsets_t210b01, sizeof(evp_thunk_func_offsets_t210b01)); + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); word_count &= 0x7F; - word_addr = 191; + word_addr = FUSE_ARRAY_WORDS_NUM - 1; while (word_count) { total_read += word_count; - if (total_read >= ARRAYSIZE(words)) - { + if (total_read >= ARRAY_SIZE(words)) break; - } for (u32 i = 0; i < word_count; i++) + { words[i] = fuse_read(word_addr--); + // Parse extra T210B01 fuses when the difference is reached. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 && + word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) - + (FUSE_ARRAY_WORDS_NUM_B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32))) + { + word_addr = FUSE_ARRAY_WORDS_NUM_B01 - 1; + } + } word0 = words[0]; if (_patch_hash_multi(words, word_count) >= 2) { + free(evp_thunk_tmp); return 1; } + u32 ipatch_count = (words[0] >> 16) & 0xF; u32 insn_count = word_count - ipatch_count - 1; if (insn_count) @@ -292,10 +415,10 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) { evp_thunk_dst_addr = (void *)iram_evp_thunks; - memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len); - evp_thunk_dst_addr += evp_thunk_template_len; + memcpy(evp_thunk_dst_addr, (void *)evp_thunk_tmp, sizeof(evp_thunk_template)); + evp_thunk_dst_addr += sizeof(evp_thunk_template); evp_thunk_written = 1; - *iram_evp_thunks_len = evp_thunk_template_len; + *iram_evp_thunks_len = sizeof(evp_thunk_template); //write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks); } @@ -305,28 +428,34 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) evp_thunk_dst_addr += thunk_patch_len; *iram_evp_thunks_len += thunk_patch_len; } + words[0] = word0; if ((word0 >> 25) == 0) break; + if (_patch_hash_one(&word0) >= 2) { + free(evp_thunk_tmp); return 3; } + word_count = word0 >> 25; } + free(evp_thunk_tmp); + return 0; } bool fuse_check_patched_rcm() { - // Check if XUSB in use. - if (FUSE(FUSE_RESERVED_SW) & (1<<7)) + // Check if XUSB in use or Tegra X1+. + if (FUSE(FUSE_RESERVED_SW) & (1<<7) || hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) return true; // Check if RCM is ipatched. u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; - u32 word_addr = 191; + u32 word_addr = FUSE_ARRAY_WORDS_NUM - 1; while (word_count) { diff --git a/bdk/soc/fuse.h b/bdk/soc/fuse.h new file mode 100644 index 0000000..48a2c7f --- /dev/null +++ b/bdk/soc/fuse.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 shuffle2 + * Copyright (c) 2018 balika011 + * Copyright (c) 2019-2023 CTCaer + * + * 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 + +/*! 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 +#define FUSE_PRIV2RESHIFT 0x3C +#define FUSE_FUSETIME_RD0 0x40 +#define FUSE_FUSETIME_RD1 0x44 +#define FUSE_FUSETIME_RD2 0x48 +#define FUSE_FUSETIME_RD3 0x4C +#define FUSE_PRIVATE_KEY0_NONZERO 0x80 +#define FUSE_PRIVATE_KEY1_NONZERO 0x84 +#define FUSE_PRIVATE_KEY2_NONZERO 0x88 +#define FUSE_PRIVATE_KEY3_NONZERO 0x8C +#define FUSE_PRIVATE_KEY4_NONZERO 0x90 + +/*! Fuse Cached registers */ +#define FUSE_RESERVED_ODM8_B01 0x98 +#define FUSE_RESERVED_ODM9_B01 0x9C +#define FUSE_RESERVED_ODM10_B01 0xA0 +#define FUSE_RESERVED_ODM11_B01 0xA4 +#define FUSE_RESERVED_ODM12_B01 0xA8 +#define FUSE_RESERVED_ODM13_B01 0xAC +#define FUSE_RESERVED_ODM14_B01 0xB0 +#define FUSE_RESERVED_ODM15_B01 0xB4 +#define FUSE_RESERVED_ODM16_B01 0xB8 +#define FUSE_RESERVED_ODM17_B01 0xBC +#define FUSE_RESERVED_ODM18_B01 0xC0 +#define FUSE_RESERVED_ODM19_B01 0xC4 +#define FUSE_RESERVED_ODM20_B01 0xC8 +#define FUSE_RESERVED_ODM21_B01 0xCC +#define FUSE_KEK00_B01 0xD0 +#define FUSE_KEK01_B01 0xD4 +#define FUSE_KEK02_B01 0xD8 +#define FUSE_KEK03_B01 0xDC +#define FUSE_BEK00_B01 0xE0 +#define FUSE_BEK01_B01 0xE4 +#define FUSE_BEK02_B01 0xE8 +#define FUSE_BEK03_B01 0xEC +#define FUSE_OPT_RAM_RTSEL_TSMCSP_PO4SVT_B01 0xF0 +#define FUSE_OPT_RAM_WTSEL_TSMCSP_PO4SVT_B01 0xF4 +#define FUSE_OPT_RAM_RTSEL_TSMCPDP_PO4SVT_B01 0xF8 +#define FUSE_OPT_RAM_MTSEL_TSMCPDP_PO4SVT_B01 0xFC + +#define FUSE_PRODUCTION_MODE 0x100 +#define FUSE_JTAG_SECUREID_VALID 0x104 +#define FUSE_ODM_LOCK 0x108 +#define FUSE_OPT_OPENGL_EN 0x10C +#define FUSE_SKU_INFO 0x110 +#define FUSE_CPU_SPEEDO_0_CALIB 0x114 +#define FUSE_CPU_IDDQ_CALIB 0x118 + +#define FUSE_RESERVED_ODM22_B01 0x11C +#define FUSE_RESERVED_ODM23_B01 0x120 +#define FUSE_RESERVED_ODM24_B01 0x124 + +#define FUSE_OPT_FT_REV 0x128 +#define FUSE_CPU_SPEEDO_1_CALIB 0x12C +#define FUSE_CPU_SPEEDO_2_CALIB 0x130 +#define FUSE_SOC_SPEEDO_0_CALIB 0x134 +#define FUSE_SOC_SPEEDO_1_CALIB 0x138 +#define FUSE_SOC_SPEEDO_2_CALIB 0x13C +#define FUSE_SOC_IDDQ_CALIB 0x140 + +#define FUSE_RESERVED_ODM25_B01 0x144 + +#define FUSE_FA 0x148 +#define FUSE_RESERVED_PRODUCTION 0x14C +#define FUSE_HDMI_LANE0_CALIB 0x150 +#define FUSE_HDMI_LANE1_CALIB 0x154 +#define FUSE_HDMI_LANE2_CALIB 0x158 +#define FUSE_HDMI_LANE3_CALIB 0x15C +#define FUSE_ENCRYPTION_RATE 0x160 +#define FUSE_PUBLIC_KEY0 0x164 +#define FUSE_PUBLIC_KEY1 0x168 +#define FUSE_PUBLIC_KEY2 0x16C +#define FUSE_PUBLIC_KEY3 0x170 +#define FUSE_PUBLIC_KEY4 0x174 +#define FUSE_PUBLIC_KEY5 0x178 +#define FUSE_PUBLIC_KEY6 0x17C +#define FUSE_PUBLIC_KEY7 0x180 +#define FUSE_TSENSOR1_CALIB 0x184 +#define FUSE_TSENSOR2_CALIB 0x188 + +#define FUSE_OPT_SECURE_SCC_DIS_B01 0x18C + +#define FUSE_OPT_CP_REV 0x190 +#define FUSE_OPT_PFG 0x194 +#define FUSE_TSENSOR0_CALIB 0x198 +#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19C +#define FUSE_SECURITY_MODE 0x1A0 +#define FUSE_PRIVATE_KEY0 0x1A4 +#define FUSE_PRIVATE_KEY1 0x1A8 +#define FUSE_PRIVATE_KEY2 0x1AC +#define FUSE_PRIVATE_KEY3 0x1B0 +#define FUSE_PRIVATE_KEY4 0x1B4 +#define FUSE_ARM_JTAG_DIS 0x1B8 +#define FUSE_BOOT_DEVICE_INFO 0x1BC +#define FUSE_RESERVED_SW 0x1C0 +#define FUSE_OPT_VP9_DISABLE 0x1C4 + +#define FUSE_RESERVED_ODM0 0x1C8 +#define FUSE_RESERVED_ODM1 0x1CC +#define FUSE_RESERVED_ODM2 0x1D0 +#define FUSE_RESERVED_ODM3 0x1D4 +#define FUSE_RESERVED_ODM4 0x1D8 +#define FUSE_RESERVED_ODM5 0x1DC +#define FUSE_RESERVED_ODM6 0x1E0 +#define FUSE_RESERVED_ODM7 0x1E4 + +#define FUSE_OBS_DIS 0x1E8 + +#define FUSE_OPT_NVJTAG_PROTECTION_ENABLE_B01 0x1EC + +#define FUSE_USB_CALIB 0x1F0 +#define FUSE_SKU_DIRECT_CONFIG 0x1F4 +#define FUSE_KFUSE_PRIVKEY_CTRL 0x1F8 +#define FUSE_PACKAGE_INFO 0x1FC +#define FUSE_OPT_VENDOR_CODE 0x200 +#define FUSE_OPT_FAB_CODE 0x204 +#define FUSE_OPT_LOT_CODE_0 0x208 +#define FUSE_OPT_LOT_CODE_1 0x20C +#define FUSE_OPT_WAFER_ID 0x210 +#define FUSE_OPT_X_COORDINATE 0x214 +#define FUSE_OPT_Y_COORDINATE 0x218 +#define FUSE_OPT_SEC_DEBUG_EN 0x21C +#define FUSE_OPT_OPS_RESERVED 0x220 +#define FUSE_SATA_CALIB 0x224 + +#define FUSE_SPARE_REGISTER_ODM_B01 0x224 + +#define FUSE_GPU_IDDQ_CALIB 0x228 +#define FUSE_TSENSOR3_CALIB 0x22C +#define FUSE_CLOCK_BONDOUT0 0x230 +#define FUSE_CLOCK_BONDOUT1 0x234 + +#define FUSE_RESERVED_ODM26_B01 0x238 +#define FUSE_RESERVED_ODM27_B01 0x23C +#define FUSE_RESERVED_ODM28_B01 0x240 + +#define FUSE_OPT_SAMPLE_TYPE 0x244 +#define FUSE_OPT_SUBREVISION 0x248 +#define FUSE_OPT_SW_RESERVED_0 0x24C +#define FUSE_OPT_SW_RESERVED_1 0x250 +#define FUSE_TSENSOR4_CALIB 0x254 +#define FUSE_TSENSOR5_CALIB 0x258 +#define FUSE_TSENSOR6_CALIB 0x25C +#define FUSE_TSENSOR7_CALIB 0x260 +#define FUSE_OPT_PRIV_SEC_DIS 0x264 +#define FUSE_PKC_DISABLE 0x268 + +#define FUSE_BOOT_SECURITY_INFO_B01 0x268 +#define FUSE_OPT_RAM_RTSEL_TSMCSP_PO4HVT_B01 0x26C +#define FUSE_OPT_RAM_WTSEL_TSMCSP_PO4HVT_B01 0x270 +#define FUSE_OPT_RAM_RTSEL_TSMCPDP_PO4HVT_B01 0x274 +#define FUSE_OPT_RAM_MTSEL_TSMCPDP_PO4HVT_B01 0x278 + +#define FUSE_FUSE2TSEC_DEBUG_DISABLE 0x27C +#define FUSE_TSENSOR_COMMON 0x280 +#define FUSE_OPT_CP_BIN 0x284 +#define FUSE_OPT_GPU_DISABLE 0x288 +#define FUSE_OPT_FT_BIN 0x28C +#define FUSE_OPT_DONE_MAP 0x290 + +#define FUSE_RESERVED_ODM29_B01 0x294 + +#define FUSE_APB2JTAG_DISABLE 0x298 +#define FUSE_ODM_INFO 0x29C +#define FUSE_ARM_CRYPT_DE_FEATURE 0x2A8 + +#define FUSE_OPT_RAM_WTSEL_TSMCPDP_PO4SVT_B01 0x2B0 +#define FUSE_OPT_RAM_RCT_TSMCDP_PO4SVT_B01 0x2B4 +#define FUSE_OPT_RAM_WCT_TSMCDP_PO4SVT_B01 0x2B8 +#define FUSE_OPT_RAM_KP_TSMCDP_PO4SVT_B01 0x2BC + +#define FUSE_WOA_SKU_FLAG 0x2C0 +#define FUSE_ECO_RESERVE_1 0x2C4 +#define FUSE_GCPLEX_CONFIG_FUSE 0x2C8 +#define FUSE_PRODUCTION_MONTH 0x2CC +#define FUSE_RAM_REPAIR_INDICATOR 0x2D0 +#define FUSE_TSENSOR9_CALIB 0x2D4 +#define FUSE_VMIN_CALIBRATION 0x2DC +#define FUSE_AGING_SENSOR_CALIBRATION 0x2E0 +#define FUSE_DEBUG_AUTHENTICATION 0x2E4 +#define FUSE_SECURE_PROVISION_INDEX 0x2E8 +#define FUSE_SECURE_PROVISION_INFO 0x2EC +#define FUSE_OPT_GPU_DISABLE_CP1 0x2F0 +#define FUSE_SPARE_ENDIS 0x2F4 +#define FUSE_ECO_RESERVE_0 0x2F8 +#define FUSE_RESERVED_CALIB0 0x304 +#define FUSE_RESERVED_CALIB1 0x308 +#define FUSE_OPT_GPU_TPC0_DISABLE 0x30C +#define FUSE_OPT_GPU_TPC0_DISABLE_CP1 0x310 +#define FUSE_OPT_CPU_DISABLE 0x314 +#define FUSE_OPT_CPU_DISABLE_CP1 0x318 +#define FUSE_TSENSOR10_CALIB 0x31C +#define FUSE_TSENSOR10_CALIB_AUX 0x320 +#define FUSE_OPT_RAM_SVOP_DP 0x324 +#define FUSE_OPT_RAM_SVOP_PDP 0x328 +#define FUSE_OPT_RAM_SVOP_REG 0x32C +#define FUSE_OPT_RAM_SVOP_SP 0x330 +#define FUSE_OPT_RAM_SVOP_SMPDP 0x334 + +#define FUSE_OPT_RAM_WTSEL_TSMCPDP_PO4HVT_B01 0x324 +#define FUSE_OPT_RAM_RCT_TSMCDP_PO4HVT_B01 0x328 +#define FUSE_OPT_RAM_WCT_TSMCDP_PO4HVT_B01 0x32c +#define FUSE_OPT_RAM_KP_TSMCDP_PO4HVT_B01 0x330 +#define FUSE_OPT_ROM_SVOP_SP_B01 0x334 + +#define FUSE_OPT_GPU_TPC0_DISABLE_CP2 0x338 +#define FUSE_OPT_GPU_TPC1_DISABLE 0x33C +#define FUSE_OPT_GPU_TPC1_DISABLE_CP1 0x340 +#define FUSE_OPT_GPU_TPC1_DISABLE_CP2 0x344 +#define FUSE_OPT_CPU_DISABLE_CP2 0x348 +#define FUSE_OPT_GPU_DISABLE_CP2 0x34C +#define FUSE_USB_CALIB_EXT 0x350 +#define FUSE_RESERVED_FIELD 0x354 +#define FUSE_SPARE_REALIGNMENT_REG 0x37C +#define FUSE_SPARE_BIT_0 0x380 +//... +#define FUSE_SPARE_BIT_31 0x3FC + +/*! Fuse commands. */ +#define FUSE_IDLE 0x0 +#define FUSE_READ 0x1 +#define FUSE_WRITE 0x2 +#define FUSE_SENSE 0x3 +#define FUSE_CMD_MASK 0x3 + +/*! Fuse status. */ +#define FUSE_STATUS_RESET 0 +#define FUSE_STATUS_POST_RESET 1 +#define FUSE_STATUS_LOAD_ROW0 2 +#define FUSE_STATUS_LOAD_ROW1 3 +#define FUSE_STATUS_IDLE 4 +#define FUSE_STATUS_READ_SETUP 5 +#define FUSE_STATUS_READ_STROBE 6 +#define FUSE_STATUS_SAMPLE_FUSES 7 +#define FUSE_STATUS_READ_HOLD 8 +#define FUSE_STATUS_FUSE_SRC_SETUP 9 +#define FUSE_STATUS_WRITE_SETUP 10 +#define FUSE_STATUS_WRITE_ADDR_SETUP 11 +#define FUSE_STATUS_WRITE_PROGRAM 12 +#define FUSE_STATUS_WRITE_ADDR_HOLD 13 +#define FUSE_STATUS_FUSE_SRC_HOLD 14 +#define FUSE_STATUS_LOAD_RIR 15 +#define FUSE_STATUS_READ_BEFORE_WRITE_SETUP 16 +#define FUSE_STATUS_READ_DEASSERT_PD 17 + +/*! Fuse cache registers. */ +#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) + +#define FUSE_ARRAY_WORDS_NUM 192 +#define FUSE_ARRAY_WORDS_NUM_B01 256 + +enum +{ + FUSE_NX_HW_TYPE_ICOSA, + FUSE_NX_HW_TYPE_IOWA, + FUSE_NX_HW_TYPE_HOAG, + FUSE_NX_HW_TYPE_AULA +}; + +enum +{ + FUSE_NX_HW_STATE_PROD, + FUSE_NX_HW_STATE_DEV +}; + +void fuse_disable_program(); +u32 fuse_read_odm(u32 idx); +u32 fuse_read_odm_keygen_rev(); +u32 fuse_read_dramid(bool raw_id); +u32 fuse_read_hw_state(); +u32 fuse_read_hw_type(); +int fuse_set_sbk(); +void fuse_wait_idle(); +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); +void fuse_read_array(u32 *words); +bool fuse_check_patched_rcm(); + +#endif diff --git a/bdk/soc/gpio.c b/bdk/soc/gpio.c new file mode 100644 index 0000000..8575333 --- /dev/null +++ b/bdk/soc/gpio.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2023 CTCaer + * + * 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 + +#define GPIO_BANK_IDX(port) ((port) >> 2) +#define GPIO_PORT_OFFSET(port) ((GPIO_BANK_IDX(port) << 8) + (((port) % 4) << 2)) + +#define GPIO_CNF_OFFSET(port) (0x00 + GPIO_PORT_OFFSET(port)) +#define GPIO_OE_OFFSET(port) (0x10 + GPIO_PORT_OFFSET(port)) +#define GPIO_OUT_OFFSET(port) (0x20 + GPIO_PORT_OFFSET(port)) +#define GPIO_IN_OFFSET(port) (0x30 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_STA_OFFSET(port) (0x40 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_ENB_OFFSET(port) (0x50 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_LVL_OFFSET(port) (0x60 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_CLR_OFFSET(port) (0x70 + GPIO_PORT_OFFSET(port)) + +#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + GPIO_PORT_OFFSET(port)) +#define GPIO_OE_MASKED_OFFSET(port) (0x90 + GPIO_PORT_OFFSET(port)) +#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + GPIO_PORT_OFFSET(port)) +#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + GPIO_PORT_OFFSET(port)) + +#define GPIO_DB_CTRL_OFFSET(port) (0xB0 + GPIO_PORT_OFFSET(port)) +#define GPIO_DB_CNT_OFFSET(port) (0xF0 + GPIO_PORT_OFFSET(port)) + +#define GPIO_IRQ_BANK1 32 +#define GPIO_IRQ_BANK2 33 +#define GPIO_IRQ_BANK3 34 +#define GPIO_IRQ_BANK4 35 +#define GPIO_IRQ_BANK5 55 +#define GPIO_IRQ_BANK6 87 +#define GPIO_IRQ_BANK7 89 +#define GPIO_IRQ_BANK8 125 + +static u8 gpio_bank_irq_ids[8] = { + GPIO_IRQ_BANK1, GPIO_IRQ_BANK2, GPIO_IRQ_BANK3, GPIO_IRQ_BANK4, + GPIO_IRQ_BANK5, GPIO_IRQ_BANK6, GPIO_IRQ_BANK7, GPIO_IRQ_BANK8 +}; + +void gpio_config(u32 port, u32 pins, int mode) +{ + const u32 offset = GPIO_CNF_OFFSET(port); + + if (mode) + GPIO(offset) |= pins; + else + GPIO(offset) &= ~pins; + + (void)GPIO(offset); // Commit the write. +} + +void gpio_output_enable(u32 port, u32 pins, int enable) +{ + const u32 port_offset = GPIO_OE_OFFSET(port); + + if (enable) + GPIO(port_offset) |= pins; + else + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. +} + +void gpio_write(u32 port, u32 pins, int high) +{ + const u32 port_offset = GPIO_OUT_OFFSET(port); + + if (high) + GPIO(port_offset) |= pins; + else + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. +} + +void gpio_direction_input(u32 port, u32 pins) +{ + gpio_config(port, pins, GPIO_MODE_GPIO); + gpio_output_enable(port, pins, GPIO_OUTPUT_DISABLE); +} + +void gpio_direction_output(u32 port, u32 pins, int high) +{ + gpio_config(port, pins, GPIO_MODE_GPIO); + gpio_write(port, pins, high); + gpio_output_enable(port, pins, GPIO_OUTPUT_ENABLE); +} + +int gpio_read(u32 port, u32 pins) +{ + const u32 port_offset = GPIO_IN_OFFSET(port); + + return (GPIO(port_offset) & pins) ? 1 : 0; +} + +void gpio_set_debounce(u32 port, u32 pins, u32 ms) +{ + const u32 db_ctrl_offset = GPIO_DB_CTRL_OFFSET(port); + const u32 db_cnt_offset = GPIO_DB_CNT_OFFSET(port); + + if (ms) + { + if (ms > 255) + ms = 255; + + // Debounce time affects all pins of the same port. + GPIO(db_cnt_offset) = ms; + GPIO(db_ctrl_offset) = (pins << 8) | pins; + } + else + GPIO(db_ctrl_offset) = (pins << 8) | 0; + + (void)GPIO(db_ctrl_offset); // Commit the write. +} + +static void _gpio_interrupt_clear(u32 port, u32 pins) +{ + const u32 port_offset = GPIO_INT_CLR_OFFSET(port); + + GPIO(port_offset) |= pins; + + (void)GPIO(port_offset); // Commit the write. +} + +int gpio_interrupt_status(u32 port, u32 pins) +{ + const u32 port_offset = GPIO_INT_STA_OFFSET(port); + const u32 enabled_mask = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins; + + int status = ((GPIO(port_offset) & pins) && enabled_mask) ? 1 : 0; + + // Clear the interrupt status. + if (status) + _gpio_interrupt_clear(port, pins); + + return status; +} + +void gpio_interrupt_enable(u32 port, u32 pins, int enable) +{ + const u32 port_offset = GPIO_INT_ENB_OFFSET(port); + + // Clear any possible stray interrupt. + _gpio_interrupt_clear(port, pins); + + if (enable) + GPIO(port_offset) |= pins; + else + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. +} + +void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta) +{ + const u32 port_offset = GPIO_INT_LVL_OFFSET(port); + + u32 val = GPIO(port_offset); + + if (high) + val |= pins; + else + val &= ~pins; + + if (edge) + val |= pins << 8; + else + val &= ~(pins << 8); + + if (delta) + val |= pins << 16; + else + val &= ~(pins << 16); + + GPIO(port_offset) = val; + + (void)GPIO(port_offset); // Commit the write. + + // Clear any possible stray interrupt. + _gpio_interrupt_clear(port, pins); +} + +u32 gpio_get_bank_irq_id(u32 port) +{ + const u32 bank_idx = GPIO_BANK_IDX(port); + + return gpio_bank_irq_ids[bank_idx]; +} diff --git a/bootloader/soc/gpio.h b/bdk/soc/gpio.h similarity index 66% rename from bootloader/soc/gpio.h rename to bdk/soc/gpio.h index 83170b0..7f94de5 100644 --- a/bootloader/soc/gpio.h +++ b/bdk/soc/gpio.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,24 +18,37 @@ #ifndef _GPIO_H_ #define _GPIO_H_ -#include "../utils/types.h" +#include #define GPIO_MODE_SPIO 0 #define GPIO_MODE_GPIO 1 + #define GPIO_OUTPUT_DISABLE 0 #define GPIO_OUTPUT_ENABLE 1 + +#define GPIO_IRQ_DISABLE 0 +#define GPIO_IRQ_ENABLE 1 + #define GPIO_LOW 0 #define GPIO_HIGH 1 +#define GPIO_FALLING 0 +#define GPIO_RISING 1 + +#define GPIO_LEVEL 0 +#define GPIO_EDGE 1 + +#define GPIO_CONFIGURED_EDGE 0 +#define GPIO_ANY_EDGE_CHANGE 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) +#define GPIO_PIN_0 BIT(0) +#define GPIO_PIN_1 BIT(1) +#define GPIO_PIN_2 BIT(2) +#define GPIO_PIN_3 BIT(3) +#define GPIO_PIN_4 BIT(4) +#define GPIO_PIN_5 BIT(5) +#define GPIO_PIN_6 BIT(6) +#define GPIO_PIN_7 BIT(7) /*! GPIO ports (A-EE). */ #define GPIO_PORT_A 0 @@ -71,7 +85,14 @@ void gpio_config(u32 port, u32 pins, int mode); void gpio_output_enable(u32 port, u32 pins, int enable); +void gpio_direction_input(u32 port, u32 pins); +void gpio_direction_output(u32 port, u32 pins, int high); void gpio_write(u32 port, u32 pins, int high); -int gpio_read(u32 port, u32 pins); +int gpio_read(u32 port, u32 pins); +void gpio_set_debounce(u32 port, u32 pins, u32 ms); +int gpio_interrupt_status(u32 port, u32 pins); +void gpio_interrupt_enable(u32 port, u32 pins, int enable); +void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta); +u32 gpio_get_bank_irq_id(u32 port); #endif diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c new file mode 100644 index 0000000..7bfa599 --- /dev/null +++ b/bdk/soc/hw_init.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern boot_cfg_t b_cfg; +extern volatile nyx_storage_t *nyx_str; + +u32 hw_rst_status; +u32 hw_rst_reason; + +u32 hw_get_chip_id() +{ + if (((APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF) >= GP_HIDREV_MAJOR_T210B01) + return GP_HIDREV_MAJOR_T210B01; + else + return GP_HIDREV_MAJOR_T210; +} + +/* + * CLK_OSC - 38.4 MHz crystal. + * CLK_M - 19.2 MHz (osc/2). + * CLK_S - 32.768 KHz (from PMIC). + * SCLK - 204MHz init (-> 408MHz -> OC). + * HCLK - 204MHz init (-> 408MHz -> OC). + * PCLK - 68MHz init (-> 136MHz -> OC/4). + */ + +static void _config_oscillators() +{ + CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. + SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. + TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. + + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; + PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; + PMC(APB_MISC_GP_ASDBGREG) = (PMC(APB_MISC_GP_ASDBGREG) & 0xFCFFFFFF) | (2 << 24); // CFG2TMC_RAM_SVOP_PDP. + + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable. + + PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; // 0x249F = 19200000 * (16 / 32.768 kHz). + + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set BPMP/SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set BPMP/SCLK source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. +} + +void hw_config_arbiter(bool reset) +{ + if (reset) + { + ARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x0040090; + ARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x12024C2; + ARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x2201209; + ARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320365B; + } + else + { + ARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x12412D1; + ARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x0000000; + ARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x220244A; + ARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320369B; + } +} + +// The uart is skipped for Copper, Hoag and Calcio. Used in Icosa, Iowa and Aula. +static void _config_gpios(bool nx_hoag) +{ + // Clamp inputs when tristated. + APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; + + if (!nx_hoag) + { + // Turn Joy-Con detect on. (GPIO mode and input logic for UARTB/C TX pins.) + PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; + PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + gpio_direction_input(GPIO_PORT_G, GPIO_PIN_0); + gpio_direction_input(GPIO_PORT_D, GPIO_PIN_1); + } + + // Set Joy-Con IsAttached pinmux. Shared with UARTB/UARTC TX. + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + + // Configure Joy-Con IsAttached pins. Shared with UARTB/UARTC TX. + gpio_direction_input(GPIO_PORT_E, GPIO_PIN_6); + gpio_direction_input(GPIO_PORT_H, GPIO_PIN_6); + + pinmux_config_i2c(I2C_1); + pinmux_config_i2c(I2C_5); + pinmux_config_uart(UART_A); + + // Configure volume up/down as inputs. + gpio_direction_input(GPIO_PORT_X, GPIO_PIN_6 | GPIO_PIN_7); + + // Configure HOME as input. (Shared with UARTB RTS). + PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + gpio_direction_input(GPIO_PORT_Y, GPIO_PIN_1); + + // Power button can be configured for hoag here. Only SKU where it's connected. +} + +static void _config_pmc_scratch() +{ + PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. + PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset WDT_DURING_BR. + PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; +} + +static void _mbist_workaround() +{ + // Make sure Audio clocks are enabled before accessing I2S. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); + + // Set mux output to SOR1 clock switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; + // Enabled PLLD and set csi to PLLD for test pattern generation. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; + + // Clear per-clock resets for APE/VIC/HOST1X/DISP1. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = BIT(CLK_Y_APE); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = BIT(CLK_X_VIC); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); + usleep(2); + + // I2S channels to master and disable SLCG. + I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE; + + // Set SLCG overrides. + DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE. + VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0xFFFFFFFF; + usleep(2); + + // Set per-clock reset for APE/VIC/HOST1X/DISP1. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = BIT(CLK_Y_APE); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = BIT(CLK_X_VIC); + + // Enable specific clocks and disable all others. + // CLK L Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = + BIT(CLK_H_PMC) | + BIT(CLK_H_FUSE); + // CLK H Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = + BIT(CLK_L_RTC) | + BIT(CLK_L_TMR) | + BIT(CLK_L_GPIO) | + BIT(CLK_L_BPMP_CACHE_CTRL); + // CLK U Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = + BIT(CLK_U_CSITE) | + BIT(CLK_U_IRAMA) | + BIT(CLK_U_IRAMB) | + BIT(CLK_U_IRAMC) | + BIT(CLK_U_IRAMD) | + BIT(CLK_U_BPMP_CACHE_RAM); + // CLK V Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = + BIT(CLK_V_MSELECT) | + BIT(CLK_V_APB2APE) | + BIT(CLK_V_SPDIF_DOUBLER) | + BIT(CLK_V_SE); + // CLK W Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = + BIT(CLK_W_PCIERX0) | + BIT(CLK_W_PCIERX1) | + BIT(CLK_W_PCIERX2) | + BIT(CLK_W_PCIERX3) | + BIT(CLK_W_PCIERX4) | + BIT(CLK_W_PCIERX5) | + BIT(CLK_W_ENTROPY) | + BIT(CLK_W_MC1); + // CLK X Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = + BIT(CLK_X_MC_CAPA) | + BIT(CLK_X_MC_CBPA) | + BIT(CLK_X_MC_CPU) | + BIT(CLK_X_MC_BBC) | + BIT(CLK_X_GPU) | + BIT(CLK_X_DBGAPB) | + BIT(CLK_X_PLLG_REF); + // CLK Y Devices. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = + BIT(CLK_Y_MC_CDPA) | + BIT(CLK_Y_MC_CCPA); + + // Disable clock gate overrides. + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; + + // Set child clock sources. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. +} + +static void _config_se_brom() +{ + // Enable Fuse visibility. + clock_enable_fuse(true); + + // Try to set SBK from fuses. If patched, skip. + fuse_set_sbk(); + + // Lock SSK (although it's not set and unused anyways). + // se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG); + + // This memset needs to happen here, else TZRAM will behave weirdly later on. + memset((void *)TZRAM_BASE, 0, TZRAM_SIZE); + PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE; + + // Clear SE interrupts. + SE(SE_INT_STATUS_REG) = SE_INT_OP_DONE | SE_INT_OUT_DONE | SE_INT_OUT_LL_BUF_WR | SE_INT_IN_DONE | SE_INT_IN_LL_BUF_RD; + + // Save reset reason. + hw_rst_status = PMC(APBDEV_PMC_SCRATCH200); + hw_rst_reason = PMC(APBDEV_PMC_RST_STATUS) & PMC_RST_STATUS_MASK; + + // Clear the boot reason to avoid problems later. + PMC(APBDEV_PMC_SCRATCH200) = 0; + PMC(APBDEV_PMC_RST_STATUS) = PMC_RST_STATUS_POR; + APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); +} + +static void _config_regulators(bool tegra_t210, bool nx_hoag) +{ + // Set RTC/AO domain to POR voltage. + if (tegra_t210) + max7762x_regulator_set_voltage(REGULATOR_LDO4, 1000000); + + // Disable low battery shutdown monitor. + max77620_low_battery_monitor_config(false); + + // Power on all relevant rails in case we came out of warmboot. Only keep MEM/MEM_COMP and SDMMC1 states. + PMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_MEM_COMP | PMC_NO_IOPOWER_SDMMC1 | PMC_NO_IOPOWER_MEM; + + // Make sure SDMMC1 IO/Core are powered off. + max7762x_regulator_enable(REGULATOR_LDO2, false); + gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); + PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1; + (void)PMC(APBDEV_PMC_NO_IOPOWER); + sd_power_cycle_time_start = get_tmr_ms(); + + // Disable backup battery charger. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); + + // Set PWR delay for forced shutdown off to 6s. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_RSVD | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); + + if (tegra_t210) + { + // Configure all Flexible Power Sequencers for MAX77620. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (0 << MAX77620_FPS_EN_SRC_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + max77620_regulator_config_fps(REGULATOR_LDO4); + max77620_regulator_config_fps(REGULATOR_LDO8); + max77620_regulator_config_fps(REGULATOR_SD0); + max77620_regulator_config_fps(REGULATOR_SD1); + max77620_regulator_config_fps(REGULATOR_SD3); + + // Set GPIO3 to FPS0 for SYS 3V3 EN. Enabled when FPS0 is enabled. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, (4 << MAX77620_FPS_PU_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); + + // Set vdd_core voltage to 1.125V. + max7762x_regulator_set_voltage(REGULATOR_SD0, 1125000); + + // Power down CPU/GPU regulators after L4T warmboot. + max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_DISABLE); + max77620_config_gpio(6, MAX77620_GPIO_OUTPUT_DISABLE); + + // Set POR configuration. + max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_POR_CFG); + max77621_config_default(REGULATOR_GPU0, MAX77621_CTRL_POR_CFG); + } + else + { + // Tegra X1+ set vdd_core voltage to 1.05V. + max7762x_regulator_set_voltage(REGULATOR_SD0, 1050000); + + // Power on SD2 regulator for supplying LDO0/1/8. + max7762x_regulator_set_voltage(REGULATOR_SD2, 1325000); + + // Set slew rate and enable SD2 regulator. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD2_CFG, (1 << MAX77620_SD_SR_SHIFT) | + (MAX77620_POWER_MODE_NORMAL << MAX77620_SD_POWER_MODE_SHIFT) | + MAX77620_SD_CFG1_FSRADE_SD_ENABLE); + + // Enable LDO8 on HOAG as it also powers I2C1 IO pads. + if (nx_hoag) + { + max7762x_regulator_set_voltage(REGULATOR_LDO8, 2800000); + max7762x_regulator_enable(REGULATOR_LDO8, true); + } + } +} + +void hw_init() +{ + // Get Chip ID and SKU. + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + bool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG; + + // Bootrom stuff we skipped by going through rcm. + _config_se_brom(); + //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; + + // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. + SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; + PMC(APBDEV_PMC_SCRATCH49) &= 0xFFFFFFFC; + + // Perform Memory Built-In Self Test WAR if T210. + if (tegra_t210) + _mbist_workaround(); + + // Make sure PLLP_OUT3/4 is set to 408 MHz and enabled. + CLOCK(CLK_RST_CONTROLLER_PLLP_OUTB) = 0x30003; + + // Enable Security Engine clock. + clock_enable_se(); + + // Enable Fuse visibility. + clock_enable_fuse(true); + + // Disable Fuse programming. + fuse_disable_program(); + + // Enable clocks to Memory controllers and disable AHB redirect. + mc_enable(); + + // Initialize counters, CLKM, BPMP and other clocks based on 38.4MHz oscillator. + _config_oscillators(); + + // Initialize pin configuration. + _config_gpios(nx_hoag); + + // Enable CL-DVFS clock unconditionally to avoid issues with I2C5 sharing. + clock_enable_cl_dvfs(); + + // Enable clocks to I2C1 and I2CPWR. + clock_enable_i2c(I2C_1); + clock_enable_i2c(I2C_5); + + // Enable clock to TZRAM. + clock_enable_tzram(); + + // Initialize I2C5, mandatory for PMIC. + i2c_init(I2C_5); + + // Initialize various regulators based on Erista/Mariko platform. + _config_regulators(tegra_t210, nx_hoag); + + // Initialize I2C1 for various power related devices. + i2c_init(I2C_1); + + _config_pmc_scratch(); // Missing from 4.x+ + + // Set BPMP/SCLK to PLLP_OUT (408MHz). + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; + + // Power on T210B01 shadow TZRAM and lock the reg. + if (!tegra_t210) + { + PMC(APBDEV_PMC_TZRAM_PWR_CNTRL) &= ~PMC_TZRAM_PWR_CNTRL_SD; + PMC(APBDEV_PMC_TZRAM_NON_SEC_DISABLE) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ; + PMC(APBDEV_PMC_TZRAM_SEC_DISABLE) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ; + } + + // Set arbiter. + hw_config_arbiter(false); + + // Initialize External memory controller and configure DRAM parameters. + sdram_init(); + + bpmp_mmu_enable(); + + // Enable HOST1X used by every display module (DC, VIC, NVDEC, NVENC, TSEC, etc). + clock_enable_host1x(); + +#ifdef DEBUG_UART_PORT + // Setup debug uart port. + #if (DEBUG_UART_PORT == UART_B) + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + #elif (DEBUG_UART_PORT == UART_C) + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + #endif + pinmux_config_uart(DEBUG_UART_PORT); + clock_enable_uart(DEBUG_UART_PORT); + uart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX); + uart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD); +#endif +} + +void hw_deinit(bool coreboot, u32 bl_magic) +{ + bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; + + // Scale down BPMP clock. + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + +#ifdef BDK_HW_EXTRA_DEINIT + // Disable temperature sensor, touchscreen, 5V regulators, Joy-Con and VIC. + vic_end(); + tmp451_end(); + fan_set_duty(0); + touch_power_off(); + jc_deinit(); + regulator_5v_disable(REGULATOR_5V_ALL); +#endif + + // set DRAM clock to 204MHz. + minerva_change_freq(FREQ_204); + nyx_str->mtc_cfg.init_done = 0; + + // Flush/disable MMU cache. + bpmp_mmu_disable(); + + // Reset arbiter. + hw_config_arbiter(true); + + // Re-enable clocks to Audio Processing Engine as a workaround to hanging. + if (tegra_t210) + { + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); + } + + // Do coreboot mitigations. + if (coreboot) + { + msleep(10); + + clock_disable_cl_dvfs(); + + // Disable Joy-con detect in order to restore UART TX. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + // Reinstate SD controller power. + PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_SDMMC1; + } + + // Seamless display or display power off. + switch (bl_magic) + { + case BL_MAGIC_CRBOOT_SLD:; + // Set pwm to 0%, switch to gpio mode and restore pwm duty. + u32 brightness = display_get_backlight_brightness(); + display_backlight_brightness(0, 1000); + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_GPIO); + display_backlight_brightness(brightness, 0); + break; + case BL_MAGIC_L4TLDR_SLD: + // Do not disable display or backlight at all. + break; + default: + display_end(); + clock_disable_host1x(); + } +} diff --git a/nyx/nyx_gui/utils/btn.h b/bdk/soc/hw_init.h similarity index 60% rename from nyx/nyx_gui/utils/btn.h rename to bdk/soc/hw_init.h index 8394a52..fcd8d10 100644 --- a/nyx/nyx_gui/utils/btn.h +++ b/bdk/soc/hw_init.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -15,17 +15,20 @@ * along with this program. If not, see . */ -#ifndef _BTN_H_ -#define _BTN_H_ +#ifndef _HW_INIT_H_ +#define _HW_INIT_H_ -#include "types.h" +#include -#define BTN_POWER (1 << 0) -#define BTN_VOL_DOWN (1 << 1) -#define BTN_VOL_UP (1 << 2) +#define BL_MAGIC_CRBOOT_SLD 0x30444C53 // SLD0, seamless display type 0. +#define BL_MAGIC_L4TLDR_SLD 0x31444C53 // SLD1, seamless display type 1. -u8 btn_read(); -u8 btn_wait(); -u8 btn_wait_timeout(u32 time_ms, u8 mask); +extern u32 hw_rst_status; +extern u32 hw_rst_reason; + +void hw_init(); +void hw_deinit(bool coreboot, u32 magic); +void hw_config_arbiter(bool reset); +u32 hw_get_chip_id(); #endif diff --git a/bdk/soc/i2c.c b/bdk/soc/i2c.c new file mode 100644 index 0000000..c38e952 --- /dev/null +++ b/bdk/soc/i2c.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2022 CTCaer + * + * 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 +#include +#include + +#define I2C_PACKET_PROT_I2C BIT(4) +#define I2C_HEADER_CONT_XFER BIT(15) +#define I2C_HEADER_REP_START BIT(16) +#define I2C_HEADER_IE_ENABLE BIT(17) +#define I2C_HEADER_READ BIT(19) + +#define I2C_CNFG (0x00 / 4) +#define CMD1_WRITE (0 << 6) +#define CMD1_READ BIT(6) +#define NORMAL_MODE_GO BIT(9) +#define PACKET_MODE_GO BIT(10) +#define NEW_MASTER_FSM BIT(11) +#define DEBOUNCE_CNT_4T (2 << 12) + +#define I2C_CMD_ADDR0 (0x04 / 4) +#define ADDR0_WRITE 0 +#define ADDR0_READ 1 + +#define I2C_CMD_DATA1 (0x0C / 4) +#define I2C_CMD_DATA2 (0x10 / 4) + +#define I2C_STATUS (0x1C / 4) +#define I2C_STATUS_NOACK (0xF << 0) +#define I2C_STATUS_BUSY BIT(8) + +#define I2C_TX_FIFO (0x50 / 4) +#define I2C_RX_FIFO (0x54 / 4) + +#define I2C_FIFO_CONTROL (0x5C / 4) +#define RX_FIFO_FLUSH BIT(0) +#define TX_FIFO_FLUSH BIT(1) + +#define I2C_FIFO_STATUS (0x60 / 4) +#define RX_FIFO_FULL_CNT (0xF << 0) +#define TX_FIFO_EMPTY_CNT (0xF << 4) + +#define I2C_INT_EN (0x64 / 4) +#define I2C_INT_STATUS (0x68 / 4) +#define I2C_INT_SOURCE (0x70 / 4) +#define RX_FIFO_DATA_REQ BIT(0) +#define TX_FIFO_DATA_REQ BIT(1) +#define ARB_LOST BIT(2) +#define NO_ACK BIT(3) +#define RX_FIFO_UNDER BIT(4) +#define TX_FIFO_OVER BIT(5) +#define ALL_PACKETS_COMPLETE BIT(6) +#define PACKET_COMPLETE BIT(7) +#define BUS_CLEAR_DONE BIT(11) + +#define I2C_CLK_DIVISOR (0x6C / 4) + +#define I2C_BUS_CLEAR_CONFIG (0x84 / 4) +#define BC_ENABLE BIT(0) +#define BC_TERMINATE BIT(1) + +#define I2C_BUS_CLEAR_STATUS (0x88 / 4) + +#define I2C_CONFIG_LOAD (0x8C / 4) +#define MSTR_CONFIG_LOAD BIT(0) +#define TIMEOUT_CONFIG_LOAD BIT(2) + +/* I2C_1, 2, 3, 4, 5 and 6. */ +static const u16 _i2c_base_offsets[6] = { 0x0, 0x400, 0x500, 0x700, 0x1000, 0x1100 }; + +static void _i2c_load_cfg_wait(vu32 *base) +{ + base[I2C_CONFIG_LOAD] = BIT(5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD; + for (u32 i = 0; i < 20; i++) + { + if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD)) + break; + usleep(1); + } +} + +static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size) +{ + if (size > 8) + return 0; + + u32 tmp = 0; + + vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]); + + // Set device address and send mode. + base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE; + + if (size > 4) + { + memcpy(&tmp, buf, 4); + base[I2C_CMD_DATA1] = tmp; //Set value. + tmp = 0; + memcpy(&tmp, buf + 4, size - 4); + base[I2C_CMD_DATA2] = tmp; + } + else + { + memcpy(&tmp, buf, size); + base[I2C_CMD_DATA1] = tmp; //Set value. + } + + // Set size and send mode. + base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on normal mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; + + u32 timeout = get_tmr_us() + 200000; // Actual for max 8 bytes at 100KHz is 0.74ms. + while (base[I2C_STATUS] & I2C_STATUS_BUSY) + { + if (get_tmr_us() > timeout) + return 0; + } + + if (base[I2C_STATUS] & I2C_STATUS_NOACK) + return 0; + + return 1; +} + +static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr) +{ + if (size > 8) + return 0; + + vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]); + + // Set device address and recv mode. + base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; + + // Set size and recv mode. + base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on normal mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; + + u32 timeout = get_tmr_us() + 200000; // Actual for max 8 bytes at 100KHz is 0.74ms. + while (base[I2C_STATUS] & I2C_STATUS_BUSY) + { + if (get_tmr_us() > timeout) + return 0; + } + + if (base[I2C_STATUS] & I2C_STATUS_NOACK) + return 0; + + u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. + if (size > 4) + { + memcpy(buf, &tmp, 4); + tmp = base[I2C_CMD_DATA2]; // Get MS value. + memcpy(buf + 4, &tmp, size - 4); + } + else + memcpy(buf, &tmp, size); + + return 1; +} + +static int _i2c_send_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr) +{ + if (size > 32) + return 0; + + int res = 0; + + vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]); + + // Enable interrupts. + base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK | + ARB_LOST | TX_FIFO_OVER | RX_FIFO_UNDER | TX_FIFO_DATA_REQ; + base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; + + // Set device address and send mode. + base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_WRITE; + + // Set recv mode. + base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE; + + // Set and flush FIFO. + base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on packet mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | PACKET_MODE_GO; + + u32 hdr[3]; + hdr[0] = I2C_PACKET_PROT_I2C; + hdr[1] = size - 1; + hdr[2] = I2C_HEADER_IE_ENABLE | I2C_HEADER_CONT_XFER | (dev_addr << 1); + + // Send header with request. + base[I2C_TX_FIFO] = hdr[0]; + base[I2C_TX_FIFO] = hdr[1]; + base[I2C_TX_FIFO] = hdr[2]; + + u32 timeout = get_tmr_ms() + 400; + while (size) + { + if (base[I2C_FIFO_STATUS] & TX_FIFO_EMPTY_CNT) + { + u32 tmp = 0; + u32 snd_size = MIN(size, 4); + memcpy(&tmp, buf, snd_size); + base[I2C_TX_FIFO] = tmp; + buf += snd_size; + size -= snd_size; + } + + if (get_tmr_ms() > timeout) + { + res = 1; + break; + } + } + + if (base[I2C_STATUS] & I2C_STATUS_NOACK || base[I2C_INT_STATUS] & NO_ACK) + res = 1; + + // Disable packet mode. + usleep(20); + base[I2C_CNFG] &= 0xFFFFF9FF; + + // Disable interrupts. + base[I2C_INT_EN] = 0; + + return res; +} + +static int _i2c_recv_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr, u32 reg) +{ + if (size > 32) + return 0; + + int res = 0; + + vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]); + + // Enable interrupts. + base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK | + ARB_LOST | TX_FIFO_OVER | RX_FIFO_UNDER | RX_FIFO_DATA_REQ; + base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; + + // Set device address and recv mode. + base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; + + // Set recv mode. + base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ; + + // Set and flush FIFO. + base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH; + + // Load configuration. + _i2c_load_cfg_wait(base); + + // Initiate transaction on packet mode. + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | PACKET_MODE_GO; + + // Send reg request. + u32 hdr[3]; + hdr[0] = I2C_PACKET_PROT_I2C; + hdr[1] = 1 - 1; + hdr[2] = I2C_HEADER_REP_START | (dev_addr << 1); + + // Send header with reg request. + base[I2C_TX_FIFO] = hdr[0]; + base[I2C_TX_FIFO] = hdr[1]; + base[I2C_TX_FIFO] = hdr[2]; + base[I2C_TX_FIFO] = reg; + + u32 timeout = get_tmr_ms() + 400; + while (!(base[I2C_FIFO_STATUS] & TX_FIFO_EMPTY_CNT)) + if (get_tmr_ms() > timeout) + break; + + // Send read request. + hdr[1] = size - 1; + hdr[2] = I2C_HEADER_READ | (dev_addr << 1); + + // Send header with read request. + base[I2C_TX_FIFO] = hdr[0]; + base[I2C_TX_FIFO] = hdr[1]; + base[I2C_TX_FIFO] = hdr[2]; + + timeout = get_tmr_ms() + 400; + while (size) + { + if (base[I2C_FIFO_STATUS] & RX_FIFO_FULL_CNT) + { + u32 rcv_size = MIN(size, 4); + u32 tmp = base[I2C_RX_FIFO]; + memcpy(buf, &tmp, rcv_size); + buf += rcv_size; + size -= rcv_size; + } + + if (get_tmr_ms() > timeout) + { + res = 1; + break; + } + } + + if (base[I2C_STATUS] & I2C_STATUS_NOACK || base[I2C_INT_STATUS] & NO_ACK) + res = 1; + + // Disable packet mode. + usleep(20); + base[I2C_CNFG] &= 0xFFFFF9FF; + + // Disable interrupts. + base[I2C_INT_EN] = 0; + + return res; +} + +void i2c_init(u32 i2c_idx) +{ + vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]); + + base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2. + base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE; + + // Load configuration. + _i2c_load_cfg_wait(base); + + for (u32 i = 0; i < 10; i++) + { + if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE) + break; + usleep(25); + } + + (vu32)base[I2C_BUS_CLEAR_STATUS]; + base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; +} + +int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr) +{ + return _i2c_recv_single(i2c_idx, buf, size, dev_addr); +} + +int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size) +{ + if (size > 32) + return 0; + + return _i2c_send_pkt(i2c_idx, buf, size, dev_addr); +} + +int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg) +{ + return _i2c_recv_pkt(i2c_idx, buf, size, dev_addr, reg); +} + +int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size) +{ + u8 tmp[8]; + + if (size > 7) + return 0; + + tmp[0] = reg; + memcpy(tmp + 1, buf, size); + + return _i2c_send_single(i2c_idx, dev_addr, tmp, size + 1); +} + +int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg) +{ + int res = _i2c_send_single(i2c_idx, dev_addr, (u8 *)®, 1); + if (res) + res = _i2c_recv_single(i2c_idx, buf, size, dev_addr); + return res; +} + +int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val) +{ + return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1); +} + +u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg) +{ + u8 tmp = 0; + i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg); + return tmp; +} + diff --git a/bootloader/soc/i2c.h b/bdk/soc/i2c.h similarity index 56% rename from bootloader/soc/i2c.h rename to bdk/soc/i2c.h index e2b2af5..ab3078e 100644 --- a/bootloader/soc/i2c.h +++ b/bdk/soc/i2c.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +18,7 @@ #ifndef _I2C_H_ #define _I2C_H_ -#include "../utils/types.h" +#include #define I2C_1 0 #define I2C_2 1 @@ -26,21 +27,13 @@ #define I2C_5 4 #define I2C_6 5 -#define I2C_CNFG 0x00 -#define I2C_CMD_ADDR0 0x01 -#define I2C_CMD_DATA1 0x03 -#define I2C_CMD_DATA2 0x04 -#define I2C_STATUS 0x07 -#define INTERRUPT_STATUS_REGISTER 0x1A -#define I2C_CLK_DIVISOR_REGISTER 0x1B -#define I2C_BUS_CLEAR_CONFIG 0x21 -#define I2C_BUS_CLEAR_STATUS 0x22 -#define I2C_CONFIG_LOAD 0x23 - -void i2c_init(u32 idx); -int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size); -int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y); -int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b); -u8 i2c_recv_byte(u32 idx, u32 x, u32 y); +void i2c_init(u32 i2c_idx); +int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr); +int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size); +int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg); +int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size); +int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg); +int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val); +u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg); #endif diff --git a/bdk/soc/irq.c b/bdk/soc/irq.c new file mode 100644 index 0000000..f39774e --- /dev/null +++ b/bdk/soc/irq.c @@ -0,0 +1,272 @@ +/* + * BPMP-Lite IRQ driver for Tegra X1 + * + * Copyright (c) 2019-2024 CTCaer + * + * 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 "irq.h" +#include +#include +#include +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +extern void excp_reset(); +extern void irq_disable(); +extern void irq_enable_cpu_irq_exceptions(); +extern void irq_disable_cpu_irq_exceptions(); + +typedef struct _irq_ctxt_t +{ + u32 irq; + int (*handler)(u32 irq, void *data); + void *data; + u32 flags; +} irq_ctxt_t; + +bool irq_init_done = false; +irq_ctxt_t irqs[IRQ_MAX_HANDLERS]; + +static void _irq_enable_source(u32 irq) +{ + u32 ctrl_idx = irq >> 5; + u32 bit = irq % 32; + + // Set as normal IRQ. + ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~BIT(bit); + + // Enable IRQ source. + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = BIT(bit); +} + +static void _irq_disable_source(u32 irq) +{ + u32 ctrl_idx = irq >> 5; + u32 bit = irq % 32; + + // Disable IRQ source. + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = BIT(bit); +} + +static void _irq_disable_and_ack_all() +{ + // Disable and ack all IRQ sources. + for (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++) + { + u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER); + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs; + } +} + +void irq_free(u32 irq) +{ + for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].irq == irq && irqs[idx].handler) + { + irqs[idx].irq = 0; + irqs[idx].handler = NULL; + irqs[idx].data = NULL; + irqs[idx].flags = 0; + + _irq_disable_source(irq); + } + } +} + +static void _irq_free_all() +{ + for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].handler) + { + _irq_disable_source(irqs[idx].irq); + + irqs[idx].irq = 0; + irqs[idx].handler = NULL; + irqs[idx].data = NULL; + irqs[idx].flags = 0; + } + } +} + +static irq_status_t _irq_handle_source(u32 irq) +{ + int status = IRQ_NONE; + + _irq_disable_source(irq); + + u32 idx; + for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].irq == irq) + { + status = irqs[idx].handler(irqs[idx].irq, irqs[idx].data); + + if (status == IRQ_HANDLED) + break; + } + } + + // Do not re-enable if not handled or error. + if (status != IRQ_HANDLED) + return status; + + if (irqs[idx].flags & IRQ_FLAG_ONE_OFF) + irq_free(irq); + else + _irq_enable_source(irq); + + return status; +} + +void irq_handler() +{ + // Get IRQ source. + u32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF; + + if (!irq_init_done) + { + _irq_disable_source(irq); + + return; + } + + DPRINTF("IRQ: %d\n", irq); + + int err = _irq_handle_source(irq); + + if (err == IRQ_NONE) + { + DPRINTF("Unhandled IRQ got disabled: %d!\n", irq); + } +} + +static void _irq_init() +{ + _irq_disable_and_ack_all(); + memset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS); + irq_init_done = true; +} + +void irq_end() +{ + if (!irq_init_done) + return; + + _irq_free_all(); + irq_disable_cpu_irq_exceptions(); + irq_init_done = false; +} + +void irq_wait_event(u32 irq) +{ + irq_disable_cpu_irq_exceptions(); + + _irq_enable_source(irq); + + // Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ. + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ; + + _irq_disable_source(irq); + + irq_enable_cpu_irq_exceptions(); +} + +void irq_disable_wait_event() +{ + irq_enable_cpu_irq_exceptions(); +} + +irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags) +{ + if (!irq_init_done) + _irq_init(); + + for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].handler == NULL || + (irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE)) + { + DPRINTF("Registered handler, IRQ: %d, Slot: %d\n", irq, idx); + DPRINTF("Handler: %08p, Flags: %x\n", (u32)handler, flags); + + irqs[idx].irq = irq; + irqs[idx].handler = handler; + irqs[idx].data = data; + irqs[idx].flags = flags; + + _irq_enable_source(irq); + + return IRQ_ENABLED; + } + else if (irqs[idx].irq == irq) + return IRQ_ALREADY_REGISTERED; + } + + return IRQ_NO_SLOTS_AVAILABLE; +} + +void __attribute__ ((target("arm"))) fiq_setup() +{ +/* + asm volatile("mrs r12, cpsr\n\t" + "bic r12, r12, #0x1F\n\t" + "orr r12, r12, #0x11\n\t" + "msr cpsr_c, r12\n\t"); + + register volatile char *text asm ("r8"); + register volatile char *uart_tx asm ("r9"); + register int len asm ("r10"); + + len = 5; + uart_tx = (char *)0x70006040; + memcpy((char *)text, "FIQ\r\n", len); + *uart_tx = 0; + + asm volatile("mrs r12, cpsr\n" + "orr r12, r12, #0x1F\n" + "msr cpsr_c, r12"); +*/ +} + +void __attribute__ ((target("arm"), interrupt ("FIQ"))) fiq_handler() +{ +/* + register volatile char *text asm ("r8"); + register volatile char *uart_tx asm ("r9"); + register int len asm ("r10"); + + while (len) + { + *uart_tx = *text++; + len--; + } +*/ +#ifdef BDK_WATCHDOG_FIQ_ENABLE + // Set watchdog timeout status and disable WDT and its FIQ signal. + watchdog_handle(); + +#ifdef BDK_RESTART_BL_ON_WDT + // Restart bootloader. + excp_reset(); +#endif + +#endif +} diff --git a/bdk/soc/irq.h b/bdk/soc/irq.h new file mode 100644 index 0000000..54dc12a --- /dev/null +++ b/bdk/soc/irq.h @@ -0,0 +1,223 @@ +/* + * BPMP-Lite IRQ driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * 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 IRQ_H +#define IRQ_H + +#include + +#define IRQ_MAX_HANDLERS 16 + +/* Primary interrupt controller ids */ +#define IRQ_TMR1 0 +#define IRQ_TMR2 1 +#define IRQ_RTC 2 +#define IRQ_CEC 3 +#define IRQ_SHR_SEM_INBOX_FULL 4 +#define IRQ_SHR_SEM_INBOX_EMPTY 5 +#define IRQ_SHR_SEM_OUTBOX_FULL 6 +#define IRQ_SHR_SEM_OUTBOX_EMPTY 7 +#define IRQ_NVJPEG 8 +#define IRQ_NVDEC 9 +#define IRQ_QUAD_SPI 10 +#define IRQ_DPAUX_INT1 11 +#define IRQ_SATA_RX_STAT 13 +#define IRQ_SDMMC1 14 +#define IRQ_SDMMC2 15 +#define IRQ_VGPIO_INT 16 +#define IRQ_VII2C_INT 17 +#define IRQ_SDMMC3 19 +#define IRQ_USB 20 +#define IRQ_USB2 21 +#define IRQ_SATA_CTL 23 +#define IRQ_PMC_INT 24 +#define IRQ_FC_INT 25 +#define IRQ_APB_DMA_CPU 26 +#define IRQ_ARB_SEM_GNT_COP 28 +#define IRQ_ARB_SEM_GNT_CPU 29 +#define IRQ_SDMMC4 31 + +/* Secondary interrupt controller ids */ +#define IRQ_GPIO1 32 +#define IRQ_GPIO2 33 +#define IRQ_GPIO3 34 +#define IRQ_GPIO4 35 +#define IRQ_UARTA 36 +#define IRQ_UARTB 37 +#define IRQ_I2C 38 +#define IRQ_USB3_HOST_INT 39 +#define IRQ_USB3_HOST_SMI 40 +#define IRQ_TMR3 41 +#define IRQ_TMR4 42 +#define IRQ_USB3_HOST_PME 43 +#define IRQ_USB3_DEV_HOST 44 +#define IRQ_ACTMON 45 +#define IRQ_UARTC 46 +#define IRQ_THERMAL 48 +#define IRQ_XUSB_PADCTL 49 +#define IRQ_TSEC 50 +#define IRQ_EDP 51 +#define IRQ_I2C5 53 +#define IRQ_GPIO5 55 +#define IRQ_USB3_DEV_SMI 56 +#define IRQ_USB3_DEV_PME 57 +#define IRQ_SE 58 +#define IRQ_SPI1 59 +#define IRQ_APB_DMA_COP 60 +#define IRQ_CLDVFS 62 +#define IRQ_I2C6 63 + +/* Tertiary interrupt controller ids */ +#define IRQ_HOST1X_SYNCPT_COP 64 +#define IRQ_HOST1X_SYNCPT_CPU 65 +#define IRQ_HOST1X_GEN_COP 66 +#define IRQ_HOST1X_GEN_CPU 67 +#define IRQ_NVENC 68 +#define IRQ_VI 69 +#define IRQ_ISPB 70 +#define IRQ_ISP 71 +#define IRQ_VIC 72 +#define IRQ_DISPLAY 73 +#define IRQ_DISPLAYB 74 +#define IRQ_SOR1 75 +#define IRQ_SOR 76 +#define IRQ_MC 77 +#define IRQ_EMC 78 +#define IRQ_TSECB 80 +#define IRQ_HDA 81 +#define IRQ_SPI2 82 +#define IRQ_SPI3 83 +#define IRQ_I2C2 84 +#define IRQ_PMU_EXT 86 +#define IRQ_GPIO6 87 +#define IRQ_GPIO7 89 +#define IRQ_UARTD 90 +#define IRQ_I2C3 92 +#define IRQ_SPI4 93 + +/* Quaternary interrupt controller ids */ +#define IRQ_DTV 96 +#define IRQ_PCIE_INT 98 +#define IRQ_PCIE_MSI 99 +#define IRQ_AVP_CACHE 101 +#define IRQ_APE_INT1 102 +#define IRQ_APE_INT0 103 +#define IRQ_APB_DMA_CH0 104 +#define IRQ_APB_DMA_CH1 105 +#define IRQ_APB_DMA_CH2 106 +#define IRQ_APB_DMA_CH3 107 +#define IRQ_APB_DMA_CH4 108 +#define IRQ_APB_DMA_CH5 109 +#define IRQ_APB_DMA_CH6 110 +#define IRQ_APB_DMA_CH7 111 +#define IRQ_APB_DMA_CH8 112 +#define IRQ_APB_DMA_CH9 113 +#define IRQ_APB_DMA_CH10 114 +#define IRQ_APB_DMA_CH11 115 +#define IRQ_APB_DMA_CH12 116 +#define IRQ_APB_DMA_CH13 117 +#define IRQ_APB_DMA_CH14 118 +#define IRQ_APB_DMA_CH15 119 +#define IRQ_I2C4 120 +#define IRQ_TMR5 121 +#define IRQ_WDT_CPU 123 +#define IRQ_WDT_AVP 124 +#define IRQ_GPIO8 125 +#define IRQ_CAR 126 + +/* Quinary interrupt controller ids */ +#define IRQ_APB_DMA_CH16 128 +#define IRQ_APB_DMA_CH17 129 +#define IRQ_APB_DMA_CH18 130 +#define IRQ_APB_DMA_CH19 131 +#define IRQ_APB_DMA_CH20 132 +#define IRQ_APB_DMA_CH21 133 +#define IRQ_APB_DMA_CH22 134 +#define IRQ_APB_DMA_CH23 135 +#define IRQ_APB_DMA_CH24 136 +#define IRQ_APB_DMA_CH25 137 +#define IRQ_APB_DMA_CH26 138 +#define IRQ_APB_DMA_CH27 139 +#define IRQ_APB_DMA_CH28 140 +#define IRQ_APB_DMA_CH29 141 +#define IRQ_APB_DMA_CH30 142 +#define IRQ_APB_DMA_CH31 143 +#define IRQ_CPU0_PMU_INTR 144 +#define IRQ_CPU1_PMU_INTR 145 +#define IRQ_CPU2_PMU_INTR 146 +#define IRQ_CPU3_PMU_INTR 147 +#define IRQ_SDMMC1_SYS 148 +#define IRQ_SDMMC2_SYS 149 +#define IRQ_SDMMC3_SYS 150 +#define IRQ_SDMMC4_SYS 151 +#define IRQ_TMR6 152 +#define IRQ_TMR7 153 +#define IRQ_TMR8 154 +#define IRQ_TMR9 155 +#define IRQ_TMR0 156 +#define IRQ_GPU_STALL 157 +#define IRQ_GPU_NONSTALL 158 +#define IRQ_DPAUX 159 + +/* Senary interrupt controller ids */ +#define IRQ_MPCORE_AXIERRIRQ 160 +#define IRQ_MPCORE_INTERRIRQ 161 +#define IRQ_EVENT_GPIO_A 162 +#define IRQ_EVENT_GPIO_B 163 +#define IRQ_EVENT_GPIO_C 164 +#define IRQ_EVENT_GPIO_D_T210B01 165 +#define IRQ_FLOW_RSM_CPU 168 +#define IRQ_FLOW_RSM_COP 169 +#define IRQ_TMR_SHARED 170 +#define IRQ_MPCORE_CTIIRQ0 171 +#define IRQ_MPCORE_CTIIRQ1 172 +#define IRQ_MPCORE_CTIIRQ2 173 +#define IRQ_MPCORE_CTIIRQ3 174 +#define IRQ_MSELECT_ERROR 175 +#define IRQ_TMR10 176 +#define IRQ_TMR11 177 +#define IRQ_TMR12 178 +#define IRQ_TMR13 179 + +typedef int (*irq_handler_t)(u32 irq, void *data); + +typedef enum _irq_status_t +{ + IRQ_NONE = 0, + IRQ_HANDLED = 1, + IRQ_ERROR = 2, + + IRQ_ENABLED = 0, + IRQ_NO_SLOTS_AVAILABLE = 1, + IRQ_ALREADY_REGISTERED = 2 +} irq_status_t; + +typedef enum _irq_flags_t +{ + IRQ_FLAG_NONE = 0, + IRQ_FLAG_ONE_OFF = BIT(0), + IRQ_FLAG_REPLACEABLE = BIT(1) +} irq_flags_t; + +void irq_end(); +void irq_free(u32 irq); +void irq_wait_event(); +void irq_disable_wait_event(); +irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags); + +#endif \ No newline at end of file diff --git a/nyx/nyx_gui/soc/kfuse.c b/bdk/soc/kfuse.c similarity index 93% rename from nyx/nyx_gui/soc/kfuse.c rename to bdk/soc/kfuse.c index a02acda..2da9593 100644 --- a/nyx/nyx_gui/soc/kfuse.c +++ b/bdk/soc/kfuse.c @@ -14,9 +14,9 @@ * along with this program. If not, see . */ -#include "../soc/kfuse.h" -#include "../soc/clock.h" -#include "../soc/t210.h" +#include +#include +#include int kfuse_wait_ready() { @@ -45,7 +45,7 @@ int kfuse_read(u32 *buf) res = 1; -out:; +out: clock_disable_kfuse(); return res; } diff --git a/bootloader/soc/kfuse.h b/bdk/soc/kfuse.h similarity index 76% rename from bootloader/soc/kfuse.h rename to bdk/soc/kfuse.h index a535803..2cd290b 100644 --- a/bootloader/soc/kfuse.h +++ b/bdk/soc/kfuse.h @@ -17,18 +17,18 @@ #ifndef _KFUSE_H_ #define _KFUSE_H_ -#include "../utils/types.h" +#include -#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_STATE_ERRBLOCK_SHIFT 8 +#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 +#define KFUSE_STATE_DONE BIT(16) +#define KFUSE_STATE_CRCPASS BIT(17) +#define KFUSE_STATE_RESTART BIT(24) +#define KFUSE_STATE_STOP BIT(25) +#define KFUSE_STATE_SOFTRESET BIT(31) -#define KFUSE_KEYADDR_AUTOINC (1<<16) +#define KFUSE_KEYADDR_AUTOINC BIT(16) #define KFUSE_STATE 0x80 #define KFUSE_KEYADDR 0x88 diff --git a/bootloader/soc/pinmux.c b/bdk/soc/pinmux.c similarity index 60% rename from bootloader/soc/pinmux.c rename to bdk/soc/pinmux.c index 582ab29..84969c6 100644 --- a/bootloader/soc/pinmux.c +++ b/bdk/soc/pinmux.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,15 +15,15 @@ * along with this program. If not, see . */ -#include "../soc/pinmux.h" -#include "../soc/t210.h" +#include +#include void pinmux_config_uart(u32 idx) { - PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0; - PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0; + PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0; - PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN; + PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; } void pinmux_config_i2c(u32 idx) @@ -30,3 +31,11 @@ void pinmux_config_i2c(u32 idx) PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE; PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE; } + +void pinmux_config_i2s(u32 idx) +{ + PINMUX_AUX(PINMUX_AUX_X_I2S_LRCK(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN; + PINMUX_AUX(PINMUX_AUX_X_I2C_DIN(idx)) = PINMUX_DRIVE_4X | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_DOWN; + PINMUX_AUX(PINMUX_AUX_X_I2C_DOUT(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN; + PINMUX_AUX(PINMUX_AUX_X_I2C_BCLK(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN; +} diff --git a/bootloader/soc/pinmux.h b/bdk/soc/pinmux.h similarity index 66% rename from bootloader/soc/pinmux.h rename to bdk/soc/pinmux.h index bb4ecb1..f9ad5af 100644 --- a/bootloader/soc/pinmux.h +++ b/bdk/soc/pinmux.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +18,7 @@ #ifndef _PINMUX_H_ #define _PINMUX_H_ -#include "../utils/types.h" +#include /*! APB MISC registers. */ #define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4 @@ -39,6 +40,7 @@ #define PINMUX_AUX_SDMMC3_DAT2 0x2C #define PINMUX_AUX_SDMMC3_DAT3 0x30 #define PINMUX_AUX_SATA_LED_ACTIVE 0x4C +#define PINMUX_AUX_GPIO_PA5_T210B01 PINMUX_AUX_SATA_LED_ACTIVE #define PINMUX_AUX_DMIC3_CLK 0xB4 #define PINMUX_AUX_DMIC3_DAT 0xB8 #define PINMUX_AUX_CAM_I2C_SCL 0xD4 @@ -46,7 +48,10 @@ #define PINMUX_AUX_UART2_TX 0xF4 #define PINMUX_AUX_UART3_TX 0x104 #define PINMUX_AUX_DAP4_DIN 0x148 +#define PINMUX_AUX_DAP4_DOUT 0x14C #define PINMUX_AUX_DAP4_SCLK 0x150 +#define PINMUX_AUX_CLK_32K_OUT 0x164 +#define PINMUX_AUX_AUD_MCLK 0x180 #define PINMUX_AUX_GPIO_X1_AUD 0x18C #define PINMUX_AUX_GPIO_X3_AUD 0x190 #define PINMUX_AUX_SPDIF_IN 0x1A4 @@ -57,19 +62,41 @@ #define PINMUX_AUX_AP_WAKE_NFC 0x1CC #define PINMUX_AUX_NFC_EN 0x1D0 #define PINMUX_AUX_NFC_INT 0x1D4 +#define PINMUX_AUX_CAM_RST 0x1E0 #define PINMUX_AUX_CAM1_PWDN 0x1EC #define PINMUX_AUX_CAM2_PWDN 0x1F0 +#define PINMUX_AUX_CAM1_STROBE 0x1F4 #define PINMUX_AUX_LCD_BL_PWM 0x1FC #define PINMUX_AUX_LCD_BL_EN 0x200 #define PINMUX_AUX_LCD_RST 0x204 +#define PINMUX_AUX_LCD_GPIO1 0x208 #define PINMUX_AUX_LCD_GPIO2 0x20C +#define PINMUX_AUX_TOUCH_RST 0x214 +#define PINMUX_AUX_TOUCH_CLK 0x218 #define PINMUX_AUX_TOUCH_INT 0x220 #define PINMUX_AUX_MOTION_INT 0x224 +#define PINMUX_AUX_ALS_PROX_INT 0x228 +#define PINMUX_AUX_BUTTON_POWER_ON 0x230 #define PINMUX_AUX_BUTTON_HOME 0x240 #define PINMUX_AUX_GPIO_PE6 0x248 +#define PINMUX_AUX_GPIO_PE7 0x24C #define PINMUX_AUX_GPIO_PH6 0x250 #define PINMUX_AUX_GPIO_PK3 0x260 +#define PINMUX_AUX_GPIO_PK7 0x270 #define PINMUX_AUX_GPIO_PZ1 0x280 +#define PINMUX_AUX_GPIO_PZ4 0x28C +/* Only in T210B01 */ +#define PINMUX_AUX_SDMMC2_DAT0 0x294 +#define PINMUX_AUX_SDMMC2_DAT1 0x298 +#define PINMUX_AUX_SDMMC2_DAT2 0x29C +#define PINMUX_AUX_SDMMC2_DAT3 0x2A0 +#define PINMUX_AUX_SDMMC2_DAT4 0x2A4 +#define PINMUX_AUX_SDMMC2_DAT5 0x2A8 +#define PINMUX_AUX_SDMMC2_DAT6 0x2AC +#define PINMUX_AUX_SDMMC2_DAT7 0x2B0 +#define PINMUX_AUX_SDMMC2_CLK 0x2B4 +#define PINMUX_AUX_SDMMC2_CMD 0x2BC + /*! 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)) @@ -78,6 +105,11 @@ /*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */ #define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x)) #define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x)) +/*! 0:I2S1, 1:I2S2 */ +#define PINMUX_AUX_X_I2S_LRCK(x) (0x124 + 0x10 * (x)) +#define PINMUX_AUX_X_I2C_DIN(x) (0x128 + 0x10 * (x)) +#define PINMUX_AUX_X_I2C_DOUT(x) (0x12c + 0x10 * (x)) +#define PINMUX_AUX_X_I2C_BCLK(x) (0x130 + 0x10 * (x)) #define PINMUX_FUNC_MASK (3 << 0) @@ -86,23 +118,27 @@ #define PINMUX_PULL_DOWN (1 << 2) #define PINMUX_PULL_UP (2 << 2) -#define PINMUX_TRISTATE (1 << 4) -#define PINMUX_PARKED (1 << 5) -#define PINMUX_INPUT_ENABLE (1 << 6) -#define PINMUX_LOCK (1 << 7) -#define PINMUX_LPDR (1 << 8) -#define PINMUX_HSM (1 << 9) +#define PINMUX_TRISTATE BIT(4) +#define PINMUX_PARKED BIT(5) +#define PINMUX_INPUT_ENABLE BIT(6) +#define PINMUX_LOCK BIT(7) +#define PINMUX_LPDR BIT(8) +#define PINMUX_HSM BIT(9) -#define PINMUX_IO_HV (1 << 10) -#define PINMUX_OPEN_DRAIN (1 << 11) -#define PINMUX_SCHMT (1 << 12) +#define PINMUX_IO_HV BIT(10) +#define PINMUX_OPEN_DRAIN BIT(11) +#define PINMUX_SCHMT BIT(12) +#define PINMUX_DRIVE_MASK (3 << 13) #define PINMUX_DRIVE_1X (0 << 13) #define PINMUX_DRIVE_2X (1 << 13) #define PINMUX_DRIVE_3X (2 << 13) #define PINMUX_DRIVE_4X (3 << 13) +#define PINMUX_PREEMP BIT(15) + void pinmux_config_uart(u32 idx); void pinmux_config_i2c(u32 idx); +void pinmux_config_i2s(u32 idx); #endif diff --git a/bdk/soc/pmc.c b/bdk/soc/pmc.c new file mode 100644 index 0000000..472b22c --- /dev/null +++ b/bdk/soc/pmc.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020 CTCaer + * + * 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 +#include +#include + +void pmc_scratch_lock(pmc_sec_lock_t lock_mask) +{ + // Lock Private key disable, Fuse write enable, MC carveout, Warmboot PA id and Warmboot address. + + // Happens on T210B01 LP0 always. + if (lock_mask & PMC_SEC_LOCK_MISC) + { + PMC(APBDEV_PMC_SEC_DISABLE) |= 0x700FF0; // RW lock: 0-3. + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0xFC000000; // RW lock: 21-23. + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0x3F0FFF00; // RW lock: 28-33, 36-38. + PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xC000000; // RW lock: 85. + // Default: 0xFF00FF00: RW lock: 108-111, 116-119. Gets locked in LP0. + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF005500; // W lock: 108-111, RW lock: 116-119. + } + + // Happens on T210B01 LP0 always. + if (lock_mask & PMC_SEC_LOCK_LP0_PARAMS) + { + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF; // RW lock: 8-15, 17-20. L4T expects 8-15 as write locked only. + PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF; // RW lock: 40-50, 52-54. + PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF; // RW lock: 56-71. + PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F; // RW lock: 72-73, 79-84, 86-87. + PMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF; // RW lock: 88-98. + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF; // RW lock: 104-107. + } + + if (lock_mask & PMC_SEC_LOCK_RST_VECTOR) + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0xF00000; // RW lock: 34-35. + + if (lock_mask & PMC_SEC_LOCK_CARVEOUTS) + { + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x30000; // RW lock: 16. + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0xC0000000; // RW lock: 39. + PMC(APBDEV_PMC_SEC_DISABLE4) |= 0xC0C00000; // RW lock: 51, 55. + PMC(APBDEV_PMC_SEC_DISABLE6) |= 0x3FF0; // RW lock: 74-78. + PMC(APBDEV_PMC_SEC_DISABLE7) |= 0xFFC00000; // RW lock: 99-103. + } + + // HOS specific. + if (lock_mask & PMC_SEC_LOCK_TZ_CMAC_W) + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0x550000; // W lock: 112-115. + + if (lock_mask & PMC_SEC_LOCK_TZ_CMAC_R) + PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xAA0000; // R lock: 112-115. + + if (lock_mask & PMC_SEC_LOCK_TZ_KEK_W) + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0x55; // W lock: 24-27. + + if (lock_mask & PMC_SEC_LOCK_TZ_KEK_R) + PMC(APBDEV_PMC_SEC_DISABLE3) |= 0xAA; // R lock: 24-27. + // End of HOS specific. + + if (lock_mask & PMC_SEC_LOCK_SE_SRK) + PMC(APBDEV_PMC_SEC_DISABLE) |= 0xFF000; // RW lock: 4-7 + + if (lock_mask & PMC_SEC_LOCK_SE2_SRK_B01) + PMC(APBDEV_PMC_SEC_DISABLE9) |= 0x3FC; // RW lock: 120-123 (T210B01). LP0 also sets global bits (b0-1). + + if (lock_mask & PMC_SEC_LOCK_MISC_B01) + PMC(APBDEV_PMC_SEC_DISABLE10) = 0xFFFFFFFF; // RW lock: 135-150. Happens on T210B01 LP0 always. + + if (lock_mask & PMC_SEC_LOCK_CARVEOUTS_L4T) + PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x5555; // W: 8-15 LP0 and Carveouts. Superseded by LP0 lock. + + // NVTBOOT misses APBDEV_PMC_SCRATCH_WRITE_LOCK_DISABLE_STICKY. bit0: SCRATCH_WR_DIS_ON. + // They could also use the NS write disable registers instead. + if (lock_mask & PMC_SEC_LOCK_LP0_PARAMS_B01) + { + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE0) |= 0xCBCFE0; // W lock: 5-11, 14-17, 19, 22-23. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE1) |= 0x583FF; // W lock: 24-33, 39-40, 42. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE2) |= 0x1BE; // W lock: 44-48, 50-51. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE3) = 0xFFFFFFFF; // W lock: 56-87. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE4) |= 0xFFFFFFF; // W lock: 88-115. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE5) |= 0xFFFFFFF8; // W lock: 123-151. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE6) = 0xFFFFFFFF; // W lock: 152-183. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE7) |= 0xFC00FFFF; // W lock: 184-199, 210-215. + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE8) |= 0xF; // W lock: 216-219. + } +} + +int pmc_enable_partition(pmc_power_rail_t part, u32 enable) +{ + u32 part_mask = BIT(part); + u32 desired_state = enable << part; + + // Check if the partition has the state we want. + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) + return 1; + + u32 i = 5001; + while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) + { + usleep(1); + i--; + if (i < 1) + return 0; + } + + // Toggle power gating. + PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; + + i = 5001; + while (i > 0) + { + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) + break; + usleep(1); + i--; + } + + return 1; +} diff --git a/bdk/soc/pmc.h b/bdk/soc/pmc.h new file mode 100644 index 0000000..5721895 --- /dev/null +++ b/bdk/soc/pmc.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 st4rk + * Copyright (c) 2018-2024 CTCaer + * + * 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 _PMC_H_ +#define _PMC_H_ + +#include + +/*! PMC registers. */ +#define APBDEV_PMC_CNTRL 0x0 +#define PMC_CNTRL_RTC_CLK_DIS BIT(1) +#define PMC_CNTRL_RTC_RST BIT(2) +#define PMC_CNTRL_MAIN_RST BIT(4) +#define PMC_CNTRL_LATCHWAKE_EN BIT(5) +#define PMC_CNTRL_BLINK_EN BIT(7) +#define PMC_CNTRL_PWRREQ_OE BIT(9) +#define PMC_CNTRL_SYSCLK_OE BIT(11) +#define PMC_CNTRL_PWRGATE_DIS BIT(12) +#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) +#define PMC_CNTRL_CPUPWRREQ_OE BIT(16) +#define PMC_CNTRL_FUSE_OVERRIDE BIT(18) +#define PMC_CNTRL_SHUTDOWN_OE BIT(22) +#define APBDEV_PMC_SEC_DISABLE 0x4 +#define APBDEV_PMC_PWRGATE_TOGGLE 0x30 +#define APBDEV_PMC_PWRGATE_STATUS 0x38 +#define APBDEV_PMC_NO_IOPOWER 0x44 +#define PMC_NO_IOPOWER_MEM BIT(7) +#define PMC_NO_IOPOWER_SDMMC1 BIT(12) +#define PMC_NO_IOPOWER_SDMMC4 BIT(14) +#define PMC_NO_IOPOWER_MEM_COMP BIT(16) +#define PMC_NO_IOPOWER_AUDIO_HV BIT(18) +#define PMC_NO_IOPOWER_GPIO BIT(21) +#define APBDEV_PMC_SCRATCH0 0x50 +#define PMC_SCRATCH0_MODE_WARMBOOT BIT(0) +#define PMC_SCRATCH0_MODE_RCM BIT(1) +#define PMC_SCRATCH0_MODE_PAYLOAD BIT(29) +#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) +#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) +#define PMC_SCRATCH0_MODE_CUSTOM_ALL (PMC_SCRATCH0_MODE_RECOVERY | \ + PMC_SCRATCH0_MODE_BOOTLOADER | \ + PMC_SCRATCH0_MODE_PAYLOAD) +#define APBDEV_PMC_BLINK_TIMER 0x40 +#define PMC_BLINK_ON(n) ((n & 0x7FFF)) +#define PMC_BLINK_FORCE BIT(15) +#define PMC_BLINK_OFF(n) ((u32)(n & 0xFFFF) << 16) +#define APBDEV_PMC_SCRATCH1 0x54 +#define APBDEV_PMC_SCRATCH20 0xA0 // ODM data/config scratch. +#define APBDEV_PMC_SECURE_SCRATCH4 0xC0 +#define APBDEV_PMC_SECURE_SCRATCH5 0xC4 +#define APBDEV_PMC_PWR_DET_VAL 0xE4 +#define PMC_PWR_DET_33V_SDMMC1 BIT(12) +#define PMC_PWR_DET_33V_AUDIO_HV BIT(18) +#define PMC_PWR_DET_33V_GPIO BIT(21) +#define APBDEV_PMC_DDR_PWR 0xE8 +#define APBDEV_PMC_USB_AO 0xF0 +#define APBDEV_PMC_CRYPTO_OP 0xF4 +#define PMC_CRYPTO_OP_SE_ENABLE 0 +#define PMC_CRYPTO_OP_SE_DISABLE 1 +#define APBDEV_PMC_PLLP_WB0_OVERRIDE 0xF8 +#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE_ENABLE BIT(11) +#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12) +#define APBDEV_PMC_SCRATCH33 0x120 +#define APBDEV_PMC_SCRATCH37 0x130 +#define PMC_SCRATCH37_KERNEL_PANIC_MAGIC 0x4E415054 // "TPAN" +#define APBDEV_PMC_SCRATCH39 0x138 +#define APBDEV_PMC_SCRATCH40 0x13C +#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 +#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER BIT(22) +#define APBDEV_PMC_CLK_OUT_CNTRL 0x1A8 +#define PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN BIT(2) +#define PMC_CLK_OUT_CNTRL_CLK2_FORCE_EN BIT(10) +#define PMC_CLK_OUT_CNTRL_CLK3_FORCE_EN BIT(18) +#define PMC_CLK_OUT_CNTRL_CLK1_SRC_SEL(src) (((src) & 3) << 6) +#define PMC_CLK_OUT_CNTRL_CLK2_SRC_SEL(src) (((src) & 3) << 14) +#define PMC_CLK_OUT_CNTRL_CLK3_SRC_SEL(src) (((src) & 3) << 22) +#define OSC_DIV1 0 +#define OSC_DIV2 1 +#define OSC_DIV4 2 +#define OSC_CAR 3 +#define APBDEV_PMC_RST_STATUS 0x1B4 +#define PMC_RST_STATUS_MASK 7 +#define PMC_RST_STATUS_POR 0 +#define PMC_RST_STATUS_WATCHDOG 1 +#define PMC_RST_STATUS_SENSOR 2 +#define PMC_RST_STATUS_SW_MAIN 3 +#define PMC_RST_STATUS_LP0 4 +#define PMC_RST_STATUS_AOTAG 5 +#define APBDEV_PMC_IO_DPD_REQ 0x1B8 +#define PMC_IO_DPD_REQ_DPD_IDLE (0 << 30u) +#define PMC_IO_DPD_REQ_DPD_OFF (1 << 30u) +#define PMC_IO_DPD_REQ_DPD_ON (2 << 30u) +#define APBDEV_PMC_IO_DPD2_REQ 0x1C0 +#define APBDEV_PMC_VDDP_SEL 0x1CC +#define APBDEV_PMC_DDR_CFG 0x1D0 +#define APBDEV_PMC_SECURE_SCRATCH6 0x224 +#define APBDEV_PMC_SECURE_SCRATCH7 0x228 +#define APBDEV_PMC_SCRATCH45 0x234 +#define APBDEV_PMC_SCRATCH46 0x238 +#define APBDEV_PMC_SCRATCH49 0x244 +#define APBDEV_PMC_SCRATCH52 0x250 +#define APBDEV_PMC_SCRATCH53 0x254 +#define APBDEV_PMC_SCRATCH54 0x258 +#define APBDEV_PMC_SCRATCH55 0x25C +#define APBDEV_PMC_TSC_MULT 0x2B4 +#define APBDEV_PMC_STICKY_BITS 0x2C0 +#define PMC_STICKY_BITS_HDA_LPBK_DIS BIT(0) +#define APBDEV_PMC_SEC_DISABLE2 0x2C4 +#define APBDEV_PMC_WEAK_BIAS 0x2C8 +#define APBDEV_PMC_REG_SHORT 0x2CC +#define APBDEV_PMC_SEC_DISABLE3 0x2D8 +#define APBDEV_PMC_SECURE_SCRATCH21 0x334 +#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT BIT(4) +#define APBDEV_PMC_SECURE_SCRATCH22 0x338 // AArch32 reset address. +#define APBDEV_PMC_SECURE_SCRATCH32 0x360 +#define APBDEV_PMC_SECURE_SCRATCH34 0x368 // AArch64 reset address. +#define APBDEV_PMC_SECURE_SCRATCH35 0x36C // AArch64 reset hi-address. +#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 +#define APBDEV_PMC_CNTRL2 0x440 +#define PMC_CNTRL2_WAKE_INT_EN BIT(0) +#define PMC_CNTRL2_WAKE_DET_EN BIT(9) +#define PMC_CNTRL2_SYSCLK_ORRIDE BIT(10) +#define PMC_CNTRL2_HOLD_CKE_LOW_EN BIT(12) +#define PMC_CNTRL2_ALLOW_PULSE_WAKE BIT(14) +#define APBDEV_PMC_FUSE_CONTROL 0x450 +#define PMC_FUSE_CONTROL_PS18_LATCH_SET BIT(8) +#define PMC_FUSE_CONTROL_PS18_LATCH_CLR BIT(9) +#define APBDEV_PMC_IO_DPD3_REQ 0x45C +#define APBDEV_PMC_IO_DPD4_REQ 0x464 +#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 +#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC +#define APBDEV_PMC_DDR_CNTRL 0x4E4 +#define APBDEV_PMC_SEC_DISABLE4 0x5B0 +#define APBDEV_PMC_SEC_DISABLE5 0x5B4 +#define APBDEV_PMC_SEC_DISABLE6 0x5B8 +#define APBDEV_PMC_SEC_DISABLE7 0x5BC +#define APBDEV_PMC_SEC_DISABLE8 0x5C0 +#define APBDEV_PMC_SEC_DISABLE9 0x5C4 +#define APBDEV_PMC_SEC_DISABLE10 0x5C8 +#define APBDEV_PMC_SCRATCH188 0x810 +#define APBDEV_PMC_SCRATCH190 0x818 +#define APBDEV_PMC_SCRATCH200 0x840 +#define APBDEV_PMC_SCRATCH201 0x844 +#define APBDEV_PMC_SCRATCH250 0x908 +#define APBDEV_PMC_SECURE_SCRATCH108 0xB08 +#define APBDEV_PMC_SECURE_SCRATCH109 0xB0C +#define APBDEV_PMC_SECURE_SCRATCH110 0xB10 +#define APBDEV_PMC_SECURE_SCRATCH112 0xB18 +#define APBDEV_PMC_SECURE_SCRATCH113 0xB1C +#define APBDEV_PMC_SECURE_SCRATCH114 0xB20 +#define APBDEV_PMC_SECURE_SCRATCH119 0xB34 + +// Only in T210B01. +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE0 0xA48 +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE1 0xA4C +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE2 0xA50 +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE3 0xA54 +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE4 0xA58 +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE5 0xA5C +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE6 0xA60 +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE7 0xA64 +#define APBDEV_PMC_SCRATCH_WRITE_DISABLE8 0xA68 +#define APBDEV_PMC_LED_BREATHING_CTRL 0xB48 +#define PMC_LED_BREATHING_CTRL_ENABLE BIT(0) +#define PMC_LED_BREATHING_CTRL_COUNTER1_EN BIT(1) +#define APBDEV_PMC_LED_BREATHING_SLOPE_STEPS 0xB4C +#define APBDEV_PMC_LED_BREATHING_ON_COUNTER 0xB50 +#define APBDEV_PMC_LED_BREATHING_OFF_COUNTER1 0xB54 +#define APBDEV_PMC_LED_BREATHING_OFF_COUNTER0 0xB58 +#define PMC_LED_BREATHING_COUNTER_HZ 32768 +#define APBDEV_PMC_LED_BREATHING_STATUS 0xB5C +#define PMC_LED_BREATHING_FSM_STATUS_MASK 0x7 +#define PMC_LED_BREATHING_FSM_STS_IDLE 0 +#define PMC_LED_BREATHING_FSM_STS_UP_RAMP 1 +#define PMC_LED_BREATHING_FSM_STS_PLATEAU 2 +#define PMC_LED_BREATHING_FSM_STS_DOWN_RAMP 3 +#define PMC_LED_BREATHING_FSM_STS_SHORT_LOW_PERIOD 4 +#define PMC_LED_BREATHING_FSM_STS_LONG_LOW_PERIOD 5 +#define APBDEV_PMC_TZRAM_PWR_CNTRL 0xBE8 +#define PMC_TZRAM_PWR_CNTRL_SD BIT(0) +#define APBDEV_PMC_TZRAM_SEC_DISABLE 0xBEC +#define APBDEV_PMC_TZRAM_NON_SEC_DISABLE 0xBF0 +#define PMC_TZRAM_DISABLE_REG_WRITE BIT(0) +#define PMC_TZRAM_DISABLE_REG_READ BIT(1) + +typedef enum _pmc_sec_lock_t +{ + PMC_SEC_LOCK_MISC = BIT(0), + PMC_SEC_LOCK_LP0_PARAMS = BIT(1), + PMC_SEC_LOCK_RST_VECTOR = BIT(2), + PMC_SEC_LOCK_CARVEOUTS = BIT(3), + PMC_SEC_LOCK_TZ_CMAC_W = BIT(4), + PMC_SEC_LOCK_TZ_CMAC_R = BIT(5), + PMC_SEC_LOCK_TZ_KEK_W = BIT(6), + PMC_SEC_LOCK_TZ_KEK_R = BIT(7), + PMC_SEC_LOCK_SE_SRK = BIT(8), + PMC_SEC_LOCK_SE2_SRK_B01 = BIT(9), + PMC_SEC_LOCK_MISC_B01 = BIT(10), + PMC_SEC_LOCK_CARVEOUTS_L4T = BIT(11), + PMC_SEC_LOCK_LP0_PARAMS_B01 = BIT(12), +} pmc_sec_lock_t; + +typedef enum _pmc_power_rail_t +{ + POWER_RAIL_CRAIL = 0, + POWER_RAIL_3D0 = 1, + POWER_RAIL_VENC = 2, + POWER_RAIL_PCIE = 3, + POWER_RAIL_VDEC = 4, + POWER_RAIL_L2C = 5, + POWER_RAIL_MPE = 6, + POWER_RAIL_HEG = 7, + POWER_RAIL_SATA = 8, + POWER_RAIL_CE1 = 9, + POWER_RAIL_CE2 = 10, + POWER_RAIL_CE3 = 11, + POWER_RAIL_CELP = 12, + POWER_RAIL_3D1 = 13, + POWER_RAIL_CE0 = 14, + POWER_RAIL_C0NC = 15, + POWER_RAIL_C1NC = 16, + POWER_RAIL_SOR = 17, + POWER_RAIL_DIS = 18, + POWER_RAIL_DISB = 19, + POWER_RAIL_XUSBA = 20, + POWER_RAIL_XUSBB = 21, + POWER_RAIL_XUSBC = 22, + POWER_RAIL_VIC = 23, + POWER_RAIL_IRAM = 24, + POWER_RAIL_NVDEC = 25, + POWER_RAIL_NVJPG = 26, + POWER_RAIL_AUD = 27, + POWER_RAIL_DFD = 28, + POWER_RAIL_VE2 = 29 +} pmc_power_rail_t; + +void pmc_scratch_lock(pmc_sec_lock_t lock_mask); +int pmc_enable_partition(pmc_power_rail_t part, u32 enable); + +#endif diff --git a/bootloader/soc/pmc_lp0_t210.h b/bdk/soc/pmc_lp0_t210.h similarity index 99% rename from bootloader/soc/pmc_lp0_t210.h rename to bdk/soc/pmc_lp0_t210.h index 641d9f7..5b87d5a 100644 --- a/bootloader/soc/pmc_lp0_t210.h +++ b/bdk/soc/pmc_lp0_t210.h @@ -14,7 +14,7 @@ #ifndef _TEGRA210_PMC_H_ #define _TEGRA210_PMC_H_ -#include "../utils/types.h" +#include struct tegra_pmc_regs { diff --git a/bdk/soc/t210.h b/bdk/soc/t210.h new file mode 100644 index 0000000..eaf59df --- /dev/null +++ b/bdk/soc/t210.h @@ -0,0 +1,379 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2018-2023 CTCaer +* +* 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 _T210_H_ +#define _T210_H_ + +#include + +#define IROM_BASE 0x100000 +#define IRAM_BASE 0x40000000 +#define HOST1X_BASE 0x50000000 +#define BPMP_CACHE_BASE 0x50040000 +#define MSELECT_BASE 0x50060000 +#define DPAUX1_BASE 0x54040000 +#define TSEC2_BASE 0x54100000 +#define DISPLAY_A_BASE 0x54200000 +#define DISPLAY_B_BASE 0x54240000 +#define DSI_BASE 0x54300000 +#define VIC_BASE 0x54340000 +#define NVJPG_BASE 0x54380000 +#define NVDEC_BASE 0x54480000 +#define NVENC_BASE 0x544C0000 +#define TSEC_BASE 0x54500000 +#define SOR1_BASE 0x54580000 +#define GPU_BASE 0x57000000 +#define GPU_USER_BASE 0x58000000 +#define RES_SEMAPH_BASE 0x60001000 +#define ARB_SEMAPH_BASE 0x60002000 +#define ARB_PRI_BASE 0x60003000 +#define ICTLR_BASE 0x60004000 +#define TMR_BASE 0x60005000 +#define CLOCK_BASE 0x60006000 +#define FLOW_CTLR_BASE 0x60007000 +#define AHBDMA_BASE 0x60008000 +#define SYSREG_BASE 0x6000C000 +#define SB_BASE (SYSREG_BASE + 0x200) +#define ACTMON_BASE 0x6000C800 +#define GPIO_BASE 0x6000D000 +#define EXCP_VEC_BASE 0x6000F000 +#define IPATCH_BASE 0x6001DC00 +#define APBDMA_BASE 0x60020000 +#define VGPIO_BASE 0x60024000 +#define APB_MISC_BASE 0x70000000 +#define PINMUX_AUX_BASE 0x70003000 +#define UART_BASE 0x70006000 +#define PWM_BASE 0x7000A000 +#define I2C_BASE 0x7000C000 +#define RTC_BASE 0x7000E000 +#define PMC_BASE 0x7000E400 +#define FUSE_BASE 0x7000F800 +#define KFUSE_BASE 0x7000FC00 +#define SE_BASE 0x70012000 +#define TSENSOR_BASE 0x70014000 +#define ATOMICS_BASE 0x70016000 +#define MC_BASE 0x70019000 +#define EMC_BASE 0x7001B000 +#define EMC0_BASE 0x7001E000 +#define EMC1_BASE 0x7001F000 +#define XUSB_HOST_BASE 0x70090000 +#define XUSB_PADCTL_BASE 0x7009F000 +#define XUSB_DEV_BASE 0x700D0000 +#define SDMMC_BASE 0x700B0000 +#define SOC_THERM_BASE 0x700E2000 +#define MIPI_CAL_BASE 0x700E3000 +#define SYSCTR0_BASE 0x700F0000 +#define SYSCTR1_BASE 0x70100000 +#define CL_DVFS_BASE 0x70110000 +#define APE_BASE 0x702C0000 +#define AHUB_BASE 0x702D0000 +#define ADMAIF_BASE 0x702D0000 +#define AXBAR_BASE 0x702D0800 +#define I2S_BASE 0x702D1000 +#define ADMA_BASE 0x702E2000 +#define AMC_BASE 0x702EF000 +#define SE2_BASE 0x70412000 +#define SE_PKA1_BASE 0x70420000 +#define TZRAM_BASE 0x7C010000 +#define TZRAM_SIZE 0x10000 +#define TZRAM_T210B01_SIZE 0x3C000 +#define USB_BASE 0x7D000000 +#define USB_OTG_BASE USB_BASE +#define USB1_BASE 0x7D004000 +#define EMEM_BASE 0x80000000 + +#define MMIO_REG32(base, off) *(vu32 *)((base) + (off)) + +#define HOST1X(off) MMIO_REG32(HOST1X_BASE, off) +#define BPMP_CACHE_CTRL(off) MMIO_REG32(BPMP_CACHE_BASE, off) +#define MSELECT(off) MMIO_REG32(MSELECT_BASE, off) +#define DPAUX1(off) MMIO_REG32(DPAUX1_BASE, off) +#define TSEC2(off) MMIO_REG32(TSEC2_BASE, off) +#define DISPLAY_A(off) MMIO_REG32(DISPLAY_A_BASE, off) +#define DISPLAY_B(off) MMIO_REG32(DISPLAY_B_BASE, off) +#define DSI(off) MMIO_REG32(DSI_BASE, off) +#define VIC(off) MMIO_REG32(VIC_BASE, off) +#define NVJPG(off) MMIO_REG32(NVJPG_BASE, off) +#define NVDEC(off) MMIO_REG32(NVDEC_BASE, off) +#define NVENC(off) MMIO_REG32(NVENC_BASE, off) +#define TSEC(off) MMIO_REG32(TSEC_BASE, off) +#define SOR1(off) MMIO_REG32(SOR1_BASE, off) +#define GPU(off) MMIO_REG32(GPU_BASE, off) +#define GPU_USER(off) MMIO_REG32(GPU_USER_BASE, off) +#define ARB_PRI(off) MMIO_REG32(ARB_PRI_BASE, off) +#define ICTLR(cidx, off) MMIO_REG32(ICTLR_BASE + (0x100 * (cidx)), off) +#define TMR(off) MMIO_REG32(TMR_BASE, off) +#define CLOCK(off) MMIO_REG32(CLOCK_BASE, off) +#define FLOW_CTLR(off) MMIO_REG32(FLOW_CTLR_BASE, off) +#define AHBDMA(off) MMIO_REG32(AHBDMA_BASE, off) +#define SYSREG(off) MMIO_REG32(SYSREG_BASE, off) +#define AHB_GIZMO(off) MMIO_REG32(SYSREG_BASE, off) +#define SB(off) MMIO_REG32(SB_BASE, off) +#define ACTMON(off) MMIO_REG32(ACTMON_BASE, off) +#define GPIO(off) MMIO_REG32(GPIO_BASE, off) +#define EXCP_VEC(off) MMIO_REG32(EXCP_VEC_BASE, off) +#define APBDMA(off) MMIO_REG32(APBDMA_BASE, off) +#define VGPIO(off) MMIO_REG32(VGPIO_BASE, off) +#define APB_MISC(off) MMIO_REG32(APB_MISC_BASE, off) +#define PINMUX_AUX(off) MMIO_REG32(PINMUX_AUX_BASE, off) +#define PWM(off) MMIO_REG32(PWM_BASE, off) +#define RTC(off) MMIO_REG32(RTC_BASE, off) +#define PMC(off) MMIO_REG32(PMC_BASE, off) +#define SYSCTR0(off) MMIO_REG32(SYSCTR0_BASE, off) +#define SYSCTR1(off) MMIO_REG32(SYSCTR1_BASE, off) +#define FUSE(off) MMIO_REG32(FUSE_BASE, off) +#define KFUSE(off) MMIO_REG32(KFUSE_BASE, off) +#define SE(off) MMIO_REG32(SE_BASE, off) +#define MC(off) MMIO_REG32(MC_BASE, off) +#define EMC(off) MMIO_REG32(EMC_BASE, off) +#define EMC_CH0(off) MMIO_REG32(EMC0_BASE, off) +#define EMC_CH1(off) MMIO_REG32(EMC1_BASE, off) +#define XUSB_HOST(off) MMIO_REG32(XUSB_HOST_BASE, off) +#define XUSB_PADCTL(off) MMIO_REG32(XUSB_PADCTL_BASE, off) +#define XUSB_DEV(off) MMIO_REG32(XUSB_DEV_BASE, off) +#define XUSB_DEV_XHCI(off) MMIO_REG32(XUSB_DEV_BASE, off) +#define XUSB_DEV_PCI(off) MMIO_REG32(XUSB_DEV_BASE + 0x8000, off) +#define XUSB_DEV_DEV(off) MMIO_REG32(XUSB_DEV_BASE + 0x9000, off) +#define MIPI_CAL(off) MMIO_REG32(MIPI_CAL_BASE, off) +#define CL_DVFS(off) MMIO_REG32(CL_DVFS_BASE, off) +#define I2S(off) MMIO_REG32(I2S_BASE, off) +#define ADMA(off) MMIO_REG32(ADMA_BASE, off) +#define AMC(off) MMIO_REG32(AMC_BASE, off) +#define SE2(off) MMIO_REG32(SE2_BASE, off) +#define SE_PKA1(off) MMIO_REG32(SE_PKA1_BASE, off) +#define USB(off) MMIO_REG32(USB_BASE, off) +#define USB1(off) MMIO_REG32(USB1_BASE, off) +#define TEST_REG(off) MMIO_REG32(0x0, off) + +/* HOST1X v3 registers. */ +#define HOST1X_CH0_SYNC_BASE 0x2100 +#define HOST1X_CH0_SYNC_SYNCPT_BASE (HOST1X_CH0_SYNC_BASE + 0xF80) +#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_SYNCPT_BASE + 0x24) +#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_SYNCPT_BASE + 0x280) + +/*! EVP registers. */ +#define EVP_CPU_RESET_VECTOR 0x100 +#define EVP_COP_RESET_VECTOR 0x200 +#define EVP_COP_UNDEF_VECTOR 0x204 +#define EVP_COP_SWI_VECTOR 0x208 +#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C +#define EVP_COP_DATA_ABORT_VECTOR 0x210 +#define EVP_COP_RSVD_VECTOR 0x214 +#define EVP_COP_IRQ_VECTOR 0x218 +#define EVP_COP_FIQ_VECTOR 0x21C +#define EVP_COP_IRQ_STS 0x220 + +/*! Primary Interrupt Controller registers. */ +#define PRI_ICTLR_ISR 0x10 +#define PRI_ICTLR_FIR 0x14 +#define PRI_ICTLR_FIR_SET 0x18 +#define PRI_ICTLR_FIR_CLR 0x1C +#define PRI_ICTLR_CPU_IER 0x20 +#define PRI_ICTLR_CPU_IER_SET 0x24 +#define PRI_ICTLR_CPU_IER_CLR 0x28 +#define PRI_ICTLR_CPU_IEP_CLASS 0x2C +#define PRI_ICTLR_COP_IER 0x30 +#define PRI_ICTLR_COP_IER_SET 0x34 +#define PRI_ICTLR_COP_IER_CLR 0x38 +#define PRI_ICTLR_COP_IEP_CLASS 0x3C + +/* Arbiter registers */ +#define ARB_PRIO_CPU_PRIORITY 0x0 +#define ARB_PRIO_COP_PRIORITY 0x4 +#define ARB_PRIO_VCP_PRIORITY 0x8 +#define ARB_PRIO_DMA_PRIORITY 0xC +#define ARB_PRIO_UCQ_PRIORITY 0x10 + +/*! AHB Gizmo registers. */ +#define AHB_ARBITRATION_PRIORITY_CTRL 0x8 +#define PRIORITY_CTRL_WEIGHT(x) (((x) & 7) << 29) +#define PRIORITY_SELECT_USB BIT(6) // USB-OTG. +#define PRIORITY_SELECT_USB2 BIT(18) // USB-HSIC. +#define PRIORITY_SELECT_USB3 BIT(17) // XUSB. +#define AHB_GIZMO_AHB_MEM 0x10 +#define AHB_MEM_ENB_FAST_REARBITRATE BIT(2) +#define AHB_MEM_DONT_SPLIT_AHB_WR BIT(7) +#define AHB_MEM_IMMEDIATE BIT(18) +#define AHB_GIZMO_APB_DMA 0x14 +#define AHB_GIZMO_USB 0x20 +#define AHB_GIZMO_SDMMC4 0x48 +#define AHB_GIZMO_USB2 0x7C +#define AHB_GIZMO_USB3 0x80 // Doesn't exist on T21x?? +#define AHB_GIZMO_IMMEDIATE BIT(18) +#define AHB_ARBITRATION_XBAR_CTRL 0xE0 +#define AHB_AHB_MEM_PREFETCH_CFG3 0xE4 +#define AHB_AHB_MEM_PREFETCH_CFG4 0xE8 +#define AHB_AHB_MEM_PREFETCH_CFG1 0xF0 +#define AHB_AHB_MEM_PREFETCH_CFG2 0xF4 +#define MST_ID(x) (((x) & 0x1F) << 26) +#define MEM_PREFETCH_AHBDMA_MST_ID MST_ID(5) +#define MEM_PREFETCH_USB_MST_ID MST_ID(6) // USB-OTG. Doesn't exist on T210B01. +#define MEM_PREFETCH_USB2_MST_ID MST_ID(18) // USB-HSIC. Doesn't exist on T210B01. +#define MEM_PREFETCH_USB3_MST_ID MST_ID(17) // XUSB. Doesn't exist on T210B01. +#define MEM_PREFETCH_ADDR_BNDRY(x) (((x) & 0xF) << 21) +#define MEM_PREFETCH_ENABLE BIT(31) +#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xFC +#define MEM_WRQUE_SE_MST_ID BIT(14) +#define AHB_AHB_SPARE_REG 0x110 + +/*! Misc registers. */ +#define APB_MISC_PP_STRAPPING_OPT_A 0x8 +#define APB_MISC_PP_PINMUX_GLOBAL 0x40 +#define APB_MISC_GP_HIDREV 0x804 +#define GP_HIDREV_MAJOR_T210 0x1 +#define GP_HIDREV_MAJOR_T210B01 0x2 +#define APB_MISC_GP_ASDBGREG 0x810 +#define APB_MISC_GP_TRANSACTOR_SCRATCH 0x864 +#define APB_MISC_GP_AVP_TRANSACTOR_SCRATCH 0x880 +#define APB_MISC_GP_CPU0_TRANSACTOR_SCRATCH 0x884 +#define APB_MISC_GP_CPU1_TRANSACTOR_SCRATCH 0x888 +#define APB_MISC_GP_CPU2_TRANSACTOR_SCRATCH 0x88C +#define APB_MISC_GP_CPU3_TRANSACTOR_SCRATCH 0x890 +#define APB_MISC_GP_AUD_MCLK_CFGPADCTRL 0x8F4 +#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 +#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 +#define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL 0xA9C +#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 +#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC +#define APB_MISC_GP_DSI_PAD_CONTROL 0xAC0 +#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 +#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 + +/*! Secure boot registers. */ +#define SB_CSR 0x0 +#define SB_CSR_NS_RST_VEC_WR_DIS BIT(1) +#define SB_CSR_PIROM_DISABLE BIT(4) +#define SB_AA64_RESET_LOW 0x30 +#define SB_AA64_RST_AARCH64_MODE_EN BIT(0) +#define SB_AA64_RESET_HIGH 0x34 + +/*! SOR registers. */ +#define SOR_DP_HDCP_BKSV_LSB 0x1E8 +#define SOR_TMDS_HDCP_BKSV_LSB 0x21C +#define SOR_TMDS_HDCP_CN_MSB 0x208 +#define SOR_TMDS_HDCP_CN_LSB 0x20C + +/*! RTC registers. */ +#define APBDEV_RTC_SECONDS 0x8 +#define APBDEV_RTC_SHADOW_SECONDS 0xC +#define APBDEV_RTC_MILLI_SECONDS 0x10 + +/*! SYSCTR0 registers. */ +#define SYSCTR0_CNTCR 0x00 +#define SYSCTR0_CNTFID0 0x20 +#define SYSCTR0_COUNTERS_BASE 0xFD0 +#define SYSCTR0_COUNTERS 12 +#define SYSCTR0_COUNTERID0 0xFE0 +#define SYSCTR0_COUNTERID1 0xFE4 +#define SYSCTR0_COUNTERID2 0xFE8 +#define SYSCTR0_COUNTERID3 0xFEC +#define SYSCTR0_COUNTERID4 0xFD0 +#define SYSCTR0_COUNTERID5 0xFD4 +#define SYSCTR0_COUNTERID6 0xFD8 +#define SYSCTR0_COUNTERID7 0xFDC +#define SYSCTR0_COUNTERID8 0xFF0 +#define SYSCTR0_COUNTERID9 0xFF4 +#define SYSCTR0_COUNTERID10 0xFF8 +#define SYSCTR0_COUNTERID11 0xFFC + +/*! IPATCH registers. */ +#define IPATCH_CAM_VALID 0x0 +#define IPATCH_CAM_BASE 0x4 +#define IPATCH_CAM(i) (IPATCH_CAM_BASE + (i) * 4) +#define IPATCH_CAM_ENTRIES 12 + +/*! I2S registers. */ +#define I2S1_CG 0x88 +#define I2S1_CTRL 0xA0 +#define I2S2_CG 0x188 +#define I2S2_CTRL 0x1A0 +#define I2S3_CG 0x288 +#define I2S3_CTRL 0x2A0 +#define I2S4_CG 0x388 +#define I2S4_CTRL 0x3A0 +#define I2S5_CG 0x488 +#define I2S5_CTRL 0x4A0 +#define I2S_CG_SLCG_ENABLE BIT(0) +#define I2S_CTRL_MASTER_EN BIT(10) + +/*! PWM registers. */ +#define PWM_CONTROLLER_PWM_CSR_0 0x00 +#define PWM_CONTROLLER_PWM_CSR_1 0x10 +#define PWM_CSR_EN BIT(31) + +/*! Special registers. */ +#define EMC_SCRATCH0 0x324 +#define EMC_HEKA_UPD BIT(30) + +/*! Flow controller registers. */ +#define FLOW_CTLR_HALT_COP_EVENTS 0x4 +#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 +#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 +#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C +#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 +#define HALT_GIC_IRQ BIT(9) +#define HALT_LIC_IRQ BIT(11) +#define HALT_SEC BIT(23) +#define HALT_MSEC BIT(24) +#define HALT_USEC BIT(25) +#define HALT_JTAG BIT(28) +#define HALT_MODE_NONE (0 << 29u) +#define HALT_MODE_RUN_AND_INT (1 << 29u) +#define HALT_MODE_WAITEVENT (2 << 29u) +#define HALT_MODE_WAITEVENT_AND_INT (3 << 29u) +#define HALT_MODE_STOP_UNTIL_IRQ (4 << 29u) +#define HALT_MODE_STOP_UNTIL_IRQ_AND_INT (5 << 29u) +#define HALT_MODE_STOP_UNTIL_EVENT_AND_IRQ (6 << 29u) +#define HALT_MAX_CNT 0xFF +#define FLOW_CTLR_COP_CSR 0xC +#define FLOW_CTLR_CPU0_CSR 0x8 +#define FLOW_CTLR_CPU1_CSR 0x18 +#define FLOW_CTLR_CPU2_CSR 0x20 +#define FLOW_CTLR_CPU3_CSR 0x28 +#define CSR_ENABLE BIT(0) +#define CSR_WAIT_WFI_NONE (0 << 8u) +#define CSR_WAIT_WFI_CPU0 (BIT(0) << 8u) +#define CSR_ENABLE_EXT_CPU_ONLY (0 << 12u) +#define CSR_ENABLE_EXT_CPU_NCPU (1 << 12u) +#define CSR_ENABLE_EXT_CPU_RAIL (2 << 12u) +#define CSR_EVENT_FLAG BIT(14) +#define CSR_INTR_FLAG BIT(15) +#define CSR_HALT BIT(22) +#define FLOW_CTLR_CPU_PWR_CSR 0x38 +#define CPU_PWR_RAIL_STS_MASK (3 << 1u) +#define CPU_PWR_RAIL_OFF 0 +#define FLOW_CTLR_RAM_REPAIR 0x40 +#define RAM_REPAIR_REQ BIT(0) +#define RAM_REPAIR_STS BIT(1) +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 +#define CLUSTER_CTRL_ACTIVE_SLOW BIT(0) + +/* MSelect registers */ +#define MSELECT_CONFIG 0x00 +#define MSELECT_CFG_ERR_RESP_EN_PCIE BIT(24) +#define MSELECT_CFG_ERR_RESP_EN_GPU BIT(25) +#define MSELECT_CFG_WRAP_TO_INCR_BPMP BIT(27) +#define MSELECT_CFG_WRAP_TO_INCR_PCIE BIT(28) +#define MSELECT_CFG_WRAP_TO_INCR_GPU BIT(29) + +/* NVDEC registers */ +#define NVDEC_SA_KEYSLOT_FALCON 0x2100 +#define NVDEC_SA_KEYSLOT_TZ 0x2104 +#define NVDEC_SA_KEYSLOT_OTF 0x210C +#define NVDEC_SA_KEYSLOT_GLOBAL_RW 0x2118 +#define NVDEC_VPR_ALL_OTF_GOTO_VPR 0x211C +#endif diff --git a/bdk/soc/timer.c b/bdk/soc/timer.c new file mode 100644 index 0000000..786f123 --- /dev/null +++ b/bdk/soc/timer.c @@ -0,0 +1,123 @@ +/* + * Timer/Watchdog driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * 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 +#include +#include +#include + +#define EXCP_TYPE_ADDR 0x4003FFF8 +#define EXCP_TYPE_WDT 0x544457 // "WDT". + +#define USE_RTC_TIMER + +u32 get_tmr_s() +{ + (void)RTC(APBDEV_RTC_MILLI_SECONDS); + return (u32)RTC(APBDEV_RTC_SECONDS); +} + +u32 get_tmr_ms() +{ + // The registers must be read with the following order: + // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) + return (u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); +} + +u32 get_tmr_us() +{ + return (u32)TMR(TIMERUS_CNTR_1US); +} + +void msleep(u32 ms) +{ +#ifdef USE_RTC_TIMER + u32 start = (u32)RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); + // Casting to u32 is important! + while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) + ; +#else + bpmp_msleep(ms); +#endif +} + +void usleep(u32 us) +{ +#ifdef USE_RTC_TIMER + u32 start = (u32)TMR(TIMERUS_CNTR_1US); + + // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately. + if ((start + us) < start) + bpmp_usleep(us); + else + while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important! + ; +#else + bpmp_usleep(us); +#endif +} + +// Instruction wait loop. Each loop is 3 cycles (SUBS+BGT). Usage: isleep(ILOOP(instr)). Base 408MHz: 7.35ns. +void __attribute__((target("arm"))) isleep(u32 is) +{ + asm volatile( "0:" "SUBS %[is_cnt], #1;" "BGT 0b;" : [is_cnt] "+r" (is)); +} + +void timer_usleep(u32 us) +{ + TMR(TIMER_TMR8_TMR_PTV) = TIMER_EN | us; + + irq_wait_event(IRQ_TMR8); + + TMR(TIMER_TMR8_TMR_PCR) = TIMER_INTR_CLR; +} + +void watchdog_start(u32 us, u32 mode) +{ + // WDT4 is for BPMP. + TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN; + TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN | us; + TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | mode; + TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; +} + +void watchdog_end() +{ + // WDT4 is for BPMP. + TMR(TIMER_TMR9_TMR_PTV) = 0; + TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN; + TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; // Re-arm to clear any interrupts. + TMR(TIMER_WDT4_COMMAND) = TIMER_CNT_DISABLE; + TMR(TIMER_TMR9_TMR_PCR) = TIMER_INTR_CLR; +} + +void watchdog_handle() +{ + // Disable watchdog and clear its interrupts. + watchdog_end(); + + // Set watchdog magic. + *(u32 *)EXCP_TYPE_ADDR = EXCP_TYPE_WDT; +} + +bool watchdog_fired() +{ + // Return if watchdog got fired. User handles clearing. + return (*(u32 *)EXCP_TYPE_ADDR == EXCP_TYPE_WDT); +} diff --git a/bdk/soc/timer.h b/bdk/soc/timer.h new file mode 100644 index 0000000..800eaac --- /dev/null +++ b/bdk/soc/timer.h @@ -0,0 +1,64 @@ +/* + * Timer/Watchdog driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * 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 _TIMER_H_ +#define _TIMER_H_ + +#include + +// TMR registers. +#define TIMERUS_CNTR_1US (0x10 + 0x0) +#define TIMERUS_USEC_CFG (0x10 + 0x4) +#define TIMER_TMR8_TMR_PTV 0x78 +#define TIMER_TMR9_TMR_PTV 0x80 +#define TIMER_PER_EN BIT(30) +#define TIMER_EN BIT(31) +#define TIMER_TMR8_TMR_PCR 0x7C +#define TIMER_TMR9_TMR_PCR 0x8C +#define TIMER_INTR_CLR BIT(30) + +// WDT registers. +#define TIMER_WDT4_CONFIG (0x100 + 0x80) +#define TIMER_SRC(TMR) ((TMR) & 0xF) +#define TIMER_PER(PER) (((PER) & 0xFF) << 4) +#define TIMER_IRQENABL_EN BIT(12) +#define TIMER_FIQENABL_EN BIT(13) +#define TIMER_SYSRESET_EN BIT(14) +#define TIMER_PMCRESET_EN BIT(15) +#define TIMER_WDT4_COMMAND (0x108 + 0x80) +#define TIMER_START_CNT BIT(0) +#define TIMER_CNT_DISABLE BIT(1) +#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80) +#define TIMER_MAGIC_PTRN 0xC45A + +u32 get_tmr_us(); +u32 get_tmr_ms(); +u32 get_tmr_s(); +void usleep(u32 us); +void msleep(u32 ms); +#define ILOOP(is) ((is) / 3) +void isleep(u32 is); + +void timer_usleep(u32 us); + +void watchdog_start(u32 us, u32 mode); +void watchdog_end(); +void watchdog_handle(); +bool watchdog_fired(); + +#endif diff --git a/bdk/soc/uart.c b/bdk/soc/uart.c new file mode 100644 index 0000000..c76c66e --- /dev/null +++ b/bdk/soc/uart.c @@ -0,0 +1,221 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2022 CTCaer +* +* 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 +#include +#include + +/* UART A, B, C, D and E. */ +static const u16 _uart_base_offsets[5] = { 0, 0x40, 0x200, 0x300, 0x400 }; + +void uart_init(u32 idx, u32 baud, u32 mode) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + // Make sure no data is being sent. + if (!(mode & (UART_MCR_CTS_EN | UART_MCR_DTR))) + uart_wait_xfer(idx, UART_TX_IDLE); + + // Set clock. + bool clk_type = clock_uart_use_src_div(idx, baud); + + // 2 STOP bits for rates > 1M. (Reduced efficiency but less errors on high baudrates). + u32 uart_lcr_stop = baud > 1000000 ? UART_LCR_STOP : 0; + + // Misc settings. + u32 div = clk_type ? ((8 * baud + 408000000) / (16 * baud)) : 1; // DIV_ROUND_CLOSEST. + uart->UART_IER_DLAB = 0; // Disable interrupts. + uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode. + uart->UART_THR_DLAB = (u8)div; // Divisor latch LSB. + uart->UART_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB. + + // Disable DLAB and set STOP bits setting if applicable. + uart->UART_LCR = uart_lcr_stop | UART_LCR_WORD_LENGTH_8; + (void)uart->UART_SPR; + + // Enable fifo. + uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO; + (void)uart->UART_SPR; + usleep(20); + + // Disable hardware flow control. + uart->UART_MCR = 0; + usleep(96); + + // Clear tx/rx fifos. + uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; + + // Set hardware flow control. + uart->UART_MCR = mode; + + // Wait 3 symbols for baudrate change. + usleep(3 * ((baud + 999999) / baud)); + uart_wait_xfer(idx, UART_TX_IDLE | UART_RX_RDYR); +} + +void uart_wait_xfer(u32 idx, u32 which) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + if (UART_TX_IDLE & which) + { + while (!(uart->UART_LSR & UART_LSR_TMTY)) + ; + } + if (UART_RX_RDYR & which) + { + while (uart->UART_LSR & UART_LSR_RDR) + (void)uart->UART_THR_DLAB; + } +} + +void uart_send(u32 idx, const u8 *buf, u32 len) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + for (u32 i = 0; i != len; i++) + { + while (!(uart->UART_LSR & UART_LSR_THRE)) + ; + uart->UART_THR_DLAB = buf[i]; + } +} + +u32 uart_recv(u32 idx, u8 *buf, u32 len) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + bool manual_mode = uart->UART_MCR & UART_MCR_RTS; + u32 timeout = get_tmr_us() + 250; + u32 i; + + if (manual_mode) + uart->UART_MCR &= ~UART_MCR_RTS; + + for (i = 0; ; i++) + { + if (len && len <= i) + break; + + while (!(uart->UART_LSR & UART_LSR_RDR)) + if (timeout < get_tmr_us()) + goto out; + + buf[i] = uart->UART_THR_DLAB; + timeout = get_tmr_us() + 250; + } + +out: + if (manual_mode) + uart->UART_MCR |= UART_MCR_RTS; + + return i; +} + +void uart_invert(u32 idx, bool enable, u32 invert_mask) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + if (enable) + uart->UART_IRDA_CSR |= invert_mask; + else + uart->UART_IRDA_CSR &= ~invert_mask; + (void)uart->UART_SPR; +} + +void uart_set_mode(u32 idx, u32 mode) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + uart->UART_MCR = mode; + (void)uart->UART_SPR; +} + +u32 uart_get_IIR(u32 idx) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + u32 iir = uart->UART_IIR_FCR & UART_IIR_INT_MASK; + + if (iir & UART_IIR_NO_INT) + return 0; + else + return ((iir >> 1) + 1); // Return encoded interrupt. +} + +void uart_set_IIR(u32 idx) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD; + (void)uart->UART_SPR; + uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD; + (void)uart->UART_SPR; +} + +void uart_empty_fifo(u32 idx, u32 which) +{ + uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]); + + uart->UART_MCR = 0; + (void)uart->UART_SPR; + usleep(96); + + uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | which; + (void)uart->UART_SPR; + usleep(18); + u32 tries = 0; + + if (UART_IIR_FCR_TX_CLR & which) + { + while (tries < 10 && !(uart->UART_LSR & UART_LSR_TMTY)) + { + tries++; + usleep(100); + } + tries = 0; + } + + if (UART_IIR_FCR_RX_CLR & which) + { + while (tries < 10 && (uart->UART_LSR & UART_LSR_RDR)) + { + tries++; + usleep(100); + } + } +} + +#ifdef DEBUG_UART_PORT +#include +#include + +#include + +void uart_printf(const char *fmt, ...) +{ + va_list ap; + + //! NOTE: Anything more and it will hang. Heap usage is out of the question. + char text[256]; + + va_start(ap, fmt); + s_vprintf(text, fmt, ap); + va_end(ap); + + uart_send(DEBUG_UART_PORT, (u8 *)text, strlen(text)); +} +#endif diff --git a/bdk/soc/uart.h b/bdk/soc/uart.h new file mode 100644 index 0000000..a24d5c9 --- /dev/null +++ b/bdk/soc/uart.h @@ -0,0 +1,118 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2020 CTCaer +* +* 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 _UART_H_ +#define _UART_H_ + +#include + +#define UART_A 0 +#define UART_B 1 +#define UART_C 2 +#define UART_D 3 +#define UART_E 4 + +#define BAUD_115200 115200 + +#define UART_TX_IDLE BIT(0) +#define UART_RX_RDYR BIT(1) + +#define UART_TX_FIFO_FULL BIT(8) +#define UART_RX_FIFO_EMPTY BIT(9) + +#define UART_INVERT_RXD BIT(0) +#define UART_INVERT_TXD BIT(1) +#define UART_INVERT_CTS BIT(2) +#define UART_INVERT_RTS BIT(3) + +#define UART_IER_DLAB_IE_EORD BIT(5) + +#define UART_LCR_WORD_LENGTH_8 0x3 +#define UART_LCR_STOP BIT(2) +#define UART_LCR_DLAB BIT(7) + +#define UART_LSR_RDR BIT(0) +#define UART_LSR_THRE BIT(5) +#define UART_LSR_TMTY BIT(6) +#define UART_LSR_FIFOE BIT(7) + +#define UART_IIR_FCR_EN_FIFO BIT(0) +#define UART_IIR_FCR_RX_CLR BIT(1) +#define UART_IIR_FCR_TX_CLR BIT(2) + +#define UART_IIR_NO_INT BIT(0) +#define UART_IIR_INT_MASK 0xF +/* Custom returned interrupt results. Actual interrupts are -1 */ +#define UART_IIR_NOI 0 // No interrupt. +#define UART_IIR_MSI 1 // Modem status interrupt. +#define UART_IIR_THRI 2 // Transmitter holding register empty. +#define UART_IIR_RDI 3 // Receiver data interrupt. +#define UART_IIR_ERROR 4 // Overrun Error, Parity Error, Framing Error, Break. +#define UART_IIR_REDI 5 // Receiver end of data interrupt. +#define UART_IIR_RDTI 7 // Receiver data timeout interrupt. + +#define UART_MCR_DTR BIT(0) +#define UART_MCR_RTS BIT(1) +#define UART_MCR_CTS_EN BIT(5) +#define UART_MCR_RTS_EN BIT(6) + +#define UART_FIFO_SIZE 36 + +typedef struct _uart_t +{ + /* 0x00 */ vu32 UART_THR_DLAB; + /* 0x04 */ vu32 UART_IER_DLAB; + /* 0x08 */ vu32 UART_IIR_FCR; + /* 0x0C */ vu32 UART_LCR; + /* 0x10 */ vu32 UART_MCR; + /* 0x14 */ vu32 UART_LSR; + /* 0x18 */ vu32 UART_MSR; + /* 0x1C */ vu32 UART_SPR; + /* 0x20 */ vu32 UART_IRDA_CSR; + /* 0x24 */ vu32 UART_RX_FIFO_CFG; + /* 0x28 */ vu32 UART_MIE; + /* 0x2C */ vu32 UART_VENDOR_STATUS; + /* 0x30 */ u8 _pad_30[0xC]; + /* 0x3C */ vu32 UART_ASR; +} uart_t; + +//! TODO: Commented out modes are not supported yet. +typedef enum _uart_mode_t +{ + UART_AO_TX_AO_RX = 0, + //UART_MN_TX_AO_RX = UART_MCR_RTS | UART_MCR_DTR, + UART_AO_TX_MN_RX = UART_MCR_RTS, // Up to 36 bytes read. + //UART_MN_TX_AO_RX = UART_MCR_DTR, + //UART_HW_TX_HW_RX = UART_MCR_RTS_EN | UART_MCR_CTS_EN, + UART_AO_TX_HW_RX = UART_MCR_RTS_EN, + //UART_HW_TX_AO_RX = UART_MCR_CTS_EN, +} uart_mode_t; + +void uart_init(u32 idx, u32 baud, u32 mode); +void uart_wait_xfer(u32 idx, u32 which); +void uart_send(u32 idx, const u8 *buf, u32 len); +u32 uart_recv(u32 idx, u8 *buf, u32 len); +void uart_invert(u32 idx, bool enable, u32 invert_mask); +void uart_set_mode(u32 idx, u32 mode); +u32 uart_get_IIR(u32 idx); +void uart_set_IIR(u32 idx); +void uart_empty_fifo(u32 idx, u32 which); +#ifdef DEBUG_UART_PORT +void uart_printf(const char *fmt, ...); +#endif + +#endif diff --git a/bdk/storage/emmc.c b/bdk/storage/emmc.c new file mode 100644 index 0000000..b1ab03d --- /dev/null +++ b/bdk/storage/emmc.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2024 CTCaer + * + * 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 "emmc.h" +#include +#include +#include +#include + +static u16 emmc_errors[3] = { 0 }; // Init and Read/Write errors. +static u32 emmc_mode = EMMC_MMC_HS400; + +sdmmc_t emmc_sdmmc; +sdmmc_storage_t emmc_storage; +FATFS emmc_fs; + +#ifdef BDK_EMUMMC_ENABLE +int emummc_storage_read(u32 sector, u32 num_sectors, void *buf); +int emummc_storage_write(u32 sector, u32 num_sectors, void *buf); +#endif + +void emmc_error_count_increment(u8 type) +{ + switch (type) + { + case EMMC_ERROR_INIT_FAIL: + emmc_errors[0]++; + break; + case EMMC_ERROR_RW_FAIL: + emmc_errors[1]++; + break; + case EMMC_ERROR_RW_RETRY: + emmc_errors[2]++; + break; + } +} + +u16 *emmc_get_error_count() +{ + return emmc_errors; +} + +u32 emmc_get_mode() +{ + return emmc_mode; +} + +void emmc_end() { sdmmc_storage_end(&emmc_storage); } + +int emmc_init_retry(bool power_cycle) +{ + u32 bus_width = SDMMC_BUS_WIDTH_8; + u32 type = SDHCI_TIMING_MMC_HS400; + + // Power cycle SD eMMC. + if (power_cycle) + { + emmc_mode--; + emmc_end(); + } + + // Get init parameters. + switch (emmc_mode) + { + case EMMC_INIT_FAIL: // Reset to max. + return 0; + case EMMC_1BIT_HS52: + bus_width = SDMMC_BUS_WIDTH_1; + type = SDHCI_TIMING_MMC_HS52; + break; + case EMMC_8BIT_HS52: + type = SDHCI_TIMING_MMC_HS52; + break; + case EMMC_MMC_HS200: + type = SDHCI_TIMING_MMC_HS200; + break; + case EMMC_MMC_HS400: + type = SDHCI_TIMING_MMC_HS400; + break; + default: + emmc_mode = EMMC_MMC_HS400; + } + + return sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type); +} + +bool emmc_initialize(bool power_cycle) +{ + // Reset mode in case of previous failure. + if (emmc_mode == EMMC_INIT_FAIL) + emmc_mode = EMMC_MMC_HS400; + + if (power_cycle) + emmc_end(); + + int res = !emmc_init_retry(false); + + while (true) + { + if (!res) + return true; + else + { + emmc_errors[EMMC_ERROR_INIT_FAIL]++; + + if (emmc_mode == EMMC_INIT_FAIL) + break; + else + res = !emmc_init_retry(true); + } + } + + emmc_end(); + + return false; +} + +int emmc_set_partition(u32 partition) { return sdmmc_storage_set_mmc_partition(&emmc_storage, partition); } + +void emmc_gpt_parse(link_t *gpt) +{ + gpt_t *gpt_buf = (gpt_t *)zalloc(GPT_NUM_BLOCKS * EMMC_BLOCKSIZE); + +#ifdef BDK_EMUMMC_ENABLE + emummc_storage_read(GPT_FIRST_LBA, GPT_NUM_BLOCKS, gpt_buf); +#else + sdmmc_storage_read(&emmc_storage, GPT_FIRST_LBA, GPT_NUM_BLOCKS, gpt_buf); +#endif + + // Check if no GPT or more than max allowed entries. + if (memcmp(&gpt_buf->header.signature, "EFI PART", 8) || gpt_buf->header.num_part_ents > 128) + goto out; + + for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++) + { + emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t)); + + if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba) + continue; + + part->index = i; + part->lba_start = gpt_buf->entries[i].lba_start; + part->lba_end = gpt_buf->entries[i].lba_end; + part->attrs = gpt_buf->entries[i].attrs; + + // ASCII conversion. Copy only the LSByte of the UTF-16LE name. + for (u32 j = 0; j < 36; j++) + part->name[j] = gpt_buf->entries[i].name[j]; + part->name[35] = 0; + + list_append(gpt, &part->link); + } + +out: + free(gpt_buf); +} + +void emmc_gpt_free(link_t *gpt) +{ + LIST_FOREACH_SAFE(iter, gpt) + free(CONTAINER_OF(iter, emmc_part_t, link)); +} + +emmc_part_t *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 emmc_part_read(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; + +#ifdef BDK_EMUMMC_ENABLE + return emummc_storage_read(part->lba_start + sector_off, num_sectors, buf); +#else + return sdmmc_storage_read(&emmc_storage, part->lba_start + sector_off, num_sectors, buf); +#endif +} + +int emmc_part_write(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; + +#ifdef BDK_EMUMMC_ENABLE + return emummc_storage_write(part->lba_start + sector_off, num_sectors, buf); +#else + return sdmmc_storage_write(&emmc_storage, part->lba_start + sector_off, num_sectors, buf); +#endif +} + +void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1) +{ + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD) + { + *mod0 = 0xF7; + *mod1 = 0x86; + } + else + { + *mod0 = 0x37; + *mod1 = 0x84; + } +} diff --git a/bdk/storage/emmc.h b/bdk/storage/emmc.h new file mode 100644 index 0000000..904852d --- /dev/null +++ b/bdk/storage/emmc.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019-2022 CTCaer + * + * 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 _EMMC_H_ +#define _EMMC_H_ + +#include +#include +#include + +#include + +#define GPT_FIRST_LBA 1 +#define GPT_NUM_BLOCKS 33 +#define EMMC_BLOCKSIZE SDMMC_DAT_BLOCKSIZE + +enum +{ + EMMC_INIT_FAIL = 0, + EMMC_1BIT_HS52 = 1, + EMMC_8BIT_HS52 = 2, + EMMC_MMC_HS200 = 3, + EMMC_MMC_HS400 = 4, +}; + +enum +{ + EMMC_ERROR_INIT_FAIL = 0, + EMMC_ERROR_RW_FAIL = 1, + EMMC_ERROR_RW_RETRY = 2 +}; + +typedef struct _emmc_part_t +{ + u32 index; + u32 lba_start; + u32 lba_end; + u64 attrs; + char name[37]; + link_t link; +} emmc_part_t; + +extern sdmmc_t emmc_sdmmc; +extern sdmmc_storage_t emmc_storage; +extern FATFS emmc_fs; + +void emmc_error_count_increment(u8 type); +u16 *emmc_get_error_count(); +u32 emmc_get_mode(); +int emmc_init_retry(bool power_cycle); +bool emmc_initialize(bool power_cycle); +int emmc_set_partition(u32 partition); +void emmc_end(); + +void emmc_gpt_parse(link_t *gpt); +void emmc_gpt_free(link_t *gpt); +emmc_part_t *emmc_part_find(link_t *gpt, const char *name); +int emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); +int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); + +void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1); + +#endif diff --git a/bdk/storage/mbr_gpt.h b/bdk/storage/mbr_gpt.h new file mode 100644 index 0000000..7f38108 --- /dev/null +++ b/bdk/storage/mbr_gpt.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * 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 MBR_GPT_H +#define MBR_GPT_H + +#include + +typedef struct _mbr_chs_t +{ + u8 head; + u8 sector; + u8 cylinder; +} __attribute__((packed)) mbr_chs_t; + +typedef struct _mbr_part_t +{ + u8 status; + mbr_chs_t start_sct_chs; + u8 type; + mbr_chs_t end_sct_chs; + u32 start_sct; + u32 size_sct; +} __attribute__((packed)) mbr_part_t; + +typedef struct _mbr_t +{ +/* 0x000 */ u8 bootstrap[440]; +/* 0x1B8 */ u32 signature; +/* 0x1BC */ u16 copy_protected; +/* 0x1BE */ mbr_part_t partitions[4]; +/* 0x1FE */ u16 boot_signature; +} __attribute__((packed)) mbr_t; + +typedef struct _gpt_entry_t +{ +/* 0x00 */ u8 type_guid[0x10]; +/* 0x10 */ u8 part_guid[0x10]; +/* 0x20 */ u64 lba_start; +/* 0x28 */ u64 lba_end; +/* 0x30 */ u64 attrs; +/* 0x38 */ u16 name[36]; +} gpt_entry_t; + +typedef struct _gpt_header_t +{ +/* 0x00 */ u64 signature; // "EFI PART" +/* 0x08 */ u32 revision; +/* 0x0C */ u32 size; +/* 0x10 */ u32 crc32; +/* 0x14 */ u32 res1; +/* 0x18 */ u64 my_lba; +/* 0x20 */ u64 alt_lba; +/* 0x28 */ u64 first_use_lba; +/* 0x30 */ u64 last_use_lba; +/* 0x38 */ u8 disk_guid[0x10]; +/* 0x48 */ u64 part_ent_lba; +/* 0x50 */ u32 num_part_ents; +/* 0x54 */ u32 part_ent_size; +/* 0x58 */ u32 part_ents_crc32; +/* 0x5C */ u8 res2[420]; // Used as first 3 partition entries backup for HOS. +} gpt_header_t; + +typedef struct _gpt_t +{ + gpt_header_t header; + gpt_entry_t entries[128]; +} gpt_t; + +#endif diff --git a/nyx/nyx_gui/storage/mmc.h b/bdk/storage/mmc.h similarity index 86% rename from nyx/nyx_gui/storage/mmc.h rename to bdk/storage/mmc.h index 0d87e35..c7d6106 100644 --- a/nyx/nyx_gui/storage/mmc.h +++ b/bdk/storage/mmc.h @@ -2,6 +2,7 @@ * Header for MultiMediaCard (MMC) * * Copyright 2002 Hewlett-Packard Company + * Copyright 2018-2021 CTCaer * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is @@ -21,8 +22,8 @@ * 15 May 2002 */ -#ifndef LINUX_MMC_MMC_H -#define LINUX_MMC_MMC_H +#ifndef MMC_H +#define MMC_H /* Standard MMC commands (4.1) type argument response */ /* class 1 */ @@ -84,6 +85,11 @@ #define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ +#define MMC_VENDOR_60_CMD 60 /* Vendor Defined */ +#define MMC_VENDOR_61_CMD 61 /* Vendor Defined */ +#define MMC_VENDOR_62_CMD 62 /* Vendor Defined */ +#define MMC_VENDOR_63_CMD 63 /* Vendor Defined */ + /* 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 */ @@ -92,29 +98,29 @@ #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_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 + * 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 */ @@ -136,13 +142,17 @@ c : clear by read #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_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_SKIP_STATE_CHECK (1 << 4) /* Custom state to skip expected state check */ +#define R1_AKE_SEQ_ERROR (1 << 3) +/* R1_CURRENT_STATE 12:9 */ +#define R1_STATE(x) ((x) << 9) #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 @@ -154,9 +164,9 @@ c : clear by read #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. -*/ + * 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) @@ -177,13 +187,16 @@ c : clear by read #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 */ + * OCR bits are mostly in host.h + */ +#define MMC_CARD_VDD_18 (1 << 7) /* Card VDD voltage 1.8 */ +#define MMC_CARD_VDD_27_34 (0x7F << 15) /* Card VDD voltage 2.7 ~ 3.4 */ +#define MMC_CARD_CCS (1 << 30) /* Card Capacity status bit */ +#define MMC_CARD_BUSY (1 << 31) /* Card Power up status bit */ /* -* Card Command Classes (CCC) -*/ + * 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) */ @@ -211,8 +224,8 @@ c : clear by read /* (CMD?) */ /* -* CSD field definitions -*/ + * 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 */ @@ -226,8 +239,8 @@ c : clear by read #define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ /* -* EXT_CSD fields -*/ + * EXT_CSD fields + */ #define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ #define EXT_CSD_FLUSH_CACHE 32 /* W */ @@ -241,6 +254,7 @@ c : clear by read #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_MAX_ENH_SIZE_MULT 157 /* RO, 3 bytes */ #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ #define EXT_CSD_HPI_MGMT 161 /* R/W */ #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ @@ -304,8 +318,8 @@ c : clear by read #define EXT_CSD_HPI_FEATURES 503 /* RO */ /* -* EXT_CSD field definitions -*/ + * EXT_CSD field definitions + */ #define EXT_CSD_WR_REL_PARAM_EN (1<<2) @@ -381,8 +395,8 @@ c : clear by read #define EXT_CSD_PACKED_EVENT_EN (1<<3) /* -* EXCEPTION_EVENT_STATUS field -*/ + * 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) @@ -392,34 +406,37 @@ c : clear by read #define EXT_CSD_PACKED_INDEXED_ERROR (1<<1) /* -* BKOPS status level -*/ -#define EXT_CSD_BKOPS_LEVEL_2 0x2 + * BKOPS status level + */ +#define EXT_CSD_BKOPS_OK 0x0 +#define EXT_CSD_BKOPS_NON_CRITICAL 0x1 +#define EXT_CSD_BKOPS_PERF_IMPACTED 0x2 +#define EXT_CSD_BKOPS_CRITICAL 0x3 /* -* BKOPS modes -*/ + * BKOPS modes + */ #define EXT_CSD_MANUAL_BKOPS_MASK 0x01 #define EXT_CSD_AUTO_BKOPS_MASK 0x02 /* -* Command Queue -*/ + * 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 -*/ + * 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 -*/ + * Erase/trim/discard + */ #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 #define MMC_TRIM_ARG 0x00000001 @@ -429,4 +446,9 @@ c : clear by read #define MMC_SECURE_ARGS 0x80000000 #define MMC_TRIM_ARGS 0x00008001 -#endif /* LINUX_MMC_MMC_H */ +/* + * Vendor definitions and structs + */ +#define MMC_SANDISK_HEALTH_REPORT 0x96C9D71C + +#endif /* MMC_H */ diff --git a/bdk/storage/nx_emmc_bis.c b/bdk/storage/nx_emmc_bis.c new file mode 100644 index 0000000..28bdc6f --- /dev/null +++ b/bdk/storage/nx_emmc_bis.c @@ -0,0 +1,325 @@ +/* + * eMMC BIS driver for Nintendo Switch + * + * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2022 CTCaer + * + * 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 + +#include +#include +#include +#include +#include +#include + +#define BIS_CLUSTER_SECTORS 32 +#define BIS_CLUSTER_SIZE 16384 +#define BIS_CACHE_MAX_ENTRIES 16384 +#define BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY -1 + +typedef struct _cluster_cache_t +{ + u32 cluster_idx; // Index of the cluster in the partition. + bool dirty; // Has been modified without write-back flag. + u8 data[BIS_CLUSTER_SIZE]; // The cached cluster itself. Aligned to 8 bytes for DMA engine. +} cluster_cache_t; + +typedef struct _bis_cache_t +{ + bool full; + bool enabled; + u32 dirty_cnt; + u32 top_idx; + u8 dma_buff[BIS_CLUSTER_SIZE]; // Aligned to 8 bytes for DMA engine. + cluster_cache_t clusters[]; +} bis_cache_t; + +static u8 ks_crypt = 0; +static u8 ks_tweak = 0; +static u32 emu_offset = 0; +static emmc_part_t *system_part = NULL; +static u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR; +static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR; + +static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush) +{ + if (!system_part) + return 3; // Not ready. + + int res; + u8 tweak[SE_KEY_128_SIZE] __attribute__((aligned(4))); + u32 cluster = sector / BIS_CLUSTER_SECTORS; + u32 aligned_sector = cluster * BIS_CLUSTER_SECTORS; + u32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS; + u32 lookup_idx = cache_lookup_tbl[cluster]; + bool is_cached = lookup_idx != (u32)BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY; + + // Write to cached cluster. + if (is_cached) + { + if (buff) + memcpy(bis_cache->clusters[lookup_idx].data + sector_in_cluster * EMMC_BLOCKSIZE, buff, count * EMMC_BLOCKSIZE); + else + buff = bis_cache->clusters[lookup_idx].data; + if (!bis_cache->clusters[lookup_idx].dirty) + bis_cache->dirty_cnt++; + bis_cache->clusters[lookup_idx].dirty = true; + + if (!flush) + return 0; // Success. + + // Reset args to trigger a full cluster flush to emmc. + sector_in_cluster = 0; + sector = aligned_sector; + count = BIS_CLUSTER_SECTORS; + } + + // Encrypt cluster. + if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE)) + return 1; // Encryption error. + + // If not reading from cache, do a regular read and decrypt. + if (!emu_offset) + res = emmc_part_write(system_part, sector, count, bis_cache->dma_buff); + else + res = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff); + if (!res) + return 1; // R/W error. + + // Mark cache entry not dirty if write succeeds. + if (is_cached) + { + bis_cache->clusters[lookup_idx].dirty = false; + bis_cache->dirty_cnt--; + } + + return 0; // Success. +} + +static void _nx_emmc_bis_cluster_cache_init(bool enable_cache) +{ + u32 cache_lookup_tbl_size = (system_part->lba_end - system_part->lba_start + 1) / BIS_CLUSTER_SECTORS * sizeof(*cache_lookup_tbl); + + // Clear cache header. + memset(bis_cache, 0, sizeof(bis_cache_t)); + + // Clear cluster lookup table. + memset(cache_lookup_tbl, BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY, cache_lookup_tbl_size); + + // Enable cache. + bis_cache->enabled = enable_cache; +} + +static void _nx_emmc_bis_flush_cache() +{ + if (!bis_cache->enabled || !bis_cache->dirty_cnt) + return; + + for (u32 i = 0; i < bis_cache->top_idx && bis_cache->dirty_cnt; i++) + { + if (bis_cache->clusters[i].dirty) { + nx_emmc_bis_write_block(bis_cache->clusters[i].cluster_idx * BIS_CLUSTER_SECTORS, BIS_CLUSTER_SECTORS, NULL, true); + bis_cache->dirty_cnt--; + } + } + + _nx_emmc_bis_cluster_cache_init(true); +} + +static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff) +{ + static u32 prev_cluster = -1; + static u32 prev_sector = 0; + static u8 tweak[SE_KEY_128_SIZE] __attribute__((aligned(4))); + + int res; + bool regen_tweak = true; + u32 tweak_exp = 0; + u32 cluster = sector / BIS_CLUSTER_SECTORS; + u32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS; + + // If not reading from cache, do a regular read and decrypt. + if (!emu_offset) + res = emmc_part_read(system_part, sector, count, bis_cache->dma_buff); + else + res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff); + if (!res) + return 1; // R/W error. + + if (prev_cluster != cluster) // Sector in different cluster than last read. + { + prev_cluster = cluster; + tweak_exp = sector_in_cluster; + } + else if (sector > prev_sector) // Sector in same cluster and past last sector. + { + // Calculates the new tweak using the saved one, reducing expensive _gf256_mul_x_le calls. + tweak_exp = sector - prev_sector - 1; + regen_tweak = false; + } + else // Sector in same cluster and before or same as last sector. + tweak_exp = sector_in_cluster; + + // Maximum one cluster (1 XTS crypto block 16KB). + if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE)) + return 1; // R/W error. + + prev_sector = sector + count - 1; + + return 0; // Success. +} + +static int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff) +{ + int res; + u8 cache_tweak[SE_KEY_128_SIZE] __attribute__((aligned(4))); + u32 cluster = sector / BIS_CLUSTER_SECTORS; + u32 cluster_sector = cluster * BIS_CLUSTER_SECTORS; + u32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS; + u32 lookup_idx = cache_lookup_tbl[cluster]; + + // Read from cached cluster. + if (lookup_idx != (u32)BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY) + { + memcpy(buff, bis_cache->clusters[lookup_idx].data + sector_in_cluster * EMMC_BLOCKSIZE, count * EMMC_BLOCKSIZE); + + return 0; // Success. + } + + // Flush cache if full. + if (bis_cache->top_idx >= BIS_CACHE_MAX_ENTRIES) + _nx_emmc_bis_flush_cache(); + + // Set new cached cluster parameters. + bis_cache->clusters[bis_cache->top_idx].cluster_idx = cluster; + bis_cache->clusters[bis_cache->top_idx].dirty = false; + cache_lookup_tbl[cluster] = bis_cache->top_idx; + + // Read the whole cluster the sector resides in. + if (!emu_offset) + res = emmc_part_read(system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff); + else + res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff); + if (!res) + return 1; // R/W error. + + // Decrypt cluster. + if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE)) + return 1; // Decryption error. + + // Copy to cluster cache. + memcpy(bis_cache->clusters[bis_cache->top_idx].data, bis_cache->dma_buff, BIS_CLUSTER_SIZE); + memcpy(buff, bis_cache->dma_buff + sector_in_cluster * EMMC_BLOCKSIZE, count * EMMC_BLOCKSIZE); + + // Increment cache count. + bis_cache->top_idx++; + + return 0; // Success. +} + +static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) +{ + if (!system_part) + return 3; // Not ready. + + if (bis_cache->enabled) + return nx_emmc_bis_read_block_cached(sector, count, buff); + else + return nx_emmc_bis_read_block_normal(sector, count, buff); +} + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff) +{ + u8 *buf = (u8 *)buff; + u32 curr_sct = sector; + + while (count) + { + // Get sector index in cluster and use it as boundary check. + u32 cnt_max = (curr_sct % BIS_CLUSTER_SECTORS); + cnt_max = BIS_CLUSTER_SECTORS - cnt_max; + + u32 sct_cnt = MIN(count, cnt_max); // Only allow cluster sized access. + + if (nx_emmc_bis_read_block(curr_sct, sct_cnt, buf)) + return 0; + + count -= sct_cnt; + curr_sct += sct_cnt; + buf += sct_cnt * EMMC_BLOCKSIZE; + } + + return 1; +} + +int nx_emmc_bis_write(u32 sector, u32 count, void *buff) +{ + u8 *buf = (u8 *)buff; + u32 curr_sct = sector; + + while (count) + { + // Get sector index in cluster and use it as boundary check. + u32 cnt_max = (curr_sct % BIS_CLUSTER_SECTORS); + cnt_max = BIS_CLUSTER_SECTORS - cnt_max; + + u32 sct_cnt = MIN(count, cnt_max); // Only allow cluster sized access. + + if (nx_emmc_bis_write_block(curr_sct, sct_cnt, buf, false)) + return 0; + + count -= sct_cnt; + curr_sct += sct_cnt; + buf += sct_cnt * EMMC_BLOCKSIZE; + } + + return 1; +} + +void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset) +{ + system_part = part; + emu_offset = emummc_offset; + + _nx_emmc_bis_cluster_cache_init(enable_cache); + + if (!strcmp(part->name, "PRODINFO") || !strcmp(part->name, "PRODINFOF")) + { + ks_crypt = 0; + ks_tweak = 1; + } + else if (!strcmp(part->name, "SAFE")) + { + ks_crypt = 2; + ks_tweak = 3; + } + else if (!strcmp(part->name, "SYSTEM") || !strcmp(part->name, "USER")) + { + ks_crypt = 4; + ks_tweak = 5; + } + else + system_part = NULL; +} + +void nx_emmc_bis_end() +{ + _nx_emmc_bis_flush_cache(); + system_part = NULL; +} diff --git a/bdk/storage/nx_emmc_bis.h b/bdk/storage/nx_emmc_bis.h new file mode 100644 index 0000000..7cdacfc --- /dev/null +++ b/bdk/storage/nx_emmc_bis.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2019 shchmue + * Copyright (c) 2019 CTCaer + * + * 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_BIS_H +#define NX_EMMC_BIS_H + +#include +#include + +typedef struct _nx_emmc_cal0_spk_t +{ + u16 unk0; + u16 unk1; + u16 eq_bw_lop; + u16 eq_gn_lop; + u16 eq_fc_bp1; + u16 eq_bw_bp1; + u16 eq_gn_bp1; + u16 eq_fc_bp2; + u16 eq_bw_bp2; + u16 eq_gn_bp2; + u16 eq_fc_bp3; + u16 eq_bw_bp3; + u16 eq_gn_bp3; + u16 eq_fc_bp4; + u16 eq_bw_bp4; + u16 eq_gn_bp4; + u16 eq_fc_hip1; + u16 eq_gn_hip1; + u16 eq_fc_hip2; + u16 eq_bw_hip2; + u16 eq_gn_hip2; + u16 eq_pre_vol; + u16 eq_pst_vol; + u16 eq_ctrl2; + u16 eq_ctrl1; + u16 drc_agc_2; + u16 drc_agc_3; + u16 drc_agc_1; + u16 spk_vol; + u16 hp_vol; + u16 dac1_min_vol_spk; + u16 dac1_max_vol_spk; + u16 dac1_min_vol_hp; + u16 dac1_max_vol_hp; + u16 in1_in2; + u16 adc_vol_min; + u16 adc_vol_max; + u8 unk4[16]; +} __attribute__((packed)) nx_emmc_cal0_spk_t; + +typedef struct _nx_emmc_cal0_t +{ + u32 magic; // 'CAL0'. + u32 version; + u32 body_size; + u16 model; + u16 update_cnt; + u8 pad_crc16_0[0x10]; + u8 body_sha256[0x20]; + char cfg_id1[0x1E]; + u8 crc16_pad1[2]; + u8 rsvd0[0x20]; + u32 wlan_cc_num; + u32 wlan_cc_last; + char wlan_cc[128][3]; + u8 crc16_pad2[8]; + u8 wlan_mac[6]; + u8 crc16_pad3[2]; + u8 rsvd1[8]; + u8 bd_mac[6]; + u8 crc16_pad4[2]; + u8 rsvd2[8]; + u16 acc_offset[3]; + u8 crc16_pad5[2]; + u16 acc_scale[3]; + u8 crc16_pad6[2]; + u16 gyro_offset[3]; + u8 crc16_pad7[2]; + u16 gyro_scale[3]; + u8 crc16_pad8[2]; + char serial_number[0x18]; + u8 crc16_pad9[8]; + + u8 ecc_p256_device_key[0x30]; + u8 crc16_pad10[0x10]; + u8 ecc_p256_device_cert[0x180]; + u8 crc16_pad11[0x10]; + u8 ecc_p233_device_key[0x30]; + u8 crc16_pad12[0x10]; + u8 ecc_p33_device_cert[0x180]; + u8 crc16_pad13[0x10]; + u8 ecc_p256_ticket_key[0x30]; + u8 crc16_pad14[0x10]; + u8 ecc_p256_ticket_cert[0x180]; + u8 crc16_pad15[0x10]; + u8 ecc_p233_ticket_key[0x30]; + u8 crc16_pad16[0x10]; + u8 ecc_p33_ticket_cert[0x180]; + u8 crc16_pad17[0x10]; + u8 ssl_key[0x110]; + u8 crc16_pad18[0x10]; + u32 ssl_cert_size; + u8 crc16_pad19[0xC]; + u8 ssl_cert[0x800]; + u8 ssl_sha256[0x20]; + u8 random_number[0x1000]; + u8 random_number_sha256[0x20]; + u8 gc_key[0x110]; + u8 crc16_pad20[0x10]; + u8 gc_cert[0x400]; + u8 gc_cert_sha256[0x20]; + u8 rsa2048_eticket_key[0x220]; + u8 crc16_pad21[0x10]; + u8 rsa2048_eticket_cert[0x240]; + u8 crc16_pad22[0x10]; + + char battery_lot[0x1E]; + u8 crc16_pad23[2]; + nx_emmc_cal0_spk_t spk_cal; + u8 spk_cal_rsvd[0x800 - sizeof(nx_emmc_cal0_spk_t)]; + u8 crc16_pad24[0x10]; + u32 region_code; + u8 crc16_pad25[0xC]; + + u8 amiibo_key[0x50]; + u8 crc16_pad26[0x10]; + u8 amiibo_ecqv_cert[0x14]; + u8 crc16_pad27[0xC]; + u8 amiibo_ecqdsa_cert[0x70]; + u8 crc16_pad28[0x10]; + u8 amiibo_ecqv_bls_key[0x40]; + u8 crc16_pad29[0x10]; + u8 amiibo_ecqv_bls_cert[0x20]; + u8 crc16_pad30[0x10]; + u8 amiibo_ecqv_bls_root_cert[0x90]; + u8 crc16_pad31[0x10]; + + u32 product_model; // 1: Nx, 2: Copper, 4: Hoag. + u8 crc16_pad32[0xC]; + u8 home_menu_scheme_main_color[6]; + u8 crc16_pad33[0xA]; + u32 lcd_bl_brightness_mapping[3]; // Floats. Normally 100%, 0% and 2%. + u8 crc16_pad34[0x4]; + + u8 ext_ecc_b233_device_key[0x50]; + u8 crc16_pad35[0x10]; + u8 ext_ecc_p256_eticket_key[0x50]; + u8 crc16_pad36[0x10]; + u8 ext_ecc_b233_eticket_key[0x50]; + u8 crc16_pad37[0x10]; + u8 ext_ecc_rsa2048_eticket_key[0x240]; + u8 crc16_pad38[0x10]; + u8 ext_ssl_key[0x130]; + u8 crc16_pad39[0x10]; + u8 ext_gc_key[0x130]; + u8 crc16_pad40[0x10]; + + u32 lcd_vendor; + u8 crc16_pad41[0xC]; + + // 5.0.0 and up. + u8 ext_rsa2048_device_key[0x240]; + u8 crc16_pad42[0x10]; + u8 rsa2048_device_cert[0x240]; + u8 crc16_pad43[0x10]; + + u8 usbc_pwr_src_circuit_ver; + u8 crc16_pad44[0xF]; + + // 9.0.0 and up. + u32 home_menu_scheme_sub_color; + u8 crc16_pad45[0xC]; + u32 home_menu_scheme_bezel_color; + u8 crc16_pad46[0xC]; + u32 home_menu_scheme_main_color1; + u8 crc16_pad47[0xC]; + u32 home_menu_scheme_main_color2; + u8 crc16_pad48[0xC]; + u32 home_menu_scheme_main_color3; + u8 crc16_pad49[0xC]; + + u8 analog_stick_type_l; + u8 crc16_pad50[0xF]; + u8 analog_stick_param_l[0x12]; + u8 crc16_pad51[0xE]; + u8 analog_stick_cal_l[0x9]; + u8 crc16_pad52[0x7]; + u8 analog_stick_type_r; + u8 crc16_pad53[0xF]; + u8 analog_stick_param_r[0x12]; + u8 crc16_pad54[0xE]; + u8 analog_stick_cal_r[0x9]; + u8 crc16_pad55[0x7]; + u8 console_6axis_sensor_type; + u8 crc16_pad56[0xF]; + u8 console_6axis_sensor_hor_off[0x6]; + u8 crc16_pad57[0xA]; + + // 6.0.0 and up. + u8 battery_ver; + u8 crc16_pad58[0xF]; + + // 10.0.0 and up. + u8 touch_ic_vendor_id; + u8 crc16_pad59[0xF]; + + // 9.0.0 and up. + u32 color_model; + u8 crc16_pad60[0xC]; + + // 10.0.0 and up. + u8 console_6axis_sensor_mount_type; +} __attribute__((packed)) nx_emmc_cal0_t; + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff); +int nx_emmc_bis_write(u32 sector, u32 count, void *buff); +void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset); +void nx_emmc_bis_end(); + +#endif diff --git a/bdk/storage/ramdisk.c b/bdk/storage/ramdisk.c new file mode 100644 index 0000000..3a86ebf --- /dev/null +++ b/bdk/storage/ramdisk.c @@ -0,0 +1,86 @@ +/* + * Ramdisk driver for Tegra X1 + * + * Copyright (c) 2019-2021 CTCaer + * + * 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 "ramdisk.h" +#include +#include +#include +#include + +#include + +static u32 disk_size = 0; + +int ram_disk_init(void *ram_fs, u32 ramdisk_size) +{ + int res = 0; + disk_size = ramdisk_size; + FATFS *ram_fatfs = (FATFS *)ram_fs; + + // If ramdisk is not raw, format it. + if (ram_fs) + { + u8 *buf = malloc(0x400000); + + // Set ramdisk size. + ramdisk_size >>= 9; + disk_set_info(DRIVE_RAM, SET_SECTOR_COUNT, &ramdisk_size); + + // Unmount ramdisk. + f_mount(NULL, "ram:", 1); + + // Format as exFAT w/ 32KB cluster with no MBR. + res = f_mkfs("ram:", FM_EXFAT | FM_SFD, RAMDISK_CLUSTER_SZ, buf, 0x400000); + + // Mount ramdisk. + if (!res) + res = f_mount(ram_fatfs, "ram:", 1); + + free(buf); + } + + return res; +} + +int ram_disk_read(u32 sector, u32 sector_count, void *buf) +{ + u32 sector_off = RAM_DISK_ADDR + (sector << 9); + u32 bytes_count = sector_count << 9; + + if ((sector_off - RAM_DISK_ADDR) > disk_size) + return 1; + + memcpy(buf, (void *)sector_off, bytes_count); + + return 0; +} + +int ram_disk_write(u32 sector, u32 sector_count, const void *buf) +{ + u32 sector_off = RAM_DISK_ADDR + (sector << 9); + u32 bytes_count = sector_count << 9; + + if ((sector_off - RAM_DISK_ADDR) > disk_size) + return 1; + + memcpy((void *)sector_off, buf, bytes_count); + + return 0; +} diff --git a/bootloader/hos/fss.h b/bdk/storage/ramdisk.h similarity index 63% rename from bootloader/hos/fss.h rename to bdk/storage/ramdisk.h index 3f56d7c..67bc0a5 100644 --- a/bootloader/hos/fss.h +++ b/bdk/storage/ramdisk.h @@ -1,5 +1,7 @@ /* - * Copyright (c) 2019 CTCaer + * Ramdisk driver for Tegra X1 + * + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,21 +16,15 @@ * along with this program. If not, see . */ -#ifndef _FSS_H_ -#define _FSS_H_ +#ifndef RAM_DISK_H +#define RAM_DISK_H -#include "hos.h" +#include -typedef struct _fss0_sept_t -{ - u32 kb; - ini_sec_t *cfg_sec; - void *sept_primary; - void *sept_secondary; +#define RAMDISK_CLUSTER_SZ 32768 -} fss0_sept_t; +int ram_disk_init(void *ram_fs, u32 ramdisk_size); +int ram_disk_read(u32 sector, u32 sector_count, void *buf); +int ram_disk_write(u32 sector, u32 sector_count, const void *buf); -int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt); -int load_sept_from_ffs0(fss0_sept_t *sept_ctxt); - -#endif +#endif \ No newline at end of file diff --git a/bdk/storage/sd.c b/bdk/storage/sd.c new file mode 100644 index 0000000..3ad31fa --- /dev/null +++ b/bdk/storage/sd.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2023 CTCaer + * + * 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 +#include +#include +#include +#include + +#ifndef BDK_SDMMC_UHS_DDR200_SUPPORT +#define SD_DEFAULT_SPEED SD_UHS_SDR104 +#else +#define SD_DEFAULT_SPEED SD_UHS_DDR208 +#endif + +static bool sd_mounted = false; +static bool sd_init_done = false; +static bool insertion_event = false; +static u16 sd_errors[3] = { 0 }; // Init and Read/Write errors. +static u32 sd_mode = SD_DEFAULT_SPEED; + + +sdmmc_t sd_sdmmc; +sdmmc_storage_t sd_storage; +FATFS sd_fs; + +void sd_error_count_increment(u8 type) +{ + switch (type) + { + case SD_ERROR_INIT_FAIL: + sd_errors[0]++; + break; + case SD_ERROR_RW_FAIL: + sd_errors[1]++; + break; + case SD_ERROR_RW_RETRY: + sd_errors[2]++; + break; + } +} + +u16 *sd_get_error_count() +{ + return sd_errors; +} + +bool sd_get_card_removed() +{ + if (insertion_event && !sdmmc_get_sd_inserted()) + return true; + + return false; +} + +bool sd_get_card_initialized() +{ + return sd_init_done; +} + +bool sd_get_card_mounted() +{ + return sd_mounted; +} + +u32 sd_get_mode() +{ + return sd_mode; +} + +int sd_init_retry(bool power_cycle) +{ + u32 bus_width = SDMMC_BUS_WIDTH_4; +#ifndef BDK_SDMMC_UHS_DDR200_SUPPORT + u32 type = SDHCI_TIMING_UHS_SDR104; +#else + u32 type = SDHCI_TIMING_UHS_DDR200; +#endif + + // Power cycle SD card. + if (power_cycle) + { + sd_mode--; + sdmmc_storage_end(&sd_storage); + } + + // Get init parameters. + switch (sd_mode) + { + case SD_INIT_FAIL: // Reset to max. + return 0; + + case SD_1BIT_HS25: + bus_width = SDMMC_BUS_WIDTH_1; + type = SDHCI_TIMING_SD_HS25; + break; + + case SD_4BIT_HS25: + type = SDHCI_TIMING_SD_HS25; + break; + + case SD_UHS_SDR82: + type = SDHCI_TIMING_UHS_SDR82; + break; + + case SD_UHS_SDR104: + type = SDHCI_TIMING_UHS_SDR104; + break; + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + case SD_UHS_DDR208: + type = SDHCI_TIMING_UHS_DDR200; + break; +#endif + + default: + sd_mode = SD_DEFAULT_SPEED; + break; + } + + int res = sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type); + if (res) + { + sd_init_done = true; + insertion_event = true; + } + else + sd_init_done = false; + + return res; +} + +bool sd_initialize(bool power_cycle) +{ + if (power_cycle) + sdmmc_storage_end(&sd_storage); + + int res = !sd_init_retry(false); + + while (true) + { + if (!res) + return true; + else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted. + { + sd_mode = SD_DEFAULT_SPEED; + break; + } + else + { + sd_errors[SD_ERROR_INIT_FAIL]++; + + if (sd_mode == SD_INIT_FAIL) + break; + else + res = !sd_init_retry(true); + } + } + + sdmmc_storage_end(&sd_storage); + + return false; +} + +bool sd_mount() +{ + if (sd_init_done && sd_mounted) + return true; + + int res = 0; + + if (!sd_init_done) + res = !sd_initialize(false); + + if (res) + { + gfx_con.mute = false; + EPRINTF("Failed to init SD card."); + if (!sdmmc_get_sd_inserted()) + EPRINTF("Make sure that it is inserted."); + else + EPRINTF("SD Card Reader is not properly seated!"); + } + else + { + if (!sd_mounted) + res = f_mount(&sd_fs, "0:", 1); // Volume 0 is SD. + if (res == FR_OK) + { + sd_mounted = true; + return true; + } + else + { + gfx_con.mute = false; + EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); + } + } + + return false; +} + +static void _sd_deinit(bool deinit) +{ + if (deinit) + { + insertion_event = false; + if (sd_mode == SD_INIT_FAIL) + sd_mode = SD_DEFAULT_SPEED; + } + + if (sd_init_done) + { + if (sd_mounted) + f_mount(NULL, "0:", 1); // Volume 0 is SD. + + if (deinit) + { + sdmmc_storage_end(&sd_storage); + sd_init_done = false; + } + } + sd_mounted = false; +} + +void sd_unmount() { _sd_deinit(false); } +void sd_end() { _sd_deinit(true); } + +bool sd_is_gpt() +{ + return sd_fs.part_type; +} + +void *sd_file_read(const char *path, u32 *fsize) +{ + FIL fp; + if (!sd_get_card_mounted()) + return NULL; + + if (f_open(&fp, path, FA_READ) != FR_OK) + return NULL; + + u32 size = f_size(&fp); + if (fsize) + *fsize = size; + + void *buf = malloc(size); + + if (f_read(&fp, buf, size, NULL) != FR_OK) + { + free(buf); + f_close(&fp); + + return NULL; + } + + f_close(&fp); + + return buf; +} + +int sd_save_to_file(const void *buf, u32 size, const char *filename) +{ + FIL fp; + u32 res = 0; + if (!sd_get_card_mounted()) + return FR_DISK_ERR; + + res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE); + if (res) + { + EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); + return res; + } + + f_write(&fp, buf, size, NULL); + f_close(&fp); + + return 0; +} diff --git a/bdk/storage/sd.h b/bdk/storage/sd.h new file mode 100644 index 0000000..1153996 --- /dev/null +++ b/bdk/storage/sd.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2023 CTCaer + * + * 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 SD_H +#define SD_H + +#include +#include +#include + +#define SD_BLOCKSIZE SDMMC_DAT_BLOCKSIZE + +enum +{ + SD_INIT_FAIL = 0, + SD_1BIT_HS25 = 1, + SD_4BIT_HS25 = 2, + SD_UHS_SDR82 = 3, + SD_UHS_SDR104 = 4, +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + SD_UHS_DDR208 = 5 +#endif + +}; + +enum +{ + SD_ERROR_INIT_FAIL = 0, + SD_ERROR_RW_FAIL = 1, + SD_ERROR_RW_RETRY = 2 +}; + +extern sdmmc_t sd_sdmmc; +extern sdmmc_storage_t sd_storage; +extern FATFS sd_fs; + +void sd_error_count_increment(u8 type); +u16 *sd_get_error_count(); +bool sd_get_card_removed(); +bool sd_get_card_initialized(); +bool sd_get_card_mounted(); +u32 sd_get_mode(); +int sd_init_retry(bool power_cycle); +bool sd_initialize(bool power_cycle); +bool sd_mount(); +void sd_unmount(); +void sd_end(); +bool sd_is_gpt(); +void *sd_file_read(const char *path, u32 *fsize); +int sd_save_to_file(const void *buf, u32 size, const char *filename); + +#endif \ No newline at end of file diff --git a/bdk/storage/sd_def.h b/bdk/storage/sd_def.h new file mode 100644 index 0000000..898ac46 --- /dev/null +++ b/bdk/storage/sd_def.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (c) 2018-2025 CTCaer + * + * 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 SD_DEF_H +#define SD_DEF_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 2 */ +#define SD_ADDR_EXT 22 /* ac [5:0] 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 */ + /* class 11 */ +#define SD_READ_EXTR_SINGLE 48 /* adtc [31:0] R1 */ +#define SD_WRITE_EXTR_SINGLE 49 /* adtc [31:0] 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 /* adtc R1 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +/* Application secure commands */ +#define SD_APP_SECURE_READ_MULTI_BLOCK 18 /* adtc R1 */ +#define SD_APP_SECURE_WRITE_MULTI_BLOCK 25 /* adtc R1 */ +#define SD_APP_SECURE_WRITE_MKB 26 /* adtc R1 */ +#define SD_APP_SECURE_ERASE 38 /* adtc R1b */ +#define SD_APP_GET_MKB 43 /* adtc [31:0] See below R1 */ +#define SD_APP_GET_MID 44 /* adtc R1 */ +#define SD_APP_SET_CER_RN1 45 /* adtc R1 */ +#define SD_APP_GET_CER_RN2 46 /* adtc R1 */ +#define SD_APP_SET_CER_RES2 47 /* adtc R1 */ +#define SD_APP_GET_CER_RES1 48 /* adtc R1 */ +#define SD_APP_CHANGE_SECURE_AREA 49 /* adtc R1b */ + +/* OCR bit definitions */ +#define SD_OCR_VDD_18 (1U << 7) /* VDD voltage 1.8 */ +#define SD_VHS_27_36 (1U << 8) /* VDD voltage 2.7 ~ 3.6 */ +#define SD_OCR_VDD_32_33 (1U << 20) /* VDD voltage 3.2 ~ 3.3 */ +#define SD_OCR_S18R (1U << 24) /* 1.8V switching request */ +#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ +#define SD_OCR_XPC (1U << 28) /* SDXC power control */ +#define SD_OCR_CCS (1U << 30) /* Card Capacity Status */ +#define SD_OCR_BUSY (1U << 31) /* Card Power up 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) + */ + +/* + * SD_APP_GET_MKB argument format: + * + * [31:24] Number of blocks to read (512 block size) + * [23:16] MKB ID + * [15:0] Block offset + */ + +/* + * 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 */ +#define SD_SCR_BUS_WIDTH_1 (1U << 0) +#define SD_SCR_BUS_WIDTH_4 (1U << 2) + +/* + * SD bus widths + */ +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 + +/* + * SD bus speeds + */ +#define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 +#define UHS_SDR25_BUS_SPEED 1 +#define UHS_SDR50_BUS_SPEED 2 +#define UHS_SDR104_BUS_SPEED 3 +#define UHS_DDR50_BUS_SPEED 4 +#define HS400_BUS_SPEED 5 + +#define SD_MODE_HIGH_SPEED (1U << HIGH_SPEED_BUS_SPEED) +#define SD_MODE_UHS_SDR12 (1U << UHS_SDR12_BUS_SPEED) +#define SD_MODE_UHS_SDR25 (1U << UHS_SDR25_BUS_SPEED) +#define SD_MODE_UHS_SDR50 (1U << UHS_SDR50_BUS_SPEED) +#define SD_MODE_UHS_SDR104 (1U << UHS_SDR104_BUS_SPEED) +#define SD_MODE_UHS_DDR50 (1U << UHS_DDR50_BUS_SPEED) + + +#define SD_SET_DRIVER_TYPE_B 0 +#define SD_SET_DRIVER_TYPE_A 1 +#define SD_SET_DRIVER_TYPE_C 2 +#define SD_SET_DRIVER_TYPE_D 3 + +#define SD_DRIVER_TYPE_B (1U << SD_SET_DRIVER_TYPE_B) +#define SD_DRIVER_TYPE_A (1U << SD_SET_DRIVER_TYPE_A) +#define SD_DRIVER_TYPE_C (1U << SD_SET_DRIVER_TYPE_C) +#define SD_DRIVER_TYPE_D (1U << SD_SET_DRIVER_TYPE_D) + +#define SD_SET_POWER_LIMIT_0_72 0 +#define SD_SET_POWER_LIMIT_1_44 1 +#define SD_SET_POWER_LIMIT_2_16 2 +#define SD_SET_POWER_LIMIT_2_88 3 + +#define SD_MAX_POWER_0_72 (1U << SD_SET_POWER_LIMIT_0_72) +#define SD_MAX_POWER_1_44 (1U << SD_SET_POWER_LIMIT_1_44) +#define SD_MAX_POWER_2_16 (1U << SD_SET_POWER_LIMIT_2_16) +#define SD_MAX_POWER_2_88 (1U << SD_SET_POWER_LIMIT_2_88) + +#define SD_SET_CMD_SYSTEM_DEF 0 +#define SD_SET_CMD_SYSTEM_MEC 1 +#define SD_SET_CMD_SYSTEM_OTP 3 +#define SD_SET_CMD_SYSTEM_OSD 3 +#define SD_SET_CMD_SYSTEM_VND 14 +#define UHS_DDR200_BUS_SPEED SD_SET_CMD_SYSTEM_VND + +#define SD_CMD_SYSTEM_DEF (1U << SD_SET_CMD_SYSTEM_DEF) +#define SD_CMD_SYSTEM_MEC (1U << SD_SET_CMD_SYSTEM_MEC) +#define SD_CMD_SYSTEM_OTP (1U << SD_SET_CMD_SYSTEM_OTP) +#define SD_CMD_SYSTEM_OSD (1U << SD_SET_CMD_SYSTEM_OSD) +#define SD_CMD_SYSTEM_VND (1U << SD_SET_CMD_SYSTEM_VND) +#define SD_MODE_UHS_DDR200 SD_CMD_SYSTEM_VND + +/* + * SD_SWITCH mode + */ +#define SD_SWITCH_CHECK 0 +#define SD_SWITCH_SET 1 + +/* + * SD_SWITCH function groups + */ +#define SD_SWITCH_GRP_ACCESS 0 +#define SD_SWITCH_GRP_CMDSYS 1 +#define SD_SWITCH_GRP_DRVSTR 2 +#define SD_SWITCH_GRP_PWRLIM 3 + +/* + * SD_SWITCH access modes + */ +#define SD_SWITCH_ACCESS_DEF 0 +#define SD_SWITCH_ACCESS_HS 1 + +#endif /* SD_DEF_H */ diff --git a/bdk/storage/sdmmc.c b/bdk/storage/sdmmc.c new file mode 100644 index 0000000..747c28d --- /dev/null +++ b/bdk/storage/sdmmc.c @@ -0,0 +1,1972 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +//#define SDMMC_DEBUG_PRINT_SD_REGS +#ifdef SDMMC_DEBUG_PRINT_SD_REGS +#define DREGPRINTF(...) gfx_printf(__VA_ARGS__) +#else +#define DREGPRINTF(...) +#endif + +#ifdef BDK_SDMMC_EXTRA_PRINT +#define ERROR_EXTRA_PRINTING +#endif + +u32 sd_power_cycle_time_start; + +static inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size) +{ + start %= 128; + + 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_card_status(u32 res) +{ + //Error mask: + //!WARN: R1_SWITCH_ERROR is reserved on SD. The card isn't supposed to use it. + if (res & + (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)) + return 0; + + // No errors. + return 1; +} + +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, NULL, NULL)) + return 0; + + sdmmc_get_cached_rsp(storage->sdmmc, resp, SDMMC_RSP_TYPE_1); + if (mask) + *resp &= ~mask; + + if (_sdmmc_storage_check_card_status(*resp)) + if (expected_state == R1_SKIP_STATE_CHECK || 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 cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); + + return sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL); +} + +static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) + return 0; + + sdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_cid, 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, R1_SKIP_STATE_CHECK); +} + +static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage) +{ + 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, NULL, NULL)) + return 0; + + sdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_csd, 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); +} + +int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_62_CMD, arg, SDMMC_RSP_TYPE_1, 1); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) + return 0; + + u32 resp; + sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1); + + resp = -1; + u32 timeout = get_tmr_ms() + 1500; + while (true) + { + _sdmmc_storage_get_status(storage, &resp, 0); + + if (resp == (R1_READY_FOR_DATA | R1_STATE(R1_STATE_TRAN))) + break; + + if (get_tmr_ms() > timeout) + break; + msleep(10); + } + + return _sdmmc_storage_check_card_status(resp); +} + +int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf) +{ + // Request health report. + if (!sdmmc_storage_execute_vendor_cmd(storage, MMC_SANDISK_HEALTH_REPORT)) + return 2; + + u32 tmp = 0; + sdmmc_cmd_t cmdbuf; + sdmmc_req_t reqbuf; + + sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_63_CMD, 0, SDMMC_RSP_TYPE_1, 0); // similar to CMD17 with arg 0x0. + + reqbuf.buf = buf; + reqbuf.num_sectors = 1; + reqbuf.blksize = SDMMC_DAT_BLOCKSIZE; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + u32 blkcnt_out; + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, &blkcnt_out)) + { + sdmmc_stop_transmission(storage->sdmmc, &tmp); + _sdmmc_storage_get_status(storage, &tmp, 0); + + return 0; + } + + return 1; +} + +static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write) +{ + u32 tmp = 0; + sdmmc_cmd_t cmdbuf; + sdmmc_req_t reqbuf; + + // If SDSC convert block address to byte address. + if (!storage->has_sector_access) + sector <<= 9; + + sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0); + + reqbuf.buf = buf; + reqbuf.num_sectors = num_sectors; + reqbuf.blksize = SDMMC_DAT_BLOCKSIZE; + reqbuf.is_write = is_write; + reqbuf.is_multi_block = 1; + reqbuf.is_auto_stop_trn = 1; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out)) + { + sdmmc_stop_transmission(storage->sdmmc, &tmp); + _sdmmc_storage_get_status(storage, &tmp, 0); + + return 0; + } + + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + if (!_sdmmc_storage_check_card_status(tmp)) + return 0; + + return 1; +} + +int sdmmc_storage_end(sdmmc_storage_t *storage) +{ + DPRINTF("[SDMMC%d] end\n", storage->sdmmc->id); + + if (!_sdmmc_storage_go_idle_state(storage)) + return 0; + + sdmmc_end(storage->sdmmc); + + storage->initialized = 0; + + return 1; +} + +static int _sdmmc_storage_handle_io_error(sdmmc_storage_t *storage, bool first_reinit) +{ + int res = 0; + + if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4) + { + if (storage->sdmmc->id == SDMMC_1) + { + sd_error_count_increment(SD_ERROR_RW_FAIL); + + if (first_reinit) + res = sd_initialize(true); + else + { + res = sd_init_retry(true); + if (!res) + sd_error_count_increment(SD_ERROR_INIT_FAIL); + } + } + else if (storage->sdmmc->id == SDMMC_4) + { + emmc_error_count_increment(EMMC_ERROR_RW_FAIL); + + if (first_reinit) + res = emmc_initialize(true); + else + { + res = emmc_init_retry(true); + if (!res) + emmc_error_count_increment(EMMC_ERROR_INIT_FAIL); + } + } + } + + return res; +} + +static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) +{ + u8 *bbuf = (u8 *)buf; + u32 sct_off = sector; + u32 sct_total = num_sectors; + bool first_reinit = true; + + // Exit if not initialized. + if (!storage->initialized) + return 0; + + // Check if out of bounds. + if (((u64)sector + num_sectors) > storage->sec_cnt) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: Out of bounds!", storage->sdmmc->id + 1); +#endif + return 0; + } + + while (sct_total) + { + u32 blkcnt = 0; + // Retry 5 times if failed. + u32 retries = 5; + do + { +reinit_try: + if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sct_off, MIN(sct_total, 0xFFFF), bbuf, is_write)) + goto out; + else + retries--; + + sd_error_count_increment(SD_ERROR_RW_RETRY); + + msleep(50); + } while (retries); + + // Disk IO failure! Reinit SD/EMMC to a lower speed. + if (_sdmmc_storage_handle_io_error(storage, first_reinit)) + { + // Reset values for a retry. + blkcnt = 0; + retries = 3; + first_reinit = false; + + bbuf = (u8 *)buf; + sct_off = sector; + sct_total = num_sectors; + + goto reinit_try; + } + + // Failed. + return 0; + +out: + sct_off += blkcnt; + sct_total -= blkcnt; + bbuf += SDMMC_DAT_BLOCKSIZE * blkcnt; + } + + return 1; +} + +int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + // Ensure that SDMMC has access to buffer and it's SDMMC DMA aligned. + if (mc_client_has_access(buf) && !((u32)buf % 8)) + return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0); + + if (num_sectors > (SDMMC_UP_BUF_SZ / SDMMC_DAT_BLOCKSIZE)) + return 0; + + u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER; + if (_sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 0)) + { + memcpy(buf, tmp_buf, SDMMC_DAT_BLOCKSIZE * num_sectors); + return 1; + } + return 0; +} + +int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + // Ensure that SDMMC has access to buffer and it's SDMMC DMA aligned. + if (mc_client_has_access(buf) && !((u32)buf % 8)) + return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1); + + if (num_sectors > (SDMMC_UP_BUF_SZ / SDMMC_DAT_BLOCKSIZE)) + return 0; + + u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER; + memcpy(tmp_buf, buf, SDMMC_DAT_BLOCKSIZE * num_sectors); + return _sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 1); +} + +/* +* MMC specific functions. +*/ + +static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u32 power) +{ + sdmmc_cmd_t cmdbuf; + + u32 arg = 0; + switch (power) + { + case SDMMC_POWER_1_8: + arg = MMC_CARD_CCS | MMC_CARD_VDD_18; + break; + + case SDMMC_POWER_3_3: + arg = MMC_CARD_CCS | MMC_CARD_VDD_27_34; + break; + + default: + return 0; + } + + sdmmc_init_cmd(&cmdbuf, MMC_SEND_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) + return 0; + + return sdmmc_get_cached_rsp(storage->sdmmc, pout, SDMMC_RSP_TYPE_3); +} + +static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) +{ + u32 timeout = get_tmr_ms() + 1500; + + while (true) + { + u32 cond = 0; + if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) + break; + + // Check if power up is done. + if (cond & MMC_CARD_BUSY) + { + // Check if card is high capacity. + if (cond & MMC_CARD_CCS) + storage->has_sector_access = 1; + + return 1; + } + if (get_tmr_ms() > timeout) + break; + + usleep(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, R1_SKIP_STATE_CHECK); +} + +static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) +{ + u32 *raw_cid = (u32 *)&(storage->raw_cid); + + switch (storage->csd.mmca_vsn) + { + case 0: /* MMC v1.0 - v1.2 */ + case 1: /* MMC v1.4 */ + storage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8); + storage->cid.manfid = unstuff_bits(raw_cid, 104, 24); + storage->cid.hwrev = unstuff_bits(raw_cid, 44, 4); + storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4); + storage->cid.serial = unstuff_bits(raw_cid, 16, 24); + break; + + case 2: /* MMC v2.0 - v2.2 */ + case 3: /* MMC v3.1 - v3.3 */ + case 4: /* MMC v4 */ + storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); + storage->cid.oemid = unstuff_bits(raw_cid, 104, 8); + storage->cid.prv = unstuff_bits(raw_cid, 48, 8); + storage->cid.serial = unstuff_bits(raw_cid, 16, 32); + break; + + default: + break; + } + + storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); + storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); + storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); + storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); + storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); + storage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8); + + storage->cid.month = unstuff_bits(raw_cid, 12, 4); + storage->cid.year = unstuff_bits(raw_cid, 8, 4) + 1997; + if (storage->ext_csd.rev >= 5) + { + if (storage->cid.year < 2010) + storage->cid.year += 16; + } +} + +static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) +{ + u32 *raw_csd = (u32 *)storage->raw_csd; + + storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); + storage->csd.structure = unstuff_bits(raw_csd, 126, 2); + storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); + storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); + storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); + storage->sec_cnt = storage->csd.capacity; +} + +static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) +{ + storage->ext_csd.rev = buf[EXT_CSD_REV]; + storage->ext_csd.ext_struct = buf[EXT_CSD_STRUCTURE]; + storage->ext_csd.card_type = buf[EXT_CSD_CARD_TYPE]; + storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION]; + storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT]; + storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT]; + //storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; + //storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; + //storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; + + storage->ext_csd.pre_eol_info = buf[EXT_CSD_PRE_EOL_INFO]; + storage->ext_csd.dev_life_est_a = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; + storage->ext_csd.dev_life_est_b = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; + + storage->ext_csd.cache_size = buf[EXT_CSD_CACHE_SIZE] | + (buf[EXT_CSD_CACHE_SIZE + 1] << 8) | + (buf[EXT_CSD_CACHE_SIZE + 2] << 16) | + (buf[EXT_CSD_CACHE_SIZE + 3] << 24); + + storage->ext_csd.max_enh_mult = (buf[EXT_CSD_MAX_ENH_SIZE_MULT] | + (buf[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8) | + (buf[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16)) * + buf[EXT_CSD_HC_WP_GRP_SIZE] * buf[EXT_CSD_HC_ERASE_GRP_SIZE]; + + storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; +} + +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 = SDMMC_DAT_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + _mmc_storage_parse_ext_csd(storage, buf); + + return _sdmmc_storage_check_card_status(tmp); +} + +int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 address, u32 len, void *buf) +{ + if (!(storage->scr.cmds & BIT(2))) + return 0; + + sdmmc_cmd_t cmdbuf; + + u32 arg = fno << 27 | page << 18 | address << 9 | (len - 1); + + sdmmc_init_cmd(&cmdbuf, SD_READ_EXTR_SINGLE, arg, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = SDMMC_DAT_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + + return _sdmmc_storage_check_card_status(tmp); +} + +static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg) +{ + return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, R1_SKIP_STATE_CHECK); +} + +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, bool check_sts_before_clk_setup) +{ + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS))) + return 0; + + if (check_sts_before_clk_setup && !_sdmmc_storage_check_status(storage)) + return 0; + + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52)) + return 0; + + DPRINTF("[MMC] switched to HS52\n"); + storage->csd.busspeed = 52; + + if (check_sts_before_clk_setup || _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, SDHCI_TIMING_MMC_HS200)) + return 0; + + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200)) + return 0; + + DPRINTF("[MMC] switched to HS200\n"); + storage->csd.busspeed = 200; + + 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_save_tap_value(storage->sdmmc); + + if (!_mmc_storage_enable_HS(storage, false)) + 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, SDHCI_TIMING_MMC_HS400)) + return 0; + + DPRINTF("[MMC] switched to HS400\n"); + storage->csd.busspeed = 400; + + return _sdmmc_storage_check_status(storage); +} + +static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type) +{ + if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8) + goto hs52_mode; + + // HS400 needs 8-bit bus width mode. + if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && + card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400) + return _mmc_storage_enable_HS400(storage); + + // Try HS200 if HS400 and 4-bit width bus or just HS200. + 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 == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)) + return _mmc_storage_enable_HS200(storage); + +hs52_mode: + if (card_type & EXT_CSD_CARD_TYPE_HS_52) + return _mmc_storage_enable_HS(storage, true); + + return 1; +} + +/* +static int _mmc_storage_enable_auto_bkops(sdmmc_storage_t *storage) +{ + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_AUTO_BKOPS_MASK))) + return 0; + + return _sdmmc_storage_check_status(storage); +} +*/ + +int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) +{ + memset(storage, 0, sizeof(sdmmc_storage_t)); + storage->sdmmc = sdmmc; + storage->rca = 2; // Set default device address. This could be a config item. + + DPRINTF("[MMC]-[init: bus: %d, type: %d]\n", bus_width, type); + + if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID)) + return 0; + DPRINTF("[MMC] after init\n"); + + // Wait 1ms + 74 cycles. + usleep(1000 + (74 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); + + 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)) + 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)) + return 0; + DPRINTF("[MMC] got csd\n"); + _mmc_storage_parse_csd(storage); + + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26)) + 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, EMMC_BLOCKSIZE)) + return 0; + DPRINTF("[MMC] set blocklen to EMMC_BLOCKSIZE\n"); + + // Check system specification version, only version 4.0 and later support below features. + if (storage->csd.mmca_vsn < CSD_SPEC_VER_4) + goto done; + + if (!_mmc_storage_switch_buswidth(storage, bus_width)) + return 0; + DPRINTF("[MMC] switched buswidth\n"); + + if (!mmc_storage_get_ext_csd(storage, (u8 *)SDMMC_UPPER_BUFFER)) + return 0; + DPRINTF("[MMC] got ext_csd\n"); + + _mmc_storage_parse_cid(storage); // This needs to be after csd and ext_csd. + +/* + if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_AUTO_BKOPS_MASK)) + { + _mmc_storage_enable_auto_bkops(storage); + DPRINTF("[MMC] BKOPS enabled\n"); + } +*/ + + if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) + return 0; + DPRINTF("[MMC] successfully switched to HS mode\n"); + + sdmmc_card_clock_powersave(storage->sdmmc, SDMMC_POWER_SAVE_ENABLE); + +done: + storage->initialized = 1; + + 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 *cmdbuf, 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, cmdbuf, 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); +} + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS +void _sd_storage_debug_print_cid(const u32 *raw_cid) +{ + gfx_printf("Card Identification\n"); + + gfx_printf("MID: %02X\n", unstuff_bits(raw_cid, 120, 8)); + gfx_printf("OID %04X\n", unstuff_bits(raw_cid, 104, 16)); + gfx_printf("PNM: %02X %02X %02X %02X %02X\n", + unstuff_bits(raw_cid, 96, 8), unstuff_bits(raw_cid, 88, 8), + unstuff_bits(raw_cid, 80, 8), unstuff_bits(raw_cid, 72, 8), + unstuff_bits(raw_cid, 64, 8)); + gfx_printf("PRV: %02X\n", unstuff_bits(raw_cid, 56, 8)); + gfx_printf("PSN: %08X\n", unstuff_bits(raw_cid, 24, 32)); + gfx_printf("MDT: %03X\n", unstuff_bits(raw_cid, 8, 12)); + gfx_printf("--RSVD-- %X\n", unstuff_bits(raw_cid, 20, 4)); +} + +void _sd_storage_debug_print_csd(const u32 *raw_csd) +{ + gfx_printf("\n"); + + gfx_printf("\nCSD_STRUCTURE: %X\n", unstuff_bits(raw_csd, 126, 2)); + gfx_printf("TAAC: %02X\n", unstuff_bits(raw_csd, 112, 8)); + gfx_printf("NSAC: %02X\n", unstuff_bits(raw_csd, 104, 8)); + gfx_printf("TRAN_SPEED: %02X\n", unstuff_bits(raw_csd, 96, 8)); + gfx_printf("CCC: %03X\n", unstuff_bits(raw_csd, 84, 12)); + gfx_printf("READ_BL_LEN: %X\n", unstuff_bits(raw_csd, 80, 4)); + gfx_printf("READ_BL_PARTIAL: %X\n", unstuff_bits(raw_csd, 79, 1)); + gfx_printf("WRITE_BLK_MISALIGN: %X\n", unstuff_bits(raw_csd, 78, 1)); + gfx_printf("READ_BLK_MISALIGN: %X\n", unstuff_bits(raw_csd, 77, 1)); + gfx_printf("DSR_IMP: %X\n", unstuff_bits(raw_csd, 76, 1)); + gfx_printf("C_SIZE: %06X\n", unstuff_bits(raw_csd, 48, 28)); // CSD 3 (SDUC). + + gfx_printf("ERASE_BLK_LEN: %X\n", unstuff_bits(raw_csd, 46, 1)); + gfx_printf("SECTOR_SIZE: %02X\n", unstuff_bits(raw_csd, 39, 6)); + gfx_printf("WP_GRP_SIZE: %02X\n", unstuff_bits(raw_csd, 32, 6)); + gfx_printf("WP_GRP_ENABLE: %X\n", unstuff_bits(raw_csd, 31, 1)); + + gfx_printf("R2W_FACTOR: %X\n", unstuff_bits(raw_csd, 26, 3)); + gfx_printf("WRITE_BL_LEN: %X\n", unstuff_bits(raw_csd, 22, 4)); + gfx_printf("WRITE_BL_PARTIAL: %X\n", unstuff_bits(raw_csd, 21, 1)); + + gfx_printf("FILE_FORMAT_GRP: %X\n", unstuff_bits(raw_csd, 15, 1)); + gfx_printf("COPY: %X\n", unstuff_bits(raw_csd, 14, 1)); + gfx_printf("PERM_WRITE_PROTECT: %X\n", unstuff_bits(raw_csd, 13, 1)); + gfx_printf("TMP_WRITE_PROTECT: %X\n", unstuff_bits(raw_csd, 12, 1)); + gfx_printf("FILE_FORMAT: %X\n", unstuff_bits(raw_csd, 10, 2)); + + gfx_printf("--RSVD-- %02X %X %X %02X %X\n", + unstuff_bits(raw_csd, 120, 6), + unstuff_bits(raw_csd, 47, 1), unstuff_bits(raw_csd, 29, 2), + unstuff_bits(raw_csd, 16, 5), unstuff_bits(raw_csd, 8, 2)); +} + +void _sd_storage_debug_print_scr(const u32 *raw_scr) +{ + u32 resp[4]; + memcpy(&resp[2], raw_scr, 8); + + gfx_printf("\n"); + + gfx_printf("SCR_STRUCTURE: %X\n", unstuff_bits(resp, 60, 4)); + gfx_printf("SD_SPEC: %X\n", unstuff_bits(resp, 56, 4)); + gfx_printf("DATA_STAT_AFTER_ERASE: %X\n", unstuff_bits(resp, 55, 1)); + gfx_printf("SD_SECURITY: %X\n", unstuff_bits(resp, 52, 3)); + gfx_printf("SD_BUS widths: %X\n", unstuff_bits(resp, 48, 4)); + gfx_printf("SD_SPEC3: %X\n", unstuff_bits(resp, 47, 1)); + gfx_printf("EX_SECURITY: %X\n", unstuff_bits(resp, 43, 4)); + gfx_printf("SD_SPEC4: %X\n", unstuff_bits(resp, 42, 1)); + gfx_printf("SD_SPECX: %X\n", unstuff_bits(resp, 38, 4)); + gfx_printf("CMD_SUPPORT: %X\n", unstuff_bits(resp, 32, 4)); + gfx_printf("VENDOR: %08X\n", unstuff_bits(resp, 0, 32)); + gfx_printf("--RSVD-- %X\n", unstuff_bits(resp, 36, 2)); +} + +void _sd_storage_debug_print_ssr(const u8 *raw_ssr) +{ + u32 raw_ssr0[4]; // 511:384. + u32 raw_ssr1[4]; // 383:256. + u32 raw_ssr2[4]; // 255:128. + u32 raw_ssr3[4]; // 127:0. + memcpy(raw_ssr0, &raw_ssr[0], 16); + memcpy(raw_ssr1, &raw_ssr[16], 16); + memcpy(raw_ssr2, &raw_ssr[32], 16); + memcpy(raw_ssr3, &raw_ssr[48], 16); + + gfx_printf("\nSD Status:\n"); + + gfx_printf("DAT_BUS_WIDTH: %X\n", unstuff_bits(raw_ssr0, 510, 2)); + gfx_printf("SECURED_MODE: %X\n", unstuff_bits(raw_ssr0, 509, 1)); + gfx_printf("SECURITY_FUNCTIONS: %02X\n", unstuff_bits(raw_ssr0, 502, 6)); + gfx_printf("SD_CARD_TYPE: %04X\n", unstuff_bits(raw_ssr0, 480, 16)); + gfx_printf("SZ_OF_PROTECTED_AREA: %08X\n", unstuff_bits(raw_ssr0, 448, 32)); + gfx_printf("SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 440, 8)); + gfx_printf("PERFORMANCE_MOVE: %02X\n", unstuff_bits(raw_ssr0, 432, 8)); + gfx_printf("AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 428, 4)); + gfx_printf("ERAZE_SIZE: %04X\n", unstuff_bits(raw_ssr0, 408, 16)); + gfx_printf("ERASE_TIMEOUT: %02X\n", unstuff_bits(raw_ssr0, 402, 6)); + gfx_printf("ERASE_OFFSET: %X\n", unstuff_bits(raw_ssr0, 400, 2)); + gfx_printf("UHS_SPEED_GRADE: %X\n", unstuff_bits(raw_ssr0, 396, 4)); + gfx_printf("UHS_AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 392, 4)); + gfx_printf("VIDEO_SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 384, 8)); + + gfx_printf("VSC_AU_SIZE: %03X\n", unstuff_bits(raw_ssr1, 368, 10)); + gfx_printf("SUS_ADDR: %06X\n", unstuff_bits(raw_ssr1, 346, 22)); + gfx_printf("APP_PERF_CLASS: %X\n", unstuff_bits(raw_ssr1, 336, 4)); + gfx_printf("PERFORMANCE_ENHANCE: %02X\n", unstuff_bits(raw_ssr1, 328, 8)); + gfx_printf("DISCARD_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 313, 1)); + gfx_printf("FULE_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 312, 1)); + + gfx_printf("--RSVD-- %02X %X %02X %02X %04X\n", + unstuff_bits(raw_ssr0, 496, 6), unstuff_bits(raw_ssr0, 424, 4), + unstuff_bits(raw_ssr1, 378, 6), unstuff_bits(raw_ssr1, 340, 6), + unstuff_bits(raw_ssr1, 314, 14)); + + gfx_printf("VENDOR_1: %06X %08X\n", + unstuff_bits(raw_ssr1, 288, 24), unstuff_bits(raw_ssr1, 256, 32)); + + gfx_printf("VENDOR_2: %08X %08X %08X %08X\n", + unstuff_bits(raw_ssr2, 224, 32), unstuff_bits(raw_ssr2, 192, 32), + unstuff_bits(raw_ssr2, 160, 32), unstuff_bits(raw_ssr2, 128, 32)); + gfx_printf("VENDOR_3: %08X %08X %08X %08X\n", + unstuff_bits(raw_ssr3, 96 - 0, 32), unstuff_bits(raw_ssr3, 64, 32), + unstuff_bits(raw_ssr3, 32 - 0, 32), unstuff_bits(raw_ssr3, 0, 32)); +} +#endif + +static int _sd_storage_send_if_cond(sdmmc_storage_t *storage, bool *is_sdsc) +{ + sdmmc_cmd_t cmdbuf; + u16 vhd_pattern = SD_VHS_27_36 | 0xAA; + sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, vhd_pattern, SDMMC_RSP_TYPE_5, 0); + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) + { + // The SD Card is version 1.X (SDSC) if there is no response. + if (storage->sdmmc->error_sts == SDHCI_ERR_INT_CMD_TIMEOUT) + { + *is_sdsc = 1; + return 1; + } + + return 0; + } + + // For Card version >= 2.0, parse results. + u32 resp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_5); + + // Check if VHD was accepted and pattern was properly returned. + if ((resp & 0xFFF) == vhd_pattern) + return 1; + + return 0; +} + +static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, bool is_sdsc, int bus_uhs_support) +{ + sdmmc_cmd_t cmdbuf; + // Support for Current > 150mA. + u32 arg = !is_sdsc ? SD_OCR_XPC : 0; + // Support for handling block-addressed SDHC cards. + arg |= !is_sdsc ? SD_OCR_CCS : 0; + // Support for 1.8V signaling. + arg |= (bus_uhs_support && !is_sdsc) ? SD_OCR_S18R : 0; + // Support for 3.3V power supply (VDD1). + arg |= SD_OCR_VDD_32_33; + + sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); + + if (!_sd_storage_execute_app_cmd(storage, R1_SKIP_STATE_CHECK, is_sdsc ? R1_ILLEGAL_COMMAND : 0, &cmdbuf, NULL, NULL)) + return 0; + + return sdmmc_get_cached_rsp(storage->sdmmc, cond, SDMMC_RSP_TYPE_3); +} + +static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int bus_uhs_support) +{ + u32 timeout = get_tmr_ms() + 1500; + + while (true) + { + u32 cond = 0; + if (!_sd_storage_get_op_cond_once(storage, &cond, is_sdsc, bus_uhs_support)) + break; + + // Check if power up is done. + if (cond & SD_OCR_BUSY) + { + DPRINTF("[SD] op cond: %08X, lv: %d\n", cond, bus_uhs_support); + + // Check if card is high capacity. + if (cond & SD_OCR_CCS) + storage->has_sector_access = 1; + + // Check if card supports 1.8V signaling. + if (cond & SD_ROCR_S18A && bus_uhs_support && !storage->is_low_voltage) + { + // Switch to 1.8V signaling. + if (_sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) + { + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_UHS_SDR12)) + return 0; + + if (!sdmmc_enable_low_voltage(storage->sdmmc)) + return 0; + + storage->is_low_voltage = 1; + + DPRINTF("-> switched to low voltage\n"); + } + } + else + { + DPRINTF("[SD] no low voltage support\n"); + } + + return 1; + } + if (get_tmr_ms() > timeout) + break; + msleep(10); // Needs to be at least 10ms for some SD Cards + } + + 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_ms() + 1500; + + while (true) + { + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) + break; + + u32 resp = 0; + if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_4)) + break; + + if (resp >> 16) + { + storage->rca = resp >> 16; + return 1; + } + + if (get_tmr_ms() > timeout) + break; + usleep(1000); + } + + return 0; +} + +static void _sd_storage_parse_scr(sdmmc_storage_t *storage) +{ + // unstuff_bits can parse only 4 u32 + u32 resp[4]; + + memcpy(&resp[2], storage->raw_scr, 8); + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS + _sd_storage_debug_print_scr((u32 *)storage->raw_scr); +#endif + + storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); + storage->scr.bus_widths = unstuff_bits(resp, 48, 4); + + // If v2.0 is supported, check if Physical Layer Spec v3.0 is supported. + if (storage->scr.sda_vsn == SCR_SPEC_VER_2) + storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); + if (storage->scr.sda_spec3) + { + u8 sda_spec4 = unstuff_bits(resp, 42, 1); + if (sda_spec4) + storage->scr.cmds = unstuff_bits(resp, 32, 4); + else + storage->scr.cmds = unstuff_bits(resp, 32, 2); + } +} + +int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *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_stop_trn = 0; + + if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + //Prepare buffer for unstuff_bits + for (u32 i = 0; i < 8; i+=4) + { + storage->raw_scr[i + 3] = buf[i]; + storage->raw_scr[i + 2] = buf[i + 1]; + storage->raw_scr[i + 1] = buf[i + 2]; + storage->raw_scr[i] = buf[i + 3]; + } + _sd_storage_parse_scr(storage); + + return _sdmmc_storage_check_card_status(tmp); +} + +static 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 = SDMMC_CMD_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + return _sdmmc_storage_check_card_status(tmp); +} + +static int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, u32 arg) +{ + sdmmc_cmd_t cmdbuf; + u32 switchcmd = mode << 31 | 0x00FFFFFF; + switchcmd &= ~(0xF << (group * 4)); + switchcmd |= arg << (group * 4); + sdmmc_init_cmd(&cmdbuf, SD_SWITCH, switchcmd, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = SDMMC_CMD_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + return _sdmmc_storage_check_card_status(tmp); +} + +static void _sd_storage_set_power_limit(sdmmc_storage_t *storage, u16 power_limit, u8 *buf) +{ + u32 pwr = SD_SET_POWER_LIMIT_0_72; + + // If UHS-I only, anything above 1.44W defaults to 1.44W. + /* + if (power_limit & SD_MAX_POWER_2_88) + pwr = SD_SET_POWER_LIMIT_2_88; + else if (power_limit & SD_MAX_POWER_2_16) + pwr = SD_SET_POWER_LIMIT_2_16; + */ + if (power_limit & SD_MAX_POWER_1_44) + pwr = SD_SET_POWER_LIMIT_1_44; + + _sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_PWRLIM, pwr); + + switch ((buf[15] >> 4) & 0x0F) + { + /* + case SD_SET_POWER_LIMIT_2_88: + DPRINTF("[SD] power limit raised to 2880 mW\n"); + break; + + case SD_SET_POWER_LIMIT_2_16: + DPRINTF("[SD] power limit raised to 2160 mW\n"); + break; + */ + case SD_SET_POWER_LIMIT_1_44: + DPRINTF("[SD] power limit raised to 1440 mW\n"); + break; + + default: + case SD_SET_POWER_LIMIT_0_72: + DPRINTF("[SD] power limit defaulted to 720 mW\n"); + break; + } +} + +int _sd_storage_set_driver_type(sdmmc_storage_t *storage, u32 driver, u8 *buf) +{ + if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, SD_SWITCH_GRP_DRVSTR, driver)) + return 0; + + u32 driver_out = buf[15] & 0xF; + if (driver_out != driver) + return 0; + DPRINTF("[SD] supports Driver Strength %d\n", driver); + + if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_DRVSTR, driver)) + return 0; + + if (driver_out != (buf[15] & 0xF)) + return 0; + DPRINTF("[SD] card accepted Driver Strength %d\n", driver); + + sdmmc_setup_drv_type(storage->sdmmc, driver); + + return 1; +} + +/* + * SD Card DDR200 (DDR208) support + * + * DLL Tuning (a) or Tuning Window (b) procedure: + * 1. Check that Vendor Specific Command System is supported. + * Used as Enable DDR200 Bus. + * 2. Enable DDR200 bus mode via setting 14 to Group 2 via CMD6. + * Access Mode group is left to default 0 (SDR12). + * 3. Setup clock to 200 or 208 MHz. + * 4a. Set host to DDR200/HS400 bus mode that enables DLL syncing. + * Actual implementation supported by all DDR200 cards. + * -- + * 4b. Set host to DDR50 bus mode that supports such high clocks. + * Execute Manual Tuning. + * Limited to non-Sandisk cards. + * + * On Tegra SoCs, that can be done with DDR50 host mode. + * That's because HS400 4-bit or HS400 generally, is not supported on SD SDMMC. + * And also, tuning can't be done automatically on any DDR mode. + * So it needs to be done manually and selected tap will be applied from the + * biggest sampling window. + * That allows DDR200 support on every DDR200 SD card, other than the original + * maker of DDR200, Sandisk. + * + * On the original implementation of DDR200 from Sandisk, a DLL mechanism, + * like the one in eMMC HS400 is mandatory. + * So the card can start data signals whenever it wants, and the host should + * synchronize to the first DAT signal edge change. + * Every single other vendor that implemented that, always starts data transfers + * aligned to clock. That basically makes DDR200 in such SD cards a SDR104 but + * sampled on both edges. So effectively, it's an in-spec signal with DDR50, + * only that is clocked at 200MHz, instead of 50MHz. + * So the extra needed thing is using a tuning window, which is absent from the + * original implementation, since DDL syncing does not use that. + * + * On DLL tuning method expected cards, the tuning window is tiny. + * So check against a minimum of 8 taps window, to disallow DDR200. + */ +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT +static int _sd_storage_enable_DDR200(sdmmc_storage_t *storage, u8 *buf) +{ + u32 cmd_system = UHS_DDR200_BUS_SPEED; + if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, SD_SWITCH_GRP_CMDSYS, cmd_system)) + return 0; + + u32 system_out = (buf[16] >> 4) & 0xF; + if (system_out != cmd_system) + return 0; + DPRINTF("[SD] supports DDR200 mode\n"); + + u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1]; + DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000); + storage->max_power = total_pwr_consumption; + + if (total_pwr_consumption <= 800) + { + if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_CMDSYS, cmd_system)) + return 0; + + if (system_out != ((buf[16] >> 4) & 0xF)) + return 0; + DPRINTF("[SD] card accepted DDR200\n"); + + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_UHS_DDR200)) + return 0; + DPRINTF("[SD] after setup clock DDR200\n"); + + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_UHS_DDR200, MMC_SEND_TUNING_BLOCK)) + return 0; + DPRINTF("[SD] after tuning DDR200\n"); + + return _sdmmc_storage_check_status(storage); + } + + DPRINTF("[SD] card max power over limit\n"); + return 0; +} +#endif + +static int _sd_storage_set_card_bus_speed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) +{ + if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, SD_SWITCH_GRP_ACCESS, hs_type)) + return 0; + + u32 type_out = buf[16] & 0xF; + if (type_out != hs_type) + return 0; + DPRINTF("[SD] supports selected (U)HS mode %d\n", buf[16] & 0xF); + + u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1]; + DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000); + storage->max_power = total_pwr_consumption; + + if (total_pwr_consumption <= 800) + { + if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_ACCESS, hs_type)) + return 0; + + if (type_out != (buf[16] & 0xF)) + return 0; + + return 1; + } + + DPRINTF("[SD] card max power over limit\n"); + return 0; +} + +int sd_storage_get_fmodes(sdmmc_storage_t *storage, u8 *buf, sd_func_modes_t *fmodes) +{ + if (!buf) + buf = (u8 *)SDMMC_UPPER_BUFFER; + + if (!_sd_storage_switch_get(storage, buf)) + return 0; + + fmodes->access_mode = buf[13] | (buf[12] << 8); + fmodes->cmd_system = buf[11] | (buf[10] << 8); + fmodes->driver_strength = buf[9] | (buf[8] << 8); + fmodes->power_limit = buf[7] | (buf[6] << 8); + + return 1; +} + +static int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) +{ + sd_func_modes_t fmodes; + + if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) + return 0; + + if (!sd_storage_get_fmodes(storage, buf, &fmodes)) + return 0; + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + DPRINTF("[SD] access: %02X, power: %02X, cmd: %02X\n", fmodes.access_mode, fmodes.power_limit, fmodes.cmd_system); +#else + DPRINTF("[SD] access: %02X, power: %02X\n", fmodes.access_mode, fmodes.power_limit); +#endif + + u32 hs_type = 0; + switch (type) + { +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + case SDHCI_TIMING_UHS_DDR200: + // Fall through if DDR200 is not supported. + if (fmodes.cmd_system & SD_MODE_UHS_DDR200) + { + DPRINTF("[SD] setting bus speed to DDR200\n"); + storage->csd.busspeed = 200; + _sd_storage_set_power_limit(storage, fmodes.power_limit, buf); + return _sd_storage_enable_DDR200(storage, buf); + } +#endif + + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + // Fall through if not supported. + if (fmodes.access_mode & SD_MODE_UHS_SDR104) + { + type = SDHCI_TIMING_UHS_SDR104; + hs_type = UHS_SDR104_BUS_SPEED; + DPRINTF("[SD] setting bus speed to SDR104\n"); + switch (type) + { + case SDHCI_TIMING_UHS_SDR104: + storage->csd.busspeed = 104; + break; + case SDHCI_TIMING_UHS_SDR82: + storage->csd.busspeed = 82; + break; + } + break; + } + + case SDHCI_TIMING_UHS_SDR50: + if (fmodes.access_mode & SD_MODE_UHS_SDR50) + { + type = SDHCI_TIMING_UHS_SDR50; + hs_type = UHS_SDR50_BUS_SPEED; + DPRINTF("[SD] setting bus speed to SDR50\n"); + storage->csd.busspeed = 50; + break; + } +/* + case SDHCI_TIMING_UHS_DDR50: + if (fmodes.access_mode & SD_MODE_UHS_DDR50) + { + type = SDHCI_TIMING_UHS_DDR50; + hs_type = UHS_DDR50_BUS_SPEED; + DPRINTF("[SD] setting bus speed to DDR50\n"); + storage->csd.busspeed = 50; + break; + } +*/ + case SDHCI_TIMING_UHS_SDR25: + if (fmodes.access_mode & SD_MODE_UHS_SDR25) + { + type = SDHCI_TIMING_UHS_SDR25; + hs_type = UHS_SDR25_BUS_SPEED; + DPRINTF("[SD] setting bus speed to SDR25\n"); + storage->csd.busspeed = 25; + break; + } + + default: + DPRINTF("[SD] bus speed defaulted to SDR12\n"); + storage->csd.busspeed = 12; + return 1; + } + + // Try to raise the power limit to let the card perform better. + if (hs_type != UHS_SDR25_BUS_SPEED) // Not applicable for SDR12/SDR25. + _sd_storage_set_power_limit(storage, fmodes.power_limit, buf); + + // Setup and set selected card and bus speed. + if (!_sd_storage_set_card_bus_speed(storage, hs_type, buf)) + return 0; + DPRINTF("[SD] card accepted UHS\n"); + + if (!sdmmc_setup_clock(storage->sdmmc, type)) + return 0; + DPRINTF("[SD] after setup clock\n"); + + if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) + return 0; + DPRINTF("[SD] after tuning\n"); + + return _sdmmc_storage_check_status(storage); +} + +static int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) +{ + sd_func_modes_t fmodes; + + if (!sd_storage_get_fmodes(storage, buf, &fmodes)) + return 0; + + DPRINTF("[SD] access: %02X, power: %02X\n", fmodes.access_mode, fmodes.power_limit); + + if (!(fmodes.access_mode & SD_MODE_HIGH_SPEED)) + return 1; + + if (!_sd_storage_set_card_bus_speed(storage, HIGH_SPEED_BUS_SPEED, buf)) + return 0; + + if (!_sdmmc_storage_check_status(storage)) + return 0; + + return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25); +} + +u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage) +{ + u32 au_size = storage->ssr.uhs_au_size; + + if (!au_size) + au_size = storage->ssr.au_size; + + if (au_size <= 10) + { + u32 shift = au_size; + au_size = shift ? 8 : 0; + au_size <<= shift; + } + else + { + switch (au_size) + { + case 11: + au_size = 12288; + break; + case 12: + au_size = 16384; + break; + case 13: + au_size = 24576; + break; + case 14: + au_size = 32768; + break; + case 15: + au_size = 65536; + break; + } + } + + return au_size; +} + +static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) +{ + // unstuff_bits supports only 4 u32 so break into 2 x u32x4 groups. + u32 raw_ssr1[4]; // 511:384. + u32 raw_ssr2[4]; // 383:256. + + memcpy(raw_ssr1, &storage->raw_ssr[0], 16); + memcpy(raw_ssr2, &storage->raw_ssr[16], 16); + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS + _sd_storage_debug_print_ssr(storage->raw_ssr); +#endif + + storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510, 2) & SD_BUS_WIDTH_4) ? 4 : 1; + storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448, 32); + + u32 speed_class = unstuff_bits(raw_ssr1, 440, 8); + switch(speed_class) + { + case 0: + case 1: + case 2: + case 3: + storage->ssr.speed_class = speed_class << 1; + break; + + case 4: + storage->ssr.speed_class = 10; + break; + + default: + storage->ssr.speed_class = speed_class; + break; + } + storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396, 4); + storage->ssr.video_class = unstuff_bits(raw_ssr1, 384, 8); + storage->ssr.app_class = unstuff_bits(raw_ssr2, 336, 4); + + storage->ssr.au_size = unstuff_bits(raw_ssr1, 428, 4); + storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392, 4); + + storage->ssr.perf_enhance = unstuff_bits(raw_ssr2, 328, 8); +} + +int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf) +{ + // Check status reg for support. + storage->ser.cache = (storage->ssr.perf_enhance >> 2) & BIT(0); + storage->ser.cmdq = (storage->ssr.perf_enhance >> 3) & 0x1F; + + if (!sd_storage_get_ext_reg(storage, fno, page, offset, 512, buf)) + { + storage->ser.cache_ext = 0; + storage->ser.cmdq_ext = 0; + + return 0; + } + + storage->ser.cache_ext = buf[4] & BIT(0); + storage->ser.cmdq_ext = buf[6] & 0x1F; + + return 1; +} + +static void _sd_storage_parse_ext_reg(sdmmc_storage_t *storage, u8 *buf, u16 *addr_next) +{ + u16 addr = *addr_next; + + // Address to the next extension. + *addr_next = (buf[addr + 41] << 8) | buf[addr + 40]; + + u16 sfc = (buf[addr + 1] << 8) | buf[addr]; + + u32 reg_sets = buf[addr + 42]; + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS + for (u32 i = 0; i < reg_sets; i++) + { + u32 reg_set_addr; + memcpy(®_set_addr, &buf[addr + 44 + 4 * i], 4); + u16 off = reg_set_addr & 0x1FF; + u8 page = reg_set_addr >> 9 & 0xFF; + u8 fno = reg_set_addr >> 18 & 0xFF; + gfx_printf("Addr: %04X sfc:%02X - fno:%02X, page:%02X, off:%04X\n", addr, sfc, fno, page, off); + } +#endif + + // Parse Performance Enhance. + if (sfc == 2 && reg_sets == 1) + { + u32 reg_set0_addr; + memcpy(®_set0_addr, &buf[addr + 44], 4); + u16 off = reg_set0_addr & 0x1FF; + u8 page = reg_set0_addr >> 9 & 0xFF; + u8 fno = reg_set0_addr >> 18 & 0xFF; + + if (sd_storage_parse_perf_enhance(storage, fno, page, off, buf)) + storage->ser.valid = 1; + } +} + +void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf) +{ + DREGPRINTF("SD Extension Registers:\n\n"); + + if (!(storage->scr.cmds & BIT(2))) + { + DREGPRINTF("Not Supported!\n"); + return; + } + + if (!sd_storage_get_ext_reg(storage, 0, 0, 0, 512, buf)) + { + DREGPRINTF("Failed to get general info!\n"); + return; + } + + u16 size = (buf[3] << 8) | buf[2]; + u16 addr_next = 16; + u32 num_ext = buf[4]; + for (u32 i = 0; i < num_ext && addr_next < size; i++) + _sd_storage_parse_ext_reg(storage, buf, &addr_next); +} + +int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) +{ + sdmmc_cmd_t cmdbuf; + sdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = SDMMC_CMD_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!(storage->csd.cmdclass & CCC_APP_SPEC)) + { + DPRINTF("[SD] ssr: Not supported\n"); + return 0; + } + + if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + + // Convert buffer to LE. + for (u32 i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4) + { + storage->raw_ssr[i + 3] = buf[i]; + storage->raw_ssr[i + 2] = buf[i + 1]; + storage->raw_ssr[i + 1] = buf[i + 2]; + storage->raw_ssr[i] = buf[i + 3]; + } + + _sd_storage_parse_ssr(storage); + + return _sdmmc_storage_check_card_status(tmp); +} + +static void _sd_storage_parse_cid(sdmmc_storage_t *storage) +{ + u32 *raw_cid = (u32 *)&(storage->raw_cid); + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS + _sd_storage_debug_print_cid(raw_cid); +#endif + + storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); + storage->cid.oemid = unstuff_bits(raw_cid, 104, 16); + storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); + storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); + storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); + storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); + storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); + storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4); + storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4); + storage->cid.serial = unstuff_bits(raw_cid, 24, 32); + storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000; + storage->cid.month = unstuff_bits(raw_cid, 8, 4); +} + +static void _sd_storage_parse_csd(sdmmc_storage_t *storage) +{ + u32 *raw_csd = (u32 *)&(storage->raw_csd); + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS + _sd_storage_debug_print_csd(raw_csd); +#endif + + storage->csd.structure = unstuff_bits(raw_csd, 126, 2); + storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); + storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); + storage->csd.write_protect = unstuff_bits(raw_csd, 12, 2); + switch(storage->csd.structure) + { + case 0: + storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); + storage->csd.capacity <<= unstuff_bits(raw_csd, 80, 4) - 9; // Convert native block size to LBA SDMMC_DAT_BLOCKSIZE. + break; + + case 1: + storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22)); + storage->csd.capacity = storage->csd.c_size << 10; + storage->csd.read_blkbits = 9; + break; + + default: + DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); + break; + } + + storage->sec_cnt = storage->csd.capacity; +} + +static bool _sdmmc_storage_get_bus_uhs_support(u32 bus_width, u32 type) +{ + switch (type) + { + case SDHCI_TIMING_UHS_SDR12: + case SDHCI_TIMING_UHS_SDR25: + case SDHCI_TIMING_UHS_SDR50: + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + case SDHCI_TIMING_UHS_DDR50: + case SDHCI_TIMING_UHS_DDR200: + if (bus_width == SDMMC_BUS_WIDTH_4) + return true; + default: + return false; + } +} + +void sdmmc_storage_init_wait_sd() +{ + // T210/T210B01 WAR: Wait exactly 239ms for IO and Controller power to discharge. + u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; + if (sd_poweroff_time < 239) + msleep(239 - sd_poweroff_time); +} + +int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) +{ + u32 tmp = 0; + bool is_sdsc = 0; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; + bool bus_uhs_support = _sdmmc_storage_get_bus_uhs_support(bus_width, type); + + DPRINTF("[SD]-[init: bus: %d, type: %d]\n", bus_width, type); + + // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. + sdmmc_storage_init_wait_sd(); + + memset(storage, 0, sizeof(sdmmc_storage_t)); + storage->sdmmc = sdmmc; + + if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID)) + return 0; + DPRINTF("[SD] after init\n"); + + // Wait 1ms + 74 cycles. + usleep(1000 + (74 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); + + if (!_sdmmc_storage_go_idle_state(storage)) + return 0; + DPRINTF("[SD] went to idle state\n"); + + if (!_sd_storage_send_if_cond(storage, &is_sdsc)) + return 0; + DPRINTF("[SD] after send if cond\n"); + + if (!_sd_storage_get_op_cond(storage, is_sdsc, bus_uhs_support)) + return 0; + DPRINTF("[SD] got op cond\n"); + + if (!_sdmmc_storage_get_cid(storage)) + return 0; + DPRINTF("[SD] got cid\n"); + _sd_storage_parse_cid(storage); + + if (!_sd_storage_get_rca(storage)) + return 0; + DPRINTF("[SD] got rca (= %04X)\n", storage->rca); + + if (!_sdmmc_storage_get_csd(storage)) + return 0; + DPRINTF("[SD] got csd\n"); + _sd_storage_parse_csd(storage); + + if (!storage->is_low_voltage) + { + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12)) + return 0; + DPRINTF("[SD] after setup default clock\n"); + } + + if (!_sdmmc_storage_select_card(storage)) + return 0; + DPRINTF("[SD] card selected\n"); + + if (!_sdmmc_storage_set_blocklen(storage, SD_BLOCKSIZE)) + return 0; + DPRINTF("[SD] set blocklen to SD_BLOCKSIZE\n"); + + // Disconnect Card Detect resistor from DAT3. + 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"); + + if (!sd_storage_get_scr(storage, buf)) + return 0; + DPRINTF("[SD] got scr\n"); + + // If card supports a wider bus and if it's not SD Version 1.0 switch bus width. + if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & BIT(SD_BUS_WIDTH_4)) && storage->scr.sda_vsn) + { + if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) + return 0; + + sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); + DPRINTF("[SD] switched to wide bus width\n"); + } + else + { + bus_width = SDMMC_BUS_WIDTH_1; + DPRINTF("[SD] SD does not support wide bus width\n"); + } + + if (storage->is_low_voltage) + { + if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) + return 0; + DPRINTF("[SD] enabled UHS\n"); + } + else if (type != SDHCI_TIMING_SD_DS12 && storage->scr.sda_vsn) // Not default speed and not SD Version 1.0. + { + if (!_sd_storage_enable_hs_high_volt(storage, buf)) + return 0; + + DPRINTF("[SD] enabled HS\n"); + switch (bus_width) + { + case SDMMC_BUS_WIDTH_4: + storage->csd.busspeed = 25; + break; + + case SDMMC_BUS_WIDTH_1: + storage->csd.busspeed = 6; + break; + } + } + + // Parse additional card info from sd status. + if (sd_storage_get_ssr(storage, buf)) + { + DPRINTF("[SD] got sd status\n"); + } + + sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); + + storage->initialized = 1; + + 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, MMC_VENDOR_60_CMD, 0, SDMMC_RSP_TYPE_1, 1); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = SDMMC_CMD_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 1; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) + { + sdmmc_stop_transmission(storage->sdmmc, &resp); + return 0; + } + + if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1)) + return 0; + if (!_sdmmc_storage_check_card_status(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, SDHCI_TIMING_MMC_HS100)) + return 0; + DPRINTF("[GC] after init\n"); + + // Wait 1ms + 10 clock cycles. + usleep(1000 + (10 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); + + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS100, MMC_SEND_TUNING_BLOCK_HS200)) + return 0; + DPRINTF("[GC] after tuning\n"); + + sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); + + storage->initialized = 1; + + return 1; +} diff --git a/bdk/storage/sdmmc.h b/bdk/storage/sdmmc.h new file mode 100644 index 0000000..6da130a --- /dev/null +++ b/bdk/storage/sdmmc.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include +#include + +#define SDMMC_CMD_BLOCKSIZE 64 +#define SDMMC_DAT_BLOCKSIZE 512 + +extern u32 sd_power_cycle_time_start; + +typedef enum _sdmmc_type +{ + MMC_SD = 0, + MMC_EMMC = 1, + + EMMC_GPP = 0, + EMMC_BOOT0 = 1, + EMMC_BOOT1 = 2, + EMMC_RPMB = 3 +} sdmmc_type; + +typedef struct _mmc_sandisk_advanced_report_t +{ + u32 power_inits; + + u32 max_erase_cycles_sys; + u32 max_erase_cycles_slc; + u32 max_erase_cycles_mlc; + + u32 min_erase_cycles_sys; + u32 min_erase_cycles_slc; + u32 min_erase_cycles_mlc; + + u32 max_erase_cycles_euda; + u32 min_erase_cycles_euda; + u32 avg_erase_cycles_euda; + u32 read_reclaim_cnt_euda; + u32 bad_blocks_euda; + + u32 pre_eol_euda; + u32 pre_eol_sys; + u32 pre_eol_mlc; + + u32 uncorrectable_ecc; + + u32 temperature_now; + u32 temperature_min; + u32 temperature_max; + + u32 health_pct_euda; + u32 health_pct_sys; + u32 health_pct_mlc; + + u32 unk0; + u32 unk1; + u32 unk2; + + u32 reserved[78]; +} mmc_sandisk_advanced_report_t; + +typedef struct _mmc_sandisk_report_t +{ + u32 avg_erase_cycles_sys; + u32 avg_erase_cycles_slc; + u32 avg_erase_cycles_mlc; + + u32 read_reclaim_cnt_sys; + u32 read_reclaim_cnt_slc; + u32 read_reclaim_cnt_mlc; + + u32 bad_blocks_factory; + u32 bad_blocks_sys; + u32 bad_blocks_slc; + u32 bad_blocks_mlc; + + u32 fw_updates_cnt; + + u8 fw_update_date[12]; + u8 fw_update_time[8]; + + u32 total_writes_100mb; + u32 vdrops; + u32 vdroops; + + u32 vdrops_failed_data_rec; + u32 vdrops_data_rec_ops; + + u32 total_writes_slc_100mb; + u32 total_writes_mlc_100mb; + + u32 mlc_bigfile_mode_limit_exceeded; + u32 avg_erase_cycles_hybrid; + + mmc_sandisk_advanced_report_t advanced; +} mmc_sandisk_report_t; + +typedef struct _mmc_cid +{ + u32 manfid; + u8 prod_name[8]; + u32 serial; + u16 oemid; + u16 year; + u8 prv; + u8 hwrev; + u8 fwrev; + u8 month; +} mmc_cid_t; + +typedef struct _mmc_csd +{ + u8 structure; + u8 mmca_vsn; + u16 cmdclass; + u32 c_size; + u32 r2w_factor; + u32 read_blkbits; + u32 capacity; + u8 write_protect; + u16 busspeed; +} mmc_csd_t; + +typedef struct _mmc_ext_csd +{ + //u8 bkops; /* background support bit */ + //u8 bkops_en; /* manual bkops enable bit */ + //u8 bkops_status; /* 246 */ + u8 rev; + u8 ext_struct; /* 194 */ + u8 card_type; /* 196 */ + u8 pre_eol_info; + u8 dev_life_est_a; + u8 dev_life_est_b; + u8 boot_mult; + u8 rpmb_mult; + u16 dev_version; + u32 cache_size; + u32 max_enh_mult; +} mmc_ext_csd_t; + +typedef struct _sd_scr +{ + u8 sda_vsn; + u8 sda_spec3; + u8 bus_widths; + u8 cmds; +} sd_scr_t; + +typedef struct _sd_ssr +{ + u8 bus_width; + u8 speed_class; + u8 uhs_grade; + u8 video_class; + u8 app_class; + u8 au_size; + u8 uhs_au_size; + u8 perf_enhance; + u32 protected_size; +} sd_ssr_t; + +typedef struct _sd_ext_reg_t +{ + u8 cmdq; + u8 cmdq_ext; + u8 cache; + u8 cache_ext; + int valid; +} sd_ext_reg_t; + +/*! SDMMC storage context. */ +typedef struct _sdmmc_storage_t +{ + sdmmc_t *sdmmc; + int initialized; + int is_low_voltage; + int has_sector_access; + u32 rca; + u32 sec_cnt; + u32 partition; + u32 max_power; + u8 raw_cid[0x10]; + u8 raw_csd[0x10]; + u8 raw_scr[8]; + u8 raw_ssr[0x40]; + mmc_cid_t cid; + mmc_csd_t csd; + mmc_ext_csd_t ext_csd; + sd_scr_t scr; + sd_ssr_t ssr; + sd_ext_reg_t ser; +} sdmmc_storage_t; + +typedef struct _sd_func_modes_t +{ + u16 access_mode; + u16 cmd_system; + u16 driver_strength; + u16 power_limit; +} sd_func_modes_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 bus_width, u32 type); +int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +void sdmmc_storage_init_wait_sd(); +int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type); +int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); + +int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg); +int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf); + +int mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf); + +int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u32 len, void *buf); +int sd_storage_get_fmodes(sdmmc_storage_t *storage, u8 *buf, sd_func_modes_t *functions); +int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf); +int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf); +u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage); + +void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf); +int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf); + +#endif diff --git a/bdk/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c new file mode 100644 index 0000000..b6e3c8e --- /dev/null +++ b/bdk/storage/sdmmc_driver.c @@ -0,0 +1,1545 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +//#define ERROR_EXTRA_PRINTING +#define DPRINTF(...) + +#ifdef BDK_SDMMC_EXTRA_PRINT +#define ERROR_EXTRA_PRINTING +#endif + +/*! SCMMC controller base addresses. */ +static const u16 _sdmmc_base_offsets[4] = { 0x0, 0x200, 0x400, 0x600 }; + +int sdmmc_get_io_power(sdmmc_t *sdmmc) +{ + u32 p = sdmmc->regs->pwrcon; + if (!(p & SDHCI_POWER_ON)) + return SDMMC_POWER_OFF; + if (p & SDHCI_POWER_180) + return SDMMC_POWER_1_8; + if (p & SDHCI_POWER_330) + return SDMMC_POWER_3_3; + return -1; +} + +static int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 power) +{ + switch (power) + { + case SDMMC_POWER_OFF: + sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON; + break; + + case SDMMC_POWER_1_8: + sdmmc->regs->pwrcon = SDHCI_POWER_180; + break; + + case SDMMC_POWER_3_3: + sdmmc->regs->pwrcon = SDHCI_POWER_330; + break; + + default: + return 0; + } + + if (power != SDMMC_POWER_OFF) + sdmmc->regs->pwrcon |= SDHCI_POWER_ON; + + return 1; +} + +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc) +{ + u32 h = sdmmc->regs->hostctl; + if (h & SDHCI_CTRL_8BITBUS) // eMMC only (or UHS-II). + return SDMMC_BUS_WIDTH_8; + if (h & SDHCI_CTRL_4BITBUS) // SD only. + return SDMMC_BUS_WIDTH_4; + return SDMMC_BUS_WIDTH_1; +} + +void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) +{ + u32 host_control = sdmmc->regs->hostctl & ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS); + + if (bus_width == SDMMC_BUS_WIDTH_1) + sdmmc->regs->hostctl = host_control; + else if (bus_width == SDMMC_BUS_WIDTH_4) + sdmmc->regs->hostctl = host_control | SDHCI_CTRL_4BITBUS; // SD only. + else if (bus_width == SDMMC_BUS_WIDTH_8) + sdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS; // eMMC only (or UHS-II). +} + +void sdmmc_save_tap_value(sdmmc_t *sdmmc) +{ + sdmmc->venclkctl_tap = (sdmmc->regs->venclkctl & 0xFF0000) >> 16; + sdmmc->venclkctl_set = 1; +} + +static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type) +{ + static const u32 dqs_trim_val = 40; // 24 if HS533/HS667. + static const u8 tap_values_t210[4] = { 4, 0, 3, 0 }; + + u32 tap_val = 0; + + if (type == SDHCI_TIMING_MMC_HS400) + sdmmc->regs->vencapover = (sdmmc->regs->vencapover & 0xFFFFC0FF) | (dqs_trim_val << 8); + + sdmmc->regs->ventunctl0 &= ~SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + + if (type == SDHCI_TIMING_MMC_HS400) + { + if (!sdmmc->venclkctl_set) + return 0; + + tap_val = sdmmc->venclkctl_tap; + } + else + tap_val = sdmmc->t210b01 ? 11 : tap_values_t210[sdmmc->id]; + + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16); + + return 1; +} + +static void _sdmmc_commit_changes(sdmmc_t *sdmmc) +{ + (void)sdmmc->regs->clkcon; +} + +static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) +{ + _sdmmc_commit_changes(sdmmc); + switch (sdmmc->id) + { + case SDMMC_1: // 33 Ohm 2X Driver. + if (power == SDMMC_POWER_OFF) + break; + u32 sdmmc1_pad_cfg = APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xF8080FFF; + if (sdmmc->t210b01) + sdmmc1_pad_cfg |= (0x808 << 12); // Up: 8, Dn: 8. For 33 ohm. + else if (power == SDMMC_POWER_1_8) + sdmmc1_pad_cfg |= (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm. + else if (power == SDMMC_POWER_3_3) + sdmmc1_pad_cfg |= (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg; + (void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write. + break; + + case SDMMC_2: + if (sdmmc->t210b01) + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xF8080FFF) | 0xA0A000; + else + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; // PU:16, PD:16. + (void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); + break; + + case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16, B01: PU:10, PD:10. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | + (sdmmc->t210b01 ? 0xA28 : 0x1040); + (void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write. + break; + } +} + +static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) +{ + bool should_enable_sd_clock = false; + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) + { + should_enable_sd_clock = true; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + } + + // Enable E_INPUT (SD) or Disable E_PWRD (eMMC) power. + if (!(sdmmc->regs->sdmemcmppadctl & SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD)) + { + sdmmc->regs->sdmemcmppadctl |= SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD; + _sdmmc_commit_changes(sdmmc); + usleep(1); + } + + // Enable auto calibration and start auto configuration. + sdmmc->regs->autocalcfg |= SDHCI_TEGRA_AUTOCAL_ENABLE | SDHCI_TEGRA_AUTOCAL_START; + _sdmmc_commit_changes(sdmmc); + usleep(2); + + u32 timeout = get_tmr_ms() + 10; + while (sdmmc->regs->autocalsts & SDHCI_TEGRA_AUTOCAL_ACTIVE) + { + if (get_tmr_ms() > timeout) + { + timeout = 0; // Set timeout to 0 if we timed out. + break; + } + } + +#ifdef ERROR_EXTRA_PRINTING + // Check if Comp pad is open or short to ground. + // SDMMC1: CZ pads - T210/T210B01: 7-bit/5-bit. SDMMC2/4: LV_CZ pads - 5-bit. + // Use 0x1F mask for all. + u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x1F; + if (!autocal_pu_status) + EPRINTFARGS("SDMMC%d: Comp Pad open!", sdmmc->id + 1); // Or resistance is extreme. + else if (autocal_pu_status == 0x1F) + EPRINTFARGS("SDMMC%d: Comp Pad short to gnd!", sdmmc->id + 1); +#endif + + // In case auto calibration fails, we load suggested standard values. + if (!timeout) + { + sdmmc->regs->autocalcfg &= ~SDHCI_TEGRA_AUTOCAL_ENABLE; + _sdmmc_pad_config_fallback(sdmmc, power); +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: Comp Pad cal timeout!", sdmmc->id + 1); +#endif + } + + // Disable E_INPUT (SD) or enable E_PWRD (eMMC) to conserve power. + sdmmc->regs->sdmemcmppadctl &= ~SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD; + + if (should_enable_sd_clock) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; +} + +static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) +{ + int result = 1, should_disable_sd_clock = 0; + + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + } + + // Add -4 TX_DLY_CODE_OFFSET if HS533/HS667. + // if (sdmmc->id == SDMMC_4 && sdmmc->card_clock > 208000) + // sdmmc->regs->vendllctl0 = sdmmc->regs->vendllctl0 &= 0xFFFFC07F | (0x7C << 7); + + sdmmc->regs->vendllcalcfg |= SDHCI_TEGRA_DLLCAL_CALIBRATE; + _sdmmc_commit_changes(sdmmc); + + u32 timeout = get_tmr_ms() + 5; + while (sdmmc->regs->vendllcalcfg & SDHCI_TEGRA_DLLCAL_CALIBRATE) + { + if (get_tmr_ms() > timeout) + { + result = 0; + goto out; + } + } + + timeout = get_tmr_ms() + 10; + while (sdmmc->regs->vendllcalcfgsts & SDHCI_TEGRA_DLLCAL_ACTIVE) + { + if (get_tmr_ms() > timeout) + { + result = 0; + goto out; + } + } + +out:; + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + return result; +} + +static void _sdmmc_reset_cmd_data(sdmmc_t *sdmmc) +{ + sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA; + _sdmmc_commit_changes(sdmmc); + u32 timeout = get_tmr_ms() + 2000; + while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout) + ; +} + +static void _sdmmc_reset_all(sdmmc_t *sdmmc) +{ + sdmmc->regs->swrst |= SDHCI_RESET_ALL; + _sdmmc_commit_changes(sdmmc); + u32 timeout = get_tmr_ms() + 2000;//100ms + while ((sdmmc->regs->swrst & SDHCI_RESET_ALL) && get_tmr_ms() < timeout) + ; +} + +void sdmmc_setup_drv_type(sdmmc_t *sdmmc, u32 type) +{ + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_DRV_TYPE_MASK)) | SDHCI_CTRL_DRV_TYPE(type); + + _sdmmc_commit_changes(sdmmc); +} + +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) +{ + // Disable the SD clock if it was enabled, and reenable it later. + bool should_enable_sd_clock = false; + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) + { + should_enable_sd_clock = true; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + } + + _sdmmc_config_tap_val(sdmmc, type); + + _sdmmc_reset_cmd_data(sdmmc); + + switch (type) + { + case SDHCI_TIMING_MMC_ID: + case SDHCI_TIMING_MMC_LS26: + case SDHCI_TIMING_SD_ID: + case SDHCI_TIMING_SD_DS12: + sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD; + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; + break; + + case SDHCI_TIMING_MMC_HS52: + case SDHCI_TIMING_SD_HS25: + sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD; + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; + break; + + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_UHS_SDR50: // T210 Errata: the host must be set to SDR104 to WAR a CRC issue. + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + case SDHCI_TIMING_MMC_HS100: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_SDR104_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + + case SDHCI_TIMING_MMC_HS400: + // Non standard. + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | HS400_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + + case SDHCI_TIMING_UHS_SDR25: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_SDR25_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + + case SDHCI_TIMING_UHS_SDR12: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_SDR12_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + + case SDHCI_TIMING_UHS_DDR50: +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + case SDHCI_TIMING_UHS_DDR200: +#endif + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_DDR50_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + } + + _sdmmc_commit_changes(sdmmc); + + u32 clock; + u16 divisor; + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); + clock_sdmmc_config_clock_source(&clock, sdmmc->id, clock); + sdmmc->card_clock = (clock + divisor - 1) / divisor; + + // (divisor != 1) && (divisor & 1) -> error + + u16 div_lo = divisor >> 1; + u16 div_hi = div_lo >> 8; + + sdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK)) | + (div_lo << SDHCI_DIV_LO_SHIFT) | (div_hi << SDHCI_DIV_HI_SHIFT); + + // Enable the SD clock again. + if (should_enable_sd_clock) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + + if (type == SDHCI_TIMING_MMC_HS400) + return _sdmmc_dll_cal_execute(sdmmc); + + return 1; +} + +static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc) +{ + // Recalibrate periodically if needed. + if (sdmmc->periodic_calibration && !sdmmc->powersave_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + if (!sdmmc->powersave_enabled) + { + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + } + sdmmc->card_clock_enabled = 1; +} + +static void _sdmmc_card_clock_disable(sdmmc_t *sdmmc) +{ + sdmmc->card_clock_enabled = 0; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; +} + +void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable) +{ + // Recalibrate periodically if needed. + if (sdmmc->periodic_calibration && !powersave_enable && sdmmc->card_clock_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + sdmmc->powersave_enabled = powersave_enable; + if (powersave_enable) + { + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + return; + } + + if (sdmmc->card_clock_enabled) + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; +} + +static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type) +{ + switch (type) + { + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_3: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + rsp[0] = sdmmc->regs->rspreg[0]; + break; + + case SDMMC_RSP_TYPE_2: + // CRC is stripped, so shifting is needed. + for (u32 i = 0; i < 4; i++) + { + u32 tempreg = sdmmc->regs->rspreg[3 - i]; + rsp[i] = tempreg << 8; + + if (i != 0) + rsp[i - 1] |= (tempreg >> 24) & 0xFF; + } + break; + + default: + return 0; + } + + return 1; +} + +int sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, 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: + rsp[0] = sdmmc->rsp[0]; + break; + + case SDMMC_RSP_TYPE_2: + for (u32 i = 0; i < 4; i++) + rsp[i] = sdmmc->rsp[i]; + break; + + default: + return 0; + } + + return 1; +} + +static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat) +{ + _sdmmc_commit_changes(sdmmc); + + u32 timeout = get_tmr_ms() + 2000; + while (sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT) + if (get_tmr_ms() > timeout) + { + _sdmmc_reset_cmd_data(sdmmc); + return 0; + } + + if (wait_dat) + { + timeout = get_tmr_ms() + 2000; + while (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT) + if (get_tmr_ms() > timeout) + { + _sdmmc_reset_cmd_data(sdmmc); + return 0; + } + } + + return 1; +} + +static int _sdmmc_wait_card_busy(sdmmc_t *sdmmc) +{ + _sdmmc_commit_changes(sdmmc); + + u32 timeout = get_tmr_ms() + 2000; + while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL)) + if (get_tmr_ms() > timeout) + { + _sdmmc_reset_cmd_data(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; + + case SDMMC_BUS_WIDTH_4: + sdmmc->regs->blksize = 64; + break; + + case SDMMC_BUS_WIDTH_8: + sdmmc->regs->blksize = 128; + break; + } + + sdmmc->regs->blkcnt = 1; + sdmmc->regs->trnmod = SDHCI_TRNS_READ; + + return 1; +} + +static int _sdmmc_send_cmd(sdmmc_t *sdmmc, const sdmmc_cmd_t *cmd, bool 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 = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; + else + cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; + break; + + case SDMMC_RSP_TYPE_2: + cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC; + break; + + case SDMMC_RSP_TYPE_3: + cmdflags = SDHCI_CMD_RESP_LEN48; + break; + + default: + return 0; + } + + if (is_data_present) + cmdflags |= SDHCI_CMD_DATA; + + sdmmc->regs->argument = cmd->arg; + sdmmc->regs->cmdreg = SDHCI_CMD_IDX(cmd->cmd) | cmdflags; + + return 1; +} + +static void _sdmmc_send_tuning_cmd(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_send_cmd(sdmmc, &cmdbuf, true); +} + +static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd, u32 tap) +{ + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, true)) + return 0; + + _sdmmc_setup_read_small_block(sdmmc); + + sdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL; + sdmmc->regs->norintsts = sdmmc->regs->norintsts; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + // Set tap if manual tuning. + if (tap != HW_TAP_TUNING) + { + sdmmc->regs->ventunctl0 &= ~SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap << 16); + sdmmc->regs->ventunctl0 |= SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + } +#endif + + _sdmmc_send_tuning_cmd(sdmmc, cmd); + _sdmmc_commit_changes(sdmmc); + usleep(1); + + _sdmmc_reset_cmd_data(sdmmc); + + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_commit_changes(sdmmc); + + u32 timeout = get_tmr_us() + 5000; + while (get_tmr_us() < timeout) + { + if (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL) + { + sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL; + sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; + _sdmmc_commit_changes(sdmmc); + usleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles. + return 1; + } + } + + _sdmmc_reset_cmd_data(sdmmc); + + sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; + _sdmmc_commit_changes(sdmmc); + usleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles. + + return 0; +} + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT +typedef struct _sdmmc_manual_tuning_t +{ + u32 result[8]; + u32 num_iter; + u32 tap_start; + u32 tap_end; +} sdmmc_manual_tuning_t; + +static int _sdmmc_manual_tuning_set_tap(sdmmc_t *sdmmc, sdmmc_manual_tuning_t *tuning) +{ + u32 tap_start = INVALID_TAP; + u32 win_size = 0; + u32 best_tap = 0; + u32 best_size = 0; + + for (u32 i = 0; i < tuning->num_iter; i++) + { + u32 iter_end = i == (tuning->num_iter - 1) ? 1 : 0; + u32 stable = tuning->result[i / 32] & BIT(i % 32); + if (stable && !iter_end) + { + if (tap_start == INVALID_TAP) + tap_start = i; + + win_size++; + } + else + { + if (tap_start != INVALID_TAP) + { + u32 tap_end = !iter_end ? (i - 1) : i; + + // Check if window is wider. + if (win_size > best_size) + { + best_tap = (tap_start + tap_end) / 2; + best_size = win_size + iter_end; + } + + tap_start = INVALID_TAP; + win_size = 0; + } + } + } + + + // Check if failed or window too small. + if (!best_tap || best_size < SAMPLING_WINDOW_SIZE_MIN) + return 0; + + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + sdmmc->regs->ventunctl0 &= ~SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + + // Set tap. + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (best_tap << 16); + + sdmmc->regs->ventunctl0 |= SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + + return 1; +} + +/* + * SD Card DDR200 (DDR208) support + * + * On Tegra X1, that can be done with DDR50 host mode. + * That's because HS400 4-bit or HS400 generally, is not supported on SDMMC1/3. + * And also, tuning can't be done automatically on any DDR mode. + * So it needs to be done manually and selected tap will be applied from the biggest + * sampling window. + * That allows DDR200 support on every DDR200 sd card, other than the original maker + * of DDR200, Sandisk. Since Sandisk cards mandate DLL syncing. + */ +static int sdmmc_tuning_execute_ddr200(sdmmc_t *sdmmc) +{ + sdmmc_manual_tuning_t manual_tuning = { 0 }; + manual_tuning.num_iter = 128; + + sdmmc->regs->ventunctl1 = 0; // step_size 1. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | (2 << 13); // 128 Tries. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier. + sdmmc->regs->ventunctl0 |= SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + + sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; + + for (u32 i = 0; i < manual_tuning.num_iter; i++) + { + _sdmmc_tuning_execute_once(sdmmc, MMC_SEND_TUNING_BLOCK, i); + + // Save result for manual tuning. + int sampled = (sdmmc->regs->hostctl2 >> SDHCI_CTRL_TUNED_CLK_SHIFT) & 1; + manual_tuning.result[i / 32] |= sampled << (i % 32); + + if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) + break; + } + + return _sdmmc_manual_tuning_set_tap(sdmmc, &manual_tuning); +} +#endif + +int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd) +{ + u32 num_iter, flag; + + if (sdmmc->powersave_enabled) + return 0; + + switch (type) + { + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + num_iter = 128; + flag = (2 << 13); // 128 iterations. + break; + + case SDHCI_TIMING_UHS_SDR50: + case SDHCI_TIMING_UHS_DDR50: // HW tuning is not supported on DDR modes. But it sets tap to 0 which is proper. + case SDHCI_TIMING_MMC_HS100: + num_iter = 256; + flag = (4 << 13); // 256 iterations. + break; + + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR12: + case SDHCI_TIMING_UHS_SDR25: + return 1; + +#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT + case SDHCI_TIMING_UHS_DDR200: + return sdmmc_tuning_execute_ddr200(sdmmc); +#endif + + default: + return 0; + } + + sdmmc->regs->ventunctl1 = 0; // step_size 1. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier. + sdmmc->regs->ventunctl0 |= SDHCI_TEGRA_TUNING_TAP_HW_UPDATED; + + sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; + + for (u32 i = 0; i < num_iter; i++) + { + _sdmmc_tuning_execute_once(sdmmc, cmd, HW_TAP_TUNING); + + if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) + break; + } + + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) + 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 |= SDHCI_CLOCK_INT_EN; + _sdmmc_commit_changes(sdmmc); + u32 timeout = get_tmr_ms() + 2000; + while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE)) + { + if (get_tmr_ms() > timeout) + return 0; + } + + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; + sdmmc->regs->clkcon &= ~SDHCI_PROG_CLOCK_MODE; + // Enable 32/64bit addressing if used (sysad. if blkcnt it fallbacks to 16bit). + sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; + + if (!(sdmmc->regs->capareg & SDHCI_CAP_64BIT)) + return 0; + + sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; + sdmmc->regs->hostctl &= ~SDHCI_CTRL_DMA_MASK; // Use SDMA. Host V4 enabled so adma address regs in use. + sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 14; // TMCLK * 2^27. + + 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: + if (power == SDMMC_POWER_1_8) + { + if (!sdmmc->t210b01) + { + off_pd = 0x7B; // -5. + off_pu = 0x7B; // -5. + } + else + { + off_pd = 6; + off_pu = 6; + } + } + else if (power == SDMMC_POWER_3_3) + { + if (!sdmmc->t210b01) + { + off_pd = 0x7D; // -3. + off_pu = 0; + } + } + else + return 0; + break; + } + + sdmmc->regs->autocalcfg = (sdmmc->regs->autocalcfg & 0xFFFF8080) | (off_pd << 8) | off_pu; + return 1; +} + +static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc) +{ + sdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; + sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; + sdmmc->regs->norintsts = sdmmc->regs->norintsts; + sdmmc->regs->errintsts = sdmmc->regs->errintsts; + sdmmc->error_sts = 0; +} + +static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc) +{ + sdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; + sdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); +} + +static u32 _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 & SDHCI_INT_ERROR) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: intsts %08X, errintsts %08X", sdmmc->id + 1, norintsts, errintsts); +#endif + sdmmc->error_sts = errintsts; + 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_response(sdmmc_t *sdmmc) +{ + _sdmmc_commit_changes(sdmmc); + + u32 timeout = get_tmr_ms() + 2000; + while (true) + { + u32 result = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE); + if (result == SDMMC_MASKINT_MASKED) + break; + if (result != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout) + { + _sdmmc_reset_cmd_data(sdmmc); + return 0; + } + } + + return 1; +} + +static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) +{ + sdmmc_cmd_t cmd; + + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, false)) + 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_send_cmd(sdmmc, &cmd, false); + + int result = _sdmmc_wait_response(sdmmc); + _sdmmc_mask_interrupts(sdmmc); + + if (!result) + return 0; + + _sdmmc_cache_rsp(sdmmc, rsp, SDMMC_RSP_TYPE_1); + + return _sdmmc_wait_card_busy(sdmmc); +} + +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) +{ + if (!sdmmc->card_clock_enabled) + return 0; + + // Recalibrate periodically if needed. + if (sdmmc->periodic_calibration && sdmmc->powersave_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + bool should_disable_sd_clock = false; + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = true; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_commit_changes(sdmmc); + usleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles. + } + + int result = _sdmmc_stop_transmission_inner(sdmmc, rsp); + usleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles. + + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + + return result; +} + +static int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, const 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 & 7) + return 0; + + sdmmc->regs->admaaddr = admaaddr; + sdmmc->regs->admaaddr_hi = 0; + + sdmmc->dma_addr_next = ALIGN_DOWN((admaaddr + SZ_512K), SZ_512K); + + sdmmc->regs->blksize = req->blksize | (7u << 12); // SDMA DMA 512KB Boundary (Detects A18 carry out). + sdmmc->regs->blkcnt = blkcnt; + + if (blkcnt_out) + *blkcnt_out = blkcnt; + + u32 trnmode = SDHCI_TRNS_DMA | SDHCI_TRNS_RTYPE_R1; + + // Set multiblock request. + if (req->is_multi_block) + trnmode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN; + + // Set request direction. + if (!req->is_write) + trnmode |= SDHCI_TRNS_READ; + + // Automatic send of stop transmission or set block count cmd. + if (req->is_auto_stop_trn) + trnmode |= SDHCI_TRNS_AUTO_CMD12; + //else if (req->is_auto_set_blkcnt) + // trnmode |= SDHCI_TRNS_AUTO_CMD23; + + sdmmc->regs->trnmod = trnmode; + + return 1; +} + +static int _sdmmc_update_sdma(sdmmc_t *sdmmc) +{ + u16 blkcnt = 0; + do + { + blkcnt = sdmmc->regs->blkcnt; + u32 timeout = get_tmr_ms() + 1500; + do + { + u32 result = SDMMC_MASKINT_MASKED; + while (true) + { + u16 intr = 0; + result = _sdmmc_check_mask_interrupt(sdmmc, &intr, + SDHCI_INT_DATA_END | SDHCI_INT_DMA_END); + if (result != SDMMC_MASKINT_MASKED) + break; + + if (intr & SDHCI_INT_DATA_END) + return 1; // Transfer complete. + + if (intr & SDHCI_INT_DMA_END) + { + // Update DMA. + sdmmc->regs->admaaddr = sdmmc->dma_addr_next; + sdmmc->regs->admaaddr_hi = 0; + sdmmc->dma_addr_next += SZ_512K; + } + } + + if (result != SDMMC_MASKINT_NOERROR) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: int error!", sdmmc->id + 1); +#endif + _sdmmc_reset_cmd_data(sdmmc); + + return 0; + } + } while (get_tmr_ms() < timeout); + } while (sdmmc->regs->blkcnt != blkcnt); + + _sdmmc_reset_cmd_data(sdmmc); + + return 0; +} + +static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +{ + bool has_req_or_check_busy = req || cmd->check_busy; + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy)) + return 0; + + u32 blkcnt = 0; + bool is_data_present = false; + if (req) + { + if (!_sdmmc_config_sdma(sdmmc, &blkcnt, req)) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: DMA Wrong cfg!", sdmmc->id + 1); +#endif + return 0; + } + + // Flush cache before starting the transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false); + + is_data_present = true; + } + + _sdmmc_enable_interrupts(sdmmc); + + if (!_sdmmc_send_cmd(sdmmc, cmd, is_data_present)) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: Wrong Response type %08X!", sdmmc->id + 1, cmd->rsp_type); +#endif + return 0; + } + + int result = _sdmmc_wait_response(sdmmc); +#ifdef ERROR_EXTRA_PRINTING + if (!result) + EPRINTFARGS("SDMMC%d: Transfer error!", sdmmc->id + 1); +#endif + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, + sdmmc->regs->rspreg[0], sdmmc->regs->rspreg[1], sdmmc->regs->rspreg[2], sdmmc->regs->rspreg[3]); + if (result) + { + if (cmd->rsp_type) + { + sdmmc->expected_rsp_type = cmd->rsp_type; + result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, cmd->rsp_type); +#ifdef ERROR_EXTRA_PRINTING + if (!result) + EPRINTFARGS("SDMMC%d: Unknown response type!", sdmmc->id + 1); +#endif + } + if (req && result) + { + result = _sdmmc_update_sdma(sdmmc); +#ifdef ERROR_EXTRA_PRINTING + if (!result) + EPRINTFARGS("SDMMC%d: DMA Update failed!", sdmmc->id + 1); +#endif + } + } + + _sdmmc_mask_interrupts(sdmmc); + + if (result) + { + if (req) + { + // Invalidate cache after transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + if (blkcnt_out) + *blkcnt_out = blkcnt; + + if (req->is_auto_stop_trn) + sdmmc->stop_trn_rsp = sdmmc->regs->rspreg[3]; + } + + if (has_req_or_check_busy) + { + result = _sdmmc_wait_card_busy(sdmmc); +#ifdef ERROR_EXTRA_PRINTING + if (!result) + EPRINTFARGS("SDMMC%d: Busy timeout!", sdmmc->id + 1); +#endif + return result; + } + } + + return result; +} + +bool sdmmc_get_sd_inserted() +{ + return (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)); +} + +static void _sdmmc_config_sdmmc1_schmitt() +{ + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; +} + +static void _sdmmc_config_sdmmc2_schmitt() +{ + PINMUX_AUX(PINMUX_AUX_SDMMC2_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT7) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT6) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT5) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT4) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT0) |= PINMUX_SCHMT; +} + +static void _sdmmc_config_sdmmc1_pads(bool discharge) +{ + u32 sdmmc1_pin_mask = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5; + + // Set values for Reset state. + u32 function = GPIO_MODE_SPIO; + u32 level = GPIO_LOW; + u32 output = GPIO_OUTPUT_DISABLE; + + // Set values for discharging. + if (discharge) + { + function = GPIO_MODE_GPIO; + level = GPIO_HIGH; + output = GPIO_OUTPUT_ENABLE; + } + + // Set all pads function. + gpio_config(GPIO_PORT_M, sdmmc1_pin_mask, function); + // Set all pads output level. + gpio_write(GPIO_PORT_M, sdmmc1_pin_mask, level); + // Set all pads output. + gpio_output_enable(GPIO_PORT_M, sdmmc1_pin_mask, output); +} + +static int _sdmmc_config_sdmmc1(bool t210b01) +{ + // Configure SD card detect. + PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 2; // GPIO control, pull up. + APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; + gpio_direction_input(GPIO_PORT_Z, GPIO_PIN_1); + usleep(100); + + // Check if SD card is inserted. + if (!sdmmc_get_sd_inserted()) + return 0; + + // Enable deep loopback for SDMMC1 CLK pad so reads work. + APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; + + // Configure SDMMC1 CLK pinmux, based on state and SoC type. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_SCHMT; + if (PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) != (PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN)) // Check if CLK pad is already configured. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | (t210b01 ? PINMUX_PULL_NONE : PINMUX_PULL_DOWN); + + // Configure reset state of SDMMC1 pins pinmux. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + + // Force schmitt trigger for T210B01. + if (t210b01) + _sdmmc_config_sdmmc1_schmitt(); + + // Make sure the SDMMC1 controller is powered. + PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1; + usleep(1000); + PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_SDMMC1; + (void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write. + + // Enable SD card power. Powers LDO2 also. + PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; + gpio_direction_output(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); + usleep(10000); // Minimum 3 to 10 ms. + + // Inform IO pads that voltage is gonna be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + + // Enable SD card IO power. + max7762x_regulator_set_voltage(REGULATOR_LDO2, 3300000); + max7762x_regulator_enable(REGULATOR_LDO2, true); + usleep(1000); + + // Set pad slew codes to get good quality clock. + if (!t210b01) + { + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000; + (void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write. + usleep(1000); + } + + return 1; +} + +static void _sdmmc_config_emmc(u32 id, bool t210b01) +{ + switch (id) + { + case SDMMC_2: + if (!t210b01) + { + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF; + (void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); // Commit write. + } + else // Enable schmitt trigger for T210B01. + _sdmmc_config_sdmmc2_schmitt(); + break; + + case SDMMC_4: + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) &= 0xF8003FFF; + // Set default pad cfg. + if (t210b01) + APB_MISC(APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL) &= 0xFFBFFFF9; // Unset CMD/CLK/DQS weak pull up/down. + // Enable schmitt trigger. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; + (void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write. + break; + } +} + +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type) +{ + u32 clock; + u16 divisor; + u8 vref_sel = 7; + + static const u8 trim_values_t210[4] = { 2, 8, 3, 8 }; + static const u8 trim_values_t210b01[4] = { 14, 13, 15, 13 }; + const u8 *trim_values; + + if (id > SDMMC_4 || id == SDMMC_3) + return 0; + + memset(sdmmc, 0, sizeof(sdmmc_t)); + + sdmmc->regs = (t210_sdmmc_t *)(SDMMC_BASE + (u32)_sdmmc_base_offsets[id]); + sdmmc->id = id; + sdmmc->clock_stopped = 1; + sdmmc->t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; + + trim_values = sdmmc->t210b01 ? trim_values_t210b01 : trim_values_t210; + + // Do specific SDMMC HW configuration. + switch (id) + { + case SDMMC_1: + if (!_sdmmc_config_sdmmc1(sdmmc->t210b01)) + return 0; + if (sdmmc->t210b01) + vref_sel = 0; + else + sdmmc->periodic_calibration = 1; + break; + + case SDMMC_2: + case SDMMC_4: + _sdmmc_config_emmc(id, sdmmc->t210b01); + break; + } + + // Disable clock if enabled. + if (clock_sdmmc_is_not_reset_and_enabled(id)) + { + _sdmmc_card_clock_disable(sdmmc); + _sdmmc_commit_changes(sdmmc); + } + + // Configure and enable selected clock. + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); + clock_sdmmc_enable(id, clock); + sdmmc->clock_stopped = 0; + + // Make sure all sdmmc registers are reset. + _sdmmc_reset_all(sdmmc); + + // Set default pad IO trimming configuration. + sdmmc->regs->iospare |= BIT(19); // Enable 1 cycle delayed cmd_oen. + sdmmc->regs->veniotrimctl &= ~BIT(2); // Set Band Gap VREG to supply DLL. + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | ((u32)trim_values[sdmmc->id] << 24); + sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & ~SDHCI_TEGRA_PADCTRL_VREF_SEL_MASK) | vref_sel; + + // Configure auto calibration values. + if (!_sdmmc_autocal_config_offset(sdmmc, power)) + return 0; + + _sdmmc_commit_changes(sdmmc); + + // Calibrate pads. + _sdmmc_autocal_execute(sdmmc, power); + + // Enable internal clock and power. + if (_sdmmc_enable_internal_clock(sdmmc)) + { + sdmmc_set_bus_width(sdmmc, bus_width); + _sdmmc_set_io_power(sdmmc, power); + + if (sdmmc_setup_clock(sdmmc, type)) + { + sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_DISABLE); + _sdmmc_card_clock_enable(sdmmc); + _sdmmc_commit_changes(sdmmc); + + return 1; + } + } + + return 0; +} + +void sdmmc1_disable_power() +{ + // T210B01 WAR: Clear pull down from CLK pad. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_PULL_MASK; + + // T210B01 WAR: Set pads to discharge state. + _sdmmc_config_sdmmc1_pads(true); + + // Disable SD card IO power. + max7762x_regulator_enable(REGULATOR_LDO2, false); + usleep(4000); + + // Disable SD card power. + gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); + + // T210/T210B01 WAR: Set start timer for IO and Controller power discharge. + sd_power_cycle_time_start = get_tmr_ms(); + usleep(10000); // To power cycle, min 1ms without power is needed. + + // Disable SDMMC1 controller power. + PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1; + (void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write. + + // Inform IO pads that next voltage might be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + + // T210B01 WAR: Restore pads to reset state. + _sdmmc_config_sdmmc1_pads(false); + + // T210B01 WAR: Restore pull down to CLK pad. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_PULL_DOWN; +} + +void sdmmc_end(sdmmc_t *sdmmc) +{ + if (!sdmmc->clock_stopped) + { + _sdmmc_card_clock_disable(sdmmc); + // Disable SDMMC power. + _sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF); + _sdmmc_commit_changes(sdmmc); + + // Disable SD card power. + if (sdmmc->id == SDMMC_1) + sdmmc1_disable_power(); + + 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->card_clock_enabled) + return 0; + + // Recalibrate periodically if needed. + if (sdmmc->periodic_calibration && sdmmc->powersave_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + int should_disable_sd_clock = 0; + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_commit_changes(sdmmc); + usleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles. + } + + int result = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); + usleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles. + + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + + return result; +} + +int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) +{ + if (sdmmc->id != SDMMC_1) + return 0; + + _sdmmc_commit_changes(sdmmc); + + // Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed. + max7762x_regulator_set_voltage(REGULATOR_LDO2, 1800000); + usleep(150); + + // Inform IO pads that we switched to 1.8V. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_33V_SDMMC1; + (void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write. + + // Enable schmitt trigger for better duty cycle and low jitter clock. + _sdmmc_config_sdmmc1_schmitt(); + + _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); + _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); + _sdmmc_set_io_power(sdmmc, SDMMC_POWER_1_8); + _sdmmc_commit_changes(sdmmc); + msleep(5); // Wait minimum 5ms before turning on the card clock. + + // Turn on SDCLK. + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) + { + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_commit_changes(sdmmc); + usleep(1000); + if ((sdmmc->regs->prnsts & SDHCI_DATA_LVL_MASK) == SDHCI_DATA_LVL_MASK) + return 1; + } + + return 0; +} diff --git a/bdk/storage/sdmmc_driver.h b/bdk/storage/sdmmc_driver.h new file mode 100644 index 0000000..fe09c5a --- /dev/null +++ b/bdk/storage/sdmmc_driver.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include + +/*! SDMMC controller IDs. */ +#define SDMMC_1 0 // Version 4.00. +#define SDMMC_2 1 // Version 5.0 + SW CQE + Enhanced Strobe. +#define SDMMC_3 2 // Version 4.00. +#define SDMMC_4 3 // Version 5.0 + SW CQE + Enhanced Strobe. + +/*! SDMMC power types. */ +#define SDMMC_POWER_OFF 0 +#define SDMMC_POWER_1_8 1 +#define SDMMC_POWER_3_3 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 bus widths. */ +#define SDMMC_BUS_WIDTH_1 0 +#define SDMMC_BUS_WIDTH_4 1 +#define SDMMC_BUS_WIDTH_8 2 + +/*! SDMMC mask interrupt status. */ +#define SDMMC_MASKINT_MASKED 0 +#define SDMMC_MASKINT_NOERROR 1 +#define SDMMC_MASKINT_ERROR 2 + +/*! SDMMC present state. 0x24. */ +#define SDHCI_CMD_INHIBIT BIT(0) +#define SDHCI_DATA_INHIBIT BIT(1) +#define SDHCI_DAT_LINE_ACTIVE BIT(2) +#define SDHCI_RETUNING_REQUEST BIT(3) +#define SDHCI_EMMC_LINE_LVL_MASK (0xFU << 4) +#define SDHCI_DATA_4_LVL BIT(4) // eMMC only. +#define SDHCI_DATA_5_LVL BIT(5) // eMMC only. +#define SDHCI_DATA_6_LVL BIT(6) // eMMC only. +#define SDHCI_DATA_7_LVL BIT(7) // eMMC only. +#define SDHCI_DOING_WRITE BIT(8) +#define SDHCI_DOING_READ BIT(9) // SD only. +#define SDHCI_SPACE_AVAILABLE BIT(10) // Write buffer empty. +#define SDHCI_DATA_AVAILABLE BIT(11) // Read buffer has data. +#define SDHCI_CARD_PRESENT BIT(16) +#define SDHCI_CD_STABLE BIT(17) +#define SDHCI_CD_LVL BIT(18) +#define SDHCI_WRITE_PROTECT BIT(19) +#define SDHCI_DATA_LVL_MASK 0xF00000 +#define SDHCI_DATA_0_LVL BIT(20) +#define SDHCI_DATA_1_LVL BIT(21) +#define SDHCI_DATA_2_LVL BIT(22) +#define SDHCI_DATA_3_LVL BIT(23) +#define SDHCI_CMD_LVL BIT(24) + +/*! SDMMC transfer mode. 0x0C. */ +#define SDHCI_TRNS_DMA BIT(0) +#define SDHCI_TRNS_BLK_CNT_EN BIT(1) +#define SDHCI_TRNS_AUTO_CMD12 (1U << 2) +#define SDHCI_TRNS_AUTO_CMD23 (2U << 2) +#define SDHCI_TRNS_WRITE (0U << 4) +#define SDHCI_TRNS_READ BIT(4) +#define SDHCI_TRNS_MULTI BIT(5) +#define SDHCI_TRNS_RTYPE_R1 (0U << 6) +#define SDHCI_TRNS_RTYPE_R5 BIT(6) +#define SDHCI_TRNS_RSP_ERR_CHK BIT(7) +#define SDHCI_TRNS_RSP_INT_DIS BIT(8) + +/*! SDMMC command. 0x0E. */ +#define SDHCI_CMD_RESP_MASK 0x3 +#define SDHCI_CMD_RESP_NO_RESP 0x0 +#define SDHCI_CMD_RESP_LEN136 0x1 +#define SDHCI_CMD_RESP_LEN48 0x2 +#define SDHCI_CMD_RESP_LEN48_BUSY 0x3 +#define SDHCI_CMD_CRC BIT(3) +#define SDHCI_CMD_INDEX BIT(4) +#define SDHCI_CMD_DATA BIT(5) +#define SDHCI_CMD_TYPE_NORMAL (0U << 6) +#define SDHCI_CMD_TYPE_SUSPEND (1U << 6) +#define SDHCI_CMD_TYPE_RESUME (2U << 6) +#define SDHCI_CMD_TYPE_ABORT (3U << 6) +#define SDHCI_CMD_SPI_CS_LOW BIT(7) +#define SDHCI_CMD_IDX(cmd) ((cmd) << 8) + + +/*! SDMMC host control. 0x28. */ +#define SDHCI_CTRL_LED BIT(0) +#define SDHCI_CTRL_4BITBUS BIT(1) // SD only. +#define SDHCI_CTRL_HISPD BIT(2) // SD only. +#define SDHCI_CTRL_DMA_MASK (3U << 3) +#define SDHCI_CTRL_SDMA (0U << 3) +#define SDHCI_CTRL_ADMA1 (1U << 3) +#define SDHCI_CTRL_ADMA32 (2U << 3) +#define SDHCI_CTRL_ADMA64 (3U << 3) +#define SDHCI_CTRL_8BITBUS BIT(5) // eMMC only (or UHS-II). +#define SDHCI_CTRL_CDTEST_INS BIT(6) +#define SDHCI_CTRL_CDTEST_EN BIT(7) + +/*! SDMMC host control 2. 0x3E. */ +#define SDHCI_CTRL_UHS_MASK 0x7 +#define SDHCI_CTRL_VDD_180 BIT(3) +#define SDHCI_CTRL_DRV_TYPE_MASK (3U << 4) +#define SDHCI_CTRL_DRV_TYPE_B (0U << 4) +#define SDHCI_CTRL_DRV_TYPE_A (1U << 4) +#define SDHCI_CTRL_DRV_TYPE_C (2U << 4) +#define SDHCI_CTRL_DRV_TYPE_D (3U << 4) +#define SDHCI_CTRL_DRV_TYPE(type) ((type) << 4) +#define SDHCI_CTRL_EXEC_TUNING BIT(6) +#define SDHCI_CTRL_TUNED_CLK_SHIFT 7 +#define SDHCI_CTRL_TUNED_CLK BIT(7) +#define SDHCI_HOST_VERSION_4_EN BIT(12) +#define SDHCI_ADDRESSING_64BIT_EN BIT(13) +#define SDHCI_CTRL_PRESET_VAL_EN BIT(15) + +/*! SDMMC power control. 0x29. */ +#define SDHCI_POWER_ON BIT(0) +#define SDHCI_POWER_180 (5U << 1) +#define SDHCI_POWER_300 (6U << 1) +#define SDHCI_POWER_330 (7U << 1) +#define SDHCI_POWER_MASK 0xF1 // UHS-II only. + +/*! SDMMC clock control. 0x2C. */ +#define SDHCI_CLOCK_INT_EN BIT(0) // Internal Clock. +#define SDHCI_CLOCK_INT_STABLE BIT(1) // Internal Clock Stable. +#define SDHCI_CLOCK_CARD_EN BIT(2) +#define SDHCI_PROG_CLOCK_MODE BIT(5) +#define SDHCI_DIV_HI_SHIFT 6 +#define SDHCI_DIV_HI_MASK (3U << SDHCI_DIV_HI_SHIFT) +#define SDHCI_DIV_LO_SHIFT 8 +#define SDHCI_DIV_MASK (0xFFU << SDHCI_DIV_LO_SHIFT) + + +/*! SDMMC software reset. 0x2F. */ +#define SDHCI_RESET_ALL BIT(0) +#define SDHCI_RESET_CMD BIT(1) +#define SDHCI_RESET_DATA BIT(2) + +/*! SDMMC interrupt status and control. 0x30/0x34. */ +#define SDHCI_INT_RESPONSE BIT(0) +#define SDHCI_INT_DATA_END BIT(1) +#define SDHCI_INT_BLK_GAP BIT(2) +#define SDHCI_INT_DMA_END BIT(3) +#define SDHCI_INT_SPACE_AVAIL BIT(4) // Write buffer empty. +#define SDHCI_INT_DATA_AVAIL BIT(5) // Read buffer has data. +#define SDHCI_INT_CARD_INSERT BIT(6) +#define SDHCI_INT_CARD_REMOVE BIT(7) +#define SDHCI_INT_CARD_INT BIT(8) +#define SDHCI_INT_RETUNE BIT(12) +#define SDHCI_INT_ERROR BIT(15) + +/*! SDMMC error interrupt status and control. 0x32/0x36. */ +#define SDHCI_ERR_INT_CMD_TIMEOUT BIT(0) +#define SDHCI_ERR_INT_CMD_CRC BIT(1) +#define SDHCI_ERR_INT_CMD_END_BIT BIT(2) +#define SDHCI_ERR_INT_CMD_INDEX BIT(3) +#define SDHCI_ERR_INT_DATA_TIMEOUT BIT(4) +#define SDHCI_ERR_INT_DATA_CRC BIT(5) +#define SDHCI_ERR_INT_DATA_END_BIT BIT(6) +#define SDHCI_ERR_INT_BUS_POWER BIT(7) +#define SDHCI_ERR_INT_AUTO_CMD12 BIT(8) +#define SDHCI_ERR_INT_ADMA BIT(9) +#define SDHCI_ERR_INT_TUNE BIT(10) +#define SDHCI_ERR_INT_RSP BIT(11) +#define SDHCI_ERR_INT_TARGET_RSP BIT(12) +#define SDHCI_ERR_INT_SPI BIT(13) +#define SDHCI_ERR_INT_VND_BOOT_TMO BIT(14) +#define SDHCI_ERR_INT_VND_BOOT_ACK BIT(15) + +#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \ + (SDHCI_ERR_INT_AUTO_CMD12 | SDHCI_ERR_INT_DATA_END_BIT | \ + SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \ + SDHCI_ERR_INT_CMD_INDEX | SDHCI_ERR_INT_CMD_END_BIT | \ + SDHCI_ERR_INT_CMD_CRC | SDHCI_ERR_INT_CMD_TIMEOUT) + +/*! Host Capability 1. 0x40. */ +#define SDHCI_CAP_TM_CLK_FREQ_MASK 0x3F +#define SDHCI_CAP_TM_UNIT_MHZ BIT(7) +#define SDHCI_CAP_BASE_CLK_FREQ_MASK (0xFFU << 8) +#define SDHCI_CAP_MAX_BLK_LEN_MASK (3U << 16) +#define SDHCI_CAP_EMMC_8BIT BIT(18) +#define SDHCI_CAP_ADMA2 BIT(19) +#define SDHCI_CAP_HISPD BIT(21) +#define SDHCI_CAP_SDMA BIT(22) +#define SDHCI_CAP_SUSPEND_RESUME BIT(23) +#define SDHCI_CAP_3_3_V BIT(24) +#define SDHCI_CAP_3_0_V BIT(25) +#define SDHCI_CAP_1_8_V BIT(26) +#define SDHCI_CAP_64BIT BIT(28) +#define SDHCI_CAP_ASYNC_INT BIT(29) +#define SDHCI_CAP_SLOT_TYPE_MASK (3U << 30) +#define SDHCI_CAP_SLOT_TYPE_REMOVABLE (0U << 30) +#define SDHCI_CAP_SLOT_TYPE_EMBEDDED (1U << 30) +#define SDHCI_CAP_SLOT_TYPE_SHARED (2U << 30) +#define SDHCI_CAP_SLOT_TYPE_UHS2 (3U << 30) + +/*! Host Capability 2. 0x44. */ +#define SDHCI_CAP_SDR50 BIT(0) +#define SDHCI_CAP_SDR5104 BIT(1) +#define SDHCI_CAP_DDR50 BIT(2) +#define SDHCI_CAP_UHS2 BIT(3) +#define SDHCI_CAP_DRV_TYPE_A BIT(4) +#define SDHCI_CAP_DRV_TYPE_C BIT(5) +#define SDHCI_CAP_DRV_TYPE_D BIT(6) +#define SDHCI_CAP_RSP_TIMER_CNT_MASK (0xFU << 8) +#define SDHCI_CAP_SDR50_TUNING BIT(13) +#define SDHCI_CAP_RSP_MODES_MASK (3U << 14) +#define SDHCI_CAP_CLK_MULT (0xFFU << 16) +#define SDHCI_CAP_ADMA3 BIT(27) +#define SDHCI_CAP_VDD2_1_8V BIT(28) + +/*! SDMMC max current. 0x48 */ +#define SDHCI_MAX_CURRENT_3_3_V_MASK (0xFFU << 0) +#define SDHCI_MAX_CURRENT_3_0_V_MASK (0xFFU << 8) +#define SDHCI_MAX_CURRENT_1_8_V_MASK (0xFFU << 16) +#define SDHCI_MAX_CURRENT_MULTIPLIER 4 + +/*! SDMMC max current. 0x4C */ +#define SDHCI_MAX_CURRENT_1_8_V_VDD2_MASK (0xFFU << 0) + +/*! SD bus speeds. */ +#define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 +#define UHS_SDR25_BUS_SPEED 1 +#define UHS_SDR50_BUS_SPEED 2 +#define UHS_SDR104_BUS_SPEED 3 +#define UHS_DDR50_BUS_SPEED 4 +#define HS400_BUS_SPEED 5 + +/*! SDMMC timmings. */ +#define SDHCI_TIMING_MMC_ID 0 +#define SDHCI_TIMING_MMC_LS26 1 +#define SDHCI_TIMING_MMC_HS52 2 +#define SDHCI_TIMING_MMC_HS200 3 +#define SDHCI_TIMING_MMC_HS400 4 +#define SDHCI_TIMING_SD_ID 5 +#define SDHCI_TIMING_SD_DS12 6 +#define SDHCI_TIMING_SD_HS25 7 +#define SDHCI_TIMING_UHS_SDR12 8 +#define SDHCI_TIMING_UHS_SDR25 9 +#define SDHCI_TIMING_UHS_SDR50 10 +#define SDHCI_TIMING_UHS_SDR104 11 +#define SDHCI_TIMING_UHS_DDR50 12 +// SDR104 with a 163.2MHz -> 81.6MHz clock. +#define SDHCI_TIMING_UHS_SDR82 13 // GC FPGA. Obsolete and Repurposed. MMC_HS50 -> SDR82. +#define SDHCI_TIMING_MMC_HS100 14 // GC ASIC. +#define SDHCI_TIMING_UHS_DDR200 15 + +/*! SDMMC Low power features. */ +#define SDMMC_POWER_SAVE_DISABLE 0 +#define SDMMC_POWER_SAVE_ENABLE 1 + +/*! Helper for SWITCH command argument. */ +#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) + +#define HW_TAP_TUNING 0x100 +#define INVALID_TAP 0x100 +#define SAMPLING_WINDOW_SIZE_MIN 8 + +/*! SDMMC controller context. */ +typedef struct _sdmmc_t +{ + t210_sdmmc_t *regs; + u32 id; + u32 card_clock; + u32 clock_stopped; + int powersave_enabled; + int periodic_calibration; + int card_clock_enabled; + int venclkctl_set; + u32 venclkctl_tap; + u32 expected_rsp_type; + u32 dma_addr_next; + u32 rsp[4]; + u32 stop_trn_rsp; + u32 error_sts; + int t210b01; +} 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_stop_trn; +} sdmmc_req_t; + +int sdmmc_get_io_power(sdmmc_t *sdmmc); +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); +void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); +void sdmmc_save_tap_value(sdmmc_t *sdmmc); +void sdmmc_setup_drv_type(sdmmc_t *sdmmc, u32 type); +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); +void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable); +int sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type); +int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd); +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); +bool sdmmc_get_sd_inserted(); +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type); +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/bdk/storage/sdmmc_t210.h b/bdk/storage/sdmmc_t210.h new file mode 100644 index 0000000..26c1e49 --- /dev/null +++ b/bdk/storage/sdmmc_t210.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include + +#define SDHCI_TEGRA_TUNING_TAP_HW_UPDATED BIT(17) +#define SDHCI_TEGRA_DLLCAL_CALIBRATE BIT(31) +#define SDHCI_TEGRA_DLLCAL_ACTIVE BIT(31) +#define SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD BIT(31) +#define SDHCI_TEGRA_PADCTRL_VREF_SEL_MASK 0xF +#define SDHCI_TEGRA_AUTOCAL_SLW_OVERRIDE BIT(28) +#define SDHCI_TEGRA_AUTOCAL_ENABLE BIT(29) +#define SDHCI_TEGRA_AUTOCAL_START BIT(31) +#define SDHCI_TEGRA_AUTOCAL_ACTIVE BIT(31) + +typedef struct _t210_sdmmc_t +{ +/* 0x00 */ vu32 sysad; // sdma system address. +/* 0x04 */ vu16 blksize; +/* 0x06 */ vu16 blkcnt; +/* 0x08 */ vu32 argument; +/* 0x0C */ vu16 trnmod; +/* 0x0E */ vu16 cmdreg; +/* 0x10 */ vu32 rspreg[4]; +/* 0x20 */ vu32 bdata; // Buffer data port. +/* 0x24 */ vu32 prnsts; +/* 0x28 */ vu8 hostctl; +/* 0x29 */ vu8 pwrcon; +/* 0x2A */ vu8 blkgap; +/* 0x2B */ vu8 wakcon; +/* 0x2C */ vu16 clkcon; +/* 0x2E */ vu8 timeoutcon; +/* 0x2F */ vu8 swrst; +/* 0x30 */ vu16 norintsts; // Normal interrupt status. +/* 0x32 */ vu16 errintsts; // Error interrupt status. +/* 0x34 */ vu16 norintstsen; // Enable irq status. +/* 0x36 */ vu16 errintstsen; // Enable irq status. +/* 0x38 */ vu16 norintsigen; // Enable irq signal to LIC/GIC. +/* 0x3A */ vu16 errintsigen; // Enable irq signal to LIC/GIC. +/* 0x3C */ vu16 acmd12errsts; +/* 0x3E */ vu16 hostctl2; + +// CAP0: 0x376CD08C. +// 12 MHz timeout clock. 208 MHz max base clock. 512B max block length. 8-bit support. +// ADMA2 support. HS25 support. SDMA support. No suspend/resume support. 3.3/3.0/1.8V support. +// 64bit addressing for V3/V4 support. Async IRQ support. All report as removable. +/* 0x40 */ vu32 capareg; +// CAP1: 0x10002F73. +// SDR50/SDR104 support. No DDR50 support. Drive A/B/C/D support. +// Timer re-tuning info from other source. SDR50 requires re-tuning. +// Tuning uses timer and transfers should be 4MB limited. +// ADMA3 not supported. 1.8V VDD2 supported. +/* 0x44 */ vu32 capareg_hi; + +/* 0x48 */ vu32 maxcurr; // Get information by another method. Can be overriden via maxcurrover and maxcurrover_hi. +/* 0x4C */ vu32 maxcurr_hi; +/* 0x50 */ vu16 setacmd12err; // Force error in acmd12errsts. +/* 0x52 */ vu16 setinterr; +/* 0x54 */ vu8 admaerr; +/* 0x55 */ vu8 rsvd1[3]; // 55-57 reserved. +/* 0x58 */ vu32 admaaddr; +/* 0x5C */ vu32 admaaddr_hi; +/* 0x60 */ vu16 presets[11]; +/* 0x76 */ vu16 rsvd2; +/* 0x78 */ vu32 adma3addr; +/* 0x7C */ vu32 adma3addr_hi; +/* 0x80 */ vu8 uhs2[124]; // 80-FB UHS-II. +/* 0xFC */ vu16 slotintsts; +/* 0xFE */ vu16 hcver; // 0x303 (4.00). + +/* UHS-II range. Used for Vendor registers here */ +/* 0x100 */ vu32 venclkctl; +/* 0x104 */ vu32 vensysswctl; +/* 0x108 */ vu32 venerrintsts; +/* 0x10C */ vu32 vencapover; +/* 0x110 */ vu32 venbootctl; +/* 0x114 */ vu32 venbootacktout; +/* 0x118 */ vu32 venbootdattout; +/* 0x11C */ vu32 vendebouncecnt; +/* 0x120 */ vu32 venmiscctl; +/* 0x124 */ vu32 maxcurrover; +/* 0x128 */ vu32 maxcurrover_hi; +/* 0x12C */ vu32 unk0[32]; // 0x12C +/* 0x1AC */ vu32 veniotrimctl; +/* 0x1B0 */ vu32 vendllcalcfg; +/* 0x1B4 */ vu32 vendllctl0; +/* 0x1B8 */ vu32 vendllctl1; +/* 0x1BC */ vu32 vendllcalcfgsts; +/* 0x1C0 */ vu32 ventunctl0; +/* 0x1C4 */ vu32 ventunctl1; +/* 0x1C8 */ vu32 ventunsts0; +/* 0x1CC */ vu32 ventunsts1; +/* 0x1D0 */ vu32 venclkgatehystcnt; +/* 0x1D4 */ vu32 venpresetval0; +/* 0x1D8 */ vu32 venpresetval1; +/* 0x1DC */ vu32 venpresetval2; +/* 0x1E0 */ vu32 sdmemcmppadctl; +/* 0x1E4 */ vu32 autocalcfg; +/* 0x1E8 */ vu32 autocalintval; +/* 0x1EC */ vu32 autocalsts; +/* 0x1F0 */ vu32 iospare; +/* 0x1F4 */ vu32 mcciffifoctl; +/* 0x1F8 */ vu32 timeoutwcoal; +} t210_sdmmc_t; + +static_assert(sizeof(t210_sdmmc_t) == 0x1FC, "T210 SDMMC REG size is wrong!"); + +#endif diff --git a/bdk/thermal/fan.c b/bdk/thermal/fan.c new file mode 100644 index 0000000..22bddcc --- /dev/null +++ b/bdk/thermal/fan.c @@ -0,0 +1,128 @@ +/* + * Fan driver for Nintendo Switch + * + * Copyright (c) 2018-2024 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +void fan_set_duty(u32 duty) +{ + static bool fan_init = false; + static u16 curr_duty = -1; + + if (duty > 236) + duty = 236; + + if (curr_duty == duty) + return; + + curr_duty = duty; + + if (!fan_init) + { + // Fan tachometer. + u32 pull_resistor = hw_get_chip_id() == GP_HIDREV_MAJOR_T210 ? PINMUX_PULL_UP : 0; + PINMUX_AUX(PINMUX_AUX_CAM1_PWDN) = PINMUX_TRISTATE | PINMUX_INPUT_ENABLE | pull_resistor | 1; + gpio_direction_input(GPIO_PORT_S, GPIO_PIN_7); + + // Enable PWM if disabled. + if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA) + clock_enable_pwm(); + + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Max PWM to disable fan. + + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. + gpio_config(GPIO_PORT_V, GPIO_PIN_4, GPIO_MODE_SPIO); // Fan power mode. + + fan_init = true; + } + + // Inverted polarity. + u32 inv_duty = 236 - duty; + + // If disabled send a 0 duty. + if (inv_duty == 236) + { + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Bit 24 is absolute 0%. + regulator_5v_disable(REGULATOR_5V_FAN); + + // Disable fan. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = PINMUX_INPUT_ENABLE | PINMUX_PARKED | + PINMUX_TRISTATE | PINMUX_PULL_DOWN; // Set source to PWM1. + } + else // Set PWM duty. + { + // Fan power supply. + regulator_5v_enable(REGULATOR_5V_FAN); + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (inv_duty << 16); + + // Enable fan. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. + } +} + +void fan_get_speed(u32 *duty, u32 *rpm) +{ + if (rpm) + { + u32 irq_count = 0; + bool should_read = true; + + // Poll irqs for 2 seconds. (5 seconds for accurate count). + int timer = get_tmr_us() + 2000000; + while ((timer - get_tmr_us()) > 0) + { + bool irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7); + if (irq_val && should_read) + { + irq_count++; + should_read = false; + } + else if (!irq_val) + should_read = true; + } + + // Halve the irq count. + irq_count /= 2; + + // Calculate rpm based on triggered interrupts. + *rpm = irq_count * (60 / 2); + } + + if (duty) + *duty = 236 - ((PWM(PWM_CONTROLLER_PWM_CSR_1) >> 16) & 0xFF); +} + +void fan_set_from_temp(u32 temp) +{ + if (temp >= 52) + fan_set_duty(102); + else if (temp >= 47) + fan_set_duty(76); + else if (temp >= 42) + fan_set_duty(51); + else if (temp <= 39) + fan_set_duty(0); +} diff --git a/nyx/nyx_gui/thermal/fan.h b/bdk/thermal/fan.h similarity index 77% rename from nyx/nyx_gui/thermal/fan.h rename to bdk/thermal/fan.h index d5b9946..3c70b30 100644 --- a/nyx/nyx_gui/thermal/fan.h +++ b/bdk/thermal/fan.h @@ -1,7 +1,7 @@ /* * Fan driver for Nintendo Switch * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,11 +19,13 @@ #ifndef __FAN_H_ #define __FAN_H_ -#include "../utils/types.h" +#include // Disable: 0 (0 RPM), min duty: 1 (960 RPM), max duty 235 (11000 RPM). -void set_fan_duty(u32 duty); -// Passing NULL ptr on either of the two, disables parsing of it. -void get_fan_speed(u32 *duty, u32 *rpm); +void fan_set_duty(u32 duty); +// Passing NULL ptr on either of the two, disables results. +void fan_get_speed(u32 *duty, u32 *rpm); + +void fan_set_from_temp(u32 temp); #endif /* __FAN_H_ */ diff --git a/nyx/nyx_gui/thermal/tmp451.c b/bdk/thermal/tmp451.c similarity index 68% rename from nyx/nyx_gui/thermal/tmp451.c rename to bdk/thermal/tmp451.c index 018cf6f..65f2fd2 100644 --- a/nyx/nyx_gui/thermal/tmp451.c +++ b/bdk/thermal/tmp451.c @@ -1,7 +1,7 @@ /* * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,8 +16,10 @@ * along with this program. If not, see . */ -#include "tmp451.h" -#include "../soc/i2c.h" +#include +#include +#include +#include u16 tmp451_get_soc_temp(bool intenger) { @@ -56,6 +58,20 @@ void tmp451_init() // Disable ALARM and Range to 0 - 127 oC. i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0x80); + // Set remote sensor offsets based on SoC. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + { + // Set offset to 0 oC for Erista. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFH_REG, 0); + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFL_REG, 0); + } + else + { + // Set offset to -12.5 oC for Mariko. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFH_REG, 0xF3); // - 13 oC. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFL_REG, 0x80); // + 0.5 oC. + } + // Set conversion rate to 32/s and make a read to update the reg. i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 9); tmp451_get_soc_temp(false); @@ -63,3 +79,9 @@ void tmp451_init() // Set rate to every 4 seconds. i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 2); } + +void tmp451_end() +{ + // Place into shutdown mode to conserve power. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0xC0); +} diff --git a/nyx/nyx_gui/thermal/tmp451.h b/bdk/thermal/tmp451.h similarity index 91% rename from nyx/nyx_gui/thermal/tmp451.h rename to bdk/thermal/tmp451.h index 00a0816..6258fbd 100644 --- a/nyx/nyx_gui/thermal/tmp451.h +++ b/bdk/thermal/tmp451.h @@ -19,7 +19,7 @@ #ifndef __TMP451_H_ #define __TMP451_H_ -#include "../utils/types.h" +#include #define TMP451_I2C_ADDR 0x4C @@ -32,11 +32,15 @@ #define TMP451_SOC_TMP_DEC_REG 0x10 #define TMP451_PCB_TMP_DEC_REG 0x15 +#define TMP451_SOC_TMP_OFH_REG 0x11 +#define TMP451_SOC_TMP_OFL_REG 0x12 + // If input is false, the return value is packed. MSByte is the integer in oC // and the LSByte is the decimal point truncated to 2 decimal places. // Otherwise it's an integer oC. u16 tmp451_get_soc_temp(bool integer); u16 tmp451_get_pcb_temp(bool integer); void tmp451_init(); +void tmp451_end(); #endif /* __TMP451_H_ */ diff --git a/bdk/usb/usb_descriptor_types.h b/bdk/usb/usb_descriptor_types.h new file mode 100644 index 0000000..cb58abc --- /dev/null +++ b/bdk/usb/usb_descriptor_types.h @@ -0,0 +1,238 @@ +/* + * USB driver for Tegra X1 + * + * Copyright (c) 2019-2020 CTCaer + * + * 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 _USB_DESCRIPTORS_TYPES_H_ +#define _USB_DESCRIPTORS_TYPES_H_ + +#include + +typedef enum { + USB_DESCRIPTOR_DEVICE = 1, + USB_DESCRIPTOR_CONFIGURATION = 2, + USB_DESCRIPTOR_STRING = 3, + USB_DESCRIPTOR_INTERFACE = 4, + USB_DESCRIPTOR_ENDPOINT = 5, + USB_DESCRIPTOR_DEVICE_QUALIFIER = 6, + USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, + USB_DESCRIPTOR_INTERFACE_POWER = 8, + USB_DESCRIPTOR_INTERFACE_OTG = 9, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT = 15, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP = 16, + USB_DESCRIPTOR_HID = 33, + USB_DESCRIPTOR_HID_REPORT = 34 +} usb_desc_type_t; + +typedef enum { + USB_DESCRIPTOR_MS_COMPAT_ID = 4, + USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES = 5 +} usb_vendor_desc_type_t; + +typedef enum { + USB_ATTR_REMOTE_WAKE_UP = 0x20, + USB_ATTR_SELF_POWERED = 0x40, + USB_ATTR_BUS_POWERED_RSVD = 0x80 +} usb_cfg_attr_type_t; + +typedef enum +{ + USB_EP_TYPE_CTRL = 0, + USB_EP_TYPE_ISO = 1, + USB_EP_TYPE_BULK = 2, + USB_EP_TYPE_INTR = 3 +} usb_cfg_ep_type_t; + +/* Device descriptor structure */ +typedef struct _usb_dev_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u16 idVendor; // Vendor ID assigned by USB forum. + u16 idProduct; // Product ID assigned by Organization. + u16 bcdDevice; // Device Release number in BCD. + u8 iManufacturer; // Index of String descriptor describing Manufacturer. + u8 iProduct; // Index of String descriptor describing Product. + u8 iSerialNumber; // Index of String descriptor describing Serial number. + u8 bNumConfigs; // Number of possible configuration. +} __attribute__((packed)) usb_dev_descr_t; + +/* Device Qualifier descriptor structure */ +typedef struct _usb_dev_qual_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_QUALIFIER) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u8 bNumOtherConfigs; // Number of possible other-speed configurations. + u8 bReserved; // Reserved for future use, must be zero +} __attribute__((packed)) usb_dev_qual_descr_t; + +/* Configuration descriptor structure */ +typedef struct _usb_cfg_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + u16 wTotalLength; // Total length of all descriptors for this configuration. + u8 bNumInterfaces; // Number of interfaces in this configuration. + u8 bConfigurationValue; // Value of this configuration (1 based). + u8 iConfiguration; // Index of String Descriptor describing the configuration. + u8 bmAttributes; // Configuration characteristics. + u8 bMaxPower; // Maximum power consumed by this configuration. In 2mA (usb2) or 8mA (usb3). +} __attribute__((packed)) usb_cfg_descr_t; + +/* Interface descriptor structure */ +typedef struct _usb_inter_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + u8 bInterfaceNumber; // Number of this interface (0 based). + u8 bAlternateSetting; // Value of this alternate interface setting. + u8 bNumEndpoints; // Number of endpoints in this interface. + u8 bInterfaceClass; // Class code (assigned by the USB-IF). + u8 bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + u8 bInterfaceProtocol; // Protocol code (assigned by the USB-IF). + u8 iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) usb_inter_descr_t; + +/* HID descriptor structure */ +typedef struct _usb_hid_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_HID). + u16 bcdHID; // HID class specification release + u8 bCountryCode; // Country code. + u8 bNumDescriptors; // Number of descriptors. + u8 bClassDescriptorType; // Type of class descriptor (USB_DESCRIPTOR_HID_REPORT). + u16 bDescriptorLength; // Report descriptor length. +} __attribute__((packed)) usb_hid_descr_t; + +/* Endpoint descriptor structure */ +typedef struct _usb_ep_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + u8 bEndpointAddress; // Endpoint address. bit7 indicates direction (0=OUT, 1=IN). + u8 bmAttributes; // Endpoint transfer type. + u16 wMaxPacketSize; // Maximum packet size. + u8 bInterval; // Polling interval in frames. For Interrupt and Isochronous data transfer only. +} __attribute__((packed)) usb_ep_descr_t; + +typedef struct _usb_cfg_simple_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_simple_descr_t; + +typedef struct _usb_cfg_hid_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_hid_descr_t hid; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_hid_descr_t; + +typedef struct _usb_dev_bot_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT) + u16 wTotalLength; // Size of this descriptor in bytes. + u8 bNumDeviceCaps; // Number of device capabilities in this descriptor. + + /* Device Capability USB 2.0 Extension Descriptor */ + /* Needed for a USB2.10 device. */ + u8 bLengthCap0; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap0; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap0; // USB2: 2. + u32 bmAttributesCap0; // bit1: Link Power Management (LPM). + + u8 bLengthCap1; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap1; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap1; // USB3: 3. + u8 bmAttributesCap1; // bit1: Latency Tolerance Messaging (LTM). + u16 wSpeedsSupported; // Supported bus speeds. 1: Low Speed, 2: Full Speed, 4: High Speed, 8: Super Speed. + u8 bFunctionalitySupport; // Lowest speed at which all the functionality is available. 1: Full speed and above. + u8 bU1DevExitLat; // USB3.0 U1 exit latency. + u16 wU2DevExitLat; // USB3.0 U2 exit latency. + +} __attribute__((packed)) usb_dev_bot_t; + +/* Microsoft OS String descriptor structure */ +typedef struct _usb_ms_os_descr_t +{ + u8 bLength; // 0x12 + u8 bDescriptorType; // 3 + u16 wSignature[7]; // "MSFT100" UTF16 LE + u8 bVendorCode; // + u8 bPadding; +} __attribute__((packed)) usb_ms_os_descr_t; + +/* Microsoft Compatible ID Feature descriptor structure */ +typedef struct _usb_ms_cid_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wCompatibilityId; + u8 bSections; + u8 bReserved0[7]; + u8 bInterfaceNumber; + u8 bReserved1; + u8 bCompatibleId[8]; + u8 bSubCompatibleId[8]; + u8 bReserved2[6]; +} __attribute__((packed)) usb_ms_cid_descr_t; + +/* Microsoft Extended Properties Feature descriptor structure */ +typedef struct _usb_ms_ext_prop_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wExtendedProperty; + u16 wSections; + u32 dPropertySize; + u32 dPropertyType; + u16 wPropertyNameLength; + u16 wPropertyName[22]; // UTF16 LE + u32 dPropertyDataLength; + u16 wPropertyData[2]; // UTF16 LE +} __attribute__((packed)) usb_ms_ext_prop_descr_t; + +typedef struct _usb_desc_t +{ + usb_dev_descr_t *dev; + usb_dev_qual_descr_t *dev_qual; + usb_cfg_simple_descr_t *cfg; + usb_cfg_simple_descr_t *cfg_other; + usb_dev_bot_t *dev_bot; + u8 *vendor; + u8 *product; + u8 *serial; + u8 *lang_id; + usb_ms_os_descr_t *ms_os; + usb_ms_cid_descr_t *ms_cid; + usb_ms_ext_prop_descr_t *mx_ext; +} usb_desc_t; + +#endif diff --git a/bdk/usb/usb_descriptors.c b/bdk/usb/usb_descriptors.c new file mode 100644 index 0000000..389a70d --- /dev/null +++ b/bdk/usb/usb_descriptors.c @@ -0,0 +1,558 @@ +/* + * USB driver for Tegra X1 + * + * Copyright (c) 2019-2020 CTCaer + * + * 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 + +static usb_dev_descr_t usb_device_descriptor_ums = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E0, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +static usb_dev_qual_descr_t usb_device_qualifier_descriptor = +{ + .bLength = 10, + .bDescriptorType = USB_DESCRIPTOR_DEVICE_QUALIFIER, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .bNumOtherConfigs = 0x01, + .bReserved = 0x00 +}; + +static usb_cfg_simple_descr_t usb_configuration_descriptor_ums = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = 0x20, + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x08, // Mass Storage Class. + .interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 0x00, + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 0x00 +}; + +static usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = +{ + /* Other Speed Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION, + .config.wTotalLength = 0x20, + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0x00, + .interface.bAlternateSetting = 0x00, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x08, // Mass Storage Class. + .interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[0].wMaxPacketSize = 0x40, + .endpoint[0].bInterval = 0, + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[1].wMaxPacketSize = 0x40, + .endpoint[1].bInterval = 0 +}; + +static usb_dev_bot_t usb_device_binary_object_descriptor = +{ + .bLength = 5, + .bDescriptorType = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT, + .wTotalLength = 22, + .bNumDeviceCaps = 2, + + /* Device Capability USB 2.0 Extension Descriptor */ + .bLengthCap0 = 7, + .bDescriptorTypeCap0 = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP, + .bDevCapabilityTypeCap0 = 2, // USB2. + .bmAttributesCap0 = 0, + + /* Device Capability SuperSpeed Descriptor */ + /* Needed for a USB2.10 device. */ + .bLengthCap1 = 10, + .bDescriptorTypeCap1 = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP, + .bDevCapabilityTypeCap1 = 3, // USB3. + .bmAttributesCap1 = 0, + .wSpeedsSupported = 0x6, // FS | HS. + .bFunctionalitySupport = 1, // FS and above. + .bU1DevExitLat = 0, + .wU2DevExitLat = 0 +}; + +static u8 usb_lang_id_string_descriptor[4] = +{ + 4, 3, + 0x09, 0x04 +}; + +static u8 usb_serial_string_descriptor[26] = +{ + 26, 0x03, + 'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00, + '9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00 +}; + +static u8 usb_vendor_string_descriptor_ums[32] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0, + 'D', 0, 'i', 0, 's', 0, 'k', 0 +}; + +static u8 usb_product_string_descriptor_ums[22] = +{ + 8, 0x03, + 'U', 0, 'M', 0, 'S', 0 +}; + +static usb_ms_os_descr_t usb_ms_os_descriptor = +{ + .bLength = 0x28, + .bDescriptorType = 0x03, + .wSignature[0] = 'M', + .wSignature[1] = 'S', + .wSignature[2] = 'F', + .wSignature[3] = 'T', + .wSignature[4] = '1', + .wSignature[5] = '0', + .wSignature[6] = '0', + .bVendorCode = 0x99, +}; + +static usb_ms_cid_descr_t usb_ms_cid_descriptor = +{ + .dLength = 0x28, + .wVersion = 0x100, + .wCompatibilityId = USB_DESCRIPTOR_MS_COMPAT_ID, + .bSections = 1, + .bInterfaceNumber = 0, + .bReserved1 = 1, + + .bCompatibleId[0] = 'N', + .bCompatibleId[1] = 'Y', + .bCompatibleId[2] = 'X', + .bCompatibleId[3] = 'U', + .bCompatibleId[4] = 'S', + .bCompatibleId[5] = 'B', +}; + +static usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = +{ + .dLength = 0x48, + .wVersion = 0x100, + .wExtendedProperty = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES, + .wSections = 1, + + .dPropertySize = 0x3E, + .dPropertyType = 4, // DWORD + + .wPropertyNameLength = 0x2C, + .wPropertyName[0] = 'M', // MaximumTransferLength. + .wPropertyName[1] = 'a', + .wPropertyName[2] = 'x', + .wPropertyName[3] = 'i', + .wPropertyName[4] = 'm', + .wPropertyName[5] = 'u', + .wPropertyName[6] = 'm', + .wPropertyName[7] = 'T', + .wPropertyName[8] = 'r', + .wPropertyName[9] = 'a', + .wPropertyName[10] = 'n', + .wPropertyName[11] = 's', + .wPropertyName[12] = 'f', + .wPropertyName[13] = 'e', + .wPropertyName[14] = 'r', + .wPropertyName[15] = 'L', + .wPropertyName[16] = 'e', + .wPropertyName[17] = 'n', + .wPropertyName[18] = 'g', + .wPropertyName[19] = 't', + .wPropertyName[20] = 'h', + .wPropertyName[21] = 0, + + .dPropertyDataLength = 0x4, + .wPropertyData[0] = 0x00, // 1MB. + .wPropertyData[1] = 0x10, +}; + +static usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = +{ + .dLength = 7, + .wVersion = 0x100, + .wExtendedProperty = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES, + .wSections = 0, +}; + +static usb_dev_descr_t usb_device_descriptor_hid_jc = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E1, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +static usb_dev_descr_t usb_device_descriptor_hid_touch = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E2, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +u8 hid_report_descriptor_jc[] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop), + 0x09, 0x04, // USAGE (Joystick), + 0xa1, 0x01, // COLLECTION (Application), + 0xa1, 0x02, // COLLECTION (Logical), + 0x75, 0x08, // REPORT_SIZE (8), + 0x95, 0x04, // REPORT_COUNT (4), + 0x15, 0x00, // LOGICAL_MINIMUM (0), + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255), + 0x35, 0x00, // PHYSICAL_MINIMUM (0), + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255), + 0x09, 0x30, // USAGE (X_ID), + 0x09, 0x31, // USAGE (Y_ID), + 0x09, 0x32, // USAGE (Z_ID), + 0x09, 0x35, // USAGE (Rz_ID), + 0x81, 0x02, // INPUT (IOF_Variable), + 0x75, 0x04, // REPORT_SIZE (4), + 0x95, 0x01, // REPORT_COUNT (1), + 0x25, 0x07, // LOGICAL_MAXIMUM (7), + 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315), + 0x65, 0x14, // UNIT (Eng_Rot_Angular_Pos), + 0x09, 0x39, // USAGE (Hat_Switch), + 0x81, 0x42, // INPUT (IOF_NullposVar), + 0x65, 0x00, // UNIT (Unit_None), + 0x75, 0x01, // REPORT_SIZE (1), + 0x95, 0x0c, // REPORT_COUNT (12), + 0x25, 0x01, // LOGICAL_MAXIMUM (1), + 0x45, 0x01, // PHYSICAL_MAXIMUM (1), + 0x05, 0x09, // USAGE_PAGE (Button_ID), + 0x19, 0x01, // USAGE_MINIMUM (1), + 0x29, 0x0c, // USAGE_MAXIMUM (12), + 0x81, 0x02, // INPUT (IOF_Variable), + 0xc0, // END_COLLECTION(), + 0xc0 // END_COLLECTION(), +}; + +u32 hid_report_descriptor_jc_size = sizeof(hid_report_descriptor_jc); + +u8 hid_report_descriptor_touch[] = +{ + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x05, // USAGE (Touch Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x05, // REPORT_ID (Touch pad) + 0x09, 0x22, // USAGE (Finger) + 0xa1, 0x02, // COLLECTION (Logical) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x42, // USAGE (Tip switch) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x15, 0x00, // LOGICAL_MINIMUM (1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x09, 0x54, // USAGE (Contact Count) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0A, // LOGICAL_MAXIMUM (10) + 0x09, 0x51, // USAGE (Contact Identifier) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + // 0x15, 0x00, // LOGICAL_MINIMUM (0) + // 0x26, 0xF8, 0x2A, // LOGICAL_MAXIMUM (11000) + // 0x95, 0x01, // REPORT_COUNT (1) + // 0x75, 0x08, // REPORT_SIZE (16) + // 0x09, 0x30, // USAGE (Pressure) + // 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x05, 0x01, // USAGE_PAGE (Generic Desk.. + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x04, // LOGICAL_MAXIMUM (1279) + 0x75, 0x10, // REPORT_SIZE (16) + 0x55, 0x0e, // UNIT_EXPONENT (-2) + 0x65, 0x13, // UNIT(Inch,EngLinear) + 0x09, 0x30, // USAGE (X) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0xFF, 0x04, // PHYSICAL_MAXIMUM (1279) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x26, 0xCF, 0x02, // LOGICAL_MAXIMUM (719) + 0x46, 0xCF, 0x02, // PHYSICAL_MAXIMUM (719) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x05, 0x0d, // USAGE PAGE (Digitizers) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; +u32 hid_report_descriptor_touch_size = sizeof(hid_report_descriptor_touch); + +static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x110, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = sizeof(hid_report_descriptor_jc), + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 4, // 8ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 4 // 8ms on HS. +}; + +static u8 usb_vendor_string_descriptor_hid[22] = +{ + 16, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'U', 0, 'S', 0, 'B', 0 +}; + +static u8 usb_product_string_descriptor_hid_jc[24] = +{ + 24, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0 +}; + +static u8 usb_product_string_descriptor_hid_touch[26] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0 +}; + +static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x111, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = sizeof(hid_report_descriptor_touch), + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 3, // 4ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 3 // 4ms on HS. +}; + +usb_desc_t usb_gadget_ums_descriptors = +{ + .dev = &usb_device_descriptor_ums, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = &usb_configuration_descriptor_ums, + .cfg_other = &usb_other_speed_config_descriptor_ums, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_ums, + .product = usb_product_string_descriptor_ums, + .serial = usb_serial_string_descriptor, + .lang_id = usb_lang_id_string_descriptor, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_ums +}; + +usb_desc_t usb_gadget_hid_jc_descriptors = +{ + .dev = &usb_device_descriptor_hid_jc, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_jc, + .cfg_other = NULL, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_hid, + .product = usb_product_string_descriptor_hid_jc, + .serial = usb_serial_string_descriptor, + .lang_id = usb_lang_id_string_descriptor, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_hid +}; + +usb_desc_t usb_gadget_hid_touch_descriptors = +{ + .dev = &usb_device_descriptor_hid_touch, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_touch, + .cfg_other = NULL, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_hid, + .product = usb_product_string_descriptor_hid_touch, + .serial = usb_serial_string_descriptor, + .lang_id = usb_lang_id_string_descriptor, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_hid +}; diff --git a/bdk/usb/usb_gadget_hid.c b/bdk/usb/usb_gadget_hid.c new file mode 100644 index 0000000..dc7681a --- /dev/null +++ b/bdk/usb/usb_gadget_hid.c @@ -0,0 +1,481 @@ +/* + * USB Gadget HID driver for Tegra X1 + * + * Copyright (c) 2019-2022 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +typedef struct _gamepad_report_t +{ + u8 x; + u8 y; + u8 z; + u8 rz; + + u8 hat:4; + u8 btn1:1; + u8 btn2:1; + u8 btn3:1; + u8 btn4:1; + + u8 btn5:1; + u8 btn6:1; + u8 btn7:1; + u8 btn8:1; + u8 btn9:1; + u8 btn10:1; + u8 btn11:1; + u8 btn12:1; +} __attribute__((packed)) gamepad_report_t; + +typedef struct _jc_cal_t +{ +// 15ms * JC_CAL_MAX_STEPS = 240 ms. +#define JC_CAL_MAX_STEPS 16 + u32 cl_step; + u32 cr_step; + + u16 clx_max; + u16 clx_min; + u16 cly_max; + u16 cly_min; + u16 crx_max; + u16 crx_min; + u16 cry_max; + u16 cry_min; +} jc_cal_t; + +enum { + INPUT_POLL_HAS_PACKET, + INPUT_POLL_NO_PACKET, + INPUT_POLL_EXIT, +}; + +static jc_cal_t jc_cal_ctx; +static usb_ops_t usb_ops; + +static bool _jc_calibration(const jc_gamepad_rpt_t *jc_pad) +{ + // Calibrate left stick. + if (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS) + { + if (jc_pad->conn_l + && jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400 + && jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00) + { + jc_cal_ctx.cl_step++; + jc_cal_ctx.clx_max = jc_pad->lstick_x + 0x72; + jc_cal_ctx.clx_min = jc_pad->lstick_x - 0x72; + jc_cal_ctx.cly_max = jc_pad->lstick_y + 0x72; + jc_cal_ctx.cly_min = jc_pad->lstick_y - 0x72; + + if (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS) + return false; + } + else + return false; + } + + // Calibrate right stick. + if (jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS) + { + if (jc_pad->conn_r + && jc_pad->rstick_x > 0x400 && jc_pad->rstick_y > 0x400 + && jc_pad->rstick_x < 0xC00 && jc_pad->rstick_y < 0xC00) + { + jc_cal_ctx.cr_step++; + jc_cal_ctx.crx_max = jc_pad->rstick_x + 0x72; + jc_cal_ctx.crx_min = jc_pad->rstick_x - 0x72; + jc_cal_ctx.cry_max = jc_pad->rstick_y + 0x72; + jc_cal_ctx.cry_min = jc_pad->rstick_y - 0x72; + + if (jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS) + return false; + } + else + return false; + } + + return true; +} + +static int _jc_poll(gamepad_report_t *rpt) +{ + static gamepad_report_t prev_rpt = {0}; + + // Poll Joy-Con. + jc_gamepad_rpt_t *jc_pad = joycon_poll(); + + if (!jc_pad) + return INPUT_POLL_NO_PACKET; + + // Exit emulation if Left stick and Home are pressed. + if (jc_pad->l3 && jc_pad->home) + return INPUT_POLL_EXIT; + + if (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS || jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS) + { + if (!_jc_calibration(jc_pad)) + return INPUT_POLL_NO_PACKET; + } + + // Re-calibrate on disconnection. + if (!jc_pad->conn_l) + jc_cal_ctx.cl_step = 0; + if (!jc_pad->conn_r) + jc_cal_ctx.cr_step = 0; + + // Calculate left analog stick. + if (jc_pad->lstick_x <= jc_cal_ctx.clx_max && jc_pad->lstick_x >= jc_cal_ctx.clx_min) + rpt->x = 0x7F; + else if (jc_pad->lstick_x > jc_cal_ctx.clx_max) + { + u16 x_raw = (jc_pad->lstick_x - jc_cal_ctx.clx_max) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->x = 0x7F + x_raw; + } + else + { + u16 x_raw = (jc_cal_ctx.clx_min - jc_pad->lstick_x) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->x = 0x7F - x_raw; + } + + if (jc_pad->lstick_y <= jc_cal_ctx.cly_max && jc_pad->lstick_y >= jc_cal_ctx.cly_min) + rpt->y = 0x7F; + else if (jc_pad->lstick_y > jc_cal_ctx.cly_max) + { + u16 y_raw = (jc_pad->lstick_y - jc_cal_ctx.cly_max) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + // Hoag has inverted Y axis. + if (!jc_pad->sio_mode) + rpt->y = 0x7F - y_raw; + else + rpt->y = 0x7F + y_raw; + } + else + { + u16 y_raw = (jc_cal_ctx.cly_min - jc_pad->lstick_y) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + // Hoag has inverted Y axis. + if (!jc_pad->sio_mode) + rpt->y = 0x7F + y_raw; + else + rpt->y = 0x7F - y_raw; + } + + // Calculate right analog stick. + if (jc_pad->rstick_x <= jc_cal_ctx.crx_max && jc_pad->rstick_x >= jc_cal_ctx.crx_min) + rpt->z = 0x7F; + else if (jc_pad->rstick_x > jc_cal_ctx.crx_max) + { + u16 x_raw = (jc_pad->rstick_x - jc_cal_ctx.crx_max) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->z = 0x7F + x_raw; + } + else + { + u16 x_raw = (jc_cal_ctx.crx_min - jc_pad->rstick_x) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->z = 0x7F - x_raw; + } + + if (jc_pad->rstick_y <= jc_cal_ctx.cry_max && jc_pad->rstick_y >= jc_cal_ctx.cry_min) + rpt->rz = 0x7F; + else if (jc_pad->rstick_y > jc_cal_ctx.cry_max) + { + u16 y_raw = (jc_pad->rstick_y - jc_cal_ctx.cry_max) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + // Hoag has inverted Y axis. + if (!jc_pad->sio_mode) + rpt->rz = 0x7F - y_raw; + else + rpt->rz = 0x7F + y_raw; + } + else + { + u16 y_raw = (jc_cal_ctx.cry_min - jc_pad->rstick_y) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + // Hoag has inverted Y axis. + if (!jc_pad->sio_mode) + rpt->rz = 0x7F + y_raw; + else + rpt->rz = 0x7F - y_raw; + } + + // Set D-pad. + switch ((jc_pad->buttons >> 16) & 0xF) + { + case 0: // none + rpt->hat = 0xF; + break; + case 1: // down + rpt->hat = 4; + break; + case 2: // up + rpt->hat = 0; + break; + case 4: // right + rpt->hat = 2; + break; + case 5: // down + right + rpt->hat = 3; + break; + case 6: // up + right + rpt->hat = 1; + break; + case 8: // left + rpt->hat = 6; + break; + case 9: // down + left + rpt->hat = 5; + break; + case 10: // up + left + rpt->hat = 7; + break; + default: + rpt->hat = 0xF; + break; + } + + // Set buttons. + rpt->btn1 = jc_pad->b; // x. + rpt->btn2 = jc_pad->a; // a. + rpt->btn3 = jc_pad->y; // b. + rpt->btn4 = jc_pad->x; // y. + + rpt->btn5 = jc_pad->l; + rpt->btn6 = jc_pad->r; + rpt->btn7 = jc_pad->zl; + rpt->btn8 = jc_pad->zr; + rpt->btn9 = jc_pad->minus; + rpt->btn10 = jc_pad->plus; + rpt->btn11 = jc_pad->l3; + rpt->btn12 = jc_pad->r3; + + //rpt->btn13 = jc_pad->cap; + //rpt->btn14 = jc_pad->home; + + if (!memcmp(rpt, &prev_rpt, sizeof(gamepad_report_t))) + return INPUT_POLL_NO_PACKET; + + memcpy(&prev_rpt, rpt, sizeof(gamepad_report_t)); + + return INPUT_POLL_HAS_PACKET; +} + +typedef struct _touchpad_report_t +{ + u8 rpt_id; + u8 tip_switch:1; + u8 count:7; + + u8 id; + + //u16 z; + u16 x; + u16 y; +} __attribute__((packed)) touchpad_report_t; + +static bool _fts_touch_read(touchpad_report_t *rpt) +{ + static touch_event touchpad; + + touch_poll(&touchpad); + + rpt->rpt_id = 5; + rpt->count = 1; + + // Decide touch enable. + switch (touchpad.type & STMFTS_MASK_EVENT_ID) + { + //case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + rpt->x = touchpad.x; + rpt->y = touchpad.y; + //rpt->z = touchpad.z; + rpt->id = touchpad.fingers ? touchpad.fingers - 1 : 0; + rpt->tip_switch = 1; + break; + case STMFTS_EV_MULTI_TOUCH_LEAVE: + rpt->x = touchpad.x; + rpt->y = touchpad.y; + //rpt->z = touchpad.z; + rpt->id = touchpad.fingers ? touchpad.fingers - 1 : 0; + rpt->tip_switch = 0; + break; + case STMFTS_EV_NO_EVENT: + return false; + } + + return true; +} + +static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len) +{ + u8 status = usb_ops.usb_device_ep1_in_write((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, USB_XFER_SYNCED_CMD); + if (status == USB_ERROR_XFER_ERROR) + { + usbs->set_text(usbs->label, "#FFDD00 Error:# EP IN transfer!"); + if (usb_ops.usbd_flush_endpoint) + usb_ops.usbd_flush_endpoint(USB_EP_BULK_IN); + } + + // Linux mitigation: If timed out, clear status. + if (status == USB_ERROR_TIMEOUT) + return 0; + + return status; +} + +static bool _hid_poll_jc(usb_ctxt_t *usbs) +{ + int res = _jc_poll((gamepad_report_t *)USB_EP_BULK_IN_BUF_ADDR); + if (res == INPUT_POLL_EXIT) + return true; + + // Send HID report. + if (res == INPUT_POLL_HAS_PACKET) + if (_hid_transfer_start(usbs, sizeof(gamepad_report_t))) + return true; // EP Error. + + return false; +} + +static bool _hid_poll_touch(usb_ctxt_t *usbs) +{ + _fts_touch_read((touchpad_report_t *)USB_EP_BULK_IN_BUF_ADDR); + + // Send HID report. + if (_hid_transfer_start(usbs, sizeof(touchpad_report_t))) + return true; // EP Error. + + return false; +} + +int usb_device_gadget_hid(usb_ctxt_t *usbs) +{ + int res = 0; + u32 gadget_type; + u32 polling_time; + + // Get USB Controller ops. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + usb_device_get_ops(&usb_ops); + else + xusb_device_get_ops(&usb_ops); + + if (usbs->type == USB_HID_GAMEPAD) + { + polling_time = 15000; + gadget_type = USB_GADGET_HID_GAMEPAD; + } + else + { + polling_time = 4000; + gadget_type = USB_GADGET_HID_TOUCHPAD; + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); + + if (usb_ops.usb_device_init()) + { + usb_ops.usbd_end(false, true); + return 1; + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for connection"); + + // Initialize Control Endpoint. + if (usb_ops.usb_device_enumerate(gadget_type)) + goto error; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for HID report request"); + + if (usb_ops.usb_device_class_send_hid_report()) + goto error; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation"); + + u32 timer_sys = get_tmr_ms() + 5000; + while (true) + { + u32 timer = get_tmr_us(); + + // Parse input device. + if (usbs->type == USB_HID_GAMEPAD) + { + if (_hid_poll_jc(usbs)) + break; + } + else + { + if (_hid_poll_touch(usbs)) + break; + } + + // Check for suspended USB in case the cable was pulled. + if (usb_ops.usb_device_get_suspended()) + break; // Disconnected. + + // Handle control endpoint. + usb_ops.usbd_handle_ep0_ctrl_setup(); + + // Wait max gadget timing. + timer = get_tmr_us() - timer; + if (timer < polling_time) + usleep(polling_time - timer); + + if (timer_sys < get_tmr_ms()) + { + usbs->system_maintenance(true); + timer_sys = get_tmr_ms() + 5000; + } + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# HID ended"); + goto exit; + +error: + usbs->set_text(usbs->label, "#FFDD00 Error:# Timed out or canceled"); + res = 1; + +exit: + usb_ops.usbd_end(true, false); + + return res; +} diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c new file mode 100644 index 0000000..1655bd5 --- /dev/null +++ b/bdk/usb/usb_gadget_ums.c @@ -0,0 +1,1970 @@ +/* + * USB Gadget UMS driver for Tegra X1 + * + * Copyright (c) 2003-2008 Alan Stern + * Copyright (c) 2009 Samsung Electronics + * Author: Michal Nazarewicz + * Copyright (c) 2019-2024 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +#define UMS_MAX_LUN 1 // Only 1 disk/partition for now. + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 // USBC. +#define USB_BULK_IN_FLAG 0x80 + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 // USBS. + +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + +#define UMS_DISK_LBA_SHIFT 9 +#define UMS_DISK_LBA_SIZE (1 << UMS_DISK_LBA_SHIFT) + +#define UMS_DISK_MAX_IO_TRANSFER_64K (USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT) +#define UMS_DISK_MAX_IO_TRANSFER_32K (UMS_DISK_MAX_IO_TRANSFER_64K / 2) + +#define UMS_SCSI_TRANSFER_512K (0x80000 >> UMS_DISK_LBA_SHIFT) + +#define UMS_EP_OUT_MAX_XFER (USB_EP_BULK_OUT_MAX_XFER) + +// Length of a SCSI Command Data Block. +#define SCSI_MAX_CMD_SZ 16 + +// SCSI device types +#define SCSI_TYPE_DISK 0x00 + +// SCSI commands. +#define SC_FORMAT_UNIT 0x04 +#define SC_INQUIRY 0x12 +#define SC_LOG_SENSE 0x4D +#define SC_MODE_SELECT_6 0x15 +#define SC_MODE_SELECT_10 0x55 +#define SC_MODE_SENSE_6 0x1A +#define SC_MODE_SENSE_10 0x5A +#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SC_READ_6 0x08 +#define SC_READ_10 0x28 +#define SC_READ_12 0xA8 +#define SC_READ_CAPACITY 0x25 +#define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_READ_HEADER 0x44 +#define SC_READ_TOC 0x43 +#define SC_RELEASE 0x17 +#define SC_REQUEST_SENSE 0x03 +#define SC_RESERVE 0x16 +#define SC_SEND_DIAGNOSTIC 0x1D +#define SC_START_STOP_UNIT 0x1B +#define SC_SYNCHRONIZE_CACHE 0x35 +#define SC_TEST_UNIT_READY 0x00 +#define SC_VERIFY 0x2F +#define SC_WRITE_6 0x0A +#define SC_WRITE_10 0x2A +#define SC_WRITE_12 0xAA + +// SCSI Sense Key/Additional Sense Code/ASC Qualifier values. +#define SS_NO_SENSE 0x0 +#define SS_COMMUNICATION_FAILURE 0x40800 +#define SS_INVALID_COMMAND 0x52000 +#define SS_INVALID_FIELD_IN_CDB 0x52400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x52100 +#define SS_MEDIUM_NOT_PRESENT 0x23A00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x55302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x62800 +#define SS_RESET_OCCURRED 0x62900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x53900 +#define SS_UNRECOVERED_READ_ERROR 0x31100 +#define SS_WRITE_ERROR 0x30C02 +#define SS_WRITE_PROTECTED 0x72700 + +#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + +enum ums_state { + UMS_STATE_NORMAL = 0, + UMS_STATE_ABORT_BULK_OUT, + UMS_STATE_PROTOCOL_RESET, + UMS_STATE_EXIT, + UMS_STATE_TERMINATED +}; + +enum ums_result { + UMS_RES_OK = 0, + UMS_RES_IO_ERROR = -5, + UMS_RES_TIMEOUT = -3, + UMS_RES_PROT_FATAL = -4, + UMS_RES_INVALID_ARG = -22 +}; + + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +enum buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +typedef struct _bulk_recv_pkt_t { + u32 Signature; // 'USBC'. + u32 Tag; // Unique per command id. + u32 DataTransferLength; // Size of the data. + u8 Flags; // Direction in bit 7. + u8 Lun; // LUN (normally 0). + u8 Length; // Of the CDB, <= SCSI_MAX_CMD_SZ. + u8 CDB[16]; // Command Data Block. +} bulk_recv_pkt_t; + +typedef struct _bulk_send_pkt_t { + u32 Signature; // 'USBS'. + u32 Tag; // Same as original command. + u32 Residue; // Amount not transferred. + u8 Status; +} bulk_send_pkt_t; + +typedef struct _logical_unit_t +{ + sdmmc_t *sdmmc; + sdmmc_storage_t *storage; + + u32 num_sectors; + u32 offset; + + int unmounted; + + u32 ro; + u32 type; + u32 partition; + u32 removable; + u32 prevent_medium_removal; + + u32 info_valid; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; +} logical_unit_t; + +typedef struct _bulk_ctxt_t { + u32 bulk_in; + int bulk_in_status; + u32 bulk_in_length; + u32 bulk_in_length_actual; + u8 *bulk_in_buf; + enum buffer_state bulk_in_buf_state; + + u32 bulk_out; + int bulk_out_status; + u32 bulk_out_length; + u32 bulk_out_length_actual; + int bulk_out_ignore; + u8 *bulk_out_buf; + enum buffer_state bulk_out_buf_state; +} bulk_ctxt_t; + +typedef struct _usbd_gadget_ums_t { + bulk_ctxt_t bulk_ctxt; + + u32 cmnd_size; + u8 cmnd[SCSI_MAX_CMD_SZ]; + + u32 lun_idx; // lun index + logical_unit_t lun; + + enum ums_state state; // For exception handling. + + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + u32 residue; + u32 usb_amount_left; + bool cbw_req_queued; + + u32 phase_error; + u32 short_packet_received; + + int thread_wakeup_needed; + int can_stall; + + u32 timeouts; + bool xusb; + + void (*system_maintenance)(bool); + void *label; + void (*set_text)(void *, const char *); +} usbd_gadget_ums_t; + +static usb_ops_t usb_ops; + +static inline void put_array_le_to_be16(u16 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 8; + _p[1] = val; +} + +static inline void put_array_le_to_be32(u32 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 24; + _p[1] = val >> 16; + _p[2] = val >> 8; + _p[3] = val; +} + +static inline u16 get_array_be_to_le16(const void *p) +{ + const u8 *_p = p; + u16 val = _p[0] << 8 | _p[1]; + return val; +} + +static inline u32 get_array_be_to_le24(const void *p) +{ + const u8 *_p = p; + u32 val = (_p[0] << 16) | (_p[1] << 8) | _p[2]; + return val; +} + +static inline u32 get_array_be_to_le32(const void *p) +{ + const u8 *_p = p; + u32 val = (_p[0] << 24) | (_p[1] << 16) | (_p[2] << 8) | _p[3]; + return val; +} + +static void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state) +{ + /* Do nothing if a higher-priority exception is already in progress. + * If a lower-or-equal priority exception is in progress, preempt it + * and notify the main thread by sending it a signal. */ + if (ums->state <= new_state) { + ums->state = new_state; + ums->thread_wakeup_needed = 1; + } +} + +static void _handle_ep0_ctrl(usbd_gadget_ums_t *ums) +{ + if (usb_ops.usbd_handle_ep0_ctrl_setup()) + raise_exception(ums, UMS_STATE_PROTOCOL_RESET); +} + +static int _wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums) +{ + /* usbd_set_ep_wedge(bulk_ctxt->bulk_in); */ + + return UMS_RES_OK; +} + +static int _set_ep_stall(u32 ep) +{ + usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_STALL); + + return UMS_RES_OK; +} + +static int _clear_ep_stall(u32 ep) +{ + usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_CLEAR); + + return UMS_RES_OK; +} + +static void _flush_endpoint(u32 ep) +{ + if (usb_ops.usbd_flush_endpoint) + usb_ops.usbd_flush_endpoint(ep); +} + +static void _transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, u32 sync_timeout) +{ + if (ep == bulk_ctxt->bulk_in) + { + bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_write( + bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length, + &bulk_ctxt->bulk_in_length_actual, sync_timeout); + + if (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR) + { + ums->set_text(ums->label, "#FFDD00 Error:# EP IN transfer!"); + _flush_endpoint(bulk_ctxt->bulk_in); + } + else if (bulk_ctxt->bulk_in_status == USB2_ERROR_XFER_NOT_ALIGNED) + ums->set_text(ums->label, "#FFDD00 Error:# EP IN Buffer not aligned!"); + + if (sync_timeout) + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + } + else + { + bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read( + bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, + &bulk_ctxt->bulk_out_length_actual, sync_timeout); + + if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) + { + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT transfer!"); + _flush_endpoint(bulk_ctxt->bulk_out); + } + else if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_NOT_ALIGNED) + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT Buffer not aligned!"); + + if (sync_timeout) + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; + } +} + +static void _transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read_big( + bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, + &bulk_ctxt->bulk_out_length_actual); + + if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) + { + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT transfer!"); + _flush_endpoint(bulk_ctxt->bulk_out); + } + + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; +} + +static void _transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, u32 sync_timeout) +{ + if (ep == bulk_ctxt->bulk_in) + { + bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_writing_finish( + &bulk_ctxt->bulk_in_length_actual, sync_timeout); + + if (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR) + { + ums->set_text(ums->label, "#FFDD00 Error:# EP IN transfer!"); + _flush_endpoint(bulk_ctxt->bulk_in); + } + + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + } + else + { + bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_reading_finish( + &bulk_ctxt->bulk_out_length_actual, sync_timeout); + + if (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR) + { + ums->set_text(ums->label, "#FFDD00 Error:# EP OUT transfer!"); + _flush_endpoint(bulk_ctxt->bulk_out); + } + + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; + } +} + +static void _reset_buffer(bulk_ctxt_t *bulk_ctxt, u32 ep) +{ + if (ep == bulk_ctxt->bulk_in) + bulk_ctxt->bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; + else + bulk_ctxt->bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; +} + +/* + * The following are old data based on max 64KB SCSI transfers. + * The endpoint xfer is actually 41.2 MB/s and SD card max 39.2 MB/s, with higher SCSI + * transfers, but the concurrency still helps and increases speeds by 20%. + * + * Concurrency of the SDMMC and USB xfers is very important with no cache. + * The worst offender being the SD card. We are already limited by bus, so + * concurrency helps minimize the SDMMC overhead. + * Max achieved bulk endpoint rate on a Tegra X1 and USB2.0 is 39.4 MB/s. + * + * USB bulk endpoint raw max transfer rate: + * 39.4MB/S - SCSI 128KB. + * 38.2MB/s - SCSI 64KB. + * + * 128 KB, 64 KB, 32 KB, 16 KB, 8 KB - Internal SDMMC I\O Sizes + * ------------------------------------------------------------------------------------- + * eMMC - Toshiba - 4MB reads: 314.8 MB/s: + * 225.9 MB/s, 168.6 MB/s, 114.7 MB/s, 86.4 MB/s, 50.3 MB/s - RAW SDMMC. + * 33.5 MB/s, 31.9 MB/s, 29.3 MB/s, 27.1 MB/s, 22.1 MB/s - SCSI 128KB, No concurrency. + * 33.5 MB/s, 35.3 MB/s, 36.3 MB/s, 37.3 MB/s, 37.8 MB/s - SCSI 128KB, Concurrency. + * --.- --/-, 31.1 MB/s, 28.7 MB/s, 26.5 MB/s, 21.7 MB/s - SCSI 64KB, No concurrency. + * --.- --/-, 31.1 MB/s, 32.7 MB/s, 34.4 MB/s, 35.0 MB/s - SCSI 64KB, Concurrency. + * + * SD Card - Samsung Evo+ 128GB - 4MB reads: 91.6 MB/s: + * 72.6 MB/s, 62.8 MB/s, 47.4 MB/s, 31.1 MB/s, 18.5 MB/s - RAW SDMMC. + * 25.5 MB/s, 24.2 MB/s, 21.5 MB/s, 17.4 MB/s, 12.6 MB/s - SCSI 128KB, No concurrency. + * 25.5 MB/s, 30.0 MB/s, 32.6 MB/s, 28.3 MB/s, 18.0 MB/s - SCSI 128KB, Concurrency. + * --.- --/-, 23.8 MB/s, 21.2 MB/s, 17.1 MB/s, 12.5 MB/s - SCSI 64KB, No concurrency. + * --.- --/-, 23.8 MB/s, 27.2 MB/s, 25.8 MB/s, 17.5 MB/s - SCSI 64KB, Concurrency. + */ + +static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u32 lba_offset; + bool first_read = true; + u8 *sdmmc_buf = (u8 *)SDXC_BUF_ALIGNED; + + // Get the starting LBA and check that it's not too big. + if (ums->cmnd[0] == SC_READ_6) + lba_offset = get_array_be_to_le24(&ums->cmnd[1]); + else + { + lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + + // We allow DPO and FUA bypass cache bits, but we don't use them. + if ((ums->cmnd[1] & ~0x18) != 0) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + } + if (lba_offset >= ums->lun.num_sectors) + { + ums->set_text(ums->label, "#FF8000 Warn:# Read - Out of range! Host notified."); + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return UMS_RES_INVALID_ARG; + } + + // Check that request data size is not 0. + u32 amount_left = ums->data_size_from_cmnd >> UMS_DISK_LBA_SHIFT; + if (!amount_left) + return UMS_RES_IO_ERROR; // No default reply. + + // Limit IO transfers based on request for faster concurrent reads. + u32 max_io_transfer = (amount_left >= UMS_SCSI_TRANSFER_512K) ? + UMS_DISK_MAX_IO_TRANSFER_64K : UMS_DISK_MAX_IO_TRANSFER_32K; + + while (true) + { + // Max io size and end sector limits. + u32 amount = MIN(amount_left, max_io_transfer); + amount = MIN(amount, ums->lun.num_sectors - lba_offset); + + // Check if it is a read past the end sector. + if (!amount) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + + bulk_ctxt->bulk_in_length = 0; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + break; + } + + // Do the SDMMC read. + if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf)) + amount = 0; + + // Wait for the async USB transfer to finish. + if (!first_read) + _transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED); + + lba_offset += amount; + amount_left -= amount; + ums->residue -= amount << UMS_DISK_LBA_SHIFT; + + bulk_ctxt->bulk_in_length = amount << UMS_DISK_LBA_SHIFT; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + bulk_ctxt->bulk_in_buf = sdmmc_buf; + + // If an error occurred, report it and its position. + if (!amount) + { + ums->set_text(ums->label, "#FFDD00 Error:# SDMMC Read!"); + ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + // Last SDMMC read. Last part will be sent by the finish reply function. + if (!amount_left) + break; + + // Start the USB transfer. + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_START); + first_read = false; + + // Increment our buffer to read new data. + sdmmc_buf += amount << UMS_DISK_LBA_SHIFT; + } + + return UMS_RES_IO_ERROR; // No default reply. +} + +/* + * Writes are another story. + * Tests showed that big writes are faster than concurrent 32K usb reads + writes. + * The only thing that can help here is caching the writes. But for the simplicity + * of this implementation it will not be implemented yet. + */ + +static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + static char txt_buf[256]; + u32 amount_left_to_req, amount_left_to_write; + u32 usb_lba_offset, lba_offset; + u32 amount; + + if (ums->lun.ro) + { + ums->set_text(ums->label, "#FF8000 Warn:# Write - Read only! Host notified."); + ums->lun.sense_data = SS_WRITE_PROTECTED; + + return UMS_RES_INVALID_ARG; + } + + if (ums->cmnd[0] == SC_WRITE_6) + lba_offset = get_array_be_to_le24(&ums->cmnd[1]); + else + { + lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + + // We allow DPO and FUA bypass cache bits. We only implement FUA by performing synchronous output. + if (ums->cmnd[1] & ~0x18) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + } + + // Check that starting LBA is not past the end sector offset. + if (lba_offset >= ums->lun.num_sectors) + { + ums->set_text(ums->label, "#FF8000 Warn:# Write - Out of range! Host notified."); + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return UMS_RES_INVALID_ARG; + } + + // Carry out the file writes. + usb_lba_offset = lba_offset; + amount_left_to_req = ums->data_size_from_cmnd; + amount_left_to_write = ums->data_size_from_cmnd; + + while (amount_left_to_write > 0) + { + // Queue a request for more data from the host. + if (amount_left_to_req > 0) + { + + // Limit write to max supported read from EP OUT. + amount = MIN(amount_left_to_req, UMS_EP_OUT_MAX_XFER); + + if (usb_lba_offset >= ums->lun.num_sectors) + { + ums->set_text(ums->label, "#FFDD00 Error:# Write - Past last sector!"); + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = usb_lba_offset; + ums->lun.info_valid = 1; + break; + } + + // Get the next buffer. + usb_lba_offset += amount >> UMS_DISK_LBA_SHIFT; + ums->usb_amount_left -= amount; + amount_left_to_req -= amount; + + bulk_ctxt->bulk_out_length = amount; + + _transfer_out_big_read(ums, bulk_ctxt); + } + + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL) + { + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + // Did something go wrong with the transfer?. + if (bulk_ctxt->bulk_out_status != 0) + { + ums->lun.sense_data = SS_COMMUNICATION_FAILURE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + + s_printf(txt_buf, "#FFDD00 Error:# Write - Comm failure %d!", bulk_ctxt->bulk_out_status); + ums->set_text(ums->label, txt_buf); + break; + } + + amount = bulk_ctxt->bulk_out_length_actual; + + if ((ums->lun.num_sectors - lba_offset) < (amount >> UMS_DISK_LBA_SHIFT)) + { + DPRINTF("write %X @ %X beyond end %X\n", amount, lba_offset, ums->lun.num_sectors); + amount = (ums->lun.num_sectors - lba_offset) << UMS_DISK_LBA_SHIFT; + } + + /* + * Don't accept excess data. The spec doesn't say + * what to do in this case. We'll ignore the error. + */ + amount = MIN(amount, bulk_ctxt->bulk_out_length); + + // Don't write a partial block. + amount -= (amount & 511); + if (amount == 0) + goto empty_write; + + // Perform the write. + if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset, + amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf)) + amount = 0; + +DPRINTF("file write %X @ %X\n", amount, lba_offset); + + lba_offset += amount >> UMS_DISK_LBA_SHIFT; + amount_left_to_write -= amount; + ums->residue -= amount; + + // If an error occurred, report it and its position. + if (!amount) + { + ums->set_text(ums->label, "#FFDD00 Error:# SDMMC Write!"); + ums->lun.sense_data = SS_WRITE_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + empty_write: + // Did the host decide to stop early? + if (bulk_ctxt->bulk_out_length_actual < bulk_ctxt->bulk_out_length) + { + ums->set_text(ums->label, "#FFDD00 Error:# Empty Write!"); + ums->short_packet_received = 1; + break; + } + } + } + + return UMS_RES_IO_ERROR; // No default reply. +} + +static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + // Check that start LBA is past the end sector offset. + u32 lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + if (lba_offset >= ums->lun.num_sectors) + { + ums->set_text(ums->label, "#FF8000 Warn:# Verif - Out of range! Host notified."); + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return UMS_RES_INVALID_ARG; + } + + // We allow DPO but we don't implement it. Check that nothing else is enabled. + if (ums->cmnd[1] & ~0x10) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + u32 verification_length = get_array_be_to_le16(&ums->cmnd[7]); + if (verification_length == 0) + return UMS_RES_IO_ERROR; // No default reply. + + u32 amount; + while (verification_length > 0) + { + + // Limit to EP buffer size and end sector offset. + amount = MIN(verification_length, USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT); + amount = MIN(amount, ums->lun.num_sectors - lba_offset); + if (amount == 0) { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)) + amount = 0; + +DPRINTF("File read %X @ %X\n", amount, lba_offset); + + if (!amount) + { + ums->set_text(ums->label, "#FFDD00 Error:# File verify!"); + ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + lba_offset += amount; + verification_length -= amount; + } + return UMS_RES_OK; +} + +static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + + memset(buf, 0, 36); + + // Enable Vital Product Data (EVPD) and Unit Serial Number. + if (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) + { + buf[0] = 0; + buf[1] = ums->cmnd[2]; + buf[2] = 0; + buf[3] = 20; // Additional length. + + buf += 4; + s_printf((char *)buf, "%04X%s", + ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC "); + + switch (ums->lun.partition) + { + case 0: + strcpy((char *)buf + strlen((char *)buf), "RAW"); + break; + case EMMC_GPP + 1: + s_printf((char *)buf + strlen((char *)buf), "GPP"); + break; + case EMMC_BOOT0 + 1: + s_printf((char *)buf + strlen((char *)buf), "BOOT0"); + break; + case EMMC_BOOT1 + 1: + s_printf((char *)buf + strlen((char *)buf), "BOOT1"); + break; + } + + for (u32 i = strlen((char *)buf); i < 20; i++) + buf[i] = ' '; + + return 24; + } + else /* if (ums->cmnd[1] == 0 && ums->cmnd[2] == 0) */ // Standard inquiry. + { + buf[0] = SCSI_TYPE_DISK; + buf[1] = ums->lun.removable ? 0x80 : 0; + buf[2] = 6; // ANSI INCITS 351-2001 (SPC-2).////////SPC2: 4, SPC4: 6 + buf[3] = 2; // SCSI-2 INQUIRY data format. + buf[4] = 31; // Additional length. + // buf5-7: No special options. + + // Vendor ID. Max 8 chars. + buf += 8; + strcpy((char *)buf, "hekate"); + + // Product ID. Max 16 chars. + buf += 8; + switch (ums->lun.partition) + { + case 0: + s_printf((char *)buf, "%s", "SD RAW"); + break; + case EMMC_GPP + 1: + s_printf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "GPP"); + break; + case EMMC_BOOT0 + 1: + s_printf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT0"); + break; + case EMMC_BOOT1 + 1: + s_printf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT1"); + break; + } + + // Rev ID. Max 4 chars. + buf += 16; + strcpy((char *)buf, "1.00"); + + return 36; + } +} + +static int _scsi_request_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u32 sd, sdinfo; + int valid; + + sd = ums->lun.sense_data; + sdinfo = ums->lun.sense_data_info; + valid = ums->lun.info_valid << 7; + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + + memset(buf, 0, 18); + buf[0] = valid | 0x70; // Valid, current error. + buf[2] = SK(sd); + put_array_le_to_be32(sdinfo, &buf[3]); // Sense information. + buf[7] = 18 - 8; // Additional sense length. + buf[12] = ASC(sd); + buf[13] = ASCQ(sd); + + return 18; +} + +static int _scsi_read_capacity(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u32 lba = get_array_be_to_le32(&ums->cmnd[2]); + int pmi = ums->cmnd[8]; + + // Check the PMI and LBA fields. + if (pmi > 1 || (pmi == 0 && lba != 0)) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + put_array_le_to_be32(ums->lun.num_sectors - 1, &buf[0]); // Max logical block. + put_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]); // Block length. + + return 8; +} + +static int _scsi_log_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u8 *buf0 = buf; + bool valid_page = false; + + u8 pc = ums->cmnd[2] >> 6; + u8 page_code = ums->cmnd[2] & 0x3F; + u8 sub_page_code = ums->cmnd[3]; + + if (ums->cmnd[1] & 1) + { + ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + + return UMS_RES_INVALID_ARG; + } + + if (pc != 1) // Current cumulative values. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + memset(buf, 0, 8); + if (page_code == 0x00 && !sub_page_code) // Supported pages. + { + valid_page = true; + buf[0] = 0x00; // Page code. + buf += 4; + + buf[0] = 0x00; // Page 0. + buf[1] = 0x0D; // Page 1. + + buf += 2; + } + else if (page_code == 0x0d && !sub_page_code) // Temperature. + { + valid_page = true; + buf[0] = 0x0D; + buf += 4; + + put_array_le_to_be16(0, &buf[0]); // Param code. + buf[2] = 1; // Param control byte. + buf[3] = 2; // Param length. + buf[4] = 0; // Reserved. + buf[5] = 35; // Temperature (C) current (PCB here). + + put_array_le_to_be16(0, &buf[6]); // PARAMETER CODE + buf[8] = 1; // Param control byte. + buf[9] = 2; // Param length. + buf[10] = 0; // Reserved. + buf[11] = 60; // Temperature (C) reference. + + buf += 12; + } + + // Check that a valid page mode data length was requested. + u32 len = buf - buf0; + if (!valid_page) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + put_array_le_to_be16(len - 4, &buf0[2]); + + return len; +} + +static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u8 *buf0 = buf; + bool valid_page = false; + + u8 pc = ums->cmnd[2] >> 6; + u8 page_code = ums->cmnd[2] & 0x3F; + bool changeable_values = pc == 1; + bool all_pages = page_code == 0x3F; + + if ((ums->cmnd[1] & ~0x08) != 0) // Mask away DBD. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + if (pc == 3) + { + ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + + return UMS_RES_INVALID_ARG; + } + + /* Write the mode parameter header. Fixed values are: default + * medium type, no cache control (DPOFUA), and no block descriptors. + * The only variable value is the WriteProtect bit. We will fill in + * the mode data length later. */ + memset(buf, 0, 8); + if (ums->cmnd[0] == SC_MODE_SENSE_6) + { + buf[2] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. + buf += 4; + } + else // SC_MODE_SENSE_10. + { + buf[3] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. + buf += 8; + } + + // The only page we support is the Caching page. + // What about x1C + if (page_code == 0x08 || all_pages) + { + valid_page = true; + buf[0] = 0x08; // Page code. + buf[1] = 18; // Page length. + memset(buf + 2, 0, 18); // Set all parameters to 0. + + // None of the fields are changeable. + if (!changeable_values) + { + // Write Cache enable, Read Cache not disabled, Multiplication Factor off. + buf[2] = 0x04; + + // Multiplication Factor is disabled, so all values below are 1x LBA. + put_array_le_to_be16(0xFFFF, &buf[4]); // Disable Prefetch if >32MB. + put_array_le_to_be16(0x0000, &buf[6]); // Minimum Prefetch 0MB. + put_array_le_to_be16(0xFFFF, &buf[8]); // Maximum Prefetch 32MB. + put_array_le_to_be16(0xFFFF, &buf[10]); // Maximum Prefetch ceiling 32MB. + } + + buf += 20; + } + + // Check that a valid page mode data length was requested. + u32 len = buf - buf0; + if (!valid_page) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + // Store the mode data length. + if (ums->cmnd[0] == SC_MODE_SENSE_6) + buf0[0] = len - 1; + else + put_array_le_to_be16(len - 2, buf0); + + return len; +} + +static int _scsi_start_stop(usbd_gadget_ums_t *ums) +{ + int loej, start; + + if (!ums->lun.removable) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + + return UMS_RES_INVALID_ARG; + } + else if ((ums->cmnd[1] & ~0x01) != 0 || // Mask away Immed. + (ums->cmnd[4] & ~0x03) != 0) // Mask LoEj, Start. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + loej = ums->cmnd[4] & 0x02; + start = ums->cmnd[4] & 0x01; + + // We do not support re-mounting. + if (start) + { + if (ums->lun.unmounted) + { + ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; + + return UMS_RES_INVALID_ARG; + } + + return UMS_RES_OK; + } + + // Check if we are allowed to unload the media. + if (ums->lun.prevent_medium_removal) + { + ums->set_text(ums->label, "#C7EA46 Status:# Unload attempt prevented"); + ums->lun.sense_data = SS_MEDIUM_REMOVAL_PREVENTED; + + return UMS_RES_INVALID_ARG; + } + + if (!loej) + return UMS_RES_OK; + + // Unmount means we exit UMS because of ejection. + ums->lun.unmounted = 1; + + return UMS_RES_OK; +} + +static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) +{ + int prevent; + + if (!ums->lun.removable) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + + return UMS_RES_INVALID_ARG; + } + + prevent = ums->cmnd[4] & 0x01; + if ((ums->cmnd[4] & ~0x01) != 0) // Mask away Prevent. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + + // Notify for possible unmounting? + // Normally we sync here but we do synced writes to SDMMC. + if (ums->lun.prevent_medium_removal && !prevent) { /* Do nothing */ } + + ums->lun.prevent_medium_removal = prevent; + + return UMS_RES_OK; +} + +static int _scsi_read_format_capacities(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor. + buf += 4; + + put_array_le_to_be32(ums->lun.num_sectors, &buf[0]); // Number of blocks. + put_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]); // Block length. + buf[4] = 0x02; // Current capacity. + + return 12; +} + +// Check whether the command is properly formed and whether its data size +// and direction agree with the values we already have. +static int _check_scsi_cmd(usbd_gadget_ums_t *ums, u32 cmnd_size, + enum data_direction data_dir, u32 mask, + int needs_medium) +{ +//const char dirletter[4] = {'u', 'o', 'i', 'n'}; +DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", + ums->cmnd[0], cmnd_size, dirletter[(int)ums->data_dir], + ums->data_size_from_cmnd, ums->cmnd_size, + dirletter[(int)data_dir], ums->data_size); + + // We can't reply if we don't know the direction and size. + if (ums->data_size_from_cmnd == 0) + data_dir = DATA_DIR_NONE; + + // This is a phase error but we continue and only transfer as much we can. + if (ums->data_size < ums->data_size_from_cmnd) + { + ums->data_size_from_cmnd = ums->data_size; + ums->phase_error = 1; + } + + ums->residue = ums->data_size; + ums->usb_amount_left = ums->data_size; + + if (ums->data_dir != data_dir && ums->data_size_from_cmnd > 0) + { + ums->phase_error = 1; + + return UMS_RES_INVALID_ARG; + } + + // Cmd length verification. + if (cmnd_size != ums->cmnd_size) + { + + // Special case workaround for Windows and Xbox 360. + if (cmnd_size <= ums->cmnd_size) + cmnd_size = ums->cmnd_size; + else + { + ums->phase_error = 1; + + return UMS_RES_INVALID_ARG; + } + } + + // check that LUN ums->cmnd[1] >> 5 is 0 because of only one. + + if (ums->cmnd[0] != SC_REQUEST_SENSE) + { + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + } + + // If a unit attention condition exists, only INQUIRY and REQUEST SENSE + // commands are allowed. + if (ums->lun.unit_attention_data != SS_NO_SENSE && ums->cmnd[0] != SC_INQUIRY && + ums->cmnd[0] != SC_REQUEST_SENSE) + { + ums->lun.sense_data = ums->lun.unit_attention_data; + ums->lun.unit_attention_data = SS_NO_SENSE; + + return UMS_RES_INVALID_ARG; + } + + // Check that only command bytes listed in the mask are set. + ums->cmnd[1] &= 0x1F; // Mask away the LUN. + for (u32 i = 1; i < cmnd_size; ++i) + { + if (ums->cmnd[i] && !(mask & BIT(i))) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return UMS_RES_INVALID_ARG; + } + } + + // If the medium isn't mounted and the command needs to access it, return an error. + if (ums->lun.unmounted && needs_medium) + { + ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; + + return UMS_RES_INVALID_ARG; + } + + return UMS_RES_OK; +} + +static int _parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u32 len; + int reply = UMS_RES_INVALID_ARG; + + ums->phase_error = 0; + ums->short_packet_received = 0; + + switch (ums->cmnd[0]) + { + case SC_INQUIRY: + ums->data_size_from_cmnd = ums->cmnd[4]; + u32 mask = (1<<4); + if (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) // Inquiry S/N. + mask = (1<<1) | (1<<2) | (1<<4); + reply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, mask, 0); + if (reply == 0) + reply = _scsi_inquiry(ums, bulk_ctxt); + break; + + case SC_LOG_SENSE: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0); + if (reply == 0) + reply = _scsi_log_sense(ums, bulk_ctxt); + break; + + case SC_MODE_SELECT_6: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (1<<1) | (1<<4), 0); + if (reply == 0) + { + // We don't support MODE SELECT. + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = UMS_RES_INVALID_ARG; + } + break; + + case SC_MODE_SELECT_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (3<<7), 0); + if (reply == 0) + { + // We don't support MODE SELECT. + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = UMS_RES_INVALID_ARG; + } + break; + + case SC_MODE_SENSE_6: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (1<<4), 0); + if (reply == 0) + reply = _scsi_mode_sense(ums, bulk_ctxt); + break; + + case SC_MODE_SENSE_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0); + if (reply == 0) + reply = _scsi_mode_sense(ums, bulk_ctxt); + break; + + case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: + ums->data_size_from_cmnd = 0; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<4), 0); + if (reply == 0) + reply = _scsi_prevent_allow_removal(ums); + break; + + case SC_READ_6: + len = ums->cmnd[4]; + ums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT; + reply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_12: + ums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT; + reply = _check_scsi_cmd(ums, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_CAPACITY: + ums->data_size_from_cmnd = 8; + reply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (0xf<<2) | (1<<8), 1); + if (reply == 0) + reply = _scsi_read_capacity(ums, bulk_ctxt); + break; + case SC_READ_FORMAT_CAPACITIES: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (3<<7), 1); + if (reply == 0) + reply = _scsi_read_format_capacities(ums, bulk_ctxt); + break; + + case SC_REQUEST_SENSE: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<4), 0); + if (reply == 0) + reply = _scsi_request_sense(ums, bulk_ctxt); + break; + + case SC_START_STOP_UNIT: + ums->data_size_from_cmnd = 0; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<1) | (1<<4), 0); + if (reply == 0) + reply = _scsi_start_stop(ums); + break; + + case SC_SYNCHRONIZE_CACHE: + ums->data_size_from_cmnd = 0; + reply = _check_scsi_cmd(ums, 10, DATA_DIR_NONE, (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = 0; // Don't bother + break; + + case SC_TEST_UNIT_READY: + ums->data_size_from_cmnd = 0; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_NONE, 0, 1); + break; + + // This command is used by Windows. We support a minimal version and BytChk must be 0. + case SC_VERIFY: + ums->data_size_from_cmnd = 0; + reply = _check_scsi_cmd(ums, 10, DATA_DIR_NONE, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_verify(ums, bulk_ctxt); + break; + + case SC_WRITE_6: + len = ums->cmnd[4]; + ums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT; + reply = _check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + case SC_WRITE_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT; + reply = _check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + case SC_WRITE_12: + ums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT; + reply = _check_scsi_cmd(ums, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + // Mandatory commands that we don't implement. No need. + case SC_READ_HEADER: + case SC_READ_TOC: + case SC_FORMAT_UNIT: + case SC_RELEASE: + case SC_RESERVE: + case SC_SEND_DIAGNOSTIC: + default: + ums->data_size_from_cmnd = 0; + reply = _check_scsi_cmd(ums, ums->cmnd_size, DATA_DIR_UNKNOWN, 0xFF, 0); + if (reply == 0) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = UMS_RES_INVALID_ARG; + } + break; + } + + if (reply == UMS_RES_INVALID_ARG) + reply = 0; // Error reply length. + + // Set up reply buffer for _finish_reply(). Otherwise it's already set. + if (reply >= 0 && ums->data_dir == DATA_DIR_TO_HOST) + { + reply = MIN((u32)reply, ums->data_size_from_cmnd); + bulk_ctxt->bulk_in_length = reply; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + ums->residue -= reply; + } + + return UMS_RES_OK; +} + +static int _pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; // For the first iteration. + u32 current_len_to_keep = bulk_ctxt->bulk_in_length; + ums->usb_amount_left = current_len_to_keep + ums->residue; + + while (ums->usb_amount_left > 0) + { + u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); + memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep); + bulk_ctxt->bulk_in_length = nsend; + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA); + ums->usb_amount_left -= nsend; + current_len_to_keep = 0; + } + + return UMS_RES_OK; +} + +static int _throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + if (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY || ums->usb_amount_left > 0) + { + // Try to submit another request if we need one. + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_EMPTY && ums->usb_amount_left > 0) + { + u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); + + bulk_ctxt->bulk_out_length = amount; + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_DATA); + ums->usb_amount_left -= amount; + + return UMS_RES_OK; + } + + // Throw away the data in a filled buffer. + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL) + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + // A short packet or an error ends everything. + if (bulk_ctxt->bulk_out_length_actual != bulk_ctxt->bulk_out_length || + bulk_ctxt->bulk_out_status != USB_RES_OK) + { + raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); + return UMS_RES_PROT_FATAL; + } + } + return UMS_RES_OK; +} + +static int _finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + int rc = UMS_RES_OK; + + switch (ums->data_dir) { + case DATA_DIR_NONE: + break; // Nothing to send. + + // If this is a CB or CBI with an unknown command, we mustn't + // try to send or receive any data. Stall if we can and wait reset. + case DATA_DIR_UNKNOWN: + if (ums->can_stall) + { + _set_ep_stall(bulk_ctxt->bulk_out); + rc = _set_ep_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#FFDD00 Error:# Direction unknown. Stalled both EP!"); + } // Else do nothing. + break; + + // All but the last buffer of data have already been sent. + case DATA_DIR_TO_HOST: + if (ums->data_size) + { + // If there's no residue, simply send the last buffer. + if (!ums->residue) + { + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA); + + /* For Bulk-only, if we're allowed to stall then send the + * short packet and halt the bulk-in endpoint. If we can't + * stall, pad out the remaining data with 0's. */ + } + else if (ums->can_stall) + { + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA); + rc = _set_ep_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#FFDD00 Error:# Residue. Stalled EP IN!"); + } + else + rc = _pad_with_zeros(ums, bulk_ctxt); + } + + // In case we used SDMMC transfer, reset the buffer address. + _reset_buffer(bulk_ctxt, bulk_ctxt->bulk_in); + break; + + // We have processed all we want from the data the host has sent. + // There may still be outstanding bulk-out requests. + case DATA_DIR_FROM_HOST: + if (ums->residue) + { + if (ums->short_packet_received) // Did the host stop sending unexpectedly early? + { + raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); + rc = UMS_RES_PROT_FATAL; + } + else // We can't stall. Read in the excess data and throw it away. + rc = _throw_away_data(ums, bulk_ctxt); + } + + break; + } + + return rc; +} + +/* + * Medium ejection heuristics. + * + * Windows: + * Uses Start/Stop Unit. Only Stop with LoEj. Observed ONLY on very specific windows machines. + * Uses Prevent/Allow Medium Removal. (For big reads and ANY write.) //////Except trivial writes. Needs check with prefetch ON + * Sends Test Unit Ready every 1s at idle. (Needs 1 EP Timeout protection: 2s) + * Does not send data when ejects. In the case it does, + * it loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0 and only goes in J-State when it ejects. + * + * Linux: + * Uses Start/Stop Unit. Stops with LoEj when Media prevention is off. + * Uses Prevent/Allow Medium Removal. (For big read and any write.) + * Sends Test Unit Ready every 2s at idle. (Needs 2 EP Timeouts protection: 4s) + * Loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0. + * + * Mac OS: + * Uses Start/Stop. Stops with LoEj when Allow Medium Removal is enabled. + * Uses Prevent/Allow Medium Removal. (Properly. Enables at mount and only disables it when ejects.) + * Does not send Test Unit Ready at idle. But Prevent Medium Removal is enabled. + * Loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0. + */ + +static int _received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + // Was this a real packet? Should it be ignored? + if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore || ums->lun.unmounted) + { + if (bulk_ctxt->bulk_out_status || ums->lun.unmounted) + { + DPRINTF("USB: EP timeout (%d)\n", bulk_ctxt->bulk_out_status); + // In case we disconnected, exit UMS. + // Raise timeout if removable and didn't got a unit ready command inside 4s. + if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_EP_DISABLED || + (bulk_ctxt->bulk_out_status == USB_ERROR_TIMEOUT && ums->lun.removable && !ums->lun.prevent_medium_removal)) + { + if (bulk_ctxt->bulk_out_status == USB_ERROR_TIMEOUT) + { + if (usb_ops.usb_device_get_port_in_sleep()) + { + ums->set_text(ums->label, "#C7EA46 Status:# EP in sleep"); + ums->timeouts += 14; + } + else if (!ums->xusb) // Timeout only on USB2. + { + ums->timeouts += 4; + DPRINTF("USB: EP removable\n"); + } + } + else + { + gfx_printf("USB: EP disabled\n"); + msleep(500); + ums->timeouts += 4; + } + } + + if (ums->lun.unmounted) + { + ums->set_text(ums->label, "#C7EA46 Status:# Medium unmounted"); + ums->timeouts++; + if (!bulk_ctxt->bulk_out_status) + ums->timeouts += 3; + } + + if (ums->timeouts > 20) + raise_exception(ums, UMS_STATE_EXIT); + } + + if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore) + return UMS_RES_INVALID_ARG; + } + + // Clear request flag to allow a new one to be queued. + ums->cbw_req_queued = false; + + // Is the CBW valid? + bulk_recv_pkt_t *cbw = (bulk_recv_pkt_t *)bulk_ctxt->bulk_out_buf; + if (bulk_ctxt->bulk_out_length_actual != USB_BULK_CB_WRAP_LEN || cbw->Signature != USB_BULK_CB_SIG) + { + gfx_printf("USB: invalid CBW: len %X sig 0x%X\n", bulk_ctxt->bulk_out_length_actual, cbw->Signature); + + /* + * The Bulk-only spec says we MUST stall the IN endpoint + * (6.6.1), so it's unavoidable. It also says we must + * retain this state until the next reset, but there's + * no way to tell the controller driver it should ignore + * Clear-Feature(HALT) requests. + * + * We aren't required to halt the OUT endpoint; instead + * we can simply accept and discard any data received + * until the next reset. + */ + _wedge_bulk_in_endpoint(ums); + bulk_ctxt->bulk_out_ignore = 1; + return UMS_RES_INVALID_ARG; + } + + // Is the CBW meaningful? + if (cbw->Lun >= UMS_MAX_LUN || cbw->Flags & ~USB_BULK_IN_FLAG || + cbw->Length == 0 || cbw->Length > SCSI_MAX_CMD_SZ) + { + gfx_printf("USB: non-meaningful CBW: lun = %X, flags = 0x%X, cmdlen %X\n", + cbw->Lun, cbw->Flags, cbw->Length); + + /* We can do anything we want here, so let's stall the + * bulk pipes if we are allowed to. */ + if (ums->can_stall) + { + _set_ep_stall(bulk_ctxt->bulk_out); + _set_ep_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#FFDD00 Error:# CBW unknown - Stalled both EP!"); + } + + return UMS_RES_INVALID_ARG; + } + + // Save the command for later. + ums->cmnd_size = cbw->Length; + memcpy(ums->cmnd, cbw->CDB, ums->cmnd_size); + + if (cbw->Flags & USB_BULK_IN_FLAG) + ums->data_dir = DATA_DIR_TO_HOST; + else + ums->data_dir = DATA_DIR_FROM_HOST; + + ums->data_size = cbw->DataTransferLength; + + if (ums->data_size == 0) + ums->data_dir = DATA_DIR_NONE; + + ums->lun_idx = cbw->Lun; + ums->tag = cbw->Tag; + + if (!ums->lun.unmounted) + ums->timeouts = 0; + + return UMS_RES_OK; +} + +static int _get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + int rc = UMS_RES_OK; + + /* Wait for the next buffer to become available */ + // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY) + // { + // //wait irq. + // } + + bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; + + // Queue a request to read a Bulk-only CBW. + if (!ums->cbw_req_queued) + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD); + else + _transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD); + + /* + * On XUSB do not allow multiple requests for CBW to be done. + * This avoids an issue with some XHCI controllers and OS combos (e.g. ASMedia and Linux/Mac OS) + * which confuse that and concatenate an old CBW request with another write request (SCSI Write) + * and create a babble error (transmit overflow). + */ + if (ums->xusb) + ums->cbw_req_queued = true; + + /* We will drain the buffer in software, which means we + * can reuse it for the next filling. No need to advance + * next_buffhd_to_fill. */ + + /* Wait for the CBW to arrive */ + // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_FULL) + // { + // //wait irq. + // } + + rc = _received_cbw(ums, bulk_ctxt); + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + return rc; +} + +static void _send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 status = USB_STATUS_PASS; + u32 sd = ums->lun.sense_data; + + if (ums->phase_error) + { + ums->set_text(ums->label, "#FFDD00 Error:# Phase-error!"); + status = USB_STATUS_PHASE_ERROR; + sd = SS_INVALID_COMMAND; + } + else if (sd != SS_NO_SENSE) + { + DPRINTF("USB: CMD fail\n"); + status = USB_STATUS_FAIL; + DPRINTF("USB: Sense: SK x%02X, ASC x%02X, ASCQ x%02X; info x%X\n", + SK(sd), ASC(sd), ASCQ(sd), ums->lun.sense_data_info); + } + + // Store and send the Bulk-only CSW. + bulk_send_pkt_t *csw = (bulk_send_pkt_t *)bulk_ctxt->bulk_in_buf; + + csw->Signature = USB_BULK_CS_SIG; + csw->Tag = ums->tag; + csw->Residue = ums->residue; + csw->Status = status; + + bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN; + _transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_CMD); +} + +static void _handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + enum ums_state old_state; + + // Clear out the controller's fifos. + _flush_endpoint(bulk_ctxt->bulk_in); + _flush_endpoint(bulk_ctxt->bulk_out); + + /* Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. */ + + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + old_state = ums->state; + + if (old_state != UMS_STATE_ABORT_BULK_OUT) + { + ums->lun.prevent_medium_removal = 0; + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.unit_attention_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + } + + ums->state = UMS_STATE_NORMAL; + + // Carry out any extra actions required for the exception. + switch (old_state) + { + case UMS_STATE_NORMAL: + break; + case UMS_STATE_ABORT_BULK_OUT: + _send_status(ums, bulk_ctxt); + break; + + case UMS_STATE_PROTOCOL_RESET: + /* In case we were forced against our will to halt a + * bulk endpoint, clear the halt now. (The SuperH UDC + * requires this.) */ + if (bulk_ctxt->bulk_out_ignore) + { + bulk_ctxt->bulk_out_ignore = 0; + _clear_ep_stall(bulk_ctxt->bulk_in); + } + ums->lun.unit_attention_data = SS_RESET_OCCURRED; + break; + + case UMS_STATE_EXIT: + ums->state = UMS_STATE_TERMINATED; // Stop the thread. + break; + + default: + break; + } +} + +static inline void _system_maintainance(usbd_gadget_ums_t *ums) +{ + static u32 timer_dram = 0; + static u32 timer_status_bar = 0; + + u32 time = get_tmr_ms(); + + if (timer_status_bar < time) + { + ums->system_maintenance(true); + timer_status_bar = get_tmr_ms() + 30000; + } + else if (timer_dram < time) + { + minerva_periodic_training(); + timer_dram = get_tmr_ms() + EMC_PERIODIC_TRAIN_MS; + } +} + +int usb_device_gadget_ums(usb_ctxt_t *usbs) +{ + int res = 0; + usbd_gadget_ums_t ums = {0}; + + // Get USB Controller ops. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210) + usb_device_get_ops(&usb_ops); + else + { + ums.xusb = true; + xusb_device_get_ops(&usb_ops); + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); + + if (usb_ops.usb_device_init()) + { + usb_ops.usbd_end(false, true); + return 1; + } + + ums.state = UMS_STATE_NORMAL; + ums.can_stall = 0; + + ums.bulk_ctxt.bulk_in = USB_EP_BULK_IN; + ums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; + + ums.bulk_ctxt.bulk_out = USB_EP_BULK_OUT; + ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; + + // Set LUN parameters. + ums.lun.ro = usbs->ro; + ums.lun.type = usbs->type; + ums.lun.partition = usbs->partition; + ums.lun.num_sectors = usbs->sectors; + ums.lun.offset = usbs->offset; + ums.lun.removable = 1; // Always removable to force OSes to use prevent media removal. + ums.lun.unit_attention_data = SS_RESET_OCCURRED; + + // Set system functions + ums.label = usbs->label; + ums.set_text = usbs->set_text; + ums.system_maintenance = usbs->system_maintenance; + + ums.set_text(ums.label, "#C7EA46 Status:# Mounting disk"); + + // Initialize sdmmc. + if (usbs->type == MMC_SD) + { + sd_end(); + if (!sd_mount()) + { + ums.set_text(ums.label, "#FFDD00 Failed to init SD!#"); + res = 1; + goto init_fail; + } + sd_unmount(); + + ums.lun.sdmmc = &sd_sdmmc; + ums.lun.storage = &sd_storage; + } + else + { + if (!emmc_initialize(false)) + { + ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#"); + res = 1; + goto init_fail; + } + emmc_set_partition(ums.lun.partition - 1); + + ums.lun.sdmmc = &emmc_sdmmc; + ums.lun.storage = &emmc_storage; + } + + ums.set_text(ums.label, "#C7EA46 Status:# Waiting for connection"); + + // Initialize Control Endpoint. + if (usb_ops.usb_device_enumerate(USB_GADGET_UMS)) + goto usb_enum_error; + + ums.set_text(ums.label, "#C7EA46 Status:# Waiting for LUN"); + + if (usb_ops.usb_device_class_send_max_lun(0)) // One device for now. + goto usb_enum_error; + + ums.set_text(ums.label, "#C7EA46 Status:# Started UMS"); + + // If partition sectors are not set get them from hardware. + if (!ums.lun.num_sectors) + { + if (usbs->type == MMC_EMMC && (ums.lun.partition - 1)) // eMMC BOOT0/1. + ums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8; + else + ums.lun.num_sectors = ums.lun.storage->sec_cnt; // eMMC GPP or SD. + } + + do + { + // Do DRAM training and update system tasks. + _system_maintainance(&ums); + + // Check for force unmount button combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + // Check if we are allowed to unload the media. + if (ums.lun.prevent_medium_removal) + ums.set_text(ums.label, "#C7EA46 Status:# Unload attempt prevented"); + else + break; + } + + if (ums.state != UMS_STATE_NORMAL) + { + _handle_exception(&ums, &ums.bulk_ctxt); + continue; + } + + _handle_ep0_ctrl(&ums); + + if (_get_next_command(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + _handle_ep0_ctrl(&ums); + + _parse_scsi_cmd(&ums, &ums.bulk_ctxt); + + if (ums.state > UMS_STATE_NORMAL) + continue; + + _handle_ep0_ctrl(&ums); + + if (_finish_reply(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + _send_status(&ums, &ums.bulk_ctxt); + } while (ums.state != UMS_STATE_TERMINATED); + + if (ums.lun.prevent_medium_removal) + ums.set_text(ums.label, "#FFDD00 Error:# Disk unsafely ejected"); + else + ums.set_text(ums.label, "#C7EA46 Status:# Disk ejected"); + goto exit; + +usb_enum_error: + ums.set_text(ums.label, "#FFDD00 Error:# Timed out or canceled!"); + res = 1; + +exit: + if (ums.lun.type == MMC_EMMC) + emmc_end(); + +init_fail: + usb_ops.usbd_end(true, false); + + return res; +} diff --git a/bdk/usb/usb_t210.h b/bdk/usb/usb_t210.h new file mode 100644 index 0000000..3485a58 --- /dev/null +++ b/bdk/usb/usb_t210.h @@ -0,0 +1,296 @@ +/* + * Enhanced & eXtensible USB device (EDCI & XDCI) driver for Tegra X1 + * + * Copyright (c) 2019-2021 CTCaer + * + * 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 _USB_T210_H_ +#define _USB_T210_H_ + +#include + +/* EHCI USB */ + +/* General USB registers */ +#define USB1_IF_USB_SUSP_CTRL 0x400 +#define SUSP_CTRL_USB_WAKE_ON_CNNT_EN_DEV BIT(3) +#define SUSP_CTRL_USB_WAKE_ON_DISCON_EN_DEV BIT(4) +#define SUSP_CTRL_USB_PHY_CLK_VALID BIT(7) +#define SUSP_CTRL_UTMIP_RESET BIT(11) +#define SUSP_CTRL_UTMIP_PHY_ENB BIT(12) +#define SUSP_CTRL_UTMIP_UTMIP_SUSPL1_SET BIT(25) +#define USB1_IF_USB_PHY_VBUS_SENSORS 0x404 +#define USB1_UTMIP_XCVR_CFG0 0x808 +#define USB1_UTMIP_BIAS_CFG0 0x80C +#define USB1_UTMIP_HSRX_CFG0 0x810 +#define USB1_UTMIP_HSRX_CFG1 0x814 +#define USB1_UTMIP_TX_CFG0 0x820 +#define USB1_UTMIP_MISC_CFG1 0x828 +#define USB1_UTMIP_DEBOUNCE_CFG0 0x82C +#define USB1_UTMIP_BAT_CHRG_CFG0 0x830 +#define BAT_CHRG_CFG0_PWRDOWN_CHRG BIT(0) +#define BAT_CHRG_CFG0_OP_SRC_EN BIT(3) +#define USB1_UTMIP_SPARE_CFG0 0x834 +#define USB1_UTMIP_XCVR_CFG1 0x838 +#define USB1_UTMIP_BIAS_CFG1 0x83C +#define USB1_UTMIP_BIAS_CFG2 0x850 +#define USB1_UTMIP_XCVR_CFG2 0x854 +#define USB1_UTMIP_XCVR_CFG3 0x858 + +/* USB Queue Head Descriptor */ +#define USB2_QH_USB2D_QH_EP_BASE (USB_BASE + 0x1000) +#define USB_QHD_EP_CAP_IOS_ENABLE BIT(15) +#define USB_QHD_EP_CAP_MAX_PKT_LEN_MASK 0x7FF +#define USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS BIT(29) +#define USB_QHD_EP_CAP_MULTI_NON_ISO (0 << 30) +#define USB_QHD_EP_CAP_MULTI_1 (1 << 30) +#define USB_QHD_EP_CAP_MULTI_2 (2 << 30) +#define USB_QHD_EP_CAP_MULTI_3 (3 << 30) + +#define USB_QHD_TOKEN_XFER_ERROR BIT(3) +#define USB_QHD_TOKEN_BUFFER_ERROR BIT(5) +#define USB_QHD_TOKEN_HALTED BIT(6) +#define USB_QHD_TOKEN_ACTIVE BIT(7) +#define USB_QHD_TOKEN_MULT_OVERR_MASK (2 << 10) +#define USB_QHD_TOKEN_IRQ_ON_COMPLETE BIT(15) +#define USB_QHD_TOKEN_TOTAL_BYTES_SHIFT 16 + +/* USB_OTG/USB_1 controllers register bits */ +#define USB2D_PORTSC1_SUSP BIT(7) + +#define USB2D_USBCMD_RUN BIT(0) +#define USB2D_USBCMD_RESET BIT(1) +#define USB2D_USBCMD_ITC_MASK (0xFF << 16) + +#define USB2D_USBSTS_UI BIT(0) +#define USB2D_USBSTS_UEI BIT(1) +#define USB2D_USBSTS_PCI BIT(2) +#define USB2D_USBSTS_FRI BIT(3) +#define USB2D_USBSTS_SEI BIT(4) +#define USB2D_USBSTS_AAI BIT(5) +#define USB2D_USBSTS_URI BIT(6) +#define USB2D_USBSTS_SRI BIT(7) +#define USB2D_USBSTS_SLI BIT(8) + +#define USB2D_USBMODE_CM_MASK (3 << 0) +#define USB2D_USBMODE_CM_IDLE 0 +#define USB2D_USBMODE_CM_RSVD 1 +#define USB2D_USBMODE_CM_DEVICE 2 +#define USB2D_USBMODE_CM_HOST 3 + +#define USB2D_ENDPT_STATUS_RX_OFFSET BIT(0) +#define USB2D_ENDPT_STATUS_TX_OFFSET BIT(16) + +#define USB2D_ENDPTCTRL_RX_EP_STALL BIT(0) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL (0 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_ISO (1 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_BULK (2 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_INTR (3 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_MASK (3 << 2) +#define USB2D_ENDPTCTRL_RX_EP_INHIBIT BIT(5) +#define USB2D_ENDPTCTRL_RX_EP_RESET BIT(6) +#define USB2D_ENDPTCTRL_RX_EP_ENABLE BIT(7) +#define USB2D_ENDPTCTRL_TX_EP_STALL BIT(16) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL (0 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_ISO (1 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_BULK (2 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_INTR (3 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_MASK (3 << 18) +#define USB2D_ENDPTCTRL_TX_EP_INHIBIT BIT(21) +#define USB2D_ENDPTCTRL_TX_EP_RESET BIT(22) +#define USB2D_ENDPTCTRL_TX_EP_ENABLE BIT(23) + +#define USB2D_HOSTPC1_DEVLC_ASUS BIT(17) +#define USB2D_HOSTPC1_DEVLC_PHCD BIT(22) +#define USB2D_HOSTPC1_DEVLC_PSPD_MASK (3 << 25) + +#define USB2D_OTGSC_USB_ID_PULLUP BIT(5) +#define USB2D_OTGSC_USB_IRQ_STS_MASK (0x7F << 16) + +/* USB_OTG/USB_1 controllers registers */ +typedef struct _t210_usb2d_t +{ + vu32 id; + vu32 unk0; + vu32 hw_host; + vu32 hw_device; + vu32 hw_txbuf; + vu32 hw_rxbuf; + vu32 unk1[26]; + vu32 gptimer0ld; + vu32 gptimer0ctrl; + vu32 gptimer1ld; + vu32 gptimer1ctrl; + vu32 unk2[28]; + vu16 caplength; + vu16 hciversion; + vu32 hcsparams; + vu32 hccparams; + vu32 unk3[5]; + vu32 dciversion; + vu32 dccparams; + vu32 extsts; + vu32 usbextintr; + vu32 usbcmd; + vu32 usbsts; + vu32 usbintr; + vu32 frindex; + vu32 unk4; + vu32 periodiclistbase; + vu32 asynclistaddr; + vu32 asyncttsts; + vu32 burstsize; + vu32 txfilltuning; + vu32 unk6; + vu32 icusb_ctrl; + vu32 ulpi_viewport; + vu32 rsvd0[4]; + vu32 portsc1; + vu32 rsvd1[15]; + vu32 hostpc1_devlc; + vu32 rsvd2[15]; + vu32 otgsc; + vu32 usbmode; + vu32 unk10; + vu32 endptnak; + vu32 endptnak_enable; + vu32 endptsetupstat; + vu32 endptprime; + vu32 endptflush; + vu32 endptstatus; + vu32 endptcomplete; + vu32 endptctrl[16]; +} t210_usb2d_t; + + +/* XHCI USB */ + +/* XUSB DEV XHCI registers */ +#define XUSB_DEV_XHCI_DB 0x4 +#define XUSB_DEV_XHCI_ERSTSZ 0x8 +#define XUSB_DEV_XHCI_ERST0BALO 0x10 +#define XUSB_DEV_XHCI_ERST0BAHI 0x14 +#define XUSB_DEV_XHCI_ERST1BALO 0x18 +#define XUSB_DEV_XHCI_ERST1BAHI 0x1C +#define XUSB_DEV_XHCI_ERDPLO 0x20 +#define XHCI_ERDPLO_EHB BIT(3) +#define XUSB_DEV_XHCI_ERDPHI 0x24 +#define XUSB_DEV_XHCI_EREPLO 0x28 +#define XCHI_ECS BIT(0) +#define XUSB_DEV_XHCI_EREPHI 0x2C +#define XUSB_DEV_XHCI_CTRL 0x30 +#define XHCI_CTRL_RUN BIT(0) +#define XHCI_CTRL_LSE BIT(1) +#define XHCI_CTRL_IE BIT(4) +#define XHCI_CTRL_ENABLE BIT(31) +#define XUSB_DEV_XHCI_ST 0x34 +#define XHCI_ST_RC BIT(0) +#define XHCI_ST_IP BIT(4) +#define XUSB_DEV_XHCI_RT_IMOD 0x38 +#define XUSB_DEV_XHCI_PORTSC 0x3C +#define XHCI_PORTSC_CCS BIT(0) +#define XHCI_PORTSC_PED BIT(1) +#define XHCI_PORTSC_PR BIT(4) +#define XHCI_PORTSC_PLS_MASK (0xF << 5) +#define XHCI_PORTSC_PLS_U0 (0 << 5) +#define XHCI_PORTSC_PLS_U1 (1 << 5) +#define XHCI_PORTSC_PLS_U2 (2 << 5) +#define XHCI_PORTSC_PLS_U3 (3 << 5) +#define XHCI_PORTSC_PLS_DISABLED (4 << 5) +#define XHCI_PORTSC_PLS_RXDETECT (5 << 5) +#define XHCI_PORTSC_PLS_INACTIVE (6 << 5) +#define XHCI_PORTSC_PLS_POLLING (7 << 5) +#define XHCI_PORTSC_PLS_RECOVERY (8 << 5) +#define XHCI_PORTSC_PLS_HOTRESET (9 << 5) +#define XHCI_PORTSC_PLS_COMPLIANCE (10 << 5) +#define XHCI_PORTSC_PLS_LOOPBACK (11 << 5) +#define XHCI_PORTSC_PLS_RESUME (15 << 5) +#define XHCI_PORTSC_PS (0xF << 10) +#define XHCI_PORTSC_LWS BIT(16) +#define XHCI_PORTSC_CSC BIT(17) +#define XHCI_PORTSC_WRC BIT(19) +#define XHCI_PORTSC_PRC BIT(21) +#define XHCI_PORTSC_PLC BIT(22) +#define XHCI_PORTSC_CEC BIT(23) +#define XHCI_PORTSC_WPR BIT(30) +#define XUSB_DEV_XHCI_ECPLO 0x40 +#define XUSB_DEV_XHCI_ECPHI 0x44 +#define XUSB_DEV_XHCI_EP_HALT 0x50 +#define XHCI_EP_HALT_DCI_EP0_IN BIT(0) +#define XUSB_DEV_XHCI_EP_PAUSE 0x54 +#define XUSB_DEV_XHCI_EP_RELOAD 0x58 +#define XUSB_DEV_XHCI_EP_STCHG 0x5C +#define XUSB_DEV_XHCI_PORTHALT 0x6C +#define XUSB_DEV_XHCI_EP_STOPPED 0x78 +#define XHCI_PORTHALT_HALT_LTSSM BIT(0) +#define XHCI_PORTHALT_STCHG_REQ BIT(20) +#define XUSB_DEV_XHCI_CFG_DEV_FE 0x85C +#define XHCI_CFG_DEV_FE_PORTREGSEL_MASK (3 << 0) +#define XHCI_CFG_DEV_FE_PORTREGSEL_SS (1 << 0) +#define XHCI_CFG_DEV_FE_PORTREGSEL_HSFS (2 << 0) + +/* XUSB DEV PCI registers */ +#define XUSB_CFG_1 0x4 +#define CFG_1_IO_SPACE BIT(0) +#define CFG_1_MEMORY_SPACE BIT(1) +#define CFG_1_BUS_MASTER BIT(2) +#define XUSB_CFG_4 0x10 +#define CFG_4_ADDRESS_TYPE_32_BIT (0 << 1) +#define CFG_4_ADDRESS_TYPE_64_BIT (2 << 1) + +/* XUSB DEV Device registers */ +#define XUSB_DEV_CONFIGURATION 0x180 +#define DEV_CONFIGURATION_EN_FPCI BIT(0) +#define XUSB_DEV_INTR_MASK 0x188 +#define DEV_INTR_MASK_IP_INT_MASK BIT(16) + +/* XUSB Pad Control registers */ +#define XUSB_PADCTL_USB2_PAD_MUX 0x4 +#define PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_USB2 (0 << 0) +#define PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB (1 << 0) +#define PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK (3 << 0) +#define PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_USB2 (0 << 18) +#define PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB (1 << 18) +#define PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK (3 << 18) +#define XUSB_PADCTL_USB2_PORT_CAP 0x8 +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_DIS (0 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_HOST (1 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_DEV (2 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_OTG (3 << 0) +#define PADCTL_USB2_PORT_CAP_PORT_0_CAP_MASK (3 << 0) +#define XUSB_PADCTL_SS_PORT_MAP 0x14 +#define PADCTL_SS_PORT_MAP_PORT0_MASK (0xF << 0) +#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20 +#define XUSB_PADCTL_ELPG_PROGRAM_1 0x24 +#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL0 0x80 +#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1 0x84 +#define XUSB_PADCTL_USB2_OTG_PAD0_CTL_0 0x88 +#define XUSB_PADCTL_USB2_OTG_PAD0_CTL_1 0x8C +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_0 0x284 +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_1 0x288 +#define XUSB_PADCTL_USB2_VBUS_ID 0xC60 +#define PADCTL_USB2_VBUS_ID_VBUS_OVR_EN (1 << 12) +#define PADCTL_USB2_VBUS_ID_VBUS_OVR_MASK (3 << 12) +#define PADCTL_USB2_VBUS_ID_VBUS_ON BIT(14) +#define PADCTL_USB2_VBUS_ID_SRC_ID_OVR_EN (1 << 16) +#define PADCTL_USB2_VBUS_ID_SRC_MASK (3 << 16) +#define PADCTL_USB2_VBUS_ID_OVR_GND (0 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_C (1 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_B (2 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_A (4 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_FLOAT (8 << 18) +#define PADCTL_USB2_VBUS_ID_OVR_MASK (0xF << 18) + +#endif diff --git a/bdk/usb/usbd.c b/bdk/usb/usbd.c new file mode 100644 index 0000000..2a7fe97 --- /dev/null +++ b/bdk/usb/usbd.c @@ -0,0 +1,1618 @@ +/* + * Enhanced USB Device (EDCI) driver for Tegra X1 + * + * Copyright (c) 2019-2024 CTCaer + * + * 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef enum +{ + USB_HW_EP0 = 0, + USB_HW_EP1 = 1 +} usb_hw_ep_t; + +typedef enum +{ + USB_EP_STATUS_IDLE = 0, + USB_EP_STATUS_ACTIVE = 1, + USB_EP_STATUS_ERROR = 2, + USB_EP_STATUS_NO_CONFIG = 3, + USB_EP_STATUS_STALLED = 4, + USB_EP_STATUS_DISABLED = 5 +} usb_ep_status_t; + +typedef enum { + USB_LOW_SPEED = 0, + USB_FULL_SPEED = 1, + USB_HIGH_SPEED = 2, + USB_SUPER_SPEED = 3, +} usb_speed_t; + +typedef struct _dTD_t +{ + vu32 next_dTD; + vu32 info; + vu32 pages[5]; + vu32 reserved; +} dTD_t; + +typedef struct _dQH_t +{ + vu32 ep_capabilities; + vu32 curr_dTD_ptr; + vu32 next_dTD_ptr; + vu32 token; + vu32 buffers[5]; // hmmm. + vu32 reserved; + vu32 setup[2]; + vu32 gap[4]; +} dQH_t; + +typedef struct _usbd_t +{ + volatile dTD_t dtds[4 * 4]; // 4 dTD per endpoint. + volatile dQH_t *qhs; + int ep_configured[4]; + int ep_bytes_requested[4]; +} usbd_t; + +typedef struct _usbd_controller_t +{ + u32 port_speed; + t210_usb2d_t *regs; + usb_ctrl_setup_t control_setup; + usb_desc_t *desc; + usb_gadget_type gadget; + u8 config_num; + u8 interface_num; + u8 max_lun; + bool usb_phy_ready; + bool configuration_set; + bool max_lun_set; + bool bulk_reset_req; + bool hid_report_sent; + u32 charger_detect; +} usbd_controller_t; + +extern u8 hid_report_descriptor_jc[]; +extern u8 hid_report_descriptor_touch[]; +extern u32 hid_report_descriptor_jc_size; +extern u32 hid_report_descriptor_touch_size; + +extern usb_desc_t usb_gadget_hid_jc_descriptors; +extern usb_desc_t usb_gadget_hid_touch_descriptors; +extern usb_desc_t usb_gadget_ums_descriptors; + +usbd_t *usbdaemon; + +usbd_controller_t *usbd_otg; +usbd_controller_t usbd_usb_otg_controller_ctxt; + +bool usb_init_done = false; + +u8 *usb_ep0_ctrl_buf = (u8 *)USB_EP_CONTROL_BUF_ADDR; + +static int _usbd_reset_usb_otg_phy_device_mode() +{ + usbd_otg->usb_phy_ready = false; + + // Clear UTMIP reset. + USB(USB1_IF_USB_SUSP_CTRL) &= ~SUSP_CTRL_UTMIP_RESET; + + // Wait for PHY clock to get validated. + u32 retries = 100000; // 200ms timeout. + while (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID)) + { + retries--; + if (!retries) + return USB_ERROR_INIT; + usleep(1); + } + usbd_otg->usb_phy_ready = true; + + // Clear all device addresses, enabled setup requests and transmit events. + usbd_otg->regs->periodiclistbase = 0; + usbd_otg->regs->endptsetupstat = usbd_otg->regs->endptsetupstat; + usbd_otg->regs->endptcomplete = usbd_otg->regs->endptcomplete; + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Set controller mode to idle. + usbd_otg->regs->usbmode &= ~USB2D_USBMODE_CM_MASK; + + // Reset the controller. + usbd_otg->regs->usbcmd |= USB2D_USBCMD_RESET; + + // Wait for the reset to complete. + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->usbcmd & USB2D_USBCMD_RESET) + { + retries--; + if (!retries) + return USB_ERROR_INIT; + usleep(1); + } + + // Wait for PHY clock to get validated after reset. + retries = 100000; // 200ms timeout. + while (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID)) + { + retries--; + if (!retries) + return USB_ERROR_INIT; + usleep(1); + } + + // Set controller to Device mode. + usbd_otg->regs->usbmode = (usbd_otg->regs->usbmode & ~USB2D_USBMODE_CM_MASK) | USB2D_USBMODE_CM_DEVICE; + + // Wait for the selected mode to be enabled. + retries = 100000; // 200ms timeout. + while ((usbd_otg->regs->usbmode & USB2D_USBMODE_CM_MASK) != USB2D_USBMODE_CM_DEVICE) + { + retries--; + if (!retries) + return USB_ERROR_INIT; + usleep(1); + } + + // Disable all interrupts. + usbd_otg->regs->usbintr = 0; + + // Set the ID pullup and disable all OTGSC interrupts. + usbd_otg->regs->otgsc = USB2D_OTGSC_USB_ID_PULLUP; + + // Clear all relevant interrupt statuses. + usbd_otg->regs->usbsts = USB2D_USBSTS_UI | USB2D_USBSTS_UEI | USB2D_USBSTS_PCI | + USB2D_USBSTS_FRI | USB2D_USBSTS_SEI | USB2D_USBSTS_AAI | + USB2D_USBSTS_URI | USB2D_USBSTS_SRI | USB2D_USBSTS_SLI; + + // Disable and clear all OTGSC interrupts. + usbd_otg->regs->otgsc = USB2D_OTGSC_USB_IRQ_STS_MASK; + + // Clear EP0, EP1, EP2 setup requests. + usbd_otg->regs->endptsetupstat = 7; //TODO: Shouldn't this be endptsetupstat = endptsetupstat? + + // Set all interrupts to immediate. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_ITC_MASK; + + return USB_RES_OK; +} + +static void _usb_charger_detect() +{ + // Charger detect init. + usbd_otg->charger_detect = 0; + bool charger_detect_enable = FUSE(FUSE_RESERVED_SW) & 0x10; // Disabled on Switch production. + if (charger_detect_enable) + { + usbd_otg->charger_detect |= 1; + // Configure detect pin. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO1) &= ~(PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); + gpio_direction_input(GPIO_PORT_V, GPIO_PIN_3); + + // Configure charger pin. + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) &= ~(PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); + gpio_config(GPIO_PORT_CC, GPIO_PIN_5, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_5, GPIO_OUTPUT_ENABLE); + + // Enable charger. + if (gpio_read(GPIO_PORT_V, GPIO_PIN_3)) + { + usbd_otg->charger_detect |= 2; + gpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_HIGH); + usbd_otg->charger_detect |= 0x100; + USB(USB1_UTMIP_BAT_CHRG_CFG0) = BAT_CHRG_CFG0_OP_SRC_EN; // Clears UTMIP_PD_CHRG and enables charger detect. + usleep(5000); + } + } +} + +static void _usb_init_phy() +{ + // Configure and enable PLLU. + clock_enable_pllu(); + + // Enable USBD clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_USBD); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_USBD); + usleep(2); + + // Clear XUSB_PADCTL reset + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_PADCTL); + + // Enable USB PHY and reset for programming. + u32 usb_susp_ctrl = USB(USB1_IF_USB_SUSP_CTRL); + USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_RESET; + USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_PHY_ENB | SUSP_CTRL_UTMIP_RESET; + + // Enable IDDQ control by software and disable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0xFFFFFFFC) | 1; + usleep(10); + + // Disable crystal clock. + USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) &= 0xBFFFFFFF; + + // Set B_SESS_VLD. + USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x1000; + USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x800; + + // Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz. + clock_enable_utmipll(); + + // Configure UTMIP Transceiver Cells. + u32 fuse_usb_calib = FUSE(FUSE_USB_CALIB); + USB(USB1_UTMIP_XCVR_CFG0) = (((USB(USB1_UTMIP_XCVR_CFG0) & 0xFFFFFFF0) | (fuse_usb_calib & 0xF)) & 0xFE3FFFFF) | ((fuse_usb_calib & 0x3F) << 25 >> 29 << 22); + USB(USB1_UTMIP_XCVR_CFG1) = (USB(USB1_UTMIP_XCVR_CFG1) & 0xFFC3FFFF) | ((fuse_usb_calib << 21) >> 28 << 18); + USB(USB1_UTMIP_XCVR_CFG3) = (USB(USB1_UTMIP_XCVR_CFG3) & 0xFFFFC1FF) | ((FUSE(FUSE_USB_CALIB_EXT) & 0x1F) << 9); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFDFFFFF; + USB(USB1_UTMIP_XCVR_CFG2) = (USB(USB1_UTMIP_XCVR_CFG2) & 0xFFFFF1FF) | 0x400; + usleep(1); + + // Configure misc UTMIP. + USB(USB1_UTMIP_DEBOUNCE_CFG0) = (USB(USB1_UTMIP_DEBOUNCE_CFG0) & 0xFFFF0000) | 0xBB80; + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFC0FF) | 0x100; // when osc is 38.4KHz + + //USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFEE7; unpatched0 + USB(USB1_UTMIP_BIAS_CFG2) |= 2; //patched0 - UTMIP_HSSQUELCH_LEVEL_NEW: 2. + USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFE67; //patched0 - FUSE_HS_IREF_CAP_CFG + USB(USB1_UTMIP_TX_CFG0) |= 0x80000; + + //USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xFFF003FF) | 0x88000 | 0x4000; unpatched1 + USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xF0F003FF) | 0x88000 | 0x4000; //patched1 - reset UTMIP_PCOUNT_UPDN_DIV: From 1 to 0. + USB(USB1_UTMIP_BIAS_CFG2) &= 0xFFFFFFF8; //patched1 - UTMIP_HSSQUELCH_LEVEL_NEW: 0 + + USB(USB1_UTMIP_HSRX_CFG1) = (USB(USB1_UTMIP_HSRX_CFG1) & 0xFFFFFFC1) | 0x12; + USB(USB1_UTMIP_MISC_CFG1) |= 0x40000000; + + // Enable crystal clock. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= 0x40000000; + + // Enable USB2 tracking clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_USB2_TRK); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4. + + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFC03F07) | 0x78000 | 0x50; // Set delays. + USB(USB1_UTMIP_BIAS_CFG0) &= 0xFFFFFBFF; // Disable Power down bias circuit. + usleep(1); + + // Force PDTRK input into power up. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE) | 2; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; + usleep(3); + + // Force PDTRK input into power up. + USB(USB1_UTMIP_BIAS_CFG1) = USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; + + // Disable USB2 tracking clock and configure UTMIP misc. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_CLR) = BIT(CLK_Y_USB2_TRK); + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFEA) | 0x2000000 | 0x28 | 2; + usleep(1); + + USB(USB1_UTMIP_BIAS_CFG0) &= 0xFF3FF7FF; + usleep(1); + + // Clear power downs on UTMIP ID and VBUS wake up, PD, PD2, PDZI, PDCHRP, PDDR. + PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; // UTMIP ID and VBUS wake up. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFFBFFF; // UTMIP_FORCE_PD_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFEFFFF; // UTMIP_FORCE_PD2_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFBFFFF; // UTMIP_FORCE_PDZI_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFFB; // UTMIP_FORCE_PDCHRP_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFEF; // UTMIP_FORCE_PDDR_POWERDOWN. + usleep(1); +} + +int usb_device_init() +{ + if (usb_init_done) + return USB_RES_OK; + + // Ease the stress to APB. + bpmp_clk_rate_relaxed(true); + + // Initialize USB2 controller PHY. + _usb_init_phy(); + + // Restore OC. + bpmp_clk_rate_relaxed(false); + + // AHB USB performance cfg. + AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_USB) |= AHB_GIZMO_IMMEDIATE; + AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7) | PRIORITY_SELECT_USB; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = MEM_PREFETCH_ENABLE | MEM_PREFETCH_USB_MST_ID | + MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles. + + // Set software and hardware context storage and clear it. + usbdaemon = (usbd_t *)USBD_ADDR; // Depends on USB_TD_BUFFER_PAGE_SIZE aligned address. + usbd_otg = &usbd_usb_otg_controller_ctxt; + memset(usbd_otg, 0, sizeof(usbd_controller_t)); + memset(usbdaemon, 0, sizeof(usbd_t)); + + usbd_otg->regs = (t210_usb2d_t *)USB_OTG_BASE; + usbd_otg->usb_phy_ready = false; + + // Initialize USB PHY on the USB_OTG Controller (#1) in Device mode. + int res = _usbd_reset_usb_otg_phy_device_mode(); + usbd_otg->configuration_set = false; + + _usb_charger_detect(); + + if (!res) + usb_init_done = true; + + return res; +} + +static void _usb_device_power_down() +{ + // Enable PHY low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_PHCD; + // Do not use any controller regs after the above! + // A reset or clear of the PHCD suspend bit must happen. + + // Power down OTG and Bias circuits. + USB(USB1_UTMIP_BIAS_CFG0) |= BIT(11) | BIT(10); // UTMIP_OTGPD, UTMIP_BIASPD. + + // Power down ID detectors. + USB(USB1_UTMIP_BIAS_CFG0) |= BIT(23) | BIT(22); // UTMIP_IDPD_SEL, UTMIP_IDPD_VAL. + + if (usbd_otg->charger_detect) + { + USB(USB1_UTMIP_BAT_CHRG_CFG0) = 1; //UTMIP_PD_CHRG + usbd_otg->charger_detect = 0; + } + + // Power down the UTMIP transceivers. + // UTMIP_FORCE_PDZI_POWERDOWN, UTMIP_FORCE_PD2_POWERDOWN, UTMIP_FORCE_PD_POWERDOWN. + USB(USB1_UTMIP_XCVR_CFG0) |= BIT(18) | BIT(16) |BIT(14); + // UTMIP_FORCE_PDDR_POWERDOWN, UTMIP_FORCE_PDCHRP_POWERDOWN, UTMIP_FORCE_PDDISC_POWERDOWN. + USB(USB1_UTMIP_XCVR_CFG1) |= BIT(4) | BIT(2) | BIT(0); + + // Keep UTMIP in reset. + USB(USB1_IF_USB_SUSP_CTRL) |= SUSP_CTRL_UTMIP_RESET; + + // Power down PD trunk. + USB(USB1_UTMIP_BIAS_CFG1) |= BIT(0); //UTMIP_FORCE_PDTRK_POWERDOWN. + + // Force UTMIP_PLL power down. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(14); // UTMIP_FORCE_PLL_ENABLE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(12); // UTMIP_FORCE_PLL_ACTIVE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= BIT(4) | BIT(0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(16); // UTMIP_FORCE_PLLU_POWERDOWN. + + // Disable crystal clock. + USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; + + // Force enable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 3; + + // Set XUSB_PADCTL reset + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); + + // Disable USBD clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD); + + // Disable PLLU. + clock_disable_pllu(); + + usb_init_done = false; +} + +static void _usbd_disable_ep1() +{ + usbd_otg->regs->endptctrl[1] = 0; +} + +static void _usbd_stall_reset_ep1(usb_dir_t direction, usb_ep_cfg_t stall) +{ + stall &= 1; + if (direction == USB_DIR_IN) + { + usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16); + if (!stall) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET; + } + else + { + usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_RX_EP_STALL) | stall; + if (!stall) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET; + } +} + +void usb_device_stall_ep1_bulk_out() +{ + _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_STALL); +} + +void usb_device_stall_ep1_bulk_in() +{ + _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_STALL); +} + +static int _usbd_get_max_pkt_length(int endpoint) +{ + switch (endpoint) + { + case USB_EP_CTRL_OUT: + case USB_EP_CTRL_IN: + return 64; + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + if (usbd_otg->port_speed == USB_HIGH_SPEED) + return 512; + else + return 64; + default: + return 64; + } +} + +static void _usbd_initialize_ep_ctrl(u32 endpoint) +{ + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_dir_t direction = endpoint & 1; + + memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); + + if (!endpoint) + usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; + + usbdaemon->qhs[endpoint].next_dTD_ptr = 1; // TERMINATE_SET + + u32 max_packet_len = _usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + usbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16; + + if (direction == USB_DIR_IN) + { + u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK; + if (actual_ep) + endpoint_type |= usbd_otg->gadget ? USB2D_ENDPTCTRL_TX_EP_TYPE_INTR : USB2D_ENDPTCTRL_TX_EP_TYPE_BULK; + else + endpoint_type |= USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL; + + usbd_otg->regs->endptctrl[actual_ep] = endpoint_type; + + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; + + if (actual_ep == USB_HW_EP1) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET; + + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_ENABLE; + } + else // EP Bulk OUT. + { + u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_RX_EP_TYPE_MASK; + if (actual_ep) + endpoint_type |= usbd_otg->gadget ? USB2D_ENDPTCTRL_RX_EP_TYPE_INTR : USB2D_ENDPTCTRL_RX_EP_TYPE_BULK; + else + endpoint_type |= USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL; + + usbd_otg->regs->endptctrl[actual_ep] = endpoint_type; + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; + + if (actual_ep == USB_HW_EP1) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET; + + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_ENABLE; + } +} + +static int _usbd_initialize_ep0() +{ + memset((void *)usbdaemon->qhs, 0, sizeof(dQH_t) * 4); // Clear all used EP queue heads. + memset((void *)usbdaemon->dtds, 0, sizeof(dTD_t) * 4); // Clear all used EP0 token heads. + + usbd_otg->regs->asynclistaddr = (u32)usbdaemon->qhs; + + _usbd_initialize_ep_ctrl(USB_EP_CTRL_OUT); + _usbd_initialize_ep_ctrl(USB_EP_CTRL_IN); + + // Disable Auto Low Power. + usbd_otg->regs->hostpc1_devlc &= ~USB2D_HOSTPC1_DEVLC_ASUS; + + // Initiate an attach event. + usbd_otg->regs->usbcmd |= USB2D_USBCMD_RUN; + + u32 retries = 100000; // 200ms timeout. + while (!(usbd_otg->regs->usbcmd & USB2D_USBCMD_RUN)) + { + retries--; + if (!retries) + return USB_ERROR_TIMEOUT; + usleep(1); + } + + return USB_RES_OK; +} + +// static void _disable_usb_wdt4() +// { +// if (TIMER_WDT4_STATUS & 1)// active +// { +// TIMER_TMR0_TMR_PTV &= 0x7FFFFFFF; // Disable timer +// TIMER_WDT4_UNLOCK_PATTERN = 0xC45A; // Alow writes to disable counter bit. +// TIMER_WDT4_COMMAND |= 2; // Disable counter +// TIMER_TMR0_TMR_PCR |= 0x40000000;// INTR_CLR +// } +// } + +int usbd_flush_endpoint(u32 endpoint) +{ + + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_dir_t direction = endpoint & 1; + u32 reg_mask = endpoint; + + // Flash all endpoints or 1. + if (endpoint != USB_EP_ALL) + { + if (direction == USB_DIR_IN) + reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + } + usbd_otg->regs->endptflush = reg_mask; + + u32 retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptflush & reg_mask) + { + retries--; + if (!retries) + return USB_ERROR_TIMEOUT; + usleep(1); + } + + // Wait for the endpoint to finish all transactions (buffer not ready). + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptstatus & reg_mask) + { + retries--; + if (!retries) + return USB_ERROR_TIMEOUT; + usleep(1); + } + + // Wait for the endpoint to clear the primed status. + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptprime & reg_mask) + { + retries--; + if (!retries) + return USB_ERROR_TIMEOUT; + usleep(1); + } + + return USB_RES_OK; +} + +static void _usb_reset_disable_ep1() +{ + usbd_flush_endpoint(USB_EP_ALL); + _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_RESET); // EP1 Bulk OUT. + _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_RESET); // EP1 Bulk IN. + _usbd_disable_ep1(); + + usbd_otg->config_num = 0; + usbd_otg->interface_num = 0; + usbd_otg->configuration_set = false; + usbd_otg->max_lun_set = false; +} + +void usbd_end(bool reset_ep, bool only_controller) +{ + if (reset_ep) + _usb_reset_disable_ep1(); + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Enable PHY auto low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS; + + if (!only_controller) + _usb_device_power_down(); +} + +static void _usbd_mark_ep_complete(u32 endpoint) +{ + u32 complete_bit; + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_dir_t direction = endpoint & 1; + + usbd_flush_endpoint(endpoint); + + memset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4); + memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); + + usbdaemon->ep_configured[endpoint] = 0; + usbdaemon->ep_bytes_requested[endpoint] = 0; + + if (direction == USB_DIR_IN) + complete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + complete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + usbd_otg->regs->endptcomplete |= complete_bit; +} + +static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) +{ + bool status; + u32 reg_val; + u32 reg_mask; + u32 actual_ep = (endpoint & 2) >> 1; + usb_dir_t direction = endpoint & 1; + + if (direction == USB_DIR_IN) + reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + if (actual_ep == USB_HW_EP1) + reg_val = usbd_otg->regs->endptctrl[1]; + else + reg_val = usbd_otg->regs->endptctrl[0]; + + // Check stalled status. + if (direction == USB_DIR_IN) + status = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL; + else + status = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL; + + if (status) + return USB_EP_STATUS_STALLED; + + // Check enabled status. + if (direction == USB_DIR_IN) + status = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE; + else + status = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE; + + if (!status) + return USB_EP_STATUS_DISABLED; + + // CHeck qHD error status. + u32 token_error_mask = USB_QHD_TOKEN_HALTED | USB_QHD_TOKEN_BUFFER_ERROR | USB_QHD_TOKEN_XFER_ERROR; + if (usbdaemon->qhs[endpoint].token & token_error_mask) + return USB_EP_STATUS_ERROR; + + // Check if endpoint has a request or a ready buffer. + if ((usbd_otg->regs->endptprime & reg_mask) || (usbd_otg->regs->endptstatus & reg_mask)) + return USB_EP_STATUS_ACTIVE; // RX/TX active. + + // Return idle or not configured status. + if (!usbdaemon->ep_configured[endpoint]) + return USB_EP_STATUS_NO_CONFIG; + + return USB_EP_STATUS_IDLE; +} + +static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, u32 sync_timeout) +{ + if (!buf) + len = 0; + + u32 prime_bit; + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_dir_t direction = endpoint & 1; + u32 length_left = len; + u32 dtd_ep_idx = endpoint * 4; + + _usbd_mark_ep_complete(endpoint); + + if (endpoint == USB_EP_CTRL_OUT) + usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; + + u32 max_packet_len = _usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + usbdaemon->qhs[endpoint].ep_capabilities |= (max_packet_len << 16) | USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS; + usbdaemon->qhs[endpoint].next_dTD_ptr = 0; // Clear terminate bit. + //usbdaemon->qhs[endpoint].ep_capabilities |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; + + usbdaemon->ep_configured[endpoint] = 1; + usbdaemon->ep_bytes_requested[endpoint] = len; + + // Configure dTD. + u32 dtd_idx = 0; + do + { + if (dtd_idx) + usbdaemon->dtds[dtd_ep_idx + dtd_idx - 1].next_dTD = (u32)&usbdaemon->dtds[dtd_ep_idx + dtd_idx]; + + u32 dtd_size = MIN(length_left, USB_TD_BUFFER_MAX_SIZE); // 16KB max per dTD. + usbdaemon->dtds[dtd_ep_idx + dtd_idx].info = (dtd_size << 16) | USB_QHD_TOKEN_ACTIVE; + // usbdaemon->dtds[dtd_ep_idx + dtd_idx].info |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; + + // Set buffers addresses to all page pointers. + u32 dt_buffer_offset = dtd_idx * USB_TD_BUFFER_MAX_SIZE; + for (u32 i = 0; i < 4; i++) + usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[i] = !buf ? 0 : + (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * i)]; + + //usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[5] = + // (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * 4)]; // Last buffer. Unused. + + length_left -= dtd_size; + if (length_left) + dtd_idx++; + } + while (length_left); + + // Last dTD, terminate it. + usbdaemon->dtds[dtd_ep_idx + dtd_idx].next_dTD = 1; + + // Set first dTD address to queue head next dTD. + usbdaemon->qhs[endpoint].next_dTD_ptr |= (u32)&usbdaemon->dtds[dtd_ep_idx] & 0xFFFFFFE0; + + // Flush AHB prefetcher. + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |= MEM_PREFETCH_ENABLE; + + if (direction == USB_DIR_IN) + prime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + prime_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + // Flush data before priming EP. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false); + + // Prime endpoint. + usbd_otg->regs->endptprime |= prime_bit; // USB2_CONTROLLER_USB2D_ENDPTPRIME. + + int res = USB_RES_OK; + usb_ep_status_t ep_status; + if (sync_timeout) + { + ep_status = _usbd_get_ep_status(endpoint); + if (ep_status == USB_EP_STATUS_ACTIVE) + { + u32 retries = sync_timeout; + while (retries) + { + ep_status = _usbd_get_ep_status(endpoint); + if (ep_status != USB_EP_STATUS_ACTIVE) + { + if (ep_status == USB_EP_STATUS_DISABLED) + res = USB2_ERROR_XFER_EP_DISABLED; + goto out; + } + retries--; + usleep(1); + } + res = USB_ERROR_TIMEOUT; + } + else if (ep_status == USB_EP_STATUS_DISABLED) + res = USB2_ERROR_XFER_EP_DISABLED; +out: + if (res) + _usbd_mark_ep_complete(endpoint); + else if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE) + res = USB_ERROR_XFER_ERROR; + + // Invalidate data after OP is done. + if (direction == USB_DIR_OUT) + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + } + + return res; +} + +static int _usbd_ep_ack(usb_ep_t ep) +{ + return _usbd_ep_operation(ep, NULL, 0, USB_XFER_SYNCED_ENUM); +} + +static void _usbd_set_ep0_stall() +{ + // EP Control endpoints must be always stalled together. + usbd_otg->regs->endptctrl[0] = USB2D_ENDPTCTRL_TX_EP_ENABLE | USB2D_ENDPTCTRL_TX_EP_STALL | + USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL; +} + +int usbd_set_ep_stall(u32 endpoint, int ep_stall) +{ + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_dir_t direction = endpoint & 1; + + if (ep_stall) + { + if (direction == USB_DIR_IN) + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN. + else + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT. + } + else + { + if (direction == USB_DIR_IN) + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN. + else + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT. + } + + return USB_RES_OK; +} + +static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, bool *ep_stall) +{ + u8 _bRequest = usbd_otg->control_setup.bRequest; + u16 _wIndex = usbd_otg->control_setup.wIndex; + u16 _wValue = usbd_otg->control_setup.wValue; + u16 _wLength = usbd_otg->control_setup.wLength; + + bool valid_interface = _wIndex == usbd_otg->interface_num; + bool valid_len = (_bRequest == USB_REQUEST_BULK_GET_MAX_LUN) ? 1 : 0; + + if (!valid_interface || _wValue != 0 || _wLength != valid_len) + { + *ep_stall = true; + return; + } + + switch (_bRequest) + { + case USB_REQUEST_BULK_RESET: + _usbd_ep_ack(USB_EP_CTRL_IN); + usbd_otg->bulk_reset_req = true; + break; // DELAYED_STATUS; + case USB_REQUEST_BULK_GET_MAX_LUN: + *transmit_data = true; + *size = 1; + descriptor[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported. + usbd_otg->max_lun_set = true; + break; + default: + *ep_stall = true; + break; + } +} + +static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, int *size, bool *ep_stall) +{ + u8 descriptor_type = usbd_otg->control_setup.wValue >> 8; + u8 descriptor_subtype = usbd_otg->control_setup.wValue & 0xFF; + + switch (descriptor_type) + { + case USB_DESCRIPTOR_DEVICE: + { +/* + u32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV); + usb_device_descriptor.idProduct = (soc_rev >> 8) & 0xFF; // chip_id. + usb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM. + usb_device_descriptor.bcdDevice = (soc_rev >> 16) & 0xF; // MINORREV. + usb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV. +*/ + *descriptor = usbd_otg->desc->dev; + *size = usbd_otg->desc->dev->bLength; + *transmit_data = true; + return; + } + case USB_DESCRIPTOR_CONFIGURATION: + if (usbd_otg->gadget == USB_GADGET_UMS) + { + if (usbd_otg->port_speed == USB_HIGH_SPEED) // High speed. 512 bytes. + { + usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x200; + usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x200; + } + else // Full speed. 64 bytes. + { + usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x40; + usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x40; + } + } + else + { + usb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_otg->desc->cfg; + if (usbd_otg->port_speed == USB_HIGH_SPEED) // High speed. 512 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x200; + tmp->endpoint[1].wMaxPacketSize = 0x200; + tmp->endpoint[0].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + } + else // Full speed. 64 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x40; + tmp->endpoint[1].wMaxPacketSize = 0x40; + tmp->endpoint[0].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + } + } + *descriptor = usbd_otg->desc->cfg; + *size = usbd_otg->desc->cfg->config.wTotalLength; + *transmit_data = true; + return; + case USB_DESCRIPTOR_STRING: + switch (descriptor_subtype) + { + case 1: + *descriptor = usbd_otg->desc->vendor; + *size = usbd_otg->desc->vendor[0]; + break; + case 2: + *descriptor = usbd_otg->desc->product; + *size = usbd_otg->desc->product[0]; + break; + case 3: + *descriptor = usbd_otg->desc->serial; + *size = usbd_otg->desc->serial[0]; + break; + case 0xEE: + *descriptor = usbd_otg->desc->ms_os; + *size = usbd_otg->desc->ms_os->bLength; + break; + default: + *descriptor = usbd_otg->desc->lang_id; + *size = 4; + break; + } + *transmit_data = true; + return; + case USB_DESCRIPTOR_DEVICE_QUALIFIER: + if (!usbd_otg->desc->dev_qual) + goto exit; + usbd_otg->desc->dev_qual->bNumOtherConfigs = 1; + *descriptor = usbd_otg->desc->dev_qual; + *size = usbd_otg->desc->dev_qual->bLength; + *transmit_data = true; + return; + case USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION: + if (!usbd_otg->desc->cfg_other) + goto exit; + if (usbd_otg->port_speed == USB_HIGH_SPEED) + { + usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x40; + usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x40; + } + else + { + usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x200; + usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x200; + } + if ((usbd_otg->charger_detect & 1) && (usbd_otg->charger_detect & 2)) + usbd_otg->desc->cfg_other->config.bMaxPower = 500 / 2; + *descriptor = usbd_otg->desc->cfg_other; + *size = usbd_otg->desc->cfg_other->config.wTotalLength; + *transmit_data = true; + return; + case USB_DESCRIPTOR_DEVICE_BINARY_OBJECT: + *descriptor = usbd_otg->desc->dev_bot; + *size = usbd_otg->desc->dev_bot->wTotalLength; + *transmit_data = true; + return; + default: + *transmit_data = false; + *ep_stall = true; + return; + } +exit: + *transmit_data = false; + *ep_stall = true; + return; +} + +static int _usbd_handle_set_request(bool *ep_stall) +{ + int res = USB_RES_OK; + u8 bRequest = usbd_otg->control_setup.bRequest; + if (bRequest == USB_REQUEST_SET_ADDRESS) + { + res = _usbd_ep_ack(USB_EP_CTRL_IN); + + // Set USB address for device mode. + if (!res) + usbd_otg->regs->periodiclistbase = (usbd_otg->regs->periodiclistbase & 0x1FFFFFF) | ((usbd_otg->control_setup.wValue & 0xFF) << 25); + } + else if (bRequest == USB_REQUEST_SET_CONFIGURATION) + { + res = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!res) + { + usbd_otg->config_num = usbd_otg->control_setup.wValue; + + // Remove configuration. + if (!usbd_otg->config_num) + { + //! TODO: Signal that to userspace. + _usb_reset_disable_ep1(); + return res; + } + + // Initialize configuration. + _usbd_initialize_ep_ctrl(USB_EP_BULK_OUT); + _usbd_initialize_ep_ctrl(USB_EP_BULK_IN); + usbd_otg->configuration_set = true; + } + } + else + *ep_stall = true; + + return res; +} + +static int _usbd_handle_ep0_control_transfer() +{ + int res = USB_RES_OK; + bool ep_stall = false; + bool transmit_data = false; + + u8 *descriptor = (u8 *)USB_DESCRIPTOR_ADDR; + int size = 0; + + u8 _bmRequestType = usbd_otg->control_setup.bmRequestType; + u8 _bRequest = usbd_otg->control_setup.bRequest; + u16 _wValue = usbd_otg->control_setup.wValue; + u16 _wIndex = usbd_otg->control_setup.wIndex; + u16 _wLength = usbd_otg->control_setup.wLength; + + //gfx_printf("%02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength); + + switch (_bmRequestType) + { + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + res = _usbd_handle_set_request(&ep_stall); + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + res = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!res) + usbd_otg->interface_num = _wValue; + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): + switch (_bRequest) + { + case USB_REQUEST_CLEAR_FEATURE: + case USB_REQUEST_SET_FEATURE: + if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) + { + int direction; + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + direction = 2; + break; + case USB_EP_ADDR_CTRL_IN: + direction = 3; + break; + case USB_EP_ADDR_BULK_OUT: + direction = 0; + break; + case USB_EP_ADDR_BULK_IN: + direction = 1; + break; + default: + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + goto out; + } + + if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + _usbd_stall_reset_ep1(direction, USB_EP_CFG_RESET); + else + _usbd_stall_reset_ep1(direction, USB_EP_CFG_STALL); + + res = _usbd_ep_ack(USB_EP_CTRL_IN); + } + else + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + + break; + default: + ep_stall = true; + break; + } + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + memset(descriptor, 0, _wLength); + _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + switch (_bRequest) + { + case USB_REQUEST_GET_STATUS: + descriptor[0] = USB_STATUS_DEV_SELF_POWERED; + descriptor[1] = 0; // No support for remove wake up. + transmit_data = true; + size = 2; + break; + case USB_REQUEST_GET_DESCRIPTOR: + _usbd_handle_get_descriptor(&transmit_data, (void **)&descriptor, &size, &ep_stall); + break; + case USB_REQUEST_GET_CONFIGURATION: + descriptor = (u8 *)&usbd_otg->config_num; + size = _wLength; + transmit_data = true; + break; + default: + ep_stall = true; + break; + } + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + if (_bRequest == USB_REQUEST_GET_INTERFACE) + { + memset(descriptor, 0, _wLength); + descriptor[0] = usbd_otg->interface_num; + size = _wLength; + } + else if (_bRequest == USB_REQUEST_GET_STATUS) + { + memset(descriptor, 0, _wLength); + size = _wLength; + } + else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_otg->gadget > USB_GADGET_UMS) + { + if (usbd_otg->gadget == USB_GADGET_HID_GAMEPAD) + { + descriptor = (u8 *)&hid_report_descriptor_jc; + size = hid_report_descriptor_jc_size; + } + else // USB_GADGET_HID_TOUCHPAD + { + descriptor = (u8 *)&hid_report_descriptor_touch; + size = hid_report_descriptor_touch_size; + } + + usbd_otg->hid_report_sent = true; + } + else + { + ep_stall = true; + break; + } + + if (_wLength < size) + size = _wLength; + transmit_data = true; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): + if (_bRequest == USB_REQUEST_GET_STATUS) + { + int ep_req; + switch (_wIndex) + { + case USB_EP_ADDR_CTRL_OUT: + ep_req = USB_EP_CTRL_OUT; + break; + case USB_EP_ADDR_BULK_OUT: + ep_req = USB_EP_BULK_OUT; + break; + case USB_EP_ADDR_CTRL_IN: + ep_req = USB_EP_CTRL_IN; + break; + case USB_EP_ADDR_BULK_IN: + ep_req = USB_EP_BULK_IN; + break; + default: + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + goto out; + } + + size = _wLength; + memset(descriptor, 0, size); + + if (_usbd_get_ep_status(ep_req) == USB_EP_STATUS_STALLED) + descriptor[0] = USB_STATUS_EP_HALTED; + else + descriptor[0] = USB_STATUS_EP_OK; + + transmit_data = true; + } + else + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + memset(descriptor, 0, _wLength); + _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_INTERFACE): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE): + if (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR) + { + switch (_wIndex) + { + case USB_DESCRIPTOR_MS_COMPAT_ID: + descriptor = (u8 *)usbd_otg->desc->ms_cid; + size = usbd_otg->desc->ms_cid->dLength; + transmit_data = true; + break; + case USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES: + descriptor = (u8 *)usbd_otg->desc->mx_ext; + size = usbd_otg->desc->mx_ext->dLength; + transmit_data = true; + break; + default: + ep_stall = true; + break; + } + } + else + ep_stall = true; + break; + + default: + ep_stall = true; + break; + } + + // Transmit data to HOST if any. + if (transmit_data) + { + memcpy(usb_ep0_ctrl_buf, descriptor, size); + + if (_wLength < size) + size = _wLength; + res = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, USB_XFER_SYNCED_ENUM); + if (!res) + res = _usbd_ep_ack(USB_EP_CTRL_OUT); + } + +out: + if (ep_stall) + _usbd_set_ep0_stall(); + + return res; +} + +static int _usbd_ep0_initialize() +{ + bool enter = false; + if (usbd_otg->configuration_set) + enter = true; + else + { + usbdaemon->qhs = (volatile dQH_t *)USB2_QH_USB2D_QH_EP_BASE; + + if (!_usbd_initialize_ep0()) + enter = true; + } + + if (enter) + { + usbd_otg->configuration_set = false; + usbd_otg->max_lun_set = false; + + // Timeout if cable or communication isn't started in 1.5 minutes. + u32 timer = get_tmr_ms() + 90000; + while (true) + { + u32 usb_status_irqs = usbd_otg->regs->usbsts; + + // Clear all interrupt statuses. + usbd_otg->regs->usbsts = usb_status_irqs; + + // Check if a reset was received. + if (usb_status_irqs & USB2D_USBSTS_URI) + { + //_disable_usb_wdt4(); + + // Clear all device addresses, enabled setup requests, transmit events and flush all endpoints. + usbd_otg->regs->periodiclistbase = 0; + usbd_otg->regs->endptsetupstat = usbd_otg->regs->endptsetupstat; + usbd_otg->regs->endptcomplete = usbd_otg->regs->endptcomplete; + usbd_flush_endpoint(USB_EP_ALL); + } + + // Check if port change happened. + if (usb_status_irqs & USB2D_USBSTS_PCI) + usbd_otg->port_speed = (usbd_otg->regs->hostpc1_devlc & USB2D_HOSTPC1_DEVLC_PSPD_MASK) >> 25; + + // Acknowledge setup request for EP0 and copy its configuration. + u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; + if (ep0_setup_req & 1) + { + usbd_otg->regs->endptsetupstat = ep0_setup_req; + memcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8); + if (_usbd_handle_ep0_control_transfer()) + break; + } + if (usbd_otg->configuration_set) + return USB_RES_OK; + + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return USB_ERROR_USER_ABORT; + } + } + + return USB_ERROR_TIMEOUT; +} + +int usb_device_enumerate(usb_gadget_type gadget) +{ + switch (gadget) + { + case USB_GADGET_UMS: + usbd_otg->desc = &usb_gadget_ums_descriptors; + break; + case USB_GADGET_HID_GAMEPAD: + usbd_otg->desc = &usb_gadget_hid_jc_descriptors; + break; + case USB_GADGET_HID_TOUCHPAD: + usbd_otg->desc = &usb_gadget_hid_touch_descriptors; + break; + } + + usbd_otg->gadget = gadget; + + return _usbd_ep0_initialize(); +} + +int usbd_handle_ep0_ctrl_setup() +{ + // Acknowledge setup request for EP0 and copy its configuration. + u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; + if (ep0_setup_req & 1) + { + usbd_otg->regs->endptsetupstat = ep0_setup_req; + memcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8); + _usbd_handle_ep0_control_transfer(); + memset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE); + } + + // Only return error if bulk reset was requested. + if (usbd_otg->bulk_reset_req) + { + usbd_otg->bulk_reset_req = false; + return USB_RES_BULK_RESET; + } + + return USB_RES_OK; +} + +static usb_ep_status_t _usbd_get_ep1_status(usb_dir_t dir) +{ + usb_ep_t ep; + if (dir == USB_DIR_OUT) + ep = USB_EP_BULK_OUT; + else + ep = USB_EP_BULK_IN; + return _usbd_get_ep_status(ep); +} + +int usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_timeout) +{ + if ((u32)buf % USB_EP_BUFFER_ALIGN) + return USB2_ERROR_XFER_NOT_ALIGNED; + + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int res = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync_timeout); + + if (sync_timeout && bytes_read) + *bytes_read = res ? 0 : len; + + return res; +} + +int usb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) +{ + if ((u32)buf % USB_EP_BUFFER_ALIGN) + return USB2_ERROR_XFER_NOT_ALIGNED; + + if (len > USB_EP_BULK_OUT_MAX_XFER) + len = USB_EP_BULK_OUT_MAX_XFER; + + int res; + u32 bytes = 0; + *bytes_read = 0; + u8 *buf_curr = buf; + + while (len) + { + u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); + + res = usb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED_DATA); + if (res) + return res; + + len -= len_ep; + buf_curr += len_ep; + *bytes_read = *bytes_read + bytes; + } + + return USB_RES_OK; +} + +static int _usbd_get_ep1_out_bytes_read() +{ + if (_usbd_get_ep_status(USB_EP_BULK_OUT) != USB_EP_STATUS_IDLE) + return 0; + else + return (usbdaemon->ep_bytes_requested[USB_EP_BULK_OUT] - (usbdaemon->qhs[USB_EP_BULK_OUT].token >> 16)); +} + +int usb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_timeout) +{ + usb_ep_status_t ep_status; + do + { + ep_status = _usbd_get_ep1_status(USB_DIR_OUT); + if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) + break; + + usbd_handle_ep0_ctrl_setup(); + } + while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); + + *pending_bytes = _usbd_get_ep1_out_bytes_read(); + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + if (ep_status == USB_EP_STATUS_IDLE) + return USB_RES_OK; + else if (ep_status == USB_EP_STATUS_DISABLED) + return USB2_ERROR_XFER_EP_DISABLED; + else + return USB_ERROR_XFER_ERROR; +} + +int usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_timeout) +{ + if ((u32)buf % USB_EP_BUFFER_ALIGN) + return USB2_ERROR_XFER_NOT_ALIGNED; + + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int res = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync_timeout); + + if (sync_timeout && bytes_written) + *bytes_written = res ? 0 : len; + + return res; +} + +static int _usbd_get_ep1_in_bytes_written() +{ + if (_usbd_get_ep_status(USB_EP_BULK_IN) != USB_EP_STATUS_IDLE) + return 0; + else + return (usbdaemon->ep_bytes_requested[USB_EP_BULK_IN] - (usbdaemon->qhs[USB_EP_BULK_IN].token >> 16)); +} + +int usb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_timeout) +{ + usb_ep_status_t ep_status; + do + { + ep_status = _usbd_get_ep1_status(USB_DIR_IN); + if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) + break; + + usbd_handle_ep0_ctrl_setup(); + } + while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); + + *pending_bytes = _usbd_get_ep1_in_bytes_written(); + + if (ep_status == USB_EP_STATUS_IDLE) + return USB_RES_OK; + else if (ep_status == USB_EP_STATUS_DISABLED) + return USB2_ERROR_XFER_EP_DISABLED; + + usb_device_stall_ep1_bulk_out(); + return USB_ERROR_XFER_ERROR; +} + +bool usb_device_get_suspended() +{ + bool suspended = (usbd_otg->regs->portsc1 & USB2D_PORTSC1_SUSP) == USB2D_PORTSC1_SUSP; + return suspended; +} + +bool usb_device_get_port_in_sleep() +{ + // Windows heuristic: Forces port into suspend, sleep and J-State. + return (usbd_otg->regs->portsc1) == 0x885; +} + +int usb_device_class_send_max_lun(u8 max_lun) +{ + // Timeout if get MAX_LUN request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + usbd_otg->max_lun = max_lun; + + while (!usbd_otg->max_lun_set) + { + usbd_handle_ep0_ctrl_setup(); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return USB_ERROR_USER_ABORT; + } + + return USB_RES_OK; +} + +int usb_device_class_send_hid_report() +{ + // Timeout if get GET_HID_REPORT request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + // Wait for request and transfer start. + while (!usbd_otg->hid_report_sent) + { + usbd_handle_ep0_ctrl_setup(); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return USB_ERROR_USER_ABORT; + } + + return USB_RES_OK; +} + +void usb_device_get_ops(usb_ops_t *ops) +{ + ops->usbd_flush_endpoint = usbd_flush_endpoint; + ops->usbd_set_ep_stall = usbd_set_ep_stall; + ops->usbd_handle_ep0_ctrl_setup = usbd_handle_ep0_ctrl_setup; + ops->usbd_end = usbd_end; + ops->usb_device_init = usb_device_init; + ops->usb_device_enumerate = usb_device_enumerate; + ops->usb_device_class_send_max_lun = usb_device_class_send_max_lun; + ops->usb_device_class_send_hid_report = usb_device_class_send_hid_report; + ops->usb_device_get_suspended = usb_device_get_suspended; + ops->usb_device_get_port_in_sleep = usb_device_get_port_in_sleep; + + ops->usb_device_ep1_out_read = usb_device_ep1_out_read; + ops->usb_device_ep1_out_read_big = usb_device_ep1_out_read_big; + ops->usb_device_ep1_out_reading_finish = usb_device_ep1_out_reading_finish; + ops->usb_device_ep1_in_write = usb_device_ep1_in_write; + ops->usb_device_ep1_in_writing_finish = usb_device_ep1_in_writing_finish; +} + diff --git a/bdk/usb/usbd.h b/bdk/usb/usbd.h new file mode 100644 index 0000000..86aa8fa --- /dev/null +++ b/bdk/usb/usbd.h @@ -0,0 +1,204 @@ +/* + * Enhanced & eXtensible USB Device (EDCI & XDCI) driver for Tegra X1 + * + * Copyright (c) 2019-2021 CTCaer + * + * 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 _USB_H_ +#define _USB_H_ + +#include + +#define USB_TD_BUFFER_PAGE_SIZE 0x1000 +#define USB_TD_BUFFER_MAX_SIZE (USB_TD_BUFFER_PAGE_SIZE * 4) +//#define USB_HW_BUFFER_5_PAGES 0x5000 +#define USB_EP_BUFFER_1_TD (USB_TD_BUFFER_MAX_SIZE) +#define USB_EP_BUFFER_2_TD (USB_TD_BUFFER_MAX_SIZE * 2) +#define USB_EP_BUFFER_4_TD (USB_TD_BUFFER_MAX_SIZE * 4) +#define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD) +#define USB_EP_BUFFER_ALIGN (USB_TD_BUFFER_PAGE_SIZE) + +#define USB_XFER_START 0 +#define USB_XFER_SYNCED_ENUM 1000000 +#define USB_XFER_SYNCED_CMD 1000000 +#define USB_XFER_SYNCED_DATA 2000000 +#define USB_XFER_SYNCED_CLASS 5000000 +#define USB_XFER_SYNCED -1 + +typedef enum _usb_hid_type +{ + USB_HID_GAMEPAD, + USB_HID_TOUCHPAD +} usb_hid_type; + +typedef enum _usb_gadget_type +{ + USB_GADGET_UMS = 0, + USB_GADGET_HID_GAMEPAD = 1, + USB_GADGET_HID_TOUCHPAD = 2, +} usb_gadget_type; + +typedef enum { + USB_DIR_OUT = 0, + USB_DIR_IN = 1, +} usb_dir_t; + +typedef enum +{ + XUSB_EP_CTRL_IN = 0, // EP0. + XUSB_EP_CTRL_OUT = 1, // EP0. + + USB_EP_CTRL_OUT = 0, // EP0. + USB_EP_CTRL_IN = 1, // EP0. + + USB_EP_BULK_OUT = 2, // EP1. + USB_EP_BULK_IN = 3, // EP1. + USB_EP_ALL = 0xFFFFFFFF +} usb_ep_t; + +typedef enum +{ + USB_EP_ADDR_CTRL_OUT = 0x00, + USB_EP_ADDR_CTRL_IN = 0x80, + USB_EP_ADDR_BULK_OUT = 0x01, + USB_EP_ADDR_BULK_IN = 0x81, +} usb_ep_addr_t; + +typedef enum +{ + USB_EP_CFG_CLEAR = 0, + USB_EP_CFG_RESET = 0, + USB_EP_CFG_STALL = 1 +} usb_ep_cfg_t; + +typedef enum { + USB_STATUS_EP_OK = 0, + USB_STATUS_EP_HALTED = 1, + + USB_STATUS_DEV_SELF_POWERED = 1, + USB_STATUS_DEV_REMOTE_WAKE = 2, +} usb_set_clear_feature_req_t; + +typedef enum { + USB_SETUP_RECIPIENT_DEVICE = 0, + USB_SETUP_RECIPIENT_INTERFACE = 1, + USB_SETUP_RECIPIENT_ENDPOINT = 2, + USB_SETUP_RECIPIENT_OTHER = 3, + + USB_SETUP_TYPE_STANDARD = 0x00, + USB_SETUP_TYPE_CLASS = 0x20, + USB_SETUP_TYPE_VENDOR = 0x40, + USB_SETUP_TYPE_RESERVED = 0x60, + + USB_SETUP_HOST_TO_DEVICE = 0x00, + USB_SETUP_DEVICE_TO_HOST = 0x80, +} usb_setup_req_type_t; + +typedef enum { + USB_REQUEST_GET_STATUS = 0, + USB_REQUEST_CLEAR_FEATURE = 1, + USB_REQUEST_SET_FEATURE = 3, + USB_REQUEST_SET_ADDRESS = 5, + USB_REQUEST_GET_DESCRIPTOR = 6, + USB_REQUEST_SET_DESCRIPTOR = 7, + USB_REQUEST_GET_CONFIGURATION = 8, + USB_REQUEST_SET_CONFIGURATION = 9, + USB_REQUEST_GET_INTERFACE = 10, + USB_REQUEST_SET_INTERFACE = 11, + USB_REQUEST_SYNCH_FRAME = 12, + USB_REQUEST_SET_SEL = 13, + + USB_REQUEST_GET_MS_DESCRIPTOR = 0x99, + + USB_REQUEST_BULK_GET_MAX_LUN = 0xFE, + USB_REQUEST_BULK_RESET = 0xFF +} usb_standard_req_t; + +typedef enum { + USB_FEATURE_ENDPOINT_HALT = 0, + USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, + USB_FEATURE_TEST_MODE = 2, +} usb_get_status_req_t; + +typedef enum _usb_error_t +{ + USB_RES_OK = 0, + USB_RES_BULK_RESET = 1, + + USB_ERROR_USER_ABORT = 2, + USB_ERROR_TIMEOUT = 3, + USB_ERROR_INIT = 4, + USB_ERROR_XFER_ERROR = 5, + + USB2_ERROR_XFER_EP_DISABLED = 28, + USB2_ERROR_XFER_NOT_ALIGNED = 29, + + XUSB_ERROR_INVALID_EP = USB_ERROR_XFER_ERROR, // From 2. + XUSB_ERROR_XFER_BULK_IN_RESIDUE = 7, + XUSB_ERROR_INVALID_CYCLE = USB2_ERROR_XFER_EP_DISABLED, // From 8. + XUSB_ERROR_BABBLE_DETECTED = 50, + XUSB_ERROR_SEQ_NUM = 51, + XUSB_ERROR_XFER_DIR = 52, + XUSB_ERROR_PORT_CFG = 54 +} usb_error_t; + +typedef struct _usb_ctrl_setup_t +{ + u8 bmRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} usb_ctrl_setup_t; + +typedef struct _usb_ops_t +{ + int (*usbd_flush_endpoint)(u32); + int (*usbd_set_ep_stall)(u32, int); + int (*usbd_handle_ep0_ctrl_setup)(); + void (*usbd_end)(bool, bool); + int (*usb_device_init)(); + int (*usb_device_enumerate)(usb_gadget_type gadget); + int (*usb_device_class_send_max_lun)(u8); + int (*usb_device_class_send_hid_report)(); + + int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, u32); + int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *); + int (*usb_device_ep1_out_reading_finish)(u32 *, u32); + int (*usb_device_ep1_in_write)(u8 *, u32, u32 *, u32); + int (*usb_device_ep1_in_writing_finish)(u32 *, u32); + bool (*usb_device_get_suspended)(); + bool (*usb_device_get_port_in_sleep)(); +} usb_ops_t; + +typedef struct _usb_ctxt_t +{ + u32 type; + u32 partition; + u32 offset; + u32 sectors; + u32 ro; + void (*system_maintenance)(bool); + void *label; + void (*set_text)(void *, const char *); +} usb_ctxt_t; + +void usb_device_get_ops(usb_ops_t *ops); +void xusb_device_get_ops(usb_ops_t *ops); + +int usb_device_gadget_ums(usb_ctxt_t *usbs); +int usb_device_gadget_hid(usb_ctxt_t *usbs); + +#endif \ No newline at end of file diff --git a/bdk/usb/xusbd.c b/bdk/usb/xusbd.c new file mode 100644 index 0000000..87df551 --- /dev/null +++ b/bdk/usb/xusbd.c @@ -0,0 +1,2215 @@ +/* + * eXtensible USB Device driver (XDCI) for Tegra X1 + * + * Copyright (c) 2020-2024 CTCaer + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define XUSB_TRB_SLOTS 16 //! TODO: Consider upping it. +#define XUSB_LINK_TRB_IDX (XUSB_TRB_SLOTS - 1) +#define XUSB_LAST_TRB_IDX (XUSB_TRB_SLOTS - 1) + +#define EP_DONT_RING 0 +#define EP_RING_DOORBELL 1 + +typedef enum { + XUSB_FULL_SPEED = 1, + XUSB_HIGH_SPEED = 3, + XUSB_SUPER_SPEED = 4 +} xusb_speed_t; + +typedef enum { + EP_DISABLED = 0, + EP_RUNNING = 1, + EP_HALTED = 2, + EP_STOPPED = 3, + EP_ERROR = 4 +} xusb_ep_status_t; + +typedef enum { + EP_TYPE_ISOC_OUT = 1, + EP_TYPE_BULK_OUT = 2, + EP_TYPE_INTR_OUT = 3, + EP_TYPE_CNTRL = 4, + EP_TYPE_ISOC_IN = 5, + EP_TYPE_BULK_IN = 6, + EP_TYPE_INTR_IN = 7 +} xusb_ep_type_t; + +typedef enum { + XUSB_DEFAULT = 0, + XUSB_ADDRESSED_STS_WAIT = 1, + XUSB_ADDRESSED = 2, + XUSB_CONFIGURED_STS_WAIT = 3, + XUSB_CONFIGURED = 4, + + XUSB_LUN_CONFIGURED_STS_WAIT = 5, + XUSB_LUN_CONFIGURED = 6, + XUSB_HID_CONFIGURED_STS_WAIT = 7, + XUSB_HID_CONFIGURED = 8, + + // XUSB_CONNECTED = , + // XUSB_DISCONNECTED = , + // XUSB_RESET = , + // XUSB_SUSPENDED = , +} xusb_dev_state_t; + +typedef enum { + XUSB_TRB_NONE = 0, + XUSB_TRB_NORMAL = 1, + XUSB_TRB_DATA = 3, + XUSB_TRB_STATUS = 4, + XUSB_TRB_LINK = 6, + XUSB_TRB_TRANSFER = 32, + XUSB_TRB_PORT_CHANGE = 34, + XUSB_TRB_SETUP = 63, +} xusb_trb_type_t; + +typedef enum { + XUSB_COMP_INVALID = 0, + XUSB_COMP_SUCCESS = 1, + XUSB_COMP_DATA_BUFFER_ERROR = 2, + XUSB_COMP_BABBLE_DETECTED_ERROR = 3, + XUSB_COMP_USB_TRANSACTION_ERROR = 4, + XUSB_COMP_TRB_ERROR = 5, + XUSB_COMP_STALL_ERROR = 6, + XUSB_COMP_RESOURCE_ERROR = 7, + XUSB_COMP_BANDWIDTH_ERROR = 8, + XUSB_COMP_NO_SLOTS_AVAILABLE_ERROR = 9, + XUSB_COMP_INVALID_STREAM_TYPE_ERROR = 10, + XUSB_COMP_SLOT_NOT_ENABLED_ERROR = 11, + XUSB_COMP_EP_DISABLED_ERROR = 12, + XUSB_COMP_SHORT_PKT = 13, + XUSB_COMP_RING_UNDERRUN = 14, + XUSB_COMP_RING_OVERRUN = 15, + XUSB_COMP_VF_EVENT_RING_FULL_ERROR = 16, + XUSB_COMP_PARAMETER_ERROR = 17, + XUSB_COMP_BANDWIDTH_OVERRUN_ERROR = 18, + XUSB_COMP_CONTEXT_STATE_ERROR = 19, + XUSB_COMP_NO_PING_RESPONSE_ERROR = 20, + XUSB_COMP_EVENT_RING_FULL_ERROR = 21, + XUSB_COMP_INCOMPATIBLE_DEVICE_ERROR = 22, + XUSB_COMP_MISSED_SERVICE_ERROR = 23, + XUSB_COMP_COMMAND_RING_STOPPED = 24, + XUSB_COMP_COMMAND_ABORTED = 25, + XUSB_COMP_STOPPED = 26, + XUSB_COMP_STOPPED_LENGTH_INVALID = 27, + XUSB_COMP_STOPPED_SHORT_PACKET = 28, + XUSB_COMP_EXIT_LATENCY_LARGE_ERROR = 29, + XUSB_COMP_ISOCH_BUFFER_OVERRUN = 31, + XUSB_COMP_EVENT_LOST_ERROR = 32, + XUSB_COMP_UNDEFINED_ERROR = 33, + XUSB_COMP_INVALID_STREAM_ID_ERROR = 34, + XUSB_COMP_SECONDARY_BANDWIDTH_ERROR = 35, + XUSB_COMP_SPLIT_TRANSACTION_ERROR = 36, + + XUSB_COMP_CODE_STREAM_NUMP_ERROR = 219, + XUSB_COMP_PRIME_PIPE_RECEIVED = 220, + XUSB_COMP_HOST_REJECTED = 221, + XUSB_COMP_CTRL_DIR_ERROR = 222, + XUSB_COMP_CTRL_SEQ_NUM_ERROR = 223 +} xusb_comp_code_t; + +typedef struct _event_trb_t +{ + u32 rsvd0; + u32 rsvd1; + + u32 rsvd2:24; + u32 comp_code:8; + + u32 cycle:1; + u32 rsvd3:9; + u32 trb_type:6; + u32 ep_id:5; + u32 rsvd4:11; +} event_trb_t; + +typedef struct _transfer_event_trb_t { + u32 trb_pointer_lo; + u32 trb_pointer_hi; + + u32 trb_tx_len:24; + u32 comp_code:8; + + u32 cycle:1; + u32 rsvddw3_0:1; + u32 event_data:1; + u32 rsvddw3_1:7; + u32 trb_type:6; + u32 ep_id:5; + u32 rsvddw3_2:11; +} transfer_event_trb_t; + +typedef struct _setup_event_trb_t +{ + usb_ctrl_setup_t ctrl_setup_data; + + u32 ctrl_seq_num:16; + u32 rsvddw2_0:8; + u32 comp_code:8; + + u32 cycle:1; + u32 rsvddw3_0:9; + u32 trb_type:6; + u32 ep_id:5; + u32 rsvddw3_1:11; +} setup_event_trb_t; + +typedef struct _status_trb_t +{ + u32 rsvd0; + u32 rsvd1; + + u32 rsvd2:22; + u32 interrupt_target:10; + + u32 cycle:1; + u32 ent:1; + u32 rsvd3_0:2; + u32 chain:1; + u32 ioc:1; + u32 rsvd3_1:4; + u32 trb_type:6; + u32 dir:1; + u32 rsvd3_2:15; +} status_trb_t; + +typedef struct _normal_trb_t +{ + u32 databufptr_lo; + u32 databufptr_hi; + + u32 trb_tx_len:17; + u32 td_size:5; + u32 interrupt_target:10; + + u32 cycle:1; + u32 ent:1; + u32 isp:1; + u32 no_snoop:1; + u32 chain:1; + u32 ioc:1; + u32 idt:1; + u32 rsvd0_0:2; + u32 bei:1; + u32 trb_type:6; + u32 rsvd0_1:16; +} normal_trb_t; + +typedef struct _data_trb_t +{ + u32 databufptr_lo; + u32 databufptr_hi; + + u32 trb_tx_len:17; + u32 td_size:5; + u32 interrupt_target:10; + + u32 cycle:1; + u32 ent:1; + u32 isp:1; + u32 no_snoop:1; + u32 chain:1; + u32 ioc:1; + u32 rsvd0_0:4; + u32 trb_type:6; + u32 dir:1; + u32 rsvd0_1:15; +} data_trb_t; + +typedef struct _link_trb_t +{ + u32 rsvd0_0:4; + u32 ring_seg_ptrlo:28; + + u32 ring_seg_ptrhi; + + u32 rsvd1_0:22; + u32 interrupt_target:10; + + u32 cycle:1; + u32 toggle_cycle:1; + u32 rsvd3_0:2; + u32 chain:1; + u32 ioc:1; + u32 rsvd3_1:4; + u32 trb_type:6; + u32 rsvd3_2:16; +} link_trb_t; + +typedef struct _xusb_ep_ctx_t +{ + // Common context. + u32 ep_state:3; + u32 rsvddW0_0:5; + u32 mult:2; + u32 max_pstreams:5; + u32 lsa:1; + u32 interval:8; + u32 rsvddW0_1:8; + + u32 rsvddw1_0:1; + u32 cerr:2; + u32 ep_type:3; + u32 rsvddw1_1:1; + u32 hid:1; + u32 max_burst_size:8; + u32 max_packet_size:16; + + u32 dcs:1; + u32 rsvddw2_0:3; + u32 trd_dequeueptr_lo:28; + + u32 trd_dequeueptr_hi; + + u32 avg_trb_len:16; + u32 max_esit_payload:16; + + // Nvidia context. + u32 event_data_txlen_acc; + + u32 cprog:8; + u32 sbyte:7; + u32 tp:2; + u32 rec:1; + u32 cec:2; + u32 ced:1; + u32 hsp1:1; + u32 rty1:1; + u32 std:1; + u32 status:8; + + u32 data_offset; + + u32 scratch_pad0; + + u32 scratch_pad1; + + u32 cping:8; + u32 sping:8; + u32 toggle_cycle:2; + u32 no_snoop:1; + u32 ro:1; + u32 tlm:1; + u32 dlm:1; + u32 hsp2:1; + u32 rty2:1; + u32 stop_rec_req:8; + + u32 device_addr:8; + u32 hub_addr:8; + u32 root_port_num:8; + u32 slot_id:8; + + u32 routing_string:20; + u32 speed:4; + u32 lpu:1; + u32 mtt:1; + u32 hub:1; + u32 dci:5; + + u32 tthub_slot_id:8; + u32 ttport_num:8; + u32 ssf:4; + u32 sps:2; + u32 interrupt_target:10; + + u32 frz:1; + u32 end:1; + u32 elm:1; + u32 mrx:1; + u32 ep_linklo:28; + + u32 ep_linkhi; +} xusb_ep_ctx_t; + +typedef struct _xusbd_controller_t +{ + data_trb_t *cntrl_epenqueue_ptr; + data_trb_t *cntrl_epdequeue_ptr; + u32 cntrl_producer_cycle; + data_trb_t *bulkout_epenqueue_ptr; + data_trb_t *bulkout_epdequeue_ptr; + u32 bulkout_producer_cycle; + data_trb_t *bulkin_epenqueue_ptr; + data_trb_t *bulkin_epdequeue_ptr; + u32 bulkin_producer_cycle; + event_trb_t *event_enqueue_ptr; + event_trb_t *event_dequeue_ptr; + u32 event_ccs; + u32 device_state; + u32 tx_bytes[2]; + u32 tx_count[2]; + u32 ctrl_seq_num; + u32 config_num; + u32 interface_num; + u32 wait_for_event_trb; + u32 port_speed; + + usb_desc_t *desc; + usb_gadget_type gadget; + + u8 max_lun; + bool max_lun_set; + bool bulk_reset_req; +} xusbd_controller_t; + +extern u32 hid_report_descriptor_jc_size; +extern u32 hid_report_descriptor_touch_size; +extern u8 hid_report_descriptor_jc[]; +extern u8 hid_report_descriptor_touch[]; +extern usb_desc_t usb_gadget_hid_jc_descriptors; +extern usb_desc_t usb_gadget_hid_touch_descriptors; +extern usb_desc_t usb_gadget_ums_descriptors; + +// All rings and EP context must be aligned to 0x10. +typedef struct _xusbd_event_queues_t +{ + event_trb_t xusb_event_ring_seg0[XUSB_TRB_SLOTS]; + event_trb_t xusb_event_ring_seg1[XUSB_TRB_SLOTS]; + data_trb_t xusb_cntrl_event_queue[XUSB_TRB_SLOTS]; + data_trb_t xusb_bulkin_event_queue[XUSB_TRB_SLOTS]; + data_trb_t xusb_bulkout_event_queue[XUSB_TRB_SLOTS]; + volatile xusb_ep_ctx_t xusb_ep_ctxt[4]; +} xusbd_event_queues_t; + +// Set event queues context to a 0x10 aligned address. +xusbd_event_queues_t *xusb_evtq = (xusbd_event_queues_t *)XUSB_RING_ADDR; + +xusbd_controller_t *usbd_xotg; +xusbd_controller_t usbd_xotg_controller_ctxt; + +static int _xusb_xhci_mask_wait(u32 reg, u32 mask, u32 val, u32 retries) +{ + do + { + if ((XUSB_DEV_XHCI(reg) & mask) == val) + return USB_RES_OK; + usleep(1); + --retries; + } + while (retries); + + return USB_ERROR_TIMEOUT; +} + +// Event rings aligned to 0x10 +static void _xusbd_ep_init_event_ring() +{ + memset(xusb_evtq->xusb_event_ring_seg0, 0, sizeof(xusb_evtq->xusb_event_ring_seg0)); + memset(xusb_evtq->xusb_event_ring_seg1, 0, sizeof(xusb_evtq->xusb_event_ring_seg1)); + + //! TODO USB3: enable pcie regulators. + + // Set Event Ring Segment 0 Base Address. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST0BALO) = (u32)xusb_evtq->xusb_event_ring_seg0; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST0BAHI) = 0; + + // Set Event Ring Segment 1 Base Address. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST1BALO) = (u32)xusb_evtq->xusb_event_ring_seg1; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST1BAHI) = 0; + + // Set Event Ring Segment sizes. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERSTSZ) = (XUSB_TRB_SLOTS << 16) | XUSB_TRB_SLOTS; + + // Set Enqueue and Dequeue pointers. + usbd_xotg->event_enqueue_ptr = xusb_evtq->xusb_event_ring_seg0; + usbd_xotg->event_dequeue_ptr = xusb_evtq->xusb_event_ring_seg0; + usbd_xotg->event_ccs = 1; + + // Event Ring Enqueue Pointer. + u32 evt_ring_addr = (u32)xusb_evtq->xusb_event_ring_seg0 & 0xFFFFFFF0; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) & 0xE) | evt_ring_addr | XCHI_ECS; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPHI) = 0; + + // Set Event Ring Dequeue Pointer. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) & 0xF) | evt_ring_addr; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPHI) = 0; +} + +static void _xusb_ep_set_type_and_metrics(u32 ep_idx, volatile xusb_ep_ctx_t *ep_ctxt) +{ + usb_ep_descr_t *ep_desc = NULL; + usb_ep_descr_t *endpoints = usbd_xotg->desc->cfg->endpoint; + + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + // Set EP type. + ep_ctxt->ep_type = EP_TYPE_CNTRL; + + // Set max packet size based on port speed. + ep_ctxt->avg_trb_len = 8; + ep_ctxt->max_packet_size = 64; //! TODO USB3: max_packet_size = 512. + break; + + case USB_EP_BULK_OUT: + // Set default EP type. + ep_ctxt->ep_type = EP_TYPE_BULK_OUT; + + // Check configuration descriptor. + if (usbd_xotg->desc->cfg->interface.bInterfaceClass == 0x3) // HID Class. + endpoints = (usb_ep_descr_t *)((void *)endpoints + sizeof(usb_hid_descr_t)); + + for (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++) + if (endpoints[i].bEndpointAddress == USB_EP_ADDR_BULK_OUT) + { + ep_desc = &endpoints[i]; + break; + } + + // Set actual EP type. + if (ep_desc) + { + switch (ep_desc->bmAttributes) + { + case USB_EP_TYPE_ISO: + ep_ctxt->ep_type = EP_TYPE_ISOC_OUT; + break; + case USB_EP_TYPE_BULK: + ep_ctxt->ep_type = EP_TYPE_BULK_OUT; + break; + case USB_EP_TYPE_INTR: + ep_ctxt->ep_type = EP_TYPE_INTR_OUT; + break; + } + } + + // Set average TRB length. + //TODO: Use ep type instead (we don't expect to calculate avg per gadget)? + switch (usbd_xotg->gadget) + { + case USB_GADGET_UMS: + ep_ctxt->avg_trb_len = 3072; + break; + case USB_GADGET_HID_GAMEPAD: + case USB_GADGET_HID_TOUCHPAD: + ep_ctxt->avg_trb_len = 1024; + break; + default: + switch (usbd_xotg->port_speed) + { + case XUSB_SUPER_SPEED: + ep_ctxt->avg_trb_len = 1024; + break; + case XUSB_HIGH_SPEED: + case XUSB_FULL_SPEED: + ep_ctxt->avg_trb_len = 512; + break; + } + break; + } + + // Set max burst rate. + ep_ctxt->max_burst_size = (ep_desc->wMaxPacketSize >> 11) & 3; + + // Set max packet size based on port speed. + if (usbd_xotg->port_speed == XUSB_SUPER_SPEED) + { + ep_ctxt->max_packet_size = 1024; + + //! TODO USB3: + // If ISO or INTR EP, set Max Esit Payload size. + // ep_ctxt->max_burst_size = bMaxBurst; + //if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT) + // ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) + { + ep_ctxt->max_packet_size = 512; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else + { + ep_ctxt->max_packet_size = 64; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size; + } + break; + + case USB_EP_BULK_IN: + // Set default EP type. + ep_ctxt->ep_type = EP_TYPE_BULK_IN; + + // Check configuration descriptor. + if (usbd_xotg->desc->cfg->interface.bInterfaceClass == 0x3) // HID Class. + endpoints = (usb_ep_descr_t *)((void *)endpoints + sizeof(usb_hid_descr_t)); + + for (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++) + if (endpoints[i].bEndpointAddress == USB_EP_ADDR_BULK_IN) + { + ep_desc = &endpoints[i]; + break; + } + + // Set actual EP type. + if (ep_desc) + { + switch (ep_desc->bmAttributes) + { + case USB_EP_TYPE_ISO: + ep_ctxt->ep_type = EP_TYPE_ISOC_IN; + break; + case USB_EP_TYPE_BULK: + ep_ctxt->ep_type = EP_TYPE_BULK_IN; + break; + case USB_EP_TYPE_INTR: + ep_ctxt->ep_type = EP_TYPE_INTR_IN; + break; + } + } + + // Set average TRB length. + //TODO: Use ep type instead (we don't expect to calculate avg per gadget)? + switch (usbd_xotg->gadget) + { + case USB_GADGET_UMS: + ep_ctxt->avg_trb_len = 3072; + break; + case USB_GADGET_HID_GAMEPAD: + case USB_GADGET_HID_TOUCHPAD: + ep_ctxt->avg_trb_len = 16; // Normal interrupt avg is 1024KB. + break; + default: + switch (usbd_xotg->port_speed) + { + case XUSB_SUPER_SPEED: + ep_ctxt->avg_trb_len = 1024; + break; + case XUSB_HIGH_SPEED: + case XUSB_FULL_SPEED: + ep_ctxt->avg_trb_len = 512; + break; + } + break; + } + + // Set max burst rate. + ep_ctxt->max_burst_size = (ep_desc->wMaxPacketSize >> 11) & 3; + + // Set max packet size based on port speed. + if (usbd_xotg->port_speed == XUSB_SUPER_SPEED) + { + ep_ctxt->max_packet_size = 1024; + + //! TODO USB3: + // If ISO or INTR EP, set Max Esit Payload size. + // ep_ctxt->max_burst_size = bMaxBurst; + //if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN) + // ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) + { + ep_ctxt->max_packet_size = 512; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1); + } + else + { + ep_ctxt->max_packet_size = 64; + + // If ISO or INTR EP, set Max Esit Payload size. + if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN) + ep_ctxt->max_esit_payload = ep_ctxt->max_packet_size; + } + break; + } +} + +static int _xusb_ep_init_context(u32 ep_idx) +{ + link_trb_t *link_trb; + + if (ep_idx > USB_EP_BULK_IN) + return USB_ERROR_INIT; + + if (ep_idx == XUSB_EP_CTRL_OUT) + ep_idx = XUSB_EP_CTRL_IN; + + volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[ep_idx]; + memset((void *)ep_ctxt, 0, sizeof(xusb_ep_ctx_t)); + + ep_ctxt->ep_state = EP_RUNNING; + ep_ctxt->dcs = 1; + ep_ctxt->cec = 3; + ep_ctxt->cerr = 3; + ep_ctxt->max_burst_size = 0; + + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + usbd_xotg->cntrl_producer_cycle = 1; + usbd_xotg->cntrl_epenqueue_ptr = xusb_evtq->xusb_cntrl_event_queue; + usbd_xotg->cntrl_epdequeue_ptr = xusb_evtq->xusb_cntrl_event_queue; + + _xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt); + + ep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_cntrl_event_queue >> 4; + ep_ctxt->trd_dequeueptr_hi = 0; + + link_trb = (link_trb_t *)&xusb_evtq->xusb_cntrl_event_queue[XUSB_LINK_TRB_IDX]; + link_trb->toggle_cycle = 1; + link_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_cntrl_event_queue >> 4; + link_trb->ring_seg_ptrhi = 0; + link_trb->trb_type = XUSB_TRB_LINK; + break; + + case USB_EP_BULK_OUT: + usbd_xotg->bulkout_producer_cycle = 1; + usbd_xotg->bulkout_epenqueue_ptr = xusb_evtq->xusb_bulkout_event_queue; + usbd_xotg->bulkout_epdequeue_ptr = xusb_evtq->xusb_bulkout_event_queue; + + _xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt); + + ep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_bulkout_event_queue >> 4; + ep_ctxt->trd_dequeueptr_hi = 0; + + link_trb = (link_trb_t *)&xusb_evtq->xusb_bulkout_event_queue[XUSB_LINK_TRB_IDX]; + link_trb->toggle_cycle = 1; + link_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_bulkout_event_queue >> 4; + link_trb->ring_seg_ptrhi = 0; + link_trb->trb_type = XUSB_TRB_LINK; + break; + + case USB_EP_BULK_IN: + usbd_xotg->bulkin_producer_cycle = 1; + usbd_xotg->bulkin_epenqueue_ptr = xusb_evtq->xusb_bulkin_event_queue; + usbd_xotg->bulkin_epdequeue_ptr = xusb_evtq->xusb_bulkin_event_queue; + + _xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt); + + ep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_bulkin_event_queue >> 4; + ep_ctxt->trd_dequeueptr_hi = 0; + + link_trb = (link_trb_t *)&xusb_evtq->xusb_bulkin_event_queue[XUSB_LINK_TRB_IDX]; + link_trb->toggle_cycle = 1; + link_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_bulkin_event_queue >> 4; + link_trb->ring_seg_ptrhi = 0; + link_trb->trb_type = XUSB_TRB_LINK; + break; + } + + return USB_RES_OK; +} + +static int _xusbd_ep_initialize(u32 ep_idx) +{ + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + case XUSB_EP_CTRL_OUT: + return _xusb_ep_init_context(XUSB_EP_CTRL_IN); + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + _xusb_ep_init_context(ep_idx); + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_RELOAD) = BIT(ep_idx); + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_RELOAD, BIT(ep_idx), 0, 1000); + if (!res) + { + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_PAUSE) &= ~BIT(ep_idx); + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~BIT(ep_idx); + } + return res; + default: + return USB_ERROR_INIT; + } +} + +static void _xusbd_ep1_disable(u32 ep_idx) +{ + volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[ep_idx]; + u32 ep_mask = BIT(ep_idx); + + switch (ep_idx) + { + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + // Skip if already disabled. + if (!ep_ctxt->ep_state) + return; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask; + + // Set EP state to disabled. + ep_ctxt->ep_state = EP_DISABLED; + + // Wait for EP status to change. + _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000); + + // Clear status change. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask; + break; + } +} + +static void _xusb_disable_ep1() +{ + _xusbd_ep1_disable(USB_EP_BULK_OUT); + _xusbd_ep1_disable(USB_EP_BULK_IN); + + // Device mode stop. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) &= ~XHCI_CTRL_RUN; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_RC; + + usbd_xotg->config_num = 0; + usbd_xotg->interface_num = 0; + usbd_xotg->max_lun_set = false; + usbd_xotg->device_state = XUSB_DEFAULT; +} + +static void _xusb_init_phy() +{ + // Configure and enable PLLU. + clock_enable_pllu(); + + // Enable IDDQ control by software and disable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0xFFFFFFFC) | 1; + + // Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz. + clock_enable_utmipll(); + + // Set UTMIP misc config. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFE8) | 0x2000008 | 0x20 | 2; + usleep(2); + + // Set OTG PAD0 calibration. + u32 fuse_usb_calib = FUSE(FUSE_USB_CALIB); + // Set HS_CURR_LEVEL. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) = (XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) & 0xFFFFFFC0) | (fuse_usb_calib & 0x3F); + // Set TERM_RANGE_ADJ and RPD_CTRL. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) = (XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) & 0x83FFFF87) | ((fuse_usb_calib & 0x780) >> 4) | ((u32)(FUSE(FUSE_USB_CALIB_EXT) << 27) >> 1); + + // Set VREG_LEV to 1. + XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1) = (XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1) & 0xFFFFFE3F) | 0x80; + + // Disable power down on usb2 ports pads. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) &= 0xDBFFFFFF; // Clear pad power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) &= 0xFFFFFFFB; // Clear pad dr power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL0) &= 0xFFFFFFFE; // Clear charging power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_0) &= 0xFFFFF7FF; // Clear bias power down. + (void)XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1); // Commit write. + + // Enable USB2 tracking clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_USB2_TRK); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4. + + // Set tracking parameters and trigger it. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x451E000; + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x51E000; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x451E000; + usleep(3); + + // Re-trigger it. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x51E000; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + XUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) |= 0x4000000; + + // Disable USB2 tracking clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_CLR) = BIT(CLK_Y_USB2_TRK); + + // Wait for XUSB PHY to stabilize. + usleep(30); +} + +static void _xusbd_init_device_clocks() +{ + // Disable reset to PLLU_OUT1 + CLOCK(CLK_RST_CONTROLLER_PLLU_OUTA) |= 1; + usleep(2); + + // Enable XUSB device clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = BIT(CLK_U_XUSB_DEV); + + // Set XUSB device core clock source to PLLP for a 102MHz result. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV) & 0x1FFFFF00) | (1 << 29) | 6; + usleep(2); + + // Set XUSB Full-Speed logic clock source to FO 48MHz. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) & 0x1FFFFFFF) | (2 << 29); + + // Enable XUSB Super-Speed logic clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB_SS); + + // Set XUSB Super-Speed logic clock source to HSIC 480MHz for 120MHz result and source FS logic clock from Super-Speed. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) & 0x1FFFFF00) | (3 << 29) | 6; + + // Clear reset to XUSB device and Super-Speed logic. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_SS); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = BIT(CLK_U_XUSB_DEV); + usleep(2); +} + +int xusb_device_init() +{ + // Ease the stress to APB. + bpmp_clk_rate_relaxed(true); + + // Disable USB2 device controller clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD); + + // Enable XUSB clock and clear Reset to XUSB Pad Control. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_PADCTL); + usleep(2); + + // USB2 Pads to XUSB. + XUSB_PADCTL(XUSB_PADCTL_USB2_PAD_MUX) = + (XUSB_PADCTL(XUSB_PADCTL_USB2_PAD_MUX) & ~(PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK | PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK)) | + PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB | PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB; + + // Initialize XUSB controller PHY. + _xusb_init_phy(); + + // Set USB2.0 Port 0 to device mode. + XUSB_PADCTL(XUSB_PADCTL_USB2_PORT_CAP) = (XUSB_PADCTL(XUSB_PADCTL_USB2_PORT_CAP) & ~PADCTL_USB2_PORT_CAP_PORT_0_CAP_MASK) | PADCTL_USB2_PORT_CAP_PORT_0_CAP_DEV; + + //! TODO USB3 + // // Set USB3.0 Port 0 cap to device. + // XUSB_PADCTL(XUSB_PADCTL_SS_PORT_CAP) = (XUSB_PADCTL(XUSB_PADCTL_SS_PORT_CAP) & ~PADCTL_SS_PORT_CAP_0_PORT1_CAP_MASK) | PADCTL_SS_PORT_CAP_0_PORT1_CAP_DEVICE_ONLY; + + // Set Super Speed Port 0 to USB2 Port 0. + XUSB_PADCTL(XUSB_PADCTL_SS_PORT_MAP) &= ~PADCTL_SS_PORT_MAP_PORT0_MASK; // 0: USB2_PORT0 + + // Power Up ID Wake up and Vbus Wake Up for UTMIP + PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; + usleep(1); + + // Initialize device clocks. + _xusbd_init_device_clocks(); + + // Restore OC. + bpmp_clk_rate_relaxed(false); + + // Enable AHB redirect for access to IRAM for Event/EP ring buffers. + mc_enable_ahb_redirect(); + + // Enable XUSB device IPFS. + XUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI; + + // Configure PCI and BAR0 address space. + XUSB_DEV_PCI(XUSB_CFG_1) |= CFG_1_BUS_MASTER | CFG_1_MEMORY_SPACE | CFG_1_IO_SPACE; + usleep(1); + XUSB_DEV_PCI(XUSB_CFG_4) = XUSB_DEV_BASE | CFG_4_ADDRESS_TYPE_32_BIT; + + // Mask SATA interrupt to MCORE. + XUSB_DEV_DEV(XUSB_DEV_INTR_MASK) |= DEV_INTR_MASK_IP_INT_MASK; + + // AHB USB performance cfg. + AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_USB3) |= AHB_GIZMO_IMMEDIATE; + AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7) | PRIORITY_SELECT_USB3; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = MEM_PREFETCH_ENABLE | MEM_PREFETCH_USB3_MST_ID | + MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles. + + // Initialize context. + usbd_xotg = &usbd_xotg_controller_ctxt; + memset(usbd_xotg, 0, sizeof(xusbd_controller_t)); + + // Initialize event and EP rings. + _xusbd_ep_init_event_ring(); + memset(xusb_evtq->xusb_cntrl_event_queue, 0, sizeof(xusb_evtq->xusb_cntrl_event_queue)); + memset(xusb_evtq->xusb_bulkin_event_queue, 0, sizeof(xusb_evtq->xusb_bulkin_event_queue)); + memset(xusb_evtq->xusb_bulkout_event_queue, 0, sizeof(xusb_evtq->xusb_bulkout_event_queue)); + + // Initialize Control EP. + int res = _xusbd_ep_initialize(XUSB_EP_CTRL_IN); + if (res) + return USB_ERROR_INIT; + + // Enable events and interrupts. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_IE | XHCI_CTRL_LSE; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPLO) = (u32)xusb_evtq->xusb_ep_ctxt & 0xFFFFFFF0; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPHI) = 0; + + //! TODO USB3: + // XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) |= DEV_XHCI_PORTHALT_STCHG_INTR_EN; + + return USB_RES_OK; +} + +//! TODO: Power down more stuff. +static void _xusb_device_power_down() +{ + // Disable clock for XUSB Super-Speed and set source to CLK_M. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) &= 0x1FFFFF00; + usleep(2); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB_SS); + + // Put XUSB device into reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_XUSB_DEV); + usleep(2); + + // Reset Full-Speed clock source to CLK_M and div1. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) = 0; + usleep(2); + + // Disable XUSB device clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_XUSB_DEV); + + // Force UTMIP_PLL power down. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) &= (~BIT(15)); + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= BIT(4) | BIT(0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. + + // Force enable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 3; + + // Disable PLLU. + clock_disable_pllu(); + + // Set XUSB_PADCTL clock reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); + + // Disable XUSB clock. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB); +} + +static int _xusb_queue_trb(u32 ep_idx, const void *trb, bool ring_doorbell) +{ + int res = USB_RES_OK; + data_trb_t *next_trb; + link_trb_t *link_trb; + + // Copy TRB and advance Enqueue list. + switch (ep_idx) + { + case XUSB_EP_CTRL_IN: + memcpy(usbd_xotg->cntrl_epenqueue_ptr, trb, sizeof(data_trb_t)); + + // Advance queue and if Link TRB set index to 0 and toggle cycle bit. + next_trb = &usbd_xotg->cntrl_epenqueue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + { + link_trb = (link_trb_t *)next_trb; + link_trb->cycle = usbd_xotg->cntrl_producer_cycle & 1; + link_trb->toggle_cycle = 1; + + next_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4); + + usbd_xotg->cntrl_producer_cycle ^= 1; + } + usbd_xotg->cntrl_epenqueue_ptr = next_trb; + break; + + case USB_EP_BULK_OUT: + memcpy(usbd_xotg->bulkout_epenqueue_ptr, trb, sizeof(data_trb_t)); + + // Advance queue and if Link TRB set index to 0 and toggle cycle bit. + next_trb = &usbd_xotg->bulkout_epenqueue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + { + link_trb = (link_trb_t *)next_trb; + link_trb->cycle = usbd_xotg->bulkout_producer_cycle & 1; + link_trb->toggle_cycle = 1; + + next_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4); + + usbd_xotg->bulkout_producer_cycle ^= 1; + } + usbd_xotg->bulkout_epenqueue_ptr = next_trb; + break; + + case USB_EP_BULK_IN: + memcpy(usbd_xotg->bulkin_epenqueue_ptr, trb, sizeof(data_trb_t)); + + // Advance queue and if Link TRB set index to 0 and toggle cycle bit. + next_trb = &usbd_xotg->bulkin_epenqueue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + { + link_trb = (link_trb_t *)next_trb; + link_trb->cycle = usbd_xotg->bulkin_producer_cycle & 1; + link_trb->toggle_cycle = 1; + + next_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4); + + usbd_xotg->bulkin_producer_cycle ^= 1; + } + usbd_xotg->bulkin_epenqueue_ptr = next_trb; + break; + + case XUSB_EP_CTRL_OUT: + default: + res = XUSB_ERROR_INVALID_EP; + break; + } + + // Ring doorbell. + if (ring_doorbell) + { + // Flush data before transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false); + + u32 target_id = (ep_idx << 8) & 0xFFFF; + if (ep_idx == XUSB_EP_CTRL_IN) + target_id |= usbd_xotg->ctrl_seq_num << 16; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_DB) = target_id; + } + + return res; +} + +static void _xusb_create_status_trb(status_trb_t *trb, usb_dir_t direction) +{ + trb->cycle = usbd_xotg->cntrl_producer_cycle & 1; + trb->ioc = 1; // Enable interrupt on completion. + trb->trb_type = XUSB_TRB_STATUS; + trb->dir = direction; +} + +static void _xusb_create_normal_trb(normal_trb_t *trb, u8 *buf, u32 len, usb_dir_t direction) +{ + u8 producer_cycle; + + trb->databufptr_lo = (u32)buf; + trb->databufptr_hi = 0; + + trb->trb_tx_len = len; + + // Single TRB transfer. + trb->td_size = 0; + trb->chain = 0; + + if (direction == USB_DIR_IN) + producer_cycle = usbd_xotg->bulkin_producer_cycle & 1; + else + producer_cycle = usbd_xotg->bulkout_producer_cycle & 1; + + trb->cycle = producer_cycle; + trb->isp = 1; // Enable interrupt on short packet. + trb->ioc = 1; // Enable interrupt on completion. + trb->trb_type = XUSB_TRB_NORMAL; +} + +static void _xusb_create_data_trb(data_trb_t *trb, u8 *buf, u32 len, usb_dir_t direction) +{ + trb->databufptr_lo = (u32)buf; + trb->databufptr_hi = 0; + + trb->trb_tx_len = len; + + // Single TRB transfer. + trb->td_size = 0; + trb->chain = 0; + + trb->cycle = usbd_xotg->cntrl_producer_cycle & 1; + trb->isp = 1; // Enable interrupt on short packet. + trb->ioc = 1; // Enable interrupt on completion. + trb->trb_type = XUSB_TRB_DATA; + trb->dir = direction; +} + +static int _xusb_issue_status_trb(usb_dir_t direction) +{ + int res = USB_RES_OK; + status_trb_t trb = {0}; + + if (usbd_xotg->cntrl_epenqueue_ptr == usbd_xotg->cntrl_epdequeue_ptr || direction == USB_DIR_OUT) + { + _xusb_create_status_trb(&trb, direction); + + res = _xusb_queue_trb(XUSB_EP_CTRL_IN, &trb, EP_RING_DOORBELL); + usbd_xotg->wait_for_event_trb = XUSB_TRB_STATUS; + } + + return res; +} + +static int _xusb_issue_normal_trb(u8 *buf, u32 len, usb_dir_t direction) +{ + normal_trb_t trb = {0}; + + _xusb_create_normal_trb(&trb, buf, len, direction); + u32 ep_idx = USB_EP_BULK_IN; + if (direction == USB_DIR_OUT) + ep_idx = USB_EP_BULK_OUT; + + int res = _xusb_queue_trb(ep_idx, &trb, EP_RING_DOORBELL); + if (!res) + usbd_xotg->wait_for_event_trb = XUSB_TRB_NORMAL; + + return res; +} + +static int _xusb_issue_data_trb(u8 *buf, u32 len, usb_dir_t direction) +{ + data_trb_t trb = {0}; + + int res = USB_RES_OK; + if (usbd_xotg->cntrl_epenqueue_ptr == usbd_xotg->cntrl_epdequeue_ptr) + { + _xusb_create_data_trb(&trb, buf, len, direction); + + res = _xusb_queue_trb(XUSB_EP_CTRL_IN, &trb, EP_RING_DOORBELL); + if (!res) + usbd_xotg->wait_for_event_trb = XUSB_TRB_DATA; + } + return res; +} + +int xusb_set_ep_stall(u32 endpoint, int ep_stall) +{ + u32 ep_mask = BIT(endpoint); + if (ep_stall) + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask; + else + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_mask; + + // Wait for EP status to change. + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000); + if (res) + return res; + + // Clear status change. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask; + + return USB_RES_OK; +} + +static int _xusb_wait_ep_stopped(u32 endpoint) +{ + u32 ep_mask = BIT(endpoint); + + // Wait for EP status to change. + _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STOPPED, ep_mask, ep_mask, 1000); + + // Clear status change. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STOPPED) = ep_mask; + + return USB_RES_OK; +} + +static int _xusb_handle_transfer_event(const transfer_event_trb_t *trb) +{ + // Advance dequeue list. + data_trb_t *next_trb; + switch (trb->ep_id) + { + case XUSB_EP_CTRL_IN: + next_trb = &usbd_xotg->cntrl_epdequeue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + next_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0); + usbd_xotg->cntrl_epdequeue_ptr = next_trb; + break; + case USB_EP_BULK_OUT: + next_trb = &usbd_xotg->bulkout_epdequeue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + next_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0); + usbd_xotg->bulkout_epdequeue_ptr = next_trb; + break; + case USB_EP_BULK_IN: + next_trb = &usbd_xotg->bulkin_epdequeue_ptr[1]; + if (next_trb->trb_type == XUSB_TRB_LINK) + next_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0); + usbd_xotg->bulkin_epdequeue_ptr = next_trb; + break; + default: + // Should never happen. + break; + } + + // Handle completion code. + switch (trb->comp_code) + { + case XUSB_COMP_SUCCESS: + case XUSB_COMP_SHORT_PKT: + switch (trb->ep_id) + { + case XUSB_EP_CTRL_IN: + if (usbd_xotg->wait_for_event_trb == XUSB_TRB_DATA) + return _xusb_issue_status_trb(USB_DIR_OUT); + else if (usbd_xotg->wait_for_event_trb == XUSB_TRB_STATUS) + { + switch (usbd_xotg->device_state) + { + case XUSB_ADDRESSED_STS_WAIT: + usbd_xotg->device_state = XUSB_ADDRESSED; + break; + case XUSB_CONFIGURED_STS_WAIT: + usbd_xotg->device_state = XUSB_CONFIGURED; + break; + case XUSB_LUN_CONFIGURED_STS_WAIT: + usbd_xotg->device_state = XUSB_LUN_CONFIGURED; + break; + case XUSB_HID_CONFIGURED_STS_WAIT: + usbd_xotg->device_state = XUSB_HID_CONFIGURED; + break; + } + } + break; + + case USB_EP_BULK_IN: + usbd_xotg->tx_bytes[USB_DIR_IN] -= trb->trb_tx_len; + if (usbd_xotg->tx_count[USB_DIR_IN]) + usbd_xotg->tx_count[USB_DIR_IN]--; + + // If bytes remaining for a Bulk IN transfer, return error. + if (trb->trb_tx_len) + return XUSB_ERROR_XFER_BULK_IN_RESIDUE; + break; + + case USB_EP_BULK_OUT: + // If short packet and Bulk OUT, it's not an error because we prime EP for 4KB. + usbd_xotg->tx_bytes[USB_DIR_OUT] -= trb->trb_tx_len; + if (usbd_xotg->tx_count[USB_DIR_OUT]) + usbd_xotg->tx_count[USB_DIR_OUT]--; + break; + } + return USB_RES_OK; +/* + case XUSB_COMP_USB_TRANSACTION_ERROR: + case XUSB_COMP_TRB_ERROR: + case XUSB_COMP_RING_UNDERRUN: + case XUSB_COMP_RING_OVERRUN: + case XUSB_COMP_CTRL_DIR_ERROR: // Redefined. + xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL); + return USB_RES_OK; +*/ + case XUSB_COMP_BABBLE_DETECTED_ERROR: + _xusb_wait_ep_stopped(trb->ep_id); + xusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL); + return XUSB_ERROR_BABBLE_DETECTED; + + case XUSB_COMP_CTRL_DIR_ERROR: + return XUSB_ERROR_XFER_DIR; + + case XUSB_COMP_CTRL_SEQ_NUM_ERROR: + return XUSB_ERROR_SEQ_NUM; //! TODO: Can mean a new setup packet was received. + + default: // Every other completion code. + return USB_ERROR_XFER_ERROR; + } +} + +/* + * Other XUSB impl: + * CBT: PR, PRC, WPR, WRC, CSC, REQ, PLC, CEC. + * LNX: REQ, PRC PR, PRC & !PR, WRC, CSC, PLC, CEC. + * BRO: CSC, PR | PRC, WPR | WRC, REQ, PLC, CEC. + */ + +static int _xusb_handle_port_change() +{ + u32 status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + u32 halt = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); + u32 clear_mask = XHCI_PORTSC_CEC | XHCI_PORTSC_PLC | XHCI_PORTSC_PRC | XHCI_PORTSC_WRC | XHCI_PORTSC_CSC; + + // Port reset (PR). + if (status & XHCI_PORTSC_PR) + { + //! TODO: + // XHCI_PORTSC_PR: device_state = XUSB_RESET + + //_disable_usb_wdt4(); + } + + // Port Reset Change (PRC). + if (status & XHCI_PORTSC_PRC) + { + // Clear PRC bit. + status &= ~clear_mask; + status |= XHCI_PORTSC_PRC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Warm Port Reset (WPR). + if (status & XHCI_PORTSC_WPR) + { + //_disable_usb_wdt4(); + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + (void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); + + //! TODO: XHCI_PORTSC_WPR: device_state = XUSB_RESET + } + + // Warm Port Reset Change (WRC). + if (status & XHCI_PORTSC_WRC) + { + // Clear WRC bit. + status &= ~clear_mask; + status |= XHCI_PORTSC_WRC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Reread port status to handle more changes. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + + // Connect Status Change (CSC). + if (status & XHCI_PORTSC_CSC) + { + //! TODO: Check CCS. + // CCS check seems to be + // XHCI_PORTSC_CCS 1: device_state = XUSB_CONNECTED + // XHCI_PORTSC_CCS 0: device_state = XUSB_DISCONNECTED + // Always do XHCI_PORTSC_CSC bit clear. + + // Set port speed. + usbd_xotg->port_speed = (status & XHCI_PORTSC_PS) >> 10; + + // In case host does not support Super Speed, revert the control EP packet size. + if (usbd_xotg->port_speed != XUSB_SUPER_SPEED) + { + volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN]; + ep_ctxt->avg_trb_len = 8; + ep_ctxt->max_packet_size = 64; + //! TODO: If super speed is supported, ep context reload, unpause and unhalt must happen. + } + + // Clear CSC bit. + status &= ~clear_mask; + status |= XHCI_PORTSC_CSC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Handle Config Request (STCHG_REQ). + if (halt & XHCI_PORTHALT_STCHG_REQ) + { + // Clear Link Training Status and pending request/reject. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + (void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT); + } + + // Reread port status to handle more changes. + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + + // Port link state change (PLC). + if (status & XHCI_PORTSC_PLC) + { + // check XHCI_PORTSC_PLS_MASK + // if XHCI_PORTSC_PLS_U3 + // device_state = XUSB_SUSPENDED + // else if XHCI_PORTSC_PLS_U0 and XUSB_SUSPENDED + // val = XUSB_DEV_XHCI_EP_PAUSE + // XUSB_DEV_XHCI_EP_PAUSE = 0 + // XUSB_DEV_XHCI_EP_STCHG = val; + + // Clear PLC bit. + status &= ~clear_mask; + status |= XHCI_PORTSC_PLC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + } + + // Port configuration link error (CEC). + if (status & XHCI_PORTSC_CEC) + { + status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC); + status &= ~clear_mask; + status |= XHCI_PORTSC_CEC; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status; + + return XUSB_ERROR_PORT_CFG; + } + + return USB_RES_OK; +} + +static int _xusb_handle_get_ep_status(u32 ep_idx) +{ + u32 ep_mask = BIT(ep_idx); + static u8 xusb_ep_status_descriptor[2] = {0}; + + xusb_ep_status_descriptor[0] = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) & ep_mask) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK; + + return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN); +} + +static int _xusb_handle_get_class_request(const usb_ctrl_setup_t *ctrl_setup) +{ + u8 _bRequest = ctrl_setup->bRequest; + u16 _wIndex = ctrl_setup->wIndex; + u16 _wValue = ctrl_setup->wValue; + u16 _wLength = ctrl_setup->wLength; + + bool valid_interface = _wIndex == usbd_xotg->interface_num; + bool valid_len = (_bRequest == USB_REQUEST_BULK_GET_MAX_LUN) ? 1 : 0; + + if (!valid_interface || _wValue != 0 || _wLength != valid_len) + goto stall; + + switch (_bRequest) + { + case USB_REQUEST_BULK_RESET: + usbd_xotg->bulk_reset_req = true; + return _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS; + + case USB_REQUEST_BULK_GET_MAX_LUN: + if (!usbd_xotg->max_lun_set) + goto stall; + usbd_xotg->device_state = XUSB_LUN_CONFIGURED_STS_WAIT; + return _xusb_issue_data_trb(&usbd_xotg->max_lun, 1, USB_DIR_IN); + } + +stall: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; +} + +static int _xusb_handle_get_descriptor(const usb_ctrl_setup_t *ctrl_setup) +{ + u32 size; + void *descriptor; + + u32 wLength = ctrl_setup->wLength; + + u8 descriptor_type = ctrl_setup->wValue >> 8; + u8 descriptor_subtype = ctrl_setup->wValue & 0xFF; + + switch (descriptor_type) + { + case USB_DESCRIPTOR_DEVICE: + //! TODO USB3: Provide a super speed descriptor. +/* + u32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV); + usb_device_descriptor.idProduct = (soc_rev >> 8) & 0xFF; // chip_id. + usb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM. + usb_device_descriptor.bcdDevice = (soc_rev >> 16) & 0xF; // MINORREV. + usb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV. +*/ + descriptor = usbd_xotg->desc->dev; + size = usbd_xotg->desc->dev->bLength; + break; + case USB_DESCRIPTOR_CONFIGURATION: + //! TODO USB3: Provide a super speed descriptor. + if (usbd_xotg->gadget == USB_GADGET_UMS) + { + if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) // High speed. 512 bytes. + { + usbd_xotg->desc->cfg->endpoint[0].wMaxPacketSize = 0x200; // No burst. + usbd_xotg->desc->cfg->endpoint[1].wMaxPacketSize = 0x200; // No burst. + } + else // Full speed. 64 bytes. + { + usbd_xotg->desc->cfg->endpoint[0].wMaxPacketSize = 0x40; + usbd_xotg->desc->cfg->endpoint[1].wMaxPacketSize = 0x40; + } + } + else + { + usb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_xotg->desc->cfg; + if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) // High speed. 512 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x200; + tmp->endpoint[1].wMaxPacketSize = 0x200; + tmp->endpoint[0].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms. + } + else // Full speed. 64 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x40; + tmp->endpoint[1].wMaxPacketSize = 0x40; + tmp->endpoint[0].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + tmp->endpoint[1].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms. + } + } + descriptor = usbd_xotg->desc->cfg; + size = usbd_xotg->desc->cfg->config.wTotalLength; + break; + case USB_DESCRIPTOR_STRING: + switch (descriptor_subtype) + { + case 1: + descriptor = usbd_xotg->desc->vendor; + size = usbd_xotg->desc->vendor[0]; + break; + case 2: + descriptor = usbd_xotg->desc->product; + size = usbd_xotg->desc->product[0]; + break; + case 3: + descriptor = usbd_xotg->desc->serial; + size = usbd_xotg->desc->serial[0]; + break; + case 0xEE: + descriptor = usbd_xotg->desc->ms_os; + size = usbd_xotg->desc->ms_os->bLength; + break; + default: + descriptor = usbd_xotg->desc->lang_id; + size = 4; + break; + } + break; + case USB_DESCRIPTOR_DEVICE_QUALIFIER: + if (!usbd_xotg->desc->dev_qual) + { + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + usbd_xotg->desc->dev_qual->bNumOtherConfigs = 0; + descriptor = usbd_xotg->desc->dev_qual; + size = usbd_xotg->desc->dev_qual->bLength; + break; + case USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION: + if (!usbd_xotg->desc->cfg_other) + { + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + if (usbd_xotg->port_speed == XUSB_HIGH_SPEED) + { + usbd_xotg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x40; + usbd_xotg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x40; + } + else + { + usbd_xotg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x200; + usbd_xotg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x200; + } + descriptor = usbd_xotg->desc->cfg_other; + size = usbd_xotg->desc->cfg_other->config.wTotalLength; + break; + case USB_DESCRIPTOR_DEVICE_BINARY_OBJECT: + descriptor = usbd_xotg->desc->dev_bot; + size = usbd_xotg->desc->dev_bot->wTotalLength; + break; + default: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + + if (wLength < size) + size = wLength; + + return _xusb_issue_data_trb(descriptor, size, USB_DIR_IN); +} + +static void _xusb_handle_set_request_dev_address(const usb_ctrl_setup_t *ctrl_setup) +{ + u32 addr = ctrl_setup->wValue & 0xFF; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) & 0x80FFFFFF) | (addr << 24); + xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN].device_addr = addr; + + _xusb_issue_status_trb(USB_DIR_IN); + + usbd_xotg->device_state = XUSB_ADDRESSED_STS_WAIT; +} + +static void _xusb_handle_set_request_configuration(const usb_ctrl_setup_t *ctrl_setup) +{ + usbd_xotg->config_num = ctrl_setup->wValue; + + // Remove configuration. + if (!usbd_xotg->config_num) + { + //! TODO: Signal that to userspace. + _xusb_disable_ep1(); + + _xusb_issue_status_trb(USB_DIR_IN); + + return; + } + + // Initialize BULK EPs. + _xusbd_ep_initialize(USB_EP_BULK_OUT); + _xusbd_ep_initialize(USB_EP_BULK_IN); + + // Device mode start. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_RUN; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_RC; + + _xusb_issue_status_trb(USB_DIR_IN); + usbd_xotg->device_state = XUSB_CONFIGURED_STS_WAIT; +} + +static int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup) +{ + u32 size; + u8 *desc; + bool ep_stall = false; + bool transmit_data = false; + + u8 _bmRequestType = ctrl_setup->bmRequestType; + u8 _bRequest = ctrl_setup->bRequest; + u16 _wValue = ctrl_setup->wValue; + u16 _wIndex = ctrl_setup->wIndex; + u16 _wLength = ctrl_setup->wLength; + + static u8 xusb_dev_status_descriptor[2] = {USB_STATUS_DEV_SELF_POWERED, 0}; + static u8 xusb_interface_descriptor[4] = {0}; + static u8 xusb_configuration_descriptor[2] = {0}; + static u8 xusb_status_descriptor[2] = {0}; + + //gfx_printf("ctrl: %02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength); + + // Unhalt EP0 IN. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI_EP0_IN; + u32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI_EP0_IN, 0, 1000); + if (res) + return res; + + switch (_bmRequestType) + { + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + if (_bRequest == USB_REQUEST_SET_ADDRESS) + _xusb_handle_set_request_dev_address(ctrl_setup); + else if (_bRequest == USB_REQUEST_SET_CONFIGURATION) + _xusb_handle_set_request_configuration(ctrl_setup); + return USB_RES_OK; // What about others. + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + usbd_xotg->interface_num = _wValue; + return _xusb_issue_status_trb(USB_DIR_IN); + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): + if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) + { + if (_bRequest == USB_REQUEST_CLEAR_FEATURE || _bRequest == USB_REQUEST_SET_FEATURE) + { + u32 ep = 0; + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + ep = XUSB_EP_CTRL_OUT; + break; + case USB_EP_ADDR_CTRL_IN: + ep = XUSB_EP_CTRL_IN; + break; + case USB_EP_ADDR_BULK_OUT: + ep = USB_EP_BULK_OUT; + break; + case USB_EP_ADDR_BULK_IN: + ep = USB_EP_BULK_IN; + break; + default: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + + if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + xusb_set_ep_stall(ep, USB_EP_CFG_CLEAR); + else if (_bRequest == USB_REQUEST_SET_FEATURE) + xusb_set_ep_stall(ep, USB_EP_CFG_STALL); + + return _xusb_issue_status_trb(USB_DIR_IN); + } + } + ep_stall = true; + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + return _xusb_handle_get_class_request(ctrl_setup); + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE): + switch (_bRequest) + { + case USB_REQUEST_GET_STATUS: + desc = xusb_dev_status_descriptor; + size = sizeof(xusb_dev_status_descriptor); + transmit_data = true; + break; + case USB_REQUEST_GET_DESCRIPTOR: + return _xusb_handle_get_descriptor(ctrl_setup); + case USB_REQUEST_GET_CONFIGURATION: + xusb_configuration_descriptor[0] = usbd_xotg->config_num; + desc = xusb_configuration_descriptor; + size = sizeof(xusb_configuration_descriptor); + transmit_data = true; + break; + default: + ep_stall = true; + break; + } + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): + if (_bRequest == USB_REQUEST_GET_INTERFACE) + { + desc = xusb_interface_descriptor; + size = sizeof(xusb_interface_descriptor); + xusb_interface_descriptor[0] = usbd_xotg->interface_num; + transmit_data = true; + } + else if (_bRequest == USB_REQUEST_GET_STATUS) + { + desc = xusb_status_descriptor; + size = sizeof(xusb_status_descriptor); + transmit_data = true; + } + else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_xotg->gadget > USB_GADGET_UMS) + { + if (usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD) + { + desc = (u8 *)&hid_report_descriptor_jc; + size = hid_report_descriptor_jc_size; + } + else // USB_GADGET_HID_TOUCHPAD + { + desc = (u8 *)&hid_report_descriptor_touch; + size = hid_report_descriptor_touch_size; + } + transmit_data = true; + usbd_xotg->device_state = XUSB_HID_CONFIGURED_STS_WAIT; + } + else + ep_stall = true; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT): + if (_bRequest == USB_REQUEST_GET_STATUS) + { + u32 ep = 0; + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + ep = XUSB_EP_CTRL_OUT; + break; + case USB_EP_ADDR_CTRL_IN: + ep = XUSB_EP_CTRL_IN; + break; + case USB_EP_ADDR_BULK_OUT: + ep = USB_EP_BULK_OUT; + break; + case USB_EP_ADDR_BULK_IN: + ep = USB_EP_BULK_IN; + break; + default: + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + return USB_RES_OK; + } + return _xusb_handle_get_ep_status(ep); + } + + ep_stall = true; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE): + return _xusb_handle_get_class_request(ctrl_setup); + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_INTERFACE): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE): + if (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR) + { + switch (_wIndex) + { + case USB_DESCRIPTOR_MS_COMPAT_ID: + desc = (u8 *)usbd_xotg->desc->ms_cid; + size = usbd_xotg->desc->ms_cid->dLength; + transmit_data = true; + break; + case USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES: + desc = (u8 *)usbd_xotg->desc->mx_ext; + size = usbd_xotg->desc->mx_ext->dLength; + transmit_data = true; + break; + default: + ep_stall = true; + break; + } + } + else + ep_stall = true; + break; + + default: + ep_stall = true; + break; + } + + if (transmit_data) + { + memcpy((u8 *)USB_EP_CONTROL_BUF_ADDR, desc, size); + if (_wLength < size) + size = _wLength; + return _xusb_issue_data_trb((u8 *)USB_EP_CONTROL_BUF_ADDR, size, USB_DIR_IN); + } + + if (ep_stall) + xusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL); + + return USB_RES_OK; +} + +static int _xusb_ep_operation(u32 tries) +{ + usb_ctrl_setup_t setup_event; + volatile event_trb_t *event_trb; + setup_event_trb_t *setup_event_trb; + + // Wait for an interrupt event. + int res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_ST, XHCI_ST_IP, XHCI_ST_IP, tries); + if (res) + return res; + + // Clear interrupt status. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_IP; + + usbd_xotg->event_enqueue_ptr = (event_trb_t *)(XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) & 0xFFFFFFF0); + event_trb = usbd_xotg->event_dequeue_ptr; + + // Check if cycle matches. + if ((event_trb->cycle & 1) != usbd_xotg->event_ccs) + return XUSB_ERROR_INVALID_CYCLE; + + while ((event_trb->cycle & 1) == usbd_xotg->event_ccs) + { + switch (event_trb->trb_type) + { + case XUSB_TRB_TRANSFER: + res = _xusb_handle_transfer_event((transfer_event_trb_t *)event_trb); + break; + case XUSB_TRB_PORT_CHANGE: + res = _xusb_handle_port_change(); + break; + case XUSB_TRB_SETUP: + setup_event_trb = (setup_event_trb_t *)event_trb; + memcpy(&setup_event, &setup_event_trb->ctrl_setup_data, sizeof(usb_ctrl_setup_t)); + usbd_xotg->ctrl_seq_num = setup_event_trb->ctrl_seq_num; + res = _xusbd_handle_ep0_control_transfer(&setup_event); + break; + default: + // TRB not supported. + break; + } + + // Check if last event TRB and reset to first one. + if (usbd_xotg->event_dequeue_ptr == &xusb_evtq->xusb_event_ring_seg1[XUSB_LAST_TRB_IDX]) + { + usbd_xotg->event_dequeue_ptr = xusb_evtq->xusb_event_ring_seg0; + usbd_xotg->event_ccs ^= 1; + } + else // Advance dequeue to next event. + usbd_xotg->event_dequeue_ptr = &usbd_xotg->event_dequeue_ptr[1]; + + // Set next event. + event_trb = usbd_xotg->event_dequeue_ptr; + + // If events exceed the interrupt time, handle them next interrupt. + if (usbd_xotg->event_dequeue_ptr == usbd_xotg->event_enqueue_ptr) + break; + } + + // Clear Event Handler bit if enabled and set Dequeue pointer. + u32 erdp = XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) & 0xF; + if (erdp & XHCI_ERDPLO_EHB) + erdp |= XHCI_ERDPLO_EHB; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) = ((u32)usbd_xotg->event_dequeue_ptr & 0xFFFFFFF0) | erdp; + + return res; +} + +int xusb_device_enumerate(usb_gadget_type gadget) +{ + switch (gadget) + { + case USB_GADGET_UMS: + usbd_xotg->desc = &usb_gadget_ums_descriptors; + break; + case USB_GADGET_HID_GAMEPAD: + usbd_xotg->desc = &usb_gadget_hid_jc_descriptors; + break; + case USB_GADGET_HID_TOUCHPAD: + usbd_xotg->desc = &usb_gadget_hid_touch_descriptors; + break; + } + + usbd_xotg->gadget = gadget; + + /* + * Set interrupt moderation to 0us. + * This is important because default value creates a 4.62ms latency. + * Effectively hurting transfers by having 15% to 96% performance loss. + */ + XUSB_DEV_XHCI(XUSB_DEV_XHCI_RT_IMOD) = 0; + + // Disable Wake events. + XUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_0) = 0; + XUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_1) = 0; + + // Enable overrides for VBUS and ID. + XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) = (XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) & ~(PADCTL_USB2_VBUS_ID_VBUS_OVR_MASK | PADCTL_USB2_VBUS_ID_SRC_MASK)) | + PADCTL_USB2_VBUS_ID_VBUS_OVR_EN | PADCTL_USB2_VBUS_ID_SRC_ID_OVR_EN; + + // Clear halt for LTSSM. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM; + + // Enable device mode. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_ENABLE; + + // Override access to High/Full Speed. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) & ~XHCI_CFG_DEV_FE_PORTREGSEL_MASK) | XHCI_CFG_DEV_FE_PORTREGSEL_HSFS; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) & ~XHCI_PORTSC_PLS_MASK) | XHCI_PORTSC_LWS | XHCI_PORTSC_PLS_RXDETECT; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) &= ~XHCI_CFG_DEV_FE_PORTREGSEL_MASK; + + // Enable VBUS and set ID to Float. + XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) = (XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) & ~PADCTL_USB2_VBUS_ID_OVR_MASK) | + PADCTL_USB2_VBUS_ID_OVR_FLOAT | PADCTL_USB2_VBUS_ID_VBUS_ON; + + usbd_xotg->wait_for_event_trb = XUSB_TRB_SETUP; + usbd_xotg->device_state = XUSB_DEFAULT; + + // Timeout if cable or communication isn't started in 1.5 minutes. + u32 timer = get_tmr_ms() + 90000; + while (true) + { + int res = _xusb_ep_operation(USB_XFER_SYNCED_ENUM); // 2s timeout. + if (res && res != USB_ERROR_TIMEOUT) + return res; + + if (usbd_xotg->device_state == XUSB_CONFIGURED) + break; + + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return USB_ERROR_USER_ABORT; + } + + return USB_RES_OK; +} + +void xusb_end(bool reset_ep, bool only_controller) +{ + // Disable endpoints and stop device mode operation. + _xusb_disable_ep1(); + + // Disable device mode. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) = 0; + + //! TODO: Add only controller support? + _xusb_device_power_down(); +} + +int xusb_handle_ep0_ctrl_setup() +{ + /* + * EP0 Control handling is done by normal ep operation in XUSB. + * Here we handle the bulk reset only. + */ + if (usbd_xotg->bulk_reset_req) + { + usbd_xotg->bulk_reset_req = false; + return USB_RES_BULK_RESET; + } + + return USB_RES_OK; +} + +int xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int res = USB_RES_OK; + usbd_xotg->tx_count[USB_DIR_OUT] = 0; + usbd_xotg->tx_bytes[USB_DIR_OUT] = len; + + _xusb_issue_normal_trb(buf, len, USB_DIR_OUT); + usbd_xotg->tx_count[USB_DIR_OUT]++; + + if (sync_tries) + { + while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) + res = _xusb_ep_operation(sync_tries); + + if (bytes_read) + *bytes_read = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT]; + } + + // Invalidate data after transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + return res; +} + +int xusb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read) +{ + if (len > USB_EP_BULK_OUT_MAX_XFER) + len = USB_EP_BULK_OUT_MAX_XFER; + + u32 bytes = 0; + *bytes_read = 0; + u8 *buf_curr = buf; + + while (len) + { + u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); + + int res = xusb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED_DATA); + if (res) + return res; + + len -= len_ep; + buf_curr += len_ep; + *bytes_read = *bytes_read + bytes; + } + + return USB_RES_OK; +} + +int xusb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_tries) +{ + int res = USB_RES_OK; + while (!res && usbd_xotg->tx_count[USB_DIR_OUT]) + res = _xusb_ep_operation(sync_tries); // Infinite retries. + + if (pending_bytes) + *pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT]; + + // Invalidate data after transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + return res; +} + +int xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_tries) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + // Flush data before transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false); + + int res = USB_RES_OK; + usbd_xotg->tx_count[USB_DIR_IN] = 0; + usbd_xotg->tx_bytes[USB_DIR_IN] = len; + + _xusb_issue_normal_trb(buf, len, USB_DIR_IN); + usbd_xotg->tx_count[USB_DIR_IN]++; + + if (sync_tries) + { + while (!res && usbd_xotg->tx_count[USB_DIR_IN]) + res = _xusb_ep_operation(sync_tries); + + if (bytes_written) + *bytes_written = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN]; + } + else + { + if ((usbd_xotg->port_speed == XUSB_FULL_SPEED && len == 64) || + (usbd_xotg->port_speed == XUSB_HIGH_SPEED && len == 512) || + (usbd_xotg->port_speed == XUSB_SUPER_SPEED && len == 1024)) + { + _xusb_issue_normal_trb(buf, 0, USB_DIR_IN); + usbd_xotg->tx_count[USB_DIR_IN]++; + } + } + + return res; +} + +int xusb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_tries) +{ + int res = USB_RES_OK; + while (!res && usbd_xotg->tx_count[USB_DIR_IN]) + res = _xusb_ep_operation(sync_tries); // Infinite retries. + + if (pending_bytes) + *pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN]; + + return res; +} + +bool xusb_device_get_port_in_sleep() +{ + // Ejection heuristic. + u32 link_mode = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) & XHCI_PORTSC_PLS_MASK; + return (link_mode == XHCI_PORTSC_PLS_U3); +} + +bool xusb_device_class_send_max_lun(u8 max_lun) +{ + // Timeout if get MAX_LUN request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + usbd_xotg->max_lun = max_lun; + usbd_xotg->max_lun_set = true; + + // Wait for request and transfer start. + while (usbd_xotg->device_state != XUSB_LUN_CONFIGURED) + { + _xusb_ep_operation(USB_XFER_SYNCED_CLASS); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + usbd_xotg->device_state = XUSB_CONFIGURED; + + return false; +} + +bool xusb_device_class_send_hid_report() +{ + // Timeout if get GET_HID_REPORT request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + // Wait for request and transfer start. + while (usbd_xotg->device_state != XUSB_HID_CONFIGURED) + { + _xusb_ep_operation(USB_XFER_SYNCED_CLASS); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + usbd_xotg->device_state = XUSB_CONFIGURED; + + return false; +} + +void xusb_device_get_ops(usb_ops_t *ops) +{ + ops->usbd_flush_endpoint = NULL; + ops->usbd_set_ep_stall = xusb_set_ep_stall; + ops->usbd_handle_ep0_ctrl_setup = xusb_handle_ep0_ctrl_setup; + ops->usbd_end = xusb_end; + ops->usb_device_init = xusb_device_init; + ops->usb_device_enumerate = xusb_device_enumerate; + ops->usb_device_class_send_max_lun = xusb_device_class_send_max_lun; + ops->usb_device_class_send_hid_report = xusb_device_class_send_hid_report; + ops->usb_device_get_suspended = xusb_device_get_port_in_sleep; + ops->usb_device_get_port_in_sleep = xusb_device_get_port_in_sleep; + + ops->usb_device_ep1_out_read = xusb_device_ep1_out_read; + ops->usb_device_ep1_out_read_big = xusb_device_ep1_out_read_big; + ops->usb_device_ep1_out_reading_finish = xusb_device_ep1_out_reading_finish; + ops->usb_device_ep1_in_write = xusb_device_ep1_in_write; + ops->usb_device_ep1_in_writing_finish = xusb_device_ep1_in_writing_finish; +} diff --git a/nyx/nyx_gui/utils/aarch64_util.h b/bdk/utils/aarch64_util.h similarity index 98% rename from nyx/nyx_gui/utils/aarch64_util.h rename to bdk/utils/aarch64_util.h index a5002c0..456bfc8 100644 --- a/nyx/nyx_gui/utils/aarch64_util.h +++ b/bdk/utils/aarch64_util.h @@ -18,7 +18,7 @@ #ifndef _ARM64_H_ #define _ARM64_H_ -#include "types.h" +#include #define LSL0 0 #define LSL16 16 diff --git a/bootloader/utils/btn.c b/bdk/utils/btn.c similarity index 67% rename from bootloader/utils/btn.c rename to bdk/utils/btn.c index d21d633..55ca67b 100644 --- a/bootloader/utils/btn.c +++ b/bdk/utils/btn.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,11 +16,11 @@ */ #include "btn.h" -#include "../soc/i2c.h" -#include "../soc/gpio.h" -#include "../soc/t210.h" -#include "util.h" -#include "../power/max77620.h" +#include +#include +#include +#include +#include u8 btn_read() { @@ -29,11 +29,27 @@ u8 btn_read() res |= BTN_VOL_DOWN; if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) res |= BTN_VOL_UP; - if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4) + // HOAG can use the GPIO. Icosa/Iowa/AULA cannot. Traces are there but they miss a resistor. + if (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & MAX77620_ONOFFSTAT_EN0) res |= BTN_POWER; return res; } +u8 btn_read_vol() +{ + u8 res = 0; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) + res |= BTN_VOL_DOWN; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) + res |= BTN_VOL_UP; + return res; +} + +u8 btn_read_home() +{ + return (!gpio_read(GPIO_PORT_Y, GPIO_PIN_1)) ? BTN_HOME : 0; +} + u8 btn_wait() { u8 res = 0, btn = btn_read(); @@ -60,6 +76,22 @@ u8 btn_wait() } u8 btn_wait_timeout(u32 time_ms, u8 mask) +{ + u32 timeout = get_tmr_ms() + time_ms; + u8 res = btn_read() & mask; + + while (get_tmr_ms() < timeout) + { + if (res == mask) + break; + else + res = btn_read() & mask; + }; + + return res; +} + +u8 btn_wait_timeout_single(u32 time_ms, u8 mask) { u8 single_button = mask & BTN_SINGLE; mask &= ~BTN_SINGLE; diff --git a/bootloader/utils/btn.h b/bdk/utils/btn.h similarity index 72% rename from bootloader/utils/btn.h rename to bdk/utils/btn.h index d6cad0c..a1c91a3 100644 --- a/bootloader/utils/btn.h +++ b/bdk/utils/btn.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,15 +18,19 @@ #ifndef _BTN_H_ #define _BTN_H_ -#include "types.h" +#include -#define BTN_POWER (1 << 0) -#define BTN_VOL_DOWN (1 << 1) -#define BTN_VOL_UP (1 << 2) -#define BTN_SINGLE (1 << 7) +#define BTN_POWER BIT(0) +#define BTN_VOL_DOWN BIT(1) +#define BTN_VOL_UP BIT(2) +#define BTN_HOME BIT(3) +#define BTN_SINGLE BIT(7) u8 btn_read(); +u8 btn_read_vol(); +u8 btn_read_home(); u8 btn_wait(); u8 btn_wait_timeout(u32 time_ms, u8 mask); +u8 btn_wait_timeout_single(u32 time_ms, u8 mask); #endif diff --git a/nyx/nyx_gui/utils/dirlist.c b/bdk/utils/dirlist.c similarity index 61% rename from nyx/nyx_gui/utils/dirlist.c rename to bdk/utils/dirlist.c index 7aa3770..b1de140 100644 --- a/nyx/nyx_gui/utils/dirlist.c +++ b/bdk/utils/dirlist.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,21 +17,23 @@ #include #include -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/types.h" +#include "dirlist.h" +#include +#include +#include -char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs) +dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs) { - u8 max_entries = 61; - int res = 0; - u32 i = 0, j = 0, k = 0; + u32 k = 0; DIR dir; FILINFO fno; - char *dir_entries = (char *)calloc(max_entries, 256); - char *temp = (char *)calloc(1, 256); + dirlist_t *dir_entries = (dirlist_t *)malloc(sizeof(dirlist_t)); + + // Setup pointer tree. + for (u32 i = 0; i < DIR_MAX_ENTRIES; i++) + dir_entries->name[i] = &dir_entries->data[i * 256]; if (!pattern && !f_opendir(&dir, directory)) { @@ -47,9 +49,8 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) { - strcpy(dir_entries + (k * 256), fno.fname); - k++; - if (k > (max_entries - 1)) + strcpy(&dir_entries->data[k * 256], fno.fname); + if (++k >= DIR_MAX_ENTRIES) break; } } @@ -62,9 +63,8 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile { if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) { - strcpy(dir_entries + (k * 256), fno.fname); - k++; - if (k > (max_entries - 1)) + strcpy(&dir_entries->data[k * 256], fno.fname); + if (++k >= DIR_MAX_ENTRIES) break; } res = f_findnext(&dir, &fno); @@ -74,27 +74,27 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile if (!k) { - free(temp); free(dir_entries); return NULL; } - // Reorder ini files by ASCII ordering. - for (i = 0; i < k - 1 ; i++) + // Terminate name list. + dir_entries->name[k] = NULL; + + // Reorder ini files Alphabetically. + for (u32 i = 0; i < k - 1 ; i++) { - for (j = i + 1; j < k; j++) + for (u32 j = i + 1; j < k; j++) { - if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + if (strcasecmp(dir_entries->name[i], dir_entries->name[j]) > 0) { - strcpy(temp, &dir_entries[i * 256]); - strcpy(&dir_entries[i * 256], &dir_entries[j * 256]); - strcpy(&dir_entries[j * 256], temp); + char *tmp = dir_entries->name[i]; + dir_entries->name[i] = dir_entries->name[j]; + dir_entries->name[j] = tmp; } } } - free(temp); - return dir_entries; -} \ No newline at end of file +} diff --git a/bootloader/mem/sdram.h b/bdk/utils/dirlist.h similarity index 66% rename from bootloader/mem/sdram.h rename to bdk/utils/dirlist.h index badc703..cb250c3 100644 --- a/bootloader/mem/sdram.h +++ b/bdk/utils/dirlist.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,14 +14,14 @@ * along with this program. If not, see . */ -#ifndef _SDRAM_H_ -#define _SDRAM_H_ +#include -#include "sdram_param_t210.h" +#define DIR_MAX_ENTRIES 64 -void sdram_init(); -sdram_params_t *sdram_get_params(); -sdram_params_t *sdram_get_params_patched(); -void sdram_lp0_save_params(const void *params); +typedef struct _dirlist_t +{ + char *name[DIR_MAX_ENTRIES]; + char data[DIR_MAX_ENTRIES * 256]; +} dirlist_t; -#endif +dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs); diff --git a/nyx/nyx_gui/config/ini.c b/bdk/utils/ini.c similarity index 63% rename from nyx/nyx_gui/config/ini.c rename to bdk/utils/ini.c index 6989d3c..6832bdc 100644 --- a/nyx/nyx_gui/config/ini.c +++ b/bdk/utils/ini.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,28 +18,10 @@ #include #include "ini.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/dirlist.h" - -static char *_strdup(char *str) -{ - if (!str) - return NULL; - - // Remove starting space. - if (str[0] == ' ' && strlen(str)) - str++; - - char *res = (char *)malloc(strlen(str) + 1); - strcpy(res, str); - - // Remove trailing space. - if (strlen(res) && res[strlen(res) - 1] == ' ') - res[strlen(res) - 1] = 0; - - return res; -} +#include +#include +#include +#include u32 _find_section_name(char *lbuf, u32 lblen, char schar) { @@ -55,28 +37,32 @@ u32 _find_section_name(char *lbuf, u32 lblen, char schar) ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type) { if (csec) - { list_append(dst, &csec->link); - csec = NULL; - } - csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); - csec->name = _strdup(name); + // Calculate total allocation size. + u32 len = name ? strlen(name) + 1 : 0; + char *buf = zalloc(sizeof(ini_sec_t) + len); + + csec = (ini_sec_t *)buf; + csec->name = strcpy_ns(buf + sizeof(ini_sec_t), name); csec->type = type; + // Initialize list. + list_init(&csec->kvs); + return csec; } -int ini_parse(link_t *dst, char *ini_path, bool is_dir) +int ini_parse(link_t *dst, const char *ini_path, bool is_dir) { - u32 lblen; - u32 pathlen = strlen(ini_path); - u32 k = 0; - char lbuf[512]; - char *filelist = NULL; FIL fp; + u32 lblen; + u32 k = 0; + u32 pathlen = strlen(ini_path); ini_sec_t *csec = NULL; + char *lbuf = NULL; + dirlist_t *filelist = NULL; char *filename = (char *)malloc(256); strcpy(filename, ini_path); @@ -99,9 +85,9 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) // Copy ini filename in path string. if (is_dir) { - if (filelist[k * 256]) + if (filelist->name[k]) { - strcpy(filename + pathlen, &filelist[k * 256]); + strcpy(filename + pathlen, filelist->name[k]); k++; } else @@ -117,6 +103,8 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) return 0; } + lbuf = malloc(512); + do { // Fetch one line. @@ -133,7 +121,6 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) _find_section_name(lbuf, lblen, ']'); csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); - list_init(&csec->kvs); } else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'. { @@ -154,13 +141,22 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) { u32 i = _find_section_name(lbuf, lblen, '='); - ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); - kv->key = _strdup(&lbuf[0]); - kv->val = _strdup(&lbuf[i + 1]); + // Calculate total allocation size. + u32 klen = strlen(&lbuf[0]) + 1; + u32 vlen = strlen(&lbuf[i + 1]) + 1; + char *buf = zalloc(sizeof(ini_kv_t) + klen + vlen); + + ini_kv_t *kv = (ini_kv_t *)buf; + buf += sizeof(ini_kv_t); + kv->key = strcpy_ns(buf, &lbuf[0]); + buf += klen; + kv->val = strcpy_ns(buf, &lbuf[i + 1]); list_append(&csec->kvs, &kv->link); } } while (!f_eof(&fp)); + free(lbuf); + f_close(&fp); if (csec) @@ -177,16 +173,55 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) return 1; } -char *ini_check_payload_section(ini_sec_t *cfg) +char *ini_check_special_section(ini_sec_t *cfg) { if (cfg == NULL) return NULL; LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) { - if (!strcmp("payload", kv->key)) + if (!strcmp("l4t", kv->key)) + return ((kv->val[0] == '1') ? (char *)-1 : NULL); + else if (!strcmp("payload", kv->key)) return kv->val; } return NULL; } + +void ini_free(link_t *src) +{ + ini_sec_t *prev_sec = NULL; + + // Parse and free all ini sections. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, src, link) + { + ini_kv_t *prev_kv = NULL; + + // Free all ini key allocations if they exist. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + // Free previous key. + if (prev_kv) + free(prev_kv); + + // Set next key to free. + prev_kv = kv; + } + + // Free last key. + if (prev_kv) + free(prev_kv); + + // Free previous section. + if (prev_sec) + free(prev_sec); + + // Set next section to free. + prev_sec = ini_sec; + } + + // Free last section. + if (prev_sec) + free(prev_sec); +} diff --git a/nyx/nyx_gui/config/ini.h b/bdk/utils/ini.h similarity index 84% rename from nyx/nyx_gui/config/ini.h rename to bdk/utils/ini.h index dffbe86..35c13c8 100644 --- a/nyx/nyx_gui/config/ini.h +++ b/bdk/utils/ini.h @@ -18,8 +18,8 @@ #ifndef _INI_H_ #define _INI_H_ -#include "../utils/types.h" -#include "../utils/list.h" +#include +#include #define INI_CHOICE 3 #define INI_CAPTION 5 @@ -43,8 +43,9 @@ typedef struct _ini_sec_t u32 color; } ini_sec_t; -int ini_parse(link_t *dst, char *ini_path, bool is_dir); -char *ini_check_payload_section(ini_sec_t *cfg); +int ini_parse(link_t *dst, const char *ini_path, bool is_dir); +char *ini_check_special_section(ini_sec_t *cfg); +void ini_free(link_t *src); #endif diff --git a/nyx/nyx_gui/utils/list.h b/bdk/utils/list.h similarity index 68% rename from nyx/nyx_gui/utils/list.h rename to bdk/utils/list.h index b891bb7..4d17261 100644 --- a/nyx/nyx_gui/utils/list.h +++ b/bdk/utils/list.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +18,7 @@ #ifndef _LIST_H_ #define _LIST_H_ -#include "types.h" +#include /*! Initialize list. */ #define LIST_INIT(name) link_t name = {&name, &name} @@ -27,16 +28,25 @@ /*! Iterate over all list links. */ #define LIST_FOREACH(iter, list) \ - for(link_t *iter = (list)->next; iter != (list); iter = iter->next) + for (link_t *iter = (list)->next; iter != (list); iter = iter->next) + +/*! Iterate over all list links backwards. */ +#define LIST_FOREACH_INVERSE(iter, list) \ + for (link_t *iter = (list)->prev; iter != (list); iter = iter->prev) /*! 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) + for (link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next) /*! Iterate over all list members and make sure that the list has at least one entry. */ #define LIST_FOREACH_ENTRY(etype, iter, list, mn) \ if ((list)->next != (list)) \ - for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) + for (etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) + +/* Iterate over all list members backwards and make sure that the list has at least one entry. */ +#define LIST_FOREACH_ENTRY_INVERSE(type, iter, list, mn) \ + if ((list)->prev != (list)) \ + for (type *iter = CONTAINER_OF((list)->prev, type, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.prev, type, mn)) typedef struct _link_t { @@ -52,7 +62,7 @@ static inline void link_init(link_t *l) static inline int link_used(link_t *l) { - if(l->next == NULL) + if (l->next == NULL) return 1; return 0; } @@ -88,7 +98,7 @@ static inline void list_remove(link_t *l) static inline int list_empty(link_t *lh) { - if(lh->next == lh) + if (lh->next == lh) return 1; return 0; } diff --git a/bdk/utils/sprintf.c b/bdk/utils/sprintf.c new file mode 100644 index 0000000..b86b96c --- /dev/null +++ b/bdk/utils/sprintf.c @@ -0,0 +1,299 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2024 CTCaer +* +* 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 + +#include + +char **sout_buf; + +static void _s_putc(char c) +{ + **sout_buf = c; + *sout_buf += 1; +} + +static void _s_putspace(int fcnt) +{ + if (fcnt <= 0) + return; + + for (int i = 0; i < fcnt; i++) + _s_putc(' '); +} + +static void _s_puts(char *s, char fill, int fcnt) +{ + if (fcnt) + { + fcnt = fcnt - strlen(s); + + // Left padding. Check if padding is not space based (dot counts as such). + if (fill != '.') + _s_putspace(fcnt); + } + + for (; *s; s++) + _s_putc(*s); + + // Right padding. Check if padding is space based (dot counts as such). + if (fill == '.') + _s_putspace(fcnt); +} + +static void _s_putn(u32 v, int base, char fill, int fcnt) +{ + static const char digits[] = "0123456789ABCDEF"; + + char *p; + char buf[65]; // Number char size + leftover for padding. + int c = fcnt; + bool negative = false; + + if (base != 10 && base != 16) + return; + + // Account for negative numbers. + if (base == 10 && v & 0x80000000) + { + negative = true; + v = (int)v * -1; + c--; + } + + p = buf + 64; + *p = 0; + do + { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (negative) + *--p = '-'; + + if (fill != 0) + { + while (c > 0 && p > buf) + { + *--p = fill; + c--; + } + } + + _s_puts(p, 0, 0); +} + +/* + * Padding: + * Numbers: + * %3d: Fill: ' ', Count: 3. + * % 3d: Fill: ' ', Count: 3. + * %.3d: Fill: '.', Count: 3. + * %23d: Fill: '2', Count: 3. + * % 23d: Fill: ' ', Count: 23. + * %223d: Fill: '2', Count: 23. + * + * Strings, Fill: ' ': + * %3s: Count: 5, Left. + * %23s: Count: 5, Left. + * %223s: Count: 25, Left. + * %.3s: Count: 5, Right. + * %.23s: Count: 25, Right. + * %.223s: Count: 225, Right. + */ + +void s_printf(char *out_buf, const char *fmt, ...) +{ + va_list ap; + int fill, fcnt; + + sout_buf = &out_buf; + + va_start(ap, fmt); + while (*fmt) + { + if (*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + + // Check for padding. Number or space based (dot count as space for string). + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ' || *fmt == '.') + { + fcnt = *fmt; // Padding size or padding type. + fmt++; + + if (*fmt >= '0' && *fmt <= '9') + { + // Padding size exists. Previous char was type. + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; +parse_padding_dec: + // Parse padding size extra digits. + if (*fmt >= '0' && *fmt <= '9') + { + fcnt = fcnt * 10 + *fmt - '0'; + fmt++; + goto parse_padding_dec; + } + } + else + { + // No padding type, use space. (Max padding size is 9). + fill = ' '; + fcnt -= '0'; + } + } + + switch (*fmt) + { + case 'c': + char c = va_arg(ap, u32); + if (c != '\0') + _s_putc(c); + break; + + case 'd': + _s_putn(va_arg(ap, u32), 10, fill, fcnt); + break; + + case 's': + _s_puts(va_arg(ap, char *), fill, fcnt); + break; + + case 'p': + case 'P': + case 'x': + case 'X': + _s_putn(va_arg(ap, u32), 16, fill, fcnt); + break; + + case '%': + _s_putc('%'); + break; + + case '\0': + goto out; + + default: + _s_putc('%'); + _s_putc(*fmt); + break; + } + } + else + _s_putc(*fmt); + fmt++; + } + +out: + **sout_buf = '\0'; + va_end(ap); +} + +void s_vprintf(char *out_buf, const char *fmt, va_list ap) +{ + int fill, fcnt; + + sout_buf = &out_buf; + + while (*fmt) + { + if (*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + + // Check for padding. Number or space based. + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + { + fcnt = *fmt; // Padding size or padding type. + fmt++; + + if (*fmt >= '0' && *fmt <= '9') + { + // Padding size exists. Previous char was type. + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; +parse_padding_dec: + // Parse padding size extra digits. + if (*fmt >= '0' && *fmt <= '9') + { + fcnt = fcnt * 10 + *fmt - '0'; + fmt++; + goto parse_padding_dec; + } + } + else + { + // No padding type, use space. (Max padding size is 9). + fill = ' '; + fcnt -= '0'; + } + } + + switch (*fmt) + { + case 'c': + char c = va_arg(ap, u32); + if (c != '\0') + _s_putc(c); + break; + + case 'd': + _s_putn(va_arg(ap, u32), 10, fill, fcnt); + break; + + case 's': + _s_puts(va_arg(ap, char *), fill, fcnt); + break; + + case 'p': + case 'P': + case 'x': + case 'X': + _s_putn(va_arg(ap, u32), 16, fill, fcnt); + break; + + case '%': + _s_putc('%'); + break; + + case '\0': + goto out; + + default: + _s_putc('%'); + _s_putc(*fmt); + break; + } + } + else + _s_putc(*fmt); + fmt++; + } + +out: + **sout_buf = '\0'; +} diff --git a/nyx/nyx_gui/utils/sprintf.h b/bdk/utils/sprintf.h similarity index 51% rename from nyx/nyx_gui/utils/sprintf.h rename to bdk/utils/sprintf.h index 96aeea8..94ce468 100644 --- a/nyx/nyx_gui/utils/sprintf.h +++ b/bdk/utils/sprintf.h @@ -17,8 +17,29 @@ #ifndef _SPRINTF_H_ #define _SPRINTF_H_ -#include "types.h" +#include -void s_printf(char *out_buf, const char *fmt, ...); +#include -#endif \ No newline at end of file +/* + * Padding: + * Numbers: + * %3d: Fill: ' ', Count: 3. + * % 3d: Fill: ' ', Count: 3. + * %23d: Fill: '2', Count: 3. + * % 23d: Fill: ' ', Count: 23. + * %223d: Fill: '2', Count: 23. + * + * Strings, Fill: ' ': + * %3s: Count: 5, Left. + * %23s: Count: 5, Left. + * %223s: Count: 25, Left. + * %.3s: Count: 5, Right. + * %.23s: Count: 25, Right. + * %.223s: Count: 225, Right. + */ + +void s_printf(char *out_buf, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +void s_vprintf(char *out_buf, const char *fmt, va_list ap); + +#endif diff --git a/bdk/utils/types.h b/bdk/utils/types.h new file mode 100644 index 0000000..66c5d60 --- /dev/null +++ b/bdk/utils/types.h @@ -0,0 +1,168 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2018-2022 CTCaer +* +* 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_ + +#include + +/* Types */ +typedef signed char s8; +typedef short s16; +typedef short SHORT; +typedef int s32; +typedef int INT; +typedef int bool; +typedef long LONG; +typedef long long int s64; + +typedef unsigned char u8; +typedef unsigned char BYTE; +typedef unsigned short u16; +typedef unsigned short WORD; +typedef unsigned short WCHAR; +typedef unsigned int u32; +typedef unsigned int UINT; +typedef unsigned long DWORD; +typedef unsigned long long QWORD; +typedef unsigned long long int u64; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; + +#ifdef __aarch64__ +typedef unsigned long long uptr; +#else /* __arm__ or __thumb__ */ +typedef unsigned long uptr; +#endif + +/* Important */ +#define false 0 +#define true 1 + +#define NULL ((void *)0) + +/* Misc */ +#define DISABLE 0 +#define ENABLE 1 + +/* Sizes */ +#define SZ_1K 0x400 +#define SZ_2K 0x800 +#define SZ_4K 0x1000 +#define SZ_8K 0x2000 +#define SZ_16K 0x4000 +#define SZ_32K 0x8000 +#define SZ_64K 0x10000 +#define SZ_128K 0x20000 +#define SZ_256K 0x40000 +#define SZ_512K 0x80000 +#define SZ_1M 0x100000 +#define SZ_2M 0x200000 +#define SZ_4M 0x400000 +#define SZ_8M 0x800000 +#define SZ_16M 0x1000000 +#define SZ_32M 0x2000000 +#define SZ_64M 0x4000000 +#define SZ_128M 0x8000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 +#define SZ_PAGE SZ_4K + +/* Macros */ +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ALIGN_DOWN(x, a) ((x) & ~((a) - 1)) +#define BIT(n) (1U << (n)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +#define OFFSET_OF(t, m) ((uptr)&((t *)NULL)->m) +#define CONTAINER_OF(mp, t, mn) ((t *)((uptr)mp - OFFSET_OF(t, mn))) + +#define byte_swap_16(num) ((((num) >> 8) & 0xFF) | (((num) & 0xFF) << 8)) +#define byte_swap_32(num) ((((num) >> 24) & 0xFF) | (((num) & 0xFF00) << 8 ) | \ + (((num) >> 8 ) & 0xFF00) | (((num) & 0xFF) << 24)) + +#define likely(x) (__builtin_expect((x) != 0, 1)) +#define unlikely(x) (__builtin_expect((x) != 0, 0)) + +/* Bootloader/Nyx */ +#define BOOT_CFG_AUTOBOOT_EN BIT(0) +#define BOOT_CFG_FROM_LAUNCH BIT(1) +#define BOOT_CFG_FROM_ID BIT(2) +#define BOOT_CFG_TO_EMUMMC BIT(3) + +#define EXTRA_CFG_KEYS BIT(0) +#define EXTRA_CFG_PAYLOAD BIT(1) +#define EXTRA_CFG_MODULE BIT(2) + +#define EXTRA_CFG_NYX_UMS BIT(5) +#define EXTRA_CFG_NYX_RELOAD BIT(6) + +typedef enum _nyx_ums_type +{ + NYX_UMS_SD_CARD = 0, + NYX_UMS_EMMC_BOOT0, + NYX_UMS_EMMC_BOOT1, + NYX_UMS_EMMC_GPP, + NYX_UMS_EMUMMC_BOOT0, + NYX_UMS_EMUMMC_BOOT1, + NYX_UMS_EMUMMC_GPP +} nyx_ums_type; + +typedef struct __attribute__((__packed__)) _boot_cfg_t +{ + u8 boot_cfg; + u8 autoboot; + u8 autoboot_list; + u8 extra_cfg; + union + { + struct + { + char id[8]; // 7 char ASCII null terminated. + char emummc_path[0x78]; // emuMMC/XXX, ASCII null terminated. + }; + u8 ums; // nyx_ums_type. + u8 xt_str[0x80]; + }; +} boot_cfg_t; + +static_assert(sizeof(boot_cfg_t) == 0x84, "Boot cfg storage size is wrong!"); + +typedef struct __attribute__((__packed__)) _ipl_ver_meta_t +{ + u32 magic; + u32 version; + u16 rsvd0; + u16 rsvd1; +} ipl_ver_meta_t; + +typedef struct __attribute__((__packed__)) _reloc_meta_t +{ + u32 start; + u32 stack; + u32 end; + u32 ep; +} reloc_meta_t; + +#endif diff --git a/bdk/utils/util.c b/bdk/utils/util.c new file mode 100644 index 0000000..69498ac --- /dev/null +++ b/bdk/utils/util.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +u8 bit_count(u32 val) +{ + u8 cnt = 0; + for (u32 i = 0; i < 32; i++) + { + if ((val >> i) & 1) + cnt++; + } + + return cnt; +} + +u32 bit_count_mask(u8 bits) +{ + u32 val = 0; + for (u32 i = 0; i < bits; i++) + val |= 1 << i; + + return val; +} + +char *strcpy_ns(char *dst, char *src) +{ + if (!src || !dst) + return NULL; + + // Remove starting space. + u32 len = strlen(src); + if (len && src[0] == ' ') + { + len--; + src++; + } + + strcpy(dst, src); + + // Remove trailing space. + if (len && dst[len - 1] == ' ') + dst[len - 1] = 0; + + return dst; +} + +// Approximate square root finder for a 64-bit number. +u64 sqrt64(u64 num) +{ + u64 base = 0; + u64 limit = num; + u64 square_root = 0; + + while (base <= limit) + { + u64 tmp_sqrt = (base + limit) / 2; + + if (tmp_sqrt * tmp_sqrt == num) { + square_root = tmp_sqrt; + break; + } + + if (tmp_sqrt * tmp_sqrt < num) + { + square_root = base; + base = tmp_sqrt + 1; + } + else + limit = tmp_sqrt - 1; + } + + return square_root; +} + +#define TULONG_MAX ((unsigned long)((unsigned long)(~0L))) +#define TLONG_MAX ((long)(((unsigned long)(~0L)) >> 1)) +#define TLONG_MIN ((long)(~TLONG_MAX)) +#define ISSPACE(ch) ((ch >= '\t' && ch <= '\r') || (ch == ' ')) +#define ISDIGIT(ch) ( ch >= '0' && ch <= '9' ) +#define ISALPHA(ch) ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) +#define ISUPPER(ch) ( ch >= 'A' && ch <= 'Z' ) + +/* + * Avoid using reentrant newlib version of strol. It's only used for errno. + * + * strol/atoi: + * Copyright (c) 1990 The Regents of the University of California. + */ +long strtol(const char *nptr, char **endptr, register int base) +{ + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (ISSPACE(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)TLONG_MIN : (base == 16 ? TULONG_MAX : TLONG_MAX); + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (ISDIGIT(c)) + c -= '0'; + else if (ISALPHA(c)) + c -= ISUPPER(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? TLONG_MIN : TLONG_MAX; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +int atoi(const char *nptr) +{ + return (int)strtol(nptr, (char **)NULL, 10); +} + +void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg) +{ + // Expected register offset is a u32 array index. + for (u32 i = 0; i < num_cfg; i++) + base[cfg[i].idx] = cfg[i].val; +} + +u32 crc32_calc(u32 crc, const u8 *buf, u32 len) +{ + const u8 *p, *q; + static u32 *table = NULL; + + // Calculate CRC table. + if (!table) + { + table = zalloc(256 * sizeof(u32)); + for (u32 i = 0; i < 256; i++) + { + u32 rem = i; + for (u32 j = 0; j < 8; j++) + { + if (rem & 1) + { + rem >>= 1; + rem ^= 0xedb88320; + } + else + rem >>= 1; + } + table[i] = rem; + } + } + + crc = ~crc; + q = buf + len; + for (p = buf; p < q; p++) + { + u8 oct = *p; + crc = (crc >> 8) ^ table[(crc & 0xff) ^ oct]; + } + + return ~crc; +} + +int qsort_compare_int(const void *a, const void *b) +{ + return (*(int *)a - *(int *)b); +} + +int qsort_compare_char(const void *a, const void *b) +{ + return strcmp(*(const char **)a, *(const char **)b); +} + +int qsort_compare_char_case(const void *a, const void *b) +{ + return strcasecmp(*(const char **)a, *(const char **)b); +} + +void panic(u32 val) +{ + // Set panic code. + PMC(APBDEV_PMC_SCRATCH200) = val; + + // Disable SE. + //PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE; + + // Immediately cause a full system reset. + watchdog_start(0, TIMER_PMCRESET_EN); + + while (true); +} + +void power_set_state(power_state_t state) +{ + u8 reg; + + // Unmount and power down sd card. + sd_end(); + + // De-initialize and power down various hardware. + hw_deinit(false, 0); + + // Set power state. + switch (state) + { + case REBOOT_RCM: + PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; // Enable RCM path. + PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; // PMC reset. + break; + + case REBOOT_BYPASS_FUSES: + panic(0x21); // Bypass fuse programming in package1. + break; + + case POWER_OFF: + // Initiate power down sequence and do not generate a reset (regulators retain state after POR). + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); + break; + + case POWER_OFF_RESET: + case POWER_OFF_REBOOT: + default: + // Enable/Disable soft reset wake event. + reg = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2); + if (state == POWER_OFF_RESET) // Do not wake up after power off. + reg &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK | MAX77620_ONOFFCNFG2_WK_ALARM1 | MAX77620_ONOFFCNFG2_WK_ALARM2); + else // POWER_OFF_REBOOT. Wake up after power off. + reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK; + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg); + + // Initiate power down sequence and generate a reset (regulators' state resets after POR). + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST); + break; + } + + while (true) + bpmp_halt(); +} + +void power_set_state_ex(void *param) +{ + power_state_t *state = (power_state_t *)param; + power_set_state(*state); +} diff --git a/bdk/utils/util.h b/bdk/utils/util.h new file mode 100644 index 0000000..2d8d9bd --- /dev/null +++ b/bdk/utils/util.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * 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 _UTIL_H_ +#define _UTIL_H_ + +#include +#include + +#define NYX_NEW_INFO 0x3058594E + +typedef enum +{ + REBOOT_RCM, // PMC reset. Enter RCM mode. + REBOOT_BYPASS_FUSES, // PMC reset via watchdog. Enter Normal mode. Bypass fuse programming in package1. + + POWER_OFF, // Power off PMIC. Do not reset regulators. + POWER_OFF_RESET, // Power off PMIC. Reset regulators. + POWER_OFF_REBOOT, // Power off PMIC. Reset regulators. Power on. +} power_state_t; + +typedef enum +{ + NYX_CFG_UMS = BIT(6), + + NYX_CFG_EXTRA = 0xFF << 24 +} nyx_cfg_t; + +typedef enum +{ + ERR_LIBSYS_LP0 = BIT(0), + ERR_SYSOLD_NYX = BIT(1), + ERR_LIBSYS_MTC = BIT(2), + ERR_SD_BOOT_EN = BIT(3), + ERR_PANIC_CODE = BIT(4), + ERR_L4T_KERNEL = BIT(24), + ERR_EXCEPTION = BIT(31), +} hekate_errors_t; + +typedef struct _reg_cfg_t +{ + u32 idx; + u32 val; +} reg_cfg_t; + +typedef struct _nyx_info_t +{ + u32 magic; + u32 sd_init; + u32 sd_errors[3]; + u8 rsvd[0x1000]; + u32 disp_id; + u32 errors; +} nyx_info_t; + +typedef struct _nyx_storage_t +{ + u32 version; + u32 cfg; + u8 irama[0x8000]; + u8 hekate[0x30000]; + u8 rsvd[SZ_8M - sizeof(nyx_info_t)]; + nyx_info_t info; + mtc_config_t mtc_cfg; + emc_table_t mtc_table[11]; // 10 + 1. +} nyx_storage_t; + +u8 bit_count(u32 val); +u32 bit_count_mask(u8 bits); +char *strcpy_ns(char *dst, char *src); +u64 sqrt64(u64 num); +long strtol(const char *nptr, char **endptr, register int base); +int atoi(const char *nptr); + +void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg); +u32 crc32_calc(u32 crc, const u8 *buf, u32 len); + +int qsort_compare_int(const void *a, const void *b); +int qsort_compare_char(const void *a, const void *b); +int qsort_compare_char_case(const void *a, const void *b); + +void panic(u32 val); +void power_set_state(power_state_t state); +void power_set_state_ex(void *param); + + +#endif diff --git a/bootloader/config.c b/bootloader/config.c new file mode 100644 index 0000000..37aed3b --- /dev/null +++ b/bootloader/config.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018-2022 CTCaer + * + * 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 + +#include + +#include "config.h" +#include "gfx/tui.h" +#include + +extern hekate_config h_cfg; + +void set_default_configuration() +{ + h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; + + h_cfg.autoboot = 0; + h_cfg.autoboot_list = 0; + h_cfg.bootwait = 3; + h_cfg.noticker = 0; //! TODO: Add GUI option. + h_cfg.backlight = 100; + h_cfg.autohosoff = h_cfg.t210b01 ? 1 : 0; + h_cfg.autonogc = 1; + h_cfg.updater2p = 0; + h_cfg.bootprotect = 0; + + h_cfg.errors = 0; + h_cfg.eks = NULL; + h_cfg.rcm_patched = fuse_check_patched_rcm(); + h_cfg.emummc_force_disable = false; +} diff --git a/nyx/nyx_gui/config/config.h b/bootloader/config.h similarity index 83% rename from nyx/nyx_gui/config/config.h rename to bootloader/config.h index 2dc37b0..6710ce3 100644 --- a/nyx/nyx_gui/config/config.h +++ b/bootloader/config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +17,9 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#include "../utils/types.h" +#include + +#include "hos/hos.h" typedef struct _hekate_config { @@ -25,23 +27,20 @@ typedef struct _hekate_config u32 autoboot; u32 autoboot_list; u32 bootwait; - u32 verification; + u32 noticker; u32 backlight; u32 autohosoff; u32 autonogc; u32 updater2p; - char *brand; - char *tagline; + u32 bootprotect; // Global temporary config. - bool se_keygen_done; - bool sept_run; + bool t210b01; bool emummc_force_disable; bool rcm_patched; - u32 sbar_time_keeping; u32 errors; + hos_eks_mbr_t *eks; } hekate_config; void set_default_configuration(); -int create_config_entry(); #endif /* _CONFIG_H_ */ diff --git a/bootloader/config/config.c b/bootloader/config/config.c deleted file mode 100644 index 2bde7ae..0000000 --- a/bootloader/config/config.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright (c) 2018-2019 CTCaer - * - * 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 - -#include "config.h" -#include "ini.h" -#include "../gfx/gfx.h" -#include "../gfx/tui.h" -#include "../libs/fatfs/ff.h" -#include "../soc/t210.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/util.h" - -extern hekate_config h_cfg; -extern bool sd_mount(); -extern void sd_unmount(); - -void set_default_configuration() -{ - h_cfg.autoboot = 0; - h_cfg.autoboot_list = 0; - h_cfg.bootwait = 3; - h_cfg.verification = 1; - h_cfg.se_keygen_done = 0; - h_cfg.sbar_time_keeping = 0; - h_cfg.backlight = 100; - h_cfg.autohosoff = 0; - h_cfg.autonogc = 1; - h_cfg.updater2p = 0; - h_cfg.brand = NULL; - h_cfg.tagline = NULL; - h_cfg.errors = 0; - h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; - h_cfg.rcm_patched = true; - h_cfg.emummc_force_disable = false; - - sd_power_cycle_time_start = 0; -} - -int create_config_entry() -{ - if (!sd_mount()) - return 1; - - char lbuf[32]; - FIL fp; - bool mainIniFound = false; - - LIST_INIT(ini_sections); - - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - mainIniFound = true; - else - { - u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); - if (res == FR_NO_FILE || res == FR_NO_PATH) - { - f_mkdir("bootloader"); - f_mkdir("bootloader/ini"); - f_mkdir("bootloader/payloads"); - f_mkdir("bootloader/sys"); - } - else - { - if (!res) - f_close(&fp); - return 1; - } - } - - if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) - return 1; - // Add config entry. - f_puts("[config]\nautoboot=", &fp); - itoa(h_cfg.autoboot, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautoboot_list=", &fp); - itoa(h_cfg.autoboot_list, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nbootwait=", &fp); - itoa(h_cfg.bootwait, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nverification=", &fp); - itoa(h_cfg.verification, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nbacklight=", &fp); - itoa(h_cfg.backlight, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautohosoff=", &fp); - itoa(h_cfg.autohosoff, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nautonogc=", &fp); - itoa(h_cfg.autonogc, lbuf, 10); - f_puts(lbuf, &fp); - f_puts("\nupdater2p=", &fp); - itoa(h_cfg.updater2p, lbuf, 10); - f_puts(lbuf, &fp); - if (h_cfg.brand) - { - f_puts("\nbrand=", &fp); - f_puts(h_cfg.brand, &fp); - } - if (h_cfg.tagline) - { - f_puts("\ntagline=", &fp); - f_puts(h_cfg.tagline, &fp); - } - f_puts("\n", &fp); - - if (mainIniFound) - { - // Re-construct existing entries. - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - switch (ini_sec->type) - { - case INI_CHOICE: // Re-construct Boot entry [ ]. - f_puts("[", &fp); - f_puts(ini_sec->name, &fp); - f_puts("]\n", &fp); - // Re-construct boot entry's config. - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - f_puts(kv->key, &fp); - f_puts("=", &fp); - f_puts(kv->val, &fp); - f_puts("\n", &fp); - } - break; - case INI_CAPTION: // Re-construct caption entry { }. - f_puts("{", &fp); - f_puts(ini_sec->name, &fp); - f_puts("}\n", &fp); - break; - case INI_NEWLINE: // Re-construct cosmetic newline \n. - f_puts("\n", &fp); - break; - case INI_COMMENT: // Re-construct comment entry #. - f_puts("#", &fp); - f_puts(ini_sec->name, &fp); - f_puts("\n", &fp); - break; - } - } - } - - f_close(&fp); - sd_unmount(); - - return 0; -} - -#pragma GCC push_options -#pragma GCC optimize ("Os") - -static void _save_config() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - if (!create_config_entry()) - gfx_puts("\nConfiguration was saved!\n"); - else - EPRINTF("\nConfiguration saving failed!"); - gfx_puts("\nPress any key..."); -} - -static void _config_autoboot_list(void *ent) -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 *temp_autoboot = NULL; - - LIST_INIT(ini_sections); - - u8 max_entries = 30; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); - u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(512 * max_entries); - - for (u32 j = 0; j < max_entries; j++) - boot_values[j] = j; - - if (sd_mount()) - { - if (ini_parse(&ini_sections, "bootloader/ini", true)) - { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - u32 i = 2; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - if (strlen(ini_sec->name) > 510) - ments[i].caption = ini_sec->name; - else - { - if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) - boot_text[(i - 1) * 512] = ' '; - - else - boot_text[(i - 1) * 512] = '*'; - strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name); - ments[i].caption = &boot_text[(i - 1) * 512]; - } - ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 1]; - i++; - - if ((i - 1) > max_entries) - break; - } - } - - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; - temp_autoboot = (u32 *)tui_do_menu(&menu); - if (temp_autoboot != NULL) - { - h_cfg.autoboot = *(u32 *)temp_autoboot; - h_cfg.autoboot_list = 1; - _save_config(); - - ment_t *tmp = (ment_t *)ent; - tmp->data = NULL; - } - else - goto out2; - } - else - { - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); - goto out; - } - } - -out:; - btn_wait(); -out2:; - free(ments); - free(boot_values); - free(boot_text); - - sd_unmount(); -} - -void config_autoboot() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 *temp_autoboot = NULL; - - LIST_INIT(ini_sections); - - u8 max_entries = 30; - u32 boot_text_size = 512; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); - u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(boot_text_size * max_entries); - - for (u32 j = 0; j < max_entries; j++) - boot_values[j] = j; - - if (sd_mount()) - { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_DATA; - if (!h_cfg.autoboot) - ments[2].caption = "*Disable"; - else - ments[2].caption = " Disable"; - ments[2].data = &boot_values[0]; - - ments[3].type = MENT_HDLR_RE; - if (h_cfg.autoboot_list) - ments[3].caption = "*More configs..."; - else - ments[3].caption = " More configs..."; - ments[3].handler = _config_autoboot_list; - ments[3].data = (void *)0xCAFE; - - ments[4].type = MENT_CHGLINE; - - u32 i = 5; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - continue; - - if (strlen(ini_sec->name) > 510) - ments[i].caption = ini_sec->name; - else - { - if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) - boot_text[(i - 4) * boot_text_size] = ' '; - - else - boot_text[(i - 4) * boot_text_size] = '*'; - strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name); - ments[i].caption = &boot_text[(i - 4) * boot_text_size]; - } - ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 4]; - i++; - - if ((i - 4) > max_entries) - break; - } - } - if (i < 6 && !h_cfg.autoboot_list) - { - ments[i].type = MENT_CAPTION; - ments[i].caption = "No main configurations found..."; - ments[i].color = 0xFFFFDD00; - i++; - } - - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; - temp_autoboot = (u32 *)tui_do_menu(&menu); - if (temp_autoboot != NULL) - { - h_cfg.autoboot = *(u32 *)temp_autoboot; - h_cfg.autoboot_list = 0; - _save_config(); - } - else - goto out2; - } - else - { - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); - goto out; - } - } - -out:; - btn_wait(); -out2:; - free(ments); - free(boot_values); - free(boot_text); - - sd_unmount(); - - if (temp_autoboot == NULL) - return; -} - -void config_bootdelay() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 delay_entries = 6; - u32 delay_text_size = 32; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); - u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); - char *delay_text = (char *)malloc(delay_text_size * delay_entries); - - for (u32 j = 0; j < delay_entries; j++) - delay_values[j] = j; - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_DATA; - if (h_cfg.bootwait) - ments[2].caption = " 0 seconds (Bootlogo disabled)"; - else - ments[2].caption = "*0 seconds (Bootlogo disabled)"; - ments[2].data = &delay_values[0]; - - u32 i = 0; - for (i = 1; i < delay_entries; i++) - { - if (h_cfg.bootwait != i) - delay_text[i * delay_text_size] = ' '; - else - delay_text[i * delay_text_size] = '*'; - delay_text[i * delay_text_size + 1] = i + '0'; - strcpy(delay_text + i * delay_text_size + 2, " seconds"); - - ments[i + 2].type = MENT_DATA; - ments[i + 2].caption = delay_text + (i * delay_text_size); - ments[i + 2].data = &delay_values[i]; - } - - memset(&ments[i + 2], 0, sizeof(ment_t)); - menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; - - u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); - if (temp_bootwait != NULL) - { - h_cfg.bootwait = *(u32 *)temp_bootwait; - _save_config(); - } - - free(ments); - free(delay_values); - free(delay_text); - - if (temp_bootwait == NULL) - return; - btn_wait(); -} - -void config_verification() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 vr_text_size = 64; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); - u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3); - char *vr_text = (char *)malloc(vr_text_size * 3); - - for (u32 j = 0; j < 3; j++) - { - vr_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &vr_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - strcpy(vr_text, " Disable (Fastest - Unsafe)"); - strcpy(vr_text + 64, " Sparse (Fast - Safe)"); - strcpy(vr_text + 128, " Full (Slow - Safe)"); - - for (u32 i = 0; i < 3; i++) - { - if (h_cfg.verification != i) - vr_text[vr_text_size * i] = ' '; - else - vr_text[vr_text_size * i] = '*'; - ments[2 + i].caption = vr_text + (i * vr_text_size); - } - - memset(&ments[5], 0, sizeof(ment_t)); - menu_t menu = {ments, "Backup & Restore verification", 0, 0}; - - u32 *temp_verification = (u32 *)tui_do_menu(&menu); - if (temp_verification != NULL) - { - h_cfg.verification = *(u32 *)temp_verification; - _save_config(); - } - - free(ments); - free(vr_values); - free(vr_text); - - if (temp_verification == NULL) - return; - btn_wait(); -} - -void config_backlight() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - u32 bri_text_size = 8; - u32 bri_entries = 11; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); - u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); - char *bri_text = (char *)malloc(bri_text_size * bri_entries); - - for (u32 j = 1; j < bri_entries; j++) - bri_values[j] = j * 10; - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - u32 i = 0; - for (i = 1; i < bri_entries; i++) - { - if ((h_cfg.backlight / 20) != i) - bri_text[i * bri_text_size] = ' '; - else - bri_text[i * bri_text_size] = '*'; - - if (i < 10) - { - bri_text[i * bri_text_size + 1] = i + '0'; - strcpy(bri_text + i * bri_text_size + 2, "0%"); - } - else - strcpy(bri_text + i * bri_text_size + 1, "100%"); - - ments[i + 1].type = MENT_DATA; - ments[i + 1].caption = bri_text + (i * bri_text_size); - ments[i + 1].data = &bri_values[i]; - } - - memset(&ments[i + 1], 0, sizeof(ment_t)); - menu_t menu = {ments, "Backlight brightness", 0, 0}; - - u32 *temp_backlight = (u32 *)tui_do_menu(&menu); - if (temp_backlight != NULL) - { - h_cfg.backlight = (*(u32 *)temp_backlight) * 2; - _save_config(); - } - - free(ments); - free(bri_values); - free(bri_text); - - if (temp_backlight == NULL) - return; - btn_wait(); -} - -void config_auto_hos_poweroff() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); - u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); - - for (u32 j = 0; j < 3; j++) - { - hp_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &hp_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - if (h_cfg.autohosoff == 1) - { - ments[2].caption = " Disable"; - ments[3].caption = "*Enable"; - ments[4].caption = " Enable (No logo)"; - } - else if (h_cfg.autohosoff >= 2) - { - ments[2].caption = " Disable"; - ments[3].caption = " Enable"; - ments[4].caption = "*Enable (No logo)"; - } - else - { - ments[2].caption = "*Disable"; - ments[3].caption = " Enable"; - ments[4].caption = " Enable (No logo)"; - } - - memset(&ments[5], 0, sizeof(ment_t)); - menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; - - u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); - if (temp_autohosoff != NULL) - { - h_cfg.autohosoff = *(u32 *)temp_autohosoff; - _save_config(); - } - - free(ments); - free(hp_values); - - if (temp_autohosoff == NULL) - return; - btn_wait(); -} - -void config_nogc() -{ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); - u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); - - for (u32 j = 0; j < 2; j++) - { - cb_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &cb_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - if (h_cfg.autonogc) - { - ments[2].caption = " Disable"; - ments[3].caption = "*Auto"; - } - else - { - ments[2].caption = "*Disable"; - ments[3].caption = " Auto"; - } - - memset(&ments[4], 0, sizeof(ment_t)); - menu_t menu = {ments, "No Gamecard", 0, 0}; - - u32 *temp_nogc = (u32 *)tui_do_menu(&menu); - if (temp_nogc != NULL) - { - h_cfg.autonogc = *(u32 *)temp_nogc; - _save_config(); - } - - free(ments); - free(cb_values); - - if (temp_nogc == NULL) - return; - btn_wait(); -} - -#pragma GCC pop_options diff --git a/bootloader/config/ini.c b/bootloader/config/ini.c deleted file mode 100644 index 651c916..0000000 --- a/bootloader/config/ini.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * - * 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 "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/dirlist.h" - -static char *_strdup(char *str) -{ - if (!str) - return NULL; - - // Remove starting space. - if (str[0] == ' ' && strlen(str)) - str++; - - char *res = (char *)malloc(strlen(str) + 1); - strcpy(res, str); - - // Remove trailing space. - if (strlen(res) && res[strlen(res) - 1] == ' ') - res[strlen(res) - 1] = 0; - - return res; -} - -u32 _find_section_name(char *lbuf, u32 lblen, char schar) -{ - u32 i; - // Depends on 'FF_USE_STRFUNC 2' that removes \r. - for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++) - ; - lbuf[i] = 0; - - return i; -} - -ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type) -{ - if (csec) - { - list_append(dst, &csec->link); - csec = NULL; - } - - csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); - csec->name = _strdup(name); - csec->type = type; - - return csec; -} - -int ini_parse(link_t *dst, char *ini_path, bool is_dir) -{ - u32 lblen; - u32 pathlen = strlen(ini_path); - u32 k = 0; - char lbuf[512]; - char *filelist = NULL; - FIL fp; - ini_sec_t *csec = NULL; - - char *filename = (char *)malloc(256); - - strcpy(filename, ini_path); - - // Get all ini filenames. - if (is_dir) - { - filelist = dirlist(filename, "*.ini", false); - if (!filelist) - { - free(filename); - return 0; - } - strcpy(filename + pathlen, "/"); - pathlen++; - } - - do - { - // Copy ini filename in path string. - if (is_dir) - { - if (filelist[k * 256]) - { - strcpy(filename + pathlen, &filelist[k * 256]); - k++; - } - else - break; - } - - // Open ini. - if (f_open(&fp, filename, FA_READ) != FR_OK) - { - free(filelist); - free(filename); - - return 0; - } - - do - { - // Fetch one line. - lbuf[0] = 0; - f_gets(lbuf, 512, &fp); - lblen = strlen(lbuf); - - // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r. - if (lblen && lbuf[lblen - 1] == '\n') - lbuf[lblen - 1] = 0; - - if (lblen > 2 && lbuf[0] == '[') // Create new section. - { - _find_section_name(lbuf, lblen, ']'); - - csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); - list_init(&csec->kvs); - } - else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'. - { - _find_section_name(lbuf, lblen, '}'); - - csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); - csec->color = 0xFF0AB9E6; - } - else if (lblen > 2 && lbuf[0] == '#') // Create comment. - { - csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT); - } - else if (lblen < 2) // Create empty line. - { - csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE); - } - else if (csec && csec->type == INI_CHOICE) // Extract key/value. - { - u32 i = _find_section_name(lbuf, lblen, '='); - - 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); - if (is_dir) - csec = NULL; - } - } while (is_dir); - - free(filename); - free(filelist); - - return 1; -} - -char *ini_check_payload_section(ini_sec_t *cfg) -{ - if (cfg == NULL) - return NULL; - - LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) - { - if (!strcmp("payload", kv->key)) - return kv->val; - } - - return NULL; -} diff --git a/bootloader/config/ini.h b/bootloader/config/ini.h deleted file mode 100644 index dffbe86..0000000 --- a/bootloader/config/ini.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../utils/types.h" -#include "../utils/list.h" - -#define INI_CHOICE 3 -#define INI_CAPTION 5 -#define INI_CHGLINE 6 -#define INI_NEWLINE 0xFE -#define INI_COMMENT 0xFF - -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; - u32 type; - u32 color; -} ini_sec_t; - -int ini_parse(link_t *dst, char *ini_path, bool is_dir); -char *ini_check_payload_section(ini_sec_t *cfg); - -#endif - diff --git a/bootloader/frontend/fe_emmc_tools.c b/bootloader/frontend/fe_emmc_tools.c deleted file mode 100644 index bd32137..0000000 --- a/bootloader/frontend/fe_emmc_tools.c +++ /dev/null @@ -1,942 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 Rajko Stojadinovic - * Copyright (c) 2018-2019 CTCaer - * - * 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 - -#include "fe_emmc_tools.h" -#include "../../common/memory_map.h" -#include "../config/config.h" -#include "../gfx/gfx.h" -#include "../gfx/tui.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/util.h" - -#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache. -#define OUT_FILENAME_SZ 128 -#define SHA256_SZ 0x20 - -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; -extern hekate_config h_cfg; - -extern bool sd_mount(); -extern void sd_unmount(); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); - -#pragma GCC push_options -#pragma GCC optimize ("Os") - -static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part) -{ - FIL fp; - u8 sparseShouldVerify = 4; - u32 btn = 0; - u32 prevPct = 200; - u32 sdFileSector = 0; - int res = 0; - - u8 hashEm[SHA256_SZ]; - u8 hashSd[SHA256_SZ]; - - if (f_open(&fp, outFilename, FA_READ) == FR_OK) - { - u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9); - - u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED; - u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED; - - u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); - tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500); - - u32 num = 0; - while (totalSectorsVer > 0) - { - num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER); - - // Check every time or every 4. - // Every 4 protects from fake sd, sector corruption and frequent I/O corruption. - // Full provides all that, plus protection from extremely rare I/O corruption. - if ((h_cfg.verification >= 2) || !(sparseShouldVerify % 4)) - { - if (!sdmmc_storage_read(storage, lba_curr, num, bufEm)) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n", - num, lba_curr); - - f_close(&fp); - return 1; - } - f_lseek(&fp, (u64)sdFileSector << (u64)9); - if (f_read(&fp, bufSd, num << 9, NULL)) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr); - - f_close(&fp); - return 1; - } - - se_calc_sha256(hashEm, bufEm, num << 9); - se_calc_sha256(hashSd, bufSd, num << 9); - res = memcmp(hashEm, hashSd, 0x10); - - if (res) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr); - - f_close(&fp); - return 1; - } - } - - pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); - if (pct != prevPct) - { - tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500); - prevPct = pct; - } - - lba_curr += num; - totalSectorsVer -= num; - sdFileSector += num; - sparseShouldVerify++; - - btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP); - if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP)) - { - gfx_con.fntsz = 16; - WPRINTF("\n\nVerification was cancelled!"); - gfx_con.fntsz = 8; - msleep(1000); - - f_close(&fp); - - return 0; - } - } - f_close(&fp); - - tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555); - - return 0; - } - else - { - gfx_con.fntsz = 16; - EPRINTF("\nFile not found or could not be loaded.\n\nVerification failed..\n"); - return 1; - } -} - -static void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx) -{ - if (numSplitParts >= 10 && currPartIdx < 10) - { - outFilename[sdPathLen] = '0'; - itoa(currPartIdx, &outFilename[sdPathLen + 1], 10); - } - else - itoa(currPartIdx, &outFilename[sdPathLen], 10); -} - -static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part) -{ - static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF; - static const u32 SECTORS_TO_MIB_COEFF = 11; - - u32 multipartSplitSize = (1u << 31); - u32 totalSectors = part->lba_end - part->lba_start + 1; - u32 currPartIdx = 0; - u32 numSplitParts = 0; - u32 maxSplitParts = 0; - u32 btn = 0; - bool isSmallSdCard = false; - bool partialDumpInProgress = false; - int res = 0; - char *outFilename = sd_path; - u32 sdPathLen = strlen(sd_path); - - FIL partialIdxFp; - char partialIdxFilename[12]; - strcpy(partialIdxFilename, "partial.idx"); - - gfx_con.fntsz = 8; - gfx_printf("\nSD Card free space: %d MiB, Total backup size %d MiB\n\n", - sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, - totalSectors >> SECTORS_TO_MIB_COEFF); - - // 1GB parts for sd cards 8GB and less. - if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192) - multipartSplitSize = (1u << 30); - // Maximum parts fitting the free space available. - maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE); - - // Check if the USER partition or the RAW eMMC fits the sd card free space. - if (totalSectors > (sd_fs.free_clst * sd_fs.csize)) - { - isSmallSdCard = true; - - gfx_printf("%k\nSD card free space is smaller than backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC); - - if (!maxSplitParts) - { - gfx_con.fntsz = 16; - EPRINTF("Not enough free space for Partial Backup."); - - return 0; - } - } - // Check if we are continuing a previous raw eMMC or USER partition backup in progress. - if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) - { - gfx_printf("%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC); - - partialDumpInProgress = true; - // Force partial dumping, even if the card is larger. - isSmallSdCard = true; - - f_read(&partialIdxFp, &currPartIdx, 4, NULL); - f_close(&partialIdxFp); - - if (!maxSplitParts) - { - gfx_con.fntsz = 16; - EPRINTF("Not enough free space for Partial Backup."); - - return 0; - } - - // Increase maxSplitParts to accommodate previously backed up parts. - maxSplitParts += currPartIdx; - } - else if (isSmallSdCard) - gfx_printf("%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC); - - // Check if filesystem is FAT32 or the free space is smaller and backup in parts. - if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) || isSmallSdCard) - { - u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE; - numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors; - - outFilename[sdPathLen++] = '.'; - - // Continue from where we left, if Partial Backup in progress. - _update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0); - } - - FIL fp; - gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy); - if (!f_open(&fp, outFilename, FA_READ)) - { - f_close(&fp); - gfx_con.fntsz = 16; - - WPRINTF("An existing backup has been detected!"); - WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n"); - msleep(500); - - if (!(btn_wait() & BTN_POWER)) - return 0; - gfx_con.fntsz = 8; - gfx_clear_partial_grey(0x1B, gfx_con.savedy, 48); - } - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("Filename: %s\n\n", outFilename); - res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE); - if (res) - { - gfx_con.fntsz = 16; - EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename); - - return 0; - } - - u8 *buf = (u8 *)MIXD_BUF_ALIGNED; - - u32 lba_curr = part->lba_start; - u32 lbaStartPart = part->lba_start; - u32 bytesWritten = 0; - u32 prevPct = 200; - int retryCount = 0; - - // Continue from where we left, if Partial Backup in progress. - if (partialDumpInProgress) - { - lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE); - totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE); - lbaStartPart = lba_curr; // Update the start LBA for verification. - } - u64 totalSize = (u64)((u64)totalSectors << 9); - if (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT)) - f_lseek(&fp, totalSize); - else - f_lseek(&fp, MIN(totalSize, multipartSplitSize)); - f_lseek(&fp, 0); - - u32 num = 0; - u32 pct = 0; - while (totalSectors > 0) - { - if (numSplitParts != 0 && bytesWritten >= multipartSplitSize) - { - f_close(&fp); - memset(&fp, 0, sizeof(fp)); - currPartIdx++; - - if (h_cfg.verification) - { - // Verify part. - if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part)) - { - EPRINTF("\nPress any key and try again...\n"); - - return 0; - } - } - - _update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx); - - // Always create partial.idx before next part, in case a fatal error occurs. - if (isSmallSdCard) - { - // Create partial backup index file. - if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) - { - f_write(&partialIdxFp, &currPartIdx, 4, NULL); - f_close(&partialIdxFp); - } - else - { - gfx_con.fntsz = 16; - EPRINTF("\nError creating partial.idx file.\n"); - - return 0; - } - - // More parts to backup that do not currently fit the sd card free space or fatal error. - if (currPartIdx >= maxSplitParts) - { - gfx_puts("\n\n1. Press any key to unmount SD Card.\n\ - 2. Remove SD Card and move files to free space.\n\ - Don\'t move the partial.idx file!\n\ - 3. Re-insert SD Card.\n\ - 4. Select the SAME option again to continue.\n"); - gfx_con.fntsz = 16; - - return 1; - } - } - - // Create next part. - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("Filename: %s\n\n", outFilename); - lbaStartPart = lba_curr; - res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE); - if (res) - { - gfx_con.fntsz = 16; - EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename); - - return 0; - } - - bytesWritten = 0; - - totalSize = (u64)((u64)totalSectors << 9); - f_lseek(&fp, MIN(totalSize, multipartSplitSize)); - f_lseek(&fp, 0); - } - - retryCount = 0; - num = MIN(totalSectors, NUM_SECTORS_PER_ITER); - while (!sdmmc_storage_read(storage, lba_curr, num, buf)) - { - EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...", - num, lba_curr, ++retryCount); - - msleep(150); - if (retryCount >= 3) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nFailed to read %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n", - num, lba_curr); - EPRINTF("\nPress any key and try again...\n"); - - f_close(&fp); - f_unlink(outFilename); - - return 0; - } - } - res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL); - if (res) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res); - EPRINTF("\nPress any key and try again...\n"); - - f_close(&fp); - f_unlink(outFilename); - - return 0; - } - pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); - if (pct != prevPct) - { - tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555); - prevPct = pct; - } - - lba_curr += num; - totalSectors -= num; - bytesWritten += num * NX_EMMC_BLOCKSIZE; - - // Force a flush after a lot of data if not splitting. - if (numSplitParts == 0 && bytesWritten >= multipartSplitSize) - { - f_sync(&fp); - bytesWritten = 0; - } - - btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP); - if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP)) - { - gfx_con.fntsz = 16; - WPRINTF("\n\nThe backup was cancelled!"); - EPRINTF("\nPress any key...\n"); - msleep(1500); - - f_close(&fp); - f_unlink(outFilename); - - return 0; - } - } - tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555); - - // Backup operation ended successfully. - f_close(&fp); - - if (h_cfg.verification) - { - // Verify last part or single file backup. - if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part)) - { - EPRINTF("\nPress any key and try again...\n"); - - return 0; - } - else - tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500); - } - - gfx_con.fntsz = 16; - // Remove partial backup index file if no fatal errors occurred. - if (isSmallSdCard) - { - f_unlink(partialIdxFilename); - gfx_printf("%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC); - } - gfx_puts("\n\n"); - - return 1; -} - -typedef enum -{ - PART_BOOT = (1 << 0), - PART_SYSTEM = (1 << 1), - PART_USER = (1 << 2), - PART_RAW = (1 << 3), - PART_GP_ALL = (1 << 7) -} emmcPartType_t; - -static void _dump_emmc_selected(emmcPartType_t dumpType) -{ - int res = 0; - u32 timer = 0; - gfx_clear_partial_grey(0x1B, 0, 1256); - tui_sbar(true); - gfx_con_setpos(0, 0); - - if (!sd_mount()) - goto out; - - gfx_puts("Checking for available free space...\n\n"); - // Get SD Card free space for Partial Backup. - f_getfree("", &sd_fs.free_clst, NULL); - - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - EPRINTF("Failed to init eMMC."); - goto out; - } - - int i = 0; - char sdPath[OUT_FILENAME_SZ]; - // Create Restore folders, if they do not exist. - emmcsn_path_impl(sdPath, "/restore", "", &storage); - emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage); - - timer = get_tmr_s(); - if (dumpType & PART_BOOT) - { - const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; - - emmc_part_t bootPart; - memset(&bootPart, 0, sizeof(bootPart)); - bootPart.lba_start = 0; - bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; - for (i = 0; i < 2; i++) - { - strcpy(bootPart.name, "BOOT"); - bootPart.name[4] = (u8)('0' + i); - bootPart.name[5] = 0; - - gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i, - bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC); - - sdmmc_storage_set_mmc_partition(&storage, i + 1); - - emmcsn_path_impl(sdPath, "", bootPart.name, &storage); - res = _dump_emmc_part(sdPath, &storage, &bootPart); - } - } - - if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW)) - { - sdmmc_storage_set_mmc_partition(&storage, 0); - - if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER)) - { - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) - { - if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER")) - continue; - if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER")) - continue; - - gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++, - part->name, part->lba_start, part->lba_end, 0xFFCCCCCC); - - emmcsn_path_impl(sdPath, "/partitions", part->name, &storage); - res = _dump_emmc_part(sdPath, &storage, part); - // If a part failed, don't continue. - if (!res) - break; - } - nx_emmc_gpt_free(&gpt); - } - - if (dumpType & PART_RAW) - { - // Get GP partition size dynamically. - const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt; - - emmc_part_t rawPart; - memset(&rawPart, 0, sizeof(rawPart)); - rawPart.lba_start = 0; - rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1; - strcpy(rawPart.name, "rawnand.bin"); - { - gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++, - rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC); - - emmcsn_path_impl(sdPath, "", rawPart.name, &storage); - res = _dump_emmc_part(sdPath, &storage, &rawPart); - } - } - } - - gfx_putc('\n'); - timer = get_tmr_s() - timer; - gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60); - sdmmc_storage_end(&storage); - if (res && h_cfg.verification) - gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC); - else if (res) - gfx_printf("\nFinished! Press any key...\n"); - -out: - sd_unmount(); - btn_wait(); -} - -void dump_emmc_system() { _dump_emmc_selected(PART_SYSTEM); } -void dump_emmc_user() { _dump_emmc_selected(PART_USER); } -void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); } -void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); } - -static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part) -{ - static const u32 SECTORS_TO_MIB_COEFF = 11; - - u32 totalSectors = part->lba_end - part->lba_start + 1; - u32 currPartIdx = 0; - u32 numSplitParts = 0; - u32 lbaStartPart = part->lba_start; - int res = 0; - char *outFilename = sd_path; - u32 sdPathLen = strlen(sd_path); - u64 fileSize = 0; - u64 totalCheckFileSize = 0; - gfx_con.fntsz = 8; - - FIL fp; - FILINFO fno; - - gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy); - - bool use_multipart = false; - - if (allow_multi_part) - { - // Check to see if there is a combined file and if so then use that. - if (f_stat(outFilename, &fno)) - { - // If not, check if there are partial files and the total size matches. - gfx_printf("No single file, checking for part files...\n"); - - outFilename[sdPathLen++] = '.'; - - // Stat total size of the part files. - while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors) - { - _update_filename(outFilename, sdPathLen, 99, numSplitParts); - - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("\nFilename: %s\n", outFilename); - - if (f_stat(outFilename, &fno)) - { - WPRINTFARGS("Error (%d) file not found '%s'. Aborting...\n", res, outFilename); - return 0; - } - else - totalCheckFileSize += (u64)fno.fsize; - - numSplitParts++; - } - - gfx_printf("\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9)); - - if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors) - { - gfx_con.fntsz = 16; - EPRINTF("Size of SD Card split backups does not match,\neMMC's selected part size.\n"); - - return 0; - } - else - { - use_multipart = true; - _update_filename(outFilename, sdPathLen, numSplitParts, 0); - } - } - } - - res = f_open(&fp, outFilename, FA_READ); - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("\nFilename: %s\n", outFilename); - if (res) - { - if (res != FR_NO_FILE) - EPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res); - else - WPRINTFARGS("Error (%d) file not found. Continuing...\n", res); - gfx_con.fntsz = 16; - - return 0; - } - else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size. - { - gfx_con.fntsz = 16; - EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n"); - f_close(&fp); - - return 0; - } - else - { - fileSize = (u64)f_size(&fp); - gfx_printf("\nTotal restore size: %d MiB.\n\n", - (u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF); - } - - u8 *buf = (u8 *)MIXD_BUF_ALIGNED; - - u32 lba_curr = part->lba_start; - u32 bytesWritten = 0; - u32 prevPct = 200; - int retryCount = 0; - - u32 num = 0; - u32 pct = 0; - - gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy); - - while (totalSectors > 0) - { - // If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that. - if (numSplitParts != 0 && bytesWritten >= fileSize) - { - // If we have more bytes written then close the file pointer and increase the part index we are using - f_close(&fp); - memset(&fp, 0, sizeof(fp)); - currPartIdx++; - - if (h_cfg.verification) - { - // Verify part. - if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part)) - { - EPRINTF("\nPress any key and try again...\n"); - - return 0; - } - } - - _update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx); - - // Read from next part. - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("Filename: %s\n\n", outFilename); - - lbaStartPart = lba_curr; - - // Try to open the next file part - res = f_open(&fp, outFilename, FA_READ); - if (res) - { - gfx_con.fntsz = 16; - EPRINTFARGS("Error (%d) opening file %s.\n", res, outFilename); - - return 0; - } - fileSize = (u64)f_size(&fp); - bytesWritten = 0; - } - - retryCount = 0; - num = MIN(totalSectors, NUM_SECTORS_PER_ITER); - - res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL); - if (res) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res); - EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n"); - - f_close(&fp); - return 0; - } - while (!sdmmc_storage_write(storage, lba_curr, num, buf)) - { - EPRINTFARGS("Error writing %d blocks @ LBA %08X\nto eMMC (try %d), retrying...", - num, lba_curr, ++retryCount); - - msleep(150); - if (retryCount >= 3) - { - gfx_con.fntsz = 16; - EPRINTFARGS("\nFailed to write %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n", - num, lba_curr); - EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n"); - - f_close(&fp); - return 0; - } - } - pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); - if (pct != prevPct) - { - tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555); - prevPct = pct; - } - - lba_curr += num; - totalSectors -= num; - bytesWritten += num * NX_EMMC_BLOCKSIZE; - } - tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555); - - // Restore operation ended successfully. - f_close(&fp); - - if (h_cfg.verification) - { - // Verify restored data. - if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part)) - { - EPRINTF("\nPress any key and try again...\n"); - - return 0; - } - else - tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500); - } - - gfx_con.fntsz = 16; - gfx_puts("\n\n"); - - return 1; -} - -static void _restore_emmc_selected(emmcPartType_t restoreType) -{ - int res = 0; - u32 timer = 0; - gfx_clear_partial_grey(0x1B, 0, 1256); - tui_sbar(true); - gfx_con_setpos(0, 0); - - gfx_printf("%kThis may render your device inoperative!\n\n", 0xFFFFDD00); - gfx_printf("Are you really sure?\n\n%k", 0xFFCCCCCC); - if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL)) - { - gfx_puts("The mode you selected will only restore\nthe "); - if (restoreType & PART_BOOT) - gfx_puts("boot "); - gfx_puts("partitions that it can find.\n"); - gfx_puts("If it is not found, it will be skipped\nand continue with the next.\n\n"); - } - gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy); - - u8 failsafe_wait = 10; - while (failsafe_wait > 0) - { - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC); - msleep(1000); - failsafe_wait--; - } - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - - gfx_puts("Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n"); - - u32 btn = btn_wait(); - if (!(btn & BTN_POWER)) - goto out; - - if (!sd_mount()) - goto out; - - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - EPRINTF("Failed to init eMMC."); - goto out; - } - - int i = 0; - char sdPath[OUT_FILENAME_SZ]; - - timer = get_tmr_s(); - if (restoreType & PART_BOOT) - { - const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; - - emmc_part_t bootPart; - memset(&bootPart, 0, sizeof(bootPart)); - bootPart.lba_start = 0; - bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; - for (i = 0; i < 2; i++) - { - strcpy(bootPart.name, "BOOT"); - bootPart.name[4] = (u8)('0' + i); - bootPart.name[5] = 0; - - gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i, - bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC); - - sdmmc_storage_set_mmc_partition(&storage, i + 1); - - emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage); - res = _restore_emmc_part(sdPath, &storage, &bootPart, false); - } - } - - if (restoreType & PART_GP_ALL) - { - sdmmc_storage_set_mmc_partition(&storage, 0); - - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) - { - gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++, - part->name, part->lba_start, part->lba_end, 0xFFCCCCCC); - - emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage); - res = _restore_emmc_part(sdPath, &storage, part, false); - } - nx_emmc_gpt_free(&gpt); - } - - if (restoreType & PART_RAW) - { - // Get GP partition size dynamically. - const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt; - - emmc_part_t rawPart; - memset(&rawPart, 0, sizeof(rawPart)); - rawPart.lba_start = 0; - rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1; - strcpy(rawPart.name, "rawnand.bin"); - { - gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++, - rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC); - - emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage); - res = _restore_emmc_part(sdPath, &storage, &rawPart, true); - } - } - - gfx_putc('\n'); - timer = get_tmr_s() - timer; - gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60); - sdmmc_storage_end(&storage); - if (res && h_cfg.verification) - gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC); - else if (res) - gfx_printf("\nFinished! Press any key...\n"); - -out: - sd_unmount(); - btn_wait(); -} - -void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); } -void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); } -void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); } - -#pragma GCC pop_options diff --git a/bootloader/frontend/fe_emmc_tools.h b/bootloader/frontend/fe_emmc_tools.h deleted file mode 100644 index 059a03a..0000000 --- a/bootloader/frontend/fe_emmc_tools.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018 Rajko Stojadinovic - * Copyright (c) 2018 CTCaer - * - * 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 _FE_EMMC_TOOLS_H_ -#define _FE_EMMC_TOOLS_H_ - -void dump_emmc_system(); -void dump_emmc_user(); -void dump_emmc_boot(); -void dump_emmc_rawnand(); - -void restore_emmc_boot(); -void restore_emmc_rawnand(); -void restore_emmc_gpp_parts(); - -#endif diff --git a/bootloader/frontend/fe_info.c b/bootloader/frontend/fe_info.c index b12854e..67bcfba 100644 --- a/bootloader/frontend/fe_info.c +++ b/bootloader/frontend/fe_info.c @@ -1,7 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2018 balika011 + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,121 +17,47 @@ #include +#include + #include "fe_info.h" -#include "../gfx/gfx.h" +#include "../config.h" #include "../hos/hos.h" #include "../hos/pkg1.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../power/bq24193.h" -#include "../power/max17050.h" -#include "../sec/tsec.h" -#include "../soc/fuse.h" -#include "../soc/i2c.h" -#include "../soc/kfuse.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../storage/mmc.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/util.h" +#include -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; - -extern bool sd_mount(); -extern void sd_unmount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); +extern hekate_config h_cfg; #pragma GCC push_options #pragma GCC optimize ("Os") void print_fuseinfo() { + u32 fuse_size = h_cfg.t210b01 ? 0x368 : 0x300; + u32 fuse_address = h_cfg.t210b01 ? 0x7000F898 : 0x7000F900; + gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); - u32 burntFuses = 0; - for (u32 i = 0; i < 32; i++) - { - if ((fuse_read_odm(7) >> i) & 1) - burntFuses++; - } - gfx_printf("\nSKU: %X - ", FUSE(FUSE_SKU_INFO)); - switch (fuse_read_odm(4) & 3) + switch (fuse_read_hw_state()) { - case 0: + case FUSE_NX_HW_STATE_PROD: gfx_printf("Retail\n"); break; - case 3: + case FUSE_NX_HW_STATE_DEV: gfx_printf("Dev\n"); break; } - gfx_printf("Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F); - gfx_printf("Burnt fuses: %d / 64\n", burntFuses); + gfx_printf("Sdram ID: %d\n", fuse_read_dramid(true)); + gfx_printf("Burnt fuses: %d / 64\n", bit_count(fuse_read_odm(7))); gfx_printf("Secure key: %08X%08X%08X%08X\n\n\n", byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3))); - gfx_printf("%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC); - gfx_hexdump(0x7000F900, (u8 *)0x7000F900, 0x300); + gfx_printf("%kFuse cache:\n\n%k", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); + gfx_hexdump(fuse_address, (u8 *)fuse_address, fuse_size); - gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n"); - - u32 btn = btn_wait(); - if (btn & BTN_POWER) - { - if (sd_mount()) - { - char path[64]; - emmcsn_path_impl(path, "/dumps", "fuse_cached.bin", NULL); - if (!sd_save_to_file((u8 *)0x7000F900, 0x300, path)) - gfx_puts("\nfuse_cached.bin saved!\n"); - - u32 words[192]; - fuse_read_array(words); - emmcsn_path_impl(path, "/dumps", "fuse_array_raw.bin", NULL); - if (!sd_save_to_file((u8 *)words, sizeof(words), path)) - gfx_puts("\nfuse_array_raw.bin saved!\n"); - - sd_unmount(); - } - - btn_wait(); - } -} - -void print_kfuseinfo() -{ - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - gfx_printf("%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC); - u32 buf[KFUSE_NUM_WORDS]; - if (!kfuse_read(buf)) - EPRINTF("CRC fail."); - else - gfx_hexdump(0, (u8 *)buf, KFUSE_NUM_WORDS * 4); - - gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n"); - - u32 btn = btn_wait(); - if (btn & BTN_POWER) - { - if (sd_mount()) - { - char path[64]; - emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL); - if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path)) - gfx_puts("\nDone!\n"); - sd_unmount(); - } - - btn_wait(); - } + btn_wait(); } void print_mmc_info() @@ -142,10 +67,7 @@ void print_mmc_info() static const u32 SECTORS_TO_MIB_COEFF = 11; - sdmmc_storage_t storage; - sdmmc_t sdmmc; - - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { EPRINTF("Failed to init eMMC."); goto out; @@ -155,52 +77,35 @@ void print_mmc_info() u16 card_type; u32 speed = 0; - gfx_printf("%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC); - switch (storage.csd.mmca_vsn) + gfx_printf("%kCID:%k\n", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); + switch (emmc_storage.csd.mmca_vsn) { - case 0: /* MMC v1.0 - v1.2 */ - case 1: /* MMC v1.4 */ - gfx_printf( - " Vendor ID: %03X\n" - " Model: %c%c%c%c%c%c%c\n" - " HW rev: %X\n" - " FW rev: %X\n" - " S/N: %03X\n" - " Month/Year: %02d/%04d\n\n", - storage.cid.manfid, - storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2], - storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5], - storage.cid.prod_name[6], storage.cid.hwrev, storage.cid.fwrev, - storage.cid.serial, storage.cid.month, storage.cid.year); - break; case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ case 4: /* MMC v4 */ gfx_printf( " Vendor ID: %X\n" - " Card/BGA: %X\n" " OEM ID: %02X\n" " Model: %c%c%c%c%c%c\n" " Prd Rev: %X\n" " S/N: %04X\n" " Month/Year: %02d/%04d\n\n", - storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid, - storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2], - storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5], - storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year); + emmc_storage.cid.manfid, emmc_storage.cid.oemid, + emmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2], + emmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4], emmc_storage.cid.prod_name[5], + emmc_storage.cid.prv, emmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year); break; default: - EPRINTFARGS("eMMC has unknown MMCA version %d", storage.csd.mmca_vsn); break; } - if (storage.csd.structure == 0) + if (emmc_storage.csd.structure == 0) EPRINTF("Unknown CSD structure."); else { gfx_printf("%kExtended CSD V1.%d:%k\n", - 0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC); - card_type = storage.ext_csd.card_type; + TXT_CLR_CYAN_L, emmc_storage.ext_csd.ext_struct, TXT_CLR_DEFAULT); + card_type = emmc_storage.ext_csd.card_type; char card_type_support[96]; card_type_support[0] = 0; if (card_type & EXT_CSD_CARD_TYPE_HS_26) @@ -238,48 +143,48 @@ void print_mmc_info() " Max Rate: %d MB/s (%d MHz)\n" " Current Rate: %d MB/s\n" " Type Support: ", - storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass, - storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF, - storage.csd.busspeed); + emmc_storage.csd.mmca_vsn, emmc_storage.ext_csd.rev, emmc_storage.ext_csd.dev_version, emmc_storage.csd.cmdclass, + emmc_storage.csd.capacity == (4096 * EMMC_BLOCKSIZE) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF, + emmc_storage.csd.busspeed); gfx_con.fntsz = 8; gfx_printf("%s", card_type_support); gfx_con.fntsz = 16; gfx_printf("\n\n", card_type_support); - u32 boot_size = storage.ext_csd.boot_mult << 17; - u32 rpmb_size = storage.ext_csd.rpmb_mult << 17; - gfx_printf("%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC); - gfx_printf(" 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC, - boot_size / 1024, boot_size / 512); + u32 boot_size = emmc_storage.ext_csd.boot_mult << 17; + u32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17; + gfx_printf("%keMMC Partitions:%k\n", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); + gfx_printf(" 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", TXT_CLR_GREENISH, TXT_CLR_DEFAULT, + boot_size / 1024, boot_size / EMMC_BLOCKSIZE); gfx_put_small_sep(); - gfx_printf(" 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC, - boot_size / 1024, boot_size / 512); + gfx_printf(" 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", TXT_CLR_GREENISH, TXT_CLR_DEFAULT, + boot_size / 1024, boot_size / EMMC_BLOCKSIZE); gfx_put_small_sep(); - gfx_printf(" 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC, - rpmb_size / 1024, rpmb_size / 512); + gfx_printf(" 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", TXT_CLR_GREENISH, TXT_CLR_DEFAULT, + rpmb_size / 1024, rpmb_size / EMMC_BLOCKSIZE); gfx_put_small_sep(); - gfx_printf(" 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC, - storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt); + gfx_printf(" 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", TXT_CLR_GREENISH, TXT_CLR_DEFAULT, + emmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt); gfx_put_small_sep(); - gfx_printf("%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC); + gfx_printf("%kGPP (eMMC USER) partition table:%k\n", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); - sdmmc_storage_set_mmc_partition(&storage, 0); + emmc_set_partition(EMMC_GPP); LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); + emmc_gpt_parse(&gpt); int gpp_idx = 0; LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) { gfx_printf(" %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n", - gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, + gpp_idx++, TXT_CLR_GREENISH, part->name, TXT_CLR_DEFAULT, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end); gfx_put_small_sep(); } - nx_emmc_gpt_free(&gpt); + emmc_gpt_free(&gpt); } } out: - sdmmc_storage_end(&storage); + emmc_end(); btn_wait(); } @@ -291,9 +196,9 @@ void print_sdcard_info() gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); - if (sd_mount()) + if (sd_initialize(false)) { - gfx_printf("%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC); + gfx_printf("%kCard IDentification:%k\n", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); gfx_printf( " Vendor ID: %02x\n" " OEM ID: %c%c\n" @@ -308,7 +213,8 @@ void print_sdcard_info() sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial, sd_storage.cid.month, sd_storage.cid.year); - gfx_printf("%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC); + u16 *sd_errors = sd_get_error_count(); + gfx_printf("%kCard-Specific Data V%d.0:%k\n", TXT_CLR_CYAN_L, sd_storage.csd.structure + 1, TXT_CLR_DEFAULT); gfx_printf( " Cmd Classes: %02X\n" " Capacity: %d MiB\n" @@ -318,137 +224,50 @@ void print_sdcard_info() " UHS Grade: U%d\n" " Video Class: V%d\n" " App perf class: A%d\n" - " Write Protect: %d\n\n", + " Write Protect: %d\n" + " SDMMC Errors: %d %d %d\n\n", sd_storage.csd.cmdclass, sd_storage.sec_cnt >> 11, sd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2, sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, - sd_storage.ssr.app_class, sd_storage.csd.write_protect); + sd_storage.ssr.app_class, sd_storage.csd.write_protect, + sd_errors[0], sd_errors[1], sd_errors[2]); // SD_ERROR_INIT_FAIL, SD_ERROR_RW_FAIL, SD_ERROR_RW_RETRY. - gfx_puts("Acquiring FAT volume info...\n\n"); - f_getfree("", &sd_fs.free_clst, NULL); - gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n", - 0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC, - sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512); - sd_unmount(); + int res = f_mount(&sd_fs, "", 1); + if (!res) + { + gfx_puts("Acquiring FAT volume info...\n\n"); + f_getfree("", &sd_fs.free_clst, NULL); + gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n", + TXT_CLR_CYAN_L, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", TXT_CLR_DEFAULT, + sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512); + f_mount(NULL, "", 1); + } + else + { + EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\n" + "Make sure that a FAT partition exists..", res); + } + + sd_end(); + } + else + { + EPRINTF("Failed to init SD card."); + if (!sdmmc_get_sd_inserted()) + EPRINTF("Make sure that it is inserted."); + else + EPRINTF("SD Card Reader is not properly seated!"); + sd_end(); } btn_wait(); } -void print_tsec_key() -{ - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - u32 retries = 0; - - tsec_ctxt_t tsec_ctxt; - 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); - sdmmc_storage_end(&storage); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); - if (!pkg1_id) - { - EPRINTF("Unknown pkg1 version for reading\nTSEC firmware."); - goto out_wait; - } - - u8 keys[0x10 * 2]; - memset(keys, 0x00, 0x20); - - tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off; - tsec_ctxt.pkg1 = pkg1; - tsec_ctxt.pkg11_off = pkg1_id->pkg11_off; - tsec_ctxt.secmon_base = pkg1_id->secmon_base; - - if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600) - tsec_ctxt.size = 0xF00; - else if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - tsec_ctxt.size = 0x2900; - else if (pkg1_id->kb == KB_FIRMWARE_VERSION_700) - { - tsec_ctxt.size = 0x3000; - // Exit after TSEC key generation. - *((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8; - } - else - tsec_ctxt.size = 0x3300; - - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size); - tsec_ctxt.fw = tsec_paged; - } - - int res = 0; - - while (tsec_query(keys, pkg1_id->kb, &tsec_ctxt) < 0) - { - memset(keys, 0x00, 0x20); - - retries++; - - if (retries > 3) - { - res = -1; - break; - } - } - - gfx_printf("%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC); - - if (res >= 0) - { - for (u32 j = 0; j < 0x10; j++) - gfx_printf("%02X", keys[j]); - - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - { - gfx_printf("\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC); - for (u32 j = 0; j < 0x10; j++) - gfx_printf("%02X", keys[0x10 + j]); - } - } - else - EPRINTFARGS("ERROR %X\n", res); - - gfx_puts("\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n"); - - u32 btn = btn_wait(); - if (btn & BTN_POWER) - { - if (sd_mount()) - { - char path[64]; - emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL); - if (!sd_save_to_file(keys, 0x10 * 2, path)) - gfx_puts("\nDone!\n"); - sd_unmount(); - } - } - else - goto out; - -out_wait: - btn_wait(); - -out: - free(pkg1); -} - void print_fuel_gauge_info() { int value = 0; - gfx_printf("%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC); + gfx_printf("%kFuel Gauge Info:\n%k", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); max17050_get_property(MAX17050_RepSOC, &value); gfx_printf("Capacity now: %3d%\n", value >> 8); @@ -463,16 +282,10 @@ void print_fuel_gauge_info() gfx_printf("Capacity (design): %4d mAh\n", value); max17050_get_property(MAX17050_Current, &value); - if (value >= 0) - gfx_printf("Current now: %d mA\n", value / 1000); - else - gfx_printf("Current now: -%d mA\n", ~value / 1000); + gfx_printf("Current now: %d mA\n", value / 1000); max17050_get_property(MAX17050_AvgCurrent, &value); - if (value >= 0) - gfx_printf("Current average: %d mA\n", value / 1000); - else - gfx_printf("Current average: -%d mA\n", ~value / 1000); + gfx_printf("Current average: %d mA\n", value / 1000); max17050_get_property(MAX17050_VCELL, &value); gfx_printf("Voltage now: %4d mV\n", value); @@ -490,35 +303,30 @@ void print_fuel_gauge_info() gfx_printf("Empty voltage (design): %4d mV\n", value); max17050_get_property(MAX17050_TEMP, &value); - if (value >= 0) - gfx_printf("Battery temperature: %d.%d oC\n", value / 10, value % 10); - else - gfx_printf("Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10); + gfx_printf("Battery temperature: %d.%d oC\n", value / 10, + (value >= 0 ? value : (~value)) % 10); } void print_battery_charger_info() { int value = 0; - gfx_printf("%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC); - - bq24193_get_property(BQ24193_InputVoltageLimit, &value); - gfx_printf("Input voltage limit: %4d mV\n", value); + gfx_printf("%k\n\nBattery Charger Info:\n%k", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); bq24193_get_property(BQ24193_InputCurrentLimit, &value); - gfx_printf("Input current limit: %4d mA\n", value); + gfx_printf("Input current limit: %4d mA\n", value); bq24193_get_property(BQ24193_SystemMinimumVoltage, &value); - gfx_printf("Min voltage limit: %4d mV\n", value); + gfx_printf("System voltage limit: %4d mV\n", value); bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value); - gfx_printf("Fast charge current limit: %4d mA\n", value); + gfx_printf("Charge current limit: %4d mA\n", value); bq24193_get_property(BQ24193_ChargeVoltageLimit, &value); - gfx_printf("Charge voltage limit: %4d mV\n", value); + gfx_printf("Charge voltage limit: %4d mV\n", value); bq24193_get_property(BQ24193_ChargeStatus, &value); - gfx_printf("Charge status: "); + gfx_printf("Charge status: "); switch (value) { case 0: @@ -538,7 +346,7 @@ void print_battery_charger_info() break; } bq24193_get_property(BQ24193_TempStatus, &value); - gfx_printf("Temperature status: "); + gfx_printf("Temperature status: "); switch (value) { case 0: @@ -573,7 +381,7 @@ void print_battery_info() u8 *buf = (u8 *)malloc(0x100 * 2); - gfx_printf("%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC); + gfx_printf("%k\n\nBattery Fuel Gauge Registers:\n%k", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); for (int i = 0; i < 0x200; i += 2) { @@ -583,94 +391,7 @@ void print_battery_info() gfx_hexdump(0, (u8 *)buf, 0x200); - gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n"); - - u32 btn = btn_wait(); - - if (btn & BTN_POWER) - { - if (sd_mount()) - { - char path[64]; - emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL); - if (sd_save_to_file((u8 *)buf, 0x200, path)) - EPRINTF("\nError creating fuel.bin file."); - else - gfx_puts("\nDone!\n"); - sd_unmount(); - } - - btn_wait(); - } - free(buf); -} - -void _ipatch_process(u32 offset, u32 value) -{ - gfx_printf("%8x %8x", BOOTROM_BASE + offset, value); - u8 lo = value & 0xff; - switch (value >> 8) - { - case 0x20: - gfx_printf(" MOVS R0, #0x%02X", lo); - break; - case 0xDF: - gfx_printf(" SVC #0x%02X", lo); - break; - } - gfx_puts("\n"); -} - -void bootrom_ipatches_info() -{ - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - static const u32 BOOTROM_SIZE = 0x18000; - - u32 res = fuse_read_ipatch(_ipatch_process); - if (res != 0) - EPRINTFARGS("Failed to read ipatches. Error: %d", res); - - gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n"); - - u32 btn = btn_wait(); - if (btn & BTN_POWER) - { - if (sd_mount()) - { - char path[64]; - u32 iram_evp_thunks[0x200]; - u32 iram_evp_thunks_len = sizeof(iram_evp_thunks); - res = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len); - if (res == 0) - { - emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL); - if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path)) - gfx_puts("\nevp_thunks.bin saved!\n"); - } - else - EPRINTFARGS("Failed to read evp_thunks. Error: %d", res); - - emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL); - if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path)) - gfx_puts("\nbootrom_patched.bin saved!\n"); - - u32 ipatch_backup[14]; - memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup)); - memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup)); - - emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL); - if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path)) - gfx_puts("\nbootrom_unpatched.bin saved!\n"); - - memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup)); - - sd_unmount(); - } - - btn_wait(); - } + btn_wait(); } #pragma GCC pop_options diff --git a/bootloader/frontend/fe_info.h b/bootloader/frontend/fe_info.h index 64eb83f..db649aa 100644 --- a/bootloader/frontend/fe_info.h +++ b/bootloader/frontend/fe_info.h @@ -1,7 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * Copyright (c) 2018 balika011 + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -20,13 +19,10 @@ #define _FE_INFO_H_ void print_fuseinfo(); -void print_kfuseinfo(); void print_mmc_info(); void print_sdcard_info(); -void print_tsec_key(); void print_fuel_gauge_info(); void print_battery_charger_info(); void print_battery_info(); -void bootrom_ipatches_info(); #endif diff --git a/bootloader/frontend/fe_tools.c b/bootloader/frontend/fe_tools.c index 484364c..eb47fb0 100644 --- a/bootloader/frontend/fe_tools.c +++ b/bootloader/frontend/fe_tools.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * Copyright (c) 2018 Reisyukaku * * This program is free software; you can redistribute it and/or modify it @@ -19,293 +19,84 @@ #include #include +#include + #include "fe_tools.h" -#include "../config/config.h" -#include "../gfx/gfx.h" +#include "../config.h" #include "../gfx/tui.h" -#include "../hos/hos.h" -#include "../hos/pkg1.h" -#include "../hos/pkg2.h" -#include "../hos/sept.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../power/max7762x.h" -#include "../sec/se.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../soc/fuse.h" -#include "../utils/btn.h" -#include "../utils/util.h" +#include extern boot_cfg_t b_cfg; extern hekate_config h_cfg; -extern bool sd_mount(); -extern void sd_unmount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); - #pragma GCC push_options #pragma GCC optimize ("Os") -void dump_packages12() +static void _toggle_autorcm(bool enable) { - if (!sd_mount()) - return; - - char path[64]; - - u8 *pkg1 = (u8 *)calloc(1, 0x40000); - u8 *warmboot = (u8 *)calloc(1, 0x40000); - u8 *secmon = (u8 *)calloc(1, 0x40000); - u8 *loader = (u8 *)calloc(1, 0x40000); - u8 *pkg2 = NULL; - u8 kb = 0; - - tsec_ctxt_t tsec_ctxt; - gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - EPRINTF("Failed to init eMMC."); - goto out_free; - } - sdmmc_storage_set_mmc_partition(&storage, 1); - - // Read package1. - 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) - { - EPRINTF("Unknown pkg1 version for reading\nTSEC firmware."); - // Dump package1. - emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &storage); - if (sd_save_to_file(pkg1, 0x40000, path)) - goto out_free; - gfx_puts("\nEnc pkg1 dumped to pkg1_enc.bin\n"); - - goto out_free; - } - const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20); - - kb = pkg1_id->kb; - - if (!h_cfg.se_keygen_done) - { - tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off; - tsec_ctxt.pkg1 = (void *)pkg1; - tsec_ctxt.pkg11_off = pkg1_id->pkg11_off; - tsec_ctxt.secmon_base = pkg1_id->secmon_base; - - if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) - { - b_cfg.autoboot = 0; - b_cfg.autoboot_list = 0; - - gfx_printf("sept will run to get the keys.\nThen rerun this option."); - btn_wait(); - - if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb, NULL)) - { - gfx_printf("Failed to run sept\n"); - goto out_free; - } - } - - // Read keyblob. - u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); - sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob); - - // Decrypt. - keygen(keyblob, kb, &tsec_ctxt, NULL); - if (kb <= KB_FIRMWARE_VERSION_600) - h_cfg.se_keygen_done = 1; - free(keyblob); - } - - if (kb <= KB_FIRMWARE_VERSION_600) - pkg1_decrypt(pkg1_id, pkg1); - - if (kb <= KB_FIRMWARE_VERSION_620) - { - pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1); - - // Display info. - gfx_printf("%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size); - - gfx_printf("%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base); - gfx_printf("%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size); - - gfx_printf("%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base); - gfx_printf("%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size); - - // Dump package1.1. - emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage); - if (sd_save_to_file(pkg1, 0x40000, path)) - goto out_free; - gfx_puts("\npkg1 dumped to pkg1_decr.bin\n"); - - // Dump nxbootloader. - emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage); - if (sd_save_to_file(loader, hdr->ldr_size, path)) - goto out_free; - gfx_puts("NX Bootloader dumped to nxloader.bin\n"); - - // Dump secmon. - emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage); - if (sd_save_to_file(secmon, hdr->sm_size, path)) - goto out_free; - gfx_puts("Secure Monitor dumped to secmon.bin\n"); - - // Dump warmboot. - emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage); - if (sd_save_to_file(warmboot, hdr->wb_size, path)) - goto out_free; - gfx_puts("Warmboot dumped to warmboot.bin\n\n\n"); - } - - // Dump package2.1. - sdmmc_storage_set_mmc_partition(&storage, 0); - // Parse eMMC GPT. - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - // 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. - u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); - u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); - u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; - free(tmp); - // Read in package2. - u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); - pkg2 = malloc(pkg2_size_aligned); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, - pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); - // Decrypt package2 and parse KIP1 blobs in INI1 section. - pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2, kb); - if (!pkg2_hdr) - { - gfx_printf("Pkg2 decryption failed!\n"); - goto out; - } - - // Display info. - gfx_printf("%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]); - gfx_printf("%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]); - - // Dump pkg2.1. - emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage); - if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path)) - goto out; - gfx_puts("\npkg2 dumped to pkg2_decr.bin\n"); - - // Dump kernel. - emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage); - if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path)) - goto out; - gfx_puts("Kernel dumped to kernel.bin\n"); - - // Dump INI1. - emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage); - u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; - u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1]; - if (!ini1_size) - { - pkg2_get_newkern_info(pkg2_hdr->data); - ini1_off = pkg2_newkern_ini1_start; - ini1_size = pkg2_newkern_ini1_end - pkg2_newkern_ini1_start; - } - if (sd_save_to_file(pkg2_hdr->data + ini1_off, ini1_size, path)) - goto out; - gfx_puts("INI1 dumped to ini1.bin\n"); - - gfx_puts("\nDone. Press any key...\n"); - -out: - nx_emmc_gpt_free(&gpt); -out_free: - free(pkg1); - free(secmon); - free(warmboot); - free(loader); - free(pkg2); - sdmmc_storage_end(&storage); - sd_unmount(); - - if (kb >= KB_FIRMWARE_VERSION_620) - se_aes_key_clear(8); - - btn_wait(); -} - -void _toggle_autorcm(bool enable) -{ - sdmmc_storage_t storage; - sdmmc_t sdmmc; - - u8 randomXor = 0; - - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - EPRINTF("Failed to init eMMC."); - goto out; - } - - u8 *tempbuf = (u8 *)malloc(0x200); - sdmmc_storage_set_mmc_partition(&storage, 1); - int i, sect = 0; - u8 corr_mod_byte0; - if ((fuse_read_odm(4) & 3) != 3) - corr_mod_byte0 = 0xF7; - else - corr_mod_byte0 = 0x37; + u8 corr_mod0, mod1; + u8 *tempbuf = (u8 *)malloc(0x200); + // Get the correct RSA modulus byte masks. + nx_emmc_get_autorcm_masks(&corr_mod0, &mod1); + + // Iterate BCTs. for (i = 0; i < 4; i++) { - sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE; - sdmmc_storage_read(&storage, sect, 1, tempbuf); + sect = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; + sdmmc_storage_read(&emmc_storage, sect, 1, tempbuf); + + // Check if 2nd byte of modulus is correct. + if (tempbuf[0x11] != mod1) + continue; if (enable) - { - do - { - randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking. - } while (!randomXor); // Avoid the lottery. - - tempbuf[0x10] ^= randomXor; - } + tempbuf[0x10] = 0; else - tempbuf[0x10] = corr_mod_byte0; - sdmmc_storage_write(&storage, sect, 1, tempbuf); + tempbuf[0x10] = corr_mod0; + sdmmc_storage_write(&emmc_storage, sect, 1, tempbuf); } free(tempbuf); - sdmmc_storage_end(&storage); if (enable) - gfx_printf("%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC); + gfx_printf("%kAutoRCM mode enabled!%k", TXT_CLR_ORANGE, TXT_CLR_DEFAULT); else - gfx_printf("%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC); + gfx_printf("%kAutoRCM mode disabled!%k", TXT_CLR_GREENISH, TXT_CLR_DEFAULT); gfx_printf("\n\nPress any key...\n"); -out: btn_wait(); } -void _enable_autorcm() { _toggle_autorcm(true); } -void _disable_autorcm() { _toggle_autorcm(false); } +static void _enable_autorcm() { _toggle_autorcm(true); } +static void _disable_autorcm() { _toggle_autorcm(false); } + +bool tools_autorcm_enabled() +{ + u8 mod0, mod1; + u8 *tempbuf = (u8 *)malloc(0x200); + + // Get the correct RSA modulus byte masks. + nx_emmc_get_autorcm_masks(&mod0, &mod1); + + // Get 1st RSA modulus. + emmc_set_partition(EMMC_BOOT0); + sdmmc_storage_read(&emmc_storage, 0x200 / EMMC_BLOCKSIZE, 1, tempbuf); + + // Check if 2nd byte of modulus is correct. + bool enabled = false; + if (tempbuf[0x11] == mod1) + if (tempbuf[0x10] != mod0) + enabled = true; + + free(tempbuf); + + return enabled; +} void menu_autorcm() { @@ -314,20 +105,13 @@ void menu_autorcm() if (h_cfg.rcm_patched) { - gfx_printf("%kThis device is RCM patched and\nAutoRCM function is disabled.\n\n" - "In case %kAutoRCM%k is enabled\nthis will %kBRICK%k your device PERMANENTLY!!%k", - 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC); + WPRINTF("This device is RCM patched and the\nfunction is disabled to avoid BRICKS!\n"); btn_wait(); return; } - // Do a simple check on the main BCT. - sdmmc_storage_t storage; - sdmmc_t sdmmc; - bool disabled = true; - - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { EPRINTF("Failed to init eMMC."); btn_wait(); @@ -335,23 +119,8 @@ void menu_autorcm() return; } - u8 *tempbuf = (u8 *)malloc(0x200); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf); - - if ((fuse_read_odm(4) & 3) != 3) - { - if (tempbuf[0x10] != 0xF7) - disabled = false; - } - else - { - if (tempbuf[0x10] != 0x37) - disabled = false; - } - - free(tempbuf); - sdmmc_storage_end(&storage); + // Do a simple check on the main BCT. + bool enabled = tools_autorcm_enabled(); // Create AutoRCM menu. ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); @@ -363,17 +132,17 @@ void menu_autorcm() ments[2].type = MENT_CAPTION; ments[3].type = MENT_CHGLINE; - if (disabled) + if (!enabled) { ments[2].caption = "Status: Disabled!"; - ments[2].color = 0xFF96FF00; + ments[2].color = TXT_CLR_GREENISH; ments[4].caption = "Enable AutoRCM"; ments[4].handler = _enable_autorcm; } else { ments[2].caption = "Status: Enabled!"; - ments[2].color = 0xFFFFBA00; + ments[2].color = TXT_CLR_ORANGE; ments[4].caption = "Disable AutoRCM"; ments[4].handler = _disable_autorcm; } @@ -381,223 +150,13 @@ void menu_autorcm() ments[4].data = NULL; memset(&ments[5], 0, sizeof(ment_t)); - menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0}; + menu_t menu = {ments, "This corrupts BOOT0!", 0, 0}; tui_do_menu(&menu); + + emmc_end(); + + free(ments); } -int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run) -{ - FRESULT res; - DIR dir; - u32 dirLength = 0; - static FILINFO fno; - - if (check_first_run) - { - // Read file attributes. - res = f_stat(path, &fno); - if (res != FR_OK) - return res; - - // Check if archive bit is set. - if (fno.fattrib & AM_ARC) - { - *(u32 *)total = *(u32 *)total + 1; - f_chmod(path, 0, AM_ARC); - } - } - - // Open directory. - res = f_opendir(&dir, path); - if (res != FR_OK) - return res; - - dirLength = strlen(path); - for (;;) - { - // Clear file or folder path. - path[dirLength] = 0; - - // Read a directory item. - res = f_readdir(&dir, &fno); - - // Break on error or end of dir. - if (res != FR_OK || fno.fname[0] == 0) - break; - - // Skip official Nintendo dir if started from root. - if (!hos_folder && !strcmp(fno.fname, "Nintendo")) - continue; - - // Set new directory or file. - memcpy(&path[dirLength], "/", 1); - memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1); - - // Check if archive bit is set. - if (fno.fattrib & AM_ARC) - { - *total = *total + 1; - f_chmod(path, 0, AM_ARC); - } - - // Is it a directory? - if (fno.fattrib & AM_DIR) - { - // Set archive bit to NCA folders. - if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca")) - { - *total = *total + 1; - f_chmod(path, AM_ARC, AM_ARC); - } - - // Update status bar. - tui_sbar(false); - - // Enter the directory. - res = _fix_attributes(path, total, hos_folder, 0); - if (res != FR_OK) - break; - } - } - - f_closedir(&dir); - - return res; -} - -void _fix_sd_attr(u32 type) -{ - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - char path[256]; - char label[16]; - - u32 total = 0; - if (sd_mount()) - { - switch (type) - { - case 0: - strcpy(path, "/"); - strcpy(label, "SD Card"); - break; - case 1: - default: - strcpy(path, "/Nintendo"); - strcpy(label, "Nintendo folder"); - break; - } - - gfx_printf("Traversing all %s files!\nThis may take some time...\n\n", label); - _fix_attributes(path, &total, type, type); - gfx_printf("%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC); - sd_unmount(); - } - btn_wait(); -} - -void fix_sd_all_attr() { _fix_sd_attr(0); } -void fix_sd_nin_attr() { _fix_sd_attr(1); } - -/* void fix_fuel_gauge_configuration() -{ - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - int battVoltage, avgCurrent; - - max17050_get_property(MAX17050_VCELL, &battVoltage); - max17050_get_property(MAX17050_AvgCurrent, &avgCurrent); - - // Check if still charging. If not, check if battery is >= 95% (4.1V). - if (avgCurrent < 0 && battVoltage > 4100) - { - if ((avgCurrent / 1000) < -10) - EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!"); - else - { - gfx_printf("%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00); - gfx_printf("Additionally this will power off your console.\n%k", 0xFFCCCCCC); - - gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n"); - - u32 btn = btn_wait(); - if (btn & BTN_POWER) - { - max17050_fix_configuration(); - msleep(1000); - gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy); - u16 value = 0; - gfx_printf("%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC); - while (value < 46) - { - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("%2ds elapsed", value); - msleep(1000); - value++; - } - msleep(2000); - - power_off(); - } - return; - } - } - else - EPRINTF("You need a fully charged battery\nand connected to a wall adapter,\nto apply this fix!"); - - msleep(500); - btn_wait(); -} */ - -/*void reset_pmic_fuel_gauge_charger_config() -{ - int avgCurrent; - - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - - gfx_printf("%k\nThis will wipe your battery stats completely!\n" - "%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k" - "\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC); - - gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n"); - u32 btn = btn_wait(); - if (btn & BTN_POWER) - { - gfx_clear_partial_grey(0x1B, 0, 1256); - gfx_con_setpos(0, 0); - gfx_printf("%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC); - gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy); - - u8 value = 30; - while (value > 0) - { - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - gfx_printf("%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC); - msleep(1000); - value--; - } - gfx_con_setpos(gfx_con.savedx, gfx_con.savedy); - - //Check if still connected. - max17050_get_property(MAX17050_AvgCurrent, &avgCurrent); - if ((avgCurrent / 1000) < -10) - EPRINTF("You need to be connected to a wall adapter\nor PC to apply this fix!"); - else - { - // Apply fix. - bq24193_fake_battery_removal(); - gfx_printf("Done! \n" - "%k1. Remove the USB cable\n" - "2. Press POWER for 15s.\n" - "3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC); - } - msleep(500); - btn_wait(); - } -}*/ - #pragma GCC pop_options diff --git a/bootloader/frontend/fe_tools.h b/bootloader/frontend/fe_tools.h index 5311cbd..e9f2bfb 100644 --- a/bootloader/frontend/fe_tools.h +++ b/bootloader/frontend/fe_tools.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,10 +18,7 @@ #ifndef _FE_TOOLS_H_ #define _FE_TOOLS_H_ -void dump_packages12(); -void fix_sd_all_attr(); -void fix_sd_nin_attr(); -void fix_battery_desync(); void menu_autorcm(); +bool tools_autorcm_enabled(); #endif diff --git a/bootloader/gfx/di.c b/bootloader/gfx/di.c deleted file mode 100644 index 200d412..0000000 --- a/bootloader/gfx/di.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "di.h" -#include "../gfx/gfx.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../soc/clock.h" -#include "../soc/gpio.h" -#include "../soc/i2c.h" -#include "../soc/pinmux.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -#include "di.inl" - -static u32 _display_ver = 0; - -static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) -{ - u32 end = get_tmr_us() + timeout; - while (get_tmr_us() < end && DSI(off) & mask) - ; - usleep(5); -} - -void display_init() -{ - // Power on. - max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); - - // Enable Display Interface specific clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL. - - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X. - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). - - // Disable deap power down. - PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; - PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; - - // Config LCD and Backlight pins. - PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; - - // Set Backlight +-5V pins mode and direction - gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); - - // Enable Backlight power. - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable. - usleep(10000); - - // Configure Backlight pins (PWM, EN, RST). - gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. - - // Power up supply regulator for display interface. - MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0; - - // Set DISP1 clock source and parrent clock. - exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4); - - // Setup display communication interfaces. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94); - exec_cfg((u32 *)DSI_BASE, _display_config_3, 61); - usleep(10000); - - // Enable Backlight Reset. - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); - usleep(60000); - - // Setups DSI packet configuration and request display id. - DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; - DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; - _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); - - usleep(5000); - - _display_ver = DSI(_DSIREG(DSI_RD_DATA)); - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_4, 43); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(180000); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(20000); - - // Configure PLLD for DISP1. - exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3); - - // Finalize DSI configuration. - exec_cfg((u32 *)DSI_BASE, _display_config_5, 21); - DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; - exec_cfg((u32 *)DSI_BASE, _display_config_7, 10); - usleep(10000); - - // Calibrate display communication pads. - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6); - exec_cfg((u32 *)DSI_BASE, _display_config_9, 4); - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16); - usleep(10000); - - // Enable video display controller. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113); -} - -void display_backlight_pwm_init() -{ - clock_enable_pwm(); - - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. - - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source. - gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. -} - -void display_backlight(bool enable) -{ - gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); // Backlight PWM GPIO. -} - -void display_backlight_brightness(u32 brightness, u32 step_delay) -{ - u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF; - if (brightness == old_value) - return; - - if (brightness > 255) - brightness = 255; - - if (old_value < brightness) - { - for (u32 i = old_value; i < brightness + 1; i++) - { - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. - usleep(step_delay); - } - } - else - { - for (u32 i = old_value; i > brightness; i--) - { - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. - usleep(step_delay); - } - } - if (!brightness) - PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; -} - -void display_end() -{ - display_backlight_brightness(0, 1000); - - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1; - DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF - - DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. - - // De-initialize video controller. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17); - exec_cfg((u32 *)DSI_BASE, _display_config_13, 16); - usleep(10000); - - // De-initialize display panel. - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_14, 22); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(50000); - - // Disable display and backlight pins. - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. - usleep(10000); - - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. - usleep(10000); - - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. - usleep(10000); - - // Disable Display Interface specific clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X. - - // Power down pads. - DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); - DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; - - // Switch to automatic function mode. - gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. - - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1; -} - -void display_color_screen(u32 color) -{ - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8); - - // Configure display to show single color. - DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; - DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; - usleep(35000); - - display_backlight(true); -} - -u32 *display_init_framebuffer() -{ - // Sanitize framebuffer area. - memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000); - - // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); - usleep(35000); - - return (u32 *)IPL_FB_ADDRESS; -} - diff --git a/bootloader/gfx/di.h b/bootloader/gfx/di.h deleted file mode 100644 index ee796a7..0000000 --- a/bootloader/gfx/di.h +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 _DI_H_ -#define _DI_H_ - -#include "../../common/memory_map.h" -#include "../utils/types.h" - -/*! Display registers. */ -#define _DIREG(reg) ((reg) * 4) - -#define DC_CMD_GENERAL_INCR_SYNCPT 0x00 - -#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 -#define SYNCPT_CNTRL_NO_STALL (1 << 8) -#define SYNCPT_CNTRL_SOFT_RESET (1 << 0) - -#define DC_CMD_CONT_SYNCPT_VSYNC 0x28 -#define SYNCPT_VSYNC_ENABLE (1 << 8) - -#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 - -#define DC_CMD_DISPLAY_COMMAND 0x32 -#define DISP_CTRL_MODE_STOP (0 << 5) -#define DISP_CTRL_MODE_C_DISPLAY (1 << 5) -#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) -#define DISP_CTRL_MODE_MASK (3 << 5) - -#define DC_CMD_DISPLAY_POWER_CONTROL 0x36 -#define PW0_ENABLE (1 << 0) -#define PW1_ENABLE (1 << 2) -#define PW2_ENABLE (1 << 4) -#define PW3_ENABLE (1 << 6) -#define PW4_ENABLE (1 << 8) -#define PM0_ENABLE (1 << 16) -#define PM1_ENABLE (1 << 18) - -#define DC_CMD_INT_MASK 0x38 -#define DC_CMD_INT_ENABLE 0x39 - -#define DC_CMD_STATE_ACCESS 0x40 -#define READ_MUX (1 << 0) -#define WRITE_MUX (1 << 2) - -#define DC_CMD_STATE_CONTROL 0x41 -#define GENERAL_ACT_REQ (1 << 0) -#define WIN_A_ACT_REQ (1 << 1) -#define WIN_B_ACT_REQ (1 << 2) -#define WIN_C_ACT_REQ (1 << 3) -#define CURSOR_ACT_REQ (1 << 7) -#define GENERAL_UPDATE (1 << 8) -#define WIN_A_UPDATE (1 << 9) -#define WIN_B_UPDATE (1 << 10) -#define WIN_C_UPDATE (1 << 11) -#define CURSOR_UPDATE (1 << 15) -#define NC_HOST_TRIG (1 << 24) - -#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 -#define WINDOW_A_SELECT (1 << 4) -#define WINDOW_B_SELECT (1 << 5) -#define WINDOW_C_SELECT (1 << 6) - -#define DC_CMD_REG_ACT_CONTROL 0x043 - -#define DC_COM_CRC_CONTROL 0x300 -#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) -#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) - -#define DC_COM_DSC_TOP_CTL 0x33E - -#define DC_DISP_DISP_WIN_OPTIONS 0x402 -#define HDMI_ENABLE (1 << 30) -#define DSI_ENABLE (1 << 29) -#define SOR1_TIMING_CYA (1 << 27) -#define SOR1_ENABLE (1 << 26) -#define SOR_ENABLE (1 << 25) -#define CURSOR_ENABLE (1 << 16) - -#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 -#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 -#define DC_DISP_DISP_TIMING_OPTIONS 0x405 -#define DC_DISP_REF_TO_SYNC 0x406 -#define DC_DISP_SYNC_WIDTH 0x407 -#define DC_DISP_BACK_PORCH 0x408 -#define DC_DISP_ACTIVE 0x409 -#define DC_DISP_FRONT_PORCH 0x40A - -#define DC_DISP_DISP_CLOCK_CONTROL 0x42E -#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) -#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) -#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) -#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) -#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) -#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) -#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) -#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) -#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) -#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) -#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) -#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) -#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) -#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) - -#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F -#define DISP_DATA_FORMAT_DF1P1C (0 << 0) -#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) -#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) -#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) -#define DISP_DATA_FORMAT_DF2S (4 << 0) -#define DISP_DATA_FORMAT_DF3S (5 << 0) -#define DISP_DATA_FORMAT_DFSPI (6 << 0) -#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) -#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) -#define DISP_ALIGNMENT_MSB (0 << 8) -#define DISP_ALIGNMENT_LSB (1 << 8) -#define DISP_ORDER_RED_BLUE (0 << 9) -#define DISP_ORDER_BLUE_RED (1 << 9) - -#define DC_DISP_DISP_COLOR_CONTROL 0x430 -#define DITHER_CONTROL_MASK (3 << 8) -#define DITHER_CONTROL_DISABLE (0 << 8) -#define DITHER_CONTROL_ORDERED (2 << 8) -#define DITHER_CONTROL_ERRDIFF (3 << 8) -#define BASE_COLOR_SIZE_MASK (0xf << 0) -#define BASE_COLOR_SIZE_666 (0 << 0) -#define BASE_COLOR_SIZE_111 (1 << 0) -#define BASE_COLOR_SIZE_222 (2 << 0) -#define BASE_COLOR_SIZE_333 (3 << 0) -#define BASE_COLOR_SIZE_444 (4 << 0) -#define BASE_COLOR_SIZE_555 (5 << 0) -#define BASE_COLOR_SIZE_565 (6 << 0) -#define BASE_COLOR_SIZE_332 (7 << 0) -#define BASE_COLOR_SIZE_888 (8 << 0) - -#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 -#define SC1_H_QUALIFIER_NONE (1 << 16) -#define SC0_H_QUALIFIER_NONE (1 << 0) - -#define DC_DISP_DATA_ENABLE_OPTIONS 0x432 -#define DE_SELECT_ACTIVE_BLANK (0 << 0) -#define DE_SELECT_ACTIVE (1 << 0) -#define DE_SELECT_ACTIVE_IS (2 << 0) -#define DE_CONTROL_ONECLK (0 << 2) -#define DE_CONTROL_NORMAL (1 << 2) -#define DE_CONTROL_EARLY_EXT (2 << 2) -#define DE_CONTROL_EARLY (3 << 2) -#define DE_CONTROL_ACTIVE_BLANK (4 << 2) - -#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 -#define DC_DISP_SD_BL_PARAMETERS 0x4D7 -#define DC_DISP_SD_BL_CONTROL 0x4DC -#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 - -#define DC_WIN_CSC_YOF 0x611 -#define DC_WIN_CSC_KYRGB 0x612 -#define DC_WIN_CSC_KUR 0x613 -#define DC_WIN_CSC_KVR 0x614 -#define DC_WIN_CSC_KUG 0x615 -#define DC_WIN_CSC_KVG 0x616 -#define DC_WIN_CSC_KUB 0x617 -#define DC_WIN_CSC_KVB 0x618 -#define DC_WIN_AD_WIN_OPTIONS 0xB80 -#define DC_WIN_BD_WIN_OPTIONS 0xD80 -#define DC_WIN_CD_WIN_OPTIONS 0xF80 - -// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). -#define DC_WIN_WIN_OPTIONS 0x700 -#define H_DIRECTION (1 << 0) -#define V_DIRECTION (1 << 2) -#define SCAN_COLUMN (1 << 4) -#define COLOR_EXPAND (1 << 6) -#define CSC_ENABLE (1 << 18) -#define WIN_ENABLE (1 << 30) - -#define DC_WIN_COLOR_DEPTH 0x703 -#define WIN_COLOR_DEPTH_P1 0x0 -#define WIN_COLOR_DEPTH_P2 0x1 -#define WIN_COLOR_DEPTH_P4 0x2 -#define WIN_COLOR_DEPTH_P8 0x3 -#define WIN_COLOR_DEPTH_B4G4R4A4 0x4 -#define WIN_COLOR_DEPTH_B5G5R5A 0x5 -#define WIN_COLOR_DEPTH_B5G6R5 0x6 -#define WIN_COLOR_DEPTH_AB5G5R5 0x7 -#define WIN_COLOR_DEPTH_B8G8R8A8 0xC -#define WIN_COLOR_DEPTH_R8G8B8A8 0xD -#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE -#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF -#define WIN_COLOR_DEPTH_YCbCr422 0x10 -#define WIN_COLOR_DEPTH_YUV422 0x11 -#define WIN_COLOR_DEPTH_YCbCr420P 0x12 -#define WIN_COLOR_DEPTH_YUV420P 0x13 -#define WIN_COLOR_DEPTH_YCbCr422P 0x14 -#define WIN_COLOR_DEPTH_YUV422P 0x15 -#define WIN_COLOR_DEPTH_YCbCr422R 0x16 -#define WIN_COLOR_DEPTH_YUV422R 0x17 -#define WIN_COLOR_DEPTH_YCbCr422RA 0x18 -#define WIN_COLOR_DEPTH_YUV422RA 0x19 - -#define DC_WIN_BUFFER_CONTROL 0x702 -#define DC_WIN_POSITION 0x704 - -#define DC_WIN_SIZE 0x705 -#define H_SIZE(x) (((x) & 0x1fff) << 0) -#define V_SIZE(x) (((x) & 0x1fff) << 16) - -#define DC_WIN_PRESCALED_SIZE 0x706 -#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) -#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) - -#define DC_WIN_H_INITIAL_DDA 0x707 -#define DC_WIN_V_INITIAL_DDA 0x708 - -#define DC_WIN_DDA_INC 0x709 -#define H_DDA_INC(x) (((x) & 0xffff) << 0) -#define V_DDA_INC(x) (((x) & 0xffff) << 16) - -#define DC_WIN_LINE_STRIDE 0x70A -#define LINE_STRIDE(x) (x) -#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) -#define DC_WIN_DV_CONTROL 0x70E - -/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ -#define DC_WINBUF_START_ADDR 0x800 -#define DC_WINBUF_ADDR_H_OFFSET 0x806 -#define DC_WINBUF_ADDR_V_OFFSET 0x808 -#define DC_WINBUF_SURFACE_KIND 0x80B -#define PITCH (0 << 0) -#define TILED (1 << 0) -#define BLOCK (2 << 0) -#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) - -/*! Display serial interface registers. */ -#define _DSIREG(reg) ((reg) * 4) - -#define DSI_RD_DATA 0x9 -#define DSI_WR_DATA 0xA - -#define DSI_POWER_CONTROL 0xB -#define DSI_POWER_CONTROL_ENABLE 1 - -#define DSI_INT_ENABLE 0xC -#define DSI_INT_STATUS 0xD -#define DSI_INT_MASK 0xE - -#define DSI_HOST_CONTROL 0xF -#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) -#define DSI_HOST_CONTROL_CRC_RESET (1 << 20) -#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) -#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) -#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) -#define DSI_HOST_CONTROL_RAW (1 << 6) -#define DSI_HOST_CONTROL_HS (1 << 5) -#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) -#define DSI_HOST_CONTROL_IMM_BTA (1 << 3) -#define DSI_HOST_CONTROL_PKT_BTA (1 << 2) -#define DSI_HOST_CONTROL_CS (1 << 1) -#define DSI_HOST_CONTROL_ECC (1 << 0) - -#define DSI_CONTROL 0x10 -#define DSI_CONTROL_HS_CLK_CTRL (1 << 20) -#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) -#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) -#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) -#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) -#define DSI_CONTROL_DCS_ENABLE (1 << 3) -#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) -#define DSI_CONTROL_VIDEO_ENABLE (1 << 1) -#define DSI_CONTROL_HOST_ENABLE (1 << 0) - -#define DSI_SOL_DELAY 0x11 -#define DSI_MAX_THRESHOLD 0x12 - -#define DSI_TRIGGER 0x13 -#define DSI_TRIGGER_HOST (1 << 1) -#define DSI_TRIGGER_VIDEO (1 << 0) - -#define DSI_TX_CRC 0x14 -#define DSI_STATUS 0x15 -#define DSI_INIT_SEQ_CONTROL 0x1A -#define DSI_INIT_SEQ_DATA_0 0x1B -#define DSI_INIT_SEQ_DATA_1 0x1C -#define DSI_INIT_SEQ_DATA_2 0x1D -#define DSI_INIT_SEQ_DATA_3 0x1E -#define DSI_PKT_SEQ_0_LO 0x23 -#define DSI_PKT_SEQ_0_HI 0x24 -#define DSI_PKT_SEQ_1_LO 0x25 -#define DSI_PKT_SEQ_1_HI 0x26 -#define DSI_PKT_SEQ_2_LO 0x27 -#define DSI_PKT_SEQ_2_HI 0x28 -#define DSI_PKT_SEQ_3_LO 0x29 -#define DSI_PKT_SEQ_3_HI 0x2A -#define DSI_PKT_SEQ_4_LO 0x2B -#define DSI_PKT_SEQ_4_HI 0x2C -#define DSI_PKT_SEQ_5_LO 0x2D -#define DSI_PKT_SEQ_5_HI 0x2E -#define DSI_DCS_CMDS 0x33 -#define DSI_PKT_LEN_0_1 0x34 -#define DSI_PKT_LEN_2_3 0x35 -#define DSI_PKT_LEN_4_5 0x36 -#define DSI_PKT_LEN_6_7 0x37 -#define DSI_PHY_TIMING_0 0x3C -#define DSI_PHY_TIMING_1 0x3D -#define DSI_PHY_TIMING_2 0x3E -#define DSI_BTA_TIMING 0x3F - -#define DSI_TIMEOUT_0 0x44 -#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) -#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) - -#define DSI_TIMEOUT_1 0x45 -#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) -#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) - -#define DSI_TO_TALLY 0x46 - -#define DSI_PAD_CONTROL_0 0x4B -#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) -#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) -#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) -#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) - -#define DSI_PAD_CONTROL_CD 0x4C -#define DSI_VIDEO_MODE_CONTROL 0x4E - -#define DSI_PAD_CONTROL_1 0x4F -#define DSI_PAD_CONTROL_2 0x50 - -#define DSI_PAD_CONTROL_3 0x51 -#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) -#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) -#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) -#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) - -#define DSI_PAD_CONTROL_4 0x52 -#define DSI_INIT_SEQ_DATA_15 0x5F - -#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60 - -void display_init(); -void display_backlight_pwm_init(); -void display_end(); - -/*! Show one single color on the display. */ -void display_color_screen(u32 color); - -/*! Switches screen backlight ON/OFF. */ -void display_backlight(bool enable); -void display_backlight_brightness(u32 brightness, u32 step_delay); - -/*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */ -u32 *display_init_framebuffer(); - -#endif diff --git a/bootloader/gfx/di.inl b/bootloader/gfx/di.inl deleted file mode 100644 index dd82899..0000000 --- a/bootloader/gfx/di.inl +++ /dev/null @@ -1,564 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer -* -* 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 . -*/ - -//Clock config. -static const cfg_op_t _display_config_1[4] = { - {0x4E, 0x40000000}, //CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 - {0x34, 0x4830A001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2D0AAA} //CLK_RST_CONTROLLER_PLLD_MISC -}; - -//Display A config. -static const cfg_op_t _display_config_2[94] = { - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_REG_ACT_CONTROL, 0x54}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_DISP_DC_MCCIF_FIFOCTRL, 0}, - {DC_DISP_DISP_MEM_HIGH_PRIORITY, 0}, - {DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0}, - {DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE}, - {DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL}, - {DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, - {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, - {DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, - {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, - {0x4E4, 0}, - {DC_COM_CRC_CONTROL, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} -}; - -//DSI Init config. -static const cfg_op_t _display_config_3[61] = { - {DSI_WR_DATA, 0}, - {DSI_INT_ENABLE, 0}, - {DSI_INT_STATUS, 0}, - {DSI_INT_MASK, 0}, - {DSI_INIT_SEQ_DATA_0, 0}, - {DSI_INIT_SEQ_DATA_1, 0}, - {DSI_INIT_SEQ_DATA_2, 0}, - {DSI_INIT_SEQ_DATA_3, 0}, - {DSI_INIT_SEQ_DATA_15, 0}, - {DSI_DCS_CMDS, 0}, - {DSI_PKT_SEQ_0_LO, 0}, - {DSI_PKT_SEQ_1_LO, 0}, - {DSI_PKT_SEQ_2_LO, 0}, - {DSI_PKT_SEQ_3_LO, 0}, - {DSI_PKT_SEQ_4_LO, 0}, - {DSI_PKT_SEQ_5_LO, 0}, - {DSI_PKT_SEQ_0_HI, 0}, - {DSI_PKT_SEQ_1_HI, 0}, - {DSI_PKT_SEQ_2_HI, 0}, - {DSI_PKT_SEQ_3_HI, 0}, - {DSI_PKT_SEQ_4_HI, 0}, - {DSI_PKT_SEQ_5_HI, 0}, - {DSI_CONTROL, 0}, - {DSI_PAD_CONTROL_CD, 0}, - {DSI_SOL_DELAY, 0x18}, - {DSI_MAX_THRESHOLD, 0x1E0}, - {DSI_TRIGGER, 0}, - {DSI_INIT_SEQ_CONTROL, 0}, - {DSI_PKT_LEN_0_1, 0}, - {DSI_PKT_LEN_2_3, 0}, - {DSI_PKT_LEN_4_5, 0}, - {DSI_PKT_LEN_6_7, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30109}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_POWER_CONTROL, 0}, - {DSI_POWER_CONTROL, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30118}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_MAX_THRESHOLD, 0x40}, - {DSI_TRIGGER, 0}, - {DSI_TX_CRC, 0}, - {DSI_INIT_SEQ_CONTROL, 0} -}; - -//DSI config (if ver == 0x10). -static const cfg_op_t _display_config_4[43] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1939}, - {DSI_WR_DATA, 0xAAAAAAD8}, - {DSI_WR_DATA, 0xAAAAAAEB}, - {DSI_WR_DATA, 0xAAEBAAAA}, - {DSI_WR_DATA, 0xAAAAAAAA}, - {DSI_WR_DATA, 0xAAAAAAEB}, - {DSI_WR_DATA, 0xAAEBAAAA}, - {DSI_WR_DATA, 0xAA}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1BD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2739}, - {DSI_WR_DATA, 0xFFFFFFD8}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFF}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2BD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xF39}, - {DSI_WR_DATA, 0xFFFFFFD8}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFF}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x6D915}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST} -}; - -//DSI config. -static const cfg_op_t _display_config_5[21] = { - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30172}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)}, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_PKT_SEQ_0_LO, 0x40000208}, - {DSI_PKT_SEQ_2_LO, 0x40000308}, - {DSI_PKT_SEQ_4_LO, 0x40000308}, - {DSI_PKT_SEQ_1_LO, 0x40000308}, - {DSI_PKT_SEQ_3_LO, 0x3F3B2B08}, - {DSI_PKT_SEQ_3_HI, 0x2CC}, - {DSI_PKT_SEQ_5_LO, 0x3F3B2B08}, - {DSI_PKT_SEQ_5_HI, 0x2CC}, - {DSI_PKT_LEN_0_1, 0xCE0000}, - {DSI_PKT_LEN_2_3, 0x87001A2}, - {DSI_PKT_LEN_4_5, 0x190}, - {DSI_PKT_LEN_6_7, 0x190}, - {DSI_HOST_CONTROL, 0}, -}; - -//Clock config. -static const cfg_op_t _display_config_6[3] = { - {0x34, 0x4810C001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2DFC00} //CLK_RST_CONTROLLER_PLLD_MISC -}; - -//DSI config. -static const cfg_op_t _display_config_7[10] = { - {DSI_TRIGGER, 0}, - {DSI_CONTROL, 0}, - {DSI_SOL_DELAY, 6}, - {DSI_MAX_THRESHOLD, 0x1E0}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL| DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC} -}; - -//MIPI CAL config. -static const cfg_op_t _display_config_8[6] = { - {0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS - {0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0 - {0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1 -}; - -//DSI config. -static const cfg_op_t _display_config_9[4] = { - {DSI_PAD_CONTROL_1, 0}, - {DSI_PAD_CONTROL_2, 0}, - {DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, - {DSI_PAD_CONTROL_4, 0} -}; - -//MIPI CAL config. -static const cfg_op_t _display_config_10[16] = { - {0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG - {0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG - {0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 - {0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 - {0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG - {0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG - {0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG - {0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG - {0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG - {0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG - {0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG - {0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG - {0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 - {0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 - {0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 - {0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG -}; - -//Display A config. -static const cfg_op_t _display_config_11[113] = { - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, - {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, - {DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, - {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, - {0x4E4, 0}, - {DC_COM_CRC_CONTROL, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_STATE_ACCESS, 0}, - /* Set Display timings */ - {DC_DISP_DISP_TIMING_OPTIONS, 0}, - {DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1. - {DC_DISP_SYNC_WIDTH, 0x10048}, - {DC_DISP_BACK_PORCH, 0x90048}, - {DC_DISP_ACTIVE, 0x50002D0}, - {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. - /* End of Display timings */ - {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, - {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, - {DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, - {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, - {DC_DISP_DISP_CLOCK_CONTROL, 0}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX}, - {DC_DISP_FRONT_PORCH, 0xA0088}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, - {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0} -}; - -////Display A config. -static const cfg_op_t _display_config_12[17] = { - {DC_DISP_FRONT_PORCH, 0xA0088}, - {DC_CMD_INT_MASK, 0}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_INT_ENABLE, 0}, - {DC_CMD_CONT_SYNCPT_VSYNC, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_DISPLAY_POWER_CONTROL, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, -}; - -//DSI config. -static const cfg_op_t _display_config_13[16] = { - {DSI_POWER_CONTROL, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30118}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) }, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_MAX_THRESHOLD, 0x40}, - {DSI_TRIGGER, 0}, - {DSI_TX_CRC, 0}, - {DSI_INIT_SEQ_CONTROL, 0} -}; - -//DSI config (if ver == 0x10). -static const cfg_op_t _display_config_14[22] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2139}, - {DSI_WR_DATA, 0x191919D5}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xB39}, - {DSI_WR_DATA, 0x4F0F41B1}, - {DSI_WR_DATA, 0xF179A433}, - {DSI_WR_DATA, 0x2D81}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST} -}; - -//Display A config. -static const cfg_op_t cfg_display_one_color[8] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} //DISPLAY_CTRL_MODE: continuous display. -}; - -//Display A config. -static const cfg_op_t cfg_display_framebuffer[32] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 - {DC_WIN_WIN_OPTIONS, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_WIN_POSITION, 0}, //(0,0) - {DC_WIN_H_INITIAL_DDA, 0}, - {DC_WIN_V_INITIAL_DDA, 0}, - {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. - {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, - {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. - {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. - {DC_WIN_BUFFER_CONTROL, 0}, - {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. - {DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address. - {DC_WINBUF_ADDR_H_OFFSET, 0}, - {DC_WINBUF_ADDR_V_OFFSET, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD. - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. -}; diff --git a/bootloader/gfx/gfx.c b/bootloader/gfx/gfx.c index 5fa58c0..37d7c37 100644 --- a/bootloader/gfx/gfx.c +++ b/bootloader/gfx/gfx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +19,12 @@ #include #include "gfx.h" +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + +static bool gfx_con_init_done = false; + static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) @@ -117,28 +123,28 @@ static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) }; -void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) -{ - gfx_ctxt.fb = fb; - gfx_ctxt.width = width; - gfx_ctxt.height = height; - gfx_ctxt.stride = stride; -} - void gfx_clear_grey(u8 color) { memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); } +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +{ + memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); +} + void gfx_clear_color(u32 color) { for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) gfx_ctxt.fb[i] = color; } -void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) { - memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; } void gfx_con_init() @@ -149,10 +155,12 @@ void gfx_con_init() gfx_con.y = 0; gfx_con.savedx = 0; gfx_con.savedy = 0; - gfx_con.fgcol = 0xFFCCCCCC; + gfx_con.fgcol = TXT_CLR_DEFAULT; gfx_con.fillbg = 1; - gfx_con.bgcol = 0xFF1B1B1B; + gfx_con.bgcol = TXT_CLR_BG; gfx_con.mute = 0; + + gfx_con_init_done = true; } void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) @@ -219,7 +227,7 @@ void gfx_putc(char c) else if (c == '\n') { gfx_con.x = 0; - gfx_con.y +=16; + gfx_con.y += 16; if (gfx_con.y > gfx_ctxt.height - 16) gfx_con.y = 0; } @@ -257,9 +265,9 @@ void gfx_putc(char c) } } -void gfx_puts(char *s) +void gfx_puts(const char *s) { - if (!s || gfx_con.mute) + if (!s || !gfx_con_init_done || gfx_con.mute) return; for (; *s; s++) @@ -268,14 +276,24 @@ void gfx_puts(char *s) static void _gfx_putn(u32 v, int base, char fill, int fcnt) { - char buf[65]; - static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; - char *p; - int c = fcnt; + static const char digits[] = "0123456789ABCDEF"; - if (base > 36) + char *p; + char buf[65]; + int c = fcnt; + bool negative = false; + + if (base != 10 && base != 16) return; + // Account for negative numbers. + if (base == 10 && v & 0x80000000) + { + negative = true; + v = (int)v * -1; + c--; + } + p = buf + 64; *p = 0; do @@ -285,9 +303,12 @@ static void _gfx_putn(u32 v, int base, char fill, int fcnt) v /= base; } while (v); + if (negative) + *--p = '-'; + if (fill != 0) { - while (c > 0) + while (c > 0 && p > buf) { *--p = fill; c--; @@ -315,16 +336,16 @@ void gfx_put_big_sep() void gfx_printf(const char *fmt, ...) { - if (gfx_con.mute) + if (!gfx_con_init_done || gfx_con.mute) return; va_list ap; int fill, fcnt; va_start(ap, fmt); - while(*fmt) + while (*fmt) { - if(*fmt == '%') + if (*fmt == '%') { fmt++; fill = 0; @@ -389,24 +410,37 @@ void gfx_printf(const char *fmt, ...) va_end(ap); } -void gfx_hexdump(u32 base, const u8 *buf, u32 len) +static void _gfx_cputs(u32 color, const char *s) { - if (gfx_con.mute) + gfx_con.fgcol = color; + gfx_puts(s); + gfx_putc('\n'); + gfx_con.fgcol = TXT_CLR_DEFAULT; +} + +void gfx_wputs(const char *s) { _gfx_cputs(TXT_CLR_WARNING, s); } +void gfx_eputs(const char *s) { _gfx_cputs(TXT_CLR_ERROR, s); } + +void gfx_hexdump(u32 base, const void *buf, u32 len) +{ + if (!gfx_con_init_done || gfx_con.mute) return; + u8 *buff = (u8 *)buf; + u8 prevFontSize = gfx_con.fntsz; gfx_con.fntsz = 8; - for(u32 i = 0; i < len; i++) + for (u32 i = 0; i < len; i++) { - if(i % 0x10 == 0) + if (i % 0x10 == 0) { - if(i != 0) + if (i != 0) { gfx_puts("| "); - for(u32 j = 0; j < 0x10; j++) + for (u32 j = 0; j < 0x10; j++) { - u8 c = buf[i - 0x10 + j]; - if(c >= 32 && c <= 126) + u8 c = buff[i - 0x10 + j]; + if (c >= 32 && c <= 126) gfx_putc(c); else gfx_putc('.'); @@ -415,7 +449,7 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) } gfx_printf("%08x: ", base + i); } - gfx_printf("%02x ", buf[i]); + gfx_printf("%02x ", buff[i]); if (i == len - 1) { int ln = len % 0x10 != 0; @@ -427,10 +461,10 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_puts(" "); } gfx_puts("| "); - for(u32 j = 0; j < (ln ? k : k + 1); j++) + for (u32 j = 0; j < (ln ? k : k + 1); j++) { - u8 c = buf[i - k + j]; - if(c >= 32 && c <= 126) + u8 c = buff[i - k + j]; + if (c >= 32 && c <= 126) gfx_putc(c); else gfx_putc('.'); diff --git a/bootloader/gfx/gfx.h b/bootloader/gfx/gfx.h index 252d5ff..b2fa915 100644 --- a/bootloader/gfx/gfx.h +++ b/bootloader/gfx/gfx.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it @@ -19,12 +19,53 @@ #ifndef _GFX_H_ #define _GFX_H_ -#include "../../common/common_gfx.h" +#include -#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) -#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) -#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) -#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) +#define TXT_CLR_BG 0xFF1B1B1B // Dark Grey. +#define TXT_CLR_DEFAULT 0xFFCCCCCC // Light Grey. +#define TXT_CLR_WARNING 0xFFFFDD00 // Yellow. +#define TXT_CLR_ERROR 0xFFFF0000 // Red. +#define TXT_CLR_CYAN_L 0xFF00CCFF // Light Cyan. +#define TXT_CLR_TURQUOISE 0xFF00FFCC // Turquoise. +#define TXT_CLR_ORANGE 0xFFFFBA00 // Orange. +#define TXT_CLR_GREENISH 0xFF96FF00 // Toxic Green. +#define TXT_CLR_GREEN_D 0xFF008800 // Dark Green. +#define TXT_CLR_RED_D 0xFF880000 // Dark Red. +#define TXT_CLR_GREY_D 0xFF303030 // Darkest Grey. +#define TXT_CLR_GREY_DM 0xFF444444 // Darker Grey. +#define TXT_CLR_GREY_M 0xFF555555 // Dark Grey. +#define TXT_CLR_GREY 0xFF888888 // Grey. + +#define EPRINTF(text) gfx_eputs(text) +#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", TXT_CLR_ERROR, args, TXT_CLR_DEFAULT) +#define WPRINTF(text) gfx_wputs(text) +#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", TXT_CLR_WARNING, args, TXT_CLR_DEFAULT) + +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 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); void gfx_clear_grey(u8 color); @@ -35,9 +76,11 @@ void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol); void gfx_con_getpos(u32 *x, u32 *y); void gfx_con_setpos(u32 x, u32 y); void gfx_putc(char c); -void gfx_puts(char *s); -void gfx_printf(const char *fmt, ...); -void gfx_hexdump(u32 base, const u8 *buf, u32 len); +void gfx_puts(const char *s); +void gfx_wputs(const char *s); +void gfx_eputs(const char *s); +void gfx_printf(const char *fmt, ...) /* __attribute__((format(printf, 1, 2))) */; +void gfx_hexdump(u32 base, const void *buf, u32 len); void gfx_set_pixel(u32 x, u32 y, u32 color); void gfx_line(int x0, int y0, int x1, int y1, u32 color); @@ -48,8 +91,4 @@ void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_ void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -// Global gfx console and context. -gfx_ctxt_t gfx_ctxt; -gfx_con_t gfx_con; - #endif diff --git a/bootloader/gfx/logos.c b/bootloader/gfx/logos.c new file mode 100644 index 0000000..8b14e15 --- /dev/null +++ b/bootloader/gfx/logos.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2018-2022 CTCaer + * + * 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 +#include +#include "logos.h" + +// 68 x 192 @8bpp Grayscale RAW. +#define BOOTLOGO_WIDTH 68 +#define BOOTLOGO_HEIGHT 192 +#define BOOTLOGO_X ((720 - BOOTLOGO_WIDTH) / 2) +#define BOOTLOGO_Y ((1280 - BOOTLOGO_HEIGHT) / 2) +#define BOOTLOGO_SIZE 13056 +#define BOOTLOGO_BLZ_SIZE 3988 + +u8 bootlogo_blz[] = { + 0x0F, 0xF0, 0x80, 0x1B, 0x1B, 0x40, 0xF0, 0x1E, 0x1F, 0x48, 0x5A, 0x0F, 0xF0, 0x0F, 0xF0, 0xE4, + 0x17, 0xF0, 0x91, 0x13, 0x26, 0x28, 0x23, 0x1E, 0x0A, 0xA0, 0x0F, 0xF0, 0xC3, 0x22, 0xF0, 0xC3, + 0xA4, 0x1E, 0x29, 0x33, 0xDB, 0x2C, 0xEA, 0x53, 0x83, 0x0F, 0xF0, 0x38, 0xF0, 0xBC, 0x39, 0x21, + 0x22, 0xB0, 0x87, 0x20, 0x2F, 0x27, 0x3E, 0xDB, 0x35, 0x01, 0xA6, 0x69, 0xF2, 0x3C, 0xFD, 0x25, + 0x2D, 0x38, 0x77, 0x28, 0x15, 0x8A, 0x33, 0x45, 0xDB, 0x09, 0xEF, 0xBB, 0x44, 0xD0, 0xC0, 0x18, + 0xEF, 0x2E, 0x3B, 0xF5, 0x32, 0x25, 0x41, 0xC0, 0x83, 0x52, 0xE1, 0x07, 0xCD, 0x08, 0xF4, 0xF5, + 0x3B, 0x61, 0xB2, 0x95, 0xF1, 0x01, 0x10, 0xE7, 0xA3, 0x02, 0x95, 0x91, 0x3C, 0xFD, 0x41, 0x90, + 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x7F, 0x3D, 0x9B, 0xFA, 0x41, 0xF0, 0x41, 0xF0, 0x0F, + 0xF0, 0x26, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xFE, 0x4C, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x4D, 0xF5, + 0x95, 0x01, 0x9B, 0x02, 0xCD, 0x5D, 0x41, 0xF0, 0xFF, 0x41, 0xF0, 0x4D, 0xF5, 0x77, 0xC5, 0x18, + 0x93, 0xCD, 0x8D, 0x41, 0xF0, 0x41, 0xF0, 0xEB, 0x4D, 0xF5, 0x69, 0xFB, 0x6C, 0xF4, 0x41, 0xF0, + 0x4D, 0xF5, 0x65, 0x3F, 0x28, 0x01, 0x10, 0xBF, 0x03, 0x30, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x30, + 0x45, 0x57, 0x03, 0xE4, 0x03, 0x41, 0xB0, 0xCD, 0xFD, 0x5D, 0x02, 0xCD, 0x1D, 0xC9, 0x1C, 0x2C, + 0x38, 0x3F, 0x3F, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x41, 0x41, 0x41, 0x48, 0x0E, 0x56, 0x61, + 0xF5, 0x41, 0xED, 0xDF, 0xCD, 0xFD, 0x3D, 0xBB, 0x30, 0x2D, 0x6D, 0xB3, 0x6D, 0x4D, 0x15, 0x38, + 0x01, 0x10, 0xE1, 0xF6, 0xD0, 0x3C, 0x27, 0x41, 0xB0, 0xCD, 0xFD, 0xA4, 0xCD, 0x2D, 0xF0, 0x4E, + 0x6F, 0x6C, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x73, 0x73, 0x73, 0x74, 0x75, 0x07, 0x72, 0x68, + 0x31, 0x22, 0x41, 0xD0, 0xA4, 0xF2, 0xCD, 0x3D, 0xE6, 0x1E, 0xF0, 0x36, 0x3D, 0x02, 0x20, 0x03, + 0x30, 0x00, 0x00, 0x40, 0x40, 0x40, 0x1C, 0x3F, 0x3A, 0x31, 0x84, 0x89, 0x21, 0x41, 0xF0, 0xB8, + 0xCB, 0x20, 0x68, 0x23, 0x26, 0x28, 0x2A, 0x2C, 0x2F, 0x2F, 0x2E, 0x00, 0x2B, 0x28, 0x28, 0x01, + 0x10, 0x27, 0x27, 0x27, 0x27, 0x08, 0x26, 0x24, 0x21, 0x08, 0x85, 0x41, 0xF0, 0xCB, 0xF8, 0x21, + 0x28, 0x38, 0x2F, 0x35, 0x38, 0x39, 0x36, 0x31, 0x2B, 0x24, 0x00, 0x1F, 0x1D, 0x01, 0x10, 0x1C, + 0x1C, 0x1C, 0xC3, 0x50, 0x41, 0xF0, 0xC4, 0x39, 0xF8, 0x40, 0x20, 0x2D, 0x3A, 0x56, 0xA8, 0xBE, + 0xBE, 0x03, 0xBE, 0xA7, 0x63, 0x34, 0x42, 0x40, 0x41, 0xF0, 0xB1, 0xF7, 0xA8, 0x02, 0xF0, 0xE5, + 0x06, 0x77, 0xB3, 0x8A, 0x08, 0x25, 0x30, 0x41, 0xAA, 0x11, 0xED, 0xD3, 0xAC, 0xA1, 0xAD, 0xCA, + 0xF5, 0xB2, 0x00, 0x39, 0x37, 0x33, 0x41, 0xF0, 0x41, 0xF0, 0x50, 0x49, 0x6D, 0x71, 0x03, 0x1B, + 0x5E, 0x20, 0x2D, 0x41, 0xAB, 0xE4, 0x80, 0x4E, 0x48, 0x00, 0x46, 0x4A, 0x53, 0x77, 0xE4, 0xBD, + 0x35, 0x24, 0x00, 0x44, 0x94, 0x41, 0xF0, 0x4D, 0xF5, 0x09, 0x15, 0x26, 0x3A, 0x7C, 0xF5, 0x0F, + 0x7F, 0x45, 0x37, 0x30, 0x2F, 0x32, 0x3F, 0x51, 0x00, 0x78, 0xF5, 0x74, 0x2D, 0xAE, 0x32, 0x41, + 0xF0, 0x4D, 0xF5, 0x9D, 0x6A, 0xF0, 0x1F, 0x2D, 0x45, 0xC1, 0xC1, 0x47, 0x30, 0x23, 0x00, 0x1F, + 0x1F, 0x21, 0x2A, 0x3D, 0x54, 0xC1, 0xBE, 0x00, 0x35, 0x22, 0x01, 0x10, 0x41, 0xF0, 0xA5, 0xF2, + 0x3D, 0x44, 0x15, 0x0A, 0x20, 0x7C, 0x33, 0x4C, 0xED, 0x88, 0x39, 0x24, 0x84, 0x10, 0x1F, 0x40, + 0x2F, 0x49, 0x8D, 0xED, 0x3B, 0x44, 0x0D, 0x41, 0xF0, 0x41, 0xF0, 0xE0, 0x64, 0x02, 0x27, 0x0B, + 0xBB, 0xB3, 0xB5, 0x13, 0x21, 0x37, 0x4F, 0x13, 0xF5, 0x49, 0x30, 0xED, 0x21, 0x1D, 0x28, 0x40, + 0x55, 0x08, 0xF5, 0x3F, 0x15, 0x40, 0x41, 0xF0, 0x2D, 0xF3, 0xAF, 0x07, 0x2D, 0x41, 0x50, 0xBC, + 0x42, 0x2C, 0xB8, 0x32, 0x24, 0x3B, 0x52, 0xF5, 0x40, 0x04, 0xB1, 0xF7, 0x1B, 0x41, 0xF0, 0x41, + 0xF0, 0x41, 0x41, 0xD0, 0x41, 0xF0, 0x41, 0xF0, 0xED, 0x79, 0xF7, 0x41, 0xF0, 0x41, 0xF0, 0xD0, + 0xD9, 0x8A, 0x8A, 0x8A, 0x8A, 0x0F, 0x8A, 0x93, 0xAC, 0x09, 0x50, 0x29, 0xB7, 0xF9, 0xF3, 0x41, + 0xF0, 0x8C, 0x0D, 0xF8, 0x81, 0x1F, 0x0F, 0x81, 0xBB, 0x81, 0x41, 0x10, 0x50, 0xF5, 0x22, 0x45, + 0x30, 0x70, 0x33, 0x29, 0x3F, 0x54, 0xF5, 0x46, 0x04, 0x30, 0x72, 0x23, 0x20, 0x71, 0xE3, 0xA5, + 0xF2, 0x3D, 0x20, 0x77, 0x9B, 0x3A, 0xAD, 0x16, 0x52, 0xF5, 0x52, 0x09, 0x00, 0x07, 0x10, 0x3B, + 0x4E, 0x31, 0x61, 0xF5, 0x54, 0x41, 0x35, 0x35, 0x35, 0x35, 0x00, 0x34, 0x30, 0x29, 0x21, 0x0D, + 0xF1, 0x41, 0xF0, 0x11, 0x4E, 0x36, 0x70, 0x50, 0xF5, 0xAF, 0x09, 0x00, 0x07, 0x10, 0xAA, 0xAF, + 0xB4, 0x18, 0xF5, 0xB1, 0xAC, 0xA9, 0xA9, 0xA9, 0xA9, 0xA8, 0x00, 0xA5, 0xA2, 0x99, 0xCE, 0x1D, + 0xF2, 0xA1, 0x22, 0x11, 0x3E, 0x30, 0x46, 0x3C, 0xC1, 0xC2, 0x09, 0x10, 0x06, 0x10, 0xC2, 0xC4, + 0xC5, 0xC3, 0x0C, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0xBD, 0xBA, 0x00, 0x2A, 0x41, 0xB0, 0x6D, + 0xF7, 0x41, 0x00, 0x8A, 0xA4, 0x3D, 0x8A, 0x0E, 0xA4, 0x95, 0x01, 0x27, 0x35, 0x43, 0x49, 0x09, + 0x00, 0x07, 0x10, 0xC2, 0x49, 0x4B, 0x4E, 0x4F, 0x4C, 0x49, 0x48, 0x48, 0x00, 0x48, 0x48, 0x46, + 0x40, 0x34, 0x51, 0x91, 0x41, 0xF0, 0x01, 0x10, 0xE0, 0xC7, 0x00, 0x9B, 0xBB, 0xB3, 0x4A, 0xC9, + 0x10, 0x25, 0x2C, 0x21, 0x01, 0x10, 0x06, 0x30, 0x31, 0x31, 0x31, 0x00, 0x00, 0x30, 0x30, 0x23, + 0x30, 0x2C, 0x27, 0xC9, 0x00, 0x41, 0xF0, 0xA1, 0xF2, 0x42, 0x40, 0x06, 0x60, 0xF8, 0x03, 0x30, + 0x00, 0x00, 0x1F, 0xDD, 0xA6, 0x41, 0xF0, 0xBF, 0xF3, 0x02, 0x20, 0xCD, 0xFD, 0xFB, 0x95, 0xF1, + 0x17, 0xD6, 0x62, 0x6D, 0x62, 0x2D, 0x90, 0x48, 0x29, 0x43, 0x2E, 0x03, 0x30, 0x03, 0x30, 0x00, + 0x00, 0x2F, 0x2F, 0x2F, 0x2B, 0x0E, 0x7D, 0xF8, 0x95, 0xF1, 0xB3, 0x9B, 0xAC, 0x95, 0x21, 0x1D, + 0x23, 0x23, 0x2F, 0x60, 0x66, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x68, 0x68, 0x38, 0x68, 0x67, + 0x63, 0x5B, 0x27, 0x85, 0x10, 0x41, 0xF0, 0x0D, 0xF1, 0xE0, 0x39, 0x03, 0x28, 0x39, 0x07, 0x70, + 0x03, 0x30, 0x00, 0x00, 0xF5, 0xF5, 0x39, 0xF5, 0x2C, 0x20, 0x41, 0x90, 0x41, 0xF0, 0x27, 0x1B, + 0x25, 0x2B, 0xF5, 0x17, 0xF8, 0x34, 0x44, 0x4F, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x52, 0x52, + 0x38, 0x52, 0x51, 0x49, 0x3A, 0x29, 0xE0, 0x12, 0x41, 0xF0, 0x2D, 0xF3, 0xE0, 0x42, 0x00, 0x20, + 0x28, 0x31, 0x38, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE1, 0x39, 0x39, 0x39, 0x34, 0x2C, 0x23, + 0xA9, 0xBF, 0xE9, 0xF2, 0xC0, 0xAC, 0x32, 0x4A, 0xBB, 0x3B, 0x27, 0x20, 0x21, 0xAC, 0xCF, 0x22, + 0x49, 0x22, 0xA9, 0xFF, 0xB5, 0xF3, 0xEA, 0x2F, 0x57, 0xAC, 0xAD, 0x63, 0x38, 0xF0, 0xCE, 0x41, + 0xF0, 0xDD, 0xFE, 0xA4, 0x9B, 0xA4, 0xBB, 0x81, 0x06, 0x60, 0x83, 0x37, 0xF0, 0x41, 0xF0, 0xD6, + 0xF5, 0xC3, 0x00, 0xD4, 0xC5, 0x1D, 0xF0, 0x41, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x19, 0xF0, + 0x41, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x41, 0xF0, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x6D, + 0x6D, 0xD9, 0xC1, 0x33, 0xF0, 0x41, 0xF0, 0x15, 0xFA, 0x03, 0x30, 0xF9, 0x23, 0xF0, 0x41, 0xF0, + 0x41, 0xF0, 0x19, 0xF0, 0xE2, 0x3F, 0x20, 0x91, 0xAD, 0x1B, 0x5F, 0x41, 0xF0, 0x24, 0xF0, 0xA6, + 0xD2, 0x24, 0x2A, 0x56, 0x26, 0x61, 0xD2, 0x87, 0x41, 0xF0, 0xF8, 0xCC, 0xD9, 0xC1, 0x2C, 0x39, + 0xF5, 0x31, 0x24, 0x07, 0x15, 0x90, 0x41, 0xF0, 0xA5, 0xF2, 0x15, 0xD0, 0x46, 0xF5, 0x15, 0x10, + 0x41, 0xF0, 0xCF, 0xE5, 0xF6, 0x57, 0xBB, 0x00, 0x00, 0x57, 0x57, 0x57, 0x77, 0x09, 0x7D, 0xC0, + 0x22, 0x38, 0x4D, 0xF5, 0x3F, 0xC9, 0x50, 0x41, 0xF0, 0xC1, 0xBC, 0xBC, 0xBB, 0x00, 0x00, 0xAC, + 0xAC, 0xAC, 0xA4, 0xA5, 0x92, 0x85, 0x41, 0xF0, 0x41, 0xF0, 0xD9, 0xF1, 0x41, 0xF0, 0x39, 0x4F, + 0xF5, 0x40, 0x0F, 0xCE, 0x14, 0x41, 0xF0, 0x41, 0xF0, 0xD5, 0x3D, 0x85, 0xF5, 0x37, 0x4B, 0xF5, + 0x1F, 0x3E, 0x46, 0x74, 0x41, 0xF0, 0x26, 0xF0, 0x15, 0xF0, 0x32, 0x44, 0xF5, 0x1E, 0x39, 0xEE, + 0x76, 0x1B, 0x41, 0xF0, 0xA5, 0xF2, 0x6D, 0xFC, 0x36, 0x7C, 0x3A, 0x2F, 0x23, 0x15, 0xB0, 0x41, + 0xF0, 0xA5, 0xF2, 0x71, 0xAB, 0x22, 0x28, 0x3C, 0x2A, 0x25, 0x1F, 0x15, 0x90, 0x41, 0xF0, 0xA5, + 0xF2, 0x11, 0xC0, 0x6E, 0x0C, 0xF8, 0xE3, 0xAE, 0x41, 0xF0, 0xA5, 0xF2, 0x41, 0xC0, 0x33, 0xF0, + 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0x33, + 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0A, 0xA0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x09, 0x90, + 0x1E, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x04, 0x40, 0xFF, 0x25, 0xF0, 0xD5, 0xF5, 0x41, 0xF0, 0x53, + 0xF2, 0x85, 0xFE, 0x4D, 0xF5, 0xE3, 0xFA, 0x81, 0x7F, 0x8A, 0x81, 0xA9, 0x3B, 0x1E, 0x21, 0x26, + 0x26, 0x23, 0x04, 0x1F, 0x1C, 0x33, 0xAD, 0x24, 0x28, 0x29, 0x26, 0x05, 0x89, 0x84, 0x41, 0xF0, + 0x47, 0x20, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0xA4, 0x03, 0x2D, 0x81, 0x24, 0x40, 0x41, 0x39, 0x28, + 0x1F, 0xCB, 0x18, 0x82, 0x21, 0x21, 0x20, 0x1E, 0x1B, 0x2A, 0x24, 0x68, 0x6A, 0x20, 0x62, 0x2B, + 0x3D, 0xA4, 0x41, 0xF0, 0x93, 0xA4, 0x58, 0x16, 0x2D, 0x4C, 0xA4, 0x93, 0x10, 0x10, 0x4C, 0x10, + 0x10, 0x23, 0x84, 0x09, 0x2B, 0x54, 0x35, 0x37, 0xBB, 0x07, 0x96, 0x1F, 0x4F, 0x2E, 0x00, 0x39, + 0x24, 0x2C, 0x41, 0xA0, 0x41, 0xF0, 0x55, 0x31, 0x3D, 0x2D, 0x23, 0x63, 0x18, 0x29, 0x34, 0x04, + 0xD7, 0x41, 0xC7, 0xC8, 0xC4, 0x31, 0x21, 0x0E, 0x5F, 0x46, 0x40, 0xA1, 0xB6, 0x55, 0xFE, 0x9A, + 0x52, 0x10, 0x70, 0x34, 0x64, 0xB2, 0x14, 0x6E, 0x2E, 0x00, 0xBF, 0x4D, 0xA5, 0xB2, 0x65, 0xFF, + 0xA5, 0x36, 0x6D, 0xAC, 0x10, 0x70, 0x34, 0x64, 0xCE, 0x2E, 0x40, 0x41, 0xF0, 0xD2, 0xD9, 0xBB, + 0x77, 0x2D, 0x1B, 0x2D, 0x07, 0x77, 0xBB, 0x6D, 0x10, 0x70, 0x34, 0x64, 0x2E, 0x40, 0x41, 0xF0, + 0x08, 0xE9, 0xF8, 0x98, 0x1E, 0xAC, 0x62, 0x41, 0xC0, 0x41, 0xF0, 0x41, 0xF0, 0x77, 0xC8, 0x41, + 0x60, 0xF9, 0x41, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xB5, 0xF3, 0x07, 0x60, 0xA2, 0xF3, 0x41, 0xF0, + 0x71, 0xF3, 0xFF, 0x06, 0x20, 0x07, 0x40, 0x55, 0x32, 0x24, 0x24, 0x2B, 0x47, 0x03, 0x44, 0x09, + 0x41, 0xF0, 0x47, 0xBD, 0x8A, 0x81, 0x4A, 0x1B, 0x77, 0x07, 0xB3, 0xBB, 0xD5, 0x55, 0x06, 0x20, + 0x07, 0x40, 0x6B, 0x44, 0x05, 0x46, 0x5C, 0x5E, 0xBC, 0x08, 0x41, 0xF0, 0xC8, 0xB4, 0x93, 0x73, + 0x07, 0xAC, 0x62, 0x2E, 0x3D, 0x6D, 0xAC, 0x3D, 0x34, 0x06, 0x20, 0x07, 0x40, 0xD1, 0xCF, 0x38, + 0xCD, 0xCD, 0xCF, 0xD1, 0xD2, 0x41, 0xC0, 0x91, 0xF5, 0x77, 0x60, 0x80, 0x14, 0x8D, 0x15, 0x57, + 0xBB, 0xA5, 0x32, 0x40, 0xF0, 0x92, 0x52, 0x41, 0xF0, 0xF3, 0x41, 0xF0, 0x1D, 0x02, 0x3E, 0x6D, + 0x01, 0x10, 0x3D, 0xF0, 0x4C, 0x0A, 0x12, 0xB3, 0x41, 0xF0, 0x41, 0xF0, 0xF1, 0x1B, 0x61, 0x01, + 0x10, 0x29, 0xF3, 0x44, 0x21, 0x8F, 0xB7, 0x41, 0xF0, 0x03, 0x20, 0x61, 0x5B, 0x1F, 0x21, 0xFF, + 0x21, 0xFF, 0xD5, 0xF5, 0x03, 0x20, 0xF7, 0xAE, 0x27, 0xBB, 0x1B, 0xF6, 0x1F, 0x47, 0x51, 0x52, + 0x50, 0x09, 0x21, 0xAF, 0x4E, 0x4E, 0x4B, 0x44, 0x38, 0x65, 0x2F, 0x41, 0xF0, 0xC1, 0xB1, 0xF7, + 0x51, 0x04, 0x25, 0x32, 0x41, 0x45, 0x3F, 0x34, 0x03, 0x21, 0x0F, 0x03, 0x30, 0x00, 0x00, 0x1E, + 0x0F, 0x29, 0x28, 0x24, 0x02, 0x6A, 0x8F, 0x41, 0xF0, 0x45, 0xFD, 0x42, 0x34, 0x0F, 0x34, 0x24, + 0x01, 0x10, 0x03, 0x30, 0xCB, 0x00, 0x00, 0x1D, 0x35, 0x59, 0x41, 0xF0, 0x19, 0xF0, 0x34, 0xBF, + 0x1B, 0xF0, 0x41, 0xF0, 0xFD, 0x19, 0xF0, 0xB5, 0x83, 0x1E, 0xF0, 0x41, 0xF0, 0x1C, 0xF0, 0x21, + 0x9F, 0x2D, 0x83, 0x15, 0xF0, 0xFF, 0x41, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x91, 0xD5, 0x41, 0xF0, + 0x41, 0xF0, 0x57, 0x34, 0x3F, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x26, 0x26, 0x26, 0x24, 0x21, + 0x07, 0x1E, 0x1C, 0x41, 0x80, 0x51, 0xF1, 0x99, 0xFE, 0x6D, 0x51, 0x04, 0x40, 0x9C, 0x45, 0x00, + 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x32, 0x02, 0x26, 0x01, 0xDD, 0x38, 0xAC, 0xAA, 0x83, 0x41, + 0x50, 0xE1, 0xE1, 0x04, 0x40, 0x9E, 0xE0, 0x00, 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0xDE, 0xDA, 0x02, + 0x34, 0x22, 0x41, 0xC0, 0xC4, 0xA8, 0x4A, 0xB2, 0x73, 0x41, 0x50, 0x3E, 0xF0, 0xEC, 0x85, 0xF0, + 0xCD, 0xB0, 0x81, 0xDB, 0x31, 0x8A, 0xBB, 0x77, 0x41, 0x50, 0x8B, 0x3E, 0xF0, 0x69, 0xFB, 0xCA, + 0xD0, 0x57, 0xB2, 0x13, 0x9B, 0x3D, 0x65, 0x7F, 0x97, 0xDD, 0xFA, 0x41, 0xE1, 0xFA, 0xC7, 0xC0, + 0x8A, 0x9B, 0xB3, 0x6D, 0x0D, 0x41, 0x80, 0x7E, 0x76, 0x04, 0x40, 0x70, 0x00, 0x00, 0x70, 0x70, + 0x29, 0x70, 0x6E, 0x63, 0x4C, 0x35, 0xCC, 0x51, 0xF1, 0x81, 0xBB, 0x30, 0xBB, 0x6D, 0x01, 0x9D, + 0x6A, 0x4C, 0x04, 0x40, 0x40, 0x00, 0x00, 0xA4, 0x40, 0xD1, 0xD9, 0x41, 0xF0, 0xF5, 0x0F, 0xA4, + 0xAC, 0x62, 0x77, 0x0E, 0xE7, 0x02, 0xBD, 0x7C, 0x54, 0x30, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, + 0x22, 0x73, 0x22, 0x22, 0x21, 0x1F, 0xA5, 0xD2, 0x2D, 0xF3, 0x5F, 0x32, 0x79, 0x8C, 0xF0, 0x3A, + 0xD1, 0x1C, 0xF7, 0x83, 0x21, 0x2D, 0xF3, 0xAC, 0x57, 0xD7, 0x41, 0x95, 0xB3, 0x9B, 0x35, 0x1C, + 0xF1, 0x1B, 0x4F, 0x70, 0x46, 0x85, 0x61, 0x27, 0x6C, 0x25, 0x20, 0x6D, 0xD7, 0xD8, 0xA5, 0xCA, + 0x79, 0x9B, 0x7C, 0x7B, 0xB8, 0x70, 0xDC, 0xBD, 0x04, 0x34, 0x3E, 0x41, 0x80, 0x2B, 0xE5, 0x56, + 0x41, 0xF0, 0xC1, 0x05, 0xF9, 0x59, 0xF0, 0xF0, 0xEF, 0xDC, 0x60, 0x1D, 0x20, 0x21, 0x09, 0x05, + 0x4A, 0x6B, 0xB9, 0xE6, 0xFF, 0x39, 0xC9, 0x10, 0x81, 0x41, 0xF0, 0x3B, 0xF0, 0x59, 0x2A, 0x54, + 0x58, 0x49, 0x30, 0x21, 0x07, 0xC1, 0x50, 0x81, 0x04, 0xA4, 0x17, 0x26, 0xC5, 0x24, 0x41, 0xF0, + 0xC3, 0xF0, 0xF5, 0x17, 0xFB, 0x29, 0x32, 0x33, 0x2E, 0x24, 0x1E, 0xC1, 0x50, 0x7C, 0x40, 0xBC, + 0x80, 0x30, 0x09, 0xF5, 0xAC, 0xCF, 0xA9, 0x6F, 0x85, 0x20, 0x1F, 0x1F, 0x3E, 0x1F, 0xD3, 0x19, + 0x2F, 0x39, 0x49, 0xC1, 0x00, 0x2C, 0x63, 0x71, 0xE3, 0xE2, 0x5F, 0xBA, 0x00, 0x00, 0x5A, 0x0A, + 0x4A, 0x93, 0xBB, 0x77, 0x76, 0x53, 0x87, 0x24, 0x2B, 0x35, 0x42, 0x52, 0x98, 0xC1, 0x60, 0xF1, + 0x40, 0xC0, 0x90, 0x4D, 0xE9, 0xF2, 0x1B, 0x1B, 0xCE, 0xF9, 0x9B, 0x48, 0x3D, 0xEE, 0x32, 0x22, + 0x28, 0x31, 0x3E, 0x4D, 0x7B, 0x02, 0xBC, 0xF0, 0x1C, 0x62, 0xA6, 0x6C, 0x55, 0x42, 0x61, 0xF2, + 0x84, 0xD2, 0xF9, 0x93, 0xB3, 0x54, 0x1A, 0x45, 0x2D, 0x37, 0x47, 0x69, 0x19, 0xB0, 0xE0, 0x94, + 0x51, 0xDA, 0x36, 0x00, 0x6A, 0x45, 0x30, 0x14, 0x27, 0x21, 0x91, 0xA5, 0x41, 0xF0, 0xBF, 0x1C, + 0x93, 0x3D, 0x51, 0x61, 0x9C, 0x92, 0xCF, 0xF8, 0x3E, 0x60, 0x88, 0x7F, 0x51, 0x11, 0x30, 0x48, + 0x1F, 0x1D, 0x41, 0xF0, 0x4D, 0xC9, 0x9B, 0xAC, 0x62, 0xA1, 0x66, 0x8C, 0x32, 0x56, 0x11, 0x41, + 0xDA, 0xB7, 0x7C, 0x5F, 0x55, 0x04, 0x62, 0xC9, 0x10, 0x50, 0x41, 0x00, 0x41, 0xF0, 0x93, 0xB5, + 0xBB, 0x81, 0x3A, 0xC6, 0x54, 0x41, 0x60, 0xF8, 0xC1, 0x8A, 0x77, 0x5F, 0x4A, 0x03, 0x39, 0x35, + 0x41, 0x60, 0x41, 0xF0, 0x84, 0xA4, 0xBB, 0x9B, 0xD5, 0x65, 0x9C, 0x2D, 0x13, 0x89, 0x4D, 0xDA, + 0xAC, 0x6E, 0x49, 0x39, 0x34, 0x03, 0x49, 0x74, 0x41, 0x40, 0x41, 0xF0, 0xE0, 0xFE, 0x4D, 0x55, + 0x1F, 0x32, 0x3C, 0x57, 0xD1, 0xD1, 0x40, 0xF8, 0xD6, 0x9E, 0x52, 0x61, 0x04, 0x7C, 0xC6, 0xA8, + 0x41, 0xF0, 0x3B, 0xF0, 0x1D, 0x12, 0x3E, 0x5B, 0x80, 0x1E, 0xD1, 0x60, 0xF8, 0xD1, 0xB0, 0x3A, + 0x00, 0x55, 0x2F, 0x14, 0x8E, 0x91, 0x1B, 0x41, 0xF0, 0x95, 0xF1, 0x29, 0x38, 0xD1, 0x00, 0x8F, + 0xC1, 0x26, 0xF1, 0x8A, 0x75, 0x69, 0x43, 0x2F, 0x27, 0x21, 0x42, 0x30, 0x82, 0x41, 0xF0, 0x3A, + 0xF0, 0x68, 0x2B, 0xD1, 0x90, 0x98, 0x22, 0xB9, 0x72, 0x41, 0x1F, 0xF5, 0x23, 0x41, 0xF0, 0x3C, + 0xF0, 0xD1, 0xA0, 0x54, 0x67, 0x82, 0xB8, 0x0F, 0xE1, 0xAF, 0x53, 0xE6, 0xAF, 0xC5, 0x24, 0x41, + 0xF0, 0x3B, 0xF0, 0xD1, 0x90, 0xF2, 0x2F, 0x3B, 0x49, 0x5B, 0x6C, 0x90, 0xC1, 0xF1, 0x00, 0xC5, + 0x54, 0x1D, 0x32, 0x41, 0xF0, 0x39, 0xF0, 0xD1, 0x80, 0x23, 0x29, 0x33, 0x1F, 0x3F, 0x4F, 0x61, + 0x72, 0xA5, 0xD2, 0x95, 0xB1, 0x41, 0xF0, 0xC0, 0x40, 0xF0, 0xE1, 0x0D, 0xC4, 0x5D, 0x1F, 0x25, + 0x2C, 0x36, 0x44, 0x07, 0x55, 0x68, 0x83, 0xC1, 0xE9, 0x51, 0x41, 0x41, 0xF0, 0xAF, 0xF3, 0xE0, + 0xD1, 0x19, 0x25, 0x27, 0x23, 0x1E, 0x25, 0xE0, 0x3F, 0x21, 0x27, 0x31, 0x30, 0x3B, 0x4D, 0x65, + 0x79, 0x9C, 0xDE, 0x99, 0xDE, 0x80, 0x15, 0xFA, 0x00, 0x00, 0x8A, 0x8A, 0x8A, 0x8A, 0x49, 0x19, + 0x35, 0x43, 0xA9, 0x36, 0x2A, 0x2E, 0x52, 0xD9, 0x22, 0x27, 0x35, 0x4F, 0x18, 0x6B, 0x99, 0xEF, + 0x44, 0x41, 0xB0, 0x7D, 0xF8, 0xB3, 0x81, 0x30, 0xE9, 0x52, 0x20, 0x31, 0x4B, 0xFF, 0xB2, 0x43, + 0x2C, 0x01, 0x21, 0xE9, 0x61, 0x1D, 0x21, 0x2B, 0x40, 0x5E, 0xBF, 0x02, 0x9D, 0xEA, 0x41, 0xF0, + 0x69, 0x3F, 0x71, 0x33, 0x60, 0x98, 0x00, 0x49, 0x30, 0x2F, 0x16, 0x59, 0x1E, 0x24, 0x31, 0x48, + 0x80, 0x42, 0x11, 0x4A, 0x41, 0x91, 0xB5, 0x51, 0xF1, 0x31, 0x81, 0x3D, 0x1C, 0x15, 0xE7, 0x6F, + 0x34, 0x17, 0x25, 0x1E, 0x44, 0x41, 0x52, 0xA8, 0xF8, 0xF5, 0x37, 0x41, 0xF0, 0xC4, 0x0E, 0xAE, + 0x70, 0x5B, 0x45, 0x1D, 0x89, 0x2D, 0xF0, 0x81, 0x39, 0x27, 0x0F, 0x1F, 0x1C, 0x1D, 0x22, 0x2E, + 0x42, 0x6E, 0xD8, 0x00, 0x82, 0x20, 0xD5, 0x3F, 0xF5, 0xB7, 0x41, 0xF0, 0xB3, 0x6D, 0x8A, 0x39, + 0x99, 0xBD, 0x1C, 0x54, 0xAE, 0xD2, 0x10, 0xF8, 0x9D, 0x3D, 0x29, 0x09, 0x22, 0x27, 0x35, 0x4D, + 0x90, 0xF0, 0x18, 0x22, 0xA9, 0x40, 0x4F, 0x30, 0xF5, 0x27, 0x41, 0xF0, 0xC4, 0x7C, 0x8D, 0x69, + 0x1D, 0x27, 0x3C, 0x3C, 0x60, 0x9B, 0x57, 0x11, 0xFF, 0xB6, 0x46, 0x39, 0x08, 0x41, 0x5A, 0xC7, + 0x40, 0x20, 0xE1, 0x84, 0x4D, 0x34, 0x08, 0x24, 0xF5, 0xB7, 0x71, 0xF3, 0x8A, 0x2D, 0x42, 0x70, + 0x29, 0x3E, 0x26, 0x5B, 0x85, 0x05, 0x20, 0xCE, 0x65, 0x86, 0xE9, 0x7F, 0x20, 0x84, 0xBF, 0x60, + 0x43, 0x2F, 0x23, 0xC5, 0x10, 0x41, 0xF0, 0xE9, 0xF2, 0xE0, 0x68, 0x3B, 0x28, 0x39, 0x55, 0x75, + 0x56, 0x21, 0xE9, 0x82, 0x20, 0xA1, 0xE9, 0x94, 0x52, 0xEC, 0x02, 0x25, 0xDB, 0x61, 0xF2, 0x42, + 0xA0, 0x1E, 0x78, 0x25, 0x34, 0x4F, 0x70, 0xC1, 0x4B, 0x51, 0xC9, 0x64, 0x20, 0x47, 0x31, 0x25, + 0x1E, 0x41, 0xE0, 0x85, 0xF0, 0x9B, 0x2D, 0x30, 0x1B, 0x90, 0x1D, 0x22, 0x30, 0x49, 0x6A, 0xAF, + 0xF8, 0x01, 0xCB, 0x10, 0xF1, 0xA5, 0x5F, 0x3E, 0x2B, 0x21, 0x1D, 0x01, 0xD1, 0xE9, 0x41, 0xF0, + 0xBC, 0x0C, 0x3B, 0x34, 0x28, 0x17, 0x1F, 0x21, 0x23, 0x1F, 0x25, 0x2A, 0x36, 0x4C, 0x6C, 0x9D, + 0xF1, 0x42, 0x10, 0x80, 0x99, 0x51, 0x34, 0x28, 0x25, 0x24, 0x24, 0x22, 0x00, 0x20, 0x1E, 0x49, + 0xC9, 0x8D, 0xF9, 0x8B, 0x39, 0xA1, 0x16, 0x21, 0x2B, 0x3C, 0x37, 0x3D, 0x41, 0x41, 0x45, 0x4F, + 0x63, 0x7C, 0x00, 0x8A, 0xE9, 0x42, 0x10, 0x8C, 0x4C, 0x42, 0x40, 0x40, 0x04, 0x3F, 0x39, 0x30, + 0x25, 0x1E, 0x0C, 0x30, 0x41, 0xF0, 0xE5, 0xF6, 0xE0, 0x2B, 0x41, 0xC8, 0xCC, 0xCD, 0xCD, 0xCE, + 0xCF, 0x00, 0xD0, 0xD2, 0xD2, 0xD2, 0x37, 0x10, 0xF8, 0xD0, 0xCE, 0x10, 0xCD, 0xCD, 0xCD, 0xCA, + 0xC4, 0x31, 0xD9, 0x11, 0x41, 0xF0, 0xC0, 0x5B, 0xF2, 0xEC, 0x51, 0xFF, 0x3D, 0xF0, 0xD9, 0xF1, + 0xD8, 0xE1, 0x81, 0x8A, 0x3B, 0x81, 0xDA, 0x01, 0x9D, 0x1A, 0x66, 0x00, 0x00, 0x3E, 0xF0, 0x9D, + 0xFA, 0x2F, 0xE7, 0xF6, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0x3B, 0x10, 0x20, 0x38, 0x20, 0x5F, 0x01, + 0x10, 0xF5, 0xF3, 0x43, 0xE5, 0x36, 0x41, 0xF0, 0x25, 0x52, 0xA4, 0x76, 0x09, 0x19, 0x2D, 0x3D, + 0x14, 0x1F, 0x2F, 0x49, 0x99, 0xA1, 0x05, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0xA4, 0xA4, 0xA4, + 0xA3, 0x9D, 0x07, 0x8E, 0x36, 0x23, 0x41, 0x70, 0x41, 0xF0, 0x41, 0x14, 0xE5, 0x76, 0x26, 0x78, + 0x35, 0x45, 0x4F, 0x52, 0x4F, 0x03, 0x30, 0x4E, 0x00, 0x00, 0xA0, 0x4E, 0x4E, 0x4E, 0x4F, 0x52, + 0x52, 0x4B, 0x3C, 0x00, 0x2A, 0x41, 0x00, 0x41, 0xF0, 0xA5, 0xF2, 0xA1, 0x16, 0x24, 0x30, 0x3D, + 0x1E, 0x41, 0x3C, 0x32, 0x2D, 0x2A, 0xC0, 0x44, 0x2A, 0x2A, 0x20, 0x2A, 0x2B, 0x31, 0x3A, 0x44, + 0x42, 0x39, 0x28, 0x00, 0x09, 0xA5, 0x41, 0xF0, 0xAC, 0x30, 0x37, 0x6D, 0x05, 0x09, 0x1F, 0x2A, + 0x2B, 0x3F, 0xB1, 0xB2, 0xAD, 0x31, 0x23, 0x1D, 0x1E, 0x00, 0x20, 0x26, 0x8A, 0x04, 0x22, 0x1F, + 0x1D, 0x1D, 0x20, 0x04, 0x2D, 0x44, 0xC8, 0xC8, 0xC5, 0x32, 0x21, 0x41, 0xC0, 0x80, 0xA8, 0xE6, + 0x77, 0x2D, 0x1B, 0x2D, 0x77, 0xE5, 0x16, 0x20, 0x41, 0x34, 0x57, 0x10, 0x00, 0x3E, 0x25, 0x30, + 0x18, 0x68, 0x6A, 0x24, 0x43, 0x28, 0x20, 0x35, 0x5A, 0x2E, 0x00, 0x40, 0x09, 0x75, 0x41, 0xF0, + 0xD1, 0xB5, 0x27, 0xAC, 0x4A, 0x05, 0xAC, 0x62, 0x1B, 0xE9, 0x22, 0x10, 0x20, 0xC5, 0x30, 0x18, + 0x43, 0x48, 0x21, 0x3C, 0x6B, 0x2E, 0x00, 0xE9, 0xF2, 0x95, 0xF5, 0xE3, 0x3D, 0xA3, 0x16, 0x10, + 0x70, 0x30, 0x08, 0x74, 0x18, 0x46, 0x28, 0x4E, 0x22, 0x9E, 0x61, 0xF2, 0x95, 0xF1, 0x22, 0xF6, + 0x14, 0x02, 0x6E, 0x07, 0x00, 0x4D, 0x29, 0x2F, 0x2E, 0x20, 0x41, 0xF0, 0x2D, 0xF3, 0x22, 0x40, + 0x93, 0x10, 0x30, 0x41, 0xF0, 0x41, 0xF0, 0xEF, 0xC9, 0xF0, 0x80, 0x44, 0xBB, 0x10, 0x50, 0x41, + 0xF0, 0x41, 0xF0, 0x4F, 0xC5, 0xBB, 0x7B, 0x4C, 0x35, 0xB3, 0xA4, 0x10, 0x70, 0x07, 0x60, 0x2E, + 0x40, 0x41, 0xF0, 0xA8, 0xB2, 0xF9, 0x6D, 0xBB, 0x00, 0x00, 0x6D, 0x7A, 0x08, 0x2D, 0x41, 0x20, + 0x06, 0x20, 0xD4, 0xD5, 0x65, 0xCB, 0x25, 0x41, 0xF0, 0x51, 0xF1, 0x41, 0xA0, 0x06, 0x20, 0xD5, + 0x65, 0xCB, 0x25, 0xFF, 0x41, 0xA0, 0x41, 0xF0, 0x41, 0xF0, 0x06, 0x20, 0xD5, 0x65, 0xCB, 0x25, + 0x41, 0xB0, 0x41, 0xF0, 0xFF, 0xCE, 0xF4, 0x40, 0xF0, 0x33, 0x24, 0x41, 0x80, 0x41, 0xF0, 0x9A, + 0x21, 0x2D, 0x8A, 0x3F, 0xAC, 0x98, 0x16, 0x22, 0x3F, 0x6F, 0x01, 0x10, 0x3D, 0xF0, 0x4E, 0x62, + 0x29, 0x41, 0x90, 0x41, 0xF0, 0x8A, 0xAC, 0x4A, 0x1B, 0x9B, 0x06, 0xA4, 0x6D, 0xA4, 0x93, 0x1D, + 0x12, 0x69, 0x01, 0x10, 0xD5, 0xF1, 0xD0, 0x49, 0x1D, 0xC2, 0x85, 0xF0, 0x3D, 0x00, 0x3D, 0x1B, + 0x3D, 0xD5, 0x45, 0x8E, 0xD5, 0xF5, 0xD5, 0xF5, 0x41, 0xF0, 0xC7, 0x00, 0x7D, 0x14, 0xBB, 0xD5, + 0x25, 0xD5, 0xF5, 0xDF, 0xD5, 0xF5, 0x41, 0xF0, 0x44, 0x00, 0x8A, 0x8A, 0xCB, 0x15, 0xD5, 0x85, + 0xD5, 0xF5, 0xE7, 0x41, 0xF0, 0x3A, 0xB4, 0x93, 0xBB, 0x4A, 0x1B, 0x4A, 0xA4, 0x03, 0x77, 0xB5, + 0x13, 0x22, 0x28, 0x2A, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE2, 0x2B, 0x2B, 0x2B, 0x28, 0x24, + 0x1F, 0x1D, 0xD2, 0x23, 0xE2, 0xC0, 0x77, 0x4A, 0x9F, 0x12, 0xDA, 0x11, 0x23, 0x2E, 0x3A, 0x41, + 0x0C, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x07, 0x32, 0x26, 0x95, + 0x11, 0x41, 0xF0, 0x3B, 0xF0, 0x0D, 0x11, 0x45, 0xDC, 0x3C, 0xDF, 0x02, 0x20, 0x03, 0x30, 0x00, + 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0x0E, 0xDE, 0xDA, 0x0D, 0x21, 0x41, 0xF0, 0xC3, 0xF0, 0x85, 0x10, + 0x5D, 0x01, 0x10, 0xBC, 0x3D, 0xF0, 0x41, 0x26, 0x41, 0x90, 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x79, 0x57, 0x24, 0x03, 0x21, 0x3B, 0x67, 0x01, 0x10, 0x3D, 0xF0, 0x48, 0x62, 0x71, 0xA3, + 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xBB, 0x85, 0x00, 0x20, 0x4F, 0x37, 0x5E, 0x01, 0x10, + 0xE5, 0xF2, 0x42, 0x27, 0x01, 0x10, 0x41, 0xF0, 0xCC, 0x16, 0xC2, 0xA4, 0x81, 0xA5, 0x02, 0x2D, + 0x46, 0x7E, 0x8A, 0x09, 0x09, 0x10, 0x8E, 0x92, 0x61, 0x12, 0x94, 0x90, 0x8C, 0x8C, 0x09, 0x8C, + 0x8C, 0x8C, 0x8B, 0x83, 0x71, 0x34, 0x22, 0x00, 0x41, 0xF0, 0x1B, 0x3D, 0xF0, 0x3D, 0x41, 0x00, + 0x1D, 0x23, 0x2F, 0x15, 0x3B, 0x43, 0x09, 0x10, 0x4C, 0x63, 0x7C, 0x41, 0x00, 0x6F, 0x44, 0x52, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x45, 0x3F, 0x00, 0x33, 0x27, 0x1D, 0x62, 0x41, 0xF0, 0x9A, 0xD2, + 0x1D, 0x20, 0x23, 0x1C, 0x25, 0x09, 0x10, 0x2D, 0x49, 0x74, 0x41, 0x00, 0x57, 0x34, 0x22, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x26, 0x24, 0x21, 0x00, 0x1E, 0x1C, 0x41, 0xF0, 0x1B, 0x68, 0xF0, 0x6D, + 0x56, 0x32, 0x0B, 0x30, 0xD4, 0x23, 0x0D, 0x21, 0x50, 0x2B, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x12, + 0x1C, 0x41, 0xC0, 0x41, 0xF0, 0x00, 0x00, 0x9B, 0x9B, 0x9B, 0xA4, 0x0E, 0xBB, 0xCF, 0x31, 0x41, + 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x00, 0x00, 0x77, 0x77, 0x3E, 0x77, 0x6D, 0x3D, 0x11, 0x50, 0x41, + 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x17, 0xF0, 0xF8, 0x22, 0x40, 0x70, 0x41, 0x00, 0x4F, 0x2A, 0x16, + 0xF0, 0x41, 0xF0, 0xC8, 0x4F, 0xF3, 0x0B, 0x30, 0x24, 0x41, 0x71, 0x41, 0x00, 0x51, 0x2B, 0x23, + 0x00, 0x00, 0x1D, 0x1D, 0x81, 0x93, 0x41, 0xF0, 0xDF, 0x21, 0x62, 0x03, 0x10, 0xB9, 0x62, 0x2D, + 0x1E, 0x22, 0x1F, 0x24, 0x29, 0x2E, 0x09, 0x10, 0x84, 0x35, 0x50, 0x78, 0x41, 0x00, 0x5D, 0x3C, + 0x00, 0x00, 0x2F, 0x48, 0x2F, 0x2F, 0x2B, 0x26, 0x20, 0xD9, 0xE1, 0x40, 0xA0, 0xBB, 0x60, 0xB3, + 0x7D, 0x20, 0xB3, 0x77, 0x85, 0x22, 0x35, 0x6A, 0x72, 0x12, 0x09, 0x10, 0x78, 0x88, 0x94, 0x38, + 0x00, 0x8E, 0x7D, 0x75, 0x11, 0x75, 0x75, 0x75, 0x75, 0x74, 0x6D, 0x62, 0x2B, 0x00, 0x1F, 0x0C, + 0x60, 0x41, 0xF0, 0x77, 0xAC, 0x57, 0x42, 0x50, 0x77, 0x46, 0xC9, 0x00, 0x30, 0x4F, 0x01, 0x10, + 0x3D, 0xF0, 0x39, 0xE8, 0x71, 0x41, 0xF0, 0xD9, 0xB3, 0x6D, 0x24, 0x50, 0x57, 0xAC, 0x21, 0x00, + 0x39, 0x63, 0x24, 0x01, 0x10, 0x3D, 0xF0, 0x45, 0x0C, 0x10, 0x41, 0xF0, 0x41, 0xF0, 0x21, 0x00, + 0x3A, 0x7B, 0x65, 0x07, 0x70, 0x03, 0x30, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x47, 0x0E, 0x28, 0x41, + 0xE0, 0x08, 0x80, 0x34, 0x70, 0xBB, 0x1B, 0x1B, 0x1F, 0x0E, 0x33, 0x55, 0xE0, 0x05, 0x50, 0x03, + 0x30, 0x00, 0x00, 0xE1, 0xE1, 0x38, 0xE1, 0xDD, 0x3D, 0x25, 0x0C, 0x60, 0x41, 0xF0, 0xA4, 0x8A, + 0x30, 0x24, 0x50, 0x81, 0xA4, 0x31, 0x01, 0x28, 0x3C, 0x52, 0x60, 0x09, 0x02, 0x20, 0x03, 0x30, + 0x00, 0x00, 0x65, 0x65, 0x65, 0x63, 0x58, 0x07, 0x45, 0x2F, 0x20, 0x41, 0xC0, 0x42, 0xA0, 0xBB, + 0x81, 0x3D, 0x18, 0x22, 0x10, 0x2D, 0x81, 0xBB, 0x57, 0x31, 0x11, 0x28, 0x30, 0x21, 0x36, 0x02, + 0x20, 0x03, 0x30, 0x00, 0x00, 0x39, 0x39, 0x39, 0x37, 0x0E, 0x32, 0x2B, 0x22, 0x40, 0x70, 0x21, + 0x34, 0x47, 0xDB, 0x08, 0x3A, 0x28, 0x43, 0xB0, 0x9B, 0xBB, 0xB3, 0xAC, 0xAC, 0x04, 0xB3, 0xBB, + 0xA4, 0x3F, 0x20, 0x1C, 0x1E, 0x1F, 0x04, 0x40, 0x88, 0x03, 0x30, 0x00, 0x00, 0x20, 0x20, 0x20, + 0x1F, 0x1F, 0xD9, 0x80, 0x83, 0x20, 0x32, 0x44, 0xDB, 0x38, 0x26, 0x12, 0xC0, 0x4A, 0x40, 0x62, + 0x6D, 0x6D, 0x62, 0x4A, 0x02, 0x20, 0x0F, 0xF0, 0x15, 0xF0, 0xE0, 0x20, 0x2E, 0x3B, 0xDB, 0x32, + 0x24, 0x05, 0x50, 0x0F, 0xF0, 0xC0, 0x0F, 0xF0, 0x15, 0xF0, 0x1E, 0x26, 0x2E, 0x31, 0x29, 0x20, + 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x26, 0xF0, 0x42, 0xF0, 0x20, 0x23, 0x24, 0x20, 0x0F, 0x1D, 0x06, + 0x60, 0x0F, 0xF0, 0x0F, 0xF0, 0x13, 0xF0, 0x1C, 0x1D, 0x1D, 0x1E, 0x1C, 0x00, 0x00, 0x09, 0x90, + 0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1E, 0x94, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x6C, 0x23, 0x00, 0x00 +}; + +u8 battery_icons_blz[] = { + 0x17, 0xC0, 0x5D, 0x51, 0x79, 0x12, 0x79, 0x48, 0x69, 0x00, 0x0D, 0x46, 0xE3, 0x0F, 0xF0, 0x20, + 0xF0, 0x35, 0x2E, 0x38, 0x3F, 0x40, 0xEF, 0xCF, 0x00, 0x89, 0x77, 0x00, 0x17, 0x01, 0x14, 0x09, + 0x90, 0x36, 0xF0, 0xA4, 0xF1, 0x62, 0x01, 0x38, 0xA1, 0x99, 0x84, 0x3E, 0x00, 0x23, 0x1F, 0x04, + 0x40, 0x3B, 0xF0, 0x5B, 0x4F, 0x00, 0x18, 0x25, 0x20, 0x24, 0x90, 0x57, 0x00, 0x3C, 0xC0, 0x7B, + 0x00, 0x63, 0x10, 0x31, 0x7C, 0x2B, 0x03, 0x30, 0x3C, 0xF0, 0xA2, 0x00, 0xCE, 0x11, 0x0F, 0x0D, + 0x21, 0x00, 0x9E, 0xDE, 0x00, 0x06, 0x40, 0x60, 0xF0, 0xB9, 0xA0, 0xEA, 0x70, 0x3C, 0xF0, 0xF5, + 0x67, 0xD4, 0x3E, 0x01, 0x54, 0x00, 0x00, 0x00, 0x57, 0x70, 0xCD, 0xB1, 0x00, 0x1E, 0xFB, 0xD9, + 0x15, 0xA0, 0xC9, 0xAE, 0x69, 0x30, 0x3C, 0xD0, 0x30, 0xF0, 0xE4, 0xC1, 0xA7, 0x18, 0x10, 0x0D, + 0x0C, 0x00, 0x49, 0x3F, 0x04, 0x00, 0x87, 0x75, 0x00, 0xC5, 0xAA, 0x2A, 0x00, 0x09, 0x40, 0xC0, + 0xD7, 0xBA, 0x24, 0x00, 0x0C, 0xA0, 0x33, 0xF0, 0xF7, 0xD6, 0x0C, 0x00, 0x9C, 0x3C, 0xA0, 0x07, + 0x06, 0x2A, 0x10, 0x7D, 0x6C, 0x00, 0xBB, 0x09, 0xA2, 0x00, 0xF3, 0xD2, 0x00, 0xE3, 0xC4, 0x0C, + 0xA0, 0x80, 0x3C, 0xF0, 0x41, 0x38, 0x05, 0x50, 0x3E, 0xF1, 0x03, 0x00, 0x01, 0x19, 0x01, 0x00, + 0x33, 0x2C, 0x00, 0x71, 0x62, 0x00, 0x00, 0xAF, 0x97, 0x00, 0xEB, 0xCB, 0x03, 0x30, 0x03, 0x30, + 0x3C, 0x40, 0xE0, 0x81, 0x70, 0x04, 0x40, 0x0F, 0xF0, 0x23, 0xF0, 0x2D, 0x27, 0x00, 0x1C, 0x6B, + 0x5D, 0x00, 0xA9, 0x92, 0x00, 0xE7, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC, 0x00, 0xBF, 0xA5, + 0x0E, 0xE0, 0x81, 0x0F, 0xF0, 0x19, 0xF0, 0xA5, 0x00, 0x22, 0x00, 0x65, 0x58, 0x00, 0x07, 0x67, + 0x59, 0x07, 0x70, 0x0F, 0xF0, 0x2A, 0xF0, 0x06, 0x09, 0x45, 0x10, 0x3C, 0x0A, 0x00, 0x00, 0x03, + 0x30, 0x00, 0x00, 0x49, 0x11, 0x0B, 0x47, 0x0E, 0x10, 0x0B, 0x1B, 0x06, 0x04, 0x3F, 0xF0, 0xD2, + 0xF0, 0xCD, 0x38, 0xE0, 0x85, 0xF8, 0xF7, 0x3A, 0x26, 0x75, 0x00, 0xD2, 0xF0, 0x33, 0x00, 0x27, + 0x71, 0x09, 0x06, 0x24, 0x30, 0xBD, 0x2C, 0x1D, 0x15, 0x00, 0xDB, 0x44, 0x33, 0x22, 0x00, 0x00, + 0x03, 0x30, 0x00, 0x00, 0x57, 0x00, 0x5D, 0x00, 0x18, 0x00, 0xFC, 0xC7, 0x2E, 0x1F, 0x00, 0x00, + 0x45, 0x00, 0x29, 0x09, 0x06, 0x18, 0x89, 0x30, 0x2F, 0x0B, 0x07, 0xDF, 0x34, 0x23, 0x21, 0xC0, + 0x81, 0x59, 0x15, 0x0E, 0x3C, 0xC0, 0x2A, 0x00, 0xF5, 0xC7, 0xE1, 0x34, 0x38, 0x23, 0x31, 0x0B, + 0x07, 0xC9, 0x2F, 0x1F, 0x33, 0x00, 0x80, 0x2D, 0x00, 0x1E, 0x90, 0x4D, 0x12, 0x0C, 0x2D, 0xC0, + 0x41, 0x0F, 0x23, 0x0A, 0x03, 0x30, 0x00, 0x00, 0xD9, 0x33, 0x22, 0xE7, 0x36, 0x06, 0x24, 0x06, + 0x00, 0xCB, 0x2F, 0x1F, 0x39, 0x30, 0x15, 0x05, 0x22, 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x21, 0xF0, + 0x0F, 0x03, 0x02, 0x03, 0x00, 0x8E, 0xF9, 0x3A, 0x3C, 0xA0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, + 0x3C, 0xF0, 0x30, 0xF0, 0xFC, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, + 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, + 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, + 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, + 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, + 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, + 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, + 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, + 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x84, 0x90, 0x3F, 0x00, 0x00, 0x00, 0x0F, 0xF0, + 0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x07, 0x01, 0xB1, 0x40, + 0x81, 0x20, 0x33, 0x0C, 0x08, 0x00, 0x00, 0x0F, 0xF0, 0xC6, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, + 0x0D, 0x03, 0x02, 0x2D, 0x0A, 0x07, 0x07, 0x75, 0x30, 0x39, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, + 0xF0, 0x1B, 0xF0, 0x03, 0x00, 0xFE, 0x39, 0x00, 0xB1, 0x29, 0x1B, 0xF3, 0x39, 0x26, 0x00, 0x00, + 0x81, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xFE, 0x3B, 0x27, 0xF5, 0x0F, 0x39, 0x26, + 0xB3, 0x2A, 0x1C, 0x17, 0x05, 0x03, 0x00, 0xFF, 0xE4, 0x02, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x6A, 0x09, 0x00, 0x00 +}; + +u8 *render_static_bootlogo() +{ + // Clear background. + gfx_clear_grey(0x1B); + + // Set default logo. + u8 *logo_buf = (void *)malloc(SZ_16K); + blz_uncompress_srcdest(bootlogo_blz, sizeof(bootlogo_blz), logo_buf, BOOTLOGO_SIZE); + gfx_set_rect_grey(logo_buf, BOOTLOGO_WIDTH, BOOTLOGO_HEIGHT, BOOTLOGO_X, BOOTLOGO_Y); + + return logo_buf; +} + +bool render_ticker_logo(u32 boot_wait, u32 backlight) +{ + u32 btn = 0; + + u32 ticker_step_us = boot_wait * 1000000; + ticker_step_us /= BOOTLOGO_HEIGHT; + + // Set default logo. + u8 *logo_buf = render_static_bootlogo(); + + // Clear line. + u8 *grey = malloc(6 * BOOTLOGO_HEIGHT); + memset(grey, 0x1B, 6 * BOOTLOGO_HEIGHT); + gfx_set_rect_grey(grey, 6, BOOTLOGO_HEIGHT, 362, BOOTLOGO_Y); + free(grey); + + // Enable backlight to show first frame. + display_backlight_brightness(backlight, 1000); + + // Animated line as ticker. + for (u32 i = 1; i <= BOOTLOGO_HEIGHT; i++) + { + // If only VOL- was pressed, exit. + btn = btn_read_vol(); + if (btn == BTN_VOL_DOWN) + break; + + // Wait before setting next tick. + usleep(ticker_step_us); + + // Set next ticker progress. + gfx_set_rect_grey(logo_buf + BOOTLOGO_WIDTH * (BOOTLOGO_HEIGHT - i) + 36, 6, 1, 362, BOOTLOGO_Y + BOOTLOGO_HEIGHT - i); + } + free(logo_buf); + + return (btn == BTN_VOL_DOWN); +} + +bool render_ticker(u32 boot_wait, u32 backlight, bool no_ticker) +{ + u32 btn = 0; + + u32 ticker_step_us = boot_wait * 1000000; + ticker_step_us /= 1280; + + // Save bottom lines. + u32 *logo_line = (u32 *)malloc(1280 * sizeof(u32) * 2); + for (u32 i = 1280; !no_ticker && i >= 1; i--) + { + logo_line[i - 1] = gfx_ctxt.fb[i * gfx_ctxt.width - 2]; + logo_line[i - 1 + 1280] = gfx_ctxt.fb[i * gfx_ctxt.width - 1]; + } + + // Enable backlight to show first frame. + display_backlight_brightness(backlight, 1000); + + // Animated line as ticker. + for (u32 i = 1280; i >= 1; i--) + { + // If only VOL- was pressed, exit. + btn = btn_read_vol(); + if (btn == BTN_VOL_DOWN) + break; + + // Wait before setting next tick. + usleep(ticker_step_us); + + // Set bottom lines ticker progress. + if (!no_ticker) + { + gfx_ctxt.fb[i * gfx_ctxt.width - 2] = TXT_CLR_DEFAULT; + gfx_ctxt.fb[i * gfx_ctxt.width - 1] = TXT_CLR_DEFAULT; + } + } + + // Restore bottom lines. + for (u32 i = 1280; !no_ticker && i >= 1; i--) + { + gfx_ctxt.fb[i * gfx_ctxt.width - 2] = logo_line[i - 1]; + gfx_ctxt.fb[i * gfx_ctxt.width - 1] = logo_line[i - 1 + 1280]; + } + free(logo_line); + + return (btn == BTN_VOL_DOWN); +} diff --git a/bootloader/gfx/logos.h b/bootloader/gfx/logos.h index 24a8e93..7876379 100644 --- a/bootloader/gfx/logos.h +++ b/bootloader/gfx/logos.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,467 +14,19 @@ * along with this program. If not, see . */ -#ifndef _HEKATE_LOGOS_H_ -#define _HEKATE_LOGOS_H_ +#ifndef _GFX_LOGOS_H_ +#define _GFX_LOGOS_H_ -#ifdef MENU_LOGO_ENABLE -// 119 x 57 @24bpp RGB RAW positioned at 577 x 1199 -#define SZ_MENU_LOGO 20349 -#define SZ_MENU_LOGO_BLZ 3084 -static unsigned char Kc_MENU_LOGO_blz[SZ_MENU_LOGO_BLZ] = { - 0x03, 0x30, 0x80, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0xFF, 0x81, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x62, 0xF1, - 0x0F, 0xF0, 0x14, 0xF1, 0x62, 0xF1, 0x2A, 0xF0, 0xFF, 0x93, 0x10, 0x1D, 0x99, 0x03, 0x4F, 0xB2, - 0xBF, 0x17, 0x5A, 0x96, 0x0F, 0xF0, 0xF8, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0xBD, 0xF0, 0x81, 0xF0, 0x24, 0xF0, 0x81, 0xF0, - 0x62, 0xF1, 0x0F, 0xF0, 0x30, 0xF0, 0x62, 0xF1, 0xFF, 0xC0, 0x93, 0x90, 0x96, 0xCF, 0xF0, 0xA2, - 0x03, 0xCD, 0xF2, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0xC6, 0xF0, 0x81, 0xF0, 0x2A, 0xF0, 0xFF, 0x81, 0xF0, 0x62, 0xF1, 0x0F, - 0xF0, 0x30, 0xF0, 0x62, 0xF1, 0x96, 0xF6, 0xD8, 0xF0, 0xE1, 0xF0, 0xFF, 0xAE, 0xF3, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xC6, - 0xF0, 0x81, 0xF0, 0x27, 0xF0, 0x81, 0xF0, 0x26, 0xF1, 0x0F, 0xF0, 0x2A, 0xF0, 0xFF, 0x4A, 0xC1, - 0x07, 0x95, 0x0F, 0xF0, 0xC9, 0xC0, 0xE6, 0x84, 0x0E, 0x41, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0x51, 0xF0, 0xFF, - 0x81, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x21, 0xF0, 0x62, 0xF1, 0x51, 0xF0, 0x32, 0xF1, 0x1E, 0x90, - 0xFF, 0xC0, 0x03, 0xFF, 0x90, 0xBF, 0x07, 0xD3, 0x05, 0xBA, 0xA0, 0xE3, 0xF4, 0x0F, 0xF0, 0xE7, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x81, 0xF0, - 0xFF, 0x81, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x27, 0xF0, 0x0B, 0xF1, 0x62, 0xF1, 0x21, 0xF0, 0xEA, - 0x7F, 0x02, 0x1F, 0xD1, 0xF7, 0x21, 0xF0, 0x8A, 0x03, 0xB4, 0x90, 0x62, 0x16, 0x3C, 0x0B, 0xF1, - 0x1B, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFD, 0x0F, 0xF0, - 0x24, 0xF0, 0x54, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x21, 0xF0, 0x62, 0xF1, 0xFF, 0x2A, - 0xF0, 0x35, 0xF1, 0xA5, 0xF3, 0x7B, 0xF3, 0xF5, 0x01, 0x0B, 0x71, 0xAE, 0x4F, 0x0C, 0x16, 0x72, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFE, 0x0F, 0xF0, 0x2C, - 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x21, 0xF0, 0x81, 0xF0, 0x2A, 0xF0, 0x62, 0xF1, 0xFF, 0x62, 0xF1, - 0x20, 0xF0, 0xAE, 0x0C, 0xD0, 0xFE, 0x1B, 0x24, 0xF0, 0xD0, 0xFE, 0xD3, 0xDF, 0x04, 0xD0, 0xDE, - 0xEA, 0xC9, 0x00, 0x00, 0x33, 0xC0, 0x33, 0xF0, 0x76, 0xF8, 0xFC, 0xEF, 0x9A, 0x17, 0x01, 0x03, - 0xCF, 0x62, 0xF1, 0xED, 0x30, 0x09, 0x00, 0xB9, 0x3A, 0x0F, 0x3C, 0xFF, 0x81, 0xF0, 0x81, 0xF0, - 0x23, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x1E, 0xF0, 0xFF, 0xDF, 0x04, 0x06, - 0x4C, 0x06, 0xFC, 0x54, 0xF0, 0x06, 0xFC, 0x66, 0xF0, 0x4B, 0x30, 0xFC, 0x5C, 0x01, 0xEE, 0x02, - 0x68, 0x91, 0x06, 0x03, 0xA6, 0x95, 0x5F, 0xF1, 0x15, 0x00, 0x0F, 0x00, 0xFF, 0x09, 0x00, 0x11, - 0x94, 0x7B, 0x09, 0xA9, 0x02, 0x0E, 0x67, 0x5B, 0xF8, 0x06, 0x00, 0x15, 0x3C, 0xFF, 0x4C, 0xF5, - 0x81, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x24, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0xFF, 0x3C, - 0xF9, 0x3C, 0xF9, 0x0F, 0xF0, 0x27, 0xF0, 0x21, 0xF3, 0x1E, 0x00, 0x83, 0x91, 0x32, 0xF7, 0xFF, - 0x33, 0x30, 0x8A, 0xF9, 0x5F, 0x94, 0x0B, 0xF1, 0x7A, 0x01, 0x0C, 0x00, 0x62, 0xF1, 0x58, 0x02, - 0xFF, 0x5C, 0x01, 0x15, 0x3F, 0x24, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x24, - 0xF0, 0xFF, 0x08, 0xF1, 0x62, 0xF1, 0x72, 0xF6, 0x72, 0xF6, 0x0F, 0xF0, 0x24, 0xF0, 0x21, 0xF0, - 0xC4, 0x35, 0xFF, 0x33, 0xF0, 0x6A, 0xC8, 0xEC, 0xFA, 0x36, 0xC0, 0xCA, 0xF2, 0x3E, 0x01, 0x50, - 0xF1, 0xF0, 0x00, 0xFF, 0xC4, 0x92, 0x21, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x21, 0xF0, 0x62, 0xF1, 0xFF, 0x27, 0xF0, 0xDE, 0xF0, 0xDE, 0xF0, 0x0F, 0xF0, 0x21, 0xF0, 0x98, - 0xC1, 0x1E, 0x00, 0x33, 0xF0, 0xFF, 0xFE, 0xFA, 0xEE, 0xF2, 0x36, 0xF0, 0x2C, 0xF1, 0x3B, 0x01, - 0x1A, 0x91, 0x7F, 0xC5, 0x24, 0xF0, 0xFF, 0x57, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x24, - 0xF0, 0x27, 0xF0, 0x62, 0xF1, 0xDE, 0xF0, 0xFF, 0xDE, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x36, 0xF0, 0x62, 0xF1, 0x25, 0xFB, 0xFC, 0x03, 0xFF, 0x36, 0xF0, 0x51, 0xFC, 0xFF, 0x03, 0x1A, - 0xC1, 0x2E, 0xF5, 0x57, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x30, 0xF0, 0x27, 0xF0, - 0x62, 0xF1, 0x24, 0xF0, 0xDE, 0xF0, 0xDE, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, - 0xF0, 0x62, 0xF1, 0x25, 0xF8, 0x33, 0xF0, 0x60, 0xF9, 0x1A, 0x91, 0xFF, 0x0C, 0x9F, 0x27, 0xF0, - 0x57, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x27, 0xF0, 0xFF, 0x62, 0xF1, 0x38, - 0xF1, 0xDD, 0xF7, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x24, 0xF0, 0xFF, 0x91, 0xF5, - 0xFC, 0x33, 0x36, 0xF0, 0x39, 0xFF, 0x62, 0x01, 0x62, 0xF1, 0x2D, 0xF0, 0x81, 0xF0, 0xFF, 0x81, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x21, 0xF0, 0x4F, 0x7F, 0x18, - 0x38, 0xA1, 0x01, 0x05, 0x0F, 0xF0, 0x0F, 0xF0, 0x8A, 0xF0, 0xB4, 0xF9, 0x62, 0x01, 0xFE, 0xE9, - 0x6D, 0x1B, 0xF0, 0xAB, 0x9C, 0x0F, 0xF0, 0x09, 0x90, 0xA7, 0x9D, 0x34, 0x38, 0x62, 0xF1, 0xFF, - 0x2A, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2A, 0xF0, 0x62, 0xF1, 0x62, 0xF1, - 0xFF, 0xD5, 0xF3, 0xE1, 0x60, 0xAB, 0xF3, 0x0F, 0xF0, 0x2D, 0xF0, 0xB2, 0xF5, 0x22, 0x0B, 0x96, - 0x3C, 0xFF, 0x1F, 0x5B, 0x45, 0xF0, 0x62, 0xF1, 0x0F, 0xF0, 0x25, 0xF0, 0x1A, 0xF1, 0x62, 0xF1, - 0x1F, 0xF0, 0xFF, 0x81, 0xF0, 0x2A, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x25, - 0xF0, 0xAB, 0xF3, 0xFF, 0x37, 0xF5, 0x86, 0xFA, 0x16, 0x92, 0xB1, 0x00, 0x50, 0xD4, 0x73, 0x3B, - 0x2D, 0xC0, 0x45, 0xF0, 0xFF, 0x82, 0x98, 0xFC, 0xC6, 0x0F, 0xF0, 0x1B, 0xF0, 0x62, 0xF1, 0x29, - 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0xFF, 0x1E, 0xF0, 0x81, 0xF0, 0x27, 0xF0, 0x62, 0xF1, 0x62, 0xF1, - 0x6D, 0xF2, 0x34, 0x95, 0x38, 0x7F, 0x19, 0x01, 0x10, 0x39, 0xF0, 0xE6, 0xF4, 0x0D, 0x02, 0xCA, - 0xF5, 0xAC, 0x08, 0x02, 0x20, 0xFE, 0x2B, 0xF0, 0x62, 0xF1, 0x91, 0xF2, 0x0F, 0xF0, 0x1F, 0xF0, - 0x62, 0xF1, 0x2E, 0xF0, 0x81, 0xF0, 0xFF, 0x81, 0xF0, 0x22, 0xF0, 0x81, 0xF0, 0xC4, 0xD2, 0x62, - 0xF1, 0x62, 0xF1, 0x24, 0xF0, 0x46, 0xF2, 0xFF, 0xDA, 0x07, 0x03, 0x30, 0x33, 0xF0, 0x38, 0x19, - 0x1B, 0xF5, 0x01, 0x07, 0x1F, 0x92, 0x40, 0x12, 0x33, 0xF0, 0x30, 0xF0, 0x45, 0xF0, 0x56, 0x94, - 0x62, 0x01, 0x09, 0x90, 0xFF, 0x0F, 0xF0, 0x1B, 0xF0, 0x62, 0xF1, 0x2D, 0xF0, 0x81, 0xF0, 0x24, - 0xF0, 0x81, 0xF0, 0x5A, 0xF0, 0xFF, 0x27, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x21, 0xF0, 0xEA, 0x02, - 0x1F, 0x24, 0xC0, 0x8F, 0x36, 0xF0, 0x87, 0xF3, 0x74, 0x14, 0xBD, 0x10, 0x62, 0xF1, 0x33, 0xF0, - 0x41, 0xC4, 0xF3, 0x62, 0x31, 0xE7, 0x96, 0x14, 0x97, 0x0F, 0xF0, 0x1B, 0xF0, 0x62, 0xF1, 0x51, - 0xF0, 0x81, 0xF0, 0xFF, 0x81, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x27, 0xF0, 0x62, 0xF1, 0x62, 0xF1, - 0x5A, 0xF0, 0x84, 0x7F, 0x12, 0xB1, 0xD3, 0xAE, 0x0C, 0xC0, 0x13, 0x90, 0x93, 0x0A, 0x05, 0x9F, - 0xC3, 0xF2, 0x86, 0xF1, 0xCA, 0xF2, 0x27, 0xF0, 0xB2, 0x35, 0x4D, 0xC1, 0x62, 0x01, 0x09, 0x90, - 0x0F, 0xF0, 0xFF, 0x18, 0xF0, 0x62, 0xF1, 0x4E, 0xF0, 0x81, 0xF0, 0x0F, 0xF0, 0x6C, 0xF0, 0x81, - 0xF0, 0x24, 0xF0, 0xFF, 0x62, 0xF1, 0x51, 0xF0, 0x5A, 0xF0, 0xBB, 0x0A, 0xE1, 0x70, 0xD8, 0xF0, - 0xDB, 0xF0, 0xE7, 0x0E, 0xF1, 0x4A, 0x04, 0x6C, 0xF0, 0x11, 0xF4, 0x5F, 0x01, 0x45, 0x00, 0x12, - 0x90, 0xB5, 0x02, 0xFF, 0x86, 0x01, 0x80, 0x01, 0x09, 0x90, 0x27, 0xF0, 0x29, 0x01, 0x5B, 0xC2, - 0x1A, 0xF1, 0x48, 0xF0, 0xFF, 0x81, 0xF0, 0x7E, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0x21, 0xF0, 0x62, - 0xF1, 0x0F, 0xF0, 0x3C, 0xF0, 0xFF, 0x02, 0x01, 0x0F, 0xF0, 0xCF, 0xF0, 0xF5, 0x01, 0x20, 0x3A, - 0x32, 0x15, 0xF0, 0xC7, 0x00, 0x00, 0x39, 0x60, 0x33, 0xF0, 0xEE, 0x02, 0x18, 0x00, 0x7F, 0x7F, - 0x7F, 0x1F, 0x45, 0x60, 0x3E, 0x91, 0x41, 0x01, 0xCB, 0xCB, 0xCB, 0x03, 0x30, 0x2A, 0xF0, 0xC7, - 0x20, 0x01, 0x0B, 0x01, 0x09, 0x00, 0x62, 0xC1, 0x62, 0xF1, 0x42, 0xF0, 0x81, 0xF0, 0x7E, 0xF0, - 0xFF, 0x81, 0xF0, 0x30, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x0F, 0xF0, 0x36, 0xF0, 0x93, 0x10, 0x3F, - 0x1D, 0x03, 0x30, 0x09, 0x90, 0xD5, 0x90, 0xC6, 0x00, 0x14, 0xC1, 0x39, 0xF0, 0xE1, 0x7E, 0xE1, - 0xE1, 0x83, 0x91, 0x12, 0x00, 0x2A, 0x00, 0x24, 0x00, 0x39, 0x30, 0x21, 0x00, 0xFC, 0x45, 0x00, - 0x5F, 0x5F, 0x5F, 0x92, 0xF1, 0x15, 0x00, 0x47, 0x01, 0x35, 0x01, 0xF1, 0x37, 0x37, 0x37, 0x12, - 0x60, 0xA8, 0xA8, 0xA8, 0x00, 0x00, 0x88, 0x11, 0x01, 0x0C, 0x00, 0x62, 0xC1, 0x62, 0xF1, 0x0F, - 0xF0, 0x2D, 0xF0, 0x81, 0xF0, 0x81, 0xF0, 0xFF, 0x0F, 0xF0, 0x21, 0xF0, 0x74, 0x14, 0x1C, 0x3F, - 0x90, 0x4F, 0x18, 0x23, 0x45, 0x70, 0x0F, 0xF0, 0x2A, 0xF0, 0x12, 0x00, 0xC7, 0x07, 0x1E, 0x03, - 0x30, 0x8F, 0x00, 0x00, 0xFF, 0x00, 0x20, 0xDF, 0x04, 0x1F, 0xA1, 0x01, 0x0E, 0x1D, 0x62, 0x16, - 0x1C, 0x0F, 0xF0, 0x36, 0xF0, 0x21, 0x00, 0xE0, 0xD6, 0xD6, 0xD6, 0x39, 0x90, 0xB4, 0xB4, 0xB4, - 0x6F, 0x08, 0x6F, 0x6F, 0x0C, 0x60, 0xEB, 0xEB, 0xEB, 0x9B, 0x9B, 0x04, 0x9B, 0x00, 0x00, 0x27, - 0xF0, 0x12, 0x00, 0x0C, 0x00, 0x03, 0x30, 0x00, 0x00, 0x1B, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0x8D, - 0x8D, 0x8D, 0x18, 0xF0, 0x03, 0x00, 0xC0, 0xF5, 0xF5, 0xF5, 0x4C, 0x4C, 0x4C, 0x06, 0x60, 0x0F, - 0xF0, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x68, 0xF1, 0x0C, 0xC0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, - 0xAD, 0xAD, 0xAD, 0x09, 0x90, 0x8F, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x3F, 0xF0, 0x48, 0xF0, 0x15, 0x30, 0xFF, 0x6F, 0x60, 0x1E, 0x66, 0xD2, 0x00, 0x5B, 0x05, - 0x03, 0x30, 0x33, 0xF0, 0x17, 0xF1, 0x62, 0xF1, 0xFF, 0x0F, 0xF0, 0x15, 0xF0, 0x62, 0xF1, 0x1B, - 0xF0, 0x62, 0xF1, 0x0F, 0xF0, 0x0F, 0xF0, 0x15, 0xF0, 0xFF, 0x2B, 0xC5, 0x62, 0xF1, 0x25, 0xFB, - 0x0F, 0xF0, 0x0F, 0xF0, 0x33, 0xF0, 0x48, 0xF0, 0x0B, 0xC1, 0xFF, 0xE1, 0x63, 0x0F, 0xF0, 0x2D, - 0xF0, 0x9D, 0x92, 0x62, 0xF1, 0x0C, 0xC0, 0x18, 0xF0, 0x62, 0x91, 0xFF, 0x24, 0xF0, 0xA4, 0xF1, - 0xA6, 0x92, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x38, 0xF1, 0xB7, 0x93, 0xFF, 0x62, 0xF1, 0x9F, - 0x60, 0x26, 0x31, 0x27, 0x60, 0x93, 0x90, 0x5B, 0x68, 0x48, 0xC0, 0x5B, 0xF8, 0xFF, 0x99, 0xF0, - 0x5B, 0xF8, 0x7E, 0x90, 0x69, 0xC0, 0x62, 0xF1, 0x95, 0x34, 0x39, 0x90, 0x5B, 0x98, 0xFF, 0x81, - 0x00, 0x03, 0x00, 0x91, 0x65, 0x77, 0x31, 0x35, 0x34, 0x21, 0x30, 0xCA, 0x62, 0x4B, 0x30, 0xFF, - 0x25, 0x68, 0x5B, 0xF8, 0x8E, 0x92, 0x5C, 0xF1, 0x62, 0xF1, 0xF2, 0x67, 0x2A, 0x00, 0x5B, 0xC8, - 0xFF, 0x62, 0xF1, 0x33, 0x30, 0x60, 0x30, 0xC3, 0x36, 0xCF, 0x30, 0x56, 0x01, 0x91, 0x65, 0x91, - 0xF5, 0xFF, 0x48, 0xF0, 0x62, 0xF1, 0x91, 0xF5, 0x3C, 0x00, 0x36, 0x00, 0x63, 0x96, 0x46, 0xF5, - 0x62, 0xF1, 0xFF, 0xB8, 0x65, 0x6B, 0x31, 0x91, 0x65, 0x35, 0x34, 0x24, 0x00, 0x91, 0x95, 0xEC, - 0x34, 0x36, 0xC0, 0xFF, 0x14, 0x34, 0x3F, 0x90, 0x91, 0xC5, 0x39, 0x00, 0xF6, 0xF6, 0x56, 0xF1, - 0x62, 0xF1, 0x12, 0x00, 0xFF, 0x91, 0x65, 0x2D, 0x00, 0x62, 0xF1, 0x62, 0xF1, 0x1B, 0x00, 0x7B, - 0x66, 0xC7, 0x92, 0xC7, 0xF2, 0xFF, 0x48, 0xF0, 0x62, 0xF1, 0xC7, 0xF2, 0xCF, 0xF0, 0x7C, 0xF2, - 0x62, 0xF1, 0x40, 0x02, 0xC7, 0xF2, 0xFF, 0x85, 0xC2, 0xC7, 0x32, 0xA7, 0x34, 0xB1, 0x90, 0xD4, - 0x64, 0x2C, 0x64, 0xC7, 0xF2, 0x6F, 0x60, 0xFF, 0xB0, 0x64, 0xB5, 0xF2, 0x62, 0xF1, 0xC7, 0xF2, - 0xC7, 0xF2, 0x54, 0xF0, 0x62, 0xF1, 0x29, 0x61, 0xFF, 0x1A, 0x61, 0x03, 0x00, 0x1E, 0xF0, 0x62, - 0xF1, 0x27, 0xF0, 0x84, 0x30, 0x45, 0x60, 0x51, 0x30, 0xFF, 0x38, 0xF1, 0x62, 0xF1, 0x62, 0xF1, - 0x36, 0x00, 0x00, 0x00, 0x45, 0x90, 0x2D, 0x00, 0x5A, 0x00, 0xFF, 0xD5, 0x33, 0xFF, 0x90, 0xD1, - 0x01, 0x5D, 0x30, 0x62, 0xF1, 0x1B, 0xC0, 0x15, 0x30, 0x99, 0x30, 0xFF, 0xF3, 0x90, 0x33, 0x33, - 0x14, 0xC4, 0x62, 0xF1, 0x06, 0x60, 0x62, 0xC1, 0x54, 0xF0, 0x62, 0xF1, 0xFF, 0x03, 0x00, 0x93, - 0x00, 0xA8, 0x00, 0x12, 0x30, 0x09, 0x00, 0x03, 0x00, 0x48, 0xF0, 0x62, 0xF1, 0xFF, 0x62, 0xF1, - 0xCF, 0x30, 0xFE, 0xF4, 0x09, 0x03, 0xBF, 0x01, 0x38, 0x61, 0x62, 0xF1, 0x62, 0xF1, 0xFF, 0x24, - 0x30, 0x48, 0xC0, 0x62, 0x31, 0xCF, 0x00, 0xFF, 0x30, 0x62, 0x61, 0x26, 0xC1, 0x3F, 0x60, 0xFF, - 0x63, 0x60, 0x45, 0x00, 0x0F, 0xF0, 0x5C, 0xF1, 0x62, 0xF1, 0x2C, 0x94, 0x90, 0x30, 0x42, 0x00, - 0xFF, 0x62, 0xC1, 0x54, 0xF0, 0x62, 0xF1, 0x93, 0x30, 0x30, 0x00, 0x3F, 0x30, 0x09, 0x00, 0x03, - 0x00, 0xFF, 0x48, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0xE4, 0x30, 0xDD, 0x31, 0x57, 0x30, 0x03, 0x00, - 0x7B, 0x90, 0xFF, 0xF9, 0x30, 0x62, 0xF1, 0x62, 0xF1, 0x2D, 0x30, 0x2A, 0x00, 0xB7, 0x60, 0x3C, - 0x00, 0x62, 0x61, 0xFF, 0x39, 0x00, 0x7E, 0x60, 0xF6, 0x00, 0x62, 0x62, 0x62, 0xB4, 0x60, 0x54, - 0x00, 0xC7, 0x71, 0x31, 0x45, 0x00, 0xC6, 0x60, 0xAA, 0x31, 0xA2, 0x30, 0x41, 0x01, 0x0C, 0xC0, - 0x53, 0xF1, 0xFF, 0x62, 0xF1, 0x0C, 0x00, 0x18, 0x30, 0x2D, 0x00, 0x62, 0xC1, 0x54, 0x90, 0x2A, - 0x60, 0x48, 0x00, 0xFF, 0xBA, 0x60, 0x2D, 0x00, 0x93, 0x30, 0x1A, 0x61, 0xD2, 0x00, 0x1E, 0x30, - 0x48, 0xF0, 0x15, 0xC0, 0xFF, 0x33, 0x00, 0x6C, 0x00, 0x09, 0x60, 0x27, 0x60, 0x09, 0x00, 0xB3, - 0xB3, 0xB3, 0x1F, 0x0F, 0x00, 0x33, 0x00, 0xBA, 0x00, 0xAE, 0x60, 0x00, 0x00, 0x69, 0x30, 0xA2, - 0x00, 0x7B, 0xC0, 0xFF, 0x18, 0x00, 0x69, 0x60, 0x39, 0x00, 0x12, 0x00, 0x18, 0x00, 0x93, 0x00, - 0x0F, 0x00, 0x21, 0x30, 0xFF, 0x93, 0x93, 0x93, 0x8A, 0x00, 0x12, 0x00, 0x09, 0x00, 0xCB, 0x61, - 0x1E, 0x00, 0xF8, 0x12, 0x30, 0x21, 0x60, 0x69, 0x00, 0x4A, 0x4A, 0x4A, 0x09, 0x00, 0x18, 0x00, - 0xC7, 0x0C, 0x00, 0x9B, 0x9B, 0x9B, 0x12, 0x30, 0x81, 0x81, 0x81, 0x11, 0x3C, 0x60, 0x57, 0x57, - 0x57, 0x0F, 0xF0, 0x33, 0xF0, 0x8A, 0x8A, 0x31, 0x8A, 0x6D, 0x6D, 0x6D, 0x62, 0x31, 0x06, 0x00, - 0x00, 0x00, 0xBB, 0x70, 0xBB, 0xBB, 0xA4, 0xA4, 0xA4, 0x2D, 0x2D, 0x2D, 0x00, 0x06, 0x00, 0x3D, - 0x3D, 0x3D, 0xAC, 0xAC, 0xAC, 0x00, 0x00, 0x81, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x18, 0xF0, 0x62, 0xF1, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x15, 0xF0, 0x00, 0x00, 0x77, 0x7F, 0x77, 0x77, 0x0C, 0xC0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFC, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, - 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, - 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, - 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1F, 0xFF, 0xFF, 0xFF, - 0x0C, 0x0C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x71, 0x43, 0x00, 0x00 -}; +// 21 x 50 @8bpp RGB. +#define BATTERY_EMPTY_WIDTH 21 +#define BATTERY_EMPTY_BATT_HEIGHT 38 +#define BATTERY_EMPTY_CHRG_HEIGHT 12 +#define BATTERY_EMPTY_SIZE 3150 +#define BATTERY_EMPTY_BLZ_SIZE 740 +extern u8 battery_icons_blz[]; -#endif //MENU_LOGO_ENABLE - -// 68 x 192 @8bpp Grayscale RAW. -#define X_BOOTLOGO 68 -#define Y_BOOTLOGO 192 -#define SZ_BOOTLOGO 13056 -#define SZ_BOOTLOGO_BLZ 3988 -static u8 BOOTLOGO_BLZ[SZ_BOOTLOGO_BLZ] = { - 0x0F, 0xF0, 0x80, 0x1B, 0x1B, 0x40, 0xF0, 0x1E, 0x1F, 0x48, 0x5A, 0x0F, 0xF0, 0x0F, 0xF0, 0xE4, - 0x17, 0xF0, 0x91, 0x13, 0x26, 0x28, 0x23, 0x1E, 0x0A, 0xA0, 0x0F, 0xF0, 0xC3, 0x22, 0xF0, 0xC3, - 0xA4, 0x1E, 0x29, 0x33, 0xDB, 0x2C, 0xEA, 0x53, 0x83, 0x0F, 0xF0, 0x38, 0xF0, 0xBC, 0x39, 0x21, - 0x22, 0xB0, 0x87, 0x20, 0x2F, 0x27, 0x3E, 0xDB, 0x35, 0x01, 0xA6, 0x69, 0xF2, 0x3C, 0xFD, 0x25, - 0x2D, 0x38, 0x77, 0x28, 0x15, 0x8A, 0x33, 0x45, 0xDB, 0x09, 0xEF, 0xBB, 0x44, 0xD0, 0xC0, 0x18, - 0xEF, 0x2E, 0x3B, 0xF5, 0x32, 0x25, 0x41, 0xC0, 0x83, 0x52, 0xE1, 0x07, 0xCD, 0x08, 0xF4, 0xF5, - 0x3B, 0x61, 0xB2, 0x95, 0xF1, 0x01, 0x10, 0xE7, 0xA3, 0x02, 0x95, 0x91, 0x3C, 0xFD, 0x41, 0x90, - 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x7F, 0x3D, 0x9B, 0xFA, 0x41, 0xF0, 0x41, 0xF0, 0x0F, - 0xF0, 0x26, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xFE, 0x4C, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x4D, 0xF5, - 0x95, 0x01, 0x9B, 0x02, 0xCD, 0x5D, 0x41, 0xF0, 0xFF, 0x41, 0xF0, 0x4D, 0xF5, 0x77, 0xC5, 0x18, - 0x93, 0xCD, 0x8D, 0x41, 0xF0, 0x41, 0xF0, 0xEB, 0x4D, 0xF5, 0x69, 0xFB, 0x6C, 0xF4, 0x41, 0xF0, - 0x4D, 0xF5, 0x65, 0x3F, 0x28, 0x01, 0x10, 0xBF, 0x03, 0x30, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x30, - 0x45, 0x57, 0x03, 0xE4, 0x03, 0x41, 0xB0, 0xCD, 0xFD, 0x5D, 0x02, 0xCD, 0x1D, 0xC9, 0x1C, 0x2C, - 0x38, 0x3F, 0x3F, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x41, 0x41, 0x41, 0x48, 0x0E, 0x56, 0x61, - 0xF5, 0x41, 0xED, 0xDF, 0xCD, 0xFD, 0x3D, 0xBB, 0x30, 0x2D, 0x6D, 0xB3, 0x6D, 0x4D, 0x15, 0x38, - 0x01, 0x10, 0xE1, 0xF6, 0xD0, 0x3C, 0x27, 0x41, 0xB0, 0xCD, 0xFD, 0xA4, 0xCD, 0x2D, 0xF0, 0x4E, - 0x6F, 0x6C, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x73, 0x73, 0x73, 0x74, 0x75, 0x07, 0x72, 0x68, - 0x31, 0x22, 0x41, 0xD0, 0xA4, 0xF2, 0xCD, 0x3D, 0xE6, 0x1E, 0xF0, 0x36, 0x3D, 0x02, 0x20, 0x03, - 0x30, 0x00, 0x00, 0x40, 0x40, 0x40, 0x1C, 0x3F, 0x3A, 0x31, 0x84, 0x89, 0x21, 0x41, 0xF0, 0xB8, - 0xCB, 0x20, 0x68, 0x23, 0x26, 0x28, 0x2A, 0x2C, 0x2F, 0x2F, 0x2E, 0x00, 0x2B, 0x28, 0x28, 0x01, - 0x10, 0x27, 0x27, 0x27, 0x27, 0x08, 0x26, 0x24, 0x21, 0x08, 0x85, 0x41, 0xF0, 0xCB, 0xF8, 0x21, - 0x28, 0x38, 0x2F, 0x35, 0x38, 0x39, 0x36, 0x31, 0x2B, 0x24, 0x00, 0x1F, 0x1D, 0x01, 0x10, 0x1C, - 0x1C, 0x1C, 0xC3, 0x50, 0x41, 0xF0, 0xC4, 0x39, 0xF8, 0x40, 0x20, 0x2D, 0x3A, 0x56, 0xA8, 0xBE, - 0xBE, 0x03, 0xBE, 0xA7, 0x63, 0x34, 0x42, 0x40, 0x41, 0xF0, 0xB1, 0xF7, 0xA8, 0x02, 0xF0, 0xE5, - 0x06, 0x77, 0xB3, 0x8A, 0x08, 0x25, 0x30, 0x41, 0xAA, 0x11, 0xED, 0xD3, 0xAC, 0xA1, 0xAD, 0xCA, - 0xF5, 0xB2, 0x00, 0x39, 0x37, 0x33, 0x41, 0xF0, 0x41, 0xF0, 0x50, 0x49, 0x6D, 0x71, 0x03, 0x1B, - 0x5E, 0x20, 0x2D, 0x41, 0xAB, 0xE4, 0x80, 0x4E, 0x48, 0x00, 0x46, 0x4A, 0x53, 0x77, 0xE4, 0xBD, - 0x35, 0x24, 0x00, 0x44, 0x94, 0x41, 0xF0, 0x4D, 0xF5, 0x09, 0x15, 0x26, 0x3A, 0x7C, 0xF5, 0x0F, - 0x7F, 0x45, 0x37, 0x30, 0x2F, 0x32, 0x3F, 0x51, 0x00, 0x78, 0xF5, 0x74, 0x2D, 0xAE, 0x32, 0x41, - 0xF0, 0x4D, 0xF5, 0x9D, 0x6A, 0xF0, 0x1F, 0x2D, 0x45, 0xC1, 0xC1, 0x47, 0x30, 0x23, 0x00, 0x1F, - 0x1F, 0x21, 0x2A, 0x3D, 0x54, 0xC1, 0xBE, 0x00, 0x35, 0x22, 0x01, 0x10, 0x41, 0xF0, 0xA5, 0xF2, - 0x3D, 0x44, 0x15, 0x0A, 0x20, 0x7C, 0x33, 0x4C, 0xED, 0x88, 0x39, 0x24, 0x84, 0x10, 0x1F, 0x40, - 0x2F, 0x49, 0x8D, 0xED, 0x3B, 0x44, 0x0D, 0x41, 0xF0, 0x41, 0xF0, 0xE0, 0x64, 0x02, 0x27, 0x0B, - 0xBB, 0xB3, 0xB5, 0x13, 0x21, 0x37, 0x4F, 0x13, 0xF5, 0x49, 0x30, 0xED, 0x21, 0x1D, 0x28, 0x40, - 0x55, 0x08, 0xF5, 0x3F, 0x15, 0x40, 0x41, 0xF0, 0x2D, 0xF3, 0xAF, 0x07, 0x2D, 0x41, 0x50, 0xBC, - 0x42, 0x2C, 0xB8, 0x32, 0x24, 0x3B, 0x52, 0xF5, 0x40, 0x04, 0xB1, 0xF7, 0x1B, 0x41, 0xF0, 0x41, - 0xF0, 0x41, 0x41, 0xD0, 0x41, 0xF0, 0x41, 0xF0, 0xED, 0x79, 0xF7, 0x41, 0xF0, 0x41, 0xF0, 0xD0, - 0xD9, 0x8A, 0x8A, 0x8A, 0x8A, 0x0F, 0x8A, 0x93, 0xAC, 0x09, 0x50, 0x29, 0xB7, 0xF9, 0xF3, 0x41, - 0xF0, 0x8C, 0x0D, 0xF8, 0x81, 0x1F, 0x0F, 0x81, 0xBB, 0x81, 0x41, 0x10, 0x50, 0xF5, 0x22, 0x45, - 0x30, 0x70, 0x33, 0x29, 0x3F, 0x54, 0xF5, 0x46, 0x04, 0x30, 0x72, 0x23, 0x20, 0x71, 0xE3, 0xA5, - 0xF2, 0x3D, 0x20, 0x77, 0x9B, 0x3A, 0xAD, 0x16, 0x52, 0xF5, 0x52, 0x09, 0x00, 0x07, 0x10, 0x3B, - 0x4E, 0x31, 0x61, 0xF5, 0x54, 0x41, 0x35, 0x35, 0x35, 0x35, 0x00, 0x34, 0x30, 0x29, 0x21, 0x0D, - 0xF1, 0x41, 0xF0, 0x11, 0x4E, 0x36, 0x70, 0x50, 0xF5, 0xAF, 0x09, 0x00, 0x07, 0x10, 0xAA, 0xAF, - 0xB4, 0x18, 0xF5, 0xB1, 0xAC, 0xA9, 0xA9, 0xA9, 0xA9, 0xA8, 0x00, 0xA5, 0xA2, 0x99, 0xCE, 0x1D, - 0xF2, 0xA1, 0x22, 0x11, 0x3E, 0x30, 0x46, 0x3C, 0xC1, 0xC2, 0x09, 0x10, 0x06, 0x10, 0xC2, 0xC4, - 0xC5, 0xC3, 0x0C, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0xBD, 0xBA, 0x00, 0x2A, 0x41, 0xB0, 0x6D, - 0xF7, 0x41, 0x00, 0x8A, 0xA4, 0x3D, 0x8A, 0x0E, 0xA4, 0x95, 0x01, 0x27, 0x35, 0x43, 0x49, 0x09, - 0x00, 0x07, 0x10, 0xC2, 0x49, 0x4B, 0x4E, 0x4F, 0x4C, 0x49, 0x48, 0x48, 0x00, 0x48, 0x48, 0x46, - 0x40, 0x34, 0x51, 0x91, 0x41, 0xF0, 0x01, 0x10, 0xE0, 0xC7, 0x00, 0x9B, 0xBB, 0xB3, 0x4A, 0xC9, - 0x10, 0x25, 0x2C, 0x21, 0x01, 0x10, 0x06, 0x30, 0x31, 0x31, 0x31, 0x00, 0x00, 0x30, 0x30, 0x23, - 0x30, 0x2C, 0x27, 0xC9, 0x00, 0x41, 0xF0, 0xA1, 0xF2, 0x42, 0x40, 0x06, 0x60, 0xF8, 0x03, 0x30, - 0x00, 0x00, 0x1F, 0xDD, 0xA6, 0x41, 0xF0, 0xBF, 0xF3, 0x02, 0x20, 0xCD, 0xFD, 0xFB, 0x95, 0xF1, - 0x17, 0xD6, 0x62, 0x6D, 0x62, 0x2D, 0x90, 0x48, 0x29, 0x43, 0x2E, 0x03, 0x30, 0x03, 0x30, 0x00, - 0x00, 0x2F, 0x2F, 0x2F, 0x2B, 0x0E, 0x7D, 0xF8, 0x95, 0xF1, 0xB3, 0x9B, 0xAC, 0x95, 0x21, 0x1D, - 0x23, 0x23, 0x2F, 0x60, 0x66, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x68, 0x68, 0x38, 0x68, 0x67, - 0x63, 0x5B, 0x27, 0x85, 0x10, 0x41, 0xF0, 0x0D, 0xF1, 0xE0, 0x39, 0x03, 0x28, 0x39, 0x07, 0x70, - 0x03, 0x30, 0x00, 0x00, 0xF5, 0xF5, 0x39, 0xF5, 0x2C, 0x20, 0x41, 0x90, 0x41, 0xF0, 0x27, 0x1B, - 0x25, 0x2B, 0xF5, 0x17, 0xF8, 0x34, 0x44, 0x4F, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x52, 0x52, - 0x38, 0x52, 0x51, 0x49, 0x3A, 0x29, 0xE0, 0x12, 0x41, 0xF0, 0x2D, 0xF3, 0xE0, 0x42, 0x00, 0x20, - 0x28, 0x31, 0x38, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE1, 0x39, 0x39, 0x39, 0x34, 0x2C, 0x23, - 0xA9, 0xBF, 0xE9, 0xF2, 0xC0, 0xAC, 0x32, 0x4A, 0xBB, 0x3B, 0x27, 0x20, 0x21, 0xAC, 0xCF, 0x22, - 0x49, 0x22, 0xA9, 0xFF, 0xB5, 0xF3, 0xEA, 0x2F, 0x57, 0xAC, 0xAD, 0x63, 0x38, 0xF0, 0xCE, 0x41, - 0xF0, 0xDD, 0xFE, 0xA4, 0x9B, 0xA4, 0xBB, 0x81, 0x06, 0x60, 0x83, 0x37, 0xF0, 0x41, 0xF0, 0xD6, - 0xF5, 0xC3, 0x00, 0xD4, 0xC5, 0x1D, 0xF0, 0x41, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x19, 0xF0, - 0x41, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x41, 0xF0, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x6D, - 0x6D, 0xD9, 0xC1, 0x33, 0xF0, 0x41, 0xF0, 0x15, 0xFA, 0x03, 0x30, 0xF9, 0x23, 0xF0, 0x41, 0xF0, - 0x41, 0xF0, 0x19, 0xF0, 0xE2, 0x3F, 0x20, 0x91, 0xAD, 0x1B, 0x5F, 0x41, 0xF0, 0x24, 0xF0, 0xA6, - 0xD2, 0x24, 0x2A, 0x56, 0x26, 0x61, 0xD2, 0x87, 0x41, 0xF0, 0xF8, 0xCC, 0xD9, 0xC1, 0x2C, 0x39, - 0xF5, 0x31, 0x24, 0x07, 0x15, 0x90, 0x41, 0xF0, 0xA5, 0xF2, 0x15, 0xD0, 0x46, 0xF5, 0x15, 0x10, - 0x41, 0xF0, 0xCF, 0xE5, 0xF6, 0x57, 0xBB, 0x00, 0x00, 0x57, 0x57, 0x57, 0x77, 0x09, 0x7D, 0xC0, - 0x22, 0x38, 0x4D, 0xF5, 0x3F, 0xC9, 0x50, 0x41, 0xF0, 0xC1, 0xBC, 0xBC, 0xBB, 0x00, 0x00, 0xAC, - 0xAC, 0xAC, 0xA4, 0xA5, 0x92, 0x85, 0x41, 0xF0, 0x41, 0xF0, 0xD9, 0xF1, 0x41, 0xF0, 0x39, 0x4F, - 0xF5, 0x40, 0x0F, 0xCE, 0x14, 0x41, 0xF0, 0x41, 0xF0, 0xD5, 0x3D, 0x85, 0xF5, 0x37, 0x4B, 0xF5, - 0x1F, 0x3E, 0x46, 0x74, 0x41, 0xF0, 0x26, 0xF0, 0x15, 0xF0, 0x32, 0x44, 0xF5, 0x1E, 0x39, 0xEE, - 0x76, 0x1B, 0x41, 0xF0, 0xA5, 0xF2, 0x6D, 0xFC, 0x36, 0x7C, 0x3A, 0x2F, 0x23, 0x15, 0xB0, 0x41, - 0xF0, 0xA5, 0xF2, 0x71, 0xAB, 0x22, 0x28, 0x3C, 0x2A, 0x25, 0x1F, 0x15, 0x90, 0x41, 0xF0, 0xA5, - 0xF2, 0x11, 0xC0, 0x6E, 0x0C, 0xF8, 0xE3, 0xAE, 0x41, 0xF0, 0xA5, 0xF2, 0x41, 0xC0, 0x33, 0xF0, - 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0x33, - 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0A, 0xA0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x09, 0x90, - 0x1E, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x04, 0x40, 0xFF, 0x25, 0xF0, 0xD5, 0xF5, 0x41, 0xF0, 0x53, - 0xF2, 0x85, 0xFE, 0x4D, 0xF5, 0xE3, 0xFA, 0x81, 0x7F, 0x8A, 0x81, 0xA9, 0x3B, 0x1E, 0x21, 0x26, - 0x26, 0x23, 0x04, 0x1F, 0x1C, 0x33, 0xAD, 0x24, 0x28, 0x29, 0x26, 0x05, 0x89, 0x84, 0x41, 0xF0, - 0x47, 0x20, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0xA4, 0x03, 0x2D, 0x81, 0x24, 0x40, 0x41, 0x39, 0x28, - 0x1F, 0xCB, 0x18, 0x82, 0x21, 0x21, 0x20, 0x1E, 0x1B, 0x2A, 0x24, 0x68, 0x6A, 0x20, 0x62, 0x2B, - 0x3D, 0xA4, 0x41, 0xF0, 0x93, 0xA4, 0x58, 0x16, 0x2D, 0x4C, 0xA4, 0x93, 0x10, 0x10, 0x4C, 0x10, - 0x10, 0x23, 0x84, 0x09, 0x2B, 0x54, 0x35, 0x37, 0xBB, 0x07, 0x96, 0x1F, 0x4F, 0x2E, 0x00, 0x39, - 0x24, 0x2C, 0x41, 0xA0, 0x41, 0xF0, 0x55, 0x31, 0x3D, 0x2D, 0x23, 0x63, 0x18, 0x29, 0x34, 0x04, - 0xD7, 0x41, 0xC7, 0xC8, 0xC4, 0x31, 0x21, 0x0E, 0x5F, 0x46, 0x40, 0xA1, 0xB6, 0x55, 0xFE, 0x9A, - 0x52, 0x10, 0x70, 0x34, 0x64, 0xB2, 0x14, 0x6E, 0x2E, 0x00, 0xBF, 0x4D, 0xA5, 0xB2, 0x65, 0xFF, - 0xA5, 0x36, 0x6D, 0xAC, 0x10, 0x70, 0x34, 0x64, 0xCE, 0x2E, 0x40, 0x41, 0xF0, 0xD2, 0xD9, 0xBB, - 0x77, 0x2D, 0x1B, 0x2D, 0x07, 0x77, 0xBB, 0x6D, 0x10, 0x70, 0x34, 0x64, 0x2E, 0x40, 0x41, 0xF0, - 0x08, 0xE9, 0xF8, 0x98, 0x1E, 0xAC, 0x62, 0x41, 0xC0, 0x41, 0xF0, 0x41, 0xF0, 0x77, 0xC8, 0x41, - 0x60, 0xF9, 0x41, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xB5, 0xF3, 0x07, 0x60, 0xA2, 0xF3, 0x41, 0xF0, - 0x71, 0xF3, 0xFF, 0x06, 0x20, 0x07, 0x40, 0x55, 0x32, 0x24, 0x24, 0x2B, 0x47, 0x03, 0x44, 0x09, - 0x41, 0xF0, 0x47, 0xBD, 0x8A, 0x81, 0x4A, 0x1B, 0x77, 0x07, 0xB3, 0xBB, 0xD5, 0x55, 0x06, 0x20, - 0x07, 0x40, 0x6B, 0x44, 0x05, 0x46, 0x5C, 0x5E, 0xBC, 0x08, 0x41, 0xF0, 0xC8, 0xB4, 0x93, 0x73, - 0x07, 0xAC, 0x62, 0x2E, 0x3D, 0x6D, 0xAC, 0x3D, 0x34, 0x06, 0x20, 0x07, 0x40, 0xD1, 0xCF, 0x38, - 0xCD, 0xCD, 0xCF, 0xD1, 0xD2, 0x41, 0xC0, 0x91, 0xF5, 0x77, 0x60, 0x80, 0x14, 0x8D, 0x15, 0x57, - 0xBB, 0xA5, 0x32, 0x40, 0xF0, 0x92, 0x52, 0x41, 0xF0, 0xF3, 0x41, 0xF0, 0x1D, 0x02, 0x3E, 0x6D, - 0x01, 0x10, 0x3D, 0xF0, 0x4C, 0x0A, 0x12, 0xB3, 0x41, 0xF0, 0x41, 0xF0, 0xF1, 0x1B, 0x61, 0x01, - 0x10, 0x29, 0xF3, 0x44, 0x21, 0x8F, 0xB7, 0x41, 0xF0, 0x03, 0x20, 0x61, 0x5B, 0x1F, 0x21, 0xFF, - 0x21, 0xFF, 0xD5, 0xF5, 0x03, 0x20, 0xF7, 0xAE, 0x27, 0xBB, 0x1B, 0xF6, 0x1F, 0x47, 0x51, 0x52, - 0x50, 0x09, 0x21, 0xAF, 0x4E, 0x4E, 0x4B, 0x44, 0x38, 0x65, 0x2F, 0x41, 0xF0, 0xC1, 0xB1, 0xF7, - 0x51, 0x04, 0x25, 0x32, 0x41, 0x45, 0x3F, 0x34, 0x03, 0x21, 0x0F, 0x03, 0x30, 0x00, 0x00, 0x1E, - 0x0F, 0x29, 0x28, 0x24, 0x02, 0x6A, 0x8F, 0x41, 0xF0, 0x45, 0xFD, 0x42, 0x34, 0x0F, 0x34, 0x24, - 0x01, 0x10, 0x03, 0x30, 0xCB, 0x00, 0x00, 0x1D, 0x35, 0x59, 0x41, 0xF0, 0x19, 0xF0, 0x34, 0xBF, - 0x1B, 0xF0, 0x41, 0xF0, 0xFD, 0x19, 0xF0, 0xB5, 0x83, 0x1E, 0xF0, 0x41, 0xF0, 0x1C, 0xF0, 0x21, - 0x9F, 0x2D, 0x83, 0x15, 0xF0, 0xFF, 0x41, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x91, 0xD5, 0x41, 0xF0, - 0x41, 0xF0, 0x57, 0x34, 0x3F, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x26, 0x26, 0x26, 0x24, 0x21, - 0x07, 0x1E, 0x1C, 0x41, 0x80, 0x51, 0xF1, 0x99, 0xFE, 0x6D, 0x51, 0x04, 0x40, 0x9C, 0x45, 0x00, - 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x32, 0x02, 0x26, 0x01, 0xDD, 0x38, 0xAC, 0xAA, 0x83, 0x41, - 0x50, 0xE1, 0xE1, 0x04, 0x40, 0x9E, 0xE0, 0x00, 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0xDE, 0xDA, 0x02, - 0x34, 0x22, 0x41, 0xC0, 0xC4, 0xA8, 0x4A, 0xB2, 0x73, 0x41, 0x50, 0x3E, 0xF0, 0xEC, 0x85, 0xF0, - 0xCD, 0xB0, 0x81, 0xDB, 0x31, 0x8A, 0xBB, 0x77, 0x41, 0x50, 0x8B, 0x3E, 0xF0, 0x69, 0xFB, 0xCA, - 0xD0, 0x57, 0xB2, 0x13, 0x9B, 0x3D, 0x65, 0x7F, 0x97, 0xDD, 0xFA, 0x41, 0xE1, 0xFA, 0xC7, 0xC0, - 0x8A, 0x9B, 0xB3, 0x6D, 0x0D, 0x41, 0x80, 0x7E, 0x76, 0x04, 0x40, 0x70, 0x00, 0x00, 0x70, 0x70, - 0x29, 0x70, 0x6E, 0x63, 0x4C, 0x35, 0xCC, 0x51, 0xF1, 0x81, 0xBB, 0x30, 0xBB, 0x6D, 0x01, 0x9D, - 0x6A, 0x4C, 0x04, 0x40, 0x40, 0x00, 0x00, 0xA4, 0x40, 0xD1, 0xD9, 0x41, 0xF0, 0xF5, 0x0F, 0xA4, - 0xAC, 0x62, 0x77, 0x0E, 0xE7, 0x02, 0xBD, 0x7C, 0x54, 0x30, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, - 0x22, 0x73, 0x22, 0x22, 0x21, 0x1F, 0xA5, 0xD2, 0x2D, 0xF3, 0x5F, 0x32, 0x79, 0x8C, 0xF0, 0x3A, - 0xD1, 0x1C, 0xF7, 0x83, 0x21, 0x2D, 0xF3, 0xAC, 0x57, 0xD7, 0x41, 0x95, 0xB3, 0x9B, 0x35, 0x1C, - 0xF1, 0x1B, 0x4F, 0x70, 0x46, 0x85, 0x61, 0x27, 0x6C, 0x25, 0x20, 0x6D, 0xD7, 0xD8, 0xA5, 0xCA, - 0x79, 0x9B, 0x7C, 0x7B, 0xB8, 0x70, 0xDC, 0xBD, 0x04, 0x34, 0x3E, 0x41, 0x80, 0x2B, 0xE5, 0x56, - 0x41, 0xF0, 0xC1, 0x05, 0xF9, 0x59, 0xF0, 0xF0, 0xEF, 0xDC, 0x60, 0x1D, 0x20, 0x21, 0x09, 0x05, - 0x4A, 0x6B, 0xB9, 0xE6, 0xFF, 0x39, 0xC9, 0x10, 0x81, 0x41, 0xF0, 0x3B, 0xF0, 0x59, 0x2A, 0x54, - 0x58, 0x49, 0x30, 0x21, 0x07, 0xC1, 0x50, 0x81, 0x04, 0xA4, 0x17, 0x26, 0xC5, 0x24, 0x41, 0xF0, - 0xC3, 0xF0, 0xF5, 0x17, 0xFB, 0x29, 0x32, 0x33, 0x2E, 0x24, 0x1E, 0xC1, 0x50, 0x7C, 0x40, 0xBC, - 0x80, 0x30, 0x09, 0xF5, 0xAC, 0xCF, 0xA9, 0x6F, 0x85, 0x20, 0x1F, 0x1F, 0x3E, 0x1F, 0xD3, 0x19, - 0x2F, 0x39, 0x49, 0xC1, 0x00, 0x2C, 0x63, 0x71, 0xE3, 0xE2, 0x5F, 0xBA, 0x00, 0x00, 0x5A, 0x0A, - 0x4A, 0x93, 0xBB, 0x77, 0x76, 0x53, 0x87, 0x24, 0x2B, 0x35, 0x42, 0x52, 0x98, 0xC1, 0x60, 0xF1, - 0x40, 0xC0, 0x90, 0x4D, 0xE9, 0xF2, 0x1B, 0x1B, 0xCE, 0xF9, 0x9B, 0x48, 0x3D, 0xEE, 0x32, 0x22, - 0x28, 0x31, 0x3E, 0x4D, 0x7B, 0x02, 0xBC, 0xF0, 0x1C, 0x62, 0xA6, 0x6C, 0x55, 0x42, 0x61, 0xF2, - 0x84, 0xD2, 0xF9, 0x93, 0xB3, 0x54, 0x1A, 0x45, 0x2D, 0x37, 0x47, 0x69, 0x19, 0xB0, 0xE0, 0x94, - 0x51, 0xDA, 0x36, 0x00, 0x6A, 0x45, 0x30, 0x14, 0x27, 0x21, 0x91, 0xA5, 0x41, 0xF0, 0xBF, 0x1C, - 0x93, 0x3D, 0x51, 0x61, 0x9C, 0x92, 0xCF, 0xF8, 0x3E, 0x60, 0x88, 0x7F, 0x51, 0x11, 0x30, 0x48, - 0x1F, 0x1D, 0x41, 0xF0, 0x4D, 0xC9, 0x9B, 0xAC, 0x62, 0xA1, 0x66, 0x8C, 0x32, 0x56, 0x11, 0x41, - 0xDA, 0xB7, 0x7C, 0x5F, 0x55, 0x04, 0x62, 0xC9, 0x10, 0x50, 0x41, 0x00, 0x41, 0xF0, 0x93, 0xB5, - 0xBB, 0x81, 0x3A, 0xC6, 0x54, 0x41, 0x60, 0xF8, 0xC1, 0x8A, 0x77, 0x5F, 0x4A, 0x03, 0x39, 0x35, - 0x41, 0x60, 0x41, 0xF0, 0x84, 0xA4, 0xBB, 0x9B, 0xD5, 0x65, 0x9C, 0x2D, 0x13, 0x89, 0x4D, 0xDA, - 0xAC, 0x6E, 0x49, 0x39, 0x34, 0x03, 0x49, 0x74, 0x41, 0x40, 0x41, 0xF0, 0xE0, 0xFE, 0x4D, 0x55, - 0x1F, 0x32, 0x3C, 0x57, 0xD1, 0xD1, 0x40, 0xF8, 0xD6, 0x9E, 0x52, 0x61, 0x04, 0x7C, 0xC6, 0xA8, - 0x41, 0xF0, 0x3B, 0xF0, 0x1D, 0x12, 0x3E, 0x5B, 0x80, 0x1E, 0xD1, 0x60, 0xF8, 0xD1, 0xB0, 0x3A, - 0x00, 0x55, 0x2F, 0x14, 0x8E, 0x91, 0x1B, 0x41, 0xF0, 0x95, 0xF1, 0x29, 0x38, 0xD1, 0x00, 0x8F, - 0xC1, 0x26, 0xF1, 0x8A, 0x75, 0x69, 0x43, 0x2F, 0x27, 0x21, 0x42, 0x30, 0x82, 0x41, 0xF0, 0x3A, - 0xF0, 0x68, 0x2B, 0xD1, 0x90, 0x98, 0x22, 0xB9, 0x72, 0x41, 0x1F, 0xF5, 0x23, 0x41, 0xF0, 0x3C, - 0xF0, 0xD1, 0xA0, 0x54, 0x67, 0x82, 0xB8, 0x0F, 0xE1, 0xAF, 0x53, 0xE6, 0xAF, 0xC5, 0x24, 0x41, - 0xF0, 0x3B, 0xF0, 0xD1, 0x90, 0xF2, 0x2F, 0x3B, 0x49, 0x5B, 0x6C, 0x90, 0xC1, 0xF1, 0x00, 0xC5, - 0x54, 0x1D, 0x32, 0x41, 0xF0, 0x39, 0xF0, 0xD1, 0x80, 0x23, 0x29, 0x33, 0x1F, 0x3F, 0x4F, 0x61, - 0x72, 0xA5, 0xD2, 0x95, 0xB1, 0x41, 0xF0, 0xC0, 0x40, 0xF0, 0xE1, 0x0D, 0xC4, 0x5D, 0x1F, 0x25, - 0x2C, 0x36, 0x44, 0x07, 0x55, 0x68, 0x83, 0xC1, 0xE9, 0x51, 0x41, 0x41, 0xF0, 0xAF, 0xF3, 0xE0, - 0xD1, 0x19, 0x25, 0x27, 0x23, 0x1E, 0x25, 0xE0, 0x3F, 0x21, 0x27, 0x31, 0x30, 0x3B, 0x4D, 0x65, - 0x79, 0x9C, 0xDE, 0x99, 0xDE, 0x80, 0x15, 0xFA, 0x00, 0x00, 0x8A, 0x8A, 0x8A, 0x8A, 0x49, 0x19, - 0x35, 0x43, 0xA9, 0x36, 0x2A, 0x2E, 0x52, 0xD9, 0x22, 0x27, 0x35, 0x4F, 0x18, 0x6B, 0x99, 0xEF, - 0x44, 0x41, 0xB0, 0x7D, 0xF8, 0xB3, 0x81, 0x30, 0xE9, 0x52, 0x20, 0x31, 0x4B, 0xFF, 0xB2, 0x43, - 0x2C, 0x01, 0x21, 0xE9, 0x61, 0x1D, 0x21, 0x2B, 0x40, 0x5E, 0xBF, 0x02, 0x9D, 0xEA, 0x41, 0xF0, - 0x69, 0x3F, 0x71, 0x33, 0x60, 0x98, 0x00, 0x49, 0x30, 0x2F, 0x16, 0x59, 0x1E, 0x24, 0x31, 0x48, - 0x80, 0x42, 0x11, 0x4A, 0x41, 0x91, 0xB5, 0x51, 0xF1, 0x31, 0x81, 0x3D, 0x1C, 0x15, 0xE7, 0x6F, - 0x34, 0x17, 0x25, 0x1E, 0x44, 0x41, 0x52, 0xA8, 0xF8, 0xF5, 0x37, 0x41, 0xF0, 0xC4, 0x0E, 0xAE, - 0x70, 0x5B, 0x45, 0x1D, 0x89, 0x2D, 0xF0, 0x81, 0x39, 0x27, 0x0F, 0x1F, 0x1C, 0x1D, 0x22, 0x2E, - 0x42, 0x6E, 0xD8, 0x00, 0x82, 0x20, 0xD5, 0x3F, 0xF5, 0xB7, 0x41, 0xF0, 0xB3, 0x6D, 0x8A, 0x39, - 0x99, 0xBD, 0x1C, 0x54, 0xAE, 0xD2, 0x10, 0xF8, 0x9D, 0x3D, 0x29, 0x09, 0x22, 0x27, 0x35, 0x4D, - 0x90, 0xF0, 0x18, 0x22, 0xA9, 0x40, 0x4F, 0x30, 0xF5, 0x27, 0x41, 0xF0, 0xC4, 0x7C, 0x8D, 0x69, - 0x1D, 0x27, 0x3C, 0x3C, 0x60, 0x9B, 0x57, 0x11, 0xFF, 0xB6, 0x46, 0x39, 0x08, 0x41, 0x5A, 0xC7, - 0x40, 0x20, 0xE1, 0x84, 0x4D, 0x34, 0x08, 0x24, 0xF5, 0xB7, 0x71, 0xF3, 0x8A, 0x2D, 0x42, 0x70, - 0x29, 0x3E, 0x26, 0x5B, 0x85, 0x05, 0x20, 0xCE, 0x65, 0x86, 0xE9, 0x7F, 0x20, 0x84, 0xBF, 0x60, - 0x43, 0x2F, 0x23, 0xC5, 0x10, 0x41, 0xF0, 0xE9, 0xF2, 0xE0, 0x68, 0x3B, 0x28, 0x39, 0x55, 0x75, - 0x56, 0x21, 0xE9, 0x82, 0x20, 0xA1, 0xE9, 0x94, 0x52, 0xEC, 0x02, 0x25, 0xDB, 0x61, 0xF2, 0x42, - 0xA0, 0x1E, 0x78, 0x25, 0x34, 0x4F, 0x70, 0xC1, 0x4B, 0x51, 0xC9, 0x64, 0x20, 0x47, 0x31, 0x25, - 0x1E, 0x41, 0xE0, 0x85, 0xF0, 0x9B, 0x2D, 0x30, 0x1B, 0x90, 0x1D, 0x22, 0x30, 0x49, 0x6A, 0xAF, - 0xF8, 0x01, 0xCB, 0x10, 0xF1, 0xA5, 0x5F, 0x3E, 0x2B, 0x21, 0x1D, 0x01, 0xD1, 0xE9, 0x41, 0xF0, - 0xBC, 0x0C, 0x3B, 0x34, 0x28, 0x17, 0x1F, 0x21, 0x23, 0x1F, 0x25, 0x2A, 0x36, 0x4C, 0x6C, 0x9D, - 0xF1, 0x42, 0x10, 0x80, 0x99, 0x51, 0x34, 0x28, 0x25, 0x24, 0x24, 0x22, 0x00, 0x20, 0x1E, 0x49, - 0xC9, 0x8D, 0xF9, 0x8B, 0x39, 0xA1, 0x16, 0x21, 0x2B, 0x3C, 0x37, 0x3D, 0x41, 0x41, 0x45, 0x4F, - 0x63, 0x7C, 0x00, 0x8A, 0xE9, 0x42, 0x10, 0x8C, 0x4C, 0x42, 0x40, 0x40, 0x04, 0x3F, 0x39, 0x30, - 0x25, 0x1E, 0x0C, 0x30, 0x41, 0xF0, 0xE5, 0xF6, 0xE0, 0x2B, 0x41, 0xC8, 0xCC, 0xCD, 0xCD, 0xCE, - 0xCF, 0x00, 0xD0, 0xD2, 0xD2, 0xD2, 0x37, 0x10, 0xF8, 0xD0, 0xCE, 0x10, 0xCD, 0xCD, 0xCD, 0xCA, - 0xC4, 0x31, 0xD9, 0x11, 0x41, 0xF0, 0xC0, 0x5B, 0xF2, 0xEC, 0x51, 0xFF, 0x3D, 0xF0, 0xD9, 0xF1, - 0xD8, 0xE1, 0x81, 0x8A, 0x3B, 0x81, 0xDA, 0x01, 0x9D, 0x1A, 0x66, 0x00, 0x00, 0x3E, 0xF0, 0x9D, - 0xFA, 0x2F, 0xE7, 0xF6, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0x3B, 0x10, 0x20, 0x38, 0x20, 0x5F, 0x01, - 0x10, 0xF5, 0xF3, 0x43, 0xE5, 0x36, 0x41, 0xF0, 0x25, 0x52, 0xA4, 0x76, 0x09, 0x19, 0x2D, 0x3D, - 0x14, 0x1F, 0x2F, 0x49, 0x99, 0xA1, 0x05, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0xA4, 0xA4, 0xA4, - 0xA3, 0x9D, 0x07, 0x8E, 0x36, 0x23, 0x41, 0x70, 0x41, 0xF0, 0x41, 0x14, 0xE5, 0x76, 0x26, 0x78, - 0x35, 0x45, 0x4F, 0x52, 0x4F, 0x03, 0x30, 0x4E, 0x00, 0x00, 0xA0, 0x4E, 0x4E, 0x4E, 0x4F, 0x52, - 0x52, 0x4B, 0x3C, 0x00, 0x2A, 0x41, 0x00, 0x41, 0xF0, 0xA5, 0xF2, 0xA1, 0x16, 0x24, 0x30, 0x3D, - 0x1E, 0x41, 0x3C, 0x32, 0x2D, 0x2A, 0xC0, 0x44, 0x2A, 0x2A, 0x20, 0x2A, 0x2B, 0x31, 0x3A, 0x44, - 0x42, 0x39, 0x28, 0x00, 0x09, 0xA5, 0x41, 0xF0, 0xAC, 0x30, 0x37, 0x6D, 0x05, 0x09, 0x1F, 0x2A, - 0x2B, 0x3F, 0xB1, 0xB2, 0xAD, 0x31, 0x23, 0x1D, 0x1E, 0x00, 0x20, 0x26, 0x8A, 0x04, 0x22, 0x1F, - 0x1D, 0x1D, 0x20, 0x04, 0x2D, 0x44, 0xC8, 0xC8, 0xC5, 0x32, 0x21, 0x41, 0xC0, 0x80, 0xA8, 0xE6, - 0x77, 0x2D, 0x1B, 0x2D, 0x77, 0xE5, 0x16, 0x20, 0x41, 0x34, 0x57, 0x10, 0x00, 0x3E, 0x25, 0x30, - 0x18, 0x68, 0x6A, 0x24, 0x43, 0x28, 0x20, 0x35, 0x5A, 0x2E, 0x00, 0x40, 0x09, 0x75, 0x41, 0xF0, - 0xD1, 0xB5, 0x27, 0xAC, 0x4A, 0x05, 0xAC, 0x62, 0x1B, 0xE9, 0x22, 0x10, 0x20, 0xC5, 0x30, 0x18, - 0x43, 0x48, 0x21, 0x3C, 0x6B, 0x2E, 0x00, 0xE9, 0xF2, 0x95, 0xF5, 0xE3, 0x3D, 0xA3, 0x16, 0x10, - 0x70, 0x30, 0x08, 0x74, 0x18, 0x46, 0x28, 0x4E, 0x22, 0x9E, 0x61, 0xF2, 0x95, 0xF1, 0x22, 0xF6, - 0x14, 0x02, 0x6E, 0x07, 0x00, 0x4D, 0x29, 0x2F, 0x2E, 0x20, 0x41, 0xF0, 0x2D, 0xF3, 0x22, 0x40, - 0x93, 0x10, 0x30, 0x41, 0xF0, 0x41, 0xF0, 0xEF, 0xC9, 0xF0, 0x80, 0x44, 0xBB, 0x10, 0x50, 0x41, - 0xF0, 0x41, 0xF0, 0x4F, 0xC5, 0xBB, 0x7B, 0x4C, 0x35, 0xB3, 0xA4, 0x10, 0x70, 0x07, 0x60, 0x2E, - 0x40, 0x41, 0xF0, 0xA8, 0xB2, 0xF9, 0x6D, 0xBB, 0x00, 0x00, 0x6D, 0x7A, 0x08, 0x2D, 0x41, 0x20, - 0x06, 0x20, 0xD4, 0xD5, 0x65, 0xCB, 0x25, 0x41, 0xF0, 0x51, 0xF1, 0x41, 0xA0, 0x06, 0x20, 0xD5, - 0x65, 0xCB, 0x25, 0xFF, 0x41, 0xA0, 0x41, 0xF0, 0x41, 0xF0, 0x06, 0x20, 0xD5, 0x65, 0xCB, 0x25, - 0x41, 0xB0, 0x41, 0xF0, 0xFF, 0xCE, 0xF4, 0x40, 0xF0, 0x33, 0x24, 0x41, 0x80, 0x41, 0xF0, 0x9A, - 0x21, 0x2D, 0x8A, 0x3F, 0xAC, 0x98, 0x16, 0x22, 0x3F, 0x6F, 0x01, 0x10, 0x3D, 0xF0, 0x4E, 0x62, - 0x29, 0x41, 0x90, 0x41, 0xF0, 0x8A, 0xAC, 0x4A, 0x1B, 0x9B, 0x06, 0xA4, 0x6D, 0xA4, 0x93, 0x1D, - 0x12, 0x69, 0x01, 0x10, 0xD5, 0xF1, 0xD0, 0x49, 0x1D, 0xC2, 0x85, 0xF0, 0x3D, 0x00, 0x3D, 0x1B, - 0x3D, 0xD5, 0x45, 0x8E, 0xD5, 0xF5, 0xD5, 0xF5, 0x41, 0xF0, 0xC7, 0x00, 0x7D, 0x14, 0xBB, 0xD5, - 0x25, 0xD5, 0xF5, 0xDF, 0xD5, 0xF5, 0x41, 0xF0, 0x44, 0x00, 0x8A, 0x8A, 0xCB, 0x15, 0xD5, 0x85, - 0xD5, 0xF5, 0xE7, 0x41, 0xF0, 0x3A, 0xB4, 0x93, 0xBB, 0x4A, 0x1B, 0x4A, 0xA4, 0x03, 0x77, 0xB5, - 0x13, 0x22, 0x28, 0x2A, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE2, 0x2B, 0x2B, 0x2B, 0x28, 0x24, - 0x1F, 0x1D, 0xD2, 0x23, 0xE2, 0xC0, 0x77, 0x4A, 0x9F, 0x12, 0xDA, 0x11, 0x23, 0x2E, 0x3A, 0x41, - 0x0C, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x07, 0x32, 0x26, 0x95, - 0x11, 0x41, 0xF0, 0x3B, 0xF0, 0x0D, 0x11, 0x45, 0xDC, 0x3C, 0xDF, 0x02, 0x20, 0x03, 0x30, 0x00, - 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0x0E, 0xDE, 0xDA, 0x0D, 0x21, 0x41, 0xF0, 0xC3, 0xF0, 0x85, 0x10, - 0x5D, 0x01, 0x10, 0xBC, 0x3D, 0xF0, 0x41, 0x26, 0x41, 0x90, 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x57, 0x79, 0x57, 0x24, 0x03, 0x21, 0x3B, 0x67, 0x01, 0x10, 0x3D, 0xF0, 0x48, 0x62, 0x71, 0xA3, - 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xBB, 0x85, 0x00, 0x20, 0x4F, 0x37, 0x5E, 0x01, 0x10, - 0xE5, 0xF2, 0x42, 0x27, 0x01, 0x10, 0x41, 0xF0, 0xCC, 0x16, 0xC2, 0xA4, 0x81, 0xA5, 0x02, 0x2D, - 0x46, 0x7E, 0x8A, 0x09, 0x09, 0x10, 0x8E, 0x92, 0x61, 0x12, 0x94, 0x90, 0x8C, 0x8C, 0x09, 0x8C, - 0x8C, 0x8C, 0x8B, 0x83, 0x71, 0x34, 0x22, 0x00, 0x41, 0xF0, 0x1B, 0x3D, 0xF0, 0x3D, 0x41, 0x00, - 0x1D, 0x23, 0x2F, 0x15, 0x3B, 0x43, 0x09, 0x10, 0x4C, 0x63, 0x7C, 0x41, 0x00, 0x6F, 0x44, 0x52, - 0x47, 0x47, 0x47, 0x47, 0x47, 0x45, 0x3F, 0x00, 0x33, 0x27, 0x1D, 0x62, 0x41, 0xF0, 0x9A, 0xD2, - 0x1D, 0x20, 0x23, 0x1C, 0x25, 0x09, 0x10, 0x2D, 0x49, 0x74, 0x41, 0x00, 0x57, 0x34, 0x22, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x26, 0x24, 0x21, 0x00, 0x1E, 0x1C, 0x41, 0xF0, 0x1B, 0x68, 0xF0, 0x6D, - 0x56, 0x32, 0x0B, 0x30, 0xD4, 0x23, 0x0D, 0x21, 0x50, 0x2B, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x12, - 0x1C, 0x41, 0xC0, 0x41, 0xF0, 0x00, 0x00, 0x9B, 0x9B, 0x9B, 0xA4, 0x0E, 0xBB, 0xCF, 0x31, 0x41, - 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x00, 0x00, 0x77, 0x77, 0x3E, 0x77, 0x6D, 0x3D, 0x11, 0x50, 0x41, - 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x17, 0xF0, 0xF8, 0x22, 0x40, 0x70, 0x41, 0x00, 0x4F, 0x2A, 0x16, - 0xF0, 0x41, 0xF0, 0xC8, 0x4F, 0xF3, 0x0B, 0x30, 0x24, 0x41, 0x71, 0x41, 0x00, 0x51, 0x2B, 0x23, - 0x00, 0x00, 0x1D, 0x1D, 0x81, 0x93, 0x41, 0xF0, 0xDF, 0x21, 0x62, 0x03, 0x10, 0xB9, 0x62, 0x2D, - 0x1E, 0x22, 0x1F, 0x24, 0x29, 0x2E, 0x09, 0x10, 0x84, 0x35, 0x50, 0x78, 0x41, 0x00, 0x5D, 0x3C, - 0x00, 0x00, 0x2F, 0x48, 0x2F, 0x2F, 0x2B, 0x26, 0x20, 0xD9, 0xE1, 0x40, 0xA0, 0xBB, 0x60, 0xB3, - 0x7D, 0x20, 0xB3, 0x77, 0x85, 0x22, 0x35, 0x6A, 0x72, 0x12, 0x09, 0x10, 0x78, 0x88, 0x94, 0x38, - 0x00, 0x8E, 0x7D, 0x75, 0x11, 0x75, 0x75, 0x75, 0x75, 0x74, 0x6D, 0x62, 0x2B, 0x00, 0x1F, 0x0C, - 0x60, 0x41, 0xF0, 0x77, 0xAC, 0x57, 0x42, 0x50, 0x77, 0x46, 0xC9, 0x00, 0x30, 0x4F, 0x01, 0x10, - 0x3D, 0xF0, 0x39, 0xE8, 0x71, 0x41, 0xF0, 0xD9, 0xB3, 0x6D, 0x24, 0x50, 0x57, 0xAC, 0x21, 0x00, - 0x39, 0x63, 0x24, 0x01, 0x10, 0x3D, 0xF0, 0x45, 0x0C, 0x10, 0x41, 0xF0, 0x41, 0xF0, 0x21, 0x00, - 0x3A, 0x7B, 0x65, 0x07, 0x70, 0x03, 0x30, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x47, 0x0E, 0x28, 0x41, - 0xE0, 0x08, 0x80, 0x34, 0x70, 0xBB, 0x1B, 0x1B, 0x1F, 0x0E, 0x33, 0x55, 0xE0, 0x05, 0x50, 0x03, - 0x30, 0x00, 0x00, 0xE1, 0xE1, 0x38, 0xE1, 0xDD, 0x3D, 0x25, 0x0C, 0x60, 0x41, 0xF0, 0xA4, 0x8A, - 0x30, 0x24, 0x50, 0x81, 0xA4, 0x31, 0x01, 0x28, 0x3C, 0x52, 0x60, 0x09, 0x02, 0x20, 0x03, 0x30, - 0x00, 0x00, 0x65, 0x65, 0x65, 0x63, 0x58, 0x07, 0x45, 0x2F, 0x20, 0x41, 0xC0, 0x42, 0xA0, 0xBB, - 0x81, 0x3D, 0x18, 0x22, 0x10, 0x2D, 0x81, 0xBB, 0x57, 0x31, 0x11, 0x28, 0x30, 0x21, 0x36, 0x02, - 0x20, 0x03, 0x30, 0x00, 0x00, 0x39, 0x39, 0x39, 0x37, 0x0E, 0x32, 0x2B, 0x22, 0x40, 0x70, 0x21, - 0x34, 0x47, 0xDB, 0x08, 0x3A, 0x28, 0x43, 0xB0, 0x9B, 0xBB, 0xB3, 0xAC, 0xAC, 0x04, 0xB3, 0xBB, - 0xA4, 0x3F, 0x20, 0x1C, 0x1E, 0x1F, 0x04, 0x40, 0x88, 0x03, 0x30, 0x00, 0x00, 0x20, 0x20, 0x20, - 0x1F, 0x1F, 0xD9, 0x80, 0x83, 0x20, 0x32, 0x44, 0xDB, 0x38, 0x26, 0x12, 0xC0, 0x4A, 0x40, 0x62, - 0x6D, 0x6D, 0x62, 0x4A, 0x02, 0x20, 0x0F, 0xF0, 0x15, 0xF0, 0xE0, 0x20, 0x2E, 0x3B, 0xDB, 0x32, - 0x24, 0x05, 0x50, 0x0F, 0xF0, 0xC0, 0x0F, 0xF0, 0x15, 0xF0, 0x1E, 0x26, 0x2E, 0x31, 0x29, 0x20, - 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x26, 0xF0, 0x42, 0xF0, 0x20, 0x23, 0x24, 0x20, 0x0F, 0x1D, 0x06, - 0x60, 0x0F, 0xF0, 0x0F, 0xF0, 0x13, 0xF0, 0x1C, 0x1D, 0x1D, 0x1E, 0x1C, 0x00, 0x00, 0x09, 0x90, - 0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1E, 0x94, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x6C, 0x23, 0x00, 0x00 -}; +u8 *render_static_bootlogo(); +bool render_ticker_logo(u32 boot_wait, u32 backlight); +bool render_ticker(u32 boot_wait, u32 backlight, bool no_ticker); #endif diff --git a/bootloader/gfx/tui.c b/bootloader/gfx/tui.c index b31cb39..5c1ef28 100644 --- a/bootloader/gfx/tui.c +++ b/bootloader/gfx/tui.c @@ -15,57 +15,45 @@ * along with this program. If not, see . */ -#include "di.h" -#include "tui.h" -#include "../utils/btn.h" -#include "../config/config.h" -#include "../power/max17050.h" -#include "../utils/util.h" +#include -#ifdef MENU_LOGO_ENABLE -extern u8 *Kc_MENU_LOGO; -#define X_MENU_LOGO 119 -#define Y_MENU_LOGO 57 -#define X_POS_MENU_LOGO 577 -#define Y_POS_MENU_LOGO 1179 -#endif //MENU_LOGO_ENABLE +#include "tui.h" +#include "../config.h" extern hekate_config h_cfg; void tui_sbar(bool force_update) { u32 cx, cy; + static u32 sbar_time_keeping = 0; - u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping; + u32 timePassed = get_tmr_s() - sbar_time_keeping; if (!force_update) if (timePassed < 5) return; u8 prevFontSize = gfx_con.fntsz; gfx_con.fntsz = 16; - h_cfg.sbar_time_keeping = get_tmr_s(); + sbar_time_keeping = get_tmr_s(); u32 battPercent = 0; int battVoltCurr = 0; gfx_con_getpos(&cx, &cy); - gfx_con_setpos(0, 1260); + gfx_con_setpos(0, 1260); max17050_get_property(MAX17050_RepSOC, (int *)&battPercent); max17050_get_property(MAX17050_VCELL, &battVoltCurr); gfx_clear_partial_grey(0x30, 1256, 24); - gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888, + gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", TXT_CLR_GREY_D, TXT_CLR_GREY, (battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr); max17050_get_property(MAX17050_Current, &battVoltCurr); - if (battVoltCurr >= 0) - gfx_printf(" %k+%d mA%k%K\n", - 0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B); - else - gfx_printf(" %k-%d mA%k%K\n", - 0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B); + gfx_printf(" %k%d mA%k%K\n", battVoltCurr >= 0 ? TXT_CLR_GREEN_D : TXT_CLR_RED_D, + battVoltCurr / 1000, TXT_CLR_DEFAULT, TXT_CLR_BG); + gfx_con.fntsz = prevFontSize; gfx_con_setpos(cx, cy); } @@ -80,11 +68,11 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) gfx_con_setpos(x, y); - gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC); + gfx_printf("%k[%3d%%]%k", fgcol, val, TXT_CLR_DEFAULT); x += 7 * gfx_con.fntsz; - for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) + for (u32 i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) { gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol); gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol); @@ -103,14 +91,9 @@ void *tui_do_menu(menu_t *menu) gfx_clear_partial_grey(0x1B, 0, 1256); tui_sbar(true); -#ifdef MENU_LOGO_ENABLE - gfx_set_rect_rgb(Kc_MENU_LOGO, - X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); -#endif //MENU_LOGO_ENABLE - while (true) { - gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_con_setcol(TXT_CLR_DEFAULT, 1, TXT_CLR_BG); gfx_con_setpos(menu->x, menu->y); gfx_printf("[%s]\n\n", menu->caption); @@ -143,25 +126,25 @@ void *tui_do_menu(menu_t *menu) for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++) { if (cnt == idx) - gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC); + gfx_con_setcol(TXT_CLR_BG, 1, TXT_CLR_DEFAULT); else - gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_con_setcol(TXT_CLR_DEFAULT, 1, TXT_CLR_BG); if (menu->ents[cnt].type == MENT_CAPTION) gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption); else if (menu->ents[cnt].type != MENT_CHGLINE) gfx_printf(" %s", menu->ents[cnt].caption); - if(menu->ents[cnt].type == MENT_MENU) - gfx_printf("%k...", 0xFF0099EE); + if (menu->ents[cnt].type == MENT_MENU) + gfx_printf("%k...", TXT_CLR_CYAN_L); gfx_printf(" \n"); } - gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_con_setcol(TXT_CLR_DEFAULT, 1, TXT_CLR_BG); gfx_putc('\n'); // Print errors, help and battery status. gfx_con_setpos(0, 1127); - gfx_printf("%k Warning: %k Nyx is missing!", 0xFF800000, 0xFF555555); + gfx_printf("%k Warning: %kNyx is missing!", TXT_CLR_RED_D, TXT_CLR_GREY_M); gfx_con_setpos(0, 1191); - gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC); + gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", TXT_CLR_GREY_M, TXT_CLR_DEFAULT); display_backlight_brightness(h_cfg.backlight, 1000); @@ -209,10 +192,6 @@ void *tui_do_menu(menu_t *menu) } gfx_con.fntsz = 16; gfx_clear_partial_grey(0x1B, 0, 1256); -#ifdef MENU_LOGO_ENABLE - gfx_set_rect_rgb(Kc_MENU_LOGO, - X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); -#endif //MENU_LOGO_ENABLE } tui_sbar(false); } diff --git a/bootloader/gfx/tui.h b/bootloader/gfx/tui.h index abb8746..0fd3194 100644 --- a/bootloader/gfx/tui.h +++ b/bootloader/gfx/tui.h @@ -18,8 +18,7 @@ #ifndef _TUI_H_ #define _TUI_H_ -#include "../utils/types.h" -#include "gfx.h" +#include #define MENT_END 0 #define MENT_HANDLER 1 diff --git a/bootloader/hos/fss.c b/bootloader/hos/fss.c deleted file mode 100644 index 80c75c4..0000000 --- a/bootloader/hos/fss.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Atmosphère Fusée Secondary Storage parser. - * - * Copyright (c) 2019 CTCaer - * - * 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 "fss.h" -#include "hos.h" -#include "../config/config.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../storage/emummc.h" - -#include "../gfx/gfx.h" -#define DPRINTF(...) - -extern hekate_config h_cfg; - -extern void *sd_file_read(const char *path, u32 *fsize); -extern bool is_ipl_updated(void *buf, char *path, bool force); - -#define FSS0_MAGIC 0x30535346 -#define CNT_TYPE_FSP 0 -#define CNT_TYPE_EXO 1 -#define CNT_TYPE_WBT 2 -#define CNT_TYPE_RBT 3 -#define CNT_TYPE_SP1 4 -#define CNT_TYPE_SP2 5 -#define CNT_TYPE_KIP 6 -#define CNT_TYPE_BMP 7 -#define CNT_TYPE_EMC 8 - -typedef struct _fss_t -{ - u32 magic; - u32 size; - u32 crt0_off; - u32 cnt_off; - u32 cnt_count; - u32 hos_ver; - u32 version; - u32 git_rev; -} fss_t; - -typedef struct _fss_content_t -{ - u32 offset; - u32 size; - u32 type; - u32 rsvd1; - char name[0x10]; -} fss_content_t; - -static void _update_r2p(const char *path) -{ - char *r2p_path = malloc(256); - u32 path_len = strlen(path); - strcpy(r2p_path, path); - - while(path_len) - { - if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C)) - { - r2p_path[path_len] = 0; - strcat(r2p_path, "reboot_payload.bin"); - u8 *r2p_payload = sd_file_read(r2p_path, NULL); - - is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false); - - free(r2p_payload); - break; - } - path_len--; - } - - free(r2p_path); -} - -int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) -{ - FIL fp; - - bool stock = false; - int sept_used = 0; - - if (!sept_ctxt) - { - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) - { - if (!strcmp("stock", kv->key)) - if (kv->val[0] == '1') - stock = true; - } - - if (ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable)) - return 1; - } - - if (f_open(&fp, path, FA_READ) != FR_OK) - return 0; - - void *fss = malloc(f_size(&fp)); - // Read header. - f_read(&fp, fss, 0x400, NULL); - - u32 fss_entry = *(u32 *)(fss + 4); - fss_t *fss_meta = (fss_t *)(fss + fss_entry); - - if (fss_meta->magic == FSS0_MAGIC) - { - gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n" - "Max HOS supported: %d.%d.%d\n" - "Unpacking and loading components.. ", - fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev, - fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF); - - if (!sept_ctxt) - { - ctxt->atmosphere = true; - ctxt->fss0_hosver = fss_meta->hos_ver; - } - - fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off); - void *content; - for (u32 i = 0; i < fss_meta->cnt_count; i++) - { - content = (void *)(fss + curr_fss_cnt[i].offset); - if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size) - continue; - - // Load content to launch context. - if (!sept_ctxt) - { - switch (curr_fss_cnt[i].type) - { - case CNT_TYPE_KIP: - if (stock) - continue; - merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); - mkip1->kip1 = content; - list_append(&ctxt->kip1_list, &mkip1->link); - DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size); - break; - case CNT_TYPE_EXO: - ctxt->secmon_size = curr_fss_cnt[i].size; - ctxt->secmon = content; - break; - case CNT_TYPE_WBT: - ctxt->warmboot_size = curr_fss_cnt[i].size; - ctxt->warmboot = content; - break; - default: - continue; - } - } - else - { - // Load content to launch context. - switch (curr_fss_cnt[i].type) - { - case CNT_TYPE_SP1: - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL); - continue; - case CNT_TYPE_SP2: - if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15)) - { - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL); - sept_used = 1; - goto out; - } - continue; - default: - continue; - } - } - - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, content, curr_fss_cnt[i].size, NULL); - } - -out: - gfx_printf("Done!\n"); - f_close(&fp); - - _update_r2p(path); - - return (!sept_ctxt ? 1 : sept_used); - } - - f_close(&fp); - free(fss); - - return 0; -} - -int load_sept_from_ffs0(fss0_sept_t *sept_ctxt) -{ - LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link) - { - if (!strcmp("fss0", kv->key)) - return parse_fss(NULL, kv->val, sept_ctxt); - } - - return 0; -} diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index d8c0be5..4504a4a 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk * Copyright (c) 2018 Ced2911 - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -20,48 +20,45 @@ #include +#include + #include "hos.h" #include "hos_config.h" -#include "sept.h" #include "secmon_exo.h" -#include "../config/config.h" -#include "../gfx/di.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../mem/minerva.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../sec/tsec.h" -#include "../soc/bpmp.h" -#include "../soc/cluster.h" -#include "../soc/fuse.h" -#include "../soc/pmc.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" +#include "../frontend/fe_tools.h" +#include "../config.h" #include "../storage/emummc.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/util.h" -#include "../gfx/gfx.h" extern hekate_config h_cfg; -extern void sd_unmount(); -extern bool sd_mount(); - //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) #define EHPRINTFARGS(text, args...) \ - ({ display_backlight_brightness(h_cfg.backlight, 1000); \ - gfx_con.mute = false; \ - gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC); }) + ({ gfx_con.mute = false; \ + gfx_printf("%k"text"%k\n", TXT_CLR_ERROR, args, TXT_CLR_DEFAULT); }) #define PKG2_LOAD_ADDR 0xA9800000 +#define SECMON_BCT_CFG_ADDR 0x4003D000 +#define SECMON6_BCT_CFG_ADDR 0x4003F800 + // Secmon mailbox. -#define SECMON_MB_ADDR 0x40002EF8 -#define SECMON7_MB_ADDR 0x400000F8 +#define SECMON_MAILBOX_ADDR 0x40002E00 +#define SECMON7_MAILBOX_ADDR 0x40000000 +#define SECMON_STATE_OFFSET 0xF8 + +typedef enum +{ + SECMON_STATE_NOT_READY = 0, + + PKG1_STATE_NOT_READY = 0, + PKG1_STATE_BCT_COPIED = 1, + PKG1_STATE_DRAM_READY = 2, + PKG1_STATE_PKG2_READY_OLD = 3, + PKG1_STATE_PKG2_READY = 4 +} pkg1_states_t; + typedef struct _secmon_mailbox_t { // < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot. @@ -71,195 +68,454 @@ typedef struct _secmon_mailbox_t u32 out; } secmon_mailbox_t; -static const u8 keyblob_keyseeds[][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 - { 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } //6.0.0 +typedef struct _tsec_keys_t +{ + u8 tsec[SE_KEY_128_SIZE]; + u8 tsec_root[SE_KEY_128_SIZE]; + u8 tmp[SE_KEY_128_SIZE]; +} tsec_keys_t; + +typedef struct _kb_keys_t +{ + u8 master_kekseed[SE_KEY_128_SIZE]; + u8 random_data[0x70]; + u8 package1_key[SE_KEY_128_SIZE]; +} kb_keys_t; + +typedef struct _kb_t +{ + u8 cmac[SE_KEY_128_SIZE]; + u8 ctr[SE_AES_IV_SIZE]; + kb_keys_t keys; + u8 padding[0x150]; +} kb_t; + +static const u8 keyblob_keyseeds[HOS_KB_VERSION_600 - HOS_KB_VERSION_100 + 1][SE_KEY_128_SIZE] = { + { 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. + { 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } // 6.0.0. }; -static const u8 cmac_keyseed[0x10] = +static const u8 cmac_keyseed[SE_KEY_128_SIZE] = { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 }; -static const u8 master_keyseed_retail[0x10] = +static const u8 master_keyseed_retail[SE_KEY_128_SIZE] = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C }; -static const u8 console_keyseed[0x10] = - { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; - -const u8 package2_keyseed[] = - { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; - -static const u8 master_keyseed_4xx_5xx_610[0x10] = +static const u8 master_keyseed_4xx[SE_KEY_128_SIZE] = { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; -static const u8 master_keyseed_620[0x10] = +static const u8 master_kekseed_620[SE_KEY_128_SIZE] = { 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A }; -static const u8 console_keyseed_4xx_5xx[0x10] = +//!TODO: Update on tsec/mkey changes. +static const u8 master_kekseed_t210_tsec_v4[HOS_KB_VERSION_MAX - HOS_KB_VERSION_810 + 1][SE_KEY_128_SIZE] = { + { 0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41 }, // 8.1.0. + { 0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67 }, // 9.0.0. + { 0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A }, // 9.1.0. + { 0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A }, // 12.1.0. + { 0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23 }, // 13.0.0. + { 0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81 }, // 14.0.0. + { 0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67 }, // 15.0.0. + { 0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6 }, // 16.0.0. + { 0x71, 0xB9, 0xA6, 0xC0, 0xFF, 0x97, 0x6B, 0x0C, 0xB4, 0x40, 0xB9, 0xD5, 0x81, 0x5D, 0x81, 0x90 }, // 17.0.0. + { 0x00, 0x04, 0x5D, 0xF0, 0x4D, 0xCD, 0x14, 0xA3, 0x1C, 0xBF, 0xDE, 0x48, 0x55, 0xBA, 0x35, 0xC1 }, // 18.0.0. + { 0xD7, 0x63, 0x74, 0x46, 0x4E, 0xBA, 0x78, 0x0A, 0x7C, 0x9D, 0xB3, 0xE8, 0x7A, 0x3D, 0x71, 0xE3 }, // 19.0.0. + { 0xA1, 0x7D, 0x34, 0xDB, 0x2D, 0x9D, 0xDA, 0xE5, 0xF8, 0x15, 0x63, 0x4C, 0x8F, 0xE7, 0x6C, 0xD8 }, // 20.0.0. +}; + +//!TODO: Update on mkey changes. +static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 + 1][SE_KEY_128_SIZE] = { + { 0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56 }, // 6.0.0. + { 0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE }, // 6.2.0. + { 0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A }, // 7.0.0. + { 0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23 }, // 8.1.0. + { 0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13 }, // 9.0.0. + { 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82 }, // 9.1.0. + { 0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1 }, // 12.1.0. + { 0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6 }, // 13.0.0. + { 0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A }, // 14.0.0. + { 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D }, // 15.0.0. + { 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9 }, // 16.0.0. + { 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80 }, // 17.0.0. + { 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 }, // 18.0.0. + { 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }, // 19.0.0. + { 0x1A, 0x31, 0x62, 0x87, 0xA8, 0x09, 0xCA, 0xF8, 0x69, 0x15, 0x45, 0xC2, 0x6B, 0xAA, 0x5A, 0x8A }, // 20.0.0. +}; + +static const u8 console_keyseed[SE_KEY_128_SIZE] = + { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; + +static const u8 console_keyseed_4xx[SE_KEY_128_SIZE] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; +const u8 package2_keyseed[SE_KEY_128_SIZE] = + { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; + static void _hos_crit_error(const char *text) { gfx_con.mute = false; - gfx_printf("%k%s%k\n", 0xFFFF0000, text, 0xFFCCCCCC); - - display_backlight_brightness(h_cfg.backlight, 1000); + gfx_printf("%k%s%k\n", TXT_CLR_ERROR, text, TXT_CLR_DEFAULT); } static void _se_lock(bool lock_se) { if (lock_se) { + // Disable aes key read. for (u32 i = 0; i < 16; i++) se_key_acc_ctrl(i, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG); + // Disable RSA key read. for (u32 i = 0; i < 2; i++) se_rsa_acc_ctrl(i, SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG); - SE(SE_TZRAM_SECURITY_0) = 0; // Make SE TZRAM 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. + + SE(SE_TZRAM_SECURITY_REG) = 0; // Make SE TZRAM secure only. + SE(SE_CRYPTO_SECURITY_PERKEY_REG) = 0; // Make all AES keys access secure only. + SE(SE_RSA_SECURITY_PERKEY_REG) = 0; // Make all RSA keys access secure only. + SE(SE_SE_SECURITY_REG) &= ~SE_PERKEY_SETTING; // Make access lock regs secure only. } memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32)); SB(SB_CSR) = SB_CSR_PIROM_DISABLE; // This is useful for documenting the bits in the SE config registers, so we can keep it around. - /*gfx_printf("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0)); + /*gfx_printf("SE(SE_SE_SECURITY_REG) = %08X\n", SE(SE_SE_SECURITY_REG)); gfx_printf("SE(0x4) = %08X\n", SE(0x4)); - gfx_printf("SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET)); - gfx_printf("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("%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF); + gfx_printf("SE(SE_CRYPTO_SECURITY_PERKEY_REG) = %08X\n", SE(SE_CRYPTO_SECURITY_PERKEY_REG)); + gfx_printf("SE(SE_RSA_SECURITY_PERKEY_REG) = %08X\n", SE(SE_RSA_SECURITY_PERKEY_REG)); + for (u32 i = 0; i < 16; i++) + gfx_printf("%02X ", SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + i * 4) & 0xFF); gfx_putc('\n'); - for(u32 i = 0; i < 2; i++) - gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF); + for (u32 i = 0; i < 2; i++) + gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG + i * 4) & 0xFF); gfx_putc('\n'); gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/ } -void _pmc_scratch_lock(u32 kb) +static bool _hos_eks_rw_try(u8 *buf, bool write) { - switch (kb) + for (u32 i = 0; i < 3; i++) { - case KB_FIRMWARE_VERSION_100_200: - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3; - PMC(APBDEV_PMC_SEC_DISABLE2) = 0xFFFFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE3) = 0xFFAFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE4) = 0xFFFFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE6) = 0xFFFFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF; - break; - default: - PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF; - PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF; - PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF; - PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F; - PMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF; - PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF; - break; - } -} - -void _sysctr0_reset() -{ - SYSCTR0(SYSCTR0_CNTCR) = 0; - SYSCTR0(SYSCTR0_COUNTERID0) = 0; - SYSCTR0(SYSCTR0_COUNTERID1) = 0; - SYSCTR0(SYSCTR0_COUNTERID2) = 0; - SYSCTR0(SYSCTR0_COUNTERID3) = 0; - SYSCTR0(SYSCTR0_COUNTERID4) = 0; - SYSCTR0(SYSCTR0_COUNTERID5) = 0; - SYSCTR0(SYSCTR0_COUNTERID6) = 0; - SYSCTR0(SYSCTR0_COUNTERID7) = 0; - SYSCTR0(SYSCTR0_COUNTERID8) = 0; - SYSCTR0(SYSCTR0_COUNTERID9) = 0; - SYSCTR0(SYSCTR0_COUNTERID10) = 0; - SYSCTR0(SYSCTR0_COUNTERID11) = 0; -} - -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt) -{ - u8 tmp[0x20]; - u32 retries = 0; - - if (kb > KB_FIRMWARE_VERSION_MAX) - return 0; - - if (kb <= KB_FIRMWARE_VERSION_600) - tsec_ctxt->size = 0xF00; - else if (kb == KB_FIRMWARE_VERSION_620) - tsec_ctxt->size = 0x2900; - else if (kb == KB_FIRMWARE_VERSION_700) - tsec_ctxt->size = 0x3000; - else - tsec_ctxt->size = 0x3300; - - // Prepare smmu tsec page for 6.2.0. - if (kb == KB_FIRMWARE_VERSION_620) - { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size); - tsec_ctxt->fw = tsec_paged; - } - - // Get TSEC key. - if (kb <= KB_FIRMWARE_VERSION_620) - { - while (tsec_query(tmp, kb, tsec_ctxt) < 0) + if (!write) { - memset(tmp, 0x00, 0x20); - retries++; - - // We rely on racing conditions, make sure we cover even the unluckiest cases. - if (retries > 15) - { - _hos_crit_error("\nFailed to get TSEC keys. Please try again."); - return 0; - } + if (sdmmc_storage_read(&sd_storage, 0, 1, buf)) + return true; + } + else + { + if (sdmmc_storage_write(&sd_storage, 0, 1, buf)) + return true; } } - if (kb >= KB_FIRMWARE_VERSION_700) - se_aes_unwrap_key(8, 12, package2_keyseed); - else if (kb == KB_FIRMWARE_VERSION_620) + return false; +} + +static void _hos_eks_get() +{ + // Check if Erista based unit. + if (h_cfg.t210b01) + return; + + // Check if EKS already found and parsed. + if (!h_cfg.eks) + { + // Read EKS blob. + u8 *mbr = zalloc(SD_BLOCKSIZE); + if (!_hos_eks_rw_try(mbr, false)) + goto out; + + // Decrypt EKS blob. + hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x80); + se_aes_crypt_ecb(14, DECRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Check if valid and for this unit. + if (eks->magic == HOS_EKS_MAGIC && eks->lot0 == FUSE(FUSE_OPT_LOT_CODE_0)) + { + h_cfg.eks = eks; + return; + } + +out: + free(mbr); + } +} + +static void _hos_eks_save() +{ + // Check if Erista based unit. + if (h_cfg.t210b01) + return; + + // EKS save. Only for 7.0.0 and up. + bool new_eks = false; + if (!h_cfg.eks) + { + h_cfg.eks = zalloc(SD_BLOCKSIZE); + new_eks = true; + } + + // If matching blob doesn't exist, create it. + if (h_cfg.eks->enabled != HOS_EKS_TSEC_VER) + { + // Read EKS blob. + u8 *mbr = zalloc(SD_BLOCKSIZE); + if (!_hos_eks_rw_try(mbr, false)) + { + if (new_eks) + { + free(h_cfg.eks); + h_cfg.eks = NULL; + } + + goto out; + } + + // Get keys. + u8 *keys = (u8 *)zalloc(SZ_8K); + se_get_aes_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE); + + // Set magic and personalized info. + h_cfg.eks->magic = HOS_EKS_MAGIC; + h_cfg.eks->enabled = HOS_EKS_TSEC_VER; + h_cfg.eks->lot0 = FUSE(FUSE_OPT_LOT_CODE_0); + + // Copy new keys. + memcpy(h_cfg.eks->tsec, keys + 12 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(h_cfg.eks->troot, keys + 13 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(h_cfg.eks->troot_dev, keys + 11 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + + // Encrypt EKS blob. + u8 *eks = zalloc(SD_BLOCKSIZE); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, ENCRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + _hos_eks_rw_try(mbr, true); + + free(eks); + free(keys); +out: + free(mbr); + } +} + +static void _hos_eks_clear(u32 kb) +{ + // Check if Erista based unit. + if (h_cfg.t210b01) + return; + + if (h_cfg.eks && kb >= HOS_KB_VERSION_700) + { + // Check if current Master key is enabled. + if (h_cfg.eks->enabled) + { + // Read EKS blob. + u8 *mbr = zalloc(SD_BLOCKSIZE); + if (!_hos_eks_rw_try(mbr, false)) + goto out; + + // Disable current Master key version. + h_cfg.eks->enabled = 0; + + // Encrypt EKS blob. + u8 *eks = zalloc(SD_BLOCKSIZE); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, ENCRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + _hos_eks_rw_try(mbr, true); + + free(eks); +out: + free(mbr); + } + } +} + +static int _hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo) +{ + static bool sbk_is_set = true; + + u32 retries = 0; + bool use_tsec = false; + tsec_keys_t tsec_keys; + kb_t *kb_data = (kb_t *)keyblob; + + if (kb > HOS_KB_VERSION_MAX) + return 0; + + // Do Mariko keygen. + if (h_cfg.t210b01) + { + // Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units. + se_aes_unwrap_key(10, 14, console_keyseed_4xx); + + // Derive master key. + se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]); + se_aes_unwrap_key(7, 7, master_keyseed_retail); + + // Derive latest pkg2 key. + se_aes_unwrap_key(8, 7, package2_keyseed); + + return 1; + } + + // Do Erista keygen. + + // Check if SBK is wiped and try to restore it from fuses. + if (!sbk_is_set) + { + if (fuse_set_sbk()) + sbk_is_set = true; + else + return 1; // Continue with current SE keys. + } + + // Use HOS EKS if it exists. + _hos_eks_get(); + + // Use tsec keygen for old firmware or if EKS keys does not exist for newer. + if (kb <= HOS_KB_VERSION_620 || !h_cfg.eks || (h_cfg.eks->enabled != HOS_EKS_TSEC_VER)) + use_tsec = true; + + if (kb <= HOS_KB_VERSION_600) + { + tsec_ctxt->size = 0xF00; + tsec_ctxt->type = TSEC_FW_TYPE_OLD; + } + else if (kb == HOS_KB_VERSION_620) + { + tsec_ctxt->size = 0x2900; + tsec_ctxt->type = TSEC_FW_TYPE_EMU; + + // Prepare smmu tsec page for 6.2.0. + u8 *tsec_paged = (u8 *)smmu_page_zalloc(3); + memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size); + tsec_ctxt->fw = tsec_paged; + } + else if (use_tsec) // 7.0.0+ + { + /* + * 7.0.0/8.1.0 tsec fw are 0x3000/0x3300. + * Unused here because of THK. + */ + + // Use custom TSEC Hovi Keygen firmware. + tsec_ctxt->fw = sd_file_read("bootloader/sys/thk.bin", NULL); + if (!tsec_ctxt->fw) + { + _hos_crit_error("Failed to load thk.bin"); + return 0; + } + + tsec_ctxt->size = 0x1F00; + tsec_ctxt->type = TSEC_FW_TYPE_NEW; + } + else if (h_cfg.eks) + { + // EKS found. Set TSEC keys. + se_aes_key_set(12, h_cfg.eks->tsec, SE_KEY_128_SIZE); + se_aes_key_set(13, h_cfg.eks->troot, SE_KEY_128_SIZE); + se_aes_key_set(11, h_cfg.eks->troot_dev, SE_KEY_128_SIZE); + } + + // Get TSEC key. + while (use_tsec && tsec_query(&tsec_keys, tsec_ctxt) < 0) + { + memset(&tsec_keys, 0x00, 0x20); + retries++; + + // We rely on racing conditions, make sure we cover even the unluckiest cases. + if (retries > 15) + { + _hos_crit_error("Failed to get TSEC keys."); + return 0; + } + } + + if (kb >= HOS_KB_VERSION_700) + { + // For 7.0.0 and up, save EKS slot if it doesn't exist. + if (use_tsec) + { + _hos_eks_save(); + free(tsec_ctxt->fw); + } + + // Use 8.1.0 for 7.0.0 otherwise the proper one. + u32 mkey_idx = 0; + if (kb >= HOS_KB_VERSION_810) + mkey_idx = kb - HOS_KB_VERSION_810; + + if (!is_exo) + { + // Derive Package2 key in secmon compatible way. + se_aes_unwrap_key(7, 13, master_kekseed_t210_tsec_v4[mkey_idx]); + se_aes_unwrap_key(7, 7, master_keyseed_retail); + se_aes_unwrap_key(8, 7, package2_keyseed); + } + else + { + se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tmp, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tsec_keys.tmp); + + // Derive device keys. + se_aes_unwrap_key(10, 15, console_keyseed_4xx); + se_aes_unwrap_key(15, 15, console_keyseed); + + // Derive master kek. + se_aes_unwrap_key(13, 13, master_kekseed_t210_tsec_v4[mkey_idx]); + + // Derive device master key and master key. + se_aes_unwrap_key(12, 13, master_keyseed_4xx); + se_aes_unwrap_key(13, 13, master_keyseed_retail); + + // Package2 key. + se_aes_unwrap_key(8, 13, package2_keyseed); + } + } + else if (kb == HOS_KB_VERSION_620) { // Set TSEC key. - se_aes_key_set(12, tmp, 0x10); + se_aes_key_set(12, tsec_keys.tsec, SE_KEY_128_SIZE); // Set TSEC root key. - se_aes_key_set(13, tmp + 0x10, 0x10); + se_aes_key_set(13, tsec_keys.tsec_root, SE_KEY_128_SIZE); - if (!(emu_cfg.enabled && !h_cfg.emummc_force_disable) && hos_ctxt->stock) + if (!is_exo) { - // Package2 key. - se_aes_key_set(8, tmp + 0x10, 0x10); - se_aes_unwrap_key(8, 8, master_keyseed_620); + // Derive Package2 key in secmon compatible way. + se_aes_key_set(8, tsec_keys.tsec_root, SE_KEY_128_SIZE); + se_aes_unwrap_key(8, 8, master_kekseed_620); se_aes_unwrap_key(8, 8, master_keyseed_retail); se_aes_unwrap_key(8, 8, package2_keyseed); } else { - // Decrypt keyblob and set keyslots - se_aes_crypt_block_ecb(12, 0, tmp + 0x20, keyblob_keyseeds[0]); - se_aes_unwrap_key(15, 14, tmp + 0x20); - se_aes_unwrap_key(14, 15, console_keyseed_4xx_5xx); + // Decrypt keyblob and set keyslots for Exosphere 2. + se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tmp, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tsec_keys.tmp); + + // Derive device keys. + se_aes_unwrap_key(10, 15, console_keyseed_4xx); se_aes_unwrap_key(15, 15, console_keyseed); - se_aes_unwrap_key(13, 13, master_keyseed_620); - se_aes_unwrap_key(12, 13, master_keyseed_retail); - se_aes_unwrap_key(10, 13, master_keyseed_4xx_5xx_610); + // Derive master kek. + se_aes_unwrap_key(13, 13, master_kekseed_620); + + // Derive device master key and master key. + se_aes_unwrap_key(12, 13, master_keyseed_4xx); + se_aes_unwrap_key(13, 13, master_keyseed_retail); // Package2 key. - se_aes_unwrap_key(8, 12, package2_keyseed); - - h_cfg.se_keygen_done = 1; + se_aes_unwrap_key(8, 13, package2_keyseed); } } else @@ -268,60 +524,75 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt) se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG); // Set TSEC key. - se_aes_key_set(13, tmp, 0x10); + se_aes_key_set(13, tsec_keys.tsec, SE_KEY_128_SIZE); // Derive keyblob keys from TSEC+SBK. - se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]); - se_aes_unwrap_key(15, 14, tmp); - se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]); - se_aes_unwrap_key(13, 14, tmp); + se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tsec_keys.tsec); + se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, keyblob_keyseeds[kb]); + se_aes_unwrap_key(13, 14, tsec_keys.tsec); // Clear SBK. - se_aes_key_clear(14); + //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; +/* + // Verify keyblob CMAC. + u8 cmac[SE_KEY_128_SIZE]; + se_aes_unwrap_key(11, 13, cmac_keyseed); + se_aes_cmac(cmac, SE_KEY_128_SIZE, 11, (void *)kb_data->ctr, sizeof(kb_data->ctr) + sizeof(kb_data->keys)); + if (!memcmp(kb_data->cmac, cmac, SE_KEY_128_SIZE)) + return 0; +*/ - se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed); + se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, cmac_keyseed); se_aes_unwrap_key(11, 13, cmac_keyseed); // 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); // Package1 key. - se_aes_key_set(12, keyblob + 0x20, 0x10); - se_aes_key_set(13, keyblob + 0x20, 0x10); + se_aes_crypt_ctr(13, &kb_data->keys, sizeof(kb_keys_t), &kb_data->keys, sizeof(kb_keys_t), kb_data->ctr); + se_aes_key_set(11, kb_data->keys.package1_key, SE_KEY_128_SIZE); + se_aes_key_set(12, kb_data->keys.master_kekseed, SE_KEY_128_SIZE); + se_aes_key_set(13, kb_data->keys.master_kekseed, SE_KEY_128_SIZE); - se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail); + se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tsec, master_keyseed_retail); - switch (kb) + if (!is_exo) { - case KB_FIRMWARE_VERSION_100_200: - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - se_aes_unwrap_key(13, 15, console_keyseed); - se_aes_unwrap_key(12, 12, master_keyseed_retail); - break; - case KB_FIRMWARE_VERSION_400: - se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx); + switch (kb) + { + case HOS_KB_VERSION_100: + case HOS_KB_VERSION_300: + case HOS_KB_VERSION_301: + se_aes_unwrap_key(13, 15, console_keyseed); + se_aes_unwrap_key(12, 12, master_keyseed_retail); + break; + case HOS_KB_VERSION_400: + se_aes_unwrap_key(13, 15, console_keyseed_4xx); + se_aes_unwrap_key(15, 15, console_keyseed); + se_aes_unwrap_key(14, 12, master_keyseed_4xx); + se_aes_unwrap_key(12, 12, master_keyseed_retail); + sbk_is_set = false; + break; + case HOS_KB_VERSION_500: + case HOS_KB_VERSION_600: + se_aes_unwrap_key(10, 15, console_keyseed_4xx); + se_aes_unwrap_key(15, 15, console_keyseed); + se_aes_unwrap_key(14, 12, master_keyseed_4xx); + se_aes_unwrap_key(12, 12, master_keyseed_retail); + sbk_is_set = false; + break; + } + } + else // Exosphere 2. + { + se_aes_unwrap_key(10, 15, console_keyseed_4xx); se_aes_unwrap_key(15, 15, console_keyseed); - se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610); - se_aes_unwrap_key(12, 12, master_keyseed_retail); - break; - case KB_FIRMWARE_VERSION_500: - case KB_FIRMWARE_VERSION_600: - se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx); - se_aes_unwrap_key(15, 15, console_keyseed); - se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610); - se_aes_unwrap_key(12, 12, master_keyseed_retail); - break; + se_aes_unwrap_key(13, 12, master_keyseed_retail); + se_aes_unwrap_key(12, 12, master_keyseed_4xx); } // Package2 key. se_key_acc_ctrl(8, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG); - se_aes_unwrap_key(8, 12, package2_keyseed); + se_aes_unwrap_key(8, !is_exo ? 12 : 13, package2_keyseed); } return 1; @@ -329,122 +600,167 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt) static int _read_emmc_pkg1(launch_ctxt_t *ctxt) { - sdmmc_storage_t storage; - sdmmc_t sdmmc; + const u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. + u32 bootloader_offset = PKG1_BOOTLOADER_MAIN_OFFSET; + ctxt->pkg1 = (void *)malloc(PKG1_BOOTLOADER_SIZE); - int res = emummc_storage_init_mmc(&storage, &sdmmc); +try_load: + // Read package1. + emummc_storage_set_mmc_partition(EMMC_BOOT0); + emummc_storage_read(bootloader_offset / EMMC_BLOCKSIZE, PKG1_BOOTLOADER_SIZE / EMMC_BLOCKSIZE, ctxt->pkg1); - if (res) + ctxt->pkg1_id = pkg1_identify(ctxt->pkg1 + pk1_offset); + if (!ctxt->pkg1_id) { - if (res == 2) - _hos_crit_error("Failed to init eMMC"); + // Check if wrong pkg1 was flashed. + bool wrong_pkg1; + + const u32 pkg1_erista_check = ((bl_hdr_t210b01_t *)ctxt->pkg1)->entrypoint; + const u32 pkg1_mariko_check = *(u32 *)(ctxt->pkg1 + sizeof(pk1_hdr_t) * 2); + + if (!h_cfg.t210b01) // For Erista check if start is 0 and entrypoint matches Mariko. + wrong_pkg1 = *(u32 *)ctxt->pkg1 == 0 && pkg1_erista_check == PKG1_MARIKO_ON_ERISTA_MAGIC; + else // For Mariko check if start is not 0 and build id. It works for 8.0.0 Erista pkg1 and up. + wrong_pkg1 = *(u32 *)ctxt->pkg1 != 0 && pkg1_mariko_check == PKG1_ERISTA_ON_MARIKO_MAGIC; + + if (wrong_pkg1) + { + _hos_crit_error("Wrong pkg1 flashed:"); + EPRINTFARGS("%s pkg1 on %s!", + !h_cfg.t210b01 ? "Mariko" : "Erista", !h_cfg.t210b01 ? "Erista" : "Mariko"); + } else - _hos_crit_error("Failed to init emuMMC"); + { + _hos_crit_error("Unknown pkg1 version."); + EPRINTFARGS("HOS version not supported!%s", + (emu_cfg.enabled && !h_cfg.emummc_force_disable) ? "\nOr emuMMC corrupt!" : ""); + } + + // Try backup bootloader. + if (bootloader_offset != PKG1_BOOTLOADER_BACKUP_OFFSET) + { + EPRINTF("\nTrying backup bootloader..."); + bootloader_offset = PKG1_BOOTLOADER_BACKUP_OFFSET; + goto try_load; + } return 0; } + gfx_printf("Identified pkg1 and mkey %d\n\n", ctxt->pkg1_id->kb); - // Read package1. - ctxt->pkg1 = (void *)malloc(0x40000); - emummc_storage_set_mmc_partition(&storage, 1); - emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1); - ctxt->pkg1_id = pkg1_identify(ctxt->pkg1); - if (!ctxt->pkg1_id) + // Read the correct keyblob for older HOS versions. + if (ctxt->pkg1_id->kb <= HOS_KB_VERSION_600) { - _hos_crit_error("Unknown pkg1 version."); - EHPRINTFARGS("%sNot yet supported HOS version!", - (emu_cfg.enabled && !h_cfg.emummc_force_disable) ? "Is emuMMC corrupt?\nOr " : ""); - goto out; + ctxt->keyblob = (u8 *)zalloc(EMMC_BLOCKSIZE); + emummc_storage_read(PKG1_HOS_KEYBLOBS_OFFSET / EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob); } - gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb); - // Read the correct keyblob. - ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); - emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob); - - res = 1; - -out:; - sdmmc_storage_end(&storage); - return res; + return 1; } static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt) { u8 *bctBuf = NULL; - sdmmc_storage_t storage; - sdmmc_t sdmmc; - int res = emummc_storage_init_mmc(&storage, &sdmmc); - - if (res) - { - if (res == 2) - _hos_crit_error("Failed to init eMMC"); - else - _hos_crit_error("Failed to init emuMMC"); - - return NULL; - } - - emummc_storage_set_mmc_partition(&storage, 0); + emummc_storage_set_mmc_partition(EMMC_GPP); // Parse eMMC GPT. LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); + emmc_gpt_parse(&gpt); DPRINTF("Parsed GPT\n"); // Find package2 partition. - emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); + emmc_part_t *pkg2_part = 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. - static const u32 BCT_SIZE = 0x4000; + static const u32 BCT_SIZE = SZ_16K; bctBuf = (u8 *)malloc(BCT_SIZE); - nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE, 1, bctBuf); + emmc_part_read(pkg2_part, BCT_SIZE / EMMC_BLOCKSIZE, 1, bctBuf); u32 *hdr = (u32 *)(bctBuf + 0x100); u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3]; DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size); // Read in Boot Config. - memset(bctBuf, 0, BCT_SIZE); - nx_emmc_part_read(&storage, pkg2_part, 0, BCT_SIZE / NX_EMMC_BLOCKSIZE, bctBuf); + emmc_part_read(pkg2_part, 0, BCT_SIZE / EMMC_BLOCKSIZE, bctBuf); // Read in package2. - u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); + u32 pkg2_size_aligned = ALIGN(pkg2_size, 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, BCT_SIZE / NX_EMMC_BLOCKSIZE, - pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2); -out:; - nx_emmc_gpt_free(&gpt); - sdmmc_storage_end(&storage); + emmc_part_read(pkg2_part, BCT_SIZE / EMMC_BLOCKSIZE, + pkg2_size_aligned / EMMC_BLOCKSIZE, ctxt->pkg2); +out: + emmc_gpt_free(&gpt); return bctBuf; } static void _free_launch_components(launch_ctxt_t *ctxt) { + // Free the malloc'ed guaranteed addresses. + free(ctxt->pkg3); free(ctxt->keyblob); free(ctxt->pkg1); free(ctxt->pkg2); free(ctxt->warmboot); - free(ctxt->secmon); - free(ctxt->kernel); free(ctxt->kip1_patches); } -int hos_launch(ini_sec_t *cfg) +static bool _get_fs_exfat_compatible(link_t *info, u32 *hos_revision) { - minerva_change_freq(FREQ_1600); - launch_ctxt_t ctxt; - tsec_ctxt_t tsec_ctxt; - volatile secmon_mailbox_t *secmon_mb; + u32 fs_ids_cnt; + u32 sha_buf[32 / sizeof(u32)]; + kip1_id_t *kip_ids; - memset(&ctxt, 0, sizeof(launch_ctxt_t)); - memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t)); + LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link) + { + if (strcmp((char *)ki->kip1->name, "FS")) + continue; + + if (!se_calc_sha256_oneshot(sha_buf, ki->kip1, ki->size)) + break; + + pkg2_get_ids(&kip_ids, &fs_ids_cnt); + + for (int fs_idx = fs_ids_cnt - 1; fs_idx >= 0; fs_idx--) + { + if (!memcmp(sha_buf, kip_ids[fs_idx].hash, 8)) + { + // HOS Api special handling. + if ((fs_idx & ~1) == 16) // Check if it's 5.1.0. + *hos_revision = 1; + else if ((fs_idx & ~1) == 34) // Check if it's 10.2.0. + *hos_revision = 2; + + // Check if FAT32-only. + if (!(fs_idx & 1)) + return false; + + // FS is FAT32 + exFAT. + break; + } + } + + break; + } + + // FAT32 + exFAT or unknown FS version. + return true; +} + +void hos_launch(ini_sec_t *cfg) +{ + u8 kb; + u32 secmon_base; + u32 warmboot_base; + bool is_exo = false; + launch_ctxt_t ctxt = {0}; + tsec_ctxt_t tsec_ctxt = {0}; + + minerva_change_freq(FREQ_1600); + sdram_src_pllc(true); list_init(&ctxt.kip1_list); ctxt.cfg = cfg; @@ -453,137 +769,227 @@ int hos_launch(ini_sec_t *cfg) gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - gfx_printf("Initializing...\n\n"); + gfx_puts("Initializing...\n\n"); + + // Initialize eMMC/emuMMC. + int res = emummc_storage_init_mmc(); + if (res) + { + _hos_crit_error(res == 2 ? "Failed to init eMMC." : "Failed to init emuMMC."); + + goto error; + } + + // Check if SD Card is GPT. + if (sd_is_gpt()) + { + _hos_crit_error("SD has GPT only! Run Fix Hybrid MBR!"); + goto error; + } + + // Try to parse config if present. + if (!parse_boot_config(&ctxt)) + { + _hos_crit_error("Wrong ini cfg or missing/corrupt files!"); + goto error; + } // Read package1 and the correct keyblob. if (!_read_emmc_pkg1(&ctxt)) - return 0; - - // Try to parse config if present. - if (ctxt.cfg && !parse_boot_config(&ctxt)) { - _hos_crit_error("Wrong ini cfg or missing files!"); - return 0; + // Check if stock is enabled and device can boot in OFW. + if (ctxt.stock && (h_cfg.t210b01 || !tools_autorcm_enabled())) + { + sdram_src_pllc(false); + emmc_end(); + + WPRINTF("\nRebooting to OFW in 5s..."); + msleep(5000); + + power_set_state(REBOOT_BYPASS_FUSES); + } + goto error; } + kb = ctxt.pkg1_id->kb; + + bool emummc_enabled = emu_cfg.enabled && !h_cfg.emummc_force_disable; + // Enable emummc patching. - if (emu_cfg.enabled && !h_cfg.emummc_force_disable) + if (emummc_enabled) { if (ctxt.stock) { _hos_crit_error("Stock emuMMC is not supported yet!"); - return 0; + goto error; } - ctxt.atmosphere = true; // Set atmosphere patching in case of Stock emuMMC and no fss0. + ctxt.patch_krn_proc_id = true; // Set kernel process id patching in case of no pkg3. config_kip1patch(&ctxt, "emummc"); } + else if (!emu_cfg.enabled && ctxt.emummc_forced) + { + _hos_crit_error("emuMMC is forced but not enabled!"); + goto error; + } - // Check if fuses lower than 4.0.0 or 9.0.0 and if yes apply NO Gamecard patch. - // Additionally check if running emuMMC and disable GC if v3 fuses are burnt and HOS is <= 8.1.0. - if ((h_cfg.autonogc && - ((!(fuse_read_odm(7) & ~0xF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)) || // LAFW v2. - (!(fuse_read_odm(7) & ~0x3FF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_900)))) // LAFW v3. - || ((emu_cfg.enabled && !h_cfg.emummc_force_disable) && - ((fuse_read_odm(7) & 0x400) && (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_810)))) - config_kip1patch(&ctxt, "nogc"); + // If Auto NOGC is enabled, check if burnt fuses lower than installed HOS fuses and apply NOGC patch. + // For emuMMC, unconditionally enable NOGC when burnt fuses are higher than installed HOS fuses. + // Disable Auto NOGC in stock to prevent black screen (fatal error). Use kip1patch=nogc to force it. + if (!ctxt.stock) + { + u32 fuses = fuse_read_odm(7); + if ((h_cfg.autonogc && // Prevent GC fuse burning (sysMMC and emuMMC). + ( + (!(fuses & ~0xF) && (ctxt.pkg1_id->fuses >= 5)) || // LAFW v2, 4.0.0+ + (!(fuses & ~0x3FF) && (ctxt.pkg1_id->fuses >= 11)) || // LAFW v3, 9.0.0+ + (!(fuses & ~0x1FFF) && (ctxt.pkg1_id->fuses >= 14)) || // LAFW v4, 11.0.0+ + // Detection broken! Use kip1patch=nogc // LAFW v5, 12.0.0+ + (!(fuses & ~0x3FFF) && (ctxt.pkg1_id->fuses >= 15)) // LAFW v5, 12.0.2+ + ) + ) + || ((emummc_enabled) && // Force NOGC if already burnt (only emuMMC). + ( + ((fuses & BIT(10)) && (ctxt.pkg1_id->fuses <= 10)) || // HOS 9.0.0+ fuses burnt. + ((fuses & BIT(13)) && (ctxt.pkg1_id->fuses <= 13)) || // HOS 11.0.0+ fuses burnt. + // Detection broken! Use kip1patch=nogc // HOS 12.0.0+ + ((fuses & BIT(14)) && (ctxt.pkg1_id->fuses <= 14)) // HOS 12.0.2+ fuses burnt. + ) + )) + config_kip1patch(&ctxt, "nogc"); + } - gfx_printf("Loaded pkg1 & keyblob\n"); + gfx_printf("Loaded config and pkg1\n%s mode\n", ctxt.stock ? "Stock" : "CFW"); + + // Check if secmon is exosphere. + if (ctxt.secmon) + is_exo = !memcmp((void *)((u8 *)ctxt.secmon + ctxt.secmon_size - 4), "LENY", 4); + + // Get secmon and warmboot bases. + const pkg1_id_t *pk1_latest = pkg1_get_latest(); + secmon_base = is_exo ? pk1_latest->secmon_base : ctxt.pkg1_id->secmon_base; + warmboot_base = is_exo ? pk1_latest->warmboot_base : ctxt.pkg1_id->warmboot_base; + + // Set package1 and tsec fw offsets. + tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off; + tsec_ctxt.pkg1 = ctxt.pkg1; + tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off; // Generate keys. - if (!h_cfg.se_keygen_done) - { - tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off; - tsec_ctxt.pkg1 = ctxt.pkg1; - tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off; - tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base; - - if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) - { - _hos_crit_error("Failed to run sept"); - return 0; - } - - if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt)) - return 0; - gfx_printf("Generated keys\n"); - if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600) - h_cfg.se_keygen_done = 1; - } + if (!_hos_keygen(ctxt.keyblob, kb, &tsec_ctxt, ctxt.stock, is_exo)) + goto error; + gfx_puts("Generated keys\n"); // Decrypt and unpack package1 if we require parts of it. if (!ctxt.warmboot || !ctxt.secmon) { - if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600) - pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1); - - if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && !(emu_cfg.enabled && !h_cfg.emummc_force_disable)) + // Decrypt PK1 or PK11. + if (kb <= HOS_KB_VERSION_600 || h_cfg.t210b01) { - pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1); - gfx_printf("Decrypted & unpacked pkg1\n"); + if (!pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1)) + { + _hos_crit_error("Pkg1 decryption failed!"); + + // Check if T210B01 BEK is missing or wrong. + if (h_cfg.t210b01) + { + u32 bek_vector[4] = {0}; + se_aes_crypt_ecb(13, ENCRYPT, bek_vector, SE_KEY_128_SIZE, bek_vector, SE_KEY_128_SIZE); + if (bek_vector[0] == 0x59C14895) // Encrypted zeroes first 32bits. + EPRINTF("Pkg1 corrupt?"); + else + EPRINTF("BEK is missing!"); + } + goto error; + } + } + + // Unpack PK11. + if (h_cfg.t210b01 || (kb <= HOS_KB_VERSION_620 && !emummc_enabled)) + { + // Skip T210B01 OEM header. + u32 pk1_offset = 0; + if (h_cfg.t210b01) + pk1_offset = sizeof(bl_hdr_t210b01_t); + + pkg1_unpack((void *)warmboot_base, &ctxt.warmboot_size, + !is_exo ? (void *)ctxt.pkg1_id->secmon_base : NULL, NULL, + ctxt.pkg1_id, ctxt.pkg1 + pk1_offset); + + gfx_puts("Decrypted & unpacked pkg1\n"); } else { - _hos_crit_error("No mandatory secmon or warmboot provided!"); - return 0; + _hos_crit_error("No mandatory pkg1 files provided!"); + goto error; } } + // Configure and manage Warmboot binary. + if (!pkg1_warmboot_config(&ctxt, warmboot_base, ctxt.pkg1_id->fuses, kb)) + { + // Can only happen on T210B01. + _hos_crit_error("\nFailed to match warmboot with fuses!\nIf you continue, sleep wont work!"); + + gfx_puts("\nPress POWER to continue.\nPress VOL to go to the menu.\n"); + display_backlight_brightness(h_cfg.backlight, 1000); + + if (!(btn_wait() & BTN_POWER)) + goto error; + } + // Replace 'warmboot.bin' if requested. if (ctxt.warmboot) - memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size); - else + memcpy((void *)warmboot_base, ctxt.warmboot, ctxt.warmboot_size); + else if (!h_cfg.t210b01) { - if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700) + // Patch warmboot on T210 to allow downgrading. + if (kb >= HOS_KB_VERSION_700) { _hos_crit_error("No warmboot provided!"); - return 0; + goto error; } - // Else we patch it to allow downgrading. - patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset; - gfx_printf("%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC); - for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++) - *(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val; - } - // Set warmboot address in PMC if required. - if (ctxt.pkg1_id->set_warmboot) - PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base; - // Replace 'SecureMonitor' if requested. + pkg1_warmboot_patch((void *)&ctxt); + } + + // Replace 'SecureMonitor' if requested or patch Pkg2 checks if needed. if (ctxt.secmon) - memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); - else if (ctxt.pkg1_id->secmon_patchset) - { - // Else we patch it to allow for an unsigned package2 and patched kernel. - patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; - gfx_printf("%kPatching Security Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC); - for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) - *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; - } + memcpy((void *)secmon_base, ctxt.secmon, ctxt.secmon_size); + else + pkg1_secmon_patch((void *)&ctxt, secmon_base, h_cfg.t210b01); - gfx_printf("Loaded warmboot and secmon\n"); + gfx_puts("Loaded warmboot and secmon\n"); // Read package2. u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt); if (!bootConfigBuf) - return 0; + { + _hos_crit_error("Pkg2 read failed!"); + goto error; + } - gfx_printf("Read pkg2\n"); + gfx_puts("Read pkg2\n"); // Decrypt package2 and parse KIP1 blobs in INI1 section. - pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2, ctxt.pkg1_id->kb); + pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2, kb, is_exo); if (!pkg2_hdr) { - _hos_crit_error("Pkg2 decryption failed!"); - if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700) - EPRINTF("Is Sept updated?"); - return 0; + _hos_crit_error("Pkg2 decryption failed!\npkg1/pkg2 mismatch or old hekate!"); + + // Clear EKS slot, in case something went wrong with tsec keygen. + _hos_eks_clear(kb); + goto error; } LIST_INIT(kip1_info); - pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2); + if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2)) + { + _hos_crit_error("INI1 parsing failed!"); + goto error; + } - gfx_printf("Parsed ini1\n"); + gfx_puts("Parsed ini1\n"); // Use the kernel included in package2 in case we didn't load one already. if (!ctxt.kernel) @@ -591,14 +997,14 @@ int hos_launch(ini_sec_t *cfg) ctxt.kernel = pkg2_hdr->data; ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; - if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere)) + if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.patch_krn_proc_id)) { - u8 kernel_hash[0x20]; // Hash only Kernel when it embeds INI1. + u8 kernel_hash[0x20]; if (!ctxt.new_pkg2) - se_calc_sha256(kernel_hash, ctxt.kernel, ctxt.kernel_size); + se_calc_sha256_oneshot(kernel_hash, ctxt.kernel, ctxt.kernel_size); else - se_calc_sha256(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START, + se_calc_sha256_oneshot(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START, pkg2_newkern_ini1_start - PKG2_NEWKERN_START); ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash); @@ -606,22 +1012,22 @@ int hos_launch(ini_sec_t *cfg) { _hos_crit_error("Failed to identify kernel!"); - return 0; + goto error; } // In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode. - kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset; + const kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset; if (kernel_patchset != NULL) { - gfx_printf("%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC); + gfx_printf("%kPatching kernel%k\n", TXT_CLR_ORANGE, TXT_CLR_DEFAULT); u32 *temp; for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++) { if ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS) - || (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.atmosphere && ctxt.secmon)) - || (ctxt.atmosphere && kernel_patchset[i].id == ATM_GEN_PATCH)) + || (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.patch_krn_proc_id && ctxt.secmon)) + || (ctxt.patch_krn_proc_id && kernel_patchset[i].id == ATM_GEN_PATCH)) *(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val; - else if (ctxt.atmosphere && kernel_patchset[i].id == ATM_ARR_PATCH) + else if (ctxt.patch_krn_proc_id && kernel_patchset[i].id == ATM_ARR_PATCH) { temp = (u32 *)kernel_patchset[i].ptr; for (u32 j = 0; j < kernel_patchset[i].val; j++) @@ -635,137 +1041,162 @@ int hos_launch(ini_sec_t *cfg) } // Merge extra KIP1s into loaded ones. - gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC); LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); - // Patch kip1s in memory if needed. - const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches); - if (unappliedPatch != NULL) + // Check if FS is compatible with exFAT and if 5.1.0. + if (!ctxt.stock && (sd_fs.fs_type == FS_EXFAT || kb == HOS_KB_VERSION_500 || ctxt.pkg1_id->fuses == 13)) { - EHPRINTFARGS("Failed to apply '%s'!", unappliedPatch); + bool exfat_compat = _get_fs_exfat_compatible(&kip1_info, &ctxt.exo_ctx.hos_revision); - _free_launch_components(&ctxt); - return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated! + if (sd_fs.fs_type == FS_EXFAT && !exfat_compat) + { + _hos_crit_error("SD Card is exFAT but installed HOS driver\nonly supports FAT32!"); + + goto error; + } + } + + // Patch kip1s in memory if needed. + const char *failed_patch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches); + if (failed_patch != NULL) + { + EHPRINTFARGS("Failed to apply '%s'!", failed_patch); + + bool emmc_patch_failed = !strcmp(failed_patch, "emummc"); + if (!emmc_patch_failed) + { + gfx_puts("\nPress POWER to continue.\nPress VOL to go to the menu.\n"); + display_backlight_brightness(h_cfg.backlight, 1000); + } + + if (emmc_patch_failed || !(btn_wait() & BTN_POWER)) + goto error; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated! } // Rebuild and encrypt package2. - pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info, ctxt.new_pkg2); + pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, &ctxt, &kip1_info, is_exo); - gfx_printf("Rebuilt & loaded pkg2\n"); + // Configure Exosphere if secmon is replaced. + if (is_exo) + config_exosphere(&ctxt, warmboot_base); - // Unmount SD card. - sd_unmount(); + // Unmount SD card and eMMC. + sd_end(); + emmc_end(); - gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC); + // Close AHB aperture. Important when stock old secmon is used. + mc_disable_ahb_redirect(); + + gfx_printf("Rebuilt & loaded pkg2\n\n%kBooting...%k\n", TXT_CLR_GREENISH, TXT_CLR_DEFAULT); // Clear pkg1/pkg2 keys. se_aes_key_clear(8); se_aes_key_clear(11); - // Finalize per firmware keys. - int bootStateDramPkg2 = 0; - int bootStatePkg2Continue = 0; + // Clear derived master key in case of Erista and 7.0.0+ + se_aes_key_clear(9); - switch (ctxt.pkg1_id->kb) + // Set secmon mailbox pkg2 ready state. + u32 pkg1_state_pkg2_ready = PKG1_STATE_PKG2_READY; + + // Finalize per firmware key access. Skip access control if Exosphere 2. + switch (kb | (is_exo << 7)) { - case KB_FIRMWARE_VERSION_100_200: - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_300) - PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id. - else if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_301) - PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id. - se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG); - se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG); - bootStateDramPkg2 = 2; - bootStatePkg2Continue = 3; + case HOS_KB_VERSION_100: + case HOS_KB_VERSION_300: + case HOS_KB_VERSION_301: + se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG); + se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG); + pkg1_state_pkg2_ready = PKG1_STATE_PKG2_READY_OLD; break; - case KB_FIRMWARE_VERSION_400: - case KB_FIRMWARE_VERSION_500: - case KB_FIRMWARE_VERSION_600: - se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG); - se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG); - default: - bootStateDramPkg2 = 2; - bootStatePkg2Continue = 4; + case HOS_KB_VERSION_400: + case HOS_KB_VERSION_500: + case HOS_KB_VERSION_600: + se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG); + se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG); break; } // Clear BCT area for retail units and copy it over if dev unit. - if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_500) + if (kb <= HOS_KB_VERSION_500 && !is_exo) { - memset((void *)0x4003D000, 0, 0x3000); - if ((fuse_read_odm(4) & 3) == 3) - memcpy((void *)0x4003D000, bootConfigBuf, 0x1000); + memset((void *)SECMON_BCT_CFG_ADDR, 0, SZ_4K + SZ_8K); + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) + memcpy((void *)SECMON_BCT_CFG_ADDR, bootConfigBuf, SZ_4K); } else { - memset((void *)0x4003F000, 0, 0x1000); - if ((fuse_read_odm(4) & 3) == 3) - memcpy((void *)0x4003F800, bootConfigBuf, 0x800); + memset((void *)SECMON6_BCT_CFG_ADDR, 0, SZ_2K); + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) + memcpy((void *)SECMON6_BCT_CFG_ADDR, bootConfigBuf, SZ_2K); } - free(bootConfigBuf); - - // Config Exosphère if booting full Atmosphère. - if (ctxt.atmosphere && ctxt.secmon) - config_exosphere(&ctxt); // Finalize MC carveout. - if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301) + if (kb <= HOS_KB_VERSION_301 && !is_exo) mc_config_carveout(); // Lock SE before starting 'SecureMonitor' if < 6.2.0, otherwise lock bootrom and ipatches. - _se_lock(ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600); + _se_lock(kb <= HOS_KB_VERSION_600 && !is_exo); - // Reset sysctr0 counters. - if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620) - _sysctr0_reset(); + // Reset sysctr0 counters. Mandatory for 6.2.0 and up. + for (u32 i = 0; i < SYSCTR0_COUNTERS; i++) + SYSCTR0(SYSCTR0_COUNTERS_BASE + i * sizeof(u32)) = 0; - // < 4.0.0 pkg1.1 locks PMC scratches. - //_pmc_scratch_lock(ctxt.pkg1_id->kb); + // NX Bootloader locks LP0 Carveout secure scratch registers. + //pmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS); - // Set secmon mailbox address. - if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700) - secmon_mb = (secmon_mailbox_t *)SECMON7_MB_ADDR; + // Set secmon mailbox address and clear it. + volatile secmon_mailbox_t *secmon_mailbox; + if (kb >= HOS_KB_VERSION_700 || is_exo) + { + memset((void *)SECMON7_MAILBOX_ADDR, 0, 0x200); + secmon_mailbox = (secmon_mailbox_t *)(SECMON7_MAILBOX_ADDR + SECMON_STATE_OFFSET); + } else - secmon_mb = (secmon_mailbox_t *)SECMON_MB_ADDR; + { + if (kb <= HOS_KB_VERSION_301) + memset((void *)SECMON_MAILBOX_ADDR, 0, 0x200); + secmon_mailbox = (secmon_mailbox_t *)(SECMON_MAILBOX_ADDR + SECMON_STATE_OFFSET); + } - // Start from DRAM ready signal and reset outgoing value. - secmon_mb->in = bootStateDramPkg2; - secmon_mb->out = 0; - - // Free allocated memory. - _free_launch_components(&ctxt); + // Start directly from PKG2 ready signal and reset outgoing value. + secmon_mailbox->in = pkg1_state_pkg2_ready; + secmon_mailbox->out = SECMON_STATE_NOT_READY; // Disable display. This must be executed before secmon to provide support for all fw versions. display_end(); + clock_disable_host1x(); - // Clear EMC_SCRATCH0. - EMC(EMC_SCRATCH0) = 0; + // Override uCID if set. + EMC(EMC_SCRATCH0) = ctxt.ucid; + + // Hold USBD, USB2, AHBDMA and APBDMA in reset for SoC state validation on sleep. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_AHBDMA) | BIT(CLK_H_APBDMA) | BIT(CLK_H_USB2); + + // Reset arbiter. + hw_config_arbiter(true); + + // Scale down RAM OC if enabled. + sdram_src_pllc(false); + minerva_prep_boot_freq(); // Flush cache and disable MMU. bpmp_mmu_disable(); bpmp_clk_rate_set(BPMP_CLK_NORMAL); - minerva_change_freq(FREQ_1600); - // emuMMC: Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. - sdmmc_storage_init_wait_sd(); + // Launch secmon. + ccplex_boot_cpu0(secmon_base, true); - // Wait for secmon to get ready. - if (smmu_is_used()) - smmu_exit(); - else - cluster_boot_cpu0(ctxt.pkg1_id->secmon_base); - while (!secmon_mb->out) - ; // A usleep(1) only works when in IRAM or with a trained DRAM. - - // Signal pkg2 ready and continue boot. - secmon_mb->in = bootStatePkg2Continue; - - // Halt ourselves in waitevent state and resume if there's JTAG activity. + // Halt ourselves in wait-event state. while (true) bpmp_halt(); - return 0; +error: + _free_launch_components(&ctxt); + sdram_src_pllc(false); + emmc_end(); + + EPRINTF("\nFailed to launch HOS!"); } diff --git a/bootloader/hos/hos.h b/bootloader/hos/hos.h index 63f724d..a04f650 100644 --- a/bootloader/hos/hos.h +++ b/bootloader/hos/hos.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,26 +18,69 @@ #ifndef _HOS_H_ #define _HOS_H_ +#include + #include "pkg1.h" #include "pkg2.h" -#include "../utils/types.h" -#include "../config/ini.h" -#include "../sec/tsec.h" -#define KB_FIRMWARE_VERSION_100_200 0 -#define KB_FIRMWARE_VERSION_300 1 -#define KB_FIRMWARE_VERSION_301 2 -#define KB_FIRMWARE_VERSION_400 3 -#define KB_FIRMWARE_VERSION_500 4 -#define KB_FIRMWARE_VERSION_600 5 -#define KB_FIRMWARE_VERSION_620 6 -#define KB_FIRMWARE_VERSION_700 7 -#define KB_FIRMWARE_VERSION_810 8 -#define KB_FIRMWARE_VERSION_900 9 -#define KB_FIRMWARE_VERSION_910 10 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 +#include -#define HOS_PKG11_MAGIC 0x31314B50 +//!TODO: Update on mkey changes. +enum { + HOS_KB_VERSION_100 = 0, + HOS_KB_VERSION_300 = 1, + HOS_KB_VERSION_301 = 2, + HOS_KB_VERSION_400 = 3, + HOS_KB_VERSION_500 = 4, + HOS_KB_VERSION_600 = 5, + HOS_KB_VERSION_620 = 6, + HOS_KB_VERSION_700 = 7, + HOS_KB_VERSION_810 = 8, + HOS_KB_VERSION_900 = 9, + HOS_KB_VERSION_910 = 10, + HOS_KB_VERSION_1210 = 11, + HOS_KB_VERSION_1300 = 12, + HOS_KB_VERSION_1400 = 13, + HOS_KB_VERSION_1500 = 14, + HOS_KB_VERSION_1600 = 15, + HOS_KB_VERSION_1700 = 16, + HOS_KB_VERSION_1800 = 17, + HOS_KB_VERSION_1900 = 18, + HOS_KB_VERSION_2000 = 19, + HOS_KB_VERSION_MAX = HOS_KB_VERSION_2000 +}; + +#define HOS_TSEC_VERSION 4 //! TODO: Update on TSEC Root Key changes. + +#define HOS_PKG11_MAGIC 0x31314B50 +#define HOS_EKS_MAGIC 0x31534B45 // EKS1. +#define HOS_EKS_TSEC_VER (HOS_KB_VERSION_700 + HOS_TSEC_VERSION) + +// Use official Mariko secmon when in stock. Needs access to TZRAM. +//#define HOS_MARIKO_STOCK_SECMON + +typedef struct _exo_ctxt_t +{ + u32 hos_revision; + bool no_user_exceptions; + bool user_pmu; + bool *usb3_force; + bool *cal0_blank; + bool *cal0_allow_writes_sys; +} exo_ctxt_t; + +typedef struct _hos_eks_mbr_t +{ + u32 magic; + u32 enabled; + u32 lot0; + u32 rsvd; + u8 tsec[SE_KEY_128_SIZE]; + u8 troot[SE_KEY_128_SIZE]; + u8 troot_dev[SE_KEY_128_SIZE]; +} hos_eks_mbr_t; + +static_assert(sizeof(hos_eks_mbr_t) == 64, "HOS EKS size is wrong!"); typedef struct _launch_ctxt_t { @@ -50,24 +94,31 @@ typedef struct _launch_ctxt_t u32 warmboot_size; void *secmon; u32 secmon_size; + void *exofatal; + u32 exofatal_size; void *pkg2; u32 pkg2_size; bool new_pkg2; - void *kernel; - u32 kernel_size; - link_t kip1_list; - char* kip1_patches; + void *kernel; + u32 kernel_size; + + link_t kip1_list; + char *kip1_patches; - u32 fss0_hosver; bool svcperm; bool debugmode; bool stock; - bool atmosphere; - bool exo_no_user_exceptions; - bool exo_user_pmu; - bool emuMMC; + bool emummc_forced; + + void *pkg3; + u32 pkg3_hosver; + bool patch_krn_proc_id; + + int ucid; + + exo_ctxt_t exo_ctx; ini_sec_t *cfg; } launch_ctxt_t; @@ -78,7 +129,6 @@ typedef struct _merge_kip_t link_t link; } merge_kip_t; -int hos_launch(ini_sec_t *cfg); -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); +void hos_launch(ini_sec_t *cfg); #endif diff --git a/bootloader/hos/hos_config.c b/bootloader/hos/hos_config.c index d0b09c8..6bfb4a7 100644 --- a/bootloader/hos/hos_config.c +++ b/bootloader/hos/hos_config.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,20 +17,16 @@ #include +#include + #include "hos.h" #include "hos_config.h" -#include "fss.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/dirlist.h" - -#include "../gfx/gfx.h" +#include "pkg3.h" +#include //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -extern void *sd_file_read(const char *path, u32 *fsize); - static int _config_warmboot(launch_ctxt_t *ctxt, const char *value) { ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size); @@ -62,14 +58,14 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value) { u32 size; - if (!memcmp(value + strlen(value) - 1, "*", 1)) + if (value[strlen(value) - 1] == '*') { char *dir = (char *)malloc(256); strcpy(dir, value); u32 dirlen = 0; dir[strlen(dir) - 2] = 0; - char *filelist = dirlist(dir, "*.kip*", false); + dirlist_t *filelist = dirlist(dir, "*.kip*", false, false); strcat(dir, "/"); dirlen = strlen(dir); @@ -79,10 +75,10 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value) { while (true) { - if (!filelist[i * 256]) + if (!filelist->name[i]) break; - strcpy(dir + dirlen, &filelist[i * 256]); + strcpy(dir + dirlen, filelist->name[i]); merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); mkip1->kip1 = sd_file_read(dir, &size); @@ -123,30 +119,28 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value) int config_kip1patch(launch_ctxt_t *ctxt, const char *value) { - if (value == NULL) - return 0; - - int valueLen = strlen(value); - if (!valueLen) + int len = strlen(value); + if (!len) return 0; if (ctxt->kip1_patches == NULL) { - ctxt->kip1_patches = malloc(valueLen + 1); - memcpy(ctxt->kip1_patches, value, valueLen); - ctxt->kip1_patches[valueLen] = 0; + ctxt->kip1_patches = malloc(len + 1); + memcpy(ctxt->kip1_patches, value, len); + ctxt->kip1_patches[len] = 0; } else { - char *oldAlloc = ctxt->kip1_patches; - int oldSize = strlen(oldAlloc); - ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1); - memcpy(ctxt->kip1_patches, oldAlloc, oldSize); - free(oldAlloc); - oldAlloc = NULL; - ctxt->kip1_patches[oldSize++] = ','; - memcpy(&ctxt->kip1_patches[oldSize], value, valueLen); - ctxt->kip1_patches[oldSize + valueLen] = 0; + char *old_addr = ctxt->kip1_patches; + int old_len = strlen(old_addr); + + ctxt->kip1_patches = malloc(old_len + 1 + len + 1); + memcpy(ctxt->kip1_patches, old_addr, old_len); + free(old_addr); + + ctxt->kip1_patches[old_len++] = ','; + memcpy(&ctxt->kip1_patches[old_len], value, len); + ctxt->kip1_patches[old_len + len] = 0; } return 1; } @@ -181,12 +175,22 @@ static int _config_stock(launch_ctxt_t *ctxt, const char *value) return 1; } -static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value) +static int _config_emummc_forced(launch_ctxt_t *ctxt, const char *value) { if (*value == '1') { - DPRINTF("Enabled atmosphere patching\n"); - ctxt->atmosphere = true; + DPRINTF("Forced emuMMC\n"); + ctxt->emummc_forced = true; + } + return 1; +} + +static int _config_kernel_proc_id(launch_ctxt_t *ctxt, const char *value) +{ + if (*value == '1') + { + DPRINTF("Enabled kernel process id send/recv patching\n"); + ctxt->patch_krn_proc_id = true; } return 1; } @@ -196,7 +200,7 @@ static int _config_dis_exo_user_exceptions(launch_ctxt_t *ctxt, const char *valu if (*value == '1') { DPRINTF("Disabled exosphere user exception handlers\n"); - ctxt->exo_no_user_exceptions = true; + ctxt->exo_ctx.no_user_exceptions = true; } return 1; } @@ -206,14 +210,71 @@ static int _config_exo_user_pmu_access(launch_ctxt_t *ctxt, const char *value) if (*value == '1') { DPRINTF("Enabled user access to PMU\n"); - ctxt->exo_user_pmu = true; + ctxt->exo_ctx.user_pmu = true; } return 1; } -static int _config_fss(launch_ctxt_t *ctxt, const char *value) +static int _config_exo_usb3_force(launch_ctxt_t *ctxt, const char *value) { - return parse_fss(ctxt, value, NULL); + // Override key found. + ctxt->exo_ctx.usb3_force = zalloc(sizeof(bool)); + + if (*value == '1') + { + DPRINTF("Enabled USB 3.0\n"); + *ctxt->exo_ctx.usb3_force = true; + } + return 1; +} + +static int _config_exo_cal0_blanking(launch_ctxt_t *ctxt, const char *value) +{ + // Override key found. + ctxt->exo_ctx.cal0_blank = zalloc(sizeof(bool)); + + if (*value == '1') + { + DPRINTF("Enabled prodinfo blanking\n"); + *ctxt->exo_ctx.cal0_blank = true; + } + return 1; +} + +static int _config_exo_cal0_writes_enable(launch_ctxt_t *ctxt, const char *value) +{ + // Override key found. + ctxt->exo_ctx.cal0_allow_writes_sys = zalloc(sizeof(bool)); + + if (*value == '1') + { + DPRINTF("Enabled prodinfo writes\n"); + *ctxt->exo_ctx.cal0_allow_writes_sys = true; + } + + return 1; +} + +static int _config_pkg3(launch_ctxt_t *ctxt, const char *value) +{ + return parse_pkg3(ctxt, value); +} + +static int _config_exo_fatal_payload(launch_ctxt_t *ctxt, const char *value) +{ + ctxt->exofatal = sd_file_read(value, &ctxt->exofatal_size); + if (!ctxt->exofatal) + return 0; + + return 1; +} + +static int _config_ucid(launch_ctxt_t *ctxt, const char *value) +{ + // Override uCID if set. + ctxt->ucid = atoi(value); + + return 1; } typedef struct _cfg_handler_t @@ -223,33 +284,54 @@ typedef struct _cfg_handler_t } cfg_handler_t; static const cfg_handler_t _config_handlers[] = { - { "warmboot", _config_warmboot }, - { "secmon", _config_secmon }, - { "kernel", _config_kernel }, - { "kip1", _config_kip1 }, - { "kip1patch", config_kip1patch }, - { "fullsvcperm", _config_svcperm }, - { "debugmode", _config_debugmode }, - { "stock", _config_stock }, - { "atmosphere", _config_atmosphere }, + { "stock", _config_stock }, + { "warmboot", _config_warmboot }, + { "secmon", _config_secmon }, + { "kernel", _config_kernel }, + { "kip1", _config_kip1 }, + { "kip1patch", config_kip1patch }, + { "fullsvcperm", _config_svcperm }, + { "debugmode", _config_debugmode }, + { "kernelprocid", _config_kernel_proc_id }, + + // To override elements from PKG3, it should be set before others. + { "pkg3", _config_pkg3 }, + { "fss0", _config_pkg3 }, + + { "exofatal", _config_exo_fatal_payload}, + { "emummcforce", _config_emummc_forced }, { "nouserexceptions", _config_dis_exo_user_exceptions }, - { "userpmu", _config_exo_user_pmu_access }, - { "fss0", _config_fss }, + { "userpmu", _config_exo_user_pmu_access }, + { "usb3force", _config_exo_usb3_force }, + { "cal0blank", _config_exo_cal0_blanking }, + { "cal0writesys", _config_exo_cal0_writes_enable }, + { "ucid", _config_ucid }, { NULL, NULL }, }; int parse_boot_config(launch_ctxt_t *ctxt) { + if (!ctxt->cfg) + return 1; + + // Check each config key. LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) { - for(u32 i = 0; _config_handlers[i].key; i++) + for (u32 i = 0; _config_handlers[i].key; i++) { + // If key matches, call its handler. if (!strcmp(_config_handlers[i].key, kv->key)) + { if (!_config_handlers[i].handler(ctxt, kv->val)) { + gfx_con.mute = false; EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val); + return 0; } + + break; + } } } diff --git a/bootloader/hos/pkg1.c b/bootloader/hos/pkg1.c index 2a9d7ec..9d6b783 100644 --- a/bootloader/hos/pkg1.c +++ b/bootloader/hos/pkg1.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -18,62 +18,49 @@ */ #include +#include +#include + +#include "hos.h" #include "pkg1.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../utils/aarch64_util.h" +#include "../config.h" +#include -#define _NOPv7() 0xE320F000 +extern hekate_config h_cfg; -#define SM_100_ADR 0x4002B020 +// Secmon package2 signature/hash checks patches for Erista. +#define SM_100_ADR 0x4002B020 // Original: 0x40014020. PATCHSET_DEF(_secmon_1_patchset, // Patch the relocator to be able to run from SM_100_ADR. - { 0x1E0, _ADRP(0, 0x7C013000 - _PAGEOFF(SM_100_ADR)) }, - //Patch package2 decryption and signature/hash checks. - { 0x9F0 + 0xADC, _NOP() }, //Header signature. - { 0x9F0 + 0xB8C, _NOP() }, //Version. - { 0x9F0 + 0xBB0, _NOP() } //Sections SHA2. + { 0x1E0, _ADRP(0, TZRAM_BASE + 0x3000 - _PAGEOFF(SM_100_ADR)) }, + // Patch package2 signature/hash checks. + { 0x9F0 + 0xADC, _NOP() } ); 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. + // Patch package2 signature/hash checks. + { 0xAC8 + 0xAAC, _NOP() } ); PATCHSET_DEF(_secmon_3_patchset, - // Patch package2 decryption and signature/hash checks. - { 0xAC8 + 0xA30, _NOP() }, //Header signature. - { 0xAC8 + 0xAB4, _NOP() }, //package2 structure. - { 0xAC8 + 0xAC0, _NOP() }, //Version. - { 0xAC8 + 0xADC, _NOP() } //Sections SHA2. + // Patch package2 signature/hash checks. + { 0xAC8 + 0xA30, _NOP() } ); PATCHSET_DEF(_secmon_4_patchset, - // Patch package2 decryption and signature/hash checks. - { 0x2300 + 0x5D80, _NOP() }, //package2 structure. - { 0x2300 + 0x5D8C, _NOP() }, //Version. - { 0x2300 + 0x5EFC, _NOP() }, //Header signature. - { 0xAC8 + 0xA2C, _NOP() } //Sections SHA2. + // Patch package2 signature/hash checks. + { 0x2300 + 0x5EFC, _NOP() } ); PATCHSET_DEF(_secmon_5_patchset, - // Patch package2 decryption and signature/hash checks. - { 0xDA8 + 0x9D8, _NOP() }, //package2 structure. - { 0xDA8 + 0x9E4, _NOP() }, //Version. - { 0xDA8 + 0xC9C, _NOP() }, //Header signature. - { 0xDA8 + 0x1038, _NOP() } //Sections SHA2. + // Patch package2 signature/hash checks. + { 0xDA8 + 0xC9C, _NOP() } ); PATCHSET_DEF(_secmon_6_patchset, - // Patch package2 decryption and signature/hash checks. - { 0xDC8 + 0x820, _NOP() }, //package2 structure. - { 0xDC8 + 0x82C, _NOP() }, //Version. - { 0xDC8 + 0xE90, _NOP() }, //Header signature. - { 0xDC8 + 0x112C, _NOP() } //Sections SHA2. + // Patch package2 signature/hash checks. + { 0xDC8 + 0xE90, _NOP() } // Fix sleep mode for debug. // { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart. // { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta. @@ -84,12 +71,9 @@ PATCHSET_DEF(_secmon_6_patchset, // { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg. ); -PATCHSET_DEF(_secmon_620_patchset, - // Patch package2 decryption and signature/hash checks. - { 0xDC8 + 0x604, _NOP() }, //package2 structure. - { 0xDC8 + 0x610, _NOP() }, //Version. - { 0xDC8 + 0xC74, _NOP() }, //Header signature. - { 0xDC8 + 0xF10, _NOP() } //Sections SHA2. +PATCHSET_DEF(_secmon_62_patchset, + // Patch package2 signature/hash checks. + { 0xDC8 + 0xC74, _NOP() } // Fix sleep mode for debug. // { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart. // { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta. @@ -100,11 +84,40 @@ PATCHSET_DEF(_secmon_620_patchset, // { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg. ); -PATCHSET_DEF(_warmboot_1_patchset, - { 0x4DC, _NOPv7() } // Fuse check. +// Secmon patches for Mariko. +#define TZRAM_PROG_ADDR (TZRAM_BASE + 0x800) +#define TZRAM_COMPR_PROG_OFF 0xE04 +#define TZRAM_PROG_PK2_SIG_PATCH (TZRAM_PROG_ADDR + 0xC10) +#define TZRAM_PROG_PK2_SIG_PATCH_1000 (TZRAM_PROG_ADDR + 0xD70) +PATCHSET_DEF(_secmon_6_mariko_patchset, + // Patch package2 decryption and signature/hash checks. + { 0xDC8 + 0xE94, _NOP() } ); -PATCHSET_DEF(_warmboot_2_patchset, +PATCHSET_DEF(_secmon_620_mariko_patchset, + // Patch package2 decryption and signature/hash checks. + { 0xDC8 + 0xC78, _NOP() } +); + +// From 7.0.0 and above secmon is compressed. +PATCHSET_DEF(_secmon_7_mariko_patchset, + // Patch out decompression of program payload. + { 0x82C, _NOP() } +); + +const u16 _secmon_mariko_prog_comp_size[] = { + 0x6B03, // 7.0.0. Patch offset: 0xC10. + 0x6B16, // 7.0.1. Patch offset: 0xC10. + 0x6B23, // 8.0.0. Patch offset: 0xC10. + 0x6B84, // 8.1.0. Patch offset: 0xC10. + 0x6C90, // 9.0.0. Patch offset: 0xC10. + 0x6CE5, // 9.1.0. Patch offset: 0xC10. + 0x6EE9, // 10.0.0. Patch offset: 0xD70. +}; + +// Erista fuse check warmboot patches. +#define _NOPv7() 0xE320F000 +PATCHSET_DEF(_warmboot_1_patchset, { 0x4DC, _NOPv7() } // Fuse check. ); @@ -118,76 +131,339 @@ PATCHSET_DEF(_warmboot_4_patchset, { 0x558, _NOPv7() } // Segment id check. ); - /* * 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 } - * 6.0: {ldr, sm, wb} { 1, 2, 0 } - * 6.2: {ldr, sm, wb} { 1, 2, 0 } - * 7.0: {ldr, sm, wb} { 1, 2, 0 } + * 1.0: {sm, ldr, wb} { 2, 1, 0 } + * 2.0+: {wb, ldr, sm} { 0, 1, 2 } + * 4.0+: {ldr, sm, wb} { 1, 2, 0 } */ +static const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTION_WB }; +static const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM }; +static const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB }; + + // Timestamp KB FU TSEC PK11 SECMON Warmboot static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator) - { "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0 - { "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0 - { "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2 - { "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0 - { "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0 - { "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0 - { "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0 - { "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0 - { "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1 - { "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1 - { "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0 - { "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1 - { "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0 - { NULL } //End. + { "20161121", 0, 1, 0x1900, 0x3FE0, SM_100_ADR, 0x8000D000, _secmon_1_patchset }, // 1.0.0 (Patched relocator). + { "20170210", 0, 2, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_2_patchset }, // 2.0.0 - 2.3.0. + { "20170519", 1, 3, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_3_patchset }, // 3.0.0. + { "20170710", 2, 4, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_3_patchset }, // 3.0.1 - 3.0.2. + { "20170921", 3, 5, 0x1800, 0x3FE0, 0x4002B000, 0x4003B000, _secmon_4_patchset }, // 4.0.0 - 4.1.0. + { "20180220", 4, 6, 0x1900, 0x3FE0, 0x4002B000, 0x4003B000, _secmon_5_patchset }, // 5.0.0 - 5.1.0. + { "20180802", 5, 7, 0x1900, 0x3FE0, 0x4002B000, 0x4003D800, _secmon_6_patchset }, // 6.0.0 - 6.1.0. + { "20181107", 6, 8, 0x0E00, 0x6FE0, 0x4002B000, 0x4003D800, _secmon_62_patchset}, // 6.2.0. + { "20181218", 7, 9, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 7.0.0. + { "20190208", 7, 9, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 7.0.1. + { "20190314", 7, 9, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 8.0.0 - 8.0.1. + { "20190531", 8, 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 8.1.0 - 8.1.1. + { "20190809", 9, 11, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 9.0.0 - 9.0.1. + { "20191021", 10, 12, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 9.1.0 - 9.2.0. + { "20200303", 10, 13, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 10.0.0 - 10.2.0. + { "20201030", 10, 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 11.0.0 - 11.0.1. + { "20210129", 10, 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 12.0.0 - 12.0.1. + { "20210422", 10, 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 12.0.2 - 12.0.3. + { "20210607", 11, 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 12.1.0. + { "20210805", 12, 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 13.0.0 - 13.2.0. + { "20220105", 12, 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 13.2.1. + { "20220209", 13, 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 14.0.0 - 14.1.2. + { "20220801", 14, 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 15.0.0 - 15.0.1. + { "20230111", 15, 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 16.0.0 - 16.1.0. + { "20230906", 16, 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 17.0.0 - 17.0.1. + { "20240207", 17, 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 18.0.0 - 18.1.0. + { "20240808", 18, 20, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 19.0.0 - 19.0.1. + { "20250206", 19, 21, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 20.0.0+ }; +const pkg1_id_t *pkg1_get_latest() +{ + return &_pkg1_ids[ARRAY_SIZE(_pkg1_ids) - 1]; +} + const pkg1_id_t *pkg1_identify(u8 *pkg1) { char build_date[15]; - memcpy(build_date, (char *)(pkg1 + 0x10), 14); + pk1_hdr_t *hdr = (pk1_hdr_t *)pkg1; + + memcpy(build_date, hdr->timestamp, 14); build_date[14] = 0; gfx_printf("Found pkg1 ('%s').\n\n", build_date); - for (u32 i = 0; _pkg1_ids[i].id; i++) - if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) + for (int i = ARRAY_SIZE(_pkg1_ids) - 1; i >= 0; i--) + if (!memcmp(hdr->timestamp, _pkg1_ids[i].id, 8)) return &_pkg1_ids[i]; + return NULL; } -void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1) +int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1) { + pk11_hdr_t *hdr; + // 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); + if (!h_cfg.t210b01) + { + u8 *pkg11 = pkg1 + id->pkg11_off; + u32 pkg11_size = *(u32 *)pkg11; + hdr = (pk11_hdr_t *)(pkg11 + 0x20); + se_aes_crypt_ctr(11, hdr, pkg11_size, hdr, pkg11_size, pkg11 + 0x10); + } + else + { + bl_hdr_t210b01_t *oem_hdr = (bl_hdr_t210b01_t *)pkg1; + pkg1 += sizeof(bl_hdr_t210b01_t); + hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20); + + // Use BEK for T210B01. + // Additionally, skip 0x20 bytes from decryption to maintain the header. + se_aes_iv_clear(13); + se_aes_crypt_cbc(13, DECRYPT, pkg1 + 0x20, oem_hdr->size - 0x20, pkg1 + 0x20, oem_hdr->size - 0x20); + } + + // Return if header is valid. + return (hdr->magic == PKG1_MAGIC); } -void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1) +const u8 *pkg1_unpack(void *wm_dst, u32 *wb_sz, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1) { - pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20); + const u8 *sec_map; + const 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 }; + // Get correct header mapping. + if (id->fuses == 1) // 1.0.0. + sec_map = sec_map_100; + else if (id->fuses >= 2 && id->fuses <= 4) // 2.0.0 - 3.0.2. + sec_map = sec_map_2xx; + else // 4.0.0+ + sec_map = sec_map_4xx; + + // Copy secmon, warmboot and nx bootloader payloads. 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] == 1 && ldr_dst) - memcpy(ldr_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]]; + u32 ssize = sec_size[sec_map[i]]; + switch (sec_map[i]) + { + case PK11_SECTION_WB: + if (wm_dst) + memcpy(wm_dst, pdata, ssize); + if (wb_sz) + *wb_sz = ssize; + break; + case PK11_SECTION_LD: + if (ldr_dst) + memcpy(ldr_dst, pdata, ssize); + break; + case PK11_SECTION_SM: + if (sm_dst) + memcpy(sm_dst, pdata, ssize); + break; + } + pdata += ssize; } + + return sec_map; +} + +void pkg1_secmon_patch(void *hos_ctxt, u32 secmon_base, bool t210b01) +{ + const patch_t *secmon_patchset; + launch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt; + + // Patch Secmon to allow for an unsigned package2 and patched kernel. + if (!t210b01 && ctxt->pkg1_id->secmon_patchset) + { + // For T210 till 6.2.0 the patching is used as is, because of no compression. + secmon_patchset = ctxt->pkg1_id->secmon_patchset; + } +#ifdef HOS_MARIKO_STOCK_SECMON + else if (t210b01) + { + // For T210B01 we patch 6.X.X as is. Otherwise we decompress the program payload. + if (ctxt->pkg1_id->kb == HOS_KB_VERSION_600) + secmon_patchset = _secmon_6_mariko_patchset; + else if (ctxt->pkg1_id->kb == HOS_KB_VERSION_620) + secmon_patchset = _secmon_620_mariko_patchset; + else + { + // Patch uncompress of program payload clear TZRAM. + secmon_patchset = _secmon_7_mariko_patchset; + memset((void *)TZRAM_PROG_ADDR, 0, 0x38800); + + // Get size of compressed program payload and set patch offset. + u32 idx = ctxt->pkg1_id->kb - HOS_KB_VERSION_700; + u32 patch_offset = TZRAM_PROG_PK2_SIG_PATCH; + if (ctxt->pkg1_id->kb > HOS_KB_VERSION_910 || !memcmp(ctxt->pkg1_id->id, "20200303", 8)) //TODO: Add 11.0.0 support. + { + idx++; + patch_offset = TZRAM_PROG_PK2_SIG_PATCH_1000; + } + + // Uncompress directly to TZRAM. + LZ4_decompress_fast((const char*)(secmon_base + TZRAM_COMPR_PROG_OFF), + (char *)TZRAM_PROG_ADDR, _secmon_mariko_prog_comp_size[idx]); + + // Patch package2 signature/hash checks. + *(vu32 *)patch_offset = _NOP(); + } + } +#endif + else + return; + + // Patch Secmon. + gfx_printf("%kPatching Secure Monitor%k\n", TXT_CLR_ORANGE, TXT_CLR_DEFAULT); + for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) + *(vu32 *)(secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; +} + +void pkg1_warmboot_patch(void *hos_ctxt) +{ + launch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt; + const patch_t *warmboot_patchset; + + // Patch warmboot on T210 to allow downgrading. + switch (ctxt->pkg1_id->kb) + { + case 0: + warmboot_patchset = _warmboot_1_patchset; + break; + case 1 ... 2: + warmboot_patchset = _warmboot_3_patchset; + break; + default: // 4.0.0 - 6.2.0. + warmboot_patchset = _warmboot_4_patchset; + break; + } + gfx_printf("%kPatching Warmboot%k\n", TXT_CLR_ORANGE, TXT_CLR_DEFAULT); + for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++) + *(vu32 *)(ctxt->pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val; +} + +static void _warmboot_filename(char *out, u32 fuses) +{ + if (fuses < 16) + { + out[19] = '0'; + itoa(fuses, &out[19 + 1], 16); + } + else + itoa(fuses, &out[19], 16); + strcat(out, ".bin"); +} + +int pkg1_warmboot_config(void *hos_ctxt, u32 warmboot_base, u32 fuses_fw, u8 kb) +{ + launch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt; + int res = 1; + + if (h_cfg.t210b01) + { + u32 pa_id; + u32 fuses_max = 32; // Current ODM7 max. + u8 burnt_fuses = bit_count(fuse_read_odm(7)); + + // Save current warmboot in storage cache (MWS) and check if another one is needed. + if (!ctxt->warmboot) + { + char path[128]; + strcpy(path, "warmboot_mariko/wb_"); + _warmboot_filename(path, fuses_fw); + + // Check if warmboot fw exists and save it. + if (ctxt->warmboot_size && f_stat(path, NULL)) + { + f_mkdir("warmboot_mariko"); + sd_save_to_file((void *)warmboot_base, ctxt->warmboot_size, path); + } + + // Load warmboot fw from storage (MWS) if not matched. + if (burnt_fuses > fuses_fw) + { + u32 tmp_fuses = burnt_fuses; + while (true) + { + _warmboot_filename(path, burnt_fuses); + if (!f_stat(path, NULL)) + { + ctxt->warmboot = sd_file_read(path, &ctxt->warmboot_size); + burnt_fuses = tmp_fuses; + break; + } + if (tmp_fuses >= fuses_max) + break; + tmp_fuses++; + } + + // Check if proper warmboot firmware was not found. + if (!ctxt->warmboot) + res = 0; + } + else // Replace burnt fuses with higher count. + burnt_fuses = fuses_fw; + } + + // Configure Warmboot parameters. Anything lower is not supported. + switch (burnt_fuses) + { + case 7 ... 8: + pa_id = 0x21 * (burnt_fuses - 3) + 3; + break; + default: // From 7.0.0 and up PA id is 0x21 multiplied with fuses. + pa_id = 0x21 * burnt_fuses; + break; + } + + // Set Warmboot Physical Address ID and lock SECURE_SCRATCH32 register. + PMC(APBDEV_PMC_SECURE_SCRATCH32) = pa_id; + PMC(APBDEV_PMC_SEC_DISABLE3) |= BIT(16); + } + else + { + // Set warmboot address in PMC if required. + if (kb <= HOS_KB_VERSION_301) + PMC(APBDEV_PMC_SCRATCH1) = warmboot_base; + + // Set Warmboot Physical Address ID for 3.0.0 - 3.0.2. + if (kb == HOS_KB_VERSION_300) + PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id. + else if (kb == HOS_KB_VERSION_301) + PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id. + } + + return res; +} + +void pkg1_warmboot_rsa_mod(u32 warmboot_base) +{ + // Set warmboot binary rsa modulus. + u8 *rsa_mod = (u8 *)malloc(EMMC_BLOCKSIZE); + + emmc_set_partition(EMMC_BOOT0); + + u32 sector; + u8 mod0, mod1; + + // Get the correct RSA modulus byte masks. + nx_emmc_get_autorcm_masks(&mod0, &mod1); + + // Iterate BCTs. + for (u32 i = 0; i < 4; i++) + { + sector = 1 + (32 * i); // 0x4000 bct + 0x200 offset. + sdmmc_storage_read(&emmc_storage, sector, 1, rsa_mod); + + // Check if 2nd byte of modulus is correct. + if (rsa_mod[0x11] != mod1) + continue; + + // Patch AutoRCM out. + rsa_mod[0x10] = mod0; + + break; + } + + memcpy((void *)(warmboot_base + 0x10), rsa_mod + 0x10, 0x100); } diff --git a/bootloader/hos/pkg1.h b/bootloader/hos/pkg1.h index 455d746..c0dab9a 100644 --- a/bootloader/hos/pkg1.h +++ b/bootloader/hos/pkg1.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2022-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +18,21 @@ #ifndef _PKG1_H_ #define _PKG1_H_ -#include "../utils/types.h" +#include + +#define PKG1_MAGIC 0x31314B50 + +#define PK11_SECTION_WB 0 +#define PK11_SECTION_LD 1 +#define PK11_SECTION_SM 2 + +#define PKG1_BOOTLOADER_SIZE SZ_256K +#define PKG1_BOOTLOADER_MAIN_OFFSET 0x100000 +#define PKG1_BOOTLOADER_BACKUP_OFFSET 0x140000 +#define PKG1_HOS_KEYBLOBS_OFFSET 0x180000 + +#define PKG1_ERISTA_ON_MARIKO_MAGIC 0xE59FD00C // For 4.0.0 Erista and up. +#define PKG1_MARIKO_ON_ERISTA_MAGIC 0x40010040 // Mariko pkg1 entrypoint. typedef struct _patch_t { @@ -26,23 +41,45 @@ typedef struct _patch_t } patch_t; #define PATCHSET_DEF(name, ...) \ - patch_t name[] = { \ + const patch_t name[] = { \ __VA_ARGS__, \ { 0xFFFFFFFF, 0xFFFFFFFF } \ } +typedef struct _bl_hdr_t210b01_t +{ +/* 0x000 */ u8 aes_mac[0x10]; +/* 0x010 */ u8 rsa_sig[0x100]; +/* 0x110 */ u8 salt[0x20]; +/* 0x130 */ u8 sha256[0x20]; +/* 0x150 */ u32 version; +/* 0x154 */ u32 size; +/* 0x158 */ u32 load_addr; +/* 0x15C */ u32 entrypoint; +/* 0x160 */ u8 rsvd[0x10]; +} bl_hdr_t210b01_t; + +typedef struct _pk1_hdr_t +{ +/* 0x00 */ u32 si_sha256; // Secure Init. +/* 0x04 */ u32 sm_sha256; // Secure Monitor. +/* 0x08 */ u32 sl_sha256; // Secure Loader. +/* 0x0C */ u32 unk; // what's this? It's not warmboot. +/* 0x10 */ char timestamp[14]; +/* 0x1E */ u8 keygen; +/* 0x1F */ u8 version; +} pk1_hdr_t; + typedef struct _pkg1_id_t { const char *id; - u32 kb; - u32 tsec_off; - u32 pkg11_off; - u32 sec_map[3]; + u16 kb; + u16 fuses; + u16 tsec_off; + u16 pkg11_off; u32 secmon_base; u32 warmboot_base; - bool set_warmboot; - patch_t *secmon_patchset; - patch_t *warmboot_patchset; + const patch_t *secmon_patchset; } pkg1_id_t; typedef struct _pk11_hdr_t @@ -57,8 +94,13 @@ typedef struct _pk11_hdr_t u32 sm_off; } pk11_hdr_t; +const pkg1_id_t *pkg1_get_latest(); 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, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1); +int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); +const u8 *pkg1_unpack(void *wm_dst, u32 *wb_sz, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1); +void pkg1_secmon_patch(void *hos_ctxt, u32 secmon_base, bool t210b01); +void pkg1_warmboot_patch(void *hos_ctxt); +int pkg1_warmboot_config(void *hos_ctxt, u32 warmboot_base, u32 fuses_fw, u8 kb); +void pkg1_warmboot_rsa_mod(u32 warmboot_base); #endif diff --git a/bootloader/hos/pkg2.c b/bootloader/hos/pkg2.c index 02ada87..4ad838c 100644 --- a/bootloader/hos/pkg2.c +++ b/bootloader/hos/pkg2.c @@ -1,7 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2018 Atmosphère-NX + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,342 +17,27 @@ #include +#include + #include "hos.h" #include "pkg2.h" #include "pkg2_ini_kippatch.h" -#include "../config/config.h" -#include "../libs/fatfs/ff.h" -#include "../utils/aarch64_util.h" -#include "../mem/heap.h" -#include "../sec/se.h" +#include "../config.h" +#include +#include #include "../storage/emummc.h" -#include "../libs/compr/blz.h" -#include "../gfx/gfx.h" +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) extern hekate_config h_cfg; extern const u8 package2_keyseed[]; -extern void *sd_file_read(const char *path, u32 *fsize); - -#ifdef KIP1_PATCH_DEBUG - #include "../utils/util.h" - #define DPRINTF(...) gfx_printf(__VA_ARGS__) - #define DEBUG_PRINTING -#else - #define DPRINTF(...) -#endif - -//TODO: Replace hardcoded AArch64 instructions with instruction macros. -//TODO: Reduce hardcoded values without searching kernel for patterns? -// The process ID send/receive kernel patches were taken from Atmosphère's kernel patches. -// They should only be used when running Atmosphère. -#define FREE_CODE_OFF_1ST_100 0x4797C -#define FREE_CODE_OFF_1ST_200 0x6486C -#define FREE_CODE_OFF_1ST_300 0x494A4 -#define FREE_CODE_OFF_1ST_302 0x494BC -#define FREE_CODE_OFF_1ST_400 0x52890 -#define FREE_CODE_OFF_1ST_500 0x5C020 -#define FREE_CODE_OFF_1ST_600 0x5EE00 -#define FREE_CODE_OFF_1ST_700 0x5FEC0 -#define FREE_CODE_OFF_1ST_800 0x607F0 -#define FREE_CODE_OFF_1ST_900 0x65780 - -#define ID_SND_OFF_100 0x23CC0 -#define ID_SND_OFF_200 0x3F134 -#define ID_SND_OFF_300 0x26080 -#define ID_SND_OFF_302 0x26080 -#define ID_SND_OFF_400 0x2AF64 -#define ID_SND_OFF_500 0x2AD34 -#define ID_SND_OFF_600 0x2BB8C -#define ID_SND_OFF_700 0x2D044 -#define ID_SND_OFF_800 0x2F1FC -#define ID_SND_OFF_900 0x329A0 - -#define ID_RCV_OFF_100 0x219F0 -#define ID_RCV_OFF_200 0x3D1A8 -#define ID_RCV_OFF_300 0x240F0 -#define ID_RCV_OFF_302 0x240F0 -#define ID_RCV_OFF_400 0x28F6C -#define ID_RCV_OFF_500 0x28DAC -#define ID_RCV_OFF_600 0x29B6C -#define ID_RCV_OFF_700 0x2B23C -#define ID_RCV_OFF_800 0x2D424 -#define ID_RCV_OFF_900 0x309B4 - -static u32 PRC_ID_SND_100[] = -{ - 0xA9BF2FEA, 0x2A0E03EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B, - 0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9412948, 0xA8C12FEA -}; -#define FREE_CODE_OFF_2ND_100 (FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + sizeof(u32)) -static u32 PRC_ID_RCV_100[] = -{ - 0xA9BF2FEA, 0x2A1C03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, - 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9412968, 0xA8C12FEA -}; - -static u32 PRC_ID_SND_200[] = -{ - 0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B, - 0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9413148, 0xA8C12FEA -}; -#define FREE_CODE_OFF_2ND_200 (FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + sizeof(u32)) -static u32 PRC_ID_RCV_200[] = -{ - 0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148, - 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9413168, 0xA8C12FEA -}; - -static u32 PRC_ID_SND_300[] = -{ - 0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B, - 0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA -}; -#define FREE_CODE_OFF_2ND_300 (FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + sizeof(u32)) -static u32 PRC_ID_RCV_300[] = -{ - 0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148, - 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA -}; - -#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300) + sizeof(u32)) - -static u32 PRC_ID_SND_400[] = -{ - 0x2A1703EA, 0xD37EF54A, 0xF86A6B8A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, - 0xEB09015F, 0x54000060, 0xF94053EA, 0xF9415948, 0xF94053EA -}; -#define FREE_CODE_OFF_2ND_400 (FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + sizeof(u32)) -static u32 PRC_ID_RCV_400[] = -{ - 0xF9403BED, 0x2A0E03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, - 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B28, 0xD503201F -}; - -static u32 PRC_ID_SND_500[] = -{ - 0x2A1703EA, 0xD37EF54A, 0xF86A6B6A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, - 0xEB09015F, 0x54000060, 0xF94043EA, 0xF9415948, 0xF94043EA -}; -#define FREE_CODE_OFF_2ND_500 (FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + sizeof(u32)) -static u32 PRC_ID_RCV_500[] = -{ - 0xF9403BED, 0x2A1503EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, - 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B08, 0xF9406FEA -}; - -static u32 PRC_ID_SND_600[] = -{ - 0xA9BF2FEA, 0xF94037EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, - 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, - 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 -}; -#define FREE_CODE_OFF_2ND_600 (FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + sizeof(u32)) -static u32 PRC_ID_RCV_600[] = -{ - 0xA9BF2FEA, 0xF94043EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, - 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, - 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 -}; - -static u32 PRC_ID_SND_700[] = -{ - 0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, - 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, - 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 -}; -#define FREE_CODE_OFF_2ND_700 (FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700) + sizeof(u32)) -static u32 PRC_ID_RCV_700[] = -{ - 0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, - 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, - 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 -}; - -#define FREE_CODE_OFF_2ND_800 (FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700) + sizeof(u32)) - -static u32 PRC_ID_SND_900[] = -{ - 0xA9BF2FEA, 0xF94037EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, - 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0, - 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 -}; -#define FREE_CODE_OFF_2ND_900 (FREE_CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900) + sizeof(u32)) -static u32 PRC_ID_RCV_900[] = -{ - 0xA9BF2FEA, 0xF9404BEB, 0x2A1703EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, - 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, - 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 -}; - -// Include kernel patches here, so we can utilize pkg1 id -KERNEL_PATCHSET_DEF(_kernel_1_patchset, - { SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x44074, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_GEN_PATCH, ID_SND_OFF_100, _B(ID_SND_OFF_100, FREE_CODE_OFF_1ST_100), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_100, sizeof(PRC_ID_SND_100) >> 2, PRC_ID_SND_100}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + sizeof(u32)), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_100, _B(ID_RCV_OFF_100, FREE_CODE_OFF_2ND_100), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_100, sizeof(PRC_ID_RCV_100) >> 2, PRC_ID_RCV_100}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + sizeof(u32)), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_2_patchset, - { SVC_VERIFY_DS, 0x54834, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x6086C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_GEN_PATCH, ID_SND_OFF_200, _B(ID_SND_OFF_200, FREE_CODE_OFF_1ST_200), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_200, sizeof(PRC_ID_SND_200) >> 2, PRC_ID_SND_200}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + sizeof(u32)), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_200, _B(ID_RCV_OFF_200, FREE_CODE_OFF_2ND_200), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_200, sizeof(PRC_ID_RCV_200) >> 2, PRC_ID_RCV_200}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + sizeof(u32)), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_3_patchset, - { SVC_VERIFY_DS, 0x3BD24, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x483FC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_GEN_PATCH, ID_SND_OFF_300, _B(ID_SND_OFF_300, FREE_CODE_OFF_1ST_300), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_300, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + sizeof(u32)), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_300, _B(ID_RCV_OFF_300, FREE_CODE_OFF_2ND_300), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_300, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + sizeof(u32)), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_302_patchset, - { SVC_VERIFY_DS, 0x3BD24, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x48414, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, FREE_CODE_OFF_1ST_302), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_302, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), ID_SND_OFF_302 + sizeof(u32)), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, FREE_CODE_OFF_2ND_302), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_302 + sizeof(u32)), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_4_patchset, - { SVC_VERIFY_DS, 0x41EB4, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x4EBFC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_GEN_PATCH, ID_SND_OFF_400, _B(ID_SND_OFF_400, FREE_CODE_OFF_1ST_400), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_400, sizeof(PRC_ID_SND_400) >> 2, PRC_ID_SND_400}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), // Branch back and skip 2 instructions. - _B(FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + sizeof(u32) * 2), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_400, _B(ID_RCV_OFF_400, FREE_CODE_OFF_2ND_400), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_400, sizeof(PRC_ID_RCV_400) >> 2, PRC_ID_RCV_400}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), // Branch back and skip 1 instruction. - _B(FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + sizeof(u32)), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_5_patchset, - { SVC_GENERIC, 0x38C2C, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. - { SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_SYSM_INCR, 0x54E30, _MOVZW(8, 0x1E00, LSL16), NULL }, // System memory pool increase. - { ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, FREE_CODE_OFF_1ST_500), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2, PRC_ID_SND_500}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), // Branch back and skip 2 instructions. - _B(FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + sizeof(u32) * 2), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_500, _B(ID_RCV_OFF_500, FREE_CODE_OFF_2ND_500), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_500, sizeof(PRC_ID_RCV_500) >> 2, PRC_ID_RCV_500}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), // Branch back and skip 2 instructions. - _B(FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + sizeof(u32) * 2), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_6_patchset, - { SVC_GENERIC, 0x3A8CC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. - { SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_SYSM_INCR, 0x57330, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase. - { ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, FREE_CODE_OFF_1ST_600), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2, PRC_ID_SND_600}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + sizeof(u32) * 4), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_600, _B(ID_RCV_OFF_600, FREE_CODE_OFF_2ND_600), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_600, sizeof(PRC_ID_RCV_600) >> 2, PRC_ID_RCV_600}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + sizeof(u32) * 4), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_7_patchset, - { SVC_GENERIC, 0x3C6E0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. - { SVC_VERIFY_DS, 0x49E5C, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x581B0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_SYSM_INCR, 0x57F98, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase. - { ATM_GEN_PATCH, ID_SND_OFF_700, _B(ID_SND_OFF_700, FREE_CODE_OFF_1ST_700), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_700, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), ID_SND_OFF_700 + sizeof(u32) * 4), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_700, _B(ID_RCV_OFF_700, FREE_CODE_OFF_2ND_700), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_700, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_700 + sizeof(u32) * 4), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_8_patchset, - { SVC_GENERIC, 0x3FAD0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. - { SVC_VERIFY_DS, 0x4D15C, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x5BFAC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_SYSM_INCR, 0x5F9A4, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase. - { ATM_GEN_PATCH, ID_SND_OFF_800, _B(ID_SND_OFF_800, FREE_CODE_OFF_1ST_800), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_800, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), ID_SND_OFF_800 + sizeof(u32) * 4), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_800, _B(ID_RCV_OFF_800, FREE_CODE_OFF_2ND_800), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_800, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_800 + sizeof(u32) * 4), NULL} -); - -KERNEL_PATCHSET_DEF(_kernel_9_patchset, - { SVC_GENERIC, 0x43DFC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. - { SVC_VERIFY_DS, 0x50628, _NOP(), NULL }, // Disable SVC verifications - { DEBUG_MODE_EN, 0x609E8, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch - // Atmosphère kernel patches. - { ATM_SYSM_INCR, 0x6493C, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase. - { ATM_GEN_PATCH, ID_SND_OFF_900, _B(ID_SND_OFF_900, FREE_CODE_OFF_1ST_900), NULL}, // Send process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_1ST_900, sizeof(PRC_ID_SND_900) >> 2, PRC_ID_SND_900}, // Send process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), ID_SND_OFF_900 + sizeof(u32) * 4), NULL}, - { ATM_GEN_PATCH, ID_RCV_OFF_900, _B(ID_RCV_OFF_900, FREE_CODE_OFF_2ND_900), NULL}, // Receive process id branch. - { ATM_ARR_PATCH, FREE_CODE_OFF_2ND_900, sizeof(PRC_ID_RCV_900) >> 2, PRC_ID_RCV_900}, // Receive process id code. - { ATM_GEN_PATCH, FREE_CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), // Branch back and skip 4 instructions. - _B(FREE_CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), ID_RCV_OFF_900 + sizeof(u32) * 4), NULL} -); - -// Kernel sha256 hashes. -static const pkg2_kernel_id_t _pkg2_kernel_ids[] = -{ - { "\xb8\xc5\x0c\x68\x25\xa9\xb9\x5b", _kernel_1_patchset }, //1.0.0 - { "\x64\x0b\x51\xff\x28\x01\xb8\x30", _kernel_2_patchset }, //2.0.0 - 2.3.0 - { "\x50\x84\x23\xac\x6f\xa1\x5d\x3b", _kernel_3_patchset }, //3.0.0 - 3.0.1 - { "\x81\x9d\x08\xbe\xe4\x5e\x1f\xbb", _kernel_302_patchset }, //3.0.2 - { "\xe6\xc0\xb7\xe3\x2f\xf9\x44\x51", _kernel_4_patchset }, //4.0.0 - 4.1.0 - { "\xb2\x38\x61\xa8\xe1\xe2\xe4\xe4", _kernel_5_patchset }, //5.0.0 - 5.1.0 - { "\x85\x97\x40\xf6\xc0\x3e\x3d\x44", _kernel_6_patchset }, //6.0.0 - 6.2.0 - { "\xa2\x5e\x47\x0c\x8e\x6d\x2f\xd7", _kernel_7_patchset }, //7.0.0 - 7.0.1 - { "\xf1\x5e\xc8\x34\xfd\x68\xf0\xf0", _kernel_8_patchset }, //8.0.0 - 8.1.0. Kernel only. - { "\x69\x00\x39\xdf\x21\x56\x70\x6b", _kernel_9_patchset }, //9.0.0 - 9.1.0. Kernel only. - { "\xa2\xe3\xad\x1c\x98\xd8\x7a\x62", _kernel_9_patchset }, //9.2.0. Kernel only. -}; +u32 pkg2_newkern_ini1_info; +u32 pkg2_newkern_ini1_start; +u32 pkg2_newkern_ini1_end; +u32 pkg2_newkern_ini1_rela; enum kip_offset_section { @@ -368,313 +52,128 @@ enum kip_offset_section #define KIP_PATCH_SECTION_SHIFT (29) #define KIP_PATCH_SECTION_MASK (7 << KIP_PATCH_SECTION_SHIFT) #define KIP_PATCH_OFFSET_MASK (~KIP_PATCH_SECTION_MASK) -#define GET_KIP_PATCH_SECTION(x) ((x >> KIP_PATCH_SECTION_SHIFT) & 7) -#define GET_KIP_PATCH_OFFSET(x) (x & KIP_PATCH_OFFSET_MASK) -#define KPS(x) ((u32)(x) << KIP_PATCH_SECTION_SHIFT) +#define GET_KIP_PATCH_SECTION(x) (((x) >> KIP_PATCH_SECTION_SHIFT) & 7) +#define GET_KIP_PATCH_OFFSET(x) ((x) & KIP_PATCH_OFFSET_MASK) +#define KPS(x) ((u32)(x) << KIP_PATCH_SECTION_SHIFT) -static kip1_patch_t _fs_emummc[] = -{ - { KPS(KIP_TEXT) | 1, 0, "", "" }, - { 0, 0, NULL, NULL } -}; +#include "pkg2_patches.inl" -static kip1_patchset_t _fs_patches_100[] = -{ - { "nogc", NULL }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; +static kip1_id_t *_kip_id_sets = (kip1_id_t *)_kip_ids; +static u32 _kip_id_sets_cnt = ARRAY_SIZE(_kip_ids); -static kip1_patch_t _fs_nogc_40x[] = +void pkg2_get_ids(kip1_id_t **ids, u32 *entries) { - { KPS(KIP_TEXT) | 0xA3458, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" }, - { KPS(KIP_TEXT) | 0xAAB44, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_40x[] = -{ - { "nogc", _fs_nogc_40x }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_410[] = -{ - { KPS(KIP_TEXT) | 0xA34BC, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" }, - { KPS(KIP_TEXT) | 0xAABA8, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_410[] = -{ - { "nogc", _fs_nogc_410 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_50x[] = -{ - { KPS(KIP_TEXT) | 0xCF3C4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { KPS(KIP_TEXT) | 0xD73A0, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_50x[] = -{ - { "nogc", _fs_nogc_50x }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_510[] = -{ - { KPS(KIP_TEXT) | 0xCF794, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { KPS(KIP_TEXT) | 0xD7770, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_510[] = -{ - { "nogc", _fs_nogc_510 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_600[] = -{ - { KPS(KIP_TEXT) | 0x12CC20, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x1538F4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_600_exfat[] = -{ - { KPS(KIP_TEXT) | 0x138320, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x15EFF4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_600[] = -{ - { "nogc", _fs_nogc_600 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_600_exfat[] = -{ - { "nogc", _fs_nogc_600_exfat }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_700[] = -{ - { KPS(KIP_TEXT) | 0x134160, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x15BF04, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_700_exfat[] = -{ - { KPS(KIP_TEXT) | 0x13F710, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x1674B4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_700[] = -{ - { "nogc", _fs_nogc_700 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_700_exfat[] = -{ - { "nogc", _fs_nogc_700_exfat }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_800[] = -{ - { KPS(KIP_TEXT) | 0x136800, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x15EB94, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_800_exfat[] = -{ - { KPS(KIP_TEXT) | 0x141DB0, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x16A144, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_800[] = -{ - { "nogc", _fs_nogc_800 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_800_exfat[] = -{ - { "nogc", _fs_nogc_800_exfat }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_900[] = -{ - { KPS(KIP_TEXT) | 0x129420, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x143268, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_900[] = -{ - { "nogc", _fs_nogc_900 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -static kip1_patch_t _fs_nogc_910[] = -{ - { KPS(KIP_TEXT) | 0x129430, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, - { KPS(KIP_TEXT) | 0x143278, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" }, - { 0, 0, NULL, NULL } -}; - -static kip1_patchset_t _fs_patches_910[] = -{ - { "nogc", _fs_nogc_910 }, - { "emummc", _fs_emummc }, - { NULL, NULL } -}; - -// SHA256 hashes. -static kip1_id_t _kip_ids[] = -{ - { "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe", _fs_patches_100 }, // FS 1.0.0 - { "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96", _fs_patches_100 }, // FS 1.0.0 exfat - { "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", _fs_patches_100 }, // FS 2.0.0 - { "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9", _fs_patches_100 }, // FS 2.0.0 exfat - { "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c", _fs_patches_100 }, // FS 2.1.0 - { "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", _fs_patches_100 }, // FS 2.1.0 exfat - { "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", _fs_patches_100 }, // FS 3.0.0 - { "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", _fs_patches_100 }, // FS 3.0.0 exfat - { "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31", _fs_patches_100 }, // FS 3.0.1 - { "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89", _fs_patches_100 }, // FS 3.0.1 exfat - { "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c", _fs_patches_40x }, // FS 4.0.1 - { "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9", _fs_patches_40x }, // FS 4.0.1 exfat - { "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82", _fs_patches_410 }, // FS 4.1.0 - { "FS", "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0", _fs_patches_410 }, // FS 4.1.0 exfat - { "FS", "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad", _fs_patches_50x }, // FS 5.0.0 - { "FS", "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5", _fs_patches_50x }, // FS 5.0.0 exfat - { "FS", "\x76\xf8\x74\x02\xc9\x38\x7c\x0f", _fs_patches_510 }, // FS 5.1.0 - { "FS", "\x10\xb2\xd8\x16\x05\x48\x85\x99", _fs_patches_510 }, // FS 5.1.0 exfat - { "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52", _fs_patches_600 }, // FS 6.0.0-4.0 - { "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exfat - { "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d", _fs_patches_600 }, // FS 6.0.0-5.0 - { "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4", _fs_patches_600_exfat }, // FS 6.0.0-5.0 exfat - { "FS", "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77", _fs_patches_700 }, // FS 7.0.0 - { "FS", "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E", _fs_patches_700_exfat }, // FS 7.0.0 exfat - { "FS", "\xB2\xF5\x17\x6B\x35\x48\x36\x4D", _fs_patches_800 }, // FS 8.0.0 - { "FS", "\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", _fs_patches_800_exfat }, // FS 8.0.0 exfat - { "FS", "\x6B\x09\xB6\x7B\x29\xC0\x20\x24", _fs_patches_800 }, // FS 8.1.0 - { "FS", "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", _fs_patches_800_exfat }, // FS 8.1.0 exfat - { "FS", "\x46\x87\x40\x76\x1E\x19\x3E\xB7", _fs_patches_900 }, // FS 9.0.0 - { "FS", "\x7C\x95\x13\x76\xE5\xC1\x2D\xF8", _fs_patches_900 }, // FS 9.0.0 exfat - { "FS", "\xB5\xE7\xA6\x4C\x6F\x5C\x4F\xE3", _fs_patches_910 }, // FS 9.1.0 - { "FS", "\xF1\x96\xD1\x44\xD0\x44\x45\xB6", _fs_patches_910 } // FS 9.1.0 exfat -}; + *ids = _kip_id_sets; + *entries = _kip_id_sets_cnt; +} static void parse_external_kip_patches() { - u32 curr_kip_idx = 0; - char path[64]; - strcpy(path, "bootloader/patches.ini"); + static bool ext_patches_parsed = false; + + if (ext_patches_parsed) + return; LIST_INIT(ini_kip_sections); - if (ini_patch_parse(&ini_kip_sections, path)) + if (ini_patch_parse(&ini_kip_sections, "bootloader/patches.ini")) { + // Copy ids into a new patchset. + _kip_id_sets = zalloc(sizeof(kip1_id_t) * 256); // Max 256 kip ids. + memcpy(_kip_id_sets, _kip_ids, sizeof(_kip_ids)); + // Parse patchsets and glue them together. LIST_FOREACH_ENTRY(ini_kip_sec_t, ini_psec, &ini_kip_sections, link) { - kip1_id_t* curr_kip = &_kip_ids[curr_kip_idx]; - - if (!strcmp(curr_kip->name, ini_psec->name) && !memcmp(curr_kip->hash, ini_psec->hash, 8)) + kip1_id_t *kip = NULL; + bool found = false; + for (u32 kip_idx = 0; kip_idx < _kip_id_sets_cnt + 1; kip_idx++) { - kip1_patchset_t *patchsets = (kip1_patchset_t *)calloc(sizeof(kip1_patchset_t), 8); // Max 8 patchsets per kip. + kip = &_kip_id_sets[kip_idx]; - u32 curr_patchset_idx; - for(curr_patchset_idx = 0; curr_kip->patchset[curr_patchset_idx].name != NULL; curr_patchset_idx++) + // Check if reached the end of predefined list. + if (!kip->name) + break; + + // Check if name and hash match. + if (!strcmp(kip->name, ini_psec->name) && !memcmp(kip->hash, ini_psec->hash, 8)) { - patchsets[curr_patchset_idx].name = curr_kip->patchset[curr_patchset_idx].name; - patchsets[curr_patchset_idx].patches = curr_kip->patchset[curr_patchset_idx].patches; + found = true; + break; } - - curr_kip->patchset = patchsets; - bool first_ext_patch = true; - u32 curr_patch_idx = 0; - - // Parse patches and glue them together to a patchset. - kip1_patch_t *patches = calloc(sizeof(kip1_patch_t), 16); // Max 16 patches per set. - LIST_FOREACH_ENTRY(ini_patchset_t, pt, &ini_psec->pts, link) - { - if (first_ext_patch) - { - first_ext_patch = false; - patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1); - strcpy(patchsets[curr_patchset_idx].name, pt->name); - patchsets[curr_patchset_idx].patches = patches; - } - else - { - // Check if new patchset name is found and create a new set. - if (strcmp(pt->name, patchsets[curr_patchset_idx].name)) - { - curr_patchset_idx++; - curr_patch_idx = 0; - patches = calloc(sizeof(kip1_patch_t), 16); // Max 16 patches per set. - - patchsets[curr_patchset_idx].name = malloc(strlen(pt->name) + 1); - strcpy(patchsets[curr_patchset_idx].name, pt->name); - patchsets[curr_patchset_idx].patches = patches; - } - } - - if (pt->length) - { - patches[curr_patch_idx].offset = pt->offset; - patches[curr_patch_idx].length = pt->length; - - patches[curr_patch_idx].srcData = malloc(pt->length); - patches[curr_patch_idx].dstData = malloc(pt->length); - memcpy(patches[curr_patch_idx].srcData, pt->srcData, pt->length); - memcpy(patches[curr_patch_idx].dstData, pt->dstData, pt->length); - } - else - patches[curr_patch_idx].srcData = malloc(1); // Empty patches check. Keep everything else as 0. - - curr_patch_idx++; - } - curr_patchset_idx++; - patchsets[curr_patchset_idx].name = NULL; - patchsets[curr_patchset_idx].patches = NULL; } - curr_kip_idx++; - if (!(curr_kip_idx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])))) - break; + if (!kip) + continue; + + // If not found, create a new empty entry. + if (!found) + { + kip->name = ini_psec->name; + memcpy(kip->hash, ini_psec->hash, 8); + kip->patchset = zalloc(sizeof(kip1_patchset_t)); + + _kip_id_sets_cnt++; + } + + kip1_patchset_t *patchsets = (kip1_patchset_t *)zalloc(sizeof(kip1_patchset_t) * 16); // Max 16 patchsets per kip. + + u32 patchset_idx; + for (patchset_idx = 0; kip->patchset[patchset_idx].name != NULL; patchset_idx++) + { + patchsets[patchset_idx].name = kip->patchset[patchset_idx].name; + patchsets[patchset_idx].patches = kip->patchset[patchset_idx].patches; + } + + kip->patchset = patchsets; + bool first_ext_patch = true; + u32 patch_idx = 0; + + // Parse patches and glue them together to a patchset. + kip1_patch_t *patches = zalloc(sizeof(kip1_patch_t) * 32); // Max 32 patches per set. + LIST_FOREACH_ENTRY(ini_patchset_t, pt, &ini_psec->pts, link) + { + if (first_ext_patch) + { + first_ext_patch = false; + patchsets[patchset_idx].name = pt->name; + patchsets[patchset_idx].patches = patches; + } + else if (strcmp(pt->name, patchsets[patchset_idx].name)) + { + // New patchset name found, create a new set. + patchset_idx++; + patch_idx = 0; + patches = zalloc(sizeof(kip1_patch_t) * 32); // Max 32 patches per set. + + patchsets[patchset_idx].name = pt->name; + patchsets[patchset_idx].patches = patches; + } + + if (pt->length) + { + patches[patch_idx].offset = pt->offset; + patches[patch_idx].length = pt->length; + + patches[patch_idx].src_data = (char *)pt->src_data; + patches[patch_idx].dst_data = (char *)pt->dst_data; + } + else + patches[patch_idx].src_data = malloc(1); // Empty patches check. Keep everything else as 0. + + patch_idx++; + } + patchset_idx++; + patchsets[patchset_idx].name = NULL; + patchsets[patchset_idx].patches = NULL; } } + + ext_patches_parsed = true; } -const pkg2_kernel_id_t *pkg2_identify(u8 *hash) +const pkg2_kernel_id_t *pkg2_identify(const u8 *hash) { - for (u32 i = 0; i < (sizeof(_pkg2_kernel_ids) / sizeof(pkg2_kernel_id_t)); i++) + for (u32 i = 0; i < ARRAY_SIZE(_pkg2_kernel_ids); i++) { if (!memcmp(hash, _pkg2_kernel_ids[i].hash, sizeof(_pkg2_kernel_ids[0].hash))) return &_pkg2_kernel_ids[i]; @@ -690,22 +189,64 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) return size; } -void pkg2_get_newkern_info(u8 *kern_data) +static void _pkg2_get_newkern_info(u8 *kern_data) { - u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1); - pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC. + u32 crt_start = 0; + pkg2_newkern_ini1_info = 0; + pkg2_newkern_ini1_start = 0; + pkg2_newkern_ini1_rela = 0; - pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val); - pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); + u32 first_op = *(u32 *)kern_data; + if ((first_op & 0xFE000000) == 0x14000000) + crt_start = (first_op & 0x1FFFFFF) << 2; + + // Find static OP offset that is close to INI1 offset. + u32 counter_ops = 0x100; + while (counter_ops) + { + if (*(u32 *)(kern_data + crt_start + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC) + { + // OP found. Add 12 for the INI1 info offset. + pkg2_newkern_ini1_info = crt_start + 0x100 - counter_ops + 12; + + // On v2 kernel with dynamic crt there's a NOP after heuristic. Offset one op. + if (crt_start) + pkg2_newkern_ini1_info += 4; + break; + } + + counter_ops -= 4; + } + + // Offset not found? + if (!counter_ops) + return; + + u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_info); + pkg2_newkern_ini1_info += ((info_op & 0xFFFF) >> 3); // Parse ADR and PC. + + pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_info); + pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_info + 0x8); + + // On v2 kernel with dynamic crt, values are relative to value address. + if (crt_start) + { + pkg2_newkern_ini1_rela = pkg2_newkern_ini1_info; + pkg2_newkern_ini1_start += pkg2_newkern_ini1_info; + pkg2_newkern_ini1_end += pkg2_newkern_ini1_info + 0x8; + } } -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) +bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) { u8 *ptr; // Check for new pkg2 type. if (!pkg2->sec_size[PKG2_SEC_INI1]) { - pkg2_get_newkern_info(pkg2->data); + _pkg2_get_newkern_info(pkg2->data); + + if (!pkg2_newkern_ini1_start) + return false; ptr = pkg2->data + pkg2_newkern_ini1_start; *new_pkg2 = true; @@ -726,12 +267,14 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) ptr += ki->size; DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size); } + + return true; } int pkg2_has_kip(link_t *info, u64 tid) { LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link) - if(ki->kip1->tid == tid) + if (ki->kip1->tid == tid) return 1; return 0; } @@ -767,7 +310,7 @@ void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1) pkg2_add_kip(info, kip1); } -int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) +static int _decompress_kip(pkg2_kip1_info_t *ki, u32 sectsToDecomp) { u32 compClearMask = ~sectsToDecomp; if ((ki->kip1->flags & compClearMask) == ki->kip1->flags) @@ -776,70 +319,70 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) pkg2_kip1_t hdr; memcpy(&hdr, ki->kip1, sizeof(hdr)); - unsigned int newKipSize = sizeof(hdr); - for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) + u32 new_kip_size = sizeof(hdr); + for (u32 sect_idx = 0; sect_idx < KIP1_NUM_SECTIONS; sect_idx++) { - u32 sectCompBit = 1u << sectIdx; + u32 comp_bit_mask = BIT(sect_idx); // For compressed, cant get actual decompressed size without doing it, so use safe "output size". - if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit)) - newKipSize += hdr.sections[sectIdx].size_decomp; + if (sect_idx < 3 && (sectsToDecomp & comp_bit_mask) && (hdr.flags & comp_bit_mask)) + new_kip_size += hdr.sections[sect_idx].size_decomp; else - newKipSize += hdr.sections[sectIdx].size_comp; + new_kip_size += hdr.sections[sect_idx].size_comp; } - pkg2_kip1_t* newKip = malloc(newKipSize); - unsigned char* dstDataPtr = newKip->data; - const unsigned char* srcDataPtr = ki->kip1->data; - for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) + pkg2_kip1_t *new_kip = malloc(new_kip_size); + u8 *dst_data = new_kip->data; + const u8 *src_data = ki->kip1->data; + for (u32 sect_idx = 0; sect_idx < KIP1_NUM_SECTIONS; sect_idx++) { - u32 sectCompBit = 1u << sectIdx; + u32 comp_bit_mask = BIT(sect_idx); // Easy copy path for uncompressed or ones we dont want to uncompress. - if (sectIdx >= 3 || !(sectsToDecomp & sectCompBit) || !(hdr.flags & sectCompBit)) + if (sect_idx >= 3 || !(sectsToDecomp & comp_bit_mask) || !(hdr.flags & comp_bit_mask)) { - unsigned int dataSize = hdr.sections[sectIdx].size_comp; + u32 dataSize = hdr.sections[sect_idx].size_comp; if (dataSize == 0) continue; - memcpy(dstDataPtr, srcDataPtr, dataSize); - srcDataPtr += dataSize; - dstDataPtr += dataSize; + memcpy(dst_data, src_data, dataSize); + src_data += dataSize; + dst_data += dataSize; continue; } - unsigned int compSize = hdr.sections[sectIdx].size_comp; - unsigned int outputSize = hdr.sections[sectIdx].size_decomp; - gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize); - if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0) + u32 comp_size = hdr.sections[sect_idx].size_comp; + u32 output_size = hdr.sections[sect_idx].size_decomp; + gfx_printf("Decomping '%s', sect %d, size %d..\n", (char *)hdr.name, sect_idx, comp_size); + if (blz_uncompress_srcdest(src_data, comp_size, dst_data, output_size) == 0) { gfx_con.mute = false; - gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); - free(newKip); + gfx_printf("%kERROR decomping sect %d of '%s'!%k\n", TXT_CLR_ERROR, sect_idx, (char *)hdr.name, TXT_CLR_DEFAULT); + free(new_kip); return 1; } else { - DPRINTF("Done! Decompressed size is %d!\n", outputSize); + DPRINTF("Done! Decompressed size is %d!\n", output_size); } - hdr.sections[sectIdx].size_comp = outputSize; - srcDataPtr += compSize; - dstDataPtr += outputSize; + hdr.sections[sect_idx].size_comp = output_size; + src_data += comp_size; + dst_data += output_size; } hdr.flags &= compClearMask; - memcpy(newKip, &hdr, sizeof(hdr)); - newKipSize = dstDataPtr-(unsigned char*)(newKip); + memcpy(new_kip, &hdr, sizeof(hdr)); + new_kip_size = dst_data - (u8 *)(new_kip); free(ki->kip1); - ki->kip1 = newKip; - ki->size = newKipSize; + ki->kip1 = new_kip; + ki->size = new_kip_size; return 0; } -static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info_t* ki) +static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info_t *ki) { - if (!strcmp((const char *)ki->kip1->name, target_name)) + if (!strcmp((char *)ki->kip1->name, target_name)) { u32 size = 0; u8 *kipm_data = (u8 *)sd_file_read(kipm_path, &size); @@ -863,9 +406,9 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info u32 new_offset = 0; - for (u32 currSectIdx = 0; currSectIdx < KIP1_NUM_SECTIONS - 2; currSectIdx++) + for (u32 section_idx = 0; section_idx < KIP1_NUM_SECTIONS - 2; section_idx++) { - if(!currSectIdx) // .text. + if (!section_idx) // .text. { memcpy(ki->kip1->data + inject_size, fs_kip->data, fs_kip->sections[0].size_comp); ki->kip1->sections[0].size_decomp += inject_size; @@ -873,11 +416,11 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info } else // Others. { - if (currSectIdx < 3) - memcpy(ki->kip1->data + new_offset + inject_size, fs_kip->data + new_offset, fs_kip->sections[currSectIdx].size_comp); - ki->kip1->sections[currSectIdx].offset += inject_size; + if (section_idx < 3) + memcpy(ki->kip1->data + new_offset + inject_size, fs_kip->data + new_offset, fs_kip->sections[section_idx].size_comp); + ki->kip1->sections[section_idx].offset += inject_size; } - new_offset += fs_kip->sections[currSectIdx].size_comp; + new_offset += fs_kip->sections[section_idx].size_comp; } // Patch PMC capabilities for 1.0.0. @@ -900,266 +443,264 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info return 1; } -static bool ext_patches_parsed = false; - -const char* pkg2_patch_kips(link_t *info, char* patchNames) +const char *pkg2_patch_kips(link_t *info, char *patch_names) { - if (patchNames == NULL || patchNames[0] == 0) + bool emummc_patch_selected = false; + + if (patch_names == NULL || patch_names[0] == 0) return NULL; - if (!ext_patches_parsed) - { - parse_external_kip_patches(); - ext_patches_parsed = true; - } + gfx_printf("%kPatching kips%k\n", TXT_CLR_ORANGE, TXT_CLR_DEFAULT); static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32) * 8; - char* patches[MAX_NUM_PATCHES_REQUESTED]; + char *patches[MAX_NUM_PATCHES_REQUESTED]; - u32 numPatches = 1; - patches[0] = patchNames; + u32 patches_num = 1; + patches[0] = patch_names; { - for (char* p = patchNames; *p != 0; p++) + for (char *p = patch_names; *p != 0; p++) { if (*p == ',') { *p = 0; - patches[numPatches++] = p + 1; - if (numPatches >= MAX_NUM_PATCHES_REQUESTED) + patches[patches_num++] = p + 1; + if (patches_num >= MAX_NUM_PATCHES_REQUESTED) return "too_many_patches"; } - else if (*p >= 'A' && *p <= 'Z') + else if (*p >= 'A' && *p <= 'Z') // Convert to lowercase. *p += 0x20; } } - u32 patchesApplied = 0; // Bitset over patches. - for (u32 i = 0; i < numPatches; i++) + u32 patches_applied = 0; // Bitset over patches. + for (u32 i = 0; i < patches_num; i++) { // Eliminate leading spaces. - for (const char* p = patches[i]; *p != 0; p++) + for (const char *p = patches[i]; *p != 0; p++) { if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') patches[i]++; else break; } - int valueLen = strlen(patches[i]); - if (valueLen == 0) + + int patch_len = strlen(patches[i]); + if (patch_len == 0) continue; // Eliminate trailing spaces. - for (int chIdx = valueLen - 1; chIdx >= 0; chIdx--) + for (int chIdx = patch_len - 1; chIdx >= 0; chIdx--) { - const char* p = patches[i] + chIdx; + const char *p = patches[i] + chIdx; if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') - valueLen = chIdx; + patch_len = chIdx; else break; } - patches[i][valueLen] = 0; + patches[i][patch_len] = 0; DPRINTF("Requested patch: '%s'\n", patches[i]); } - u32 shaBuf[32 / sizeof(u32)]; + // Parse external patches if needed. + for (u32 i = 0; i < patches_num; i++) + { + if (!strcmp(patches[i], "emummc")) + { + // emuMMC patch is managed on its own. + emummc_patch_selected = true; + patches_applied |= BIT(i); + continue; + } + + if (strcmp(patches[i], "nogc")) + parse_external_kip_patches(); + } + + u32 kip_hash[SE_SHA_256_SIZE / sizeof(u32)]; LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link) { - shaBuf[0] = 0; // sha256 for this kip not yet calculated. - for (u32 currKipIdx = 0; currKipIdx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])); currKipIdx++) + // Reset hash so it can be calculated for the new kip. + kip_hash[0] = 0; + + bool emummc_patch_apply = emummc_patch_selected && !strcmp((char *)ki->kip1->name, "FS"); + + // Check all SHA256 ID sets. (IDs are grouped per KIP. IDs are still unique.) + for (u32 kip_id_idx = 0; kip_id_idx < _kip_id_sets_cnt; kip_id_idx++) { - if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0) + // Check if KIP name macthes ID's KIP name. + if (strcmp((char *)ki->kip1->name, _kip_id_sets[kip_id_idx].name) != 0) continue; - u32 bitsAffected = 0; - kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset; - while (currPatchset != NULL && currPatchset->name != NULL) + // Check if there are patches to apply. + bool patches_found = false; + const kip1_patchset_t *patchset = _kip_id_sets[kip_id_idx].patchset; + while (patchset != NULL && patchset->name != NULL && !patches_found) { - for (u32 i = 0; i < numPatches; i++) + for (u32 i = 0; i < patches_num; i++) { - if (strcmp(currPatchset->name, patches[i]) != 0) - { - bitsAffected = i + 1; - break; - } - } - currPatchset++; - } - - // Dont bother even hashing this KIP if we dont have any patches enabled for it. - if (bitsAffected == 0) - continue; - - if (shaBuf[0] == 0) - { - if (!se_calc_sha256(shaBuf, ki->kip1, ki->size)) - memset(shaBuf, 0, sizeof(shaBuf)); - } - - if (memcmp(shaBuf, _kip_ids[currKipIdx].hash, sizeof(_kip_ids[0].hash)) != 0) - continue; - - // Find out which sections are affected by the enabled patches, to know which to decompress. - bitsAffected = 0; - currPatchset = _kip_ids[currKipIdx].patchset; - while (currPatchset != NULL && currPatchset->name != NULL) - { - if (currPatchset->patches != NULL) - { - for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++) - { - if (strcmp(currPatchset->name, patches[currEnabIdx])) - continue; - - if (!strcmp(currPatchset->name, "emummc")) - bitsAffected |= 1u << GET_KIP_PATCH_SECTION(currPatchset->patches->offset); - - for (const kip1_patch_t* currPatch=currPatchset->patches; currPatch != NULL && (currPatch->length != 0); currPatch++) - bitsAffected |= 1u << GET_KIP_PATCH_SECTION(currPatch->offset); - } - } - currPatchset++; - } - - // Got patches to apply to this kip, have to decompress it. -#ifdef DEBUG_PRINTING - u32 preDecompTime = get_tmr_us(); -#endif - if (pkg2_decompress_kip(ki, bitsAffected)) - return (const char*)ki->kip1->name; // Failed to decompress. - -#ifdef DEBUG_PRINTING - u32 postDecompTime = get_tmr_us(); - if (!se_calc_sha256(shaBuf, ki->kip1, ki->size)) - memset(shaBuf, 0, sizeof(shaBuf)); - - DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime) / 1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0])); -#endif - - currPatchset = _kip_ids[currKipIdx].patchset; - bool emummc_patch_selected = false; - while (currPatchset != NULL && currPatchset->name != NULL) - { - for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++) - { - if (strcmp(currPatchset->name, patches[currEnabIdx])) + // Continue if patch name does not match. + if (strcmp(patchset->name, patches[i]) != 0) continue; - u32 appliedMask = 1u << currEnabIdx; + patches_found = true; + break; + } + patchset++; + } - if (!strcmp(currPatchset->name, "emummc")) + // Don't bother hashing this KIP if no patches are enabled for it. + if (!patches_found && !emummc_patch_apply) + continue; + + // Check if current KIP not hashed and hash it. + if (kip_hash[0] == 0) + if (!se_calc_sha256_oneshot(kip_hash, ki->kip1, ki->size)) + memset(kip_hash, 0, sizeof(kip_hash)); + + // Check if kip is the expected version. + if (memcmp(kip_hash, _kip_id_sets[kip_id_idx].hash, sizeof(_kip_id_sets[0].hash)) != 0) + continue; + + // Find out which sections are affected by the enabled patches, in order to decompress them. + u32 sections_affected = 0; + patchset = _kip_id_sets[kip_id_idx].patchset; + while (patchset != NULL && patchset->name != NULL) + { + if (patchset->patches != NULL) + { + for (u32 patch_idx = 0; patch_idx < patches_num; patch_idx++) { - emummc_patch_selected = true; - patchesApplied |= appliedMask; + if (strcmp(patchset->name, patches[patch_idx])) + continue; - break; + for (const kip1_patch_t *patch = patchset->patches; patch != NULL && (patch->length != 0); patch++) + sections_affected |= BIT(GET_KIP_PATCH_SECTION(patch->offset)); + } + } + patchset++; + } + + // If emuMMC is enabled, set its affected section. + if (emummc_patch_apply) + sections_affected |= BIT(KIP_TEXT); + + // Got patches to apply to this kip, have to decompress it. + if (_decompress_kip(ki, sections_affected)) + return (char *)ki->kip1->name; // Failed to decompress. + + // Apply all patches for matched ID. + patchset = _kip_id_sets[kip_id_idx].patchset; + while (patchset != NULL && patchset->name != NULL) + { + for (u32 patch_idx = 0; patch_idx < patches_num; patch_idx++) + { + // Check if patchset name matches requested patch. + if (strcmp(patchset->name, patches[patch_idx])) + continue; + + u32 applied_mask = BIT(patch_idx); + + // Check if patchset is empty. + if (patchset->patches == NULL) + { + DPRINTF("Patch '%s' not necessary for %s\n", patchset->name, (char *)ki->kip1->name); + patches_applied |= applied_mask; + + continue; // Continue in case it's double defined. } - if (currPatchset->patches == NULL) + // Apply patches per section. + u8 *kip_sect_data = ki->kip1->data; + for (u32 section_idx = 0; section_idx < KIP1_NUM_SECTIONS; section_idx++) { - gfx_printf("Patch '%s' not necessary for %s KIP1\n", currPatchset->name, (const char*)ki->kip1->name); - patchesApplied |= appliedMask; - - break; - } - - unsigned char* kipSectData = ki->kip1->data; - for (u32 currSectIdx = 0; currSectIdx < KIP1_NUM_SECTIONS; currSectIdx++) - { - if (bitsAffected & (1u << currSectIdx)) + if (sections_affected & BIT(section_idx)) { - gfx_printf("Applying patch '%s' on %s KIP1 sect %d\n", currPatchset->name, (const char*)ki->kip1->name, currSectIdx); - for (const kip1_patch_t* currPatch = currPatchset->patches; currPatch != NULL && currPatch->srcData != 0; currPatch++) + gfx_printf("Applying '%s' on %s, sect %d\n", patchset->name, (char *)ki->kip1->name, section_idx); + for (const kip1_patch_t *patch = patchset->patches; patch != NULL && patch->src_data != NULL; patch++) { - if (GET_KIP_PATCH_SECTION(currPatch->offset) != currSectIdx) + // Check if patch is in current section. + if (GET_KIP_PATCH_SECTION(patch->offset) != section_idx) continue; - if (!currPatch->length) + // Check if patch is empty. + if (!patch->length) { gfx_con.mute = false; - gfx_printf("%kPatch is empty!%k\n", 0xFFFF0000, 0xFFCCCCCC); - return currPatchset->name; // MUST stop here as it's not probably intended. + gfx_printf("%kPatch empty!%k\n", TXT_CLR_ERROR, TXT_CLR_DEFAULT); + return patchset->name; // MUST stop here as it's not probably intended. } - u32 currOffset = GET_KIP_PATCH_OFFSET(currPatch->offset); - // If source is does not match and is not already patched, throw an error. - if ((memcmp(&kipSectData[currOffset], currPatch->srcData, currPatch->length) != 0) && - (memcmp(&kipSectData[currOffset], currPatch->dstData, currPatch->length) != 0)) + // If source does not match and is not already patched, throw an error. + u32 patch_offset = GET_KIP_PATCH_OFFSET(patch->offset); + if (patch->src_data != KIP1_PATCH_SRC_NO_CHECK && + (memcmp(&kip_sect_data[patch_offset], patch->src_data, patch->length) != 0) && + (memcmp(&kip_sect_data[patch_offset], patch->dst_data, patch->length) != 0)) { gfx_con.mute = false; - gfx_printf("%kPatch data mismatch at 0x%x!%k\n", 0xFFFF0000, currOffset, 0xFFCCCCCC); - return currPatchset->name; // MUST stop here as kip is likely corrupt. + gfx_printf("%kPatch mismatch at 0x%x!%k\n", TXT_CLR_ERROR, patch_offset, TXT_CLR_DEFAULT); + return patchset->name; // MUST stop here as kip is likely corrupt. } else { - DPRINTF("Patching %d bytes at offset 0x%x\n", currPatch->length, currOffset); - memcpy(&kipSectData[currOffset], currPatch->dstData, currPatch->length); + DPRINTF("Patching %d bytes at offset 0x%x\n", patch->length, patch_offset); + memcpy(&kip_sect_data[patch_offset], patch->dst_data, patch->length); } } } - kipSectData += ki->kip1->sections[currSectIdx].size_comp; + kip_sect_data += ki->kip1->sections[section_idx].size_comp; } - patchesApplied |= appliedMask; - break; + patches_applied |= applied_mask; } - currPatchset++; + + patchset++; } - if (emummc_patch_selected && !strncmp(_kip_ids[currKipIdx].name, "FS", 2)) + + // emuMMC must be applied after all other patches, since it affects TEXT offset. + if (emummc_patch_apply) { - emummc_patch_selected = false; - emu_cfg.fs_ver = currKipIdx; - if (currKipIdx) + // Encode ID. + emu_cfg.fs_ver = kip_id_idx; + if (kip_id_idx) emu_cfg.fs_ver--; - if (currKipIdx > 17) + if (kip_id_idx > 17) emu_cfg.fs_ver -= 2; - gfx_printf("Injecting emuMMC. FS ver: %d\n", emu_cfg.fs_ver); - if (_kipm_inject("/bootloader/sys/emummc.kipm", "FS", ki)) + // Inject emuMMC code. + gfx_printf("Injecting emuMMC. FS ID: %d\n", emu_cfg.fs_ver); + if (_kipm_inject("bootloader/sys/emummc.kipm", "FS", ki)) return "emummc"; + + // Skip checking again. + emummc_patch_selected = false; + emummc_patch_apply = false; } } } - for (u32 i = 0; i < numPatches; i++) + // Check if all patches were applied. + for (u32 i = 0; i < patches_num; i++) { - if ((patchesApplied & (1u << i)) == 0) + if ((patches_applied & BIT(i)) == 0) return patches[i]; } + // Check if emuMMC was applied. + if (emummc_patch_selected) + return "emummc"; + return NULL; } -static const u8 mkey_keyseed_8xx[][0x10] = +// Master key 7 encrypted with 8. (7.0.0 with 8.1.0). AES-ECB +static const u8 mkey_vector_7xx[SE_KEY_128_SIZE] = + { 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }; + +u8 pkg2_keyslot; +pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb, bool is_exo) { - // Master key 8 encrypted with 9. (8.1.0 with 9.0.0) - { 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, - // Master key 9 encrypted with 10. (9.0.0 with 9.1.0) - { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A } -}; - -static bool _pkg2_key_unwrap_validate(pkg2_hdr_t *tmp_test, pkg2_hdr_t *hdr, u8 src_slot, u8 *mkey, const u8 *key_seed) -{ - - // Decrypt older encrypted mkey. - se_aes_crypt_ecb(src_slot, 0, mkey, 0x10, key_seed, 0x10); - // Set and unwrap pkg2 key. - se_aes_key_clear(9); - se_aes_key_set(9, mkey, 0x10); - se_aes_unwrap_key(9, 9, package2_keyseed); - - // Decrypt header. - se_aes_crypt_ctr(9, tmp_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); - - // Return if header is valid. - return (tmp_test->magic == PKG2_MAGIC); -} - -pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb) -{ - pkg2_hdr_t mkey_test; u8 *pdata = (u8 *)data; - u8 keyslot = 8; // Skip signature. pdata += 0x100; @@ -1169,105 +710,84 @@ pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb) // Skip header. pdata += sizeof(pkg2_hdr_t); - //! Check if we need to decrypt with newer mkeys. Valid for sept for 8.1.0 and up. - se_aes_crypt_ctr(8, &mkey_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + // Set pkg2 key slot to default. If 7.0.0 it will change to 9. + pkg2_keyslot = 8; - if (mkey_test.magic == PKG2_MAGIC) - goto key_found; - - // Decrypt older pkg2 via new mkeys. - if ((kb >= KB_FIRMWARE_VERSION_810) && (kb < KB_FIRMWARE_VERSION_MAX)) + // Decrypt 7.0.0 pkg2 via 8.1.0 mkey on Erista. + if (!h_cfg.t210b01 && kb == HOS_KB_VERSION_700) { - u8 tmp_mkey[0x10]; - u8 decr_slot = 12; // Sept mkey. - u8 mkey_seeds_cnt = sizeof(mkey_keyseed_8xx) / 0x10; - u8 mkey_seeds_idx = mkey_seeds_cnt; // Real index + 1. - u8 mkey_seeds_min_idx = mkey_seeds_cnt - (KB_FIRMWARE_VERSION_MAX - kb); + u8 tmp_mkey[SE_KEY_128_SIZE]; - while (mkey_seeds_cnt) - { - // Decrypt and validate mkey. - int res = _pkg2_key_unwrap_validate(&mkey_test, hdr, decr_slot, - tmp_mkey, mkey_keyseed_8xx[mkey_seeds_idx - 1]); + // Decrypt 7.0.0 encrypted mkey. + se_aes_crypt_ecb(!is_exo ? 7 : 13, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, mkey_vector_7xx, SE_KEY_128_SIZE); - if (res) - { - keyslot = 9; - goto key_found; - } - else - { - // Set current mkey in order to decrypt a lower mkey. - mkey_seeds_idx--; - se_aes_key_clear(9); - se_aes_key_set(9, tmp_mkey, 0x10); - - decr_slot = 9; // Temp key. + // Set and unwrap pkg2 key. + se_aes_key_set(9, tmp_mkey, SE_KEY_128_SIZE); + se_aes_unwrap_key(9, 9, package2_keyseed); - // Check if we tried last key for that pkg2 version. - // And start with a lower mkey in case sept is older. - if (mkey_seeds_idx == mkey_seeds_min_idx) - { - mkey_seeds_cnt--; - mkey_seeds_idx = mkey_seeds_cnt; - decr_slot = 12; // Sept mkey. - } - - // Out of keys. pkg2 is latest or process failed. - if (!mkey_seeds_cnt) - se_aes_key_clear(9); - } - } + pkg2_keyslot = 9; } -key_found: // Decrypt header. - se_aes_crypt_ctr(keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); - //gfx_hexdump((u32)hdr, hdr, 0x100); + se_aes_crypt_ctr(pkg2_keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); if (hdr->magic != PKG2_MAGIC) return NULL; + // Decrypt sections. 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(keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]); - //gfx_hexdump((u32)pdata, pdata, 0x100); + se_aes_crypt_ctr(pkg2_keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * SE_AES_IV_SIZE]); pdata += hdr->sec_size[i]; } - if (keyslot != 8) - se_aes_key_clear(9); - return hdr; } -static u32 _pkg2_ini1_build(u8 *pdst, pkg2_hdr_t *hdr, link_t *kips_info, bool new_pkg2) +static u32 _pkg2_ini1_build(u8 *pdst, u8 *psec, pkg2_hdr_t *hdr, link_t *kips_info, bool new_pkg2) { + // Calculate INI1 size. u32 ini1_size = sizeof(pkg2_ini1_t); + LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, kips_info, link) + { + ini1_size += ki->size; + } + + // Align size and set it. + ini1_size = ALIGN(ini1_size, 4); + + // For new kernel if INI1 fits in the old one, use it. + bool use_old_ini_region = psec && ini1_size <= (pkg2_newkern_ini1_end - pkg2_newkern_ini1_start); + if (use_old_ini_region) + pdst = psec + pkg2_newkern_ini1_start; + + // Set initial header and magic. pkg2_ini1_t *ini1 = (pkg2_ini1_t *)pdst; memset(ini1, 0, sizeof(pkg2_ini1_t)); ini1->magic = INI1_MAGIC; + ini1->size = ini1_size; pdst += sizeof(pkg2_ini1_t); + + // Merge KIPs into INI1. 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); +DPRINTF("adding kip1 '%s' @ %08X (%08X)\n", (char *)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 = ALIGN(ini1_size, 4); - ini1->size = ini1_size; + + // Encrypt INI1 in its own section if old pkg2. Otherwise it gets embedded into Kernel. if (!new_pkg2) { 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]); + se_aes_crypt_ctr(8, ini1, ini1_size, ini1, ini1_size, &hdr->sec_ctr[PKG2_SEC_INI1 * SE_AES_IV_SIZE]); } else { @@ -1275,13 +795,30 @@ DPRINTF("adding kip1 '%s' @ %08X (%08X)\n", ki->kip1->name, (u32)ki->kip1, ki->s hdr->sec_off[PKG2_SEC_INI1] = 0; } - return ini1_size; + return !use_old_ini_region ? ini1_size : 0; } -void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2) +void pkg2_build_encrypt(void *dst, void *hos_ctxt, link_t *kips_info, bool is_exo) { + launch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt; + u32 meso_magic = *(u32 *)(ctxt->kernel + 4); + u32 kernel_size = ctxt->kernel_size; + u8 kb = ctxt->pkg1_id->kb; u8 *pdst = (u8 *)dst; + // Force new Package2 if Mesosphere. + bool is_meso = (meso_magic & 0xF0FFFFFF) == ATM_MESOSPHERE; + if (is_meso) + ctxt->new_pkg2 = true; + + // Set key version. For Erista 7.0.0, use 8.1.0 because of a bug in Exo2? + u8 key_ver = kb ? kb + 1 : 0; + if (pkg2_keyslot == 9) + { + key_ver = HOS_KB_VERSION_810 + 1; + pkg2_keyslot = 8; + } + // Signature. memset(pdst, 0, 0x100); pdst += 0x100; @@ -1289,39 +826,71 @@ void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_i // Header. pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdst; memset(hdr, 0, sizeof(pkg2_hdr_t)); - pdst += sizeof(pkg2_hdr_t); + + // Set initial header values. hdr->magic = PKG2_MAGIC; - if (!new_pkg2) + hdr->bl_ver = 0; + hdr->pkg2_ver = 0xFF; + + if (!ctxt->new_pkg2) hdr->base = 0x10000000; else hdr->base = 0x60000; -DPRINTF("kernel @ %08X (%08X)\n", (u32)kernel, kernel_size); +DPRINTF("%s @ %08X (%08X)\n", is_meso ? "Mesosphere": "kernel",(u32)ctxt->kernel, kernel_size); + + pdst += sizeof(pkg2_hdr_t); // Kernel. - memcpy(pdst, kernel, kernel_size); - if (!new_pkg2) + memcpy(pdst, ctxt->kernel, kernel_size); + if (!ctxt->new_pkg2) hdr->sec_off[PKG2_SEC_KERNEL] = 0x10000000; else { - // Set new INI1 offset to kernel. - *(u32 *)(pdst + pkg2_newkern_ini1_val) = kernel_size; - kernel_size += _pkg2_ini1_build(pdst + kernel_size, hdr, kips_info, new_pkg2); + // Build INI1 for new Package2. + u32 ini1_size = _pkg2_ini1_build(pdst + kernel_size, is_meso ? NULL : pdst, hdr, kips_info, true); hdr->sec_off[PKG2_SEC_KERNEL] = 0x60000; + + // Set new INI1 offset to kernel. + u32 meso_meta_offset = *(u32 *)(pdst + 8); + if (is_meso && (meso_magic & 0x0F000000)) // MSS1. + *(u32 *)(pdst + meso_meta_offset) = kernel_size - meso_meta_offset; + else if (ini1_size) + { + if (is_meso) // MSS0. + *(u32 *)(pdst + 8) = kernel_size; + else + *(u32 *)(pdst + pkg2_newkern_ini1_info) = kernel_size - pkg2_newkern_ini1_rela; + } + + kernel_size += ini1_size; } hdr->sec_size[PKG2_SEC_KERNEL] = kernel_size; - se_aes_crypt_ctr(8, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * 0x10]); + se_aes_crypt_ctr(pkg2_keyslot, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * SE_AES_IV_SIZE]); pdst += kernel_size; DPRINTF("kernel encrypted\n"); - // INI1. + // Build INI1 for old Package2. u32 ini1_size = 0; - if (!new_pkg2) - ini1_size = _pkg2_ini1_build(pdst, hdr, kips_info, new_pkg2); + if (!ctxt->new_pkg2) + ini1_size = _pkg2_ini1_build(pdst, NULL, hdr, kips_info, false); DPRINTF("INI1 encrypted\n"); - //Encrypt header. + if (!is_exo) // Not needed on Exosphere 1.0.0 and up. + { + // Calculate SHA256 over encrypted sections. Only 3 have valid hashes. + u8 *pk2_hash_data = (u8 *)dst + 0x100 + sizeof(pkg2_hdr_t); + for (u32 i = PKG2_SEC_KERNEL; i <= PKG2_SEC_UNUSED; i++) + { + se_calc_sha256_oneshot(&hdr->sec_sha256[SE_SHA_256_SIZE * i], (void *)pk2_hash_data, hdr->sec_size[i]); + pk2_hash_data += hdr->sec_size[i]; + } + } + + // 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); + hdr->ctr[4] = key_ver; + se_aes_crypt_ctr(pkg2_keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + memset(hdr->ctr, 0 , SE_AES_IV_SIZE); *(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size; + hdr->ctr[4] = key_ver; } diff --git a/bootloader/hos/pkg2.h b/bootloader/hos/pkg2.h index 1a5f7ab..551e46e 100644 --- a/bootloader/hos/pkg2.h +++ b/bootloader/hos/pkg2.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,32 +18,37 @@ #ifndef _PKG2_H_ #define _PKG2_H_ -#include "../utils/types.h" -#include "../utils/list.h" +#include -#define PKG2_MAGIC 0x31324B50 -#define PKG2_SEC_BASE 0x80000000 +#define PKG2_MAGIC 0x31324B50 +#define PKG2_SEC_BASE 0x80000000 #define PKG2_SEC_KERNEL 0 -#define PKG2_SEC_INI1 1 +#define PKG2_SEC_INI1 1 +#define PKG2_SEC_UNUSED 2 #define INI1_MAGIC 0x31494E49 -#define PKG2_NEWKERN_GET_INI1 0x44 + +//! TODO: Update on kernel change if needed. +// Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16. +#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0. #define PKG2_NEWKERN_START 0x800 -u32 pkg2_newkern_ini1_val; -u32 pkg2_newkern_ini1_start; -u32 pkg2_newkern_ini1_end; +#define ATM_MESOSPHERE 0x3053534D + +extern u32 pkg2_newkern_ini1_info; +extern u32 pkg2_newkern_ini1_start; +extern u32 pkg2_newkern_ini1_end; typedef struct _kernel_patch_t { - u32 id; - u32 off; - u32 val; - u32 *ptr; + u32 id; + u32 off; + u32 val; + const u32 *ptr; } kernel_patch_t; #define KERNEL_PATCHSET_DEF(name, ...) \ - kernel_patch_t name[] = { \ + static const kernel_patch_t name[] = { \ __VA_ARGS__, \ {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, (u32 *)0xFFFFFFFF} \ } @@ -63,17 +68,18 @@ enum 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[]; +/* 0x000 */ u8 ctr[0x10]; +/* 0x010 */ u8 sec_ctr[0x40]; +/* 0x050 */ u32 magic; +/* 0x054 */ u32 base; +/* 0x058 */ u32 pad0; +/* 0x05C */ u8 pkg2_ver; +/* 0x05D */ u8 bl_ver; +/* 0x05E */ u16 pad1; +/* 0x060 */ u32 sec_size[4]; +/* 0x070 */ u32 sec_off[4]; +/* 0x080 */ u8 sec_sha256[0x80]; +/* 0x100 */ u8 data[]; } pkg2_hdr_t; typedef struct _pkg2_ini1_t @@ -96,17 +102,17 @@ typedef struct _pkg2_kip1_sec_t 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[]; +/* 0x000 */ u32 magic; +/* 0x004 */ u8 name[12]; +/* 0x010 */ u64 tid; +/* 0x018 */ u32 proc_cat; +/* 0x01C */ u8 main_thrd_prio; +/* 0x01D */ u8 def_cpu_core; +/* 0x01E */ u8 res; +/* 0x01F */ u8 flags; +/* 0x020 */ pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS]; +/* 0x080 */ u32 caps[0x20]; +/* 0x100 */ u8 data[]; } pkg2_kip1_t; typedef struct _pkg2_kip1_info_t @@ -119,40 +125,42 @@ typedef struct _pkg2_kip1_info_t typedef struct _pkg2_kernel_id_t { u8 hash[8]; - kernel_patch_t *kernel_patchset; + const kernel_patch_t *kernel_patchset; } pkg2_kernel_id_t; +#define KIP1_PATCH_SRC_NO_CHECK (char *)(-1) + typedef struct _kip1_patch_t { - u32 offset; // section+offset of patch to apply. - u32 length; // In bytes, 0 means last patch. - char* srcData; // That must match. - char* dstData; // That it gets replaced by. + u32 offset; // section+offset of patch to apply. + u32 length; // In bytes, 0 means last patch. + char *src_data; // That must match. + char *dst_data; // That it gets replaced by. } kip1_patch_t; typedef struct _kip1_patchset_t { - char* name; // NULL means end. - kip1_patch_t* patches; // NULL means not necessary. + char *name; // NULL means end. + const kip1_patch_t *patches; // NULL means not necessary. } kip1_patchset_t; typedef struct _kip1_id_t { - const char* name; + const char *name; u8 hash[8]; - kip1_patchset_t* patchset; + const kip1_patchset_t *patchset; } kip1_id_t; -void pkg2_get_newkern_info(u8 *kern_data); -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); +bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_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); -const char* pkg2_patch_kips(link_t *info, char* patchNames); +void pkg2_get_ids(kip1_id_t **ids, u32 *entries); +const char *pkg2_patch_kips(link_t *info, char *patch_names); -const pkg2_kernel_id_t *pkg2_identify(u8 *hash); -pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb); -void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2); +const pkg2_kernel_id_t *pkg2_identify(const u8 *hash); +pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb, bool is_exo); +void pkg2_build_encrypt(void *dst, void *hos_ctxt, link_t *kips_info, bool is_exo); #endif diff --git a/bootloader/hos/pkg2_ini_kippatch.c b/bootloader/hos/pkg2_ini_kippatch.c index 97d2751..9567eef 100644 --- a/bootloader/hos/pkg2_ini_kippatch.c +++ b/bootloader/hos/pkg2_ini_kippatch.c @@ -1,18 +1,35 @@ +/* + * Copyright (c) 2019-2024 CTCaer + * + * 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 +#include + #include "pkg2_ini_kippatch.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" +#include #define KPS(x) ((u32)(x) << 29) -static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len) +static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len, u8 *buf) { char ch = *ptr; u32 ascii_len = byte_len * 2; if (!result) - result = malloc(byte_len); + result = buf; u8 *dst = result; while (ch == ' ' || ch == '\t') @@ -45,24 +62,11 @@ static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len) return result; } -static char *_strdup(char *str) -{ - if (!str) - return NULL; - if (str[0] == ' ' && (strlen(str) > 1)) - str++; - char *res = (char *)malloc(strlen(str) + 1); - strcpy(res, str); - if (res[strlen(res) - 1] == ' ' && (strlen(res) > 1)) - res[strlen(res) - 1] = 0; - - return res; -} - static u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar) { u32 i; - for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) + // Depends on 'FF_USE_STRFUNC 2' that removes \r. + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++) ; lbuf[i] = 0; @@ -72,32 +76,38 @@ static u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar) static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, char *name) { if (ksec) - { list_append(dst, &ksec->link); - ksec = NULL; - } - ksec = (ini_kip_sec_t *)malloc(sizeof(ini_kip_sec_t)); - u32 i = _find_patch_section_name(name, strlen(name), ':') + 1; - ksec->name = _strdup(name); + // Calculate total allocation size. + u32 len = strlen(name); + char *buf = zalloc(sizeof(ini_kip_sec_t) + len + 1); + + ksec = (ini_kip_sec_t *)buf; + u32 i = _find_patch_section_name(name, len, ':') + 1; + ksec->name = strcpy_ns(buf + sizeof(ini_kip_sec_t), name); // Get hash section. - _htoa(ksec->hash, &name[i], 8); + _htoa(ksec->hash, &name[i], 8, NULL); + + // Initialize list. + list_init(&ksec->pts); return ksec; } -int ini_patch_parse(link_t *dst, char *ini_path) +int ini_patch_parse(link_t *dst, const char *ini_path) { - u32 lblen; - char lbuf[512]; FIL fp; + u32 lblen; + char *lbuf; ini_kip_sec_t *ksec = NULL; // Open ini. if (f_open(&fp, ini_path, FA_READ) != FR_OK) return 0; + lbuf = malloc(512); + do { // Fetch one line. @@ -105,53 +115,56 @@ int ini_patch_parse(link_t *dst, char *ini_path) f_gets(lbuf, 512, &fp); lblen = strlen(lbuf); - // Remove trailing newline. - if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') + // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r. + if (lblen && lbuf[lblen - 1] == '\n') lbuf[lblen - 1] = 0; if (lblen > 2 && lbuf[0] == '[') // Create new section. { _find_patch_section_name(lbuf, lblen, ']'); + // Set patchset kip name and hash. ksec = _ini_create_kip_section(dst, ksec, &lbuf[1]); - list_init(&ksec->pts); } - else if (ksec && lbuf[0] == '.') //Extract key/value. + else if (ksec && lbuf[0] == '.') // Extract key/value. { - u32 tmp = 0; - u32 i = _find_patch_section_name(lbuf, lblen, '='); + u32 str_start = 0; + u32 pos = _find_patch_section_name(lbuf, lblen, '='); - ini_patchset_t *pt = (ini_patchset_t *)malloc(sizeof(ini_patchset_t)); + // Calculate total allocation size. + char *buf = zalloc(sizeof(ini_patchset_t) + strlen(&lbuf[1]) + 1); + ini_patchset_t *pt = (ini_patchset_t *)buf; - pt->name = _strdup(&lbuf[1]); + // Set patch name. + pt->name = strcpy_ns(buf + sizeof(ini_patchset_t), &lbuf[1]); - u8 kip_sidx = lbuf[i + 1] - '0'; + u8 kip_sidx = lbuf[pos + 1] - '0'; + pos += 3; if (kip_sidx < 6) { + // Set patch offset. pt->offset = KPS(kip_sidx); - tmp = _find_patch_section_name(&lbuf[i + 3], lblen, ':'); - pt->offset |= strtol(&lbuf[i + 3], NULL, 16); + str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ':'); + pt->offset |= strtol(&lbuf[pos], NULL, 16); + pos += str_start + 1; - i += tmp + 4; + // Set patch size. + str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ':'); + pt->length = strtol(&lbuf[pos], NULL, 16); + pos += str_start + 1; - tmp = _find_patch_section_name(&lbuf[i], lblen, ':'); - pt->length = strtol(&lbuf[i], NULL, 16); + u8 *data = malloc(pt->length * 2); - i += tmp + 1; + // Set patch source data. + str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ','); + pt->src_data = _htoa(NULL, &lbuf[pos], pt->length, data); + pos += str_start + 1; - tmp = _find_patch_section_name(&lbuf[i], lblen, ','); - pt->srcData = _htoa(NULL, &lbuf[i], pt->length); - i += tmp + 1; - pt->dstData = _htoa(NULL, &lbuf[i], pt->length); - } - else - { - pt->offset = 0; - pt->length = 0; - pt->srcData = NULL; - pt->dstData = NULL; + // Set patch destination data. + pt->dst_data = _htoa(NULL, &lbuf[pos], pt->length, data + pt->length); } + list_append(&ksec->pts, &pt->link); } } while (!f_eof(&fp)); @@ -161,5 +174,7 @@ int ini_patch_parse(link_t *dst, char *ini_path) if (ksec) list_append(dst, &ksec->link); + free(lbuf); + return 1; } diff --git a/bootloader/hos/pkg2_ini_kippatch.h b/bootloader/hos/pkg2_ini_kippatch.h index f459c3c..07881c1 100644 --- a/bootloader/hos/pkg2_ini_kippatch.h +++ b/bootloader/hos/pkg2_ini_kippatch.h @@ -17,16 +17,15 @@ #ifndef _INIPATCH_H_ #define _INIPATCH_H_ -#include "../utils/types.h" -#include "../utils/list.h" +#include typedef struct _ini_patchset_t { char *name; - u32 offset; // section + offset of patch to apply. - u32 length; // In bytes, 0 means last patch. - u8 *srcData; // That must match. - u8 *dstData; // Gets replaced with. + u32 offset; // section + offset of patch to apply. + u32 length; // In bytes, 0 means last patch. + u8 *src_data; // That must match. + u8 *dst_data; // Gets replaced with. link_t link; } ini_patchset_t; @@ -38,6 +37,6 @@ typedef struct _ini_kip_sec_t link_t link; } ini_kip_sec_t; -int ini_patch_parse(link_t *dst, char *ini_path); +int ini_patch_parse(link_t *dst, const char *ini_path); #endif diff --git a/bootloader/hos/pkg2_patches.inl b/bootloader/hos/pkg2_patches.inl new file mode 100644 index 0000000..075df1b --- /dev/null +++ b/bootloader/hos/pkg2_patches.inl @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018 Atmosphère-NX + * + * 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: Replace hardcoded AArch64 instructions with instruction macros. +//TODO: Reduce hardcoded values without searching kernel for patterns? +// The process ID send/receive kernel patches were taken from Atmosphère's kernel patches. +// They should only be used when running Atmosphère. +#define CODE_OFF_1ST_100 0x4797C +#define CODE_OFF_1ST_200 0x6486C +#define CODE_OFF_1ST_300 0x494A4 +#define CODE_OFF_1ST_302 0x494BC +#define CODE_OFF_1ST_400 0x52890 +#define CODE_OFF_1ST_500 0x5C020 +#define CODE_OFF_1ST_600 0x5EE00 +#define CODE_OFF_1ST_700 0x5FEC0 +#define CODE_OFF_1ST_800 0x607F0 +#define CODE_OFF_1ST_900 0x65780 +#define CODE_OFF_1ST_1000 0x67790 +#define CODE_OFF_1ST_1100 0x49EE8 +#define CODE_OFF_1ST_1200 0x48810 + +#define ID_SND_OFF_100 0x23CC0 +#define ID_SND_OFF_200 0x3F134 +#define ID_SND_OFF_300 0x26080 +#define ID_SND_OFF_302 0x26080 +#define ID_SND_OFF_400 0x2AF64 +#define ID_SND_OFF_500 0x2AD34 +#define ID_SND_OFF_600 0x2BB8C +#define ID_SND_OFF_700 0x2D044 +#define ID_SND_OFF_800 0x2F1FC +#define ID_SND_OFF_900 0x329A0 +#define ID_SND_OFF_1000 0x34404 +#define ID_SND_OFF_1100 0x245B4 +#define ID_SND_OFF_1101 0x245B8 +#define ID_SND_OFF_1200 0x24CF4 + +#define ID_RCV_OFF_100 0x219F0 +#define ID_RCV_OFF_200 0x3D1A8 +#define ID_RCV_OFF_300 0x240F0 +#define ID_RCV_OFF_302 0x240F0 +#define ID_RCV_OFF_400 0x28F6C +#define ID_RCV_OFF_500 0x28DAC +#define ID_RCV_OFF_600 0x29B6C +#define ID_RCV_OFF_700 0x2B23C +#define ID_RCV_OFF_800 0x2D424 +#define ID_RCV_OFF_900 0x309B4 +#define ID_RCV_OFF_1000 0x322F8 +#define ID_RCV_OFF_1100 0x22B24 +#define ID_RCV_OFF_1101 0x22B28 +#define ID_RCV_OFF_1200 0x23424 + +static const u32 PRC_ID_SND_100[] = +{ + 0xA9BF2FEA, 0x2A0E03EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B, + 0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9412948, 0xA8C12FEA +}; +#define CODE_OFF_2ND_100 (CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + sizeof(u32)) +static const u32 PRC_ID_RCV_100[] = +{ + 0xA9BF2FEA, 0x2A1C03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, + 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9412968, 0xA8C12FEA +}; + +static const u32 PRC_ID_SND_200[] = +{ + 0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B, + 0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9413148, 0xA8C12FEA +}; +#define CODE_OFF_2ND_200 (CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + sizeof(u32)) +static const u32 PRC_ID_RCV_200[] = +{ + 0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148, + 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9413168, 0xA8C12FEA +}; + +static const u32 PRC_ID_SND_300[] = +{ + 0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B, + 0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA +}; +#define CODE_OFF_2ND_300 (CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + sizeof(u32)) +static const u32 PRC_ID_RCV_300[] = +{ + 0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148, + 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA +}; + +#define CODE_OFF_2ND_302 (CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300) + sizeof(u32)) + +static const u32 PRC_ID_SND_400[] = +{ + 0x2A1703EA, 0xD37EF54A, 0xF86A6B8A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, + 0xEB09015F, 0x54000060, 0xF94053EA, 0xF9415948, 0xF94053EA +}; +#define CODE_OFF_2ND_400 (CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + sizeof(u32)) +static const u32 PRC_ID_RCV_400[] = +{ + 0xF9403BED, 0x2A0E03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, + 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B28, 0xD503201F +}; + +static const u32 PRC_ID_SND_500[] = +{ + 0x2A1703EA, 0xD37EF54A, 0xF86A6B6A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, + 0xEB09015F, 0x54000060, 0xF94043EA, 0xF9415948, 0xF94043EA +}; +#define CODE_OFF_2ND_500 (CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + sizeof(u32)) +static const u32 PRC_ID_RCV_500[] = +{ + 0xF9403BED, 0x2A1503EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, + 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B08, 0xF9406FEA +}; + +static const u32 PRC_ID_SND_600[] = +{ + 0xA9BF2FEA, 0xF94037EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; +#define CODE_OFF_2ND_600 (CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + sizeof(u32)) +static const u32 PRC_ID_RCV_600[] = +{ + 0xA9BF2FEA, 0xF94043EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; + +static const u32 PRC_ID_SND_700[] = +{ + 0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; +#define CODE_OFF_2ND_700 (CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700) + sizeof(u32)) +static const u32 PRC_ID_RCV_700[] = +{ + 0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; + +#define CODE_OFF_2ND_800 (CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700) + sizeof(u32)) + +static const u32 PRC_ID_SND_900[] = +{ + 0xA9BF2FEA, 0xF94037EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; +#define CODE_OFF_2ND_900 (CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900) + sizeof(u32)) +static const u32 PRC_ID_RCV_900[] = +{ + 0xA9BF2FEA, 0xF9404BEB, 0x2A1703EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; + +static const u32 PRC_ID_SND_1000[] = +{ + 0xA9BF2FEA, 0xF94063EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; +#define CODE_OFF_2ND_1000 (CODE_OFF_1ST_1000 + sizeof(PRC_ID_SND_1000) + sizeof(u32)) +static const u32 PRC_ID_RCV_1000[] = +{ + 0xA9BF2FEA, 0xF94067EB, 0x2A1A03EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; + +static const u32 PRC_ID_SND_1100[] = +{ + 0xA9BF2FEA, 0xF94043EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; +#define CODE_OFF_2ND_1100 (CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100) + sizeof(u32)) +static const u32 PRC_ID_RCV_1100[] = +{ + 0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; + +static const u32 PRC_ID_SND_1200[] = +{ + 0xA9BF2FEA, 0xF9404FEB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002C8, 0xF9401D08, 0xAA1603E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; +#define CODE_OFF_2ND_1200 (CODE_OFF_1ST_1200 + sizeof(PRC_ID_SND_1200) + sizeof(u32)) +static const u32 PRC_ID_RCV_1200[] = +{ + 0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, + 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0, + 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0 +}; + +// Include kernel patches here, so we can utilize pkg1 id +KERNEL_PATCHSET_DEF(_kernel_1_patchset, + { SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x44074, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_GEN_PATCH, ID_SND_OFF_100, _B(ID_SND_OFF_100, CODE_OFF_1ST_100), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_100, sizeof(PRC_ID_SND_100) >> 2, PRC_ID_SND_100 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), // Branch back and skip 1 instruction. + _B(CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + 0x4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_100, _B(ID_RCV_OFF_100, CODE_OFF_2ND_100), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_100, sizeof(PRC_ID_RCV_100) >> 2, PRC_ID_RCV_100 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), // Branch back and skip 1 instruction. + _B(CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + 0x4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_2_patchset, + { SVC_VERIFY_DS, 0x54834, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x6086C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_GEN_PATCH, ID_SND_OFF_200, _B(ID_SND_OFF_200, CODE_OFF_1ST_200), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_200, sizeof(PRC_ID_SND_200) >> 2, PRC_ID_SND_200 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), // Branch back and skip 1 instruction. + _B(CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + 0x4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_200, _B(ID_RCV_OFF_200, CODE_OFF_2ND_200), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_200, sizeof(PRC_ID_RCV_200) >> 2, PRC_ID_RCV_200 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), // Branch back and skip 1 instruction. + _B(CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + 0x4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_3_patchset, + { SVC_VERIFY_DS, 0x3BD24, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x483FC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_GEN_PATCH, ID_SND_OFF_300, _B(ID_SND_OFF_300, CODE_OFF_1ST_300), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_300, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction. + _B(CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + 0x4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_300, _B(ID_RCV_OFF_300, CODE_OFF_2ND_300), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_300, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction. + _B(CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + 0x4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_302_patchset, + { SVC_VERIFY_DS, 0x3BD24, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x48414, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, CODE_OFF_1ST_302), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_302, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction. + _B(CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), ID_SND_OFF_302 + 0x4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, CODE_OFF_2ND_302), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction. + _B(CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_302 + 0x4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_4_patchset, + { SVC_VERIFY_DS, 0x41EB4, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x4EBFC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_GEN_PATCH, ID_SND_OFF_400, _B(ID_SND_OFF_400, CODE_OFF_1ST_400), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_400, sizeof(PRC_ID_SND_400) >> 2, PRC_ID_SND_400 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), // Branch back and skip 2 instructions. + _B(CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + 0x4 * 2), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_400, _B(ID_RCV_OFF_400, CODE_OFF_2ND_400), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_400, sizeof(PRC_ID_RCV_400) >> 2, PRC_ID_RCV_400 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), // Branch back and skip 1 instruction. + _B(CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + 0x4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_5_patchset, + { SVC_GENERIC, 0x38C2C, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x54E30, _MOVZW(8, 0x1E00, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, CODE_OFF_1ST_500), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2, PRC_ID_SND_500 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), // Branch back and skip 2 instructions. + _B(CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + 0x4 * 2), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_500, _B(ID_RCV_OFF_500, CODE_OFF_2ND_500), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_500, sizeof(PRC_ID_RCV_500) >> 2, PRC_ID_RCV_500 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), // Branch back and skip 2 instructions. + _B(CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + 0x4 * 2), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_6_patchset, + { SVC_GENERIC, 0x3A8CC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x57330, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, CODE_OFF_1ST_600), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2, PRC_ID_SND_600 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + 0x4 * 4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_600, _B(ID_RCV_OFF_600, CODE_OFF_2ND_600), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_600, sizeof(PRC_ID_RCV_600) >> 2, PRC_ID_RCV_600 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + 0x4 * 4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_7_patchset, + { SVC_GENERIC, 0x3C6E0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x49E5C, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x581B0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x57F98, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_700, _B(ID_SND_OFF_700, CODE_OFF_1ST_700), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_700, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), ID_SND_OFF_700 + 0x4 * 4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_700, _B(ID_RCV_OFF_700, CODE_OFF_2ND_700), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_700, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_700 + 0x4 * 4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_8_patchset, + { SVC_GENERIC, 0x3FAD0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x4D15C, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x5BFAC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x5F9A4, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_800, _B(ID_SND_OFF_800, CODE_OFF_1ST_800), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_800, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), ID_SND_OFF_800 + 0x4 * 4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_800, _B(ID_RCV_OFF_800, CODE_OFF_2ND_800), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_800, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_800 + 0x4 * 4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_9_patchset, + { SVC_GENERIC, 0x43DFC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x50628, _NOP(), NULL }, // Disable SVC verifications + { DEBUG_MODE_EN, 0x609E8, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x6493C, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_900, _B(ID_SND_OFF_900, CODE_OFF_1ST_900), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_900, sizeof(PRC_ID_SND_900) >> 2, PRC_ID_SND_900 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), ID_SND_OFF_900 + 0x4 * 4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_900, _B(ID_RCV_OFF_900, CODE_OFF_2ND_900), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_900, sizeof(PRC_ID_RCV_900) >> 2, PRC_ID_RCV_900 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), ID_RCV_OFF_900 + 0x4 * 4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_10_patchset, + { SVC_GENERIC, 0x45DAC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x523E4, _NOP(), NULL }, // Disable SVC verifications. + { DEBUG_MODE_EN, 0x62B14, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch. + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x66950, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_1000, _B(ID_SND_OFF_1000, CODE_OFF_1ST_1000), NULL }, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_1000, sizeof(PRC_ID_SND_1000) >> 2, PRC_ID_SND_1000 }, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_1000 + sizeof(PRC_ID_SND_1000), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_1000 + sizeof(PRC_ID_SND_1000), ID_SND_OFF_1000 + 0x4 * 4), NULL }, + { ATM_GEN_PATCH, ID_RCV_OFF_1000, _B(ID_RCV_OFF_1000, CODE_OFF_2ND_1000), NULL }, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_1000, sizeof(PRC_ID_RCV_1000) >> 2, PRC_ID_RCV_1000 }, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_1000 + sizeof(PRC_ID_RCV_1000), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_1000 + sizeof(PRC_ID_RCV_1000), ID_RCV_OFF_1000 + 0x4 * 4), NULL } +); + +KERNEL_PATCHSET_DEF(_kernel_11_patchset, + { SVC_GENERIC, 0x2FCE0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x39194, _NOP(), NULL }, // Disable SVC verifications. + { DEBUG_MODE_EN, 0x460C0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch. + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x490C4, _MOVZW(21, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_1100, _B(ID_SND_OFF_1100, CODE_OFF_1ST_1100), NULL}, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_1100, sizeof(PRC_ID_SND_1100) >> 2, PRC_ID_SND_1100}, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100), ID_SND_OFF_1100 + 0x4 * 4), NULL}, + { ATM_GEN_PATCH, ID_RCV_OFF_1100, _B(ID_RCV_OFF_1100, CODE_OFF_2ND_1100), NULL}, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_1100, sizeof(PRC_ID_RCV_1100) >> 2, PRC_ID_RCV_1100}, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100), ID_RCV_OFF_1100 + 0x4 * 4), NULL} +); + +KERNEL_PATCHSET_DEF(_kernel_1101_patchset, + { SVC_GENERIC, 0x2FD04, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x39194, _NOP(), NULL }, // Disable SVC verifications. + { DEBUG_MODE_EN, 0x460C0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch. + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x490C4, _MOVZW(21, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_1101, _B(ID_SND_OFF_1101, CODE_OFF_1ST_1100), NULL}, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_1100, sizeof(PRC_ID_SND_1100) >> 2, PRC_ID_SND_1100}, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100), ID_SND_OFF_1101 + 0x4 * 4), NULL}, + { ATM_GEN_PATCH, ID_RCV_OFF_1101, _B(ID_RCV_OFF_1101, CODE_OFF_2ND_1100), NULL}, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_1100, sizeof(PRC_ID_RCV_1100) >> 2, PRC_ID_RCV_1100}, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100), ID_RCV_OFF_1101 + 0x4 * 4), NULL} +); + +KERNEL_PATCHSET_DEF(_kernel_12_patchset, + { SVC_GENERIC, 0x2FCB4, _NOP(), NULL }, // Allow same process on svcControlCodeMemory. + { SVC_VERIFY_DS, 0x38440, _NOP(), NULL }, // Disable SVC verifications. + { DEBUG_MODE_EN, 0x45118, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch. + // Atmosphère kernel patches. + { ATM_SYSM_INCR, 0x4809C, _MOVZW(21, 0x1D80, LSL16), NULL }, // System memory pool increase. + { ATM_GEN_PATCH, ID_SND_OFF_1200, _B(ID_SND_OFF_1200, CODE_OFF_1ST_1200), NULL}, // Send process id branch. + { ATM_ARR_PATCH, CODE_OFF_1ST_1200, sizeof(PRC_ID_SND_1200) >> 2, PRC_ID_SND_1200}, // Send process id code. + { ATM_GEN_PATCH, CODE_OFF_1ST_1200 + sizeof(PRC_ID_SND_1200), // Branch back and skip 4 instructions. + _B(CODE_OFF_1ST_1200 + sizeof(PRC_ID_SND_1200), ID_SND_OFF_1200 + 0x4 * 4), NULL}, + { ATM_GEN_PATCH, ID_RCV_OFF_1200, _B(ID_RCV_OFF_1200, CODE_OFF_2ND_1200), NULL}, // Receive process id branch. + { ATM_ARR_PATCH, CODE_OFF_2ND_1200, sizeof(PRC_ID_RCV_1200) >> 2, PRC_ID_RCV_1200}, // Receive process id code. + { ATM_GEN_PATCH, CODE_OFF_2ND_1200 + sizeof(PRC_ID_RCV_1200), // Branch back and skip 4 instructions. + _B(CODE_OFF_2ND_1200 + sizeof(PRC_ID_RCV_1200), ID_RCV_OFF_1200 + 0x4 * 4), NULL} +); + +// Kernel sha256 hashes. Offset 0x800 up to INI1 start. +static const pkg2_kernel_id_t _pkg2_kernel_ids[] = +{ + { "\xb8\xc5\x0c\x68\x25\xa9\xb9\x5b", _kernel_1_patchset }, // 1.0.0 + { "\x64\x0b\x51\xff\x28\x01\xb8\x30", _kernel_2_patchset }, // 2.0.0 - 2.3.0 + { "\x50\x84\x23\xac\x6f\xa1\x5d\x3b", _kernel_3_patchset }, // 3.0.0 - 3.0.1 + { "\x81\x9d\x08\xbe\xe4\x5e\x1f\xbb", _kernel_302_patchset }, // 3.0.2 + { "\xe6\xc0\xb7\xe3\x2f\xf9\x44\x51", _kernel_4_patchset }, // 4.0.0 - 4.1.0 + { "\xb2\x38\x61\xa8\xe1\xe2\xe4\xe4", _kernel_5_patchset }, // 5.0.0 - 5.1.0 + { "\x85\x97\x40\xf6\xc0\x3e\x3d\x44", _kernel_6_patchset }, // 6.0.0 - 6.2.0 + { "\xa2\x5e\x47\x0c\x8e\x6d\x2f\xd7", _kernel_7_patchset }, // 7.0.0 - 7.0.1 + { "\xf1\x5e\xc8\x34\xfd\x68\xf0\xf0", _kernel_8_patchset }, // 8.0.0 - 8.1.0. Kernel only. + { "\x69\x00\x39\xdf\x21\x56\x70\x6b", _kernel_9_patchset }, // 9.0.0 - 9.1.0. Kernel only. + { "\xa2\xe3\xad\x1c\x98\xd8\x7a\x62", _kernel_9_patchset }, // 9.2.0. Kernel only. + { "\x21\xc1\xd7\x24\x8e\xcd\xbd\xa8", _kernel_10_patchset }, // 10.0.0 - 10.2.0. Kernel only. + { "\xD5\xD0\xBA\x5D\x52\xB9\x77\x85", _kernel_11_patchset }, // 11.0.0. Kernel only. + { "\xF8\x1E\xE0\x30\x3C\x7A\x08\x04", _kernel_1101_patchset },// 11.0.1. Kernel only. + { "\xA6\xD8\xFF\xF3\x67\x4A\x33\xFC", _kernel_12_patchset }, // 12.0.0 - 12.1.0. Kernel only. + //! TODO: Mesosphere is now mandatory. Missing patches: 13.0.0+ +}; + +// All kip patch offsets are without the 0x100-sized header. +static const kip1_patchset_t _fs_patches_100[] = { + { "nogc", NULL }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_40x[] = { + { KPS(KIP_TEXT) | 0xA3458, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x72" }, + { KPS(KIP_TEXT) | 0xAAB44, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_40x[] = { + { "nogc", _fs_nogc_40x }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_410[] = { + { KPS(KIP_TEXT) | 0xA34BC, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x72" }, + { KPS(KIP_TEXT) | 0xAABA8, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_410[] = { + { "nogc", _fs_nogc_410 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_50x[] = { + { KPS(KIP_TEXT) | 0xCF3C4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { KPS(KIP_TEXT) | 0xD73A0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_50x[] = { + { "nogc", _fs_nogc_50x }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_510[] = { + { KPS(KIP_TEXT) | 0xCF794, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { KPS(KIP_TEXT) | 0xD7770, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_510[] = { + { "nogc", _fs_nogc_510 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_600[] = { + { KPS(KIP_TEXT) | 0x12CC20, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1538F4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_600_exfat[] = { + { KPS(KIP_TEXT) | 0x138320, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x15EFF4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_600[] = { + { "nogc", _fs_nogc_600 }, + { NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_600_exfat[] = { + { "nogc", _fs_nogc_600_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_700[] = { + { KPS(KIP_TEXT) | 0x134160, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x15BF04, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_700_exfat[] = { + { KPS(KIP_TEXT) | 0x13F710, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1674B4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_700[] = { + { "nogc", _fs_nogc_700 }, + { NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_700_exfat[] = { + { "nogc", _fs_nogc_700_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_800[] = { + { KPS(KIP_TEXT) | 0x136800, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x15EB94, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_800_exfat[] = { + { KPS(KIP_TEXT) | 0x141DB0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x16A144, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_800[] = { + { "nogc", _fs_nogc_800 }, + { NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_800_exfat[] = { + { "nogc", _fs_nogc_800_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_900[] = { + { KPS(KIP_TEXT) | 0x129420, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x143268, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_900[] = { + { "nogc", _fs_nogc_900 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_910[] = { + { KPS(KIP_TEXT) | 0x129430, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x143278, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_910[] = { + { "nogc", _fs_nogc_910 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1000[] = { + { KPS(KIP_TEXT) | 0x13BE90, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x14DE08, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1000[] = { + { "nogc", _fs_nogc_1000 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1020[] = { + { KPS(KIP_TEXT) | 0x13C2F0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x14E268, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1020[] = { + { "nogc", _fs_nogc_1020 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1100[] = { + { KPS(KIP_TEXT) | 0x1398B4, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x156EB8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1100[] = { + { "nogc", _fs_nogc_1100 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1200[] = { + { KPS(KIP_TEXT) | 0x13EA24, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x155368, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1200[] = { + { "nogc", _fs_nogc_1200 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1203[] = { + { KPS(KIP_TEXT) | 0x13EB34, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x155478, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1203[] = { + { "nogc", _fs_nogc_1203 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1300[] = { + { KPS(KIP_TEXT) | 0x1425D0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x159018, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1300[] = { + { "nogc", _fs_nogc_1300 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1310[] = { + { KPS(KIP_TEXT) | 0x142570, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x158FB8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1310[] = { + { "nogc", _fs_nogc_1310 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1400[] = { + { KPS(KIP_TEXT) | 0x164230, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x18A2E8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1400[] = { + { "nogc", _fs_nogc_1400 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1400_exfat[] = { + { KPS(KIP_TEXT) | 0x16F5B0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x195668, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1400_exfat[] = { + { "nogc", _fs_nogc_1400_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1500[] = { + { KPS(KIP_TEXT) | 0x15ECE4, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x184158, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1500[] = { + { "nogc", _fs_nogc_1500 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1500_exfat[] = { + { KPS(KIP_TEXT) | 0x169C74, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x18F0E8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1500_exfat[] = { + { "nogc", _fs_nogc_1500_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1600[] = { + { KPS(KIP_TEXT) | 0x160B70, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1865D8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1600[] = { + { "nogc", _fs_nogc_1600 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1600_exfat[] = { + { KPS(KIP_TEXT) | 0x16B850, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1912B8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1600_exfat[] = { + { "nogc", _fs_nogc_1600_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1603[] = { + { KPS(KIP_TEXT) | 0x160BC0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x186628, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1603[] = { + { "nogc", _fs_nogc_1603 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1603_exfat[] = { + { KPS(KIP_TEXT) | 0x16B8A0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x191308, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1603_exfat[] = { + { "nogc", _fs_nogc_1603_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1700[] = { + { KPS(KIP_TEXT) | 0x165100, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x18B048, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1700[] = { + { "nogc", _fs_nogc_1700 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1700_exfat[] = { + { KPS(KIP_TEXT) | 0x16FF60, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x195EA8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1700_exfat[] = { + { "nogc", _fs_nogc_1700_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1800[] = { + { KPS(KIP_TEXT) | 0x164A50, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x18AE48, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1800[] = { + { "nogc", _fs_nogc_1800 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1800_exfat[] = { + { KPS(KIP_TEXT) | 0x16FAE0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x195ED8, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1800_exfat[] = { + { "nogc", _fs_nogc_1800_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1900[] = { + { KPS(KIP_TEXT) | 0x16F070, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x195B74, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { KPS(KIP_TEXT) | 0x195D74, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1900[] = { + { "nogc", _fs_nogc_1900 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_1900_exfat[] = { + { KPS(KIP_TEXT) | 0x17A8A0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1A13A4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { KPS(KIP_TEXT) | 0x1A15A4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_1900_exfat[] = { + { "nogc", _fs_nogc_1900_exfat }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_2000[] = { + { KPS(KIP_TEXT) | 0x17C150, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1A7D24, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { KPS(KIP_TEXT) | 0x1A7F24, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_2000[] = { + { "nogc", _fs_nogc_2000 }, + { NULL, NULL } +}; + +static const kip1_patch_t _fs_nogc_2000_exfat[] = { + { KPS(KIP_TEXT) | 0x187A70, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" }, + { KPS(KIP_TEXT) | 0x1B3644, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" }, + { KPS(KIP_TEXT) | 0x1B3844, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" }, + { 0, 0, NULL, NULL } +}; + +static const kip1_patchset_t _fs_patches_2000_exfat[] = { + { "nogc", _fs_nogc_2000_exfat }, + { NULL, NULL } +}; + +// SHA256 hashes. +static const kip1_id_t _kip_ids[] = +{ + { "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe", _fs_patches_100 }, // FS 1.0.0 + { "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96", _fs_patches_100 }, // FS 1.0.0 exFAT + { "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", _fs_patches_100 }, // FS 2.0.0 + { "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9", _fs_patches_100 }, // FS 2.0.0 exFAT + { "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c", _fs_patches_100 }, // FS 2.1.0 + { "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", _fs_patches_100 }, // FS 2.1.0 exFAT + { "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", _fs_patches_100 }, // FS 3.0.0 + { "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", _fs_patches_100 }, // FS 3.0.0 exFAT + { "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31", _fs_patches_100 }, // FS 3.0.1 + { "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89", _fs_patches_100 }, // FS 3.0.1 exFAT + { "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c", _fs_patches_40x }, // FS 4.0.1 + { "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9", _fs_patches_40x }, // FS 4.0.1 exFAT + { "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82", _fs_patches_410 }, // FS 4.1.0 + { "FS", "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0", _fs_patches_410 }, // FS 4.1.0 exFAT + { "FS", "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad", _fs_patches_50x }, // FS 5.0.0 + { "FS", "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5", _fs_patches_50x }, // FS 5.0.0 exFAT + { "FS", "\x76\xf8\x74\x02\xc9\x38\x7c\x0f", _fs_patches_510 }, // FS 5.1.0 + { "FS", "\x10\xb2\xd8\x16\x05\x48\x85\x99", _fs_patches_510 }, // FS 5.1.0 exFAT + { "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52", _fs_patches_600 }, // FS 6.0.0-4.0 + { "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exFAT + { "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d", _fs_patches_600 }, // FS 6.0.0-5.0 + { "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4", _fs_patches_600_exfat }, // FS 6.0.0-5.0 exFAT + { "FS", "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77", _fs_patches_700 }, // FS 7.0.0 + { "FS", "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E", _fs_patches_700_exfat }, // FS 7.0.0 exFAT + { "FS", "\xB2\xF5\x17\x6B\x35\x48\x36\x4D", _fs_patches_800 }, // FS 8.0.0 + { "FS", "\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", _fs_patches_800_exfat }, // FS 8.0.0 exFAT + { "FS", "\x6B\x09\xB6\x7B\x29\xC0\x20\x24", _fs_patches_800 }, // FS 8.1.0 + { "FS", "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", _fs_patches_800_exfat }, // FS 8.1.0 exFAT + { "FS", "\x46\x87\x40\x76\x1E\x19\x3E\xB7", _fs_patches_900 }, // FS 9.0.0 + { "FS", "\x7C\x95\x13\x76\xE5\xC1\x2D\xF8", _fs_patches_900 }, // FS 9.0.0 exFAT + { "FS", "\xB5\xE7\xA6\x4C\x6F\x5C\x4F\xE3", _fs_patches_910 }, // FS 9.1.0 + { "FS", "\xF1\x96\xD1\x44\xD0\x44\x45\xB6", _fs_patches_910 }, // FS 9.1.0 exFAT + { "FS", "\x3E\xEB\xD9\xB7\xBC\xD1\xB5\xE0", _fs_patches_1000 }, // FS 10.0.0 + { "FS", "\x81\x7E\xA2\xB0\xB7\x02\xC1\xF3", _fs_patches_1000 }, // FS 10.0.0 exFAT + { "FS", "\xA9\x52\xB6\x57\xAD\xF9\xC2\xBA", _fs_patches_1020 }, // FS 10.2.0 + { "FS", "\x16\x0D\x3E\x10\x4E\xAD\x61\x76", _fs_patches_1020 }, // FS 10.2.0 exFAT + { "FS", "\xE3\x99\x15\x6E\x84\x4E\xB0\xAA", _fs_patches_1100 }, // FS 11.0.0 + { "FS", "\x0B\xA1\x5B\xB3\x04\xB5\x05\x63", _fs_patches_1100 }, // FS 11.0.0 exFAT + { "FS", "\xDC\x2A\x08\x49\x96\xBB\x3C\x01", _fs_patches_1200 }, // FS 12.0.0 + { "FS", "\xD5\xA5\xBF\x36\x64\x0C\x49\xEA", _fs_patches_1200 }, // FS 12.0.0 exFAT + { "FS", "\xC8\x67\x62\xBE\x19\xA5\x1F\xA0", _fs_patches_1203 }, // FS 12.0.3 + { "FS", "\xE1\xE8\xD3\xD6\xA2\xFE\x0B\x10", _fs_patches_1203 }, // FS 12.0.3 exFAT + { "FS", "\x7D\x20\x05\x47\x17\x8A\x83\x6A", _fs_patches_1300 }, // FS 13.0.0 + { "FS", "\x51\xEB\xFA\x9C\xCF\x66\xC0\x9E", _fs_patches_1300 }, // FS 13.0.0 exFAT + { "FS", "\x91\xBA\x65\xA2\x1C\x1D\x50\xAE", _fs_patches_1310 }, // FS 13.1.0 + { "FS", "\x76\x38\x27\xEE\x9C\x20\x7E\x5B", _fs_patches_1310 }, // FS 13.1.0 exFAT + { "FS", "\x88\x7A\xC1\x50\x80\x6C\x75\xCC", _fs_patches_1400 }, // FS 14.0.0 + { "FS", "\xD4\x88\xD1\xF2\x92\x17\x35\x5C", _fs_patches_1400_exfat }, // FS 14.0.0 exFAT + { "FS", "\xD0\xD4\x49\x18\x14\xB5\x62\xAF", _fs_patches_1500 }, // FS 15.0.0 + { "FS", "\x34\xC0\xD9\xED\x6A\xD1\x87\x3D", _fs_patches_1500_exfat }, // FS 15.0.0 exFAT + { "FS", "\x56\xE8\x56\x56\x6C\x38\xD8\xBE", _fs_patches_1600 }, // FS 16.0.0 + { "FS", "\xCF\xAB\x45\x0C\x2C\x53\x9D\xA9", _fs_patches_1600_exfat }, // FS 16.0.0 exFAT + { "FS", "\x39\xEE\x1F\x1E\x0E\xA7\x32\x5D", _fs_patches_1603 }, // FS 16.0.3 + { "FS", "\x62\xC6\x5E\xFD\x9A\xBF\x7C\x43", _fs_patches_1603_exfat }, // FS 16.0.3 exFAT + { "FS", "\x27\x07\x3B\xF0\xA1\xB8\xCE\x61", _fs_patches_1700 }, // FS 17.0.0 + { "FS", "\xEE\x0F\x4B\xAC\x6D\x1F\xFC\x4B", _fs_patches_1700_exfat }, // FS 17.0.0 exFAT + { "FS", "\x79\x5F\x5A\x5E\xB0\xC6\x77\x9E", _fs_patches_1800 }, // FS 18.0.0 + { "FS", "\x1E\x2C\x64\xB1\xCC\xE2\x78\x24", _fs_patches_1800_exfat }, // FS 18.0.0 exFAT + { "FS", "\xA3\x39\xF0\x1C\x95\xBF\xA7\x68", _fs_patches_1800 }, // FS 18.1.0 + { "FS", "\x20\x4C\xBA\x86\xDE\x08\x44\x6A", _fs_patches_1800_exfat }, // FS 18.1.0 exFAT + { "FS", "\xD9\x4C\x68\x15\xF8\xF5\x0A\x20", _fs_patches_1900 }, // FS 19.0.0 + { "FS", "\xED\xA8\x78\x68\xA4\x49\x07\x50", _fs_patches_1900_exfat }, // FS 19.0.0 exFAT + { "FS", "\x63\x54\x96\x9E\x60\xA7\x97\x7B", _fs_patches_2000 }, // FS 20.0.0 + { "FS", "\x47\x41\x07\x10\x65\x4F\xA4\x3F", _fs_patches_2000_exfat }, // FS 20.0.0 exFAT + { "FS", "\xED\x34\xB4\x50\x58\x4A\x5B\x43", _fs_patches_2000 }, // FS 20.1.0 + { "FS", "\xA5\x1A\xA4\x92\x6C\x41\x87\x59", _fs_patches_2000_exfat }, // FS 20.1.0 exFAT +}; diff --git a/bootloader/hos/pkg3.c b/bootloader/hos/pkg3.c new file mode 100644 index 0000000..6752063 --- /dev/null +++ b/bootloader/hos/pkg3.c @@ -0,0 +1,282 @@ +/* + * Atmosphère Package 3 parser. + * + * Copyright (c) 2019-2025 CTCaer + * + * 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 + +#include "pkg3.h" +#include "hos.h" +#include "../config.h" +#include +#include "../storage/emummc.h" + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +extern hekate_config h_cfg; + +extern bool is_ipl_updated(void *buf, const char *path, bool force); + +#define PKG3_KIP_SKIP_MAX 16 + +// PKG3 Magic and Meta header offset. +#define PKG3_MAGIC 0x30535346 // FSS0. +#define PKG3_META_OFFSET 0x4 +#define PKG3_VERSION_0_17_0 0x110000 + +// PKG3 Content Types. +#define CNT_TYPE_FSP 0 +#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor). +#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw). +#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw). +#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader). +#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys). +#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition). +#define CNT_TYPE_BMP 7 +#define CNT_TYPE_EMC 8 +#define CNT_TYPE_KLD 9 // Kernel Loader. +#define CNT_TYPE_KRN 10 // Kernel. +#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload. +#define CNT_TYPE_TKG 12 // Tsec Keygen. + +// PKG3 Content Flags. +#define CNT_FLAG0_EXPERIMENTAL BIT(0) + +// PKG3 Meta Header. +typedef struct _pkg3_meta_t +{ + u32 magic; + u32 size; + u32 crt0_off; + u32 cnt_off; + u32 cnt_count; + u32 hos_ver; + u32 version; + u32 git_rev; +} pkg3_meta_t; + +// PKG3 Content Header. +typedef struct _pkg3_content_t +{ + u32 offset; + u32 size; + u8 type; + u8 flags0; + u8 flags1; + u8 flags2; + u32 rsvd1; + char name[0x10]; +} pkg3_content_t; + +static void _pkg3_update_r2p() +{ + u8 *r2p_payload = sd_file_read("atmosphere/reboot_payload.bin", NULL); + + is_ipl_updated(r2p_payload, "atmosphere/reboot_payload.bin", h_cfg.updater2p ? true : false); + + free(r2p_payload); +} + +static int _pkg3_kip1_skip(char ***pkg3_kip1_skip, u32 *pkg3_kip1_skip_num, char *value) +{ + int len = strlen(value); + if (!len || (*pkg3_kip1_skip_num) >= PKG3_KIP_SKIP_MAX) + return 0; + + // Allocate pointer list memory. + if (!(*pkg3_kip1_skip)) + (*pkg3_kip1_skip) = calloc(PKG3_KIP_SKIP_MAX, sizeof(char *)); + + // Set first kip name. + (*pkg3_kip1_skip)[(*pkg3_kip1_skip_num)++] = value; + + // Check if more names are set separated by comma. + for (char *c = value; *c != 0; c++) + { + if (*c == ',') + { + *c = 0; // Null termination. + + // Set next kip name to the list. + (*pkg3_kip1_skip)[(*pkg3_kip1_skip_num)++] = c + 1; + + if ((*pkg3_kip1_skip_num) >= PKG3_KIP_SKIP_MAX) + return 0; + } + } + + return 1; +} + +int parse_pkg3(launch_ctxt_t *ctxt, const char *path) +{ + FIL fp; + + char **pkg3_kip1_skip = NULL; + u32 pkg3_kip1_skip_num = 0; + + bool stock = false; + bool experimental = false; + + // Skip if stock and Exosphere and warmboot are not needed. + bool pkg1_old = ctxt->pkg1_id->kb <= HOS_KB_VERSION_620; // Should check if t210b01? + bool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) + { + if (!strcmp("stock", kv->key)) + if (kv->val[0] == '1') + stock = true; + + if (!strcmp("pkg3ex", kv->key)) + if (kv->val[0] == '1') + experimental = true; + + if (!strcmp("pkg3kip1skip", kv->key)) + _pkg3_kip1_skip(&pkg3_kip1_skip, &pkg3_kip1_skip_num, kv->val); + } + +#ifdef HOS_MARIKO_STOCK_SECMON + if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01)) + return 1; +#else + if (stock && emummc_disabled && pkg1_old) + return 1; +#endif + + // Try to open PKG3. + if (f_open(&fp, path, FA_READ) != FR_OK) + return 0; + + void *pkg3 = malloc(f_size(&fp)); + + // Read first 1024 bytes of the PKG3 file. + f_read(&fp, pkg3, 1024, NULL); + + // Get PKG3 Meta header offset. + u32 pkg3_meta_addr = *(u32 *)(pkg3 + PKG3_META_OFFSET); + pkg3_meta_t *pkg3_meta = (pkg3_meta_t *)(pkg3 + pkg3_meta_addr); + + // Check if valid PKG3 and parse it. + if (pkg3_meta->magic == PKG3_MAGIC) + { + gfx_printf("Atmosphere %d.%d.%d-%08x via PKG3\n" + "Max HOS: %d.%d.%d\n" + "Unpacking.. ", + pkg3_meta->version >> 24, (pkg3_meta->version >> 16) & 0xFF, (pkg3_meta->version >> 8) & 0xFF, pkg3_meta->git_rev, + pkg3_meta->hos_ver >> 24, (pkg3_meta->hos_ver >> 16) & 0xFF, (pkg3_meta->hos_ver >> 8) & 0xFF); + + ctxt->patch_krn_proc_id = true; + ctxt->pkg3_hosver = pkg3_meta->hos_ver; + + // Parse PKG3 contents. + pkg3_content_t *curr_pkg3_cnt = (pkg3_content_t *)(pkg3 + pkg3_meta->cnt_off); + void *content; + for (u32 i = 0; i < pkg3_meta->cnt_count; i++) + { + content = (void *)(pkg3 + curr_pkg3_cnt[i].offset); + + // Check if offset is inside limits. + if ((curr_pkg3_cnt[i].offset + curr_pkg3_cnt[i].size) > pkg3_meta->size) + continue; + + // If content is experimental and experimental config is not enabled, skip it. + if ((curr_pkg3_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !experimental) + continue; + + // Prepare content. + switch (curr_pkg3_cnt[i].type) + { + case CNT_TYPE_KIP: + if (stock) + continue; + + bool should_skip = false; + for (u32 k = 0; k < pkg3_kip1_skip_num; k++) + { + if (!strcmp(curr_pkg3_cnt[i].name, pkg3_kip1_skip[k])) + { + gfx_printf("Skipped %s.kip1 from PKG3\n", curr_pkg3_cnt[i].name); + should_skip = true; + break; + } + } + if (should_skip) + continue; + + merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); + mkip1->kip1 = content; + list_append(&ctxt->kip1_list, &mkip1->link); + DPRINTF("Loaded %s.kip1 from PKG3 (size %08X)\n", curr_pkg3_cnt[i].name, curr_pkg3_cnt[i].size); + break; + + case CNT_TYPE_KRN: + if (stock) + continue; + ctxt->kernel_size = curr_pkg3_cnt[i].size; + ctxt->kernel = content; + break; + + case CNT_TYPE_EXO: + ctxt->secmon_size = curr_pkg3_cnt[i].size; + ctxt->secmon = content; + break; + + case CNT_TYPE_EXF: + ctxt->exofatal_size = curr_pkg3_cnt[i].size; + ctxt->exofatal = content; + break; + + case CNT_TYPE_WBT: + if (h_cfg.t210b01) + continue; + ctxt->warmboot_size = curr_pkg3_cnt[i].size; + ctxt->warmboot = content; + break; + + default: + continue; + } + + // Load content to launch context. + f_lseek(&fp, curr_pkg3_cnt[i].offset); + f_read(&fp, content, curr_pkg3_cnt[i].size, NULL); + } + + gfx_printf("Done!\n"); + f_close(&fp); + + ctxt->pkg3 = pkg3; + + // Update r2p if needed. + _pkg3_update_r2p(); + + free(pkg3_kip1_skip); + + return 1; + } + + // Failed. Close and free all. + f_close(&fp); + + free(pkg3_kip1_skip); + free(pkg3); + + return 0; +} diff --git a/bootloader/utils/dirlist.h b/bootloader/hos/pkg3.h similarity index 80% rename from bootloader/utils/dirlist.h rename to bootloader/hos/pkg3.h index 4fb9af7..8d230ab 100644 --- a/bootloader/utils/dirlist.h +++ b/bootloader/hos/pkg3.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 CTCaer + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,6 +14,11 @@ * along with this program. If not, see . */ -#include "../utils/types.h" +#ifndef _PKG3_H_ +#define _PKG3_H_ -char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles); +#include "hos.h" + +int parse_pkg3(launch_ctxt_t *ctxt, const char *path); + +#endif diff --git a/bootloader/hos/secmon_exo.c b/bootloader/hos/secmon_exo.c index 0baa851..5b2d9f1 100644 --- a/bootloader/hos/secmon_exo.c +++ b/bootloader/hos/secmon_exo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * Copyright (c) 2019 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it @@ -18,24 +18,15 @@ #include #include +#include + #include "hos.h" -#include "../config/config.h" -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../soc/fuse.h" +#include "../config.h" +#include #include "../storage/emummc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/util.h" -#include "../utils/types.h" extern hekate_config h_cfg; -extern bool sd_mount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); - enum emuMMC_Type { emuMMC_None = 0, @@ -81,8 +72,12 @@ typedef struct _exo_cfg_t { u32 magic; u32 fwno; - u32 flags; - u32 reserved[5]; + u32 flags[2]; + u16 display_id; + u8 uart_port; + u8 uart_invert; + u32 uart_baudrate; + u32 rsvd1[2]; exo_emummc_config_t emummc_cfg; } exo_cfg_t; @@ -121,94 +116,204 @@ typedef struct _atm_fatal_error_ctx u64 stack_dump_size; u64 stack_trace[0x20]; u8 stack_dump[0x100]; + u8 tls[0x100]; } atm_fatal_error_ctx; #define ATM_FATAL_ERR_CTX_ADDR 0x4003E000 -#define ATM_FATAL_MAGIC 0x31454641 // AFE1 +#define ATM_FATAL_MAGIC 0x30454641 // AFE0 -#define ATM_WB_HEADER_OFF 0x244 -#define ATM_WB_MAGIC 0x30544257 +#define ATM_EXO_FATAL_ADDR 0x80020000 +#define ATM_EXO_FATAL_SIZE SZ_128K + +#define ATM_WB_HEADER_OFF 0x244 +#define ATM_WB_MAGIC 0x30544257 // WBT0 // Exosphère mailbox defines. -#define EXO_CFG_ADDR 0x8000F000 -#define EXO_MAGIC_VAL 0x304F5845 -#define EXO_FLAG_DBG_PRIV (1 << 1) -#define EXO_FLAG_DBG_USER (1 << 2) -#define EXO_FLAG_NO_USER_EXC (1 << 3) -#define EXO_FLAG_USER_PMU (1 << 4) +#define EXO_CFG_ADDR 0x8000F000 +#define EXO_MAGIC_VAL 0x304F5845 +#define EXO_FLAG_DBG_PRIV BIT(1) +#define EXO_FLAG_DBG_USER BIT(2) +#define EXO_FLAG_NO_USER_EXC BIT(3) +#define EXO_FLAG_USER_PMU BIT(4) +#define EXO_FLAG_CAL0_BLANKING BIT(5) +#define EXO_FLAG_CAL0_WRITES_SYS BIT(6) +#define EXO_FLAG_ENABLE_USB3 BIT(7) -void config_exosphere(launch_ctxt_t *ctxt) +#define EXO_FW_VER(mj, mn) (((mj) << 24) | ((mn) << 16)) + +void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base) { - u32 exoFwNo = 0; - u32 exoFlags = 0; - u32 kb = ctxt->pkg1_id->kb; + u32 exo_fw_no; + u32 exo_flags = 0; + bool usb3_force = false; + bool user_debug = false; + bool cal0_blanking = false; + bool cal0_allow_writes_sys = false; memset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t)); volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR; - switch (kb) + //! TODO: Replace current HOS version decoding (as it's bound to break in the future). + + // Old exosphere target versioning. + if (ctxt->pkg1_id->kb >= HOS_KB_VERSION_1210) // 12.1.0+ + exo_fw_no = ctxt->pkg1_id->kb + 4; + else if (ctxt->pkg1_id->fuses <= 3 || ctxt->pkg1_id->fuses >= 10) // 1.0.0 - 3.0.0, 8.1.0 - 12.0.3. + exo_fw_no = ctxt->pkg1_id->fuses; + else + exo_fw_no = ctxt->pkg1_id->fuses - 1; // 3.0.1 - 7.0.1, 8.0.x. + + // Handle versions that change API and do not burn new fuse. + if (!memcmp(ctxt->pkg1_id->id, "20190314", 8) || // 8.0.x, same fuses with 7.0.1. + !memcmp(ctxt->pkg1_id->id, "20210129", 8) // 12.0.0, same fuses with 11.0.0. + ) + exo_fw_no++; + + // Set 12.1.0 specific revision. + if (ctxt->pkg1_id->kb == HOS_KB_VERSION_1210) + ctxt->exo_ctx.hos_revision = 1; + + // Feed old exosphere target versioning to new. + switch (exo_fw_no) { - case KB_FIRMWARE_VERSION_100_200: - if (!strcmp(ctxt->pkg1_id->id, "20161121183008")) - exoFwNo = 1; - else - exoFwNo = 2; + case 1 ... 4: + case 6: + exo_fw_no = EXO_FW_VER(exo_fw_no, 0); break; - case KB_FIRMWARE_VERSION_300: - exoFwNo = 3; + case 5: + exo_fw_no = EXO_FW_VER(5, ctxt->exo_ctx.hos_revision); break; - default: - exoFwNo = kb + 1; - if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810)) - exoFwNo++; // ATM_TARGET_FW_800/810/900. + case 7: + exo_fw_no = EXO_FW_VER(6, 2); + break; + case 8 ... 9: + exo_fw_no = EXO_FW_VER(exo_fw_no - 1, 0); + break; + case 10: + exo_fw_no = EXO_FW_VER(8, 1); + break; + case 11: + exo_fw_no = EXO_FW_VER(9, 0); + break; + case 12: + exo_fw_no = EXO_FW_VER(9, 1); + break; + case 13 ... 23: //!TODO: Update on API changes. 23: 20.0.0. + exo_fw_no = EXO_FW_VER(exo_fw_no - 3, ctxt->exo_ctx.hos_revision); break; } - // To avoid problems, make private debug mode always on if not semi-stock. - if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable)) - exoFlags |= EXO_FLAG_DBG_PRIV; + // Parse exosphere.ini. + if (!ctxt->stock) + { + LIST_INIT(ini_exo_sections); + if (ini_parse(&ini_exo_sections, "exosphere.ini", false)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_exo_sections, link) + { + // Only parse exosphere section. + if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "exosphere")) + continue; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("debugmode_user", kv->key)) + user_debug = atoi(kv->val); + else if (!strcmp("log_port", kv->key)) + exo_cfg->uart_port = atoi(kv->val); + else if (!strcmp("log_inverted", kv->key)) + exo_cfg->uart_invert = atoi(kv->val); + else if (!strcmp("log_baud_rate", kv->key)) + exo_cfg->uart_baudrate = atoi(kv->val); + else if (emu_cfg.enabled && !h_cfg.emummc_force_disable) + { + if (!strcmp("blank_prodinfo_emummc", kv->key)) + cal0_blanking = atoi(kv->val); + } + else + { + if (!strcmp("blank_prodinfo_sysmmc", kv->key)) + cal0_blanking = atoi(kv->val); + else if (!strcmp("allow_writing_to_cal_sysmmc", kv->key)) + cal0_allow_writes_sys = atoi(kv->val); + } + } + break; + } + } + + // Parse usb mtim settings. Avoid parsing if it's overridden. + if (!ctxt->exo_ctx.usb3_force) + { + LIST_INIT(ini_sys_sections); + if (ini_parse(&ini_sys_sections, "atmosphere/config/system_settings.ini", false)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sys_sections, link) + { + // Only parse usb section. + if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "usb")) + continue; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("usb30_force_enabled", kv->key)) + { + usb3_force = !strcmp("u8!0x1", kv->val); + break; // Only parse usb30_force_enabled key. + } + } + break; + } + } + } + } + + // Private debug mode always on for CFW mode. + if (!ctxt->stock) + exo_flags |= EXO_FLAG_DBG_PRIV; + + // Enable user debug. + if (user_debug) + exo_flags |= EXO_FLAG_DBG_USER; // Disable proper failure handling. - if (ctxt->exo_no_user_exceptions) - exoFlags |= EXO_FLAG_NO_USER_EXC; + if (ctxt->exo_ctx.no_user_exceptions) + exo_flags |= EXO_FLAG_NO_USER_EXC; // Enable user access to PMU. - if (ctxt->exo_user_pmu) - exoFlags |= EXO_FLAG_USER_PMU; + if (ctxt->exo_ctx.user_pmu) + exo_flags |= EXO_FLAG_USER_PMU; + + // Enable USB 3.0. Check if system_settings ini value is overridden. If not, check if enabled in ini. + if ((ctxt->exo_ctx.usb3_force && *ctxt->exo_ctx.usb3_force) + || (!ctxt->exo_ctx.usb3_force && usb3_force)) + exo_flags |= EXO_FLAG_ENABLE_USB3; + + // Enable prodinfo blanking. Check if exo ini value is overridden. If not, check if enabled in exo ini. + if ((ctxt->exo_ctx.cal0_blank && *ctxt->exo_ctx.cal0_blank) + || (!ctxt->exo_ctx.cal0_blank && cal0_blanking)) + exo_flags |= EXO_FLAG_CAL0_BLANKING; + + // Allow prodinfo writes. Check if exo ini value is overridden. If not, check if enabled in exo ini. + if ((ctxt->exo_ctx.cal0_allow_writes_sys && *ctxt->exo_ctx.cal0_allow_writes_sys) + || (!ctxt->exo_ctx.cal0_allow_writes_sys && cal0_allow_writes_sys)) + exo_flags |= EXO_FLAG_CAL0_WRITES_SYS; // Set mailbox values. exo_cfg->magic = EXO_MAGIC_VAL; - - exo_cfg->fwno = exoFwNo; - - exo_cfg->flags = exoFlags; + exo_cfg->fwno = exo_fw_no; + exo_cfg->flags[0] = exo_flags; // If warmboot is lp0fw, add in RSA modulus. - volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(ctxt->pkg1_id->warmboot_base + ATM_WB_HEADER_OFF); + volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(warmboot_base + ATM_WB_HEADER_OFF); if (wb_cfg->magic == ATM_WB_MAGIC) { - wb_cfg->fwno = exoFwNo; - - sdmmc_storage_t storage; - sdmmc_t sdmmc; + wb_cfg->fwno = exo_fw_no; // Set warmboot binary rsa modulus. - u8 *rsa_mod = (u8 *)malloc(512); - - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 1, 1, rsa_mod); - sdmmc_storage_end(&storage); - - // Patch AutoRCM out. - if ((fuse_read_odm(4) & 3) != 3) - rsa_mod[0x10] = 0xF7; - else - rsa_mod[0x10] = 0x37; - - memcpy((void *)(ctxt->pkg1_id->warmboot_base + 0x10), rsa_mod + 0x10, 0x100); + pkg1_warmboot_rsa_mod(warmboot_base); } if (emu_cfg.enabled && !h_cfg.emummc_force_disable) @@ -223,13 +328,32 @@ void config_exosphere(launch_ctxt_t *ctxt) else strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path); - if (emu_cfg.nintendo_path && !ctxt->stock) + if (!ctxt->stock && emu_cfg.nintendo_path && emu_cfg.nintendo_path[0]) strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path); - else if (ctxt->stock) - strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo"); else - exo_cfg->emummc_cfg.nintendo_path[0] = 0; + strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo"); } + + // Copy over exosphere fatal for Mariko. + if (h_cfg.t210b01) + { + memset((void *)ATM_EXO_FATAL_ADDR, 0, ATM_EXO_FATAL_SIZE); + if (ctxt->exofatal) + memcpy((void *)ATM_EXO_FATAL_ADDR, ctxt->exofatal, ctxt->exofatal_size); + + // Set display id. + exo_cfg->display_id = display_get_decoded_panel_id(); + } + +#ifdef DEBUG_UART_PORT + // Ovverride logging parameters if set in compile time. + if (!ctxt->stock) + { + exo_cfg->uart_port = DEBUG_UART_PORT; + exo_cfg->uart_invert = DEBUG_UART_INVERT; + exo_cfg->uart_baudrate = DEBUG_UART_BAUDRATE; + } +#endif } static const char *get_error_desc(u32 error_desc) @@ -237,65 +361,76 @@ static const char *get_error_desc(u32 error_desc) switch (error_desc) { case 0x100: - return "Instruction Abort"; + return "IABRT"; // Instruction Abort. case 0x101: - return "Data Abort"; + return "DABRT"; // Data Abort. case 0x102: - return "PC Misalignment"; + return "IUA"; // Instruction Unaligned Access. case 0x103: - return "SP Misalignment"; + return "DUA"; // Data Unaligned Access. case 0x104: - return "Trap"; + return "UDF"; // Undefined Instruction. case 0x106: - return "SError"; + return "SYS"; // System Error. case 0x301: - return "Bad SVC"; + return "SVC"; // Bad arguments or unimplemented SVC. + case 0xF00: + return "KRNL"; // Kernel panic. + case 0xFFD: + return "SO"; // Stack Overflow. case 0xFFE: - return "std::abort()"; + return "std::abort"; default: - return "Unknown"; + return "UNK"; } } +#define HOS_PID_BOOT2 0x8 + void secmon_exo_check_panic() { volatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR; - if (rpt->magic != ATM_FATAL_MAGIC) + // Mask magic to maintain compatibility with any AFE version, thanks to additive struct members. + if ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC) return; gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); WPRINTF("Panic occurred while running Atmosphere.\n\n"); - WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id); - WPRINTFARGS("Error Desc: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc); + WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id); + WPRINTFARGS("Error: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc); + + // Check if mixed atmosphere sysmodules. + if ((u32)rpt->title_id == HOS_PID_BOOT2) + WPRINTF("Mismatched Atmosphere files?\n"); // Save context to the SD card. char filepath[0x40]; f_mkdir("atmosphere/fatal_errors"); - strcpy(filepath, "/atmosphere/fatal_errors/report_"); + strcpy(filepath, "atmosphere/fatal_errors/report_"); itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16); itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16); strcat(filepath, ".bin"); - sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath); - - gfx_con.fntsz = 8; - WPRINTFARGS("Report saved to %s\n", filepath); + if (!sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath)) + { + gfx_con.fntsz = 8; + WPRINTFARGS("Report saved to %s\n", filepath); + gfx_con.fntsz = 16; + } // Change magic to invalid, to prevent double-display of error/bootlooping. - rpt->magic = 0x0; + rpt->magic = 0; - gfx_con.fntsz = 16; gfx_printf("\n\nPress POWER to continue.\n"); display_backlight_brightness(100, 1000); msleep(1000); - u32 btn = btn_wait(); - while (!(btn & BTN_POWER)) - btn = btn_wait(); + while (!(btn_wait() & BTN_POWER)) + ; display_backlight_brightness(0, 1000); gfx_con_setpos(0, 0); diff --git a/bootloader/hos/secmon_exo.h b/bootloader/hos/secmon_exo.h index 2ff0ee3..a5b494b 100644 --- a/bootloader/hos/secmon_exo.h +++ b/bootloader/hos/secmon_exo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,9 +17,9 @@ #ifndef _SECMON_EXO_H_ #define _SECMON_EXO_H_ -#include "../utils/types.h" +#include -void config_exosphere(launch_ctxt_t *ctxt); +void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base); void secmon_exo_check_panic(); #endif diff --git a/bootloader/hos/sept.c b/bootloader/hos/sept.c deleted file mode 100644 index f37019e..0000000 --- a/bootloader/hos/sept.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 "fss.h" -#include "sept.h" -#include "../config/config.h" -#include "../gfx/di.h" -#include "../ianos/ianos.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../soc/hw_init.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../storage/emummc.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/types.h" - -#include "../gfx/gfx.h" - -#define RELOC_META_OFF 0x7C -#define PATCHED_RELOC_SZ 0x94 - -#define WB_RST_ADDR 0x40010ED0 -#define WB_RST_SIZE 0x30 - -u8 warmboot_reboot[] = { - 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 - 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 - 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0xFE, 0xFF, 0xFF, 0xEA, // LOOP - 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 - 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 -}; - -#define SEPT_PRI_ADDR 0x4003F000 - -#define SEPT_PK1T_ADDR 0xC0400000 -#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) -#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) -#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) -#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) - -extern boot_cfg_t b_cfg; -extern hekate_config h_cfg; -extern const volatile ipl_ver_meta_t ipl_ver; - -extern void *sd_file_read(char *path); -extern bool sd_mount(); -extern void sd_unmount(); -extern bool is_ipl_updated(void *buf); -extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); - -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; - -void check_sept(ini_sec_t *cfg_sec) -{ - // Check if non-hekate payload is used for sept and restore it. - if (h_cfg.sept_run) - { - if (!f_stat("sept/payload.bak", NULL)) - { - f_unlink("sept/payload.bin"); - f_rename("sept/payload.bak", "sept/payload.bin"); - } - - return; - } - - u8 *pkg1 = (u8 *)calloc(1, 0x40000); - - sdmmc_storage_t storage; - sdmmc_t sdmmc; - int res = emummc_storage_init_mmc(&storage, &sdmmc); - if (res) - { - if (res == 2) - EPRINTF("Failed to init eMMC"); - else - EPRINTF("Failed to init emuMMC"); - - goto out_free; - } - - emummc_storage_set_mmc_partition(&storage, 1); - - // Read package1. - emummc_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_con.fntsz = 16; - EPRINTF("Unknown pkg1 version."); - goto out_free; - } - - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) - { - sdmmc_storage_end(&storage); - reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec); - } - -out_free: - free(pkg1); - sdmmc_storage_end(&storage); -} - -int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec) -{ - FIL fp; - bool fss0_sept_used = false; - - // Copy warmboot reboot code and TSEC fw. - u32 tsec_fw_size = 0x3000; - if (kb > KB_FIRMWARE_VERSION_700) - tsec_fw_size = 0x3300; - memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); - memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size); - *(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size; - - if (cfg_sec) - { - fss0_sept_t sept_ctxt; - sept_ctxt.kb = kb; - sept_ctxt.cfg_sec = cfg_sec; - sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR; - sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR; - - fss0_sept_used = load_sept_from_ffs0(&sept_ctxt); - } - - if (!fss0_sept_used) - { - // Copy sept-primary. - if (f_open(&fp, "sept/sept-primary.bin", FA_READ)) - goto error; - - if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - // Copy sept-secondary. - if (kb < KB_FIRMWARE_VERSION_810) - { - if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ)) - if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. - goto error; - } - else - { - if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ)) - goto error; - } - - if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - } - - b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN); - - bool update_sept_payload = true; - if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE)) - { - ipl_ver_meta_t tmp_ver; - f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t)); - f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL); - - if (tmp_ver.magic == ipl_ver.magic) - { - if (tmp_ver.version == ipl_ver.version) - { - // Save auto boot config to sept payload, if any. - boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); - memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t)); - f_lseek(&fp, PATCHED_RELOC_SZ); - f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); - f_close(&fp); - update_sept_payload = false; - } - } - else - f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload. - - f_close(&fp); - } - - if (update_sept_payload) - { - volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); - f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS); - f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL); - f_close(&fp); - } - - sd_unmount(); - - u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); - - void (*sept)() = (void *)pk1t_sept; - - reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); - - // Patch SDRAM init to perform an SVC immediately after second write. - PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; - PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; - // Set SVC handler to jump to sept-primary in IRAM. - PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; - PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - - reconfig_hw_workaround(false, 0); - - (*sept)(); - -error: - gfx_con.mute = false; - EPRINTF("Failed to run sept\n"); - - btn_wait(); - - return 0; -} \ No newline at end of file diff --git a/bootloader/ianos/ianos.h b/bootloader/ianos/ianos.h deleted file mode 100644 index 74d02c1..0000000 --- a/bootloader/ianos/ianos.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018 M4xw - * Copyright (c) 2018 CTCaer - * - * 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 IANOS_H -#define IANOS_H - -#include "../utils/types.h" - -typedef enum -{ - DRAM_LIB = 0, // DRAM library. - EXEC_ELF = 1, // Executable elf that does not return. - DR64_LIB = 2, // AARCH64 DRAM library. - AR64_ELF = 3, // Executable elf that does not return. - KEEP_IN_RAM = (1 << 31) // Shared library mask. -} elfType_t; - -uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config); - -#endif \ No newline at end of file diff --git a/bootloader/l4t/l4t.c b/bootloader/l4t/l4t.c new file mode 100644 index 0000000..5c84825 --- /dev/null +++ b/bootloader/l4t/l4t.c @@ -0,0 +1,1188 @@ +/* + * L4T Loader for Tegra X1 + * + * Copyright (c) 2020-2025 CTCaer + * + * 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 +#include + +#include "../hos/hos.h" +#include "../hos/pkg1.h" +#include "l4t.h" +#include "l4t_config.inl" + +/* + * API Revision info + * + * 0: Base. + * 1: SDMMC1 LA programming for SDMMC1 UHS DDR200. + * 2: Arachne Register Cell v1. + * 3: Arachne Register Cell v2. PTSA Rework support. + * 4: Arachne Register Cell v3. DRAM OPT and DDR200 changes. + * 5: Arachne Register Cell v4. DRAM FREQ and DDR200 changes. + * 6: Arachne Register Cell v5. Signal quality and performance changes. TZ param changes. + * 7: Arachne Register Cell v6. Decouple of rd/wr latencies. + */ + +#define L4T_LOADER_API_REV 7 +#define L4T_FIRMWARE_REV 0x37524556 // REV7. + +#ifdef DEBUG_UART_PORT + #include + #define UPRINTF(...) uart_printf(__VA_ARGS__) +#else + #define UPRINTF(...) +#endif + +#if CARVEOUT_NVDEC_TSEC_ENABLE && CARVEOUT_SECFW_ENABLE +#error "NVDEC and SECFW carveouts can't be used together!" +#endif + +#if CARVEOUT_NVDEC_TSEC_ENABLE + #define TZDRAM_SIZE_CFG SZ_8M +#else + #define TZDRAM_SIZE_CFG SZ_1M +#endif + +// TZDRAM addresses and sizes. +#define TZDRAM_SIZE TZDRAM_SIZE_CFG // Secure Element. +#define TZDRAM_BASE (0xFFFFFFFF - TZDRAM_SIZE + 1) // 0xFFF00000 or 0xFF800000. +#define TZDRAM_COLD_ENTRY (TZDRAM_BASE) +#define TZDRAM_WARM_ENTRY (TZDRAM_BASE + 0x200) +#define TZ_PARAM_SIZE SZ_4K +#define TZ_PARAM_BASE (0xFFFFFFFF - TZ_PARAM_SIZE + 1) // 0xFFFFF000. + +// Carveout sizes. +#define CARVEOUT_NVDEC_SIZE SZ_1M +#define CARVEOUT_TSEC_SIZE SZ_1M +#define CARVEOUT_SECFW_SIZE SZ_1M +#define CARVEOUT_GPUFW_SIZE SZ_256K +#if CARVEOUT_NVDEC_TSEC_ENABLE + #define CARVEOUT_GPUWPR_SIZE CARVEOUT_GPUWPR_SIZE_CFG +#else + #define CARVEOUT_GPUWPR_SIZE (SZ_512K + SZ_256K) +#endif + +#define SC7ENTRY_HDR_SIZE 0x400 + +// Always start 1MB below TZDRAM for Secure Firmware or NVDEC. +#define GEN_CARVEOUT_TOP (TZDRAM_BASE - SZ_1M) + +// NVDEC and SECFW bases. +#define NVDFW_BASE GEN_CARVEOUT_TOP // 0xFF700000. +#define SECFW_BASE GEN_CARVEOUT_TOP // 0xFFE00000. + +// Secure Elements addresses for T210. +#define SC7ENTRY_HDR_BASE (SECFW_BASE + 0) +#define SC7ENTRY_BASE (SECFW_BASE + SC7ENTRY_HDR_SIZE) // After header. +#define SC7EXIT_BASE (SECFW_BASE + SZ_64K) // 64KB after SECFW_BASE. +#define R2P_PAYLOAD_BASE (SECFW_BASE + SZ_256K) // 256KB after SECFW_BASE. +#define MTCTABLE_BASE (SECFW_BASE + SZ_512K) // 512KB after SECFW_BASE. +#define BPMPFW_BASE (SECFW_BASE + SZ_512K + SZ_256K) // 768KB after SECFW_BASE. +#define BPMPFW_ENTRYPOINT (BPMPFW_BASE + 0x100) // Used internally also. + +// Secure Elements addresses for T210B01. +#define BPMPFW_B01_BASE (SECFW_BASE) // !! DTS carveout-start must match !! +#define BPMPFW_B01_ENTRYPOINT (BPMPFW_B01_BASE + 0x40) // Used internally also. +#define BPMPFW_B01_HEAP_BASE (BPMPFW_B01_BASE + SZ_256K - SZ_1K) // 255KB after BPMPFW_B01_BASE. +#define BPMPFW_B01_EDTB_BASE (BPMPFW_B01_BASE + SZ_1M - 0) // Top BPMPFW carveout minus EMC DTB size. +#define BPMPFW_B01_ADTB_BASE (BPMPFW_B01_BASE + 0x26008) // Attached BPMP-FW DTB address. +#define SC7EXIT_B01_BASE (BPMPFW_B01_HEAP_BASE - SZ_4K) // 4KB before BPMP heap. + +// BPMP-FW defines. Offsets are 0xD8 below real main binary. +#define BPMPFW_B01_DTB_ADDR (BPMPFW_B01_BASE + 0x14) // u32. DTB address if not attached. +#define BPMPFW_B01_CC_INIT_OP (BPMPFW_B01_BASE + 0x17324) // u8. Initial table training OP. 0: OP_SWITCH, 1: OP_TRAIN, 2: OP_TRAIN_SWITCH. Default: OP_TRAIN. +#define BPMPFW_B01_LOGLEVEL (BPMPFW_B01_BASE + 0x2547C) // u32. Log level. Default 3. +#define BPMPFW_B01_LOGLEVEL (BPMPFW_B01_BASE + 0x2547C) // u32. Log level. Default 3. +#define BPMPFW_B01_CC_PT_TIME (BPMPFW_B01_BASE + 0x25644) // u32. Periodic training period (in ms). Default 100 ms. +#define BPMPFW_B01_CC_DEBUG (BPMPFW_B01_BASE + 0x257F8) // u32. EMC Clock Change debug mask. Default: 0x50000101. + +// BPMP-FW attached DTB defines. Can be generalized. +#define BPMPFW_B01_DTB_EMC_ENTRIES 4 +#define BPMPFW_B01_DTB_SERIAL_PORT_VAL (BPMPFW_B01_ADTB_BASE + 0x5B) // u8. DTB UART port offset. 0: Disabled. +#define BPMPFW_B01_DTB_SET_SERIAL_PORT(port) (*(u8 *)BPMPFW_B01_DTB_SERIAL_PORT_VAL = port) +#define BPMPFW_B01_DTB_EMC_TBL_OFF (BPMPFW_B01_ADTB_BASE + 0xA0) +#define BPMPFW_B01_DTB_EMC_TBL_SZ 0x1120 +#define BPMPFW_B01_DTB_EMC_NAME_VAL 0xA +#define BPMPFW_B01_DTB_EMC_ENABLE_OFF 0x20 +#define BPMPFW_B01_DTB_EMC_VALUES_OFF 0x4C +#define BPMPFW_B01_DTB_EMC_FREQ_VAL 0x8C +#define BPMPFW_B01_DTB_EMC_OPT_VAL 0xEDC +#define BPMPFW_B01_DTB_EMC_TBL_START(idx) (BPMPFW_B01_DTB_EMC_TBL_OFF + BPMPFW_B01_DTB_EMC_TBL_SZ * (idx)) +#define BPMPFW_B01_DTB_EMC_TBL_SET_VAL(idx, off, val) (*(u32 *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + (off)) = (val)) +#define BPMPFW_B01_DTB_EMC_TBL_SET_FREQ(idx, freq) (*(u32 *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_FREQ_VAL) = (freq)) +#define BPMPFW_B01_DTB_EMC_TBL_SET_OPTC(idx, opt) (*(u32 *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_OPT_VAL) = (opt)) +#define BPMPFW_B01_DTB_EMC_TBL_SET_NAME(idx, name) (strcpy((char *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_NAME_VAL), (name))) +#define BPMPFW_B01_DTB_EMC_TBL_ENABLE(idx) (*(char *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_ENABLE_OFF) = 'n') +#define BPMPFW_B01_DTB_EMC_TBL_OFFSET(idx) ((void *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_VALUES_OFF)) + +// MTC table defines for T210B01. +#define BPMPFW_B01_MTC_TABLE_BASE 0xA0000000 +#define BPMPFW_B01_MTC_FREQ_TABLE_SIZE 4300 +#define BPMPFW_B01_MTC_TABLE_SIZE (BPMPFW_B01_MTC_FREQ_TABLE_SIZE * 3) +#define BPMPFW_B01_MTC_TABLE(idx) (BPMPFW_B01_MTC_TABLE_BASE + BPMPFW_B01_MTC_TABLE_SIZE * (idx)) +#define BPMPFW_B01_MTC_TABLE_OFFSET(idx, fidx) ((void *)(BPMPFW_B01_MTC_TABLE(idx) + BPMPFW_B01_MTC_FREQ_TABLE_SIZE * (fidx))) + +// BL31 Enable IRAM based config. +#define BL31_IRAM_PARAMS 0x4D415249 // "IRAM". +#define BL31_EXTRA_FEATURES_ENABLE 0x52545845 // "EXTR". + +// BL31 Flags. +#define FLAGS_PMC_NON_SECURE BIT(0) +#define FLAGS_SC7_NO_BASE_RESTRICTION BIT(1) + +// BL31 config. +#define PARAM_EP 1 +#define PARAM_BL31 3 +#define PARAM_EP_SECURE 0 +#define PARAM_EP_NON_SECURE 1 +#define VERSION_1 1 +#define SPSR_EL2T BIT(3) + +// BL33 config. +#define BL33_LOAD_BASE 0xAA000000 // DTB is loaded at 0xA8000000, so 32MB above. +#define BL33_ENV_BASE (BL33_LOAD_BASE - SZ_256K) // Before BL33_LOAD_BASE. +#define BL33_ENV_MAGIC_OFFSET (BL33_ENV_BASE - 4) +#define BL33_ENV_MAGIC 0x33334C42 +#define BL33_DTB_OFFSET (BL33_LOAD_BASE + 0x10) // After code end. +#define BL33_DTB_BASE (BL33_LOAD_BASE + *(u32 *)BL33_DTB_OFFSET) +#define BL33_DTB_UART_STATUS 0x1C94 +#define BL33_DTB_UART_STS_OF 0x12C +#define BL33_DTB_STDOUT_PATH 0x3F34 +#define BL33_DTB_STDERR_PATH 0x3F54 +#define BL33_DTB_SET_UART_STATUS(port) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_UART_STATUS + (port - 1) * BL33_DTB_UART_STS_OF), "okay")) +#define BL33_DTB_SET_STDOUT_PATH(path) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_STDOUT_PATH), (path))) +#define BL33_DTB_SET_STDERR_PATH(path) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_STDERR_PATH), (path))) + +// Misc. +#define DTB_MAGIC 0xEDFE0DD0 // D00DFEED. +#define FALCON_DMA_PAGE_SIZE 0x100 +#define ACR_GSC3_ENABLE_MAGIC 0xC0EDBBCC +#define SOC_ID_T210 0x210 +#define SOC_ID_T210B01 0x214 +#define SKU_NX 0x83 +#define HDCP22 2 + +typedef struct _tsec_init_t { + u32 sku; + u32 hdcp; + u32 soc; +} tsec_init_t; + +typedef struct _param_header { + u8 type; // type of the structure. + u8 version; // version of this structure. + u16 size; // size of this structure in bytes. + u32 attr; // attributes: unused bits SBZ. +} param_header_t; + +typedef struct _aapcs64_params { + u64 x0; + u64 x1; + u64 x2; + u64 x3; + u64 x4; + u64 x5; + u64 x6; + u64 x7; +} aapcs64_params_t; + +typedef struct _entry_point_info { + param_header_t hdr; + u64 pc; + u32 spsr; + u32 align0; // Alignment to u64 for the above member. + aapcs64_params_t args; +} entry_point_info_t; + +typedef struct _image_info { + param_header_t hdr; + u64 image_base; // physical address of base of image. + u32 image_size; // bytes read from image file. + u32 image_max_size; +} image_info_t; + +typedef struct _bl_v1_params { + param_header_t hdr; + u64 bl31_image_info; + u64 bl32_ep_info; + u64 bl32_image_info; + u64 bl33_ep_info; + u64 bl33_image_info; +} bl31_v1_params_t; + +typedef struct _plat_params_from_bl2 { + // TZDRAM. + u64 tzdram_size; + u64 tzdram_base; + + s32 uart_id; // UART port ID. + s32 l2_ecc_parity_prot_dis; // L2 ECC parity protection disable flag. + u64 boot_profiler_shmem_base; // SHMEM base address for storing the boot logs. + + // SC7-Entry firmware. + u64 sc7entry_fw_size; + u64 sc7entry_fw_base; + + s32 enable_ccplex_lock_step; // Enable dual execution. + + // Enable below features. + s32 enable_extra_features; + + // MTC table. + u64 emc_table_size; + u64 emc_table_base; + + // Initial R2P payload. + u64 r2p_payload_size; + u64 r2p_payload_base; + + u64 flags; // Platform flags. +} bl31_plat_params_from_bl2_t; + +typedef struct _l4t_fw_t +{ + u32 addr; + char *name; +} l4t_fw_t; + +typedef struct _l4t_ctxt_t +{ + char *path; + + char *ram_oc_txt; + int ram_oc_freq; + int ram_oc_vdd2; + int ram_oc_vddq; + int ram_oc_opt; + + u32 serial_port; + u32 sld_type; + + u32 sc7entry_size; + + emc_table_t *mtc_table; + + bl31_v1_params_t bl31_v1_params; + bl31_plat_params_from_bl2_t bl31_plat_params; + entry_point_info_t bl33_ep_info; +} l4t_ctxt_t; + +#define DRAM_VDD2_OC_MIN_VOLTAGE 1050 +#define DRAM_VDD2_OC_MAX_VOLTAGE 1175 +#define DRAM_VDD2Q_OC_MAX_VOLTAGE 1237 +#define DRAM_VDDQ_OC_MIN_VOLTAGE 550 +#define DRAM_VDDQ_OC_MAX_VOLTAGE 650 +#define DRAM_T210B01_TBL_MAX_FREQ 1600000 + +#define NA 0 // Default to 0 for incorrect dram ids. + +//!TODO: Update on dram config changes. +static const u8 mtc_table_idx_t210b01[] = { +/* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 */ + NA, NA, NA, 7, NA, 7, 7, NA, 0, 1, 2, 3, 0, 1, 2, 3, NA, 4, 5, 4, 8, 8, 8, 5, 4, 6, 6, 6, 5, 9, 9, 9, 10, 10, 10 +}; + +#undef NA + +static const l4t_fw_t l4t_fw[] = { + { TZDRAM_BASE, "bl31.bin" }, + { BL33_LOAD_BASE, "bl33.bin" }, + { SC7ENTRY_BASE, "sc7entry.bin" }, + { SC7EXIT_BASE, "sc7exit.bin" }, + { SC7EXIT_B01_BASE, "sc7exit_b01.bin" }, //!TODO: Update on fuse burns. + { BPMPFW_BASE, "bpmpfw.bin" }, + { BPMPFW_B01_BASE, "bpmpfw_b01.bin" }, + { BPMPFW_B01_MTC_TABLE_BASE, "mtc_tbl_b01.bin" }, +}; + +enum { + BL31_FW = 0, + BL33_FW = 1, + SC7ENTRY_FW = 2, + SC7EXIT_FW = 3, + SC7EXIT_B01_FW = 4, + BPMPFW_FW = 5, + BPMPFW_B01_FW = 6, + BPMPFW_B01_MTC_TBL = 7 +}; + +static void _l4t_crit_error(const char *text, bool needs_update) +{ + gfx_con.mute = false; + gfx_printf("%kL4T Error: %s!%sFailed to launch L4T!\n%k", + TXT_CLR_ERROR, text, needs_update ? "\nUpdate bootloader folder!\n\n" : "\n\n", TXT_CLR_DEFAULT); +} + +char *sd_path; +u32 sd_path_len; +static int _l4t_sd_load(u32 idx) +{ + FIL fp; + void *load_address = (void *)l4t_fw[idx].addr; + + if (idx == SC7EXIT_B01_FW) + load_address -= sizeof(u32); + + strcpy(sd_path + sd_path_len, l4t_fw[idx].name); + + if (f_open(&fp, sd_path, FA_READ) != FR_OK) + return 0; + + u32 size = f_size(&fp); + if (f_read(&fp, load_address, size, NULL) != FR_OK) + size = 0; + + f_close(&fp); + + u32 rev = *(u32 *)(load_address + size - sizeof(u32)); + if (idx >= SC7ENTRY_FW && rev != L4T_FIRMWARE_REV) + return 0; + + return size; +} + +static void _l4t_sdram_lp0_save_params(bool t210b01) +{ + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + +#define _REG_S(base, off) *(u32 *)((base) + (off)) +#define MC_S(off) _REG_S(MC_BASE, off) + +#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(MC_S(param), src_bits, pmc->pmcreg, dst_bits) + +// 32 bits version of s macro. +#define s32(param, pmcreg) pmc->pmcreg = MC_S(param) + + // Only save changed carveout registers into PMC for SC7 Exit. + + // VPR. + s(MC_VIDEO_PROTECT_BOM, 31:20, secure_scratch52, 26:15); + s(MC_VIDEO_PROTECT_SIZE_MB, 11:0, secure_scratch53, 11:0); + if (!t210b01) { + s(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch13, 31:30); + } else { + s(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch14, 31:30); + } + + // TZDRAM. + s(MC_SEC_CARVEOUT_BOM, 31:20, secure_scratch53, 23:12); + s(MC_SEC_CARVEOUT_SIZE_MB, 11:0, secure_scratch54, 11:0); + if (!t210b01) { + s(MC_SEC_CARVEOUT_REG_CTRL, 0:0, secure_scratch18, 30:30); + } else { + s(MC_SEC_CARVEOUT_REG_CTRL, 0:0, secure_scratch19, 29:29); + } + + // NVDEC or SECFW. + s(MC_SECURITY_CARVEOUT1_BOM, 31:17, secure_scratch50, 29:15); + s(MC_SECURITY_CARVEOUT1_SIZE_128KB, 11:0, secure_scratch57, 11:0); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0, secure_scratch59); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1, secure_scratch60); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2, secure_scratch61); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3, secure_scratch62); + if (!t210b01) + { + s(MC_SECURITY_CARVEOUT1_CFG0, 2:0, secure_scratch56, 27:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 6:3, secure_scratch41, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 13:7, secure_scratch42, 31:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 17:14, secure_scratch43, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 21:18, secure_scratch44, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 25:22, secure_scratch56, 31:28); + s(MC_SECURITY_CARVEOUT1_CFG0, 26:26, secure_scratch57, 24:24); + } + else + { + s(MC_SECURITY_CARVEOUT1_CFG0, 1:0, secure_scratch56, 31:30); + s(MC_SECURITY_CARVEOUT1_CFG0, 2:2, secure_scratch57, 24:24); + s(MC_SECURITY_CARVEOUT1_CFG0, 6:3, secure_scratch42, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 10:7, secure_scratch43, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 13:11, secure_scratch42, 31:29); + s(MC_SECURITY_CARVEOUT1_CFG0, 17:14, secure_scratch44, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 21:18, secure_scratch47, 25:22); + s(MC_SECURITY_CARVEOUT1_CFG0, 26:22, secure_scratch57, 29:25); + } + + // GPU FW. + s(MC_SECURITY_CARVEOUT2_BOM, 31:17, secure_scratch51, 29:15); + s(MC_SECURITY_CARVEOUT2_SIZE_128KB, 11:0, secure_scratch56, 23:12); + if (!t210b01) + { + s(MC_SECURITY_CARVEOUT2_CFG0, 2:0, secure_scratch55, 27:25); + s(MC_SECURITY_CARVEOUT2_CFG0, 6:3, secure_scratch19, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 10:7, secure_scratch20, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 13:11, secure_scratch41, 31:29); + s(MC_SECURITY_CARVEOUT2_CFG0, 17:14, secure_scratch39, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 21:18, secure_scratch40, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 25:22, secure_scratch55, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 26:26, secure_scratch56, 24:24); + } + else + { + s(MC_SECURITY_CARVEOUT2_CFG0, 1:0, secure_scratch55, 31:30); + s(MC_SECURITY_CARVEOUT2_CFG0, 2:2, secure_scratch56, 24:24); + s(MC_SECURITY_CARVEOUT2_CFG0, 6:3, secure_scratch20, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 10:7, secure_scratch39, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 13:11, secure_scratch41, 31:29); + s(MC_SECURITY_CARVEOUT2_CFG0, 17:14, secure_scratch40, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 21:18, secure_scratch41, 28:25); + s(MC_SECURITY_CARVEOUT2_CFG0, 26:22, secure_scratch56, 29:25); + } + + // GPU WPR. + s(MC_SECURITY_CARVEOUT3_BOM, 31:17, secure_scratch50, 14:0); + s(MC_SECURITY_CARVEOUT3_SIZE_128KB, 11:0, secure_scratch56, 11:0); + s32(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2, secure_scratch71); + s32(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4, secure_scratch73); + if (!t210b01) + { + s(MC_SECURITY_CARVEOUT3_CFG0, 2:0, secure_scratch57, 27:25); + s(MC_SECURITY_CARVEOUT3_CFG0, 10:3, secure_scratch47, 29:22); + s(MC_SECURITY_CARVEOUT3_CFG0, 13:11, secure_scratch43, 31:29); + s(MC_SECURITY_CARVEOUT3_CFG0, 21:14, secure_scratch48, 29:22); + s(MC_SECURITY_CARVEOUT3_CFG0, 25:22, secure_scratch57, 31:28); + s(MC_SECURITY_CARVEOUT3_CFG0, 26:26, secure_scratch58, 0:0); + } + else + { + s(MC_SECURITY_CARVEOUT3_CFG0, 1:0, secure_scratch57, 31:30); + s(MC_SECURITY_CARVEOUT3_CFG0, 2:2, secure_scratch58, 0:0); + s(MC_SECURITY_CARVEOUT3_CFG0, 6:3, secure_scratch47, 29:26); + s(MC_SECURITY_CARVEOUT3_CFG0, 10:7, secure_scratch48, 25:22); + s(MC_SECURITY_CARVEOUT3_CFG0, 13:11, secure_scratch43, 31:29); + s(MC_SECURITY_CARVEOUT3_CFG0, 17:14, secure_scratch48, 29:26); + s(MC_SECURITY_CARVEOUT3_CFG0, 21:18, secure_scratch52, 30:27); + s(MC_SECURITY_CARVEOUT3_CFG0, 26:22, secure_scratch58, 5:1); + } + + // TSECA. + s(MC_SECURITY_CARVEOUT4_BOM, 31:17, secure_scratch51, 14:0); + s(MC_SECURITY_CARVEOUT4_SIZE_128KB, 11:0, secure_scratch55, 23:12); + s(MC_SECURITY_CARVEOUT4_CFG0, 26:0, secure_scratch39, 26:0); + + // TSECB. + s(MC_SECURITY_CARVEOUT5_BOM, 31:17, secure_scratch52, 14:0); + s(MC_SECURITY_CARVEOUT5_SIZE_128KB, 11:0, secure_scratch57, 23:12); + s(MC_SECURITY_CARVEOUT5_CFG0, 26:0, secure_scratch40, 26:0); +} + +static void _l4t_mc_config_carveout(bool t210b01) +{ + // Disabled VPR carveout. DT decides if enabled or not. + MC(MC_VIDEO_PROTECT_BOM) = 0xFFF00000; + MC(MC_VIDEO_PROTECT_SIZE_MB) = 0; + MC(MC_VIDEO_PROTECT_REG_CTRL) = VPR_CTRL_TZ_SECURE | VPR_CTRL_LOCKED; + + // Temporarily disable TZDRAM carveout. For launching coldboot TZ. + MC(MC_SEC_CARVEOUT_BOM) = 0xFFF00000; + MC(MC_SEC_CARVEOUT_SIZE_MB) = 0; + MC(MC_SEC_CARVEOUT_REG_CTRL) = 0; + + // Print real one, not temp disabled. + UPRINTF("TZD: TZDRAM Carveout: %08X - %08X\n", TZDRAM_BASE, TZDRAM_BASE - 1 + TZDRAM_SIZE); + + // Configure generalized security carveouts. + u32 carveout_base = GEN_CARVEOUT_TOP; + +#if CARVEOUT_NVDEC_TSEC_ENABLE + + // Set NVDEC keyslot sticky bits. + clock_enable_nvdec(); + clock_enable_nvjpg(); + NVDEC(NVDEC_SA_KEYSLOT_GLOBAL_RW) = 0xFFFF; // Read disable. + NVDEC(NVDEC_SA_KEYSLOT_TZ) = 0xFFFFFFFF; // TZ enable. + NVDEC(NVDEC_SA_KEYSLOT_FALCON) = 0; // Falcon disable. + NVDEC(NVDEC_SA_KEYSLOT_OTF) = 0; // OTF disable. + NVDEC(NVDEC_VPR_ALL_OTF_GOTO_VPR) = 1; // Enable. + clock_disable_nvjpg(); + clock_disable_nvdec(); + + // Set NVDEC carveout. Only for NVDEC bl/prod. + carveout_base -= ALIGN(CARVEOUT_NVDEC_SIZE, SZ_1M); + MC(MC_SECURITY_CARVEOUT1_BOM) = carveout_base; + MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = CARVEOUT_NVDEC_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC | SEC_CARVEOUT_CA2_W_TSEC; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = SEC_CARVEOUT_CA3_R_NVDEC | SEC_CARVEOUT_CA3_W_NVDEC; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_RD_FALCON_LS | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(1) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + UPRINTF("GSC1: NVDEC Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT1_BOM), MC(MC_SECURITY_CARVEOUT1_BOM) + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) * SZ_128K); + +#elif CARVEOUT_SECFW_ENABLE + + // Flush data to ram. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + // Set SC7-Entry/SC7-Exit/R2P/MTC Table or SC7-Exit/BPMP-FW carveout. Only BPMP, CCPLEX and AHB have R/W access. + MC(MC_SECURITY_CARVEOUT1_BOM) = carveout_base; + MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = CARVEOUT_SECFW_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = SEC_CARVEOUT_CA0_R_BPMP_C | + SEC_CARVEOUT_CA0_R_PPCSAHBSLV; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = SEC_CARVEOUT_CA1_W_BPMP_C | + SEC_CARVEOUT_CA1_R_CCPLEX_C | + SEC_CARVEOUT_CA1_R_CCPLEXLP_C | + SEC_CARVEOUT_CA1_W_CCPLEX_C | + SEC_CARVEOUT_CA1_W_CCPLEXLP_C | + SEC_CARVEOUT_CA1_W_PPCSAHBSLV; + 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_CFG0) = SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_WR_NS | + SEC_CARVEOUT_CFG_WR_SEC | + SEC_CARVEOUT_CFG_LOCKED; + UPRINTF("GSC1: SECFW Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT1_BOM), MC(MC_SECURITY_CARVEOUT1_BOM) + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) * SZ_128K); + +#endif + + // Set GPU FW WPR carveout. Same value is used for GPU WPR carveout calculation if not full TOS. + carveout_base -= ALIGN(CARVEOUT_GPUFW_SIZE, SZ_1M); + + // Sanitize it and enable GSC3 for ACR. + memset((void *)carveout_base, 0, CARVEOUT_GPUFW_SIZE); + *(u32 *)(carveout_base + CARVEOUT_GPUFW_SIZE - sizeof(u32)) = ACR_GSC3_ENABLE_MAGIC; + + tsec_init_t *tsec_init = (tsec_init_t *)(carveout_base + CARVEOUT_GPUFW_SIZE - FALCON_DMA_PAGE_SIZE); + + // Set TSEC init info. + tsec_init->sku = SKU_NX; + tsec_init->hdcp = HDCP22; + tsec_init->soc = t210b01 ? SOC_ID_T210B01 : SOC_ID_T210; + + // Flush data to ram. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + // Set carveout config. + MC(MC_SECURITY_CARVEOUT2_BOM) = carveout_base; + MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = CARVEOUT_GPUFW_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2; + MC(MC_SECURITY_CARVEOUT2_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_RD_FALCON_LS | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_LS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(2) | + SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; // SEC_CARVEOUT_CFG_IS_WPR is set from GPU. + UPRINTF("GSC2: GPUFW Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT2_BOM), MC(MC_SECURITY_CARVEOUT2_BOM) + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) * SZ_128K); + + // Set GPU WPR carveout. +#if CARVEOUT_NVDEC_TSEC_ENABLE + carveout_base -= ALIGN(CARVEOUT_GPUWPR_SIZE, SZ_1M); + MC(MC_SECURITY_CARVEOUT3_BOM) = carveout_base; +#else + MC(MC_SECURITY_CARVEOUT3_BOM) = carveout_base + CARVEOUT_GPUFW_SIZE; +#endif + MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0x0; + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = CARVEOUT_GPUWPR_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0; // HOS: SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0; // HOS: SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2 + MC(MC_SECURITY_CARVEOUT3_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_RD_FALCON_LS | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_LS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(3) | + SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; // SEC_CARVEOUT_CFG_IS_WPR is set from GPU. + UPRINTF("GSC3: GPUW2 Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT3_BOM), MC(MC_SECURITY_CARVEOUT3_BOM) + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) * SZ_128K); + + /* + * Set TSECA/B carveout. Only for NVDEC bl/prod and TSEC. + * + * Otherwise disabled. + * + * With HOS SC7-Exit fw, it gets set to disallow RAM access for BPMP. But TZ can change it. + * We lock the carveout and save it in restore scratch registers so SC7-Exit can't touch it. + */ + carveout_base -= CARVEOUT_NVDEC_TSEC_ENABLE ? ALIGN(CARVEOUT_TSEC_SIZE, SZ_1M) : 0; + MC(MC_SECURITY_CARVEOUT4_BOM) = CARVEOUT_NVDEC_TSEC_ENABLE ? carveout_base : 0; + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = CARVEOUT_NVDEC_TSEC_ENABLE ? CARVEOUT_TSEC_SIZE / SZ_128K : 0; + MC(MC_SECURITY_CARVEOUT4_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(4) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + + UPRINTF("GSC4: TSEC1 Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT4_BOM), MC(MC_SECURITY_CARVEOUT4_BOM) + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) * SZ_128K); + + // Set TSECA carveout. Only for NVDEC bl/prod and TSEC. Otherwise disabled. + carveout_base -= CARVEOUT_NVDEC_TSEC_ENABLE ? ALIGN(CARVEOUT_TSEC_SIZE, SZ_1M) : 0; + MC(MC_SECURITY_CARVEOUT5_BOM) = CARVEOUT_NVDEC_TSEC_ENABLE ? carveout_base : 0; + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = CARVEOUT_NVDEC_TSEC_ENABLE ? CARVEOUT_TSEC_SIZE / SZ_128K : 0; + MC(MC_SECURITY_CARVEOUT5_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(5) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + UPRINTF("GSC5: TSEC2 Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT5_BOM), MC(MC_SECURITY_CARVEOUT5_BOM) + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) * SZ_128K); + + UPRINTF("DRAM Bank 0 TOP: %08X\n", carveout_base); + + // Save carveouts to lp0 pmc registers. + _l4t_sdram_lp0_save_params(t210b01); +} + +static void _l4t_late_hw_config(bool t210b01) +{ + // Reset System Counters. + for (u32 i = 0; i < SYSCTR0_COUNTERS; i += sizeof(u32)) + SYSCTR0(SYSCTR0_COUNTERS_BASE + i) = 0; + + /* + * PMIC config scratch register + * + * bit00: active cluster slow + * bit01: Set: max77621/max77812. Unset: OVR/OVR2. + * bit02-07: unused + * bit08-15: pmic cpu i2c address + * bit16:23: pmic cpu i2c en reg + * bit24:31: pmic cpu i2c en val + */ + PMC(APBDEV_PMC_SCRATCH201) = BIT(1); + + // Clear PLLM override for SC7. + PMC(APBDEV_PMC_PLLP_WB0_OVERRIDE) &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE_ENABLE; + + // Set spare reg to 0xE0000 and clear everything else. + if (t210b01 && (SYSREG(AHB_AHB_SPARE_REG) & 0xE0000000) != 0xE0000000) + SYSREG(AHB_AHB_SPARE_REG) = 0xE0000 << 12; + + // HDA loopback disable on prod. + PMC(APBDEV_PMC_STICKY_BITS) = PMC_STICKY_BITS_HDA_LPBK_DIS; + + // Clear any MC error. + MC(MC_INTSTATUS) = MC(MC_INTSTATUS); + + +#if LOCK_PMC_REGISTERS + // Lock LP0 parameters and misc secure registers. Always happens on warmboot. + #if CARVEOUT_NVDEC_TSEC_ENABLE + pmc_scratch_lock(PMC_SEC_LOCK_CARVEOUTS_L4T | PMC_SEC_LOCK_SE_SRK); + #else + pmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS | PMC_SEC_LOCK_MISC | PMC_SEC_LOCK_SE_SRK); + #endif + + // Lock SE2 SRK and misc secure regs. Also lock writes on normal LP0 scratch regs. + if (t210b01) + pmc_scratch_lock(PMC_SEC_LOCK_MISC_B01 | PMC_SEC_LOCK_SE2_SRK_B01 | PMC_SEC_LOCK_LP0_PARAMS_B01); +#endif +} + +static void _l4t_bpmpfw_b01_config(l4t_ctxt_t *ctxt) +{ + char *ram_oc_txt = ctxt->ram_oc_txt; + u32 ram_oc_freq = ctxt->ram_oc_freq; + u32 ram_oc_opt = ctxt->ram_oc_opt; + u32 ram_id = fuse_read_dramid(true); + + // Set default parameters. + *(u32 *)BPMPFW_B01_DTB_ADDR = 0; + *(u8 *)BPMPFW_B01_CC_INIT_OP = OP_TRAIN; + *(u32 *)BPMPFW_B01_CC_PT_TIME = 100; + +#if DEBUG_LOG_BPMPFW + // Set default debug parameters. + *(u32 *)BPMPFW_B01_LOGLEVEL = 3; + *(u32 *)BPMPFW_B01_CC_DEBUG = 0x50000101; + + // Set serial debug port. + if (*(u32 *)BPMPFW_B01_ADTB_BASE == DTB_MAGIC) + BPMPFW_B01_DTB_SET_SERIAL_PORT(ctxt->serial_port); +#endif + + // Set and copy MTC tables. + u32 mtc_idx = mtc_table_idx_t210b01[ram_id]; + for (u32 i = 0; i < 3; i++) + { + minerva_sdmmc_la_program(BPMPFW_B01_MTC_TABLE_OFFSET(mtc_idx, i), true); + memcpy(BPMPFW_B01_DTB_EMC_TBL_OFFSET(i), BPMPFW_B01_MTC_TABLE_OFFSET(mtc_idx, i), BPMPFW_B01_MTC_FREQ_TABLE_SIZE); + } + + // Always use Arachne Register Cell (ARC) for setting rated frequencies if no ram_oc is defined. + if (!ram_oc_freq) + { + if (ram_id >= LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ && + ram_id <= LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE) + { + ram_oc_txt = "1866000"; + ram_oc_freq = 1866000; + } + else + { + ram_oc_txt = "2133000"; + ram_oc_freq = 2133000; + } + } + + // Set DRAM voltage. + if (ctxt->ram_oc_vdd2) + max7762x_regulator_set_voltage(REGULATOR_SD1, ctxt->ram_oc_vdd2 * 1000); + if (ctxt->ram_oc_vddq) + max7762x_regulator_set_voltage(REGULATOR_RAM0, ctxt->ram_oc_vddq * 1000); + + // A frequency of lower or equal with stock max will skip ARC. + if (ram_oc_freq > DRAM_T210B01_TBL_MAX_FREQ) + { + // Final table. + const u32 tbl_idx = BPMPFW_B01_DTB_EMC_ENTRIES - 1; + + // Copy table and prep it for Arachne. + memcpy(BPMPFW_B01_DTB_EMC_TBL_OFFSET(tbl_idx), BPMPFW_B01_MTC_TABLE_OFFSET(mtc_idx, 2), BPMPFW_B01_MTC_FREQ_TABLE_SIZE); + + BPMPFW_B01_DTB_EMC_TBL_SET_NAME(tbl_idx, ram_oc_txt); + BPMPFW_B01_DTB_EMC_TBL_SET_FREQ(tbl_idx, ram_oc_freq); + BPMPFW_B01_DTB_EMC_TBL_SET_OPTC(tbl_idx, ram_oc_opt); + + // Enable table. + BPMPFW_B01_DTB_EMC_TBL_ENABLE(tbl_idx); + + UPRINTF("RAM Frequency set to: %d KHz. Voltage: %d mV\n", ram_oc_freq, ctxt->ram_oc_vdd2); + } + + // Save BPMP-FW entrypoint for TZ. + PMC(APBDEV_PMC_SCRATCH39) = BPMPFW_B01_ENTRYPOINT; + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE1) |= BIT(15); +} + +static int _l4t_sc7_exit_config(bool t210b01) +{ + if (!t210b01) + { + // Apply Nintendo Switch (2017) RSA modulus to SC7-Exit firmware. + emmc_initialize(false); + pkg1_warmboot_rsa_mod(SC7EXIT_BASE); + emmc_end(); + + // Set SC7-Exit firmware address for bootrom to find. + PMC(APBDEV_PMC_SCRATCH1) = SC7EXIT_BASE; + } + else + { + launch_ctxt_t hos_ctxt = {0}; + u32 fw_fuses = *(u32 *)(SC7EXIT_B01_BASE - sizeof(u32)); // Fuses count in front of actual firmware. + + // Get latest SC7-Exit if needed and setup PA id. + if (!pkg1_warmboot_config(&hos_ctxt, 0, fw_fuses, 0)) + { + gfx_con.mute = false; + gfx_wputs("\nFailed to match warmboot with fuses!\nIf you continue, sleep wont work!"); + + gfx_puts("\nPress POWER to continue.\nPress VOL to go to the menu.\n"); + + if (!(btn_wait() & BTN_POWER)) + return 0; + } + + // Copy loaded warmboot fw to address if from storage. + if (hos_ctxt.warmboot) + memcpy((void *)SC7EXIT_B01_BASE, hos_ctxt.warmboot, hos_ctxt.warmboot_size); + + // Set SC7-Exit firmware address for bootrom to find. + PMC(APBDEV_PMC_SECURE_SCRATCH119) = SC7EXIT_B01_BASE; + PMC(APBDEV_PMC_SEC_DISABLE8) |= BIT(30); + } + + return 1; +} + +static void _l4t_bl33_cfg_set_key(char *env, const char *key, const char *val) +{ + strcat(env, key); + strcat(env, "="); + strcat(env, val); + strcat(env, "\n"); +} + +static void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01) +{ + char *bl33_env = (char *)BL33_ENV_BASE; + bl33_env[0] = '\0'; + char val[4] = {0}; + + // Set default SLD type. + ctxt->sld_type = BL_MAGIC_L4TLDR_SLD; + + // Parse ini section and prepare BL33 env. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("boot_prefixes", kv->key)) + ctxt->path = kv->val; + else if (!strcmp("ram_oc", kv->key)) + { + ctxt->ram_oc_txt = kv->val; + ctxt->ram_oc_freq = atoi(kv->val); + } + else if (!strcmp("ram_oc_vdd2", kv->key)) + { + ctxt->ram_oc_vdd2 = atoi(kv->val); + + if (t210b01 && ctxt->ram_oc_vdd2 > DRAM_VDD2_OC_MAX_VOLTAGE) + ctxt->ram_oc_vdd2 = DRAM_VDD2_OC_MAX_VOLTAGE; + else if (!t210b01 && ctxt->ram_oc_vdd2 > DRAM_VDD2Q_OC_MAX_VOLTAGE) + ctxt->ram_oc_vdd2 = DRAM_VDD2Q_OC_MAX_VOLTAGE; + else if (ctxt->ram_oc_vdd2 < DRAM_VDD2_OC_MIN_VOLTAGE) + ctxt->ram_oc_vdd2 = DRAM_VDD2_OC_MIN_VOLTAGE; + } + else if (!strcmp("ram_oc_vddq", kv->key)) + { + ctxt->ram_oc_vddq = atoi(kv->val); + if (ctxt->ram_oc_vddq > DRAM_VDDQ_OC_MAX_VOLTAGE) + ctxt->ram_oc_vddq = DRAM_VDDQ_OC_MAX_VOLTAGE; + else if (ctxt->ram_oc_vddq < DRAM_VDDQ_OC_MIN_VOLTAGE) + ctxt->ram_oc_vddq = 0; + } + else if (!strcmp("ram_oc_opt", kv->key)) + ctxt->ram_oc_opt = atoi(kv->val); + else if (!strcmp("uart_port", kv->key)) + ctxt->serial_port = atoi(kv->val); + else if (!strcmp("sld_type", kv->key)) + ctxt->sld_type = strtol(kv->val, NULL, 16); + + // Set key/val to BL33 env. + _l4t_bl33_cfg_set_key(bl33_env, kv->key, kv->val); + } + +#ifdef DEBUG_UART_PORT + // Override port if bootloader UART debug is enabled. + ctxt->serial_port = DEBUG_UART_PORT + 1; +#endif + + // Set r2p parameters. + if (entry_idx >= 10) + { + val[0] = '1'; + val[1] = '0' + (entry_idx % 10); + } + else + val[0] = '0' + entry_idx; + _l4t_bl33_cfg_set_key(bl33_env, "autoboot", val); + + // NULL terminate at single char for the next env sets. + val[1] = 0; + + val[0] = '0' + is_list; + _l4t_bl33_cfg_set_key(bl33_env, "autoboot_list", val); + + val[0] = '0' + L4T_LOADER_API_REV; + _l4t_bl33_cfg_set_key(bl33_env, "loader_rev", val); + + // Enable BL33 memory env import. + *(u32 *)(BL33_ENV_MAGIC_OFFSET) = BL33_ENV_MAGIC; + + // Set boot path. + sd_path = (char *)malloc(512); + sd_path_len = strlen(ctxt->path); + strcpy(sd_path, ctxt->path); +} + +void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01) +{ + l4t_ctxt_t *ctxt = (l4t_ctxt_t *)TZ_PARAM_BASE; + memset(ctxt, 0, TZ_PARAM_SIZE); + + gfx_con_setpos(0, 0); + + // Parse config. + _l4t_set_config(ctxt, ini_sec, entry_idx, is_list, t210b01); + + if (!ctxt->path) + { + _l4t_crit_error("Path missing", false); + return; + } + + // Get MTC table. + ctxt->mtc_table = minerva_get_mtc_table(); + if (!t210b01 && !ctxt->mtc_table) + { + _l4t_crit_error("Minerva missing", true); + return; + } + + // Load BL31 (ATF/TrustZone fw). + if (!_l4t_sd_load(BL31_FW)) + { + _l4t_crit_error("BL31 missing", false); + return; + } + + // Load BL33 (U-BOOT/CBOOT). + if (!_l4t_sd_load(BL33_FW)) + { + _l4t_crit_error("BL33 missing", false); + return; + } + + // Set firmware path. + strcpy(sd_path, "bootloader/sys/l4t/"); + sd_path_len = strlen(sd_path); + + if (!t210b01) + { + // Load SC7-Entry firmware. + ctxt->sc7entry_size = _l4t_sd_load(SC7ENTRY_FW); + if (!ctxt->sc7entry_size) + { + _l4t_crit_error("loading SC7-Entry", true); + return; + } + + // Load BPMP-FW. Does power management. + if (!_l4t_sd_load(BPMPFW_FW)) + { + _l4t_crit_error("loading BPMP-FW", true); + return; + } + } + else + { + // Load BPMP-FW. Manages SC7-Entry also. + if (!_l4t_sd_load(BPMPFW_B01_FW)) + { + _l4t_crit_error("loading BPMP-FW", true); + return; + } + + // Load BPMP-FW MTC table. + if (!_l4t_sd_load(BPMPFW_B01_MTC_TBL)) + { + _l4t_crit_error("loading BPMP-FW MTC", true); + return; + } + } + + // Load SC7-Exit firmware. + if (!_l4t_sd_load(!t210b01 ? SC7EXIT_FW : SC7EXIT_B01_FW)) + { + _l4t_crit_error("loading SC7-Exit", true); + return; + } + + // Set SC7-Exit firmware address to PMC for bootrom and do further setup. + if (!_l4t_sc7_exit_config(t210b01)) + return; + + // Done loading bootloaders/firmware. + sd_end(); + + // We don't need AHB aperture open. + mc_disable_ahb_redirect(); + + // Enable debug port. + if (ctxt->serial_port) + { + pinmux_config_uart(ctxt->serial_port - 1); + clock_enable_uart(ctxt->serial_port - 1); + } + + // Restore UARTB/C TX pins to SPIO. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + // Configure BL33 parameters. + if (*(u32 *)BL33_DTB_BASE == DTB_MAGIC) + { + // Defaults are for UARTA. + char *bl33_serial_port = NULL; + switch (ctxt->serial_port) + { + case 0: // Disable. + break; + case 1: // UARTA. + bl33_serial_port = "70006000"; + break; + case 2: // UARTB. + bl33_serial_port = "70006040"; + break; + case 3: // UARTC. + bl33_serial_port = "70006200"; + break; + } + + if (bl33_serial_port) + { + BL33_DTB_SET_STDOUT_PATH(bl33_serial_port); + BL33_DTB_SET_STDERR_PATH(bl33_serial_port); + BL33_DTB_SET_UART_STATUS(ctxt->serial_port); + } + } + + // Set BL31 params. + ctxt->bl31_v1_params.hdr.type = PARAM_BL31; + ctxt->bl31_v1_params.hdr.version = VERSION_1; + ctxt->bl31_v1_params.hdr.size = sizeof(bl31_v1_params_t); + ctxt->bl31_v1_params.hdr.attr = PARAM_EP_SECURE; + ctxt->bl31_v1_params.bl33_ep_info = (u64)(u32)&ctxt->bl33_ep_info; + + // Set BL33 params. + ctxt->bl33_ep_info.hdr.type = PARAM_EP; + ctxt->bl33_ep_info.hdr.version = VERSION_1; + ctxt->bl33_ep_info.hdr.size = sizeof(entry_point_info_t); + ctxt->bl33_ep_info.hdr.attr = PARAM_EP_NON_SECURE; + ctxt->bl33_ep_info.pc = BL33_LOAD_BASE; + ctxt->bl33_ep_info.spsr = SPSR_EL2T; + + // Set Platform parameters. + ctxt->bl31_plat_params.tzdram_base = TZDRAM_BASE; + ctxt->bl31_plat_params.tzdram_size = TZDRAM_SIZE; +#if DEBUG_LOG_ATF + ctxt->bl31_plat_params.uart_id = ctxt->serial_port; +#endif + + if (!t210b01) + { + // Set SC7-Entry fw parameters. For now BPMP-FW is not used on T210. + ctxt->bl31_plat_params.sc7entry_fw_base = SC7ENTRY_HDR_BASE; + ctxt->bl31_plat_params.sc7entry_fw_size = ALIGN(ctxt->sc7entry_size + SC7ENTRY_HDR_SIZE, SZ_PAGE); + } + + // Enable below features. + ctxt->bl31_plat_params.enable_extra_features = BL31_EXTRA_FEATURES_ENABLE; + + if (!t210b01) + { + // Set R2P payload. + reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + 0x7C); + memcpy((u8 *)R2P_PAYLOAD_BASE, (u8 *)reloc->start, reloc->end - reloc->start); + memset((u8 *)R2P_PAYLOAD_BASE + 0x94, 0, sizeof(boot_cfg_t)); // Clear Boot Config Storage. + + // Set R2P payload fw parameters. + ctxt->bl31_plat_params.r2p_payload_base = R2P_PAYLOAD_BASE; + ctxt->bl31_plat_params.r2p_payload_size = ALIGN(reloc->end - reloc->start, SZ_PAGE); + } + + // Set PMC access security. NS is mandatory for T210B01. + ctxt->bl31_plat_params.flags = FLAGS_PMC_NON_SECURE; // Unsecure it unconditionally to reduce SMC calls to a minimum. + // Lift SC7 placement restrictions. Disables TZDRAM increased carveout too. + ctxt->bl31_plat_params.flags |= FLAGS_SC7_NO_BASE_RESTRICTION; + + // Prepare EMC table. + if (ctxt->mtc_table) + { + // Set DRAM voltage. + if (ctxt->ram_oc_vdd2) + max7762x_regulator_set_voltage(REGULATOR_SD1, ctxt->ram_oc_vdd2 * 1000); + + // Train the rest of the table, apply FSP WAR, set RAM to 800 MHz. + minerva_prep_boot_l4t(ctxt->ram_oc_freq, ctxt->ram_oc_opt); + + // Set emc table parameters and copy it. + int table_entries = minerva_get_mtc_table_entries(); + ctxt->bl31_plat_params.emc_table_base = MTCTABLE_BASE; + ctxt->bl31_plat_params.emc_table_size = sizeof(emc_table_t) * table_entries; + memcpy((u32 *)MTCTABLE_BASE, ctxt->mtc_table, sizeof(emc_table_t) * table_entries); + } + + // Set and enable IRAM based BL31 config. + PMC(APBDEV_PMC_SECURE_SCRATCH112) = PMC(APBDEV_PMC_SECURE_SCRATCH108); + PMC(APBDEV_PMC_SECURE_SCRATCH114) = PMC(APBDEV_PMC_SECURE_SCRATCH109); + PMC(APBDEV_PMC_SECURE_SCRATCH108) = (u32)&ctxt->bl31_v1_params; + PMC(APBDEV_PMC_SECURE_SCRATCH109) = (u32)&ctxt->bl31_plat_params; + PMC(APBDEV_PMC_SECURE_SCRATCH110) = BL31_IRAM_PARAMS; + + // Set panel model. + PMC(APBDEV_PMC_SECURE_SCRATCH113) = display_get_decoded_panel_id(); + + // Set charging limit parameters. + if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG) + { + int in_volt_lim = 0; + bq24193_get_property(BQ24193_ChargeVoltageLimit, &in_volt_lim); + + PMC(APBDEV_PMC_SECURE_SCRATCH113) |= in_volt_lim << 16; + } + + // Disable writes to above registers. + PMC(APBDEV_PMC_SEC_DISABLE8) |= BIT(18) | BIT(16) | BIT(12) | BIT(10) | BIT(8); + + // Set BPMP-FW parameters. + if (t210b01) + _l4t_bpmpfw_b01_config(ctxt); + + // Set carveouts and save them to PMC for SC7 Exit. + _l4t_mc_config_carveout(t210b01); + + // Deinit any unneeded HW. + hw_deinit(false, ctxt->sld_type); + + // Do late hardware config. + _l4t_late_hw_config(t210b01); + + if (t210b01) + { + // Launch BL31. + ccplex_boot_cpu0(TZDRAM_COLD_ENTRY, true); + + // Enable Wrap burst for BPMP, GPU and PCIE. + MSELECT(MSELECT_CONFIG) = (MSELECT(MSELECT_CONFIG) & (~(MSELECT_CFG_ERR_RESP_EN_GPU | MSELECT_CFG_ERR_RESP_EN_PCIE))) | + (MSELECT_CFG_WRAP_TO_INCR_GPU | MSELECT_CFG_WRAP_TO_INCR_PCIE | MSELECT_CFG_WRAP_TO_INCR_BPMP); + + // For T210B01, prep reset vector for SC7 save state and start BPMP-FW. + EXCP_VEC(EVP_COP_RESET_VECTOR) = BPMPFW_B01_ENTRYPOINT; + void (*bpmp_fw_ptr)() = (void *)BPMPFW_B01_ENTRYPOINT; + (*bpmp_fw_ptr)(); + } + else + { + // If T210, BPMP-FW runs BL31. + void (*bpmp_fw_ptr)() = (void *)BPMPFW_ENTRYPOINT; + (*bpmp_fw_ptr)(); + } + + // Halt BPMP. + while (true) + bpmp_halt(); +} diff --git a/nyx/nyx_gui/hos/sept.h b/bootloader/l4t/l4t.h similarity index 77% rename from nyx/nyx_gui/hos/sept.h rename to bootloader/l4t/l4t.h index 7b44c73..9e02ea6 100644 --- a/nyx/nyx_gui/hos/sept.h +++ b/bootloader/l4t/l4t.h @@ -1,5 +1,7 @@ /* - * Copyright (c) 2019 CTCaer + * L4T Loader for Tegra X1 + * + * Copyright (c) 2020-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,12 +16,9 @@ * along with this program. If not, see . */ -#ifndef _SEPT_H_ -#define _SEPT_H_ +#ifndef _L4T_H_ +#define _L4T_H_ -#include "../utils/types.h" - -void check_sept(); -int reboot_to_sept(const u8 *tsec_fw, u32 kb); +void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01); #endif diff --git a/bootloader/l4t/l4t_config.inl b/bootloader/l4t/l4t_config.inl new file mode 100644 index 0000000..0810f13 --- /dev/null +++ b/bootloader/l4t/l4t_config.inl @@ -0,0 +1,36 @@ +/* + * L4T Loader for Tegra X1 + * + * Copyright (c) 2020-2022 CTCaer + * + * 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 . + */ + +// Set to 1 to enable early boot debugging. +#define DEBUG_LOG_ATF 0 +#define DEBUG_LOG_BPMPFW 0 // Do not enable if UART setup is hindered during early boot. + +// Set to 1 to lock PMC registers that contain LP0 parameters. +#define LOCK_PMC_REGISTERS 0 + +// Configurable carveout enable config. Only one can be enabled at a time. +#define CARVEOUT_NVDEC_TSEC_ENABLE 0 // Enable for NVDEC bl/prod and full TOS/DRM. +#define CARVEOUT_SECFW_ENABLE 1 // SECFW is always allocated even if carveout is disabled. + +/* + * WPR Carveout size config. + * + * L4T: 2MB or 13MB. On non SecureOS env, only 0x100 bytes are used, probably also on full TOS. + * On 4GB+ systems, it's normally placed at BANK1_TOP - SIZE; + */ +#define CARVEOUT_GPUWPR_SIZE_CFG (SZ_8M + SZ_4M + SZ_1M) // Mandatory when CARVEOUT_NVDEC_TSEC_ENABLE is 1. diff --git a/bootloader/libs/compr/blz.c b/bootloader/libs/compr/blz.c deleted file mode 100644 index 685ef4a..0000000 --- a/bootloader/libs/compr/blz.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2018 rajkosto - * Copyright (c) 2018 SciresM - * - * 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 - -#include "blz.h" - -const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter) -{ - if (compDataLen < sizeof(blz_footer)) - return NULL; - - const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)]; - if (outFooter != NULL) - memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4. - - return srcFooter; -} - -// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM! -int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) -{ - u32 addl_size = footer->addl_size; - u32 header_size = footer->header_size; - u32 cmp_and_hdr_size = footer->cmp_and_hdr_size; - - unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size; - u32 cmp_ofs = cmp_and_hdr_size - header_size; - u32 out_ofs = cmp_and_hdr_size + addl_size; - - while (out_ofs) - { - unsigned char control = cmp_start[--cmp_ofs]; - for (unsigned int i=0; i<8; i++) - { - if (control & 0x80) - { - if (cmp_ofs < 2) - return 0; // Out of bounds. - - cmp_ofs -= 2; - u16 seg_val = ((unsigned int)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs]; - u32 seg_size = ((seg_val >> 12) & 0xF) + 3; - u32 seg_ofs = (seg_val & 0x0FFF) + 3; - if (out_ofs < seg_size) // Kernel restricts segment copy to stay in bounds. - seg_size = out_ofs; - - out_ofs -= seg_size; - - for (unsigned int j = 0; j < seg_size; j++) - cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; - } - else - { - // Copy directly. - if (cmp_ofs < 1) - return 0; //out of bounds - - cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; - } - control <<= 1; - if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done. - return 1; - } - } - - return 1; -} - -int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize) -{ - blz_footer footer; - const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer); - if (compFooterPtr == NULL) - return 0; - - // Decompression must be done in-place, so need to copy the relevant compressed data first. - unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData; - memcpy(dstData, compData, numCompBytes); - memset(&dstData[numCompBytes], 0, dstSize - numCompBytes); - - return blz_uncompress_inplace(dstData, compDataLen, &footer); -} diff --git a/bootloader/libs/elfload/elf.h b/bootloader/libs/elfload/elf.h deleted file mode 100644 index 196cf87..0000000 --- a/bootloader/libs/elfload/elf.h +++ /dev/null @@ -1,589 +0,0 @@ -/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */ -/* - * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* imported sys/exec_elf.h from OpenBSD */ - -#ifndef ELF_H -#define ELF_H -#include - -typedef uint8_t Elf_Byte; - -typedef uint32_t Elf32_Addr; /* Unsigned program address */ -typedef uint32_t Elf32_Off; /* Unsigned file offset */ -typedef int32_t Elf32_Sword; /* Signed large integer */ -typedef uint32_t Elf32_Word; /* Unsigned large integer */ -typedef uint16_t Elf32_Half; /* Unsigned medium integer */ - -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Shalf; - -#ifdef __alpha__ -typedef int64_t Elf64_Sword; -typedef uint64_t Elf64_Word; -#else -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -#endif - -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Xword; - -typedef uint32_t Elf64_Half; -typedef uint16_t Elf64_Quarter; - -/* - * e_ident[] identification indexes - * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html - */ -#define EI_MAG0 0 /* file ID */ -#define EI_MAG1 1 /* file ID */ -#define EI_MAG2 2 /* file ID */ -#define EI_MAG3 3 /* file ID */ -#define EI_CLASS 4 /* file class */ -#define EI_DATA 5 /* data encoding */ -#define EI_VERSION 6 /* ELF header version */ -#define EI_OSABI 7 /* OS/ABI ID */ -#define EI_ABIVERSION 8 /* ABI version */ -#define EI_PAD 9 /* start of pad bytes */ -#define EI_NIDENT 16 /* Size of e_ident[] */ - -/* e_ident[] magic number */ -#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ -#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ -#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ -#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ -#define ELFMAG "\177ELF" /* magic */ -#define SELFMAG 4 /* size of magic */ - -/* e_ident[] file class */ -#define ELFCLASSNONE 0 /* invalid */ -#define ELFCLASS32 1 /* 32-bit objs */ -#define ELFCLASS64 2 /* 64-bit objs */ -#define ELFCLASSNUM 3 /* number of classes */ - -/* e_ident[] data encoding */ -#define ELFDATANONE 0 /* invalid */ -#define ELFDATA2LSB 1 /* Little-Endian */ -#define ELFDATA2MSB 2 /* Big-Endian */ -#define ELFDATANUM 3 /* number of data encode defines */ - -/* e_ident[] Operating System/ABI */ -#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ -#define ELFOSABI_HPUX 1 /* HP-UX operating system */ -#define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ -#define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_MONTEREY 7 /* Monterey */ -#define ELFOSABI_IRIX 8 /* IRIX */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD */ -#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -/* e_ident */ -#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ - (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ - (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ - (ehdr).e_ident[EI_MAG3] == ELFMAG3) - -/* ELF Header */ -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ - Elf32_Half e_type; /* object file type */ - Elf32_Half e_machine; /* machine */ - Elf32_Word e_version; /* object file version */ - Elf32_Addr e_entry; /* virtual entry point */ - Elf32_Off e_phoff; /* program header table offset */ - Elf32_Off e_shoff; /* section header table offset */ - Elf32_Word e_flags; /* processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size */ - Elf32_Half e_phentsize; /* program header entry size */ - Elf32_Half e_phnum; /* number of program header entries */ - Elf32_Half e_shentsize; /* section header entry size */ - Elf32_Half e_shnum; /* number of section header entries */ - Elf32_Half e_shstrndx; /* section header table's "section - header string table" entry offset */ -} Elf32_Ehdr; - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Id bytes */ - Elf64_Quarter e_type; /* file type */ - Elf64_Quarter e_machine; /* machine type */ - Elf64_Half e_version; /* version number */ - Elf64_Addr e_entry; /* entry point */ - Elf64_Off e_phoff; /* Program hdr offset */ - Elf64_Off e_shoff; /* Section hdr offset */ - Elf64_Half e_flags; /* Processor flags */ - Elf64_Quarter e_ehsize; /* sizeof ehdr */ - Elf64_Quarter e_phentsize; /* Program header entry size */ - Elf64_Quarter e_phnum; /* Number of program headers */ - Elf64_Quarter e_shentsize; /* Section header entry size */ - Elf64_Quarter e_shnum; /* Number of section headers */ - Elf64_Quarter e_shstrndx; /* String table index */ -} Elf64_Ehdr; - -/* e_type */ -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* relocatable file */ -#define ET_EXEC 2 /* executable file */ -#define ET_DYN 3 /* shared object file */ -#define ET_CORE 4 /* core file */ -#define ET_NUM 5 /* number of types */ -#define ET_LOPROC 0xff00 /* reserved range for processor */ -#define ET_HIPROC 0xffff /* specific e_type */ - -/* e_machine */ -#define EM_NONE 0 /* No Machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola 68000 */ -#define EM_88K 5 /* Motorola 88000 */ -#define EM_486 6 /* Intel 80486 - unused? */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ -/* - * Don't know if EM_MIPS_RS4_BE, - * EM_SPARC64, EM_PARISC, - * or EM_PPC are ABI compliant - */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ -#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ -#define EM_PARISC 15 /* HPPA */ -#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ -#define EM_PPC 20 /* PowerPC */ -#define EM_ARM 40 /* ARM AArch32 */ -#define EM_ALPHA 41 /* DEC ALPHA */ -#define EM_SH 42 /* Hitachi/Renesas Super-H */ -#define EM_SPARCV9 43 /* SPARC version 9 */ -#define EM_IA_64 50 /* Intel IA-64 Processor */ -#define EM_AMD64 62 /* AMD64 architecture */ -#define EM_VAX 75 /* DEC VAX */ -#define EM_AARCH64 183 /* ARM AArch64 */ - -/* Non-standard */ -#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ - -/* Version */ -#define EV_NONE 0 /* Invalid */ -#define EV_CURRENT 1 /* Current */ -#define EV_NUM 2 /* number of versions */ - -/* Section Header */ -typedef struct -{ - Elf32_Word sh_name; /* name - index into section header - * string table section */ - Elf32_Word sh_type; /* type */ - Elf32_Word sh_flags; /* flags */ - Elf32_Addr sh_addr; /* address */ - Elf32_Off sh_offset; /* file offset */ - Elf32_Word sh_size; /* section size */ - Elf32_Word sh_link; /* section header table index link */ - Elf32_Word sh_info; /* extra information */ - Elf32_Word sh_addralign; /* address alignment */ - Elf32_Word sh_entsize; /* section entry size */ -} Elf32_Shdr; - -typedef struct -{ - Elf64_Half sh_name; /* section name */ - Elf64_Half sh_type; /* section type */ - Elf64_Xword sh_flags; /* section flags */ - Elf64_Addr sh_addr; /* virtual address */ - Elf64_Off sh_offset; /* file offset */ - Elf64_Xword sh_size; /* section size */ - Elf64_Half sh_link; /* link to another */ - Elf64_Half sh_info; /* misc info */ - Elf64_Xword sh_addralign; /* memory alignment */ - Elf64_Xword sh_entsize; /* table entry size */ -} Elf64_Shdr; - -/* Special Section Indexes */ -#define SHN_UNDEF 0 /* undefined */ -#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ -#define SHN_LOPROC 0xff00 /* reserved range for processor */ -#define SHN_HIPROC 0xff1f /* specific section indexes */ -#define SHN_ABS 0xfff1 /* absolute value */ -#define SHN_COMMON 0xfff2 /* common symbol */ -#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ - -/* sh_type */ -#define SHT_NULL 0 /* inactive */ -#define SHT_PROGBITS 1 /* program defined information */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ -#define SHT_RELA 4 /* relocation section with addends*/ -#define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ -#define SHT_NOTE 7 /* note section */ -#define SHT_NOBITS 8 /* no space section */ -#define SHT_REL 9 /* relation section without addends */ -#define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ -#define SHT_NUM 12 /* number of section types */ -#define SHT_LOPROC 0x70000000 /* reserved range for processor */ -#define SHT_HIPROC 0x7fffffff /* specific section header types */ -#define SHT_LOUSER 0x80000000 /* reserved range for application */ -#define SHT_HIUSER 0xffffffff /* specific indexes */ - -/* Section names */ -#define ELF_BSS ".bss" /* uninitialized data */ -#define ELF_DATA ".data" /* initialized data */ -#define ELF_DEBUG ".debug" /* debug */ -#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ -#define ELF_DYNSTR ".dynstr" /* dynamic string table */ -#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ -#define ELF_FINI ".fini" /* termination code */ -#define ELF_GOT ".got" /* global offset table */ -#define ELF_HASH ".hash" /* symbol hash table */ -#define ELF_INIT ".init" /* initialization code */ -#define ELF_REL_DATA ".rel.data" /* relocation data */ -#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ -#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ -#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ -#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ -#define ELF_REL_TEXT ".rel.text" /* relocation code */ -#define ELF_RODATA ".rodata" /* read-only data */ -#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ -#define ELF_STRTAB ".strtab" /* string table */ -#define ELF_SYMTAB ".symtab" /* symbol table */ -#define ELF_TEXT ".text" /* code */ - -/* Section Attribute Flags - sh_flags */ -#define SHF_WRITE 0x1 /* Writable */ -#define SHF_ALLOC 0x2 /* occupies memory */ -#define SHF_EXECINSTR 0x4 /* executable */ -#define SHF_TLS 0x400 /* thread local storage */ -#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \ - * specific section attributes */ - -/* Symbol Table Entry */ -typedef struct elf32_sym -{ - Elf32_Word st_name; /* name - index into string table */ - Elf32_Addr st_value; /* symbol value */ - Elf32_Word st_size; /* symbol size */ - unsigned char st_info; /* type and binding */ - unsigned char st_other; /* 0 - no defined meaning */ - Elf32_Half st_shndx; /* section header index */ -} Elf32_Sym; - -typedef struct -{ - Elf64_Half st_name; /* Symbol name index in str table */ - Elf_Byte st_info; /* type / binding attrs */ - Elf_Byte st_other; /* unused */ - Elf64_Quarter st_shndx; /* section index of symbol */ - Elf64_Xword st_value; /* value of symbol */ - Elf64_Xword st_size; /* size of symbol */ -} Elf64_Sym; - -/* Symbol table index */ -#define STN_UNDEF 0 /* undefined */ - -/* Extract symbol info - st_info */ -#define ELF32_ST_BIND(x) ((x) >> 4) -#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) - -#define ELF64_ST_BIND(x) ((x) >> 4) -#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) - -/* Symbol Binding - ELF32_ST_BIND - st_info */ -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* like global - lower precedence */ -#define STB_NUM 3 /* number of symbol bindings */ -#define STB_LOPROC 13 /* reserved range for processor */ -#define STB_HIPROC 15 /* specific symbol bindings */ - -/* Symbol type - ELF32_ST_TYPE - st_info */ -#define STT_NOTYPE 0 /* not specified */ -#define STT_OBJECT 1 /* data object */ -#define STT_FUNC 2 /* function */ -#define STT_SECTION 3 /* section */ -#define STT_FILE 4 /* file */ -#define STT_TLS 6 /* thread local storage */ -#define STT_LOPROC 13 /* reserved range for processor */ -#define STT_HIPROC 15 /* specific symbol types */ - -/* Relocation entry with implicit addend */ -typedef struct -{ - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ -} Elf32_Rel; - -/* Relocation entry with explicit addend */ -typedef struct -{ - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ - Elf32_Sword r_addend; -} Elf32_Rela; - -/* Extract relocation info - r_info */ -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) - -typedef struct -{ - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ -} Elf64_Rel; - -typedef struct -{ - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ - Elf64_Sxword r_addend; /* adjustment value */ -} Elf64_Rela; - -#define ELF64_R_SYM(info) ((info) >> 32) -#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF) -#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t)) - -#if defined(__mips64__) && defined(__MIPSEL__) -/* - * The 64-bit MIPS ELF ABI uses a slightly different relocation format - * than the regular ELF ABI: the r_info field is split into several - * pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details). - */ -#undef ELF64_R_SYM -#undef ELF64_R_TYPE -#undef ELF64_R_INFO -#define ELF64_R_TYPE(info) (swap32((info) >> 32)) -#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF) -#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s)) -#endif /* __mips64__ && __MIPSEL__ */ - -/* Program Header */ -typedef struct -{ - Elf32_Word p_type; /* segment type */ - Elf32_Off p_offset; /* segment offset */ - Elf32_Addr p_vaddr; /* virtual address of segment */ - Elf32_Addr p_paddr; /* physical address - ignored? */ - Elf32_Word p_filesz; /* number of bytes in file for seg. */ - Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ - Elf32_Word p_flags; /* flags */ - Elf32_Word p_align; /* memory alignment */ -} Elf32_Phdr; - -typedef struct -{ - Elf64_Half p_type; /* entry type */ - Elf64_Half p_flags; /* flags */ - Elf64_Off p_offset; /* offset */ - Elf64_Addr p_vaddr; /* virtual address */ - Elf64_Addr p_paddr; /* physical address */ - Elf64_Xword p_filesz; /* file size */ - Elf64_Xword p_memsz; /* memory size */ - Elf64_Xword p_align; /* memory & file alignment */ -} Elf64_Phdr; - -/* Segment types - p_type */ -#define PT_NULL 0 /* unused */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking section */ -#define PT_INTERP 3 /* the RTLD */ -#define PT_NOTE 4 /* auxiliary information */ -#define PT_SHLIB 5 /* reserved - purpose undefined */ -#define PT_PHDR 6 /* program header */ -#define PT_TLS 7 /* thread local storage */ -#define PT_LOOS 0x60000000 /* reserved range for OS */ -#define PT_HIOS 0x6fffffff /* specific segment types */ -#define PT_LOPROC 0x70000000 /* reserved range for processor */ -#define PT_HIPROC 0x7fffffff /* specific segment types */ - -#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */ -#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */ - -/* Segment flags - p_flags */ -#define PF_X 0x1 /* Executable */ -#define PF_W 0x2 /* Writable */ -#define PF_R 0x4 /* Readable */ -#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific segment flags */ - -/* Dynamic structure */ -typedef struct -{ - Elf32_Sword d_tag; /* controls meaning of d_val */ - union { - Elf32_Word d_val; /* Multiple meanings - see d_tag */ - Elf32_Addr d_ptr; /* program virtual address */ - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Xword d_tag; /* controls meaning of d_val */ - union { - Elf64_Addr d_ptr; - Elf64_Xword d_val; - } d_un; -} Elf64_Dyn; - -/* Dynamic Array Tags - d_tag */ -#define DT_NULL 0 /* marks end of _DYNAMIC array */ -#define DT_NEEDED 1 /* string table offset of needed lib */ -#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ -#define DT_PLTGOT 3 /* address PLT/GOT */ -#define DT_HASH 4 /* address of symbol hash table */ -#define DT_STRTAB 5 /* address of string table */ -#define DT_SYMTAB 6 /* address of symbol table */ -#define DT_RELA 7 /* address of relocation table */ -#define DT_RELASZ 8 /* size of relocation table */ -#define DT_RELAENT 9 /* size of relocation entry */ -#define DT_STRSZ 10 /* size of string table */ -#define DT_SYMENT 11 /* size of symbol table entry */ -#define DT_INIT 12 /* address of initialization func. */ -#define DT_FINI 13 /* address of termination function */ -#define DT_SONAME 14 /* string table offset of shared obj */ -#define DT_RPATH 15 /* string table offset of library \ - * search path */ -#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ -#define DT_REL 17 /* address of rel. tbl. w addends */ -#define DT_RELSZ 18 /* size of DT_REL relocation table */ -#define DT_RELENT 19 /* size of DT_REL relocation entry */ -#define DT_PLTREL 20 /* PLT referenced relocation entry */ -#define DT_DEBUG 21 /* bugger */ -#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ -#define DT_JMPREL 23 /* add. of PLT's relocation entries */ -#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ -#define DT_LOOS 0x6000000d /* reserved range for OS */ -#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */ -#define DT_LOPROC 0x70000000 /* reserved range for processor */ -#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ - -/* some other useful tags */ -#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */ -#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */ -#define DT_FLAGS_1 0x6ffffffb - -/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ -#define DF_1_NOW 0x00000001 -#define DF_1_GLOBAL 0x00000002 -#define DF_1_GROUP 0x00000004 -#define DF_1_NODELETE 0x00000008 -#define DF_1_LOADFLTR 0x00000010 -#define DF_1_INITFIRST 0x00000020 -#define DF_1_NOOPEN 0x00000040 -#define DF_1_ORIGIN 0x00000080 -#define DF_1_DIRECT 0x00000100 -#define DF_1_TRANS 0x00000200 -#define DF_1_INTERPOSE 0x00000400 -#define DF_1_NODEFLIB 0x00000800 -#define DF_1_NODUMP 0x00001000 -#define DF_1_CONLFAT 0x00002000 - -/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */ -#define DT_NUM (DT_JMPREL + 1) - -/* - * Note Definitions - */ -typedef struct -{ - Elf32_Word namesz; - Elf32_Word descsz; - Elf32_Word type; -} Elf32_Note; - -typedef struct -{ - Elf64_Half namesz; - Elf64_Half descsz; - Elf64_Half type; -} Elf64_Note; - -#if defined(ELFSIZE) && (ELFSIZE == 32) -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Phdr Elf32_Phdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym -#define Elf_Rel Elf32_Rel -#define Elf_RelA Elf32_Rela -#define Elf_Dyn Elf32_Dyn -#define Elf_Half Elf32_Half -#define Elf_Word Elf32_Word -#define Elf_Sword Elf32_Sword -#define Elf_Addr Elf32_Addr -#define Elf_Off Elf32_Off -#define Elf_Nhdr Elf32_Nhdr -#define Elf_Note Elf32_Note - -#define ELF_R_SYM ELF32_R_SYM -#define ELF_R_TYPE ELF32_R_TYPE -#define ELF_R_INFO ELF32_R_INFO -#define ELFCLASS ELFCLASS32 - -#define ELF_ST_BIND ELF32_ST_BIND -#define ELF_ST_TYPE ELF32_ST_TYPE -#define ELF_ST_INFO ELF32_ST_INFO - -#elif defined(ELFSIZE) && (ELFSIZE == 64) - -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Phdr Elf64_Phdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Sym Elf64_Sym -#define Elf_Rel Elf64_Rel -#define Elf_RelA Elf64_Rela -#define Elf_Dyn Elf64_Dyn -#define Elf_Half Elf64_Half -#define Elf_Word Elf64_Word -#define Elf_Sword Elf64_Sword -#define Elf_Addr Elf64_Addr -#define Elf_Off Elf64_Off -#define Elf_Nhdr Elf64_Nhdr -#define Elf_Note Elf64_Note - -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE -#define ELF_R_INFO ELF64_R_INFO -#define ELFCLASS ELFCLASS64 - -#define ELF_ST_BIND ELF64_ST_BIND -#define ELF_ST_TYPE ELF64_ST_TYPE -#define ELF_ST_INFO ELF64_ST_INFO - -#endif - -#endif diff --git a/bootloader/libs/elfload/elfload.h b/bootloader/libs/elfload/elfload.h deleted file mode 100644 index 3a15dc2..0000000 --- a/bootloader/libs/elfload/elfload.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright © 2018, M4xw - * Copyright © 2014, Owen Shepherd - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef ELFLOAD_H -#define ELFLOAD_H -#include - -#include "elfarch.h" -#include "elf.h" - -#include "../../utils/types.h" - -#ifdef DEBUG -#include "../../gfx/gfx.h" -#define EL_DEBUG(format, ...) \ - gfx_printf(format __VA_OPT__(, ) __VA_ARGS__) -#else -#define EL_DEBUG(...) \ - do \ - { \ - } while (0) -#endif - -typedef enum -{ - EL_OK = 0, - - EL_EIO, - EL_ENOMEM, - - EL_NOTELF, - EL_WRONGBITS, - EL_WRONGENDIAN, - EL_WRONGARCH, - EL_WRONGOS, - EL_NOTEXEC, - EL_NODYN, - EL_BADREL, - -} el_status; - -typedef struct el_ctx -{ - bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset); - - /* base_load_* -> address we are actually going to load at - */ - Elf_Addr - base_load_paddr, - base_load_vaddr; - - /* size in memory of binary */ - Elf_Addr memsz; - - /* required alignment */ - Elf_Addr align; - - /* ELF header */ - Elf_Ehdr ehdr; - - // Section Header Str Table - Elf_Shdr shstr; - Elf_Shdr symtab; - - /* Offset of dynamic table (0 if not ET_DYN) */ - Elf_Off dynoff; - /* Size of dynamic table (0 if not ET_DYN) */ - Elf_Addr dynsize; -} el_ctx; - -el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset); - -el_status el_init(el_ctx *ctx); -typedef void *(*el_alloc_cb)( - el_ctx *ctx, - Elf_Addr phys, - Elf_Addr virt, - Elf_Addr size); - -el_status el_load(el_ctx *ctx, el_alloc_cb alloccb); - -/* find the next phdr of type \p type, starting at \p *i. - * On success, returns EL_OK with *i set to the phdr number, and the phdr loaded - * in *phdr. - * - * If the end of the phdrs table was reached, *i is set to -1 and the contents - * of *phdr are undefined - */ -el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i); - -/* Relocate the loaded executable */ -el_status el_relocate(el_ctx *ctx); - -/* find a dynamic table entry - * returns the entry on success, dyn->d_tag = DT_NULL on failure - */ -el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type); - -typedef struct -{ - Elf_Off tableoff; - Elf_Addr tablesize; - Elf_Addr entrysize; -} el_relocinfo; - -/* find all information regarding relocations of a specific type. - * - * pass DT_REL or DT_RELA for type - * sets ri->entrysize = 0 if not found - */ -el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type); - -#endif diff --git a/bootloader/libs/elfload/elfreloc_aarch64.c b/bootloader/libs/elfload/elfreloc_aarch64.c deleted file mode 100644 index bbb0ce4..0000000 --- a/bootloader/libs/elfload/elfreloc_aarch64.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © 2014, Owen Shepherd - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "elfload.h" - -#if defined(__aarch64__) - -#define R_AARCH64_NONE 0 -#define R_AARCH64_RELATIVE 1027 - -el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel) -{ - uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); - uint32_t type = ELF_R_TYPE(rel->r_info); - uint32_t sym = ELF_R_SYM(rel->r_info); - - switch (type) - { - case R_AARCH64_NONE: - EL_DEBUG("R_AARCH64_NONE\n"); - break; - case R_AARCH64_RELATIVE: - if (sym) - { - EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); - return EL_BADREL; - } - - EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); - *p = rel->r_addend + ctx->base_load_vaddr; - break; - - default: - EL_DEBUG("Bad relocation %u\n", type); - return EL_BADREL; - } - - return EL_OK; -} - -el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) -{ - uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); - uint32_t type = ELF_R_TYPE(rel->r_info); - uint32_t sym = ELF_R_SYM(rel->r_info); - - switch (type) - { - case R_AARCH64_NONE: - EL_DEBUG("R_AARCH64_NONE\n"); - break; - case R_AARCH64_RELATIVE: - if (sym) - { - EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); - return EL_BADREL; - } - - EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); - *p += ctx->base_load_vaddr; - break; - - default: - EL_DEBUG("Bad relocation %u\n", type); - return EL_BADREL; - } - - return EL_OK; -} - -#endif diff --git a/bootloader/libs/elfload/elfreloc_arm.c b/bootloader/libs/elfload/elfreloc_arm.c deleted file mode 100644 index 8b905cb..0000000 --- a/bootloader/libs/elfload/elfreloc_arm.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * wrote this file. As long as you retain this notice you can do - * whatever you want with this stuff. If we meet some day, and you think this - * stuff is worth it, you can buy me a beer in return. M4xw - * ---------------------------------------------------------------------------- - */ - -#include "elfload.h" - -#if defined(__arm__) - -// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf -#define R_ARM_NONE 0 -#define R_ARM_ABS32 2 -#define R_ARM_JUMP_SLOT 22 -#define R_ARM_GLOB_DAT 21 -#define R_ARM_RELATIVE 23 - -el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) -{ - uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset - uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type - uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr - -#if 0 // For later symbol usage - Elf32_Sym *elfSym; - const char *symbolName; - - // We resolve relocs from the originating elf-image - elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym; - int strtab_offset = ctx->shstr.sh_offset; - char *strtab = (char *)buffteg + strtab_offset; - symbolName = strtab + elfSym->st_name; - //EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value); -#endif - - switch (type) - { - case R_ARM_NONE: - EL_DEBUG("R_ARM_NONE\n"); - break; - case R_ARM_JUMP_SLOT: - case R_ARM_ABS32: - case R_ARM_GLOB_DAT: - // Stubbed for later purpose - //*p += elfSym->st_value; // + vaddr from sec - //*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now - break; - case R_ARM_RELATIVE: // Needed for PIE - if (sym) - { - return EL_BADREL; - } - *p += ctx->base_load_vaddr; - break; - - default: - return EL_BADREL; - } - - return EL_OK; -} - -#endif diff --git a/bootloader/libs/fatfs/diskio.c b/bootloader/libs/fatfs/diskio.c index 803dc91..d207d96 100644 --- a/bootloader/libs/fatfs/diskio.c +++ b/bootloader/libs/fatfs/diskio.c @@ -9,12 +9,9 @@ #include -#include "../../../common/memory_map.h" +#include -#include "diskio.h" /* FatFs lower layer API */ -#include "../../storage/sdmmc.h" - -extern sdmmc_storage_t sd_storage; +#include /* FatFs lower layer API */ /*-----------------------------------------------------------------------*/ /* Get Drive Status */ @@ -46,16 +43,7 @@ DRESULT disk_read ( UINT count /* Number of sectors to read */ ) { - // Ensure that buffer resides in DRAM and it's DMA aligned. - if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) - return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - if (sdmmc_storage_read(&sd_storage, sector, count, buf)) - { - memcpy(buff, buf, 512 * count); - return RES_OK; - } - return RES_ERROR; + return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; } /*-----------------------------------------------------------------------*/ @@ -68,14 +56,7 @@ DRESULT disk_write ( UINT count /* Number of sectors to write */ ) { - // Ensure that buffer resides in DRAM and it's DMA aligned. - if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) - return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - memcpy(buf, buff, 512 * count); - if (sdmmc_storage_write(&sd_storage, sector, count, buf)) - return RES_OK; - return RES_ERROR; + return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; } /*-----------------------------------------------------------------------*/ diff --git a/bootloader/libs/fatfs/diskio.h b/bootloader/libs/fatfs/diskio.h deleted file mode 100644 index d6ae8f8..0000000 --- a/bootloader/libs/fatfs/diskio.h +++ /dev/null @@ -1,79 +0,0 @@ -/*-----------------------------------------------------------------------/ -/ Low level disk interface modlue include file (C)ChaN, 2014 / -/-----------------------------------------------------------------------*/ - -#ifndef _DISKIO_DEFINED -#define _DISKIO_DEFINED - -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../utils/types.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 FF_FS_READONLY == 0) */ -#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ -#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ -#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ -#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_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/bootloader/libs/fatfs/ff.c b/bootloader/libs/fatfs/ff.c deleted file mode 100644 index c3e2ab9..0000000 --- a/bootloader/libs/fatfs/ff.c +++ /dev/null @@ -1,6649 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * - * 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 . - */ - -/*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.13c (p4) / -/-----------------------------------------------------------------------------/ -/ -/ Copyright (C) 2018, 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 */ -#include "../../gfx/gfx.h" - -#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); -//#define EFSPRINTF(...) - -/*-------------------------------------------------------------------------- - - Module Private Definitions - ----------------------------------------------------------------------------*/ - -#if FF_DEFINED != 86604 /* Revision ID */ -#error Wrong include file (ff.h). -#endif - - -/* 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) */ - - -/* 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 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 */ - - -/* 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 */ - - -/* 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 */ - - -/* exFAT directory entry types */ -#define ET_BITMAP 0x81 /* Allocation bitmap */ -#define ET_UPCASE 0x82 /* Up-case table */ -#define ET_VLABEL 0x83 /* Volume label */ -#define ET_FILEDIR 0x85 /* File and directory */ -#define ET_STREAM 0xC0 /* Stream extension */ -#define ET_FILENAME 0xC1 /* Name extension */ - - -/* 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; /* Filesystem mount ID */ - -#if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive */ -#endif - -#if FF_FS_LOCK != 0 -static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ -#endif - -#if FF_STR_VOLUME_ID -#ifdef FF_VOLUME_STRS -static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ -#endif -#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 < FF_SFN_BUF || FF_SFN_BUF < 12 -#error Wrong setting of FF_LFN_BUF or FF_SFN_BUF -#endif -#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 -#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 /* Must be >=FF_MAX_SS */ - -#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 - ----------------------------------------------------------------------------*/ - -/*-----------------------------------------------------------------------*/ -/* Print error header */ -/*-----------------------------------------------------------------------*/ - -void print_error() -{ - gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF); -} - - -/*-----------------------------------------------------------------------*/ -/* 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++; /* Get a unit */ - 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 unit */ - 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 >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ - } - -#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ - uc = (TCHAR)*p++; /* Get a unit */ - if (uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ - if (uc >= 0x010000) 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; - -#elif FF_LFN_UNICODE == 3 /* UTF-32 output */ - DWORD hc; - - if (szb < 1) return 0; /* Buffer overflow? */ - if (chr >= 0x10000) { /* Out of BMP? */ - 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)chr; - return 1; - -#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, sizeof fs->win); - 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 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ - 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->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; - 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->bitbase + clst / 8 / SS(fs); /* Sector address */ - 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 if 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, sizeof fs->win); /* 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), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; 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 (many 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 (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ - if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ - - 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 + 1 || 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 + 1) return 0; /* Buffer overflow? */ - lfnbuf[i++] = wc = uc; /* Store it */ - } else { - if (uc != 0xFFFF) return 0; /* Check filler */ - } - } - - if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ - if (i >= FF_MAX_LFN + 1) 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 as hash value */ - 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; /* Number of bytes of the entry block */ - for (i = sum = 0; i < szblk; i++) { - if (i == XDIR_SetSum) { /* Skip 2-byte 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 file 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 up-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 ( /* Returns 32-bit checksum */ - BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ - DWORD sum /* Previous sum value */ -) -{ - 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 = 0; hs = 0; 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 API 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 support 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 file-directory entry */ - res = move_window(dp->obj.fs, dp->sect); - if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_FILEDIR) 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 stream-extension 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] != ET_STREAM) 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 file-name entries */ - i = 2 * SZDIRE; /* Name 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] != ET_FILENAME) 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 file-directory and stream-extension entry */ - mem_set(dirb, 0, 2 * SZDIRE); - dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; - dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - - /* Create file-name entries */ - i = SZDIRE * 2; /* Top of file_name entries */ - nlen = nc1 = 0; wc = 1; - do { - dirb[i++] = ET_FILENAME; dirb[i++] = 0; - 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 attr, b; -#if FF_USE_LFN - BYTE ord = 0xFF, sum = 0xFF; -#endif - - while (dp->sect) { - res = move_window(fs, dp->sect); - if (res != FR_OK) break; - b = dp->dir[DIR_Name]; /* Test for the entry type */ - if (b == 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 (b == ET_VLABEL) break; /* Volume label entry? */ - } else { - if (b == ET_FILEDIR) { /* 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 = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ -#if FF_USE_LFN /* LFN configuration */ - if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ - ord = 0xFF; - } else { - if (attr == AM_LFN) { /* An LFN entry is found */ - if (b & LLEF) { /* Is it start of an LFN sequence? */ - sum = dp->dir[LDIR_Chksum]; - b &= (BYTE)~LLEF; ord = b; - dp->blk_ofs = dp->dptr; - } - /* Check LFN validity and capture it */ - ord = (b == 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 (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~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 directory 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 by new allocation? */ - 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 - BYTE lcf; - 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 Unicode */ - 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, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ - wc = (WCHAR)fno->altname[si]; - if (wc == '.') lcf = NS_EXT; - if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) 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 number or null pointer) */ - const TCHAR** path /* Pointer to pointer to the path name */ -) -{ - const TCHAR *tp, *tt; - TCHAR tc; - int i, vol = -1; -#if FF_STR_VOLUME_ID /* Find string volume ID */ - const char *sp; - char c; -#endif - - tt = tp = *path; - if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ - - if (tc == ':') { /* DOS/Windows style volume ID? */ - i = FF_VOLUMES; - if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ - i = (int)*tp - '0'; /* Get the LD number */ - } -#if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ - else { - i = 0; - do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *tp++; - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ - } -#endif - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tt; /* Snip the drive prefix off */ - } - return vol; - } -#if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ - if (*tp == '/') { - i = 0; - do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *(++tp); - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tp; /* Snip the drive prefix off */ - return vol; - } - } -#endif - /* No drive prefix is found */ -#if FF_FS_RPATH != 0 - vol = CurrVol; /* Default drive is current drive */ -#else - vol = 0; /* Default drive is 0 */ -#endif - return vol; /* Return the default drive */ -} - - - - -/*-----------------------------------------------------------------------*/ -/* 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 here regardless of the sector size) */ - -#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: an 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 */ - EFSPRINTF("WPEN1"); - 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 */ - EFSPRINTF("MDNR"); - 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 */ - EFSPRINTF("WPEN2"); - 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 (MBR) and SFD (w/o partition). */ - 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) { - EFSPRINTF("BRNL"); - return FR_DISK_ERR; /* An error occured in the disk I/O layer */ - } - if (fmt >= 2) { - EFSPRINTF("NOFAT"); - 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; - DWORD so, cv, bcl; - - 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) */ - EFSPRINTF("EXSPS"); - 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) { - EFSPRINTF("EXFNF"); - 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); - - /* Get bitmap location and check if it is contiguous (implementation assumption) */ - so = i = 0; - for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ - if (i == 0) { - if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ - if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) { - EFSPRINTF("EXBM1C"); - return FR_DISK_ERR; - } - so++; - } - if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ - i = (i + SZDIRE) % SS(fs); /* Next entry */ - } - bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ - if (bcl < 2 || bcl >= fs->n_fatent) { - EFSPRINTF("EXBMM"); - return FR_NO_FILESYSTEM; - } - fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ - for (;;) { /* Check if bitmap is contiguous */ - if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; - cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); - if (cv == 0xFFFFFFFF) break; /* Last link? */ - if (cv != ++bcl) { - EFSPRINTF("EXBMM"); - return FR_NO_FILESYSTEM; /* Fragmented? */ - } - } - -#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)) { - EFSPRINTF("32SPS"); - 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 buffer */ -#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) { - EFSPRINTF("IDRIVE!"); - 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 number */ - 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, sizeof fp->buf); /* 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; - - UINT br_tmp; - if (!br) - br = &br_tmp; - *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) { - EFSPRINTF("FOV"); - 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 btr bytes 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) { - EFSPRINTF("CCHK"); - ABORT(fs, FR_INT_ERR); - } - if (clst == 0xFFFFFFFF) { - EFSPRINTF("DSKC"); - 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) { - EFSPRINTF("RLIO"); - 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) { - EFSPRINTF("RDC"); - ABORT(fs, FR_DISK_ERR); - } - fp->flag &= (BYTE)~FA_DIRTY; - } -#endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { - EFSPRINTF("RSC"); - 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; - - UINT bw_tmp; - if (!bw) - bw = &bw_tmp; - *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) { - EFSPRINTF("FOV"); - 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) { - EFSPRINTF("DSKFULL"); - break; /* Could not allocate a new cluster (disk full) */ - } - if (clst == 1) { - EFSPRINTF("CCHK"); - ABORT(fs, FR_INT_ERR); - } - if (clst == 0xFFFFFFFF) { - EFSPRINTF("DERR"); - 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) { - EFSPRINTF("WLIO"); - 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 */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_chdrive ( - const TCHAR* path /* Drive number to set */ -) -{ - 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; -} - - - -FRESULT f_chdir ( - const TCHAR* path /* Pointer to the directory path */ -) -{ -#if FF_STR_VOLUME_ID == 2 - UINT i; -#endif - 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) { /* Is it the start directory itself? */ - fs->cdir = dj.obj.sclust; -#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; -#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ - if (res == FR_OK) { - for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ - CurrVol = (BYTE)i; - } -#endif - } - - LEAVE_FF(fs, res); -} - - -#if FF_FS_RPATH >= 2 -FRESULT f_getcwd ( - TCHAR* buff, /* Pointer to the directory path */ - UINT len /* Size of buff in unit of TCHAR */ -) -{ - FRESULT res; - DIR dj; - FATFS *fs; - UINT i, n; - DWORD ccl; - TCHAR *tp = buff; -#if FF_VOLUMES >= 2 - UINT vl; -#if FF_STR_VOLUME_ID - const char *vp; -#endif -#endif - FILINFO fno; - DEF_NAMBUF - - - /* Get logical drive */ - buff[0] = 0; /* Set null string to get current volume */ - res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ - if (res == FR_OK) { - dj.obj.fs = fs; - INIT_NAMBUF(fs); - - /* Follow parent directories and create the path */ - 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++) ; /* Name length */ - if (i < n + 1) { /* Insufficient space to store the path name? */ - res = FR_NOT_ENOUGH_CORE; break; - } - while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ - buff[--i] = '/'; - } - } - if (res == FR_OK) { - if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ -#if FF_VOLUMES >= 2 /* Put drive prefix */ - vl = 0; -#if FF_STR_VOLUME_ID >= 1 /* String volume ID */ - for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; - if (i >= n + 2) { - if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; - for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; - if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; - vl++; - } -#else /* Numeric volume ID */ - if (i >= 3) { - *tp++ = (TCHAR)'0' + CurrVol; - *tp++ = (TCHAR)':'; - vl = 2; - } -#endif - if (vl == 0) res = FR_NOT_ENOUGH_CORE; -#endif - /* Add current directory path */ - if (res == FR_OK) { - do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ - } - } - FREE_NAMBUF(); - } - - *tp = 0; - 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) { - if (fatfs) *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->bitbase; /* Bitmap sector */ - 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; - FFOBJID sobj; - FATFS *fs; - DWORD dcl, pcl, tm; - 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) res = FR_EXIST; /* Name collision? */ - if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ - res = FR_INVALID_NAME; - } - if (res == FR_NO_FILE) { /* It is clear to create a new directory */ - sobj.fs = fs; /* New object id to create a new chain */ - dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ - res = FR_OK; - if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ - if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ - if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ - tm = GET_FATTIME(); - if (res == FR_OK) { - res = dir_clear(fs, dcl); /* Clean up the new table */ - if (res == FR_OK) { - if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ - mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ - fs->win[DIR_Name] = '.'; - fs->win[DIR_Attr] = AM_DIR; - st_dword(fs->win + DIR_ModTime, tm); - st_clust(fs, fs->win, dcl); - mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ - fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; - st_clust(fs, fs->win + SZDIRE, pcl); - fs->wflag = 1; - } - res = dir_register(&dj); /* Register the object to the parent 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)fs->csize * SS(fs)); /* File size needs to be valid */ - st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); - fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ - fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ - res = store_xdir(&dj); - } else -#endif - { - st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ - st_clust(fs, dj.dir, dcl); /* Table start cluster */ - dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ - fs->wflag = 1; - } - if (res == FR_OK) { - res = sync_fs(fs); - } - } else { - remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ - } - } - 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); /* Convert it into Unicode */ - if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ - 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 ((UINT)*label >= ' ') { /* Create volume label */ - 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 ((UINT)*label >= ' ') { /* Create volume label */ -#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] = ET_VLABEL; /* Create volume label 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)) == 0; 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 - b_vol >= 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 = 0; si = 0; i = 0; j = 0; 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 += (WCHAR)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] = ET_VLABEL; /* Volume label entry */ - buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ - st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ - st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ - buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ - st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ - st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ - st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ - 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 = (BYTE)(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[4]; - UINT rc; - DWORD dc; -#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 - WCHAR wc; -#endif -#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 - UINT ct; -#endif - -#if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ - /* Make a room for the character and terminator */ - if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; - if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; - if (FF_LFN_UNICODE == 3) len -= 1; - while (nc < len) { -#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; -#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ - f_read(fp, s, 2, &rc); - if (rc != 2) break; - dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; - if (IsSurrogateL(dc)) continue; - if (IsSurrogateH(dc)) { - f_read(fp, s, 2, &rc); - if (rc != 2) break; - wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; - if (!IsSurrogateL(wc)) continue; - dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); - } -#else /* Read a character in UTF-8 */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - dc = s[0]; - if (dc >= 0x80) { /* Multi-byte character? */ - ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte? */ - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte? */ - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte? */ - if (ct == 0) continue; - f_read(fp, s, ct, &rc); /* Get trailing bytes */ - if (rc != ct) break; - rc = 0; - do { /* Merge trailing bytes */ - if ((s[rc] & 0xC0) != 0x80) break; - dc = dc << 6 | (s[rc] & 0x3F); - } while (++rc < ct); - if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ - } -#endif - if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ -#if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ - if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ - *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ - dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ - } - *p++ = (TCHAR)dc; nc++; - if (dc == '\n') break; /* End of line? */ -#elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ - if (dc < 0x80) { /* 1-byte */ - *p++ = (TCHAR)dc; - nc++; - if (dc == '\n') break; /* End of line? */ - } 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; - } - } - } -#endif - } - -#else /* Byte-by-byte without any conversion (ANSI/OEM API) */ - len -= 1; /* Make a room for the terminator */ - while (nc < len) { - f_read(fp, s, 1, &rc); - if (rc != 1) break; - dc = s[0]; - if (FF_USE_STRFUNC == 2 && dc == '\r') continue; - *p++ = (TCHAR)dc; nc++; - if (dc == '\n') break; - } -#endif - - *p = 0; /* Terminate the string */ - return nc ? buff : 0; /* When no data read due to 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 - WCHAR hs, wc; -#if FF_LFN_UNICODE == 2 - DWORD dc; - TCHAR *tp; -#endif -#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 counter */ - -#if FF_USE_LFN && FF_LFN_UNICODE -#if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { - pb->hs = c; return; - } - hs = pb->hs; pb->hs = 0; - if (hs != 0) { - if (!IsSurrogateL(c)) hs = 0; - } else { - if (IsSurrogateL(c)) return; - } - wc = c; -#elif FF_LFN_UNICODE == 2 /* 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 multi-byte sequence? */ - return; - } - } - tp = (TCHAR*)pb->bs; - dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ - if (dc == 0xFFFFFFFF) return; - wc = (WCHAR)dc; - hs = (WCHAR)(dc >> 16); -#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ - if (IsSurrogate(c) || c >= 0x110000) return; - if (c >= 0x10000) { - hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ - wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ - } else { - hs = 0; - wc = (WCHAR)c; - } -#endif - -#if FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ - if (hs != 0) { - st_word(&pb->buf[i], hs); - i += 2; - nc++; - } - st_word(&pb->buf[i], wc); - i += 2; -#elif 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; -#elif FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ - if (hs != 0) { /* 4-byte */ - nc += 3; - 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 */ - pb->buf[i++] = (BYTE)wc; - } else { - if (wc < 0x800) { /* 2-byte */ - nc += 1; - pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); - } else { /* 3-byte */ - nc += 2; - pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); - pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); - } - pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); - } - } -#else /* Write it 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; -#endif - -#else /* ANSI/OEM input (without re-encode) */ - pb->buf[i++] = (BYTE)c; -#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 + 1; -} - - -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/bootloader/libs/fatfs/ff.h b/bootloader/libs/fatfs/ff.h deleted file mode 100644 index f867131..0000000 --- a/bootloader/libs/fatfs/ff.h +++ /dev/null @@ -1,379 +0,0 @@ -/*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.13c / -/-----------------------------------------------------------------------------/ -/ -/ Copyright (C) 2018, 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 86604 /* Revision ID */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../utils/types.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 - -#if FF_STR_VOLUME_ID -#ifndef FF_VOLUME_STRS -extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ -#endif -#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 == 3 /* Unicode in UTF-32 encoding */ -typedef DWORD TCHAR; -#define _T(x) U ## x -#define _TEXT(x) U ## x -#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) -#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 win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ - BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Associated physical drive */ - 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 */ -#if FF_FS_EXFAT - DWORD bitbase; /* Allocation bitmap base sector */ -#endif - DWORD winsect; /* Current sector appearing in the win[] */ -} 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:fragmented 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 { -#if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ -#endif - 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 -} 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 fsz, 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/bootloader/libs/fatfs/ffconf.h b/bootloader/libs/fatfs/ffconf.h index be64ef3..c6b94bc 100644 --- a/bootloader/libs/fatfs/ffconf.h +++ b/bootloader/libs/fatfs/ffconf.h @@ -41,10 +41,26 @@ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ +#if FF_USE_MKFS +#define FF_MKFS_LABEL "SWITCH SD " +#endif +/* This sets FAT/FAT32 label. Exactly 11 characters, all caps. */ + #define FF_USE_FASTSEEK 0 /* This option switches fast seek function. (0:Disable or 1:Enable) */ +#define FF_FASTFS 0 +#if FF_FASTFS +#undef FF_USE_FASTSEEK +#define FF_USE_FASTSEEK 1 +#endif +/* This option switches fast access to chained clusters. (0:Disable or 1:Enable) */ + + +#define FF_SIMPLE_GPT 1 +/* This option switches support for the first GPT partition. (0:Disable or 1:Enable) */ + #define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ @@ -178,6 +194,7 @@ / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +/ Order is important. Any change to order, must also be reflected to diskio drive enum. */ @@ -239,7 +256,7 @@ #define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2019 +#define FF_NORTC_YEAR 2025 /* The option FF_FS_NORTC switches timestamp function. 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. Every object modified by FatFs will have a fixed timestamp diff --git a/bootloader/libs/fatfs/ffsystem.c b/bootloader/libs/fatfs/ffsystem.c deleted file mode 100644 index fa44f8e..0000000 --- a/bootloader/libs/fatfs/ffsystem.c +++ /dev/null @@ -1,39 +0,0 @@ -/*------------------------------------------------------------------------*/ -/* Sample Code of OS Dependent Functions for FatFs */ -/* (C) ChaN, 2018 */ -/* (C) CTCaer, 2018 */ -/*------------------------------------------------------------------------*/ - - -#include "ff.h" -#include "../../mem/heap.h" - - - -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ - -/*------------------------------------------------------------------------*/ -/* Allocate a memory block */ -/*------------------------------------------------------------------------*/ - -void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ - UINT msize /* Number of bytes to allocate */ -) -{ - return malloc(msize); /* Allocate a new memory block with POSIX API */ -} - - -/*------------------------------------------------------------------------*/ -/* Free a memory block */ -/*------------------------------------------------------------------------*/ - -void ff_memfree ( - void* mblock /* Pointer to the memory block to free (nothing to do if null) */ -) -{ - free(mblock); /* Free the memory block with POSIX API */ -} - -#endif - diff --git a/bootloader/link.ld b/bootloader/link.ld index 85568dd..335be02 100644 --- a/bootloader/link.ld +++ b/bootloader/link.ld @@ -5,8 +5,9 @@ SECTIONS { . = __ipl_start; .text : { *(.text._start); - *(._boot_cfg); - *(._ipl_version); + KEEP(*(._boot_cfg)); + KEEP(*(._ipl_version)); + *(.text._irq_setup); *(.text*); } .data : { diff --git a/bootloader/main.c b/bootloader/main.c index 86240c0..4ec3eab 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,207 +19,72 @@ #include #include -#include "../common/memory_map.h" +#include -#include "config/config.h" -#include "gfx/di.h" -#include "gfx/gfx.h" +#include "config.h" #include "gfx/logos.h" #include "gfx/tui.h" #include "hos/hos.h" #include "hos/secmon_exo.h" -#include "hos/sept.h" -#include "ianos/ianos.h" -#include "libs/compr/blz.h" -#include "libs/fatfs/ff.h" -#include "mem/heap.h" -#include "mem/minerva.h" -#include "mem/sdram.h" -#include "power/max77620.h" -#include "rtc/max77620-rtc.h" -#include "soc/bpmp.h" -#include "soc/fuse.h" -#include "soc/hw_init.h" -#include "soc/i2c.h" -#include "soc/t210.h" -#include "soc/uart.h" +#include "l4t/l4t.h" +#include +#include +#include #include "storage/emummc.h" -#include "storage/nx_emmc.h" -#include "storage/sdmmc.h" -#include "utils/btn.h" -#include "utils/dirlist.h" -#include "utils/list.h" -#include "utils/util.h" -#include "frontend/fe_emmc_tools.h" #include "frontend/fe_tools.h" #include "frontend/fe_info.h" -//TODO: ugly. -sdmmc_t sd_sdmmc; -sdmmc_storage_t sd_storage; -FATFS sd_fs; -static bool sd_mounted; - -#ifdef MENU_LOGO_ENABLE -u8 *Kc_MENU_LOGO; -#endif //MENU_LOGO_ENABLE - hekate_config h_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = { .magic = BL_MAGIC, - .version = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16), + .version = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16) | ((BL_VER_RL) << 24), .rsvd0 = 0, .rsvd1 = 0 }; volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; -bool sd_mount() +static void _check_power_off_from_hos() { - if (sd_mounted) - return true; + // Power off on alarm wakeup from HOS shutdown. For modchips/dongles. + u8 hos_wakeup = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_IRQTOP); - if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11)) + // Clear RTC interrupts. + (void)i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_RTCINT_REG); + + // Stop the alarm, in case we injected and powered off too fast. + max77620_rtc_stop_alarm(); + + // Handle RTC wake up. + if (hos_wakeup & MAX77620_IRQ_TOP_RTC_MASK) { - gfx_con.mute = false; - EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); - } - else - { - int res = 0; - res = f_mount(&sd_fs, "", 1); - if (res == FR_OK) - { - sd_mounted = 1; - return true; - } - else - { - gfx_con.mute = false; - EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); - } - } - - return false; -} - -void sd_unmount() -{ - if (sd_mounted) - { - f_mount(NULL, "", 1); - sdmmc_storage_end(&sd_storage); - sd_mounted = false; - } -} - -void *sd_file_read(const char *path, u32 *fsize) -{ - FIL fp; - if (f_open(&fp, path, FA_READ) != FR_OK) - return NULL; - - u32 size = f_size(&fp); - if (fsize) - *fsize = size; - - void *buf = malloc(size); - - if (f_read(&fp, buf, size, NULL) != FR_OK) - { - free(buf); - f_close(&fp); - - return NULL; - } - - f_close(&fp); - - return buf; -} - -int sd_save_to_file(void *buf, u32 size, const char *filename) -{ - FIL fp; - u32 res = 0; - res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE); - if (res) - { - EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); - return res; - } - - f_write(&fp, buf, size, NULL); - f_close(&fp); - - return 0; -} - -void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage) -{ - sdmmc_storage_t storage2; - sdmmc_t sdmmc; - char emmcSN[9]; - bool init_done = false; - - memcpy(path, "backup", 7); - f_mkdir(path); - - if (!storage) - { - if (!sdmmc_storage_init_mmc(&storage2, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - memcpy(emmcSN, "00000000", 9); - else - { - init_done = true; - itoa(storage2.cid.serial, emmcSN, 16); - } - } - else - itoa(storage->cid.serial, emmcSN, 16); - - u32 sub_dir_len = strlen(sub_dir); // Can be a null-terminator. - u32 filename_len = strlen(filename); // Can be a null-terminator. - - memcpy(path + strlen(path), "/", 2); - memcpy(path + strlen(path), emmcSN, 9); - f_mkdir(path); - memcpy(path + strlen(path), sub_dir, sub_dir_len + 1); - if (sub_dir_len) - f_mkdir(path); - memcpy(path + strlen(path), "/", 2); - memcpy(path + strlen(path), filename, filename_len + 1); - - if (init_done) - sdmmc_storage_end(&storage2); -} - -void check_power_off_from_hos() -{ - // Power off on AutoRCM wakeup from HOS shutdown. For modchips/dongles. - u8 hosWakeup = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_IRQTOP); - if (hosWakeup & MAX77620_IRQ_TOP_RTC_MASK) - { - sd_unmount(); - - // Stop the alarm, in case we injected too fast. - max77620_rtc_stop_alarm(); - if (h_cfg.autohosoff == 1) { - gfx_clear_grey(0x1B); - u8 *BOOTLOGO = (void *)malloc(0x4000); - blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO); - gfx_set_rect_grey(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544); + render_static_bootlogo(); - display_backlight_brightness(10, 5000); - display_backlight_brightness(100, 25000); - msleep(600); - display_backlight_brightness(0, 20000); + if (display_get_decoded_panel_id() != PANEL_SAM_AMS699VC01) + { + // Slow fading for LCD panels. + display_backlight_brightness(10, 5000); + display_backlight_brightness(100, 25000); + msleep(600); + display_backlight_brightness(0, 20000); + } + else + { + // Blink 3 times for OLED panel. + for (u32 i = 0; i < 3; i++) + { + msleep(150); + display_backlight_brightness(100, 0); + msleep(150); + display_backlight_brightness(0, 0); + } + } } - power_off(); + power_set_state(POWER_OFF_RESET); } } @@ -228,17 +93,20 @@ void check_power_off_from_hos() #define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_STACK 0x40007000 #define PATCHED_RELOC_ENTRY 0x40010000 -#define EXT_PAYLOAD_ADDR 0xC03C0000 +#define EXT_PAYLOAD_ADDR 0xC0000000 #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -#define COREBOOT_ADDR (0xD0000000 - 0x100000) -#define CBFS_DRAM_EN_ADDR 0x4003e000 +#define COREBOOT_END_ADDR 0xD0000000 +#define COREBOOT_VER_OFF 0x41 +#define CBFS_DRAM_EN_ADDR 0x4003E000 #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" -void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) +static void *coreboot_addr; + +static void _reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); - volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); + reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); relocator->stack = PATCHED_RELOC_STACK; @@ -247,16 +115,16 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) if (payload_size == 0x7000) { - memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); // Bootblock. *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; } } -bool is_ipl_updated(void *buf, char *path, bool force) +bool is_ipl_updated(void *buf, const char *path, bool force) { ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t)); - bool magic_valid = update_ft->magic == ipl_ver.magic; + bool magic_valid = update_ft->magic == ipl_ver.magic; bool force_update = force && !magic_valid; bool is_valid_old = magic_valid && (byte_swap_32(update_ft->version) < byte_swap_32(ipl_ver.version)); @@ -269,13 +137,12 @@ bool is_ipl_updated(void *buf, char *path, bool force) if (force_update || is_valid_old) { FIL fp; - volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); - boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); - memset(tmp_cfg, 0, sizeof(boot_cfg_t)); + reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); + boot_cfg_t *tmp_cfg = zalloc(sizeof(boot_cfg_t)); f_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS); f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL); - + // Write needed tag in case injected ipl uses old versioning. f_write(&fp, "ICTC49", 6, NULL); @@ -290,411 +157,454 @@ bool is_ipl_updated(void *buf, char *path, bool force) return true; } -int launch_payload(char *path, bool update) +static void _launch_payload(char *path, bool update, bool clear_screen) { - if (!update) + if (clear_screen) gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - if (sd_mount()) + FIL fp; + if (f_open(&fp, path, FA_READ)) { - FIL fp; - if (f_open(&fp, path, FA_READ)) - { - EPRINTFARGS("Payload file is missing!\n(%s)", path); + gfx_con.mute = false; + EPRINTFARGS("Payload file is missing!\n(%s)", path); - goto out; - } + goto out; + } - // Read and copy the payload to our chosen address - void *buf; - u32 size = f_size(&fp); + // Read and copy the payload to our chosen address + void *buf; + u32 size = f_size(&fp); - if (size < 0x30000) - buf = (void *)RCM_PAYLOAD_ADDR; - else - buf = (void *)COREBOOT_ADDR; - - if (f_read(&fp, buf, size, NULL)) + if (size < 0x30000) + buf = (void *)RCM_PAYLOAD_ADDR; + else + { + coreboot_addr = (void *)(COREBOOT_END_ADDR - size); + buf = coreboot_addr; + if (h_cfg.t210b01) { f_close(&fp); - + + gfx_con.mute = false; + EPRINTF("Coreboot not allowed on Mariko!"); + goto out; } + } + if (f_read(&fp, buf, size, NULL)) + { f_close(&fp); - if (update && is_ipl_updated(buf, path, false)) - goto out; + goto out; + } - sd_unmount(); + f_close(&fp); - if (size < 0x30000) - { - if (update) - memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg. - else - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); + if (update && is_ipl_updated(buf, path, false)) + goto out; - reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); - } + sd_end(); + + if (size < 0x30000) + { + if (update) + memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg. else - { - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); - reconfig_hw_workaround(true, 0); - } + _reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); + hw_deinit(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); + } + else + { + _reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); + + // Get coreboot seamless display magic. + u32 magic = 0; + char *magic_ptr = buf + COREBOOT_VER_OFF; + memcpy(&magic, magic_ptr + strlen(magic_ptr) - 4, 4); + hw_deinit(true, magic); + } + + void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR; + void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; + + // Launch our payload. + if (!update) + { // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. sdmmc_storage_init_wait_sd(); - void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; - void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR; - - // Launch our payload. - if (!update) - (*ext_payload_ptr)(); - else - { - EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD; - (*update_ptr)(); - } + (*ext_payload_ptr)(); + } + else + { + // Set updated flag to skip check on launch. + EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD; + (*update_ptr)(); } out: if (!update) - sd_unmount(); - - return 1; -} - -void auto_launch_update() -{ - if (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD) - EMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD; - else if (sd_mount()) { - if (!f_stat("bootloader/update.bin", NULL)) - launch_payload("bootloader/update.bin", true); + gfx_con.mute = false; + EPRINTF("Failed to launch payload!"); } } -void launch_tools() +static void _launch_payloads() { u8 max_entries = 61; - char *filelist = NULL; + ment_t *ments = NULL; char *file_sec = NULL; char *dir = NULL; - - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + dirlist_t *filelist = NULL; gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - if (sd_mount()) + if (!sd_mount()) + goto failed_sd_mount; + + ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + + dir = (char *)malloc(256); + memcpy(dir, "bootloader/payloads", 20); + + filelist = dirlist(dir, NULL, false, false); + + u32 i = 0; + + if (filelist) { - dir = (char *)malloc(256); + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; - memcpy(dir, "bootloader/payloads", 20); + ments[1].type = MENT_CHGLINE; - filelist = dirlist(dir, NULL, false); - - u32 i = 0; - - if (filelist) + while (true) { - // Build configuration menu. - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - ments[1].type = MENT_CHGLINE; + if (i > max_entries || !filelist->name[i]) + break; + ments[i + 2].type = INI_CHOICE; + ments[i + 2].caption = filelist->name[i]; + ments[i + 2].data = filelist->name[i]; - while (true) - { - if (i > max_entries || !filelist[i * 256]) - break; - ments[i + 2].type = INI_CHOICE; - ments[i + 2].caption = &filelist[i * 256]; - ments[i + 2].data = &filelist[i * 256]; - - i++; - } + i++; } + } - if (i > 0) + if (i > 0) + { + memset(&ments[i + 2], 0, sizeof(ment_t)); + menu_t menu = { ments, "Choose a payload", 0, 0 }; + + file_sec = (char *)tui_do_menu(&menu); + + if (!file_sec) { - memset(&ments[i + 2], 0, sizeof(ment_t)); - menu_t menu = { ments, "Choose a file to launch", 0, 0 }; + free(ments); + free(dir); + free(filelist); + sd_end(); - file_sec = (char *)tui_do_menu(&menu); - - if (!file_sec) - { - free(ments); - free(dir); - free(filelist); - sd_unmount(); - - return; - } + return; } - else - EPRINTF("No payloads or modules found."); - - free(ments); - free(filelist); } else - { - free(ments); - goto out; - } + EPRINTF("No payloads found."); if (file_sec) { memcpy(dir + strlen(dir), "/", 2); memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1); - launch_payload(dir, false); - EPRINTF("Failed to launch payload."); + _launch_payload(dir, false, true); } -out: - sd_unmount(); +failed_sd_mount: free(dir); + free(ments); + free(filelist); + sd_end(); btn_wait(); } -void ini_list_launcher() +static void _launch_ini_list() { u8 max_entries = 61; - char *payload_path = NULL; - + char *special_path = NULL; + char *emummc_path = NULL; + ment_t *ments = NULL; ini_sec_t *cfg_sec = NULL; + LIST_INIT(ini_list_sections); gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - if (sd_mount()) + if (!sd_mount()) + goto parse_failed; + + // Check that ini files exist and parse them. + if (!ini_parse(&ini_list_sections, "bootloader/ini", true)) { - if (ini_parse(&ini_list_sections, "bootloader/ini", true)) - { - // Build configuration menu. - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - ments[1].type = MENT_CHGLINE; - - u32 i = 2; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link) - { - if (!strcmp(ini_sec->name, "config") || - ini_sec->type == INI_COMMENT || ini_sec->type == INI_NEWLINE) - continue; - ments[i].type = ini_sec->type; - ments[i].caption = ini_sec->name; - ments[i].data = ini_sec; - if (ini_sec->type == MENT_CAPTION) - ments[i].color = ini_sec->color; - i++; - - if ((i - 1) > max_entries) - break; - } - if (i > 2) - { - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = { - ments, "Launch ini configurations", 0, 0 - }; - - cfg_sec = (ini_sec_t *)tui_do_menu(&menu); - - if (cfg_sec) - { - u32 non_cfg = 1; - for (int j = 2; j < i; j++) - { - if (ments[j].type != INI_CHOICE) - non_cfg++; - - if (ments[j].data == cfg_sec) - { - b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH; - b_cfg.autoboot = j - non_cfg; - b_cfg.autoboot_list = 1; - - break; - } - } - } - - payload_path = ini_check_payload_section(cfg_sec); - - if (cfg_sec && !payload_path) - check_sept(cfg_sec); - - if (!cfg_sec) - { - free(ments); - - return; - } - } - else - EPRINTF("No extra configs found."); - free(ments); - } - else - EPRINTF("Could not find any ini\nin bootloader/ini!"); + EPRINTF("No .ini files in bootloader/ini!"); + goto parse_failed; } + // Build configuration menu. + ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 sec_idx = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link) + { + if (ini_sec->type == INI_COMMENT || + ini_sec->type == INI_NEWLINE || + !strcmp(ini_sec->name, "config")) + continue; + + ments[sec_idx].type = ini_sec->type; + ments[sec_idx].caption = ini_sec->name; + ments[sec_idx].data = ini_sec; + + if (ini_sec->type == MENT_CAPTION) + ments[sec_idx].color = ini_sec->color; + sec_idx++; + + if ((sec_idx - 1) > max_entries) + break; + } + + if (sec_idx > 2) + { + memset(&ments[sec_idx], 0, sizeof(ment_t)); + menu_t menu = { + ments, "Launch ini entries", 0, 0 + }; + + cfg_sec = (ini_sec_t *)tui_do_menu(&menu); + + special_path = ini_check_special_section(cfg_sec); + + if (cfg_sec && !special_path) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) + { + if (!strcmp("emummc_force_disable", kv->key)) + h_cfg.emummc_force_disable = atoi(kv->val); + else if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; + } + + if (emummc_path && !emummc_set_path(emummc_path)) + { + EPRINTF("emupath is wrong!"); + goto wrong_emupath; + } + } + + if (!cfg_sec) + { + free(ments); + + return; + } + } + else + EPRINTF("No extra configs found."); + +parse_failed: if (!cfg_sec) goto out; - if (payload_path) + if (special_path) { - launch_payload(payload_path, false); - EPRINTF("Failed to launch payload."); - free(payload_path); + // Try to launch Payload or L4T. + if (special_path != (char *)-1) + _launch_payload(special_path, false, true); + else + { + u32 entry_idx = 0; + for (u32 i = 0; i < sec_idx; i++) + { + if (ments[i].data == cfg_sec) + { + entry_idx = i; + break; + } + } + launch_l4t(cfg_sec, entry_idx, 1, h_cfg.t210b01); + } } - else if (!hos_launch(cfg_sec)) + else { - EPRINTF("Failed to launch firmware."); - btn_wait(); + hos_launch(cfg_sec); + +wrong_emupath: + if (emummc_path) + { + sd_mount(); + emummc_load_cfg(); // Reload emuMMC config in case of emupath. + } } out: + free(ments); btn_wait(); } -void launch_firmware() +static void _launch_config() { u8 max_entries = 61; - char *payload_path = NULL; + char *special_path = NULL; + char *emummc_path = NULL; + ment_t *ments = NULL; ini_sec_t *cfg_sec = NULL; + LIST_INIT(ini_sections); gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - if (sd_mount()) + if (!sd_mount()) + goto parse_failed; + + // Load emuMMC configuration. + emummc_load_cfg(); + + // Parse main configuration. + ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false); + + // Build configuration menu. + ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 6)); + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_HANDLER; + ments[2].caption = "Payloads..."; + ments[2].handler = _launch_payloads; + + ments[3].type = MENT_HANDLER; + ments[3].caption = "More configs..."; + ments[3].handler = _launch_ini_list; + + ments[4].type = MENT_CHGLINE; + + u32 sec_idx = 5; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + if (ini_sec->type == INI_COMMENT || + ini_sec->type == INI_NEWLINE || + !strcmp(ini_sec->name, "config")) + continue; + + ments[sec_idx].type = ini_sec->type; + ments[sec_idx].caption = ini_sec->name; + ments[sec_idx].data = ini_sec; + + if (ini_sec->type == MENT_CAPTION) + ments[sec_idx].color = ini_sec->color; + sec_idx++; + + if ((sec_idx - 4) > max_entries) + break; + } + + if (sec_idx < 6) + { + ments[sec_idx].type = MENT_CAPTION; + ments[sec_idx].caption = "No main configs found..."; + ments[sec_idx].color = TXT_CLR_WARNING; + sec_idx++; + } + + memset(&ments[sec_idx], 0, sizeof(ment_t)); + menu_t menu = { + ments, "Launch configurations", 0, 0 + }; + + cfg_sec = (ini_sec_t *)tui_do_menu(&menu); + + special_path = ini_check_special_section(cfg_sec); + + if (cfg_sec && !special_path) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) { - // Build configuration menu. - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 6)); - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - ments[1].type = MENT_CHGLINE; - - ments[2].type = MENT_HANDLER; - ments[2].caption = "Payloads..."; - ments[2].handler = launch_tools; - ments[3].type = MENT_HANDLER; - ments[3].caption = "More configs..."; - ments[3].handler = ini_list_launcher; - - ments[4].type = MENT_CHGLINE; - - u32 i = 5; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - if (!strcmp(ini_sec->name, "config") || - ini_sec->type == INI_COMMENT || ini_sec->type == INI_NEWLINE) - continue; - ments[i].type = ini_sec->type; - ments[i].caption = ini_sec->name; - ments[i].data = ini_sec; - if (ini_sec->type == MENT_CAPTION) - ments[i].color = ini_sec->color; - i++; - - if ((i - 4) > max_entries) - break; - } - if (i < 6) - { - ments[i].type = MENT_CAPTION; - ments[i].caption = "No main configs found..."; - ments[i].color = 0xFFFFDD00; - i++; - } - memset(&ments[i], 0, sizeof(ment_t)); - menu_t menu = { - ments, "Launch configurations", 0, 0 - }; - - cfg_sec = (ini_sec_t *)tui_do_menu(&menu); - - if (cfg_sec) - { - u8 non_cfg = 4; - for (int j = 5; j < i; j++) - { - if (ments[j].type != INI_CHOICE) - non_cfg++; - if (ments[j].data == cfg_sec) - { - b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH; - b_cfg.autoboot = j - non_cfg; - b_cfg.autoboot_list = 0; - - break; - } - } - } - - payload_path = ini_check_payload_section(cfg_sec); - - if (cfg_sec) - { - LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) - { - if (!strcmp("emummc_force_disable", kv->key)) - h_cfg.emummc_force_disable = atoi(kv->val); - } - } - - if (cfg_sec && !payload_path) - check_sept(cfg_sec); - - if (!cfg_sec) - { - free(ments); - sd_unmount(); - return; - } - - free(ments); + if (!strcmp("emummc_force_disable", kv->key)) + h_cfg.emummc_force_disable = atoi(kv->val); + if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; + } + + if (emummc_path && !emummc_set_path(emummc_path)) + { + EPRINTF("emupath is wrong!"); + goto wrong_emupath; } - else - EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!"); } if (!cfg_sec) { - gfx_puts("\nUsing default launch configuration...\n"); - gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu."); - - u32 btn = btn_wait(); - if (!(btn & BTN_POWER)) - goto out; + free(ments); + sd_end(); + return; } - if (payload_path) +parse_failed: + if (!cfg_sec) { - launch_payload(payload_path, false); - EPRINTF("Failed to launch payload."); - free(payload_path); + gfx_printf("\nPress any key...\n"); + goto out; + } + + if (special_path) + { + // Try to launch Payload or L4T. + if (special_path != (char *)-1) + _launch_payload(special_path, false, true); + else + { + u32 entry_idx = 0; + for (u32 i = 0; i < sec_idx; i++) + { + if (ments[i].data == cfg_sec) + { + entry_idx = i; + break; + } + } + launch_l4t(cfg_sec, entry_idx, 0, h_cfg.t210b01); + } + } + else + { + hos_launch(cfg_sec); + +wrong_emupath: + if (emummc_path) + { + sd_mount(); + emummc_load_cfg(); // Reload emuMMC config in case of emupath. + } } - else if (!hos_launch(cfg_sec)) - EPRINTF("Failed to launch firmware."); out: - sd_unmount(); + sd_end(); + + free(ments); h_cfg.emummc_force_disable = false; @@ -703,67 +613,75 @@ out: #define NYX_VER_OFF 0x9C -void nyx_load_run() +static void _nyx_load_run() { - sd_mount(); - u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", NULL); if (!nyx) return; - sd_unmount(); + sd_end(); - u32 expected_nyx_ver = ((NYX_VER_MJ + '0') << 24) | ((NYX_VER_MN + '0') << 16) | ((NYX_VER_HF + '0') << 8); - u32 nyx_ver = byte_swap_32(*(u32 *)(nyx + NYX_VER_OFF)); - - gfx_clear_grey(0x1B); - u8 *BOOTLOGO = (void *)malloc(0x4000); - blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO); - gfx_set_rect_grey(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544); - free(BOOTLOGO); + render_static_bootlogo(); display_backlight_brightness(h_cfg.backlight, 1000); // Check if Nyx version is old. + u32 expected_nyx_ver = ((NYX_VER_MJ + '0') << 24) | ((NYX_VER_MN + '0') << 16) | ((NYX_VER_HF + '0') << 8); + u32 nyx_ver = byte_swap_32(*(u32 *)(nyx + NYX_VER_OFF)) & 0xFFFFFF00; if (nyx_ver < expected_nyx_ver) { h_cfg.errors |= ERR_SYSOLD_NYX; gfx_con_setpos(0, 0); WPRINTF("Old Nyx GUI found! There will be dragons!\n"); - WPRINTF("\nUpdate your bootloader folder!\n\n"); + WPRINTF("\nUpdate bootloader folder!\n\n"); WPRINTF("Press any key..."); - msleep(2000); + msleep(1000); btn_wait(); } + // Set hekate errors. nyx_str->info.errors = h_cfg.errors; + + // Set Nyx mode. nyx_str->cfg = 0; - if (b_cfg.extra_cfg & EXTRA_CFG_NYX_DUMP) + if (b_cfg.extra_cfg & EXTRA_CFG_NYX_UMS) { - b_cfg.extra_cfg &= ~(EXTRA_CFG_NYX_DUMP); - nyx_str->cfg |= NYX_CFG_DUMP; + b_cfg.extra_cfg &= ~(EXTRA_CFG_NYX_UMS); + + nyx_str->cfg |= NYX_CFG_UMS; + nyx_str->cfg |= b_cfg.ums << 24; } + // Set hekate version used to boot Nyx. nyx_str->version = ipl_ver.version - 0x303030; // Convert ASCII to numbers. - //memcpy((u8 *)nyx_str->irama, (void *)IRAM_BASE, 0x8000); - volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); + // Set SD card initialization info. + nyx_str->info.magic = NYX_NEW_INFO; + nyx_str->info.sd_init = sd_get_mode(); + + // Set SD card error info. + u16 *sd_errors = sd_get_error_count(); + for (u32 i = 0; i < 3; i++) + nyx_str->info.sd_errors[i] = sd_errors[i]; + + reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); memcpy((u8 *)nyx_str->hekate, (u8 *)reloc->start, reloc->end - reloc->start); - void (*nyx_ptr)() = (void *)nyx; + // Do one last training. + minerva_periodic_training(); bpmp_mmu_disable(); bpmp_clk_rate_set(BPMP_CLK_NORMAL); - minerva_periodic_training(); - // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. + // Some cards (Sandisk U1), do not like a fast power cycle. sdmmc_storage_init_wait_sd(); + void (*nyx_ptr)() = (void *)nyx; (*nyx_ptr)(); } -static ini_sec_t *get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry) +static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path) { ini_sec_t *cfg_sec = NULL; @@ -776,39 +694,56 @@ static ini_sec_t *get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomE else break; } - if (!strcmp("logopath", kv->key)) + if (!strcmp("emupath", kv->key)) + *emummc_path = kv->val; + else if (!strcmp("logopath", kv->key)) *bootlogoCustomEntry = kv->val; - if (!strcmp("emummc_force_disable", kv->key)) + else if (!strcmp("emummc_force_disable", kv->key)) h_cfg.emummc_force_disable = atoi(kv->val); } if (!cfg_sec) { - *bootlogoCustomEntry = NULL; + *emummc_path = NULL; + *bootlogoCustomEntry = NULL; h_cfg.emummc_force_disable = false; } return cfg_sec; } -static void _auto_launch_firmware() +static void _bootloader_corruption_protect() { - if(b_cfg.extra_cfg & EXTRA_CFG_NYX_DUMP) + FILINFO fno; + if (!f_stat("bootloader", &fno)) { - if (!h_cfg.sept_run) - EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD; - check_sept(NULL); + if (!h_cfg.bootprotect && (fno.fattrib & AM_ARC)) + f_chmod("bootloader", 0, AM_ARC); + else if (h_cfg.bootprotect && !(fno.fattrib & AM_ARC)) + f_chmod("bootloader", AM_ARC, AM_ARC); } +} - if (!h_cfg.sept_run) - auto_launch_update(); - - u8 *BOOTLOGO = NULL; - char *payload_path = NULL; - u32 btn = 0; - bool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN); - if (boot_from_id) - b_cfg.id[7] = 0; +static void _check_for_updated_bootloader() +{ + // Check if already chainloaded update and clear flag. Otherwise check for updates. + if (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD) + EMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD; + else + { + // Check if update.bin exists and is newer and launch it. Otherwise create it. + if (!f_stat("bootloader/update.bin", NULL)) + _launch_payload("bootloader/update.bin", true, false); + else + { + u8 *buf = zalloc(0x200); + is_ipl_updated(buf, "bootloader/update.bin", true); + free(buf); + } + } +} +static void _auto_launch() +{ struct _bmp_data { u32 size; @@ -819,167 +754,174 @@ static void _auto_launch_firmware() u32 pos_y; }; - struct _bmp_data bmpData; - bool bootlogoFound = false; + u32 boot_wait = h_cfg.bootwait; + u32 boot_entry_id = 0; + ini_sec_t *cfg_sec = NULL; + char *emummc_path = NULL; char *bootlogoCustomEntry = NULL; + bool config_entry_found = false; + + _check_for_updated_bootloader(); + + bool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN); + if (boot_from_id) + b_cfg.id[7] = 0; if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH)) gfx_con.mute = true; - ini_sec_t *cfg_sec = NULL; LIST_INIT(ini_sections); LIST_INIT(ini_list_sections); - if (sd_mount()) - { - if (f_stat("bootloader/hekate_ipl.ini", NULL)) - create_config_entry(); + // Load emuMMC configuration. + emummc_load_cfg(); - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + // Parse hekate main configuration. + if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + goto out; // Can't load hekate_ipl.ini. + + // Load configuration. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) { - u32 configEntry = 0; - u32 boot_entry_id = 0; - - // Load configuration. - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + if (!config_entry_found && !strcmp(ini_sec->name, "config")) { - // Skip other ini entries for autoboot. - if (ini_sec->type == INI_CHOICE) + config_entry_found = true; + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) { - if (!strcmp(ini_sec->name, "config")) - { - configEntry = 1; - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - if (!strcmp("autoboot", kv->key)) - h_cfg.autoboot = atoi(kv->val); - else if (!strcmp("autoboot_list", kv->key)) - h_cfg.autoboot_list = atoi(kv->val); - else if (!strcmp("bootwait", kv->key)) - h_cfg.bootwait = atoi(kv->val); - else if (!strcmp("verification", kv->key)) - h_cfg.verification = atoi(kv->val); - else if (!strcmp("backlight", kv->key)) - h_cfg.backlight = atoi(kv->val); - else if (!strcmp("autohosoff", kv->key)) - h_cfg.autohosoff = atoi(kv->val); - else if (!strcmp("autonogc", kv->key)) - h_cfg.autonogc = atoi(kv->val); - else if (!strcmp("updater2p", kv->key)) - h_cfg.updater2p = atoi(kv->val); - else if (!strcmp("brand", kv->key)) - { - h_cfg.brand = malloc(strlen(kv->val) + 1); - strcpy(h_cfg.brand, kv->val); - } - else if (!strcmp("tagline", kv->key)) - { - h_cfg.tagline = malloc(strlen(kv->val) + 1); - strcpy(h_cfg.tagline, kv->val); - } - } - boot_entry_id++; - - // Override autoboot, otherwise save it for a possbile sept run. - if (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN) - { - h_cfg.autoboot = b_cfg.autoboot; - h_cfg.autoboot_list = b_cfg.autoboot_list; - } - else - { - b_cfg.autoboot = h_cfg.autoboot; - b_cfg.autoboot_list = h_cfg.autoboot_list; - } - - continue; - } - - if (boot_from_id) - cfg_sec = get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry); - else if (h_cfg.autoboot == boot_entry_id && configEntry) - { - cfg_sec = ini_sec; - LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) - { - if (!strcmp("logopath", kv->key)) - bootlogoCustomEntry = kv->val; - if (!strcmp("emummc_force_disable", kv->key)) - h_cfg.emummc_force_disable = atoi(kv->val); - } - } - if (cfg_sec) - break; - boot_entry_id++; + if (!strcmp("autoboot", kv->key)) + h_cfg.autoboot = atoi(kv->val); + else if (!strcmp("autoboot_list", kv->key)) + h_cfg.autoboot_list = atoi(kv->val); + else if (!strcmp("bootwait", kv->key)) + boot_wait = atoi(kv->val); + else if (!strcmp("backlight", kv->key)) + h_cfg.backlight = atoi(kv->val); + else if (!strcmp("noticker", kv->key)) + h_cfg.noticker = atoi(kv->val); + else if (!strcmp("autohosoff", kv->key)) + h_cfg.autohosoff = atoi(kv->val); + else if (!strcmp("autonogc", kv->key)) + h_cfg.autonogc = atoi(kv->val); + else if (!strcmp("updater2p", kv->key)) + h_cfg.updater2p = atoi(kv->val); + else if (!strcmp("bootprotect", kv->key)) + h_cfg.bootprotect = atoi(kv->val); } - } + boot_entry_id++; - if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)) - check_power_off_from_hos(); - - if (h_cfg.autoboot_list || (boot_from_id && !cfg_sec)) - { - if (boot_from_id && cfg_sec) - goto skip_list; - - cfg_sec = NULL; - boot_entry_id = 1; - bootlogoCustomEntry = NULL; - - if (ini_parse(&ini_list_sections, "bootloader/ini", true)) + // Override autoboot. + if (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN) { - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link) - { - if (ini_sec_list->type == INI_CHOICE) - { - if (!strcmp(ini_sec_list->name, "config")) - continue; - - if (boot_from_id) - cfg_sec = get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry); - else if (h_cfg.autoboot == boot_entry_id) - { - h_cfg.emummc_force_disable = false; - cfg_sec = ini_sec_list; - LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) - { - if (!strcmp("logopath", kv->key)) - bootlogoCustomEntry = kv->val; - if (!strcmp("emummc_force_disable", kv->key)) - h_cfg.emummc_force_disable = atoi(kv->val); - } - } - if (cfg_sec) - break; - boot_entry_id++; - } - } - + h_cfg.autoboot = b_cfg.autoboot; + h_cfg.autoboot_list = b_cfg.autoboot_list; } - } -skip_list: - // Add missing configuration entry. - if (!configEntry) - create_config_entry(); + // Apply bootloader protection against corruption. + _bootloader_corruption_protect(); - if (!cfg_sec) - goto out; // No configurations or auto boot is disabled. + // If ini list, exit here. + if (!boot_from_id && h_cfg.autoboot_list) + break; + + continue; + } + + if (boot_from_id) + cfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path); + else if (h_cfg.autoboot == boot_entry_id && config_entry_found) + { + cfg_sec = ini_sec; + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) + { + if (!strcmp("logopath", kv->key)) + bootlogoCustomEntry = kv->val; + else if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; + else if (!strcmp("emummc_force_disable", kv->key)) + h_cfg.emummc_force_disable = atoi(kv->val); + else if (!strcmp("bootwait", kv->key)) + boot_wait = atoi(kv->val); + } + } + if (cfg_sec) + break; + boot_entry_id++; } - else - goto out; // Can't load hekate_ipl.ini. } - else - goto out; - u8 *bitmap = NULL; - if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && h_cfg.bootwait && !h_cfg.sept_run) + if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)) + _check_power_off_from_hos(); + + if (h_cfg.autoboot_list || (boot_from_id && !cfg_sec)) { - if (bootlogoCustomEntry) // Check if user set custom logo path at the boot entry. - bitmap = (u8 *)sd_file_read(bootlogoCustomEntry, NULL); + if (boot_from_id && cfg_sec) + goto skip_list; - if (!bitmap) // Custom entry bootlogo not found, trying default custom one. - bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp", NULL); + cfg_sec = NULL; + boot_entry_id = 1; + bootlogoCustomEntry = NULL; + + if (!ini_parse(&ini_list_sections, "bootloader/ini", true)) + goto skip_list; + + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link) + { + if (ini_sec_list->type != INI_CHOICE) + continue; + + if (!strcmp(ini_sec_list->name, "config")) + continue; + + if (boot_from_id) + cfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path); + else if (h_cfg.autoboot == boot_entry_id) + { + h_cfg.emummc_force_disable = false; + cfg_sec = ini_sec_list; + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) + { + if (!strcmp("logopath", kv->key)) + bootlogoCustomEntry = kv->val; + else if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; + else if (!strcmp("emummc_force_disable", kv->key)) + h_cfg.emummc_force_disable = atoi(kv->val); + else if (!strcmp("bootwait", kv->key)) + boot_wait = atoi(kv->val); + } + } + if (cfg_sec) + break; + boot_entry_id++; + } + } + +skip_list: + if (!cfg_sec) + goto out; // No configurations or auto boot is disabled. + + // Check if entry is payload or l4t special case. + char *special_path = ini_check_special_section(cfg_sec); + + if ((!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && boot_wait) || // Conditional for HOS/Payload. + (special_path && special_path == (char *)-1)) // Always show for L4T. + { + u32 fsize; + u8 *logo_buf = NULL; + u8 *bitmap = NULL; + struct _bmp_data bmpData; + bool bootlogoFound = false; + + // Check if user set custom logo path at the boot entry. + if (bootlogoCustomEntry) + bitmap = (u8 *)sd_file_read(bootlogoCustomEntry, &fsize); + + // Custom entry bootlogo not found, trying default custom one. + if (!bitmap) + bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp", &fsize); if (bitmap) { @@ -999,18 +941,18 @@ skip_list: bmpData.size_x <= 720 && bmpData.size_y <= 1280) { - if ((bmpData.size - bmpData.offset) <= 0x400000) + if (bmpData.size <= fsize && ((bmpData.size - bmpData.offset) < SZ_4M)) { // Avoid unaligned access from BM 2-byte MAGIC and remove header. - BOOTLOGO = (u8 *)malloc(0x400000); - memcpy(BOOTLOGO, bitmap + bmpData.offset, bmpData.size - bmpData.offset); + logo_buf = (u8 *)malloc(SZ_4M); + memcpy(logo_buf, bitmap + bmpData.offset, bmpData.size - bmpData.offset); free(bitmap); // Center logo if res < 720x1280. bmpData.pos_x = (720 - bmpData.size_x) >> 1; bmpData.pos_y = (1280 - bmpData.size_y) >> 1; // Get background color from 1st pixel. if (bmpData.size_x < 720 || bmpData.size_y < 1280) - gfx_clear_color(*(u32 *)BOOTLOGO); + gfx_clear_color(*(u32 *)logo_buf); bootlogoFound = true; } @@ -1019,50 +961,67 @@ skip_list: free(bitmap); } + // Clamp value to default if it exceeds 20s to protect against corruption. + if (boot_wait > 20) + boot_wait = 3; + // Render boot logo. if (bootlogoFound) { - gfx_render_bmp_argb((u32 *)BOOTLOGO, bmpData.size_x, bmpData.size_y, + gfx_render_bmp_argb((u32 *)logo_buf, bmpData.size_x, bmpData.size_y, bmpData.pos_x, bmpData.pos_y); + free(logo_buf); + + // Do animated waiting before booting. If VOL- is pressed go into bootloader menu. + if (render_ticker(boot_wait, h_cfg.backlight, h_cfg.noticker)) + goto out; } else { - gfx_clear_grey(0x1B); - BOOTLOGO = (void *)malloc(0x4000); - blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO); - gfx_set_rect_grey(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544); + // Do animated waiting before booting. If VOL- is pressed go into bootloader menu. + if (render_ticker_logo(boot_wait, h_cfg.backlight)) + goto out; } - free(BOOTLOGO); } if (b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) display_backlight_brightness(h_cfg.backlight, 0); - else if (!h_cfg.sept_run && h_cfg.bootwait) - display_backlight_brightness(h_cfg.backlight, 1000); + else if (btn_read_vol() == BTN_VOL_DOWN) // 0s bootwait VOL- check. + goto out; - // Wait before booting. If VOL- is pressed go into bootloader menu. - if (!h_cfg.sept_run && !(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH)) + if (special_path) { - btn = btn_wait_timeout(h_cfg.bootwait * 1000, BTN_VOL_DOWN | BTN_SINGLE); - - if (btn & BTN_VOL_DOWN) - goto out; - } - - payload_path = ini_check_payload_section(cfg_sec); - - if (payload_path) - { - launch_payload(payload_path, false); - free(payload_path); + // Try to launch Payload or L4T. + if (special_path != (char *)-1) + _launch_payload(special_path, false, false); + else + launch_l4t(cfg_sec, h_cfg.autoboot, h_cfg.autoboot_list, h_cfg.t210b01); + goto error; } else { - check_sept(cfg_sec); + if (b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC) + emummc_set_path(b_cfg.emummc_path); + else if (emummc_path && !emummc_set_path(emummc_path)) + { + gfx_con.mute = false; + EPRINTF("emupath is wrong!"); + goto wrong_emupath; + } + hos_launch(cfg_sec); - EPRINTF("\nFailed to launch HOS!"); +wrong_emupath: + if (emummc_path || b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC) + { + sd_mount(); + emummc_load_cfg(); // Reload emuMMC config in case of emupath. + } + +error: + gfx_con.mute = false; gfx_printf("\nPress any key...\n"); + display_backlight_brightness(h_cfg.backlight, 1000); msleep(500); btn_wait(); } @@ -1071,84 +1030,331 @@ out: gfx_con.mute = false; // Clear boot reasons from binary. - if (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) + if (b_cfg.boot_cfg & (BOOT_CFG_FROM_ID | BOOT_CFG_TO_EMUMMC)) memset(b_cfg.xt_str, 0, sizeof(b_cfg.xt_str)); - b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH | BOOT_CFG_FROM_ID); h_cfg.emummc_force_disable = false; - nyx_load_run(); + // L4T: Clear custom boot mode flags from PMC_SCRATCH0. + PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_CUSTOM_ALL; - sd_unmount(); + _nyx_load_run(); } -static void _patched_rcm_protection() -{ - sdmmc_storage_t storage; - sdmmc_t sdmmc; +#define EXCP_EN_ADDR 0x4003FFFC +#define EXCP_MAGIC 0x30505645 // "EVP0". +#define EXCP_TYPE_ADDR 0x4003FFF8 +#define EXCP_TYPE_RESET 0x545352 // "RST". +#define EXCP_TYPE_UNDEF 0x464455 // "UDF". +#define EXCP_TYPE_PABRT 0x54424150 // "PABT". +#define EXCP_TYPE_DABRT 0x54424144 // "DABT". +#define EXCP_TYPE_WDT 0x544457 // "WDT". +#define EXCP_LR_ADDR 0x4003FFF4 - h_cfg.rcm_patched = fuse_check_patched_rcm(); +#define PSTORE_LOG_OFFSET 0x180000 +#define PSTORE_RAM_SIG 0x43474244 // "DBGC". - if (!h_cfg.rcm_patched) - return; - - // Check if AutoRCM is enabled and protect from a permanent brick. - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - return; - - u8 *tempbuf = (u8 *)malloc(0x200); - sdmmc_storage_set_mmc_partition(&storage, 1); - - u8 corr_mod_byte0; - int i, sect = 0; - if ((fuse_read_odm(4) & 3) != 3) - corr_mod_byte0 = 0xF7; - else - corr_mod_byte0 = 0x37; - - for (i = 0; i < 4; i++) - { - sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE; - sdmmc_storage_read(&storage, sect, 1, tempbuf); - - // If AutoRCM is enabled, disable it. - if (tempbuf[0x10] != corr_mod_byte0) - { - tempbuf[0x10] = corr_mod_byte0; - - sdmmc_storage_write(&storage, sect, 1, tempbuf); - } - } - - free(tempbuf); - sdmmc_storage_end(&storage); -} +typedef struct _pstore_buf { + u32 sig; + u32 start; + u32 size; +} pstore_buf_t; static void _show_errors() { + u32 *excp_lr = (u32 *)EXCP_LR_ADDR; + u32 *excp_type = (u32 *)EXCP_TYPE_ADDR; + u32 *excp_enabled = (u32 *)EXCP_EN_ADDR; + + u32 panic_status = hw_rst_status & 0xFFFFF; + + // Check for exception error. + if (*excp_enabled == EXCP_MAGIC) + h_cfg.errors |= ERR_EXCEPTION; + + // Check for L4T kernel panic. + if (PMC(APBDEV_PMC_SCRATCH37) == PMC_SCRATCH37_KERNEL_PANIC_MAGIC) + { + // Set error and clear flag. + h_cfg.errors |= ERR_L4T_KERNEL; + PMC(APBDEV_PMC_SCRATCH37) = 0; + } + + // Check for watchdog panic. + if (hw_rst_reason == PMC_RST_STATUS_WATCHDOG && panic_status && + panic_status <= 0xFF && panic_status != 0x20 && panic_status != 0x21) + { + h_cfg.errors |= ERR_PANIC_CODE; + } + + // Check if we had a panic while in CFW. + secmon_exo_check_panic(); + + // Handle errors. if (h_cfg.errors) { gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - display_backlight_brightness(h_cfg.backlight, 1000); + display_backlight_brightness(150, 1000); + + if (h_cfg.errors & ERR_SD_BOOT_EN) + { + WPRINTF("Failed to init or mount SD!\n"); + + // Clear the module bits as to not cram the error screen. + h_cfg.errors &= ~(ERR_LIBSYS_LP0 | ERR_LIBSYS_MTC); + } if (h_cfg.errors & ERR_LIBSYS_LP0) - WPRINTF("Missing LP0 (sleep mode) library!\n"); - if (h_cfg.errors & ERR_SYSOLD_MTC) - WPRINTF("Missing or old Minerva library!\n"); + WPRINTF("Missing LP0 (sleep) lib!\n"); + if (h_cfg.errors & ERR_LIBSYS_MTC) + WPRINTF("Missing Minerva lib!\n"); + + if (h_cfg.errors & (ERR_LIBSYS_LP0 | ERR_LIBSYS_MTC)) + WPRINTF("\nUpdate bootloader folder!\n\n"); + + if (h_cfg.errors & ERR_EXCEPTION) + { + WPRINTFARGS("hekate exception occurred (LR %08X):\n", *excp_lr); + switch (*excp_type) + { + case EXCP_TYPE_WDT: + WPRINTF("Hang detected in LP0/Minerva!"); + break; + case EXCP_TYPE_RESET: + WPRINTF("RESET"); + break; + case EXCP_TYPE_UNDEF: + WPRINTF("UNDEF"); + break; + case EXCP_TYPE_PABRT: + WPRINTF("PABRT"); + break; + case EXCP_TYPE_DABRT: + WPRINTF("DABRT"); + break; + } + gfx_puts("\n"); + + // Clear the exception. + *excp_enabled = 0; + *excp_type = 0; + } + + if (h_cfg.errors & ERR_L4T_KERNEL) + { + WPRINTF("L4T Kernel panic occurred!\n"); + if (!(h_cfg.errors & ERR_SD_BOOT_EN)) + { + if (!sd_save_to_file((void *)PSTORE_ADDR, PSTORE_SZ, "L4T_panic.bin")) + WPRINTF("PSTORE saved to L4T_panic.bin"); + pstore_buf_t *buf = (pstore_buf_t *)(PSTORE_ADDR + PSTORE_LOG_OFFSET); + if (buf->sig == PSTORE_RAM_SIG && buf->size && buf->size < 0x80000) + { + u32 log_offset = PSTORE_ADDR + PSTORE_LOG_OFFSET + sizeof(pstore_buf_t); + if (!sd_save_to_file((void *)log_offset, buf->size, "L4T_panic.txt")) + WPRINTF("Log saved to L4T_panic.txt"); + } + } + gfx_puts("\n"); + } + + if (h_cfg.errors & ERR_PANIC_CODE) + { + u32 r = (hw_rst_status >> 20) & 0xF; + u32 g = (hw_rst_status >> 24) & 0xF; + u32 b = (hw_rst_status >> 28) & 0xF; + r = (r << 16) | (r << 20); + g = (g << 8) | (g << 12); + b = (b << 0) | (b << 4); + u32 color = r | g | b; + + WPRINTF("HOS panic occurred!\n"); + gfx_printf("Color: %k####%k, Code: %02X\n\n", color, TXT_CLR_DEFAULT, panic_status); + } - WPRINTF("\nUpdate your bootloader folder!\n\n"); WPRINTF("Press any key..."); - msleep(2000); + msleep(1000); // Guard against injection VOL+. btn_wait(); + msleep(500); // Guard against force menu VOL-. } } +static void _check_low_battery() +{ + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) + goto out; + + int enough_battery; + int batt_volt = 0; + int charge_status = 0; + + // Enable charger in case it's disabled. + bq24193_enable_charger(); + + bq24193_get_property(BQ24193_ChargeStatus, &charge_status); + max17050_get_property(MAX17050_AvgVCELL, &batt_volt); + + enough_battery = charge_status ? 3300 : 3100; + + // If battery voltage is enough, exit. + if (batt_volt > enough_battery || !batt_volt) + goto out; + + // Prepare battery icon resources. + u8 *battery_res = malloc(ALIGN(BATTERY_EMPTY_SIZE, SZ_4K)); + blz_uncompress_srcdest(battery_icons_blz, BATTERY_EMPTY_BLZ_SIZE, battery_res, BATTERY_EMPTY_SIZE); + + u8 *battery_icon = malloc(0x95A); // 21x38x3 + u8 *charging_icon = malloc(0x2F4); // 21x12x3 + u8 *no_charging_icon = zalloc(0x2F4); + + memcpy(charging_icon, battery_res, 0x2F4); + memcpy(battery_icon, battery_res + 0x2F4, 0x95A); + + u32 battery_icon_y_pos = 1280 - 16 - BATTERY_EMPTY_BATT_HEIGHT; + u32 charging_icon_y_pos = 1280 - 16 - BATTERY_EMPTY_BATT_HEIGHT - 12 - BATTERY_EMPTY_CHRG_HEIGHT; + free(battery_res); + + charge_status = !charge_status; + + u32 timer = 0; + bool screen_on = false; + while (true) + { + bpmp_msleep(250); + + // Refresh battery stats. + int current_charge_status = 0; + bq24193_get_property(BQ24193_ChargeStatus, ¤t_charge_status); + max17050_get_property(MAX17050_AvgVCELL, &batt_volt); + enough_battery = current_charge_status ? 3300 : 3100; + + // If battery voltage is enough, exit. + if (batt_volt > enough_battery) + break; + + // Refresh charging icon. + if (screen_on && (charge_status != current_charge_status)) + { + if (current_charge_status) + gfx_set_rect_rgb(charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos); + else + gfx_set_rect_rgb(no_charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos); + } + + // Check if it's time to turn off display. + if (screen_on && timer < get_tmr_ms()) + { + // If battery is not charging, power off. + if (!current_charge_status) + { + max77620_low_battery_monitor_config(true); + + // Handle full hw deinit and power off. + power_set_state(POWER_OFF_RESET); + } + + // If charging, just disable display. + display_end(); + screen_on = false; + } + + // Check if charging status changed or Power button was pressed and enable display. + if ((charge_status != current_charge_status) || (btn_wait_timeout_single(0, BTN_POWER) & BTN_POWER)) + { + if (!screen_on) + { + display_init(); + u32 *fb = display_init_window_a_pitch(); + gfx_init_ctxt(fb, 720, 1280, 720); + + gfx_set_rect_rgb(battery_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_BATT_HEIGHT, 16, battery_icon_y_pos); + if (current_charge_status) + gfx_set_rect_rgb(charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos); + else + gfx_set_rect_rgb(no_charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos); + + display_backlight_pwm_init(); + display_backlight_brightness(100, 1000); + + screen_on = true; + } + + timer = get_tmr_ms() + 15000; + } + + // Check if forcefully continuing. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + break; + + charge_status = current_charge_status; + } + + if (screen_on) + display_end(); + + free(battery_icon); + free(charging_icon); + free(no_charging_icon); + +out: + // Re enable Low Battery Monitor shutdown. + max77620_low_battery_monitor_config(true); +} + +static void _r2c_get_config_t210b01() +{ + rtc_reboot_reason_t rr; + if (!max77620_rtc_get_reboot_reason(&rr)) + return; + + // Check if reason is actually set. + if (rr.dec.reason != REBOOT_REASON_NOP) + { + // Clear boot storage. + memset(&b_cfg, 0, sizeof(boot_cfg_t)); + + // Enable boot storage. + b_cfg.boot_cfg |= BOOT_CFG_AUTOBOOT_EN; + } + + switch (rr.dec.reason) + { + case REBOOT_REASON_NOP: + break; + case REBOOT_REASON_REC: + PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY; + case REBOOT_REASON_SELF: + b_cfg.autoboot = rr.dec.autoboot_idx; + b_cfg.autoboot_list = rr.dec.autoboot_list; + break; + case REBOOT_REASON_MENU: + break; + case REBOOT_REASON_UMS: + b_cfg.extra_cfg |= EXTRA_CFG_NYX_UMS; + b_cfg.ums = rr.dec.ums_idx; + break; + case REBOOT_REASON_PANIC: + PMC(APBDEV_PMC_SCRATCH37) = PMC_SCRATCH37_KERNEL_PANIC_MAGIC; + break; + } +} + +static void _ipl_reload() +{ + hw_deinit(false, 0); + + // Reload hekate. + void (*ipl_ptr)() = (void *)IPL_LOAD_ADDR; + (*ipl_ptr)(); +} + static void _about() { static const char credits[] = - "\nhekate (c) 2018 naehrwert, st4rk\n\n" - "CTCaer mod (c) 2018 CTCaer\n" + "\nhekate (c) 2018, naehrwert, st4rk\n\n" + " (c) 2018-2025, CTCaer\n\n" " ___________________________________________\n\n" "Thanks to: %kderrek, nedwill, plutoo,\n" " shuffle2, smea, thexyz, yellows8%k\n" @@ -1157,15 +1363,16 @@ static void _about() " Shiny Quagsire, WinterMute\n" " ___________________________________________\n\n" "Open source and free packages used:\n\n" - " - FatFs R0.13b,\n" - " Copyright (c) 2018, ChaN\n\n" - " - bcl-1.2.0,\n" - " Copyright (c) 2003-2006, Marcus Geelnard\n\n" - " - Atmosphere (Exo st/types, prc id patches),\n" - " Copyright (c) 2018-2019, Atmosphere-NX\n\n" - " - elfload,\n" - " Copyright (c) 2014, Owen Shepherd\n" - " Copyright (c) 2018, M4xw\n" + " - FatFs R0.13c\n" + " (c) 2006-2018, ChaN\n" + " (c) 2018-2022, CTCaer\n\n" + " - bcl-1.2.0\n" + " (c) 2003-2006, Marcus Geelnard\n\n" + " - blz\n" + " (c) 2018, SciresM\n\n" + " - elfload\n" + " (c) 2014, Owen Shepherd\n" + " (c) 2018, M4xw\n" " ___________________________________________\n\n"; static const char octopus[] = " %k___\n" @@ -1190,178 +1397,141 @@ static void _about() gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); - gfx_printf(credits, 0xFF00CCFF, 0xFFCCCCCC); + gfx_printf(credits, TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); gfx_con.fntsz = 8; - gfx_printf(octopus, 0xFF00CCFF, 0xFF00FFCC, 0xFF00CCFF, 0xFFCCCCCC); + gfx_printf(octopus, TXT_CLR_CYAN_L, TXT_CLR_TURQUOISE, TXT_CLR_CYAN_L, TXT_CLR_DEFAULT); btn_wait(); } -ment_t ment_options[] = { - MDEF_BACK(), - MDEF_CHGLINE(), - MDEF_HANDLER("Auto boot", config_autoboot), - MDEF_HANDLER("Boot time delay", config_bootdelay), - MDEF_HANDLER("Auto NoGC", config_nogc), - MDEF_HANDLER("Auto HOS power off", config_auto_hos_poweroff), - MDEF_HANDLER("Backlight", config_backlight), - MDEF_END() -}; - -menu_t menu_options = { ment_options, "Launch Options", 0, 0 }; - ment_t ment_cinfo[] = { MDEF_BACK(), MDEF_CHGLINE(), - MDEF_CAPTION("---- SoC Info ----", 0xFF0AB9E6), - MDEF_HANDLER("Ipatches & bootrom info", bootrom_ipatches_info), - MDEF_HANDLER("Print fuse info", print_fuseinfo), - MDEF_HANDLER("Print kfuse info", print_kfuseinfo), - MDEF_HANDLER("Print TSEC keys", print_tsec_key), + MDEF_CAPTION("---- SoC Info ----", TXT_CLR_CYAN_L), + MDEF_HANDLER("Fuses", print_fuseinfo), MDEF_CHGLINE(), - MDEF_CAPTION("-- Storage Info --", 0xFF0AB9E6), - MDEF_HANDLER("Print eMMC info", print_mmc_info), - MDEF_HANDLER("Print SD Card info", print_sdcard_info), + MDEF_CAPTION("-- Storage Info --", TXT_CLR_CYAN_L), + MDEF_HANDLER("eMMC", print_mmc_info), + MDEF_HANDLER("SD Card", print_sdcard_info), MDEF_CHGLINE(), - MDEF_CAPTION("------ Misc ------", 0xFF0AB9E6), - MDEF_HANDLER("Print battery info", print_battery_info), + MDEF_CAPTION("------ Misc ------", TXT_CLR_CYAN_L), + MDEF_HANDLER("Battery", print_battery_info), MDEF_END() }; menu_t menu_cinfo = { ment_cinfo, "Console Info", 0, 0 }; -ment_t ment_restore[] = { - MDEF_BACK(), - MDEF_CHGLINE(), - MDEF_CAPTION("------ Full --------", 0xFF0AB9E6), - MDEF_HANDLER("Restore eMMC BOOT0/1", restore_emmc_boot), - MDEF_HANDLER("Restore eMMC RAW GPP", restore_emmc_rawnand), - MDEF_CHGLINE(), - MDEF_CAPTION("-- GPP Partitions --", 0xFF0AB9E6), - MDEF_HANDLER("Restore GPP partitions", restore_emmc_gpp_parts), - MDEF_END() -}; - -menu_t menu_restore = { ment_restore, "Restore Options", 0, 0 }; - -ment_t ment_backup[] = { - MDEF_BACK(), - MDEF_CHGLINE(), - MDEF_CAPTION("------ Full --------", 0xFF0AB9E6), - MDEF_HANDLER("Backup eMMC BOOT0/1", dump_emmc_boot), - MDEF_HANDLER("Backup eMMC RAW GPP", dump_emmc_rawnand), - MDEF_CHGLINE(), - MDEF_CAPTION("-- GPP Partitions --", 0xFF0AB9E6), - MDEF_HANDLER("Backup eMMC SYS", dump_emmc_system), - MDEF_HANDLER("Backup eMMC USER", dump_emmc_user), - MDEF_END() -}; - -menu_t menu_backup = { ment_backup, "Backup Options", 0, 0 }; - ment_t ment_tools[] = { MDEF_BACK(), MDEF_CHGLINE(), - MDEF_CAPTION("-- Backup & Restore --", 0xFF0AB9E6), - MDEF_MENU("Backup", &menu_backup), - MDEF_MENU("Restore", &menu_restore), - MDEF_HANDLER("Verification options", config_verification), - MDEF_CHGLINE(), - MDEF_CAPTION("-------- Misc --------", 0xFF0AB9E6), - MDEF_HANDLER("Dump package1/2", dump_packages12), - //MDEF_HANDLER("Fix archive bit (except Nintendo)", fix_sd_all_attr), - //MDEF_HANDLER("Fix archive bit (Nintendo only)", fix_sd_nin_attr), - //MDEF_HANDLER("Fix fuel gauge configuration", fix_fuel_gauge_configuration), - //MDEF_HANDLER("Reset all battery cfg", reset_pmic_fuel_gauge_charger_config), - MDEF_CHGLINE(), - MDEF_CAPTION("-------- Other -------", 0xFFFFDD00), + MDEF_CAPTION("-------- Other -------", TXT_CLR_WARNING), MDEF_HANDLER("AutoRCM", menu_autorcm), MDEF_END() }; menu_t menu_tools = { ment_tools, "Tools", 0, 0 }; +power_state_t STATE_POWER_OFF = POWER_OFF_RESET; +power_state_t STATE_REBOOT_RCM = REBOOT_RCM; +power_state_t STATE_REBOOT_BYPASS_FUSES = REBOOT_BYPASS_FUSES; + ment_t ment_top[] = { - MDEF_HANDLER("Launch", launch_firmware), - MDEF_MENU("Options", &menu_options), - MDEF_CAPTION("---------------", 0xFF444444), - MDEF_MENU("Tools", &menu_tools), + MDEF_HANDLER("Launch", _launch_config), + MDEF_CAPTION("---------------", TXT_CLR_GREY_DM), + MDEF_MENU("Tools", &menu_tools), MDEF_MENU("Console info", &menu_cinfo), - MDEF_CAPTION("---------------", 0xFF444444), - MDEF_HANDLER("Reboot (Normal)", reboot_normal), - MDEF_HANDLER("Reboot (RCM)", reboot_rcm), - MDEF_HANDLER("Power off", power_off), - MDEF_CAPTION("---------------", 0xFF444444), + MDEF_CAPTION("---------------", TXT_CLR_GREY_DM), + MDEF_HANDLER("Reload", _ipl_reload), + MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex), + MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex), + MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex), + MDEF_CAPTION("---------------", TXT_CLR_GREY_DM), MDEF_HANDLER("About", _about), MDEF_END() }; -menu_t menu_top = { ment_top, "hekate - CTCaer mod v5.1.2", 0, 0 }; +menu_t menu_top = { ment_top, "hekate v6.3.1", 0, 0 }; extern void pivot_stack(u32 stack_top); void ipl_main() { // Do initial HW configuration. This is compatible with consecutive reruns without a reset. - config_hw(); + hw_init(); - // Pivot the stack so we have enough space. - pivot_stack(IPL_STACK_TOP); + // Pivot the stack under IPL. (Only max 4KB is needed). + pivot_stack(IPL_LOAD_ADDR); - // Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. - heap_init(IPL_HEAP_START); + // Place heap at a place outside of L4T/HOS configuration and binaries. + heap_init((void *)IPL_HEAP_START); #ifdef DEBUG_UART_PORT - uart_send(DEBUG_UART_PORT, (u8 *)"Hekate: Hello!\r\n", 16); - uart_wait_idle(DEBUG_UART_PORT, UART_TX_IDLE); + uart_send(DEBUG_UART_PORT, (u8 *)"hekate: Hello!\r\n", 16); + uart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE); #endif + // Check if battery is enough. + _check_low_battery(); + // Set bootloader's default configuration. set_default_configuration(); - sd_mount(); + // Prep RTC regs for read. Needed for T210B01 R2C. + max77620_rtc_prep_read(); + + // Initialize display. + display_init(); + + // Overclock BPMP. + bpmp_clk_rate_set(h_cfg.t210b01 ? BPMP_CLK_DEFAULT_BOOST : BPMP_CLK_LOWER_BOOST); + + // Mount SD Card. + h_cfg.errors |= !sd_mount() ? ERR_SD_BOOT_EN : 0; + + // Check if watchdog was fired previously. + if (watchdog_fired()) + goto skip_lp0_minerva_config; + + // Enable watchdog protection to avoid SD corruption based hanging in LP0/Minerva config. + watchdog_start(5000000 / 2, TIMER_FIQENABL_EN); // 5 seconds. // Save sdram lp0 config. - if (!ianos_loader(false, "bootloader/sys/libsys_lp0.bso", DRAM_LIB, (void *)sdram_get_params_patched())) + void *sdram_params = h_cfg.t210b01 ? sdram_get_params_t210b01() : sdram_get_params_patched(); + if (!ianos_loader("bootloader/sys/libsys_lp0.bso", DRAM_LIB, sdram_params)) h_cfg.errors |= ERR_LIBSYS_LP0; // Train DRAM and switch to max frequency. - if (minerva_init()) - h_cfg.errors |= ERR_SYSOLD_MTC; + if (minerva_init()) //!TODO: Add Tegra210B01 support to minerva. + h_cfg.errors |= ERR_LIBSYS_MTC; - display_init(); + // Disable watchdog protection. + watchdog_end(); - u32 *fb = display_init_framebuffer(); +skip_lp0_minerva_config: + // Initialize display window, backlight and gfx console. + u32 *fb = display_init_window_a_pitch(); gfx_init_ctxt(fb, 720, 1280, 720); - -#ifdef MENU_LOGO_ENABLE - Kc_MENU_LOGO = (u8 *)malloc(ALIGN(SZ_MENU_LOGO, 0x1000)); - blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO); -#endif - gfx_con_init(); + // Initialize backlight PWM. display_backlight_pwm_init(); //display_backlight_brightness(h_cfg.backlight, 1000); - // Overclock BPMP. - bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + // Get R2C config from RTC. + if (h_cfg.t210b01) + _r2c_get_config_t210b01(); - // Check if we had a panic while in CFW. - secmon_exo_check_panic(); - - // Check if RCM is patched and protect from a possible brick. - _patched_rcm_protection(); - - // Load emuMMC configuration from SD. - emummc_load_cfg(); - - // Show library errors. + // Show exceptions, HOS errors, library errors and L4T kernel panics. _show_errors(); // Load saved configuration and auto boot if enabled. - _auto_launch_firmware(); + if (!(h_cfg.errors & ERR_SD_BOOT_EN)) + _auto_launch(); + // Failed to launch Nyx, unmount SD Card. + sd_end(); + + // Set ram to a freq that doesn't need periodic training. minerva_change_freq(FREQ_800); while (true) diff --git a/bootloader/mem/emc.h b/bootloader/mem/emc.h deleted file mode 100644 index bfce612..0000000 --- a/bootloader/mem/emc.h +++ /dev/null @@ -1,667 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra21_emc.h - * - * Copyright (c) 2014-2015, 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 _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 -#define EMC_REFCTRL 0x20 -#define EMC_PIN 0x24 -#define EMC_TIMING_CONTROL 0x28 -#define EMC_RC 0x2c -#define EMC_RFC 0x30 -#define EMC_RFCPB 0x590 -#define EMC_RAS 0x34 -#define EMC_RP 0x38 -#define EMC_R2W 0x3c -#define EMC_W2R 0x40 -#define EMC_R2P 0x44 -#define EMC_W2P 0x48 -#define EMC_CCDMW 0x5c0 -#define EMC_RD_RCD 0x4c -#define EMC_WR_RCD 0x50 -#define EMC_RRD 0x54 -#define EMC_REXT 0x58 -#define EMC_WDV 0x5c -#define EMC_QUSE 0x60 -#define EMC_QRST 0x64 -#define EMC_ISSUE_QRST 0x428 -#define EMC_QSAFE 0x68 -#define EMC_RDV 0x6c -#define EMC_REFRESH 0x70 -#define EMC_BURST_REFRESH_NUM 0x74 -#define EMC_PDEX2WR 0x78 -#define EMC_PDEX2RD 0x7c -#define EMC_PDEX2CKE 0x118 -#define EMC_PCHG2PDEN 0x80 -#define EMC_ACT2PDEN 0x84 -#define EMC_AR2PDEN 0x88 -#define EMC_RW2PDEN 0x8c -#define EMC_CKE2PDEN 0x11c -#define EMC_TXSR 0x90 -#define EMC_TCKE 0x94 -#define EMC_TFAW 0x98 -#define EMC_TRPAB 0x9c -#define EMC_TCLKSTABLE 0xa0 -#define EMC_TCLKSTOP 0xa4 -#define EMC_TREFBW 0xa8 -#define EMC_TPPD 0xac -#define EMC_PDEX2MRR 0xb4 -#define EMC_ODT_WRITE 0xb0 -#define EMC_WEXT 0xb8 -#define EMC_RFC_SLR 0xc0 -#define EMC_MRS_WAIT_CNT2 0xc4 -#define EMC_MRS_WAIT_CNT 0xc8 -#define EMC_MRS 0xcc -#define EMC_EMRS 0xd0 -#define EMC_REF 0xd4 -#define EMC_PRE 0xd8 -#define EMC_NOP 0xdc -#define EMC_SELF_REF 0xe0 -#define EMC_DPD 0xe4 -#define EMC_MRW 0xe8 -#define EMC_MRR 0xec -#define EMC_CMDQ 0xf0 -#define EMC_MC2EMCQ 0xf4 -#define EMC_FBIO_SPARE 0x100 -#define EMC_FBIO_CFG5 0x104 -#define EMC_CFG_RSV 0x120 -#define EMC_ACPD_CONTROL 0x124 -#define EMC_MPC 0x128 -#define EMC_EMRS2 0x12c -#define EMC_EMRS3 0x130 -#define EMC_MRW2 0x134 -#define EMC_MRW3 0x138 -#define EMC_MRW4 0x13c -#define EMC_MRW5 0x4a0 -#define EMC_MRW6 0x4a4 -#define EMC_MRW7 0x4a8 -#define EMC_MRW8 0x4ac -#define EMC_MRW9 0x4b0 -#define EMC_MRW10 0x4b4 -#define EMC_MRW11 0x4b8 -#define EMC_MRW12 0x4bc -#define EMC_MRW13 0x4c0 -#define EMC_MRW14 0x4c4 -#define EMC_MRW15 0x4d0 -#define EMC_CFG_SYNC 0x4d4 -#define EMC_CLKEN_OVERRIDE 0x140 -#define EMC_R2R 0x144 -#define EMC_W2W 0x148 -#define EMC_EINPUT 0x14c -#define EMC_EINPUT_DURATION 0x150 -#define EMC_PUTERM_EXTRA 0x154 -#define EMC_TCKESR 0x158 -#define EMC_TPD 0x15c -#define EMC_STAT_CONTROL 0x160 -#define EMC_STAT_STATUS 0x164 -#define EMC_STAT_DRAM_CLOCK_LIMIT_LO 0x19c -#define EMC_STAT_DRAM_CLOCK_LIMIT_HI 0x1a0 -#define EMC_STAT_DRAM_CLOCKS_LO 0x1a4 -#define EMC_STAT_DRAM_CLOCKS_HI 0x1a8 -#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO 0x1ac -#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI 0x1b0 -#define EMC_STAT_DRAM_DEV0_READ_CNT_LO 0x1b4 -#define EMC_STAT_DRAM_DEV0_READ_CNT_HI 0x1b8 -#define EMC_STAT_DRAM_DEV0_READ8_CNT_LO 0x1bc -#define EMC_STAT_DRAM_DEV0_READ8_CNT_HI 0x1c0 -#define EMC_STAT_DRAM_DEV0_WRITE_CNT_LO 0x1c4 -#define EMC_STAT_DRAM_DEV0_WRITE_CNT_HI 0x1c8 -#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO 0x1cc -#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI 0x1d0 -#define EMC_STAT_DRAM_DEV0_REF_CNT_LO 0x1d4 -#define EMC_STAT_DRAM_DEV0_REF_CNT_HI 0x1d8 -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x1dc -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x1e0 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x1e4 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x1e8 -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x1ec -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x1f0 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x1f4 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x1f8 -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x1fc -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x200 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x204 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x208 -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x20c -#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x210 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x214 -#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x218 -#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO 0x21c -#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI 0x220 -#define EMC_STAT_DRAM_DEV0_DSR 0x224 -#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO 0x228 -#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI 0x22c -#define EMC_STAT_DRAM_DEV1_READ_CNT_LO 0x230 -#define EMC_STAT_DRAM_DEV1_READ_CNT_HI 0x234 -#define EMC_STAT_DRAM_DEV1_READ8_CNT_LO 0x238 -#define EMC_STAT_DRAM_DEV1_READ8_CNT_HI 0x23c -#define EMC_STAT_DRAM_DEV1_WRITE_CNT_LO 0x240 -#define EMC_STAT_DRAM_DEV1_WRITE_CNT_HI 0x244 -#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO 0x248 -#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI 0x24c -#define EMC_STAT_DRAM_DEV1_REF_CNT_LO 0x250 -#define EMC_STAT_DRAM_DEV1_REF_CNT_HI 0x254 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x258 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x25c -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x260 -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x264 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x268 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x26c -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x270 -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x274 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x278 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x27c -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x280 -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x284 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x288 -#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x28c -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x290 -#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x294 -#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO 0x298 -#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI 0x29c -#define EMC_STAT_DRAM_DEV1_DSR 0x2a0 -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0xc8c -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0xc90 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0xc94 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0xc98 -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0xc9c -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0xca0 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0xca4 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0xca8 -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0xcac -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0xcb0 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0xcb4 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0xcb8 -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0xcbc -#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0xcc0 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0xcc4 -#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0xcc8 -#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO 0xccc -#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI 0xcd0 -#define EMC_STAT_DRAM_IO_DSR 0xcd4 -#define EMC_AUTO_CAL_CONFIG 0x2a4 -#define EMC_AUTO_CAL_CONFIG2 0x458 -#define EMC_AUTO_CAL_CONFIG3 0x45c -#define EMC_AUTO_CAL_CONFIG4 0x5b0 -#define EMC_AUTO_CAL_CONFIG5 0x5b4 -#define EMC_AUTO_CAL_CONFIG6 0x5cc -#define EMC_AUTO_CAL_CONFIG7 0x574 -#define EMC_AUTO_CAL_CONFIG8 0x2dc -#define EMC_AUTO_CAL_VREF_SEL_0 0x2f8 -#define EMC_AUTO_CAL_VREF_SEL_1 0x300 -#define EMC_AUTO_CAL_INTERVAL 0x2a8 -#define EMC_AUTO_CAL_STATUS 0x2ac -#define EMC_AUTO_CAL_STATUS2 0x3d4 -#define EMC_AUTO_CAL_CHANNEL 0x464 -#define EMC_PMACRO_RX_TERM 0xc48 -#define EMC_PMACRO_DQ_TX_DRV 0xc70 -#define EMC_PMACRO_CA_TX_DRV 0xc74 -#define EMC_PMACRO_CMD_TX_DRV 0xc4c -#define EMC_PMACRO_AUTOCAL_CFG_0 0x700 -#define EMC_PMACRO_AUTOCAL_CFG_1 0x704 -#define EMC_PMACRO_AUTOCAL_CFG_2 0x708 -#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xc78 -#define EMC_PMACRO_ZCTRL 0xc44 -#define EMC_XM2COMPPADCTRL 0x30c -#define EMC_XM2COMPPADCTRL2 0x578 -#define EMC_XM2COMPPADCTRL3 0x2f4 -#define EMC_COMP_PAD_SW_CTRL 0x57c -#define EMC_REQ_CTRL 0x2b0 -#define EMC_EMC_STATUS 0x2b4 -#define EMC_CFG_2 0x2b8 -#define EMC_CFG_DIG_DLL 0x2bc -#define EMC_CFG_DIG_DLL_PERIOD 0x2c0 -#define EMC_DIG_DLL_STATUS 0x2c4 -#define EMC_CFG_DIG_DLL_1 0x2c8 -#define EMC_RDV_MASK 0x2cc -#define EMC_WDV_MASK 0x2d0 -#define EMC_RDV_EARLY_MASK 0x2d4 -#define EMC_RDV_EARLY 0x2d8 -#define EMC_WDV_CHK 0x4e0 -#define EMC_ZCAL_INTERVAL 0x2e0 -#define EMC_ZCAL_WAIT_CNT 0x2e4 -#define EMC_ZCAL_MRW_CMD 0x2e8 -#define EMC_ZQ_CAL 0x2ec -#define EMC_SCRATCH0 0x324 -#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE 0x3c8 -#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3cc -#define EMC_UNSTALL_RW_AFTER_CLKCHANGE 0x3d0 -#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4d8 -#define EMC_SEL_DPD_CTRL 0x3d8 -#define EMC_FDPD_CTRL_DQ 0x310 -#define EMC_FDPD_CTRL_CMD 0x314 -#define EMC_PRE_REFRESH_REQ_CNT 0x3dc -#define EMC_REFCTRL2 0x580 -#define EMC_FBIO_CFG7 0x584 -#define EMC_DATA_BRLSHFT_0 0x588 -#define EMC_DATA_BRLSHFT_1 0x58c -#define EMC_DQS_BRLSHFT_0 0x594 -#define EMC_DQS_BRLSHFT_1 0x598 -#define EMC_CMD_BRLSHFT_0 0x59c -#define EMC_CMD_BRLSHFT_1 0x5a0 -#define EMC_CMD_BRLSHFT_2 0x5a4 -#define EMC_CMD_BRLSHFT_3 0x5a8 -#define EMC_QUSE_BRLSHFT_0 0x5ac -#define EMC_QUSE_BRLSHFT_1 0x5b8 -#define EMC_QUSE_BRLSHFT_2 0x5bc -#define EMC_QUSE_BRLSHFT_3 0x5c4 -#define EMC_FBIO_CFG8 0x5c8 -#define EMC_CMD_MAPPING_CMD0_0 0x380 -#define EMC_CMD_MAPPING_CMD0_1 0x384 -#define EMC_CMD_MAPPING_CMD0_2 0x388 -#define EMC_CMD_MAPPING_CMD1_0 0x38c -#define EMC_CMD_MAPPING_CMD1_1 0x390 -#define EMC_CMD_MAPPING_CMD1_2 0x394 -#define EMC_CMD_MAPPING_CMD2_0 0x398 -#define EMC_CMD_MAPPING_CMD2_1 0x39c -#define EMC_CMD_MAPPING_CMD2_2 0x3a0 -#define EMC_CMD_MAPPING_CMD3_0 0x3a4 -#define EMC_CMD_MAPPING_CMD3_1 0x3a8 -#define EMC_CMD_MAPPING_CMD3_2 0x3ac -#define EMC_CMD_MAPPING_BYTE 0x3b0 -#define EMC_DYN_SELF_REF_CONTROL 0x3e0 -#define EMC_TXSRDLL 0x3e4 -#define EMC_CCFIFO_ADDR 0x3e8 -#define EMC_CCFIFO_DATA 0x3ec -#define EMC_CCFIFO_STATUS 0x3f0 -#define EMC_SWIZZLE_RANK0_BYTE0 0x404 -#define EMC_SWIZZLE_RANK0_BYTE1 0x408 -#define EMC_SWIZZLE_RANK0_BYTE2 0x40c -#define EMC_SWIZZLE_RANK0_BYTE3 0x410 -#define EMC_SWIZZLE_RANK1_BYTE0 0x418 -#define EMC_SWIZZLE_RANK1_BYTE1 0x41c -#define EMC_SWIZZLE_RANK1_BYTE2 0x420 -#define EMC_SWIZZLE_RANK1_BYTE3 0x424 -#define EMC_TR_TIMING_0 0x3b4 -#define EMC_TR_CTRL_0 0x3b8 -#define EMC_TR_CTRL_1 0x3bc -#define EMC_TR_DVFS 0x460 -#define EMC_SWITCH_BACK_CTRL 0x3c0 -#define EMC_TR_RDV 0x3c4 -#define EMC_TR_QPOP 0x3f4 -#define EMC_TR_RDV_MASK 0x3f8 -#define EMC_TR_QSAFE 0x3fc -#define EMC_TR_QRST 0x400 -#define EMC_IBDLY 0x468 -#define EMC_OBDLY 0x46c -#define EMC_TXDSRVTTGEN 0x480 -#define EMC_WE_DURATION 0x48c -#define EMC_WS_DURATION 0x490 -#define EMC_WEV 0x494 -#define EMC_WSV 0x498 -#define EMC_CFG_3 0x49c -#define EMC_CFG_PIPE_2 0x554 -#define EMC_CFG_PIPE_CLK 0x558 -#define EMC_CFG_PIPE_1 0x55c -#define EMC_CFG_PIPE 0x560 -#define EMC_QPOP 0x564 -#define EMC_QUSE_WIDTH 0x568 -#define EMC_PUTERM_WIDTH 0x56c -#define EMC_PROTOBIST_CONFIG_ADR_1 0x5d0 -#define EMC_PROTOBIST_CONFIG_ADR_2 0x5d4 -#define EMC_PROTOBIST_MISC 0x5d8 -#define EMC_PROTOBIST_WDATA_LOWER 0x5dc -#define EMC_PROTOBIST_WDATA_UPPER 0x5e0 -#define EMC_PROTOBIST_RDATA 0x5ec -#define EMC_DLL_CFG_0 0x5e4 -#define EMC_DLL_CFG_1 0x5e8 -#define EMC_TRAINING_CMD 0xe00 -#define EMC_TRAINING_CTRL 0xe04 -#define EMC_TRAINING_STATUS 0xe08 -#define EMC_TRAINING_QUSE_CORS_CTRL 0xe0c -#define EMC_TRAINING_QUSE_FINE_CTRL 0xe10 -#define EMC_TRAINING_QUSE_CTRL_MISC 0xe14 -#define EMC_TRAINING_WRITE_FINE_CTRL 0xe18 -#define EMC_TRAINING_WRITE_CTRL_MISC 0xe1c -#define EMC_TRAINING_WRITE_VREF_CTRL 0xe20 -#define EMC_TRAINING_READ_FINE_CTRL 0xe24 -#define EMC_TRAINING_READ_CTRL_MISC 0xe28 -#define EMC_TRAINING_READ_VREF_CTRL 0xe2c -#define EMC_TRAINING_CA_FINE_CTRL 0xe30 -#define EMC_TRAINING_CA_CTRL_MISC 0xe34 -#define EMC_TRAINING_CA_CTRL_MISC1 0xe38 -#define EMC_TRAINING_CA_VREF_CTRL 0xe3c -#define EMC_TRAINING_CA_TADR_CTRL 0xe40 -#define EMC_TRAINING_SETTLE 0xe44 -#define EMC_TRAINING_DEBUG_CTRL 0xe48 -#define EMC_TRAINING_DEBUG_DQ0 0xe4c -#define EMC_TRAINING_DEBUG_DQ1 0xe50 -#define EMC_TRAINING_DEBUG_DQ2 0xe54 -#define EMC_TRAINING_DEBUG_DQ3 0xe58 -#define EMC_TRAINING_MPC 0xe5c -#define EMC_TRAINING_PATRAM_CTRL 0xe60 -#define EMC_TRAINING_PATRAM_DQ 0xe64 -#define EMC_TRAINING_PATRAM_DMI 0xe68 -#define EMC_TRAINING_VREF_SETTLE 0xe6c -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0 0xe70 -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1 0xe74 -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2 0xe78 -#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3 0xe7c -#define EMC_TRAINING_RW_EYE_CENTER_IB_MISC 0xe80 -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0 0xe84 -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1 0xe88 -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2 0xe8c -#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3 0xe90 -#define EMC_TRAINING_RW_EYE_CENTER_OB_MISC 0xe94 -#define EMC_TRAINING_RW_OFFSET_IB_BYTE0 0xe98 -#define EMC_TRAINING_RW_OFFSET_IB_BYTE1 0xe9c -#define EMC_TRAINING_RW_OFFSET_IB_BYTE2 0xea0 -#define EMC_TRAINING_RW_OFFSET_IB_BYTE3 0xea4 -#define EMC_TRAINING_RW_OFFSET_IB_MISC 0xea8 -#define EMC_TRAINING_RW_OFFSET_OB_BYTE0 0xeac -#define EMC_TRAINING_RW_OFFSET_OB_BYTE1 0xeb0 -#define EMC_TRAINING_RW_OFFSET_OB_BYTE2 0xeb4 -#define EMC_TRAINING_RW_OFFSET_OB_BYTE3 0xeb8 -#define EMC_TRAINING_RW_OFFSET_OB_MISC 0xebc -#define EMC_TRAINING_OPT_CA_VREF 0xec0 -#define EMC_TRAINING_OPT_DQ_OB_VREF 0xec4 -#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK0 0xec8 -#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK1 0xecc -#define EMC_TRAINING_QUSE_VREF_CTRL 0xed0 -#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xed4 -#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xed8 -#define EMC_TRAINING_DRAMC_TIMING 0xedc -#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 -#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 -#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 -#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60c -#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610 -#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614 -#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620 -#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624 -#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628 -#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62c -#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630 -#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64c -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66c -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68c -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6a0 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6a4 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6a8 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6ac -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6b0 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6b4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6c0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6c4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6c8 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6cc -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4 0x6d0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5 0x6d4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6e0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6e4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6e8 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6ec -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4 0x6f0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5 0x6f4 -#define EMC_PMACRO_TX_PWRD_0 0x720 -#define EMC_PMACRO_TX_PWRD_1 0x724 -#define EMC_PMACRO_TX_PWRD_2 0x728 -#define EMC_PMACRO_TX_PWRD_3 0x72c -#define EMC_PMACRO_TX_PWRD_4 0x730 -#define EMC_PMACRO_TX_PWRD_5 0x734 -#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740 -#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744 -#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74c -#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748 -#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750 -#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754 -#define EMC_PMACRO_DDLL_BYPASS 0x760 -#define EMC_PMACRO_DDLL_PWRD_0 0x770 -#define EMC_PMACRO_DDLL_PWRD_1 0x774 -#define EMC_PMACRO_DDLL_PWRD_2 0x778 -#define EMC_PMACRO_CMD_CTRL_0 0x780 -#define EMC_PMACRO_CMD_CTRL_1 0x784 -#define EMC_PMACRO_CMD_CTRL_2 0x788 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8a0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8a4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8a8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8ac -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8b0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8b4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8b8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8bc -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99c -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9a0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9a4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9a8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9ac -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9b0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9b4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9b8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9bc -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xa00 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xa04 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xa08 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xa10 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xa14 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xa18 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xa20 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xa24 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xa28 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xa30 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xa34 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xa38 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xa40 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xa44 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xa48 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xa50 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xa54 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xa58 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xa60 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xa64 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xa68 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xa70 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xa74 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xa78 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0 0xa80 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1 0xa84 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2 0xa88 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0 0xa90 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1 0xa94 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2 0xa98 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0 0xaa0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1 0xaa4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2 0xaa8 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0 0xab0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1 0xab4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2 0xab8 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xb00 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xb04 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xb08 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xb10 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xb14 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xb18 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xb20 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xb24 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xb28 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xb30 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xb34 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xb38 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xb40 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xb44 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xb48 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xb50 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xb54 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xb58 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xb60 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xb64 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xb68 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xb70 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xb74 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xb78 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0 0xb80 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1 0xb84 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2 0xb88 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0 0xb90 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1 0xb94 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2 0xb98 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0 0xba0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1 0xba4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2 0xba8 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0 0xbb0 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1 0xbb4 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2 0xbb8 -#define EMC_PMACRO_IB_VREF_DQ_0 0xbe0 -#define EMC_PMACRO_IB_VREF_DQ_1 0xbe4 -#define EMC_PMACRO_IB_VREF_DQ_2 0xbe8 -#define EMC_PMACRO_IB_VREF_DQS_0 0xbf0 -#define EMC_PMACRO_IB_VREF_DQS_1 0xbf4 -#define EMC_PMACRO_IB_VREF_DQS_2 0xbf8 -#define EMC_PMACRO_IB_RXRT 0xcf4 -#define EMC_PMACRO_DDLL_LONG_CMD_0 0xc00 -#define EMC_PMACRO_DDLL_LONG_CMD_1 0xc04 -#define EMC_PMACRO_DDLL_LONG_CMD_2 0xc08 -#define EMC_PMACRO_DDLL_LONG_CMD_3 0xc0c -#define EMC_PMACRO_DDLL_LONG_CMD_4 0xc10 -#define EMC_PMACRO_DDLL_LONG_CMD_5 0xc14 -#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xc20 -#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xc24 -#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xc28 -#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xc30 -#define EMC_PMACRO_VTTGEN_CTRL_0 0xc34 -#define EMC_PMACRO_VTTGEN_CTRL_1 0xc38 -#define EMC_PMACRO_VTTGEN_CTRL_2 0xcf0 -#define EMC_PMACRO_BG_BIAS_CTRL_0 0xc3c -#define EMC_PMACRO_PAD_CFG_CTRL 0xc40 -#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xc50 -#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xc54 -#define EMC_PMACRO_CMD_RX_TERM_MODE 0xc58 -#define EMC_PMACRO_DATA_RX_TERM_MODE 0xc5c -#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xc60 -#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xc64 -#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xc68 -#define EMC_PMACRO_BRICK_MAPPING_0 0xc80 -#define EMC_PMACRO_BRICK_MAPPING_1 0xc84 -#define EMC_PMACRO_BRICK_MAPPING_2 0xc88 -#define EMC_PMACRO_DDLLCAL_CAL 0xce0 -#define EMC_PMACRO_DDLL_OFFSET 0xce4 -#define EMC_PMACRO_DDLL_PERIODIC_OFFSET 0xce8 -#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330 -#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334 -#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318 -#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31c -#define EMC_PMACRO_TRAINING_CTRL_0 0xcf8 -#define EMC_PMACRO_TRAINING_CTRL_1 0xcfc -#define EMC_PMC_SCRATCH1 0x440 -#define EMC_PMC_SCRATCH2 0x444 -#define EMC_PMC_SCRATCH3 0x448 - -#endif diff --git a/bootloader/mem/mc.c b/bootloader/mem/mc.c deleted file mode 100644 index dd508e2..0000000 --- a/bootloader/mem/mc.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "../mem/mc.h" -#include "../soc/t210.h" -#include "../soc/clock.h" -#include "../utils/util.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool 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, false); - mc_config_tsec_carveout(0, 0, true); - - 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) = 0x3100000; - 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() -{ - // Enable ARC_CLK_OVR_ON. - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 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; - // Disable ARC_CLK_OVR_ON. - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF; -} - -void mc_enable() -{ - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; - // Enable EMC 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_CLR) = 0x2000001; //Clear EMC and MC reset. - usleep(5); - - //#ifdef CONFIG_ENABLE_AHB_REDIRECT - mc_disable_ahb_redirect(); - //mc_enable_ahb_redirect(); - //#endif -} diff --git a/bootloader/mem/mc.h b/bootloader/mem/mc.h deleted file mode 100644 index 6a28bde..0000000 --- a/bootloader/mem/mc.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _MC_H_ -#define _MC_H_ - -#include "../utils/types.h" -#include "../mem/mc_t210.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); -void mc_config_carveout(); -void mc_config_carveout_finalize(); -void mc_enable_ahb_redirect(); -void mc_disable_ahb_redirect(); -void mc_enable(); - -#endif diff --git a/bootloader/mem/minerva.c b/bootloader/mem/minerva.c deleted file mode 100644 index d2c966e..0000000 --- a/bootloader/mem/minerva.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 - -#include "minerva.h" -#include "../soc/fuse.h" -#include "../utils/util.h" - -#include "../soc/clock.h" -#include "../ianos/ianos.h" -#include "../soc/fuse.h" -#include "../soc/t210.h" - -extern volatile nyx_storage_t *nyx_str; - -u32 minerva_init() -{ - u32 curr_ram_idx = 0; - - minerva_cfg = NULL; - mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - - // Set table to nyx storage. - mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; - - mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; - mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. - - u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); - - // Ensure that Minerva is new. - if (mtc_cfg->init_done == MTC_INIT_MAGIC) - minerva_cfg = (void *)ep_addr; - - if (!minerva_cfg) - return 1; - - // Get current frequency - for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++) - { - if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc) - break; - } - - mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz; - mtc_cfg->rate_to = 204000; - mtc_cfg->train_mode = OP_TRAIN; - minerva_cfg(mtc_cfg, NULL); - mtc_cfg->rate_to = 800000; - minerva_cfg(mtc_cfg, NULL); - mtc_cfg->rate_to = 1600000; - minerva_cfg(mtc_cfg, NULL); - - // FSP WAR. - mtc_cfg->train_mode = OP_SWITCH; - mtc_cfg->rate_to = 800000; - minerva_cfg(mtc_cfg, NULL); - - // Switch to max. - mtc_cfg->rate_to = 1600000; - minerva_cfg(mtc_cfg, NULL); - - return 0; -} - -void minerva_change_freq(minerva_freq_t freq) -{ - if (!minerva_cfg) - return; - - mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - if (mtc_cfg->rate_from != freq) - { - mtc_cfg->rate_to = freq; - mtc_cfg->train_mode = OP_SWITCH; - minerva_cfg(mtc_cfg, NULL); - } -} - -void minerva_periodic_training() -{ - if (!minerva_cfg) - return; - - mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - if (mtc_cfg->rate_from == FREQ_1600) - { - mtc_cfg->train_mode = OP_PERIODIC_TRAIN; - minerva_cfg(mtc_cfg, NULL); - } -} \ No newline at end of file diff --git a/bootloader/mem/mtc_table.h b/bootloader/mem/mtc_table.h deleted file mode 100644 index 38a3e2f..0000000 --- a/bootloader/mem/mtc_table.h +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Minerva Training Cell - * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. - * - * Copyright (c) 2018 CTCaer - * - * 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 _MTC_TABLE_H_ -#define _MTC_TABLE_H_ - -#include "../utils/types.h" - -typedef struct -{ - s32 pll_osc_in; - s32 pll_out; - u32 pll_feedback_div; - u32 pll_input_div; - u32 pll_post_div; -} pllm_clk_config_t; - -typedef struct -{ - u32 emc_rc_idx; - u32 emc_rfc_idx; - u32 emc_rfcpb_idx; - u32 emc_refctrl2_idx; - u32 emc_rfc_slr_idx; - u32 emc_ras_idx; - u32 emc_rp_idx; - u32 emc_r2w_idx; - u32 emc_w2r_idx; - u32 emc_r2p_idx; - u32 emc_w2p_idx; - u32 emc_r2r_idx; - u32 emc_tppd_idx; - u32 emc_ccdmw_idx; - u32 emc_rd_rcd_idx; - u32 emc_wr_rcd_idx; - u32 emc_rrd_idx; - u32 emc_rext_idx; - u32 emc_wext_idx; - u32 emc_wdv_chk_idx; - u32 emc_wdv_idx; - u32 emc_wsv_idx; - u32 emc_wev_idx; - u32 emc_wdv_mask_idx; - u32 emc_ws_duration_idx; - u32 emc_we_duration_idx; - u32 emc_quse_idx; - u32 emc_quse_width_idx; - u32 emc_ibdly_idx; - u32 emc_obdly_idx; - u32 emc_einput_idx; - u32 emc_mrw6_idx; - u32 emc_einput_duration_idx; - u32 emc_puterm_extra_idx; - u32 emc_puterm_width_idx; - u32 emc_qrst_idx; - u32 emc_qsafe_idx; - u32 emc_rdv_idx; - u32 emc_rdv_mask_idx; - u32 emc_rdv_early_idx; - u32 emc_rdv_early_mask_idx; - u32 emc_refresh_idx; - u32 emc_burst_refresh_num_idx; - u32 emc_pre_refresh_req_cnt_idx; - u32 emc_pdex2wr_idx; - u32 emc_pdex2rd_idx; - u32 emc_pchg2pden_idx; - u32 emc_act2pden_idx; - u32 emc_ar2pden_idx; - u32 emc_rw2pden_idx; - u32 emc_cke2pden_idx; - u32 emc_pdex2cke_idx; - u32 emc_pdex2mrr_idx; - u32 emc_txsr_idx; - u32 emc_txsrdll_idx; - u32 emc_tcke_idx; - u32 emc_tckesr_idx; - u32 emc_tpd_idx; - u32 emc_tfaw_idx; - u32 emc_trpab_idx; - u32 emc_tclkstable_idx; - u32 emc_tclkstop_idx; - u32 emc_mrw7_idx; - u32 emc_trefbw_idx; - u32 emc_odt_write_idx; - u32 emc_fbio_cfg5_idx; - u32 emc_fbio_cfg7_idx; - u32 emc_cfg_dig_dll_idx; - u32 emc_cfg_dig_dll_period_idx; - u32 emc_pmacro_ib_rxrt_idx; - u32 emc_cfg_pipe_1_idx; - u32 emc_cfg_pipe_2_idx; - u32 emc_pmacro_quse_ddll_rank0_4_idx; - u32 emc_pmacro_quse_ddll_rank0_5_idx; - u32 emc_pmacro_quse_ddll_rank1_4_idx; - u32 emc_pmacro_quse_ddll_rank1_5_idx; - u32 emc_mrw8_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx; - u32 emc_pmacro_ddll_long_cmd_0_idx; - u32 emc_pmacro_ddll_long_cmd_1_idx; - u32 emc_pmacro_ddll_long_cmd_2_idx; - u32 emc_pmacro_ddll_long_cmd_3_idx; - u32 emc_pmacro_ddll_long_cmd_4_idx; - u32 emc_pmacro_ddll_short_cmd_0_idx; - u32 emc_pmacro_ddll_short_cmd_1_idx; - u32 emc_pmacro_ddll_short_cmd_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx; - u32 emc_txdsrvttgen_idx; - u32 emc_fdpd_ctrl_dq_idx; - u32 emc_fdpd_ctrl_cmd_idx; - u32 emc_fbio_spare_idx; - u32 emc_zcal_interval_idx; - u32 emc_zcal_wait_cnt_idx; - u32 emc_mrs_wait_cnt_idx; - u32 emc_mrs_wait_cnt2_idx; - u32 emc_auto_cal_channel_idx; - u32 emc_dll_cfg_0_idx; - u32 emc_dll_cfg_1_idx; - u32 emc_pmacro_autocal_cfg_common_idx; - u32 emc_pmacro_zctrl_idx; - u32 emc_cfg_idx; - u32 emc_cfg_pipe_idx; - u32 emc_dyn_self_ref_control_idx; - u32 emc_qpop_idx; - u32 emc_dqs_brlshft_0_idx; - u32 emc_dqs_brlshft_1_idx; - u32 emc_cmd_brlshft_2_idx; - u32 emc_cmd_brlshft_3_idx; - u32 emc_pmacro_pad_cfg_ctrl_idx; - u32 emc_pmacro_data_pad_rx_ctrl_idx; - u32 emc_pmacro_cmd_pad_rx_ctrl_idx; - u32 emc_pmacro_data_rx_term_mode_idx; - u32 emc_pmacro_cmd_rx_term_mode_idx; - u32 emc_pmacro_cmd_pad_tx_ctrl_idx; - u32 emc_pmacro_data_pad_tx_ctrl_idx; - u32 emc_pmacro_common_pad_tx_ctrl_idx; - u32 emc_pmacro_vttgen_ctrl_0_idx; - u32 emc_pmacro_vttgen_ctrl_1_idx; - u32 emc_pmacro_vttgen_ctrl_2_idx; - u32 emc_pmacro_brick_ctrl_rfu1_idx; - u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx; - u32 emc_pmacro_brick_ctrl_rfu2_idx; - u32 emc_pmacro_data_brick_ctrl_fdpd_idx; - u32 emc_pmacro_bg_bias_ctrl_0_idx; - u32 emc_cfg_3_idx; - u32 emc_pmacro_tx_pwrd_0_idx; - u32 emc_pmacro_tx_pwrd_1_idx; - u32 emc_pmacro_tx_pwrd_2_idx; - u32 emc_pmacro_tx_pwrd_3_idx; - u32 emc_pmacro_tx_pwrd_4_idx; - u32 emc_pmacro_tx_pwrd_5_idx; - u32 emc_config_sample_delay_idx; - u32 emc_pmacro_tx_sel_clk_src_0_idx; - u32 emc_pmacro_tx_sel_clk_src_1_idx; - u32 emc_pmacro_tx_sel_clk_src_2_idx; - u32 emc_pmacro_tx_sel_clk_src_3_idx; - u32 emc_pmacro_tx_sel_clk_src_4_idx; - u32 emc_pmacro_tx_sel_clk_src_5_idx; - u32 emc_pmacro_ddll_bypass_idx; - u32 emc_pmacro_ddll_pwrd_0_idx; - u32 emc_pmacro_ddll_pwrd_1_idx; - u32 emc_pmacro_ddll_pwrd_2_idx; - u32 emc_pmacro_cmd_ctrl_0_idx; - u32 emc_pmacro_cmd_ctrl_1_idx; - u32 emc_pmacro_cmd_ctrl_2_idx; - u32 emc_tr_timing_0_idx; - u32 emc_tr_dvfs_idx; - u32 emc_tr_ctrl_1_idx; - u32 emc_tr_rdv_idx; - u32 emc_tr_qpop_idx; - u32 emc_tr_rdv_mask_idx; - u32 emc_mrw14_idx; - u32 emc_tr_qsafe_idx; - u32 emc_tr_qrst_idx; - u32 emc_training_ctrl_idx; - u32 emc_training_settle_idx; - u32 emc_training_vref_settle_idx; - u32 emc_training_ca_fine_ctrl_idx; - u32 emc_training_ca_ctrl_misc_idx; - u32 emc_training_ca_ctrl_misc1_idx; - u32 emc_training_ca_vref_ctrl_idx; - u32 emc_training_quse_cors_ctrl_idx; - u32 emc_training_quse_fine_ctrl_idx; - u32 emc_training_quse_ctrl_misc_idx; - u32 emc_training_quse_vref_ctrl_idx; - u32 emc_training_read_fine_ctrl_idx; - u32 emc_training_read_ctrl_misc_idx; - u32 emc_training_read_vref_ctrl_idx; - u32 emc_training_write_fine_ctrl_idx; - u32 emc_training_write_ctrl_misc_idx; - u32 emc_training_write_vref_ctrl_idx; - u32 emc_training_mpc_idx; - u32 emc_mrw15_idx; -} burst_regs_t; - - -typedef struct -{ - u32 burst_regs[221]; - u32 burst_reg_per_ch[8]; - u32 shadow_regs_ca_train[221]; - u32 shadow_regs_quse_train[221]; - u32 shadow_regs_rdwr_train[221]; -} burst_regs_table_t; - -typedef struct -{ - u32 ptfv_dqsosc_movavg_c0d0u0_idx; - u32 ptfv_dqsosc_movavg_c0d0u1_idx; - u32 ptfv_dqsosc_movavg_c0d1u0_idx; - u32 ptfv_dqsosc_movavg_c0d1u1_idx; - u32 ptfv_dqsosc_movavg_c1d0u0_idx; - u32 ptfv_dqsosc_movavg_c1d0u1_idx; - u32 ptfv_dqsosc_movavg_c1d1u0_idx; - u32 ptfv_dqsosc_movavg_c1d1u1_idx; - u32 ptfv_write_samples_idx; - u32 ptfv_dvfs_samples_idx; - u32 ptfv_movavg_weight_idx; - u32 ptfv_config_ctrl_idx; -} ptfv_list_table_t; - -typedef struct -{ - u32 emc0_mrw10_idx; - u32 emc1_mrw10_idx; - u32 emc0_mrw11_idx; - u32 emc1_mrw11_idx; - u32 emc0_mrw12_idx; - u32 emc1_mrw12_idx; - u32 emc0_mrw13_idx; - u32 emc1_mrw13_idx; -} burst_reg_per_ch_t; - -typedef struct -{ - u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx; - u32 emc_pmacro_ib_vref_dqs_0_idx; - u32 emc_pmacro_ib_vref_dqs_1_idx; - u32 emc_pmacro_ib_vref_dq_0_idx; - u32 emc_pmacro_ib_vref_dq_1_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx; - u32 emc_pmacro_quse_ddll_rank0_0_idx; - u32 emc_pmacro_quse_ddll_rank0_1_idx; - u32 emc_pmacro_quse_ddll_rank0_2_idx; - u32 emc_pmacro_quse_ddll_rank0_3_idx; - u32 emc_pmacro_quse_ddll_rank1_0_idx; - u32 emc_pmacro_quse_ddll_rank1_1_idx; - u32 emc_pmacro_quse_ddll_rank1_2_idx; - u32 emc_pmacro_quse_ddll_rank1_3_idx; -} trim_regs_t; - -typedef struct -{ - u32 emc_cmd_brlshft_0_idx; - u32 emc_cmd_brlshft_1_idx; - u32 emc0_data_brlshft_0_idx; - u32 emc1_data_brlshft_0_idx; - u32 emc0_data_brlshft_1_idx; - u32 emc1_data_brlshft_1_idx; - u32 emc_quse_brlshft_0_idx; - u32 emc_quse_brlshft_1_idx; - u32 emc_quse_brlshft_2_idx; - u32 emc_quse_brlshft_3_idx; -} trim_perch_regs_t; - -typedef struct -{ - u32 t_rp; - u32 t_fc_lpddr4; - u32 t_rfc; - u32 t_pdex; - u32 rl; -} dram_timings_t; - -typedef struct -{ - u32 emc0_training_opt_dqs_ib_vref_rank0_idx; - u32 emc1_training_opt_dqs_ib_vref_rank0_idx; - u32 emc0_training_opt_dqs_ib_vref_rank1_idx; - u32 emc1_training_opt_dqs_ib_vref_rank1_idx; -} vref_perch_regs_t; - -typedef struct -{ - u32 trim_regs[138]; - u32 trim_perch_regs[10]; - u32 vref_perch_regs[4]; -} trim_regs_table_t; - -typedef struct -{ - u32 rev; - char dvfs_ver[60]; - u32 rate_khz; - u32 min_volt; - u32 gpu_min_volt; - char clock_src[32]; - u32 clk_src_emc; - u32 needs_training; - u32 training_pattern; - u32 trained; - u32 periodic_training; - u32 trained_dram_clktree_c0d0u0; - u32 trained_dram_clktree_c0d0u1; - u32 trained_dram_clktree_c0d1u0; - u32 trained_dram_clktree_c0d1u1; - u32 trained_dram_clktree_c1d0u0; - u32 trained_dram_clktree_c1d0u1; - u32 trained_dram_clktree_c1d1u0; - u32 trained_dram_clktree_c1d1u1; - u32 current_dram_clktree_c0d0u0; - u32 current_dram_clktree_c0d0u1; - u32 current_dram_clktree_c0d1u0; - u32 current_dram_clktree_c0d1u1; - u32 current_dram_clktree_c1d0u0; - u32 current_dram_clktree_c1d0u1; - u32 current_dram_clktree_c1d1u0; - u32 current_dram_clktree_c1d1u1; - u32 run_clocks; - u32 tree_margin; - u32 num_burst; - u32 num_burst_per_ch; - u32 num_trim; - u32 num_trim_per_ch; - u32 num_mc_regs; - u32 num_up_down; - u32 vref_num; - u32 training_mod_num; - u32 dram_timing_num; - - ptfv_list_table_t ptfv_list; - - burst_regs_t burst_regs; - burst_reg_per_ch_t burst_reg_per_ch; - burst_regs_t shadow_regs_ca_train; - burst_regs_t shadow_regs_quse_train; - burst_regs_t shadow_regs_rdwr_train; - trim_regs_t trim_regs; - trim_perch_regs_t trim_perch_regs; - vref_perch_regs_t vref_perch_regs; - dram_timings_t dram_timings; - - u32 training_mod_regs[20]; - u32 save_restore_mod_regs[12]; - u32 burst_mc_regs[33]; - u32 la_scale_regs[24]; - - u32 min_mrs_wait; - u32 emc_mrw; - u32 emc_mrw2; - u32 emc_mrw3; - u32 emc_mrw4; - u32 emc_mrw9; - u32 emc_mrs; - u32 emc_emrs; - u32 emc_emrs2; - u32 emc_auto_cal_config; - u32 emc_auto_cal_config2; - 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; - u32 emc_cfg_2; - u32 emc_sel_dpd_ctrl; - u32 emc_fdpd_ctrl_cmd_no_ramp; - u32 dll_clk_src; - u32 clk_out_enb_x_0_clk_enb_emc_dll; - u32 latency; -} emc_table_t; - -#endif \ No newline at end of file diff --git a/bootloader/mem/sdram.c b/bootloader/mem/sdram.c deleted file mode 100644 index 1b33708..0000000 --- a/bootloader/mem/sdram.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 balika011 - * Copyright (c) 2019 CTCaer - * - * 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 "mc.h" -#include "emc.h" -#include "sdram_param_t210.h" -#include "../../common/memory_map.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../soc/clock.h" -#include "../soc/fuse.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -#define CONFIG_SDRAM_COMPRESS_CFG - -#ifdef CONFIG_SDRAM_COMPRESS_CFG -#include "../libs/compr/lz.h" -#include "sdram_config_lz.inl" -#else -#include "sdram_config.inl" -#endif - -static u32 _get_sdram_id() -{ - u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3; - - // Check if id is proper. - if (sdram_id > 7) - sdram_id = 0; - - return sdram_id; -} - -static void _sdram_config(const sdram_params_t *params) -{ - // Program DPD3/DPD4 regs (coldboot path). - // Enable sel_dpd on unused pins. - u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000; - PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; - usleep(params->pmc_io_dpd3_req_wait); - - // Disable e_dpd_vttgen. - dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000; - PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; - usleep(params->pmc_io_dpd4_req_wait); - - // Disable e_dpd_bg. - PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; - usleep(params->pmc_io_dpd4_req_wait); - - PMC(APBDEV_PMC_WEAK_BIAS) = 0; - usleep(1); - - // Start clocks. - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; - - // u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); - // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp; - // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000; - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); - - u32 wait_end = get_tmr_us() + 300; - while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000)) - { - if (get_tmr_us() >= wait_end) - goto break_nosleep; - } - usleep(10); - -break_nosleep: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF); - if (params->emc_clock_source_dll) - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; - if (params->clear_clock2_mc1) - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets. - - // Set pad macros. - 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; // Trigger timing update so above writes take place. - usleep(10); // Ensure the regulators settle. - - // Select EMC write mux. - EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; - - // Patch 2 using BCT spare variables. - if (params->emc_bct_spare2) - *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; - - // Program CMD mapping. Required before brick mapping, else - // we can't guarantee CK will be differential at all times. - 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; - - // Program brick mapping. - 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; - - // This is required to do any reads from the pad macros. - EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; - - EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; - - // Set swizzle for Rank 0. - 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; - // Set swizzle for Rank 1. - 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; - - // Patch 4 using BCT spare variables. - if (params->emc_bct_spare6) - *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; - - // Set pad controls. - 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; - - // Program Autocal controls with shadowed register fields. - 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; - - // Common pad macro (cpm). - EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; - - // Patch 3 using BCT spare variables. - if (params->emc_bct_spare4) - *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; - - EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. - - // Initialize MC VPR settings. - 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; - - // Program SDRAM geometry parameters. - 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; - - // Program bank swizzling. - 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; - - // Program external memory aperture (base and size). - MC(MC_EMEM_CFG) = params->mc_emem_cfg; - - // Program SEC carveout (base and size). - 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; - - // Program MTS carveout (base and size). - 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; - - // Program the memory arbiter. - 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; // Trigger MC timing update. - - // Program second-level clock enable overrides. - MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; - - // Program statistics gathering. - MC(MC_STAT_CONTROL) = params->mc_stat_control; - - // Program SDRAM geometry parameters. - EMC(EMC_ADR_CFG) = params->emc_adr_cfg; - - // Program second-level clock enable overrides. - EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; - - // Program EMC pad auto calibration. - 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; - usleep(params->emc_auto_cal_wait); - - // Patch 5 using BCT spare variables. - if (params->emc_bct_spare8) - *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; - - // Program EMC timing configuration. - 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) = 1; - 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; - - // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. - 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; - - // Set pipe bypass enable bits before sending any DRAM commands. - EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; - - // Patch BootROM. - if (params->boot_rom_patch_control & (1 << 31)) - { - *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; - MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. - } - - // Release SEL_DPD_CMD. - PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; - usleep(params->pmc_io_dpd3_req_wait); - - // Set autocal interval if not configured. - 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; - - // ZQ CAL setup (not actually issuing ZQ CAL now). - if (params->emc_zcal_warm_cold_boot_enables & 1) - { - if (params->memory_type == 2) - EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; - 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; // Trigger timing update so above writes take place. - usleep(params->emc_timing_control_wait); - - // Deassert HOLD_CKE_LOW. - PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F; - usleep(params->pmc_ddr_ctrl_wait); - - // Set clock enable signal. - u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); - if (params->memory_type == 2 || params->memory_type == 3) - { - EMC(EMC_PIN) = pin_gpio_cfg; - (void)EMC(EMC_PIN); - usleep(params->emc_pin_extra_wait + 200); - EMC(EMC_PIN) = pin_gpio_cfg | 0x100; - (void)EMC(EMC_PIN); - } - - if (params->memory_type == 3) - usleep(params->emc_pin_extra_wait + 2000); - else if (params->memory_type == 2) - usleep(params->emc_pin_extra_wait + 500); - - // Enable clock enable signal. - EMC(EMC_PIN) = pin_gpio_cfg | 0x101; - (void)EMC(EMC_PIN); - usleep(params->emc_pin_program_wait); - - // Send NOP (trigger just needs to be non-zero). - if (params->memory_type != 3) - EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; - - // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. - if (params->memory_type == 1) - usleep(params->emc_pin_extra_wait + 200); - - // Init zq calibration, - if (params->memory_type == 3) - { - // Patch 6 using BCT spare variables. - if (params->emc_bct_spare10) - *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; - - // Write mode registers. - 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) - { - // Issue ZQCAL start, device 0. - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; - usleep(params->emc_zcal_init_wait); - - // Issue ZQCAL latch. - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; - // Same for device 1. - if (!(params->emc_dev_select & 2)) - { - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; - usleep(params->emc_zcal_init_wait); - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; - } - } - } - - // Set package and DPD pad control. - PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; - - // Start periodic ZQ calibration (LPDDRx only). - 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; - } - - // Patch 7 using BCT spare variables. - if (params->emc_bct_spare12) - *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; - - EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. - - if (params->emc_extra_refresh_num) - EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; - - // Enable refresh. - 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; - - // Write addr swizzle lock bit. - EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; - - EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions. - - // Enable EMC pipe clock gating. - EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; - - // Depending on freqency, enable CMD/CLK fdpd. - EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; - - // Enable arbiter. - SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); - - // Lock carveouts per BCT cfg. - 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; - - //Disable write access to a bunch of EMC registers. - MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; -} - -sdram_params_t *sdram_get_params() -{ -#ifdef CONFIG_SDRAM_COMPRESS_CFG - u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; - LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); - return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()]; -#else - return _dram_cfgs[_get_sdram_id()]; -#endif -} - -/* - * Function: sdram_get_params_patched - * - * This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again. - * If the boot_rom_patch_control's MSB is set, it uses it as an index to - * APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data. - * (The MSB falls out when it gets multiplied by sizeof(u32)). - * Because the bootrom does not do any boundary checks, it lets us write anywhere and anything. - * Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time. - * The first patch is not needed any more when the exploit is triggered, so we overwrite that. - * 0x10459E is the address where it returns an error when the signature is not valid. - * We change that to MOV R0, #0, so we pass the check. - * - * Note: The modulus in the header must match and validated. - */ - -sdram_params_t *sdram_get_params_patched() -{ - #define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff)) - sdram_params_t *sdram_params = sdram_get_params(); - - // Disable Warmboot signature check. - sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); - sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); -/* - // Disable SBK lock. - sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4); - sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000); - - // Disable bootrom read lock. - sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4); - sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000); - sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); - sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); -*/ - return sdram_params; -} - -void sdram_init() -{ - const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); - - // Set DRAM voltage. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); - - // VDDP Select. - PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; - usleep(params->pmc_vddp_sel_wait); - - // Set DDR pad voltage. - PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); - - // Turn on MEM IO Power. - 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; - - // Patch 1 using BCT spare variables - if (params->emc_bct_spare0) - *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; - - _sdram_config(params); -} diff --git a/bootloader/mem/sdram_config.inl b/bootloader/mem/sdram_config.inl deleted file mode 100644 index d23f4da..0000000 --- a/bootloader/mem/sdram_config.inl +++ /dev/null @@ -1,1152 +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 . - */ - -static const u8 _dram_cfg_0[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, 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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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, 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_1[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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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_2[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, 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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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, 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_3[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, 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, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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_4[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, 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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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, 0x0C, 0x00, - 0x02, 0x03, 0x0C, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x18, 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, 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_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_5, - (const u32 *)_dram_cfg_6 -}; diff --git a/bootloader/mem/sdram_config_lz.inl b/bootloader/mem/sdram_config_lz.inl deleted file mode 100644 index 832b5b4..0000000 --- a/bootloader/mem/sdram_config_lz.inl +++ /dev/null @@ -1,124 +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 . - */ - -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/bootloader/mem/sdram_lp0.c b/bootloader/mem/sdram_lp0.c deleted file mode 100644 index 869e85a..0000000 --- a/bootloader/mem/sdram_lp0.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * Copyright 2014 Google Inc. - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../soc/t210.h" -#include "../soc/pmc_lp0_t210.h" -#include "sdram_lp0_param_t210.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) -{ - struct sdram_params *sdram = (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 - - //TODO: pkg1.1 (1.X - 3.X) reads them from MC. - // Patch carveout parameters. - /*sdram->McGeneralizedCarveout1Bom = 0; - sdram->McGeneralizedCarveout1BomHi = 0; - sdram->McGeneralizedCarveout1Size128kb = 0; - sdram->McGeneralizedCarveout1Access0 = 0; - sdram->McGeneralizedCarveout1Access1 = 0; - sdram->McGeneralizedCarveout1Access2 = 0; - sdram->McGeneralizedCarveout1Access3 = 0; - sdram->McGeneralizedCarveout1Access4 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout1Cfg0 = 0; - sdram->McGeneralizedCarveout2Bom = 0x80020000; - sdram->McGeneralizedCarveout2BomHi = 0; - sdram->McGeneralizedCarveout2Size128kb = 2; - sdram->McGeneralizedCarveout2Access0 = 0; - sdram->McGeneralizedCarveout2Access1 = 0; - sdram->McGeneralizedCarveout2Access2 = 0x3000000; - sdram->McGeneralizedCarveout2Access3 = 0; - sdram->McGeneralizedCarveout2Access4 = 0x300; - sdram->McGeneralizedCarveout2ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout2Cfg0 = 0x440167E; - sdram->McGeneralizedCarveout3Bom = 0; - sdram->McGeneralizedCarveout3BomHi = 0; - sdram->McGeneralizedCarveout3Size128kb = 0; - sdram->McGeneralizedCarveout3Access0 = 0; - sdram->McGeneralizedCarveout3Access1 = 0; - sdram->McGeneralizedCarveout3Access2 = 0x3000000; - sdram->McGeneralizedCarveout3Access3 = 0; - sdram->McGeneralizedCarveout3Access4 = 0x300; - sdram->McGeneralizedCarveout3ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout3Cfg0 = 0x4401E7E; - sdram->McGeneralizedCarveout4Bom = 0; - sdram->McGeneralizedCarveout4BomHi = 0; - sdram->McGeneralizedCarveout4Size128kb = 0; - sdram->McGeneralizedCarveout4Access0 = 0; - sdram->McGeneralizedCarveout4Access1 = 0; - sdram->McGeneralizedCarveout4Access2 = 0; - sdram->McGeneralizedCarveout4Access3 = 0; - sdram->McGeneralizedCarveout4Access4 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout4Cfg0 = 0x8F; - sdram->McGeneralizedCarveout5Bom = 0; - sdram->McGeneralizedCarveout5BomHi = 0; - sdram->McGeneralizedCarveout5Size128kb = 0; - sdram->McGeneralizedCarveout5Access0 = 0; - sdram->McGeneralizedCarveout5Access1 = 0; - sdram->McGeneralizedCarveout5Access2 = 0; - sdram->McGeneralizedCarveout5Access3 = 0; - sdram->McGeneralizedCarveout5Access4 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout5Cfg0 = 0x8F;*/ - - //TODO: this is 4.X+ behaviour which seems to work fine for < 4.X. - // Patch carveout parameters. - sdram->McGeneralizedCarveout1Cfg0 = 0; - sdram->McGeneralizedCarveout2Cfg0 = 0; - sdram->McGeneralizedCarveout3Cfg0 = 0; - sdram->McGeneralizedCarveout4Cfg0 = 0; - sdram->McGeneralizedCarveout5Cfg0 = 0; - - // Patch SDRAM parameters. - u32 t0 = sdram->EmcSwizzleRank0Byte0 << 5 >> 29 > sdram->EmcSwizzleRank0Byte0 << 1 >> 29; - u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->EmcSwizzleRank1Byte0 << 5 >> 29 > sdram->EmcSwizzleRank1Byte0 << 1 >> 29) << 4); - u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->EmcSwizzleRank0Byte1 << 5 >> 29 > sdram->EmcSwizzleRank0Byte1 << 1 >> 29) << 1); - u32 t3 = (t2 & 0xFFFFFFDF) | ((sdram->EmcSwizzleRank1Byte1 << 5 >> 29 > sdram->EmcSwizzleRank1Byte1 << 1 >> 29) << 5); - u32 t4 = (t3 & 0xFFFFFFFB) | ((sdram->EmcSwizzleRank0Byte2 << 5 >> 29 > sdram->EmcSwizzleRank0Byte2 << 1 >> 29) << 2); - u32 t5 = (t4 & 0xFFFFFFBF) | ((sdram->EmcSwizzleRank1Byte2 << 5 >> 29 > sdram->EmcSwizzleRank1Byte2 << 1 >> 29) << 6); - u32 t6 = (t5 & 0xFFFFFFF7) | ((sdram->EmcSwizzleRank0Byte3 << 5 >> 29 > sdram->EmcSwizzleRank0Byte3 << 1 >> 29) << 3); - u32 t7 = (t6 & 0xFFFFFF7F) | ((sdram->EmcSwizzleRank1Byte3 << 5 >> 29 > sdram->EmcSwizzleRank1Byte3 << 1 >> 29) << 7); - sdram->SwizzleRankByteEncode = t7; - sdram->EmcBctSpare2 = 0x40000DD8; - sdram->EmcBctSpare3 = t7; - - 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(EmcBctSpare3, 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); - - 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/bootloader/mem/sdram_lp0_param_t210.h b/bootloader/mem/sdram_lp0_param_t210.h deleted file mode 100644 index 9028990..0000000 --- a/bootloader/mem/sdram_lp0_param_t210.h +++ /dev/null @@ -1,964 +0,0 @@ -/* - * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. - * Copyright 2014 Google Inc. - * Copyright (c) 2018 CTCaer - * - * 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 "../utils/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/bootloader/power/bq24193.c b/bootloader/power/bq24193.c deleted file mode 100644 index 6dd3cb1..0000000 --- a/bootloader/power/bq24193.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Battery charger driver for Nintendo Switch's TI BQ24193 - * - * Copyright (c) 2018 CTCaer - * - * 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 "bq24193.h" -#include "../soc/i2c.h" -#include "../utils/util.h" - -#pragma GCC push_options -#pragma GCC optimize ("Os") - -int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) -{ - u8 data; - - switch (prop) { - case BQ24193_InputVoltageLimit: // Input voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource); - data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; - *value += ((data >> 0) & 1) ? 80 : 0; - *value += ((data >> 1) & 1) ? 160 : 0; - *value += ((data >> 2) & 1) ? 320 : 0; - *value += ((data >> 3) & 1) ? 640 : 0; - *value += 3880; - break; - case BQ24193_InputCurrentLimit: // Input current limit (mA). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource); - data &= BQ24193_INCONFIG_INLIMIT_MASK; - switch (data) - { - case 0: - *value = 100; - break; - case 1: - *value = 150; - break; - case 2: - *value = 500; - break; - case 3: - *value = 900; - break; - case 4: - *value = 1200; - break; - case 5: - *value = 1500; - break; - case 6: - *value = 2000; - break; - case 7: - *value = 3000; - break; - } - break; - case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig); - *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; - *value *= 100; - *value += 3000; - break; - case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr); - data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2; - *value += ((data >> 0) & 1) ? 64 : 0; - *value += ((data >> 1) & 1) ? 128 : 0; - *value += ((data >> 2) & 1) ? 256 : 0; - *value += ((data >> 3) & 1) ? 512 : 0; - *value += ((data >> 4) & 1) ? 1024 : 0; - *value += ((data >> 5) & 1) ? 2048 : 0; - *value += 512; - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr); - data &= BQ24193_CHRGCURR_20PCT_MASK; - if (data) - *value = *value * 20 / 100; // Fast charge current limit is 20%. - break; - case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt); - data = (data & BQ24193_CHRGVOLT_VREG) >> 2; - *value += ((data >> 0) & 1) ? 16 : 0; - *value += ((data >> 1) & 1) ? 32 : 0; - *value += ((data >> 2) & 1) ? 64 : 0; - *value += ((data >> 3) & 1) ? 128 : 0; - *value += ((data >> 4) & 1) ? 256 : 0; - *value += ((data >> 5) & 1) ? 512 : 0; - *value += 3504; - break; - case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt); - data &= BQ24193_IRTHERMAL_THERM_MASK; - if (data) - *value = 300; - else - *value = 100; - break; - case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_IRCompThermal); - data &= BQ24193_IRTHERMAL_THERM_MASK; - switch (data) - { - case 0: - *value = 60; - break; - case 1: - *value = 80; - break; - case 2: - *value = 100; - break; - case 3: - *value = 120; - break; - } - break; - case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Status); - *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; - break; - case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_FaultReg); - *value = data & BQ24193_FAULT_THERM_MASK; - break; - case BQ24193_DevID: // Dev ID. - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart); - *value = data & BQ24193_VENDORPART_DEV_MASK; - break; - case BQ24193_ProductNumber: // Product number. - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart); - *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; - break; - default: - return -1; - } - return 0; -} - -void bq24193_fake_battery_removal() -{ - u8 value; - - // Disable watchdog to keep BATFET disabled. - value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer); - value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK; - i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value); - - // Force BATFET to disabled state. This disconnects the battery from the system. - value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc); - value |= BQ24193_MISC_BATFET_DI_MASK; - i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value); -} - -#pragma GCC pop_options diff --git a/bootloader/power/max17050.h b/bootloader/power/max17050.h deleted file mode 100644 index 6104e5c..0000000 --- a/bootloader/power/max17050.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Fuel gauge driver for Nintendo Switch's Maxim 17050 - * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. - * - * Copyright (c) 2011 Samsung Electronics - * MyungJoo Ham - * Copyright (c) 2018 CTCaer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __MAX17050_H_ -#define __MAX17050_H_ - -#define MAX17050_STATUS_BattAbsent (1 << 3) -#define MAX17050_DEFAULT_SNS_RESISTOR 10000 - -/* Consider RepCap which is less then 10 units below FullCAP full */ -#define MAX17050_FULL_THRESHOLD 10 - -#define MAX17050_CHARACTERIZATION_DATA_SIZE 48 - -#define MAXIM17050_I2C_ADDR 0x36 - -enum MAX17050_reg { - MAX17050_STATUS = 0x00, - MAX17050_VALRT_Th = 0x01, - MAX17050_TALRT_Th = 0x02, - MAX17050_SALRT_Th = 0x03, - MAX17050_AtRate = 0x04, - MAX17050_RepCap = 0x05, - MAX17050_RepSOC = 0x06, - MAX17050_Age = 0x07, - MAX17050_TEMP = 0x08, - MAX17050_VCELL = 0x09, - MAX17050_Current = 0x0A, - MAX17050_AvgCurrent = 0x0B, - - MAX17050_SOC = 0x0D, - MAX17050_AvSOC = 0x0E, - MAX17050_RemCap = 0x0F, - MAX17050_FullCAP = 0x10, - MAX17050_TTE = 0x11, - MAX17050_QRTbl00 = 0x12, - MAX17050_FullSOCThr = 0x13, - MAX17050_RSLOW = 0x14, - - MAX17050_AvgTA = 0x16, - MAX17050_Cycles = 0x17, - MAX17050_DesignCap = 0x18, - MAX17050_AvgVCELL = 0x19, - MAX17050_MinMaxTemp = 0x1A, - MAX17050_MinMaxVolt = 0x1B, - MAX17050_MinMaxCurr = 0x1C, - MAX17050_CONFIG = 0x1D, - MAX17050_ICHGTerm = 0x1E, - MAX17050_AvCap = 0x1F, - MAX17050_ManName = 0x20, - MAX17050_DevName = 0x21, - MAX17050_QRTbl10 = 0x22, - MAX17050_FullCAPNom = 0x23, - MAX17050_TempNom = 0x24, - MAX17050_TempLim = 0x25, - MAX17050_TempHot = 0x26, - MAX17050_AIN = 0x27, - MAX17050_LearnCFG = 0x28, - MAX17050_FilterCFG = 0x29, - MAX17050_RelaxCFG = 0x2A, - MAX17050_MiscCFG = 0x2B, - MAX17050_TGAIN = 0x2C, - MAX17050_TOFF = 0x2D, - MAX17050_CGAIN = 0x2E, - MAX17050_COFF = 0x2F, - - MAX17050_QRTbl20 = 0x32, - MAX17050_SOC_empty = 0x33, - MAX17050_T_empty = 0x34, - MAX17050_FullCAP0 = 0x35, - MAX17050_LAvg_empty = 0x36, - MAX17050_FCTC = 0x37, - MAX17050_RCOMP0 = 0x38, - MAX17050_TempCo = 0x39, - MAX17050_V_empty = 0x3A, - MAX17050_K_empty0 = 0x3B, - MAX17050_TaskPeriod = 0x3C, - MAX17050_FSTAT = 0x3D, - MAX17050_TIMER = 0x3E, - MAX17050_SHDNTIMER = 0x3F, - - MAX17050_QRTbl30 = 0x42, - - MAX17050_dQacc = 0x45, - MAX17050_dPacc = 0x46, - - MAX17050_VFSOC0 = 0x48, - - Max17050_QH0 = 0x4C, - MAX17050_QH = 0x4D, - MAX17050_QL = 0x4E, - - MAX17050_MinVolt = 0x50, // Custom ID. Not to be sent to i2c. - MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c. - - MAX17050_VFSOC0Enable = 0x60, - MAX17050_MODELEnable1 = 0x62, - MAX17050_MODELEnable2 = 0x63, - - MAX17050_MODELChrTbl = 0x80, - - MAX17050_OCV = 0xEE, - - MAX17050_OCVInternal = 0xFB, - - MAX17050_VFSOC = 0xFF, -}; - -int max17050_get_property(enum MAX17050_reg reg, int *value); -int max17050_fix_configuration(); - -#endif /* __MAX17050_H_ */ diff --git a/bootloader/power/max7762x.c b/bootloader/power/max7762x.c deleted file mode 100644 index 6dfd6c6..0000000 --- a/bootloader/power/max7762x.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer - * - * 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 "../soc/i2c.h" -#include "../utils/util.h" - -#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, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 }, - { REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 }, - { REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 }, - { REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 }, - { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 }, - { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 }, - { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 }, - { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 }, - { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 }, - { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 }, - { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 }, - { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 }, - { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } -}; - -static void _max77620_try_set_reg(u8 reg, u8 val) -{ - u8 tmp; - do - { - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val); - tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg); - } while (val != tmp); -} - -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, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1; - return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, 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]; - - _max77620_try_set_reg(reg->fps_addr, - (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (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_min || 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, MAX77620_I2C_ADDR, reg->volt_addr); - val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_try_set_reg(reg->volt_addr, val); - usleep(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, MAX77620_I2C_ADDR, addr); - if (enable) - val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); - else - val &= ~reg->enable_mask; - _max77620_try_set_reg(addr, val); - usleep(1000); - - return 1; -} - -// LDO only. -int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) -{ - if (id > REGULATOR_MAX) - return 0; - - const max77620_regulator_t *reg = &_pmic_regulators[id]; - - if (mv < reg->mv_min || mv > reg->mv_max) - return 0; - - u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; - u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_try_set_reg(reg->volt_addr, val); - usleep(1000); - - return 1; -} - -void max77620_config_default() -{ - for (u32 i = 1; i <= REGULATOR_MAX; i++) - { - i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, 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); - } - _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); -} - -void max77620_low_battery_monitor_config() -{ - _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | - MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); -} diff --git a/bootloader/power/max7762x.h b/bootloader/power/max7762x.h deleted file mode 100644 index 8b0feb9..0000000 --- a/bootloader/power/max7762x.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer - * - * 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 "../utils/types.h" - -/* -* Switch Power domains (max77620): -* Name | Usage | uV step | uV min | uV default | uV max | Init -*-------+---------------+---------+--------+------------+---------+------------------ -* sd0 | SoC | 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, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) -* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | -* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) -* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) -* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V -* 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 - -#define MAX77621_CPU_I2C_ADDR 0x1B -#define MAX77621_GPU_I2C_ADDR 0x1C - -#define MAX77621_VOUT_REG 0 -#define MAX77621_VOUT_DVC_REG 1 -#define MAX77621_CONTROL1_REG 2 -#define MAX77621_CONTROL2_REG 3 - -/* MAX77621_VOUT */ -#define MAX77621_VOUT_ENABLE (1 << 7) -#define MAX77621_VOUT_MASK 0x7F -#define MAX77621_VOUT_0_95V 0x37 -#define MAX77621_VOUT_1_09V 0x4F - -/* MAX77621_VOUT_DVC_DVS */ -#define MAX77621_DVS_VOUT_MASK 0x7F - -/* MAX77621_CONTROL1 */ -#define MAX77621_SNS_ENABLE (1 << 7) -#define MAX77621_FPWM_EN_M (1 << 6) -#define MAX77621_NFSR_ENABLE (1 << 5) -#define MAX77621_AD_ENABLE (1 << 4) -#define MAX77621_BIAS_ENABLE (1 << 3) -#define MAX77621_FREQSHIFT_9PER (1 << 2) - -#define MAX77621_RAMP_12mV_PER_US 0x0 -#define MAX77621_RAMP_25mV_PER_US 0x1 -#define MAX77621_RAMP_50mV_PER_US 0x2 -#define MAX77621_RAMP_200mV_PER_US 0x3 -#define MAX77621_RAMP_MASK 0x3 - -/* MAX77621_CONTROL2 */ -#define MAX77621_WDTMR_ENABLE (1 << 6) -#define MAX77621_DISCH_ENBABLE (1 << 5) -#define MAX77621_FT_ENABLE (1 << 4) -#define MAX77621_T_JUNCTION_120 (1 << 7) - -#define MAX77621_CKKADV_TRIP_DISABLE 0xC -#define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 -#define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4 -#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 - -#define MAX77621_INDUCTOR_MIN_30_PER 0x0 -#define MAX77621_INDUCTOR_NOMINAL 0x1 -#define MAX77621_INDUCTOR_PLUS_30_PER 0x2 -#define MAX77621_INDUCTOR_PLUS_60_PER 0x3 - -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); -int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); -void max77620_config_default(); -void max77620_low_battery_monitor_config(); - -#endif diff --git a/bootloader/rtc/max77620-rtc.c b/bootloader/rtc/max77620-rtc.c deleted file mode 100644 index 98243d2..0000000 --- a/bootloader/rtc/max77620-rtc.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC - * - * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2019 shchmue - * - * 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 "max77620-rtc.h" -#include "../soc/i2c.h" -#include "../utils/util.h" - -void max77620_rtc_get_time(rtc_time_t *time) -{ - u8 val = 0; - - // Update RTC regs from RTC clock. - i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); - - // Get control reg config. - val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG); - // TODO: Check for binary format also? - - // Get time. - time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; - time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; - - time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F; - - if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK) - time->hour = (time->hour & 0xF) + 12; - - // Get day of week. 1: Monday to 7: Sunday. - time->weekday = 0; - val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG); - for (int i = 0; i < 8; i++) - { - time->weekday++; - if (val & 1) - break; - val >>= 1; - } - - // Get date. - time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; - time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; - time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; -} - -void max77620_rtc_stop_alarm() -{ - u8 val = 0; - - // Update RTC regs from RTC clock. - i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); - - // Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2. - for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++) - { - val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i); - val &= ~MAX77620_RTC_ALARM_EN_MASK; - i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val); - } - - // Update RTC clock from RTC regs. - i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); -} - -void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) -{ - u32 tmp, edays, year, month, day; - - // Set time. - time->sec = epoch % 60; - epoch /= 60; - time->min = epoch % 60; - epoch /= 60; - time->hour = epoch % 24; - epoch /= 24; - - // Calculate base date values. - tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15); - tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2)); - - year = (20 * tmp - 2442) / 7305; - edays = tmp - 365 * year - (year >> 2); - month = edays * 1000 / 30601; - day = edays - month * 30 - month * 601 / 1000; - - // Month/Year offset. - if(month < 14) - { - year -= 4716; - month--; - } - else - { - year -= 4715; - month -= 13; - } - - // Set date. - time->year = year; - time->month = month; - time->day = day; - - // Set weekday. - time->weekday = 0; //! TODO. -} - -u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding) -{ - u32 year, month, epoch; - - //Year - year = time->year; - //Month of year - month = time->month; - - if (!hos_encoding) - { - // Month/Year offset. - if(month < 3) - { - month += 12; - year--; - } - } - else - { - year -= 2000; - month++; - - // Month/Year offset. - if(month < 3) - { - month += 9; - year--; - } - else - month -= 3; - } - - epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days. - - if (!hos_encoding) - { - epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days. - epoch -= 719561; // Epoch time is 1/1/1970. - } - else - epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days. - - epoch *= 86400; // Days to seconds. - epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds. - - return epoch; -} diff --git a/bootloader/sec/se.c b/bootloader/sec/se.c deleted file mode 100644 index 8d27510..0000000 --- a/bootloader/sec/se.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../sec/se.h" -#include "../mem/heap.h" -#include "../soc/bpmp.h" -#include "../soc/t210.h" -#include "../sec/se_t210.h" -#include "../utils/util.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 (int 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) & SE_STATUS_0_STATE_WAIT_IN || - SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR) - return 0; - return 1; -} - -static int _se_execute(u32 op, void *dst, u32 dst_size, const 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); - - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - - SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); - int res = _se_wait(); - - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - - 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, const void *src, u32 src_size) -{ - if (!src || !dst) - return 0; - - 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 & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = - ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | - ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); - if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); -} - -void se_key_acc_ctrl(u32 ks, u32 flags) -{ - if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; - if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) - 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, const 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_BLOCK_COUNT_REG_OFFSET) = 0; - 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_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) -{ - 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) = (src_size >> 4) - 1; - return _se_execute(OP_START, dst, dst_size, src, src_size); -} - -int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) -{ - return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); -} - -int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const 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; -} - -// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256. -int se_calc_sha256(void *dst, const void *src, u32 src_size) -{ - int res; - // Setup config for SHA256, size = BITS(src_size). - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH; - SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; - - // Trigger the operation. - res = _se_execute(OP_START, NULL, 0, src, src_size); - - // Copy output hash. - u32 *dst32 = (u32 *)dst; - for (u32 i = 0; i < 8; i++) - dst32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); - - return res; -} - diff --git a/bootloader/sec/se.h b/bootloader/sec/se.h deleted file mode 100644 index bd70b28..0000000 --- a/bootloader/sec/se.h +++ /dev/null @@ -1,32 +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 . -*/ - -#ifndef _SE_H_ -#define _SE_H_ - -#include "../utils/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, const void *input); -int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); -int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); -int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); -int se_calc_sha256(void *dst, const void *src, u32 src_size); - -#endif diff --git a/bootloader/sec/se_t210.h b/bootloader/sec/se_t210.h deleted file mode 100644 index 3b610bc..0000000 --- a/bootloader/sec/se_t210.h +++ /dev/null @@ -1,389 +0,0 @@ -/* -* 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 "../utils/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_TZRAM_SECURITY_0 0x004 - -#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_STATUS_0_STATE_WAIT_IN 3 - -#define SE_ERR_STATUS_0 0x804 -#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0 - -#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_CONTINUE 0 -#define SHA_INIT_HASH 1 - -#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204 -#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208 -#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C -#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210 -#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214 -#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218 -#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C -#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220 - -#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_TBL_DIS_KEY_LOCK_FLAG 0x80 - -#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 -#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) -#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) -#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2) -#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3) -#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4) -#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5) -#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6) -#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F - -#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_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 - -#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 -#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) -#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) -#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2) -#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 -#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F - -#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/bootloader/sec/tsec.c b/bootloader/sec/tsec.c deleted file mode 100644 index 7c9f1e6..0000000 --- a/bootloader/sec/tsec.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * Copyright (c) 2018 balika011 - * - * 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 "../sec/tsec.h" -#include "../sec/tsec_t210.h" -#include "../sec/se_t210.h" -#include "../soc/bpmp.h" -#include "../soc/clock.h" -#include "../soc/kfuse.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../utils/util.h" -#include "../hos/hos.h" - -// #include "../gfx/gfx.h" - -static int _tsec_dma_wait_idle() -{ - u32 timeout = get_tmr_ms() + 10000; - - while (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE)) - if (get_tmr_ms() > timeout) - return 0; - - return 1; -} - -static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offset) -{ - u32 cmd; - - if (not_imem) - cmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes - else - cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory) - - TSEC(TSEC_DMATRFMOFFS) = i_offset; - TSEC(TSEC_DMATRFFBOFFS) = pa_offset; - TSEC(TSEC_DMATRFCMD) = cmd; - - return _tsec_dma_wait_idle(); -} - -int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) -{ - int res = 0; - u8 *fwbuf = NULL; - u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; - u32 *pkg11_magic_off; - - bpmp_mmu_disable(); - bpmp_clk_rate_set(BPMP_CLK_NORMAL); - - // Enable clocks. - clock_enable_host1x(); - usleep(2); - clock_enable_tsec(); - clock_enable_sor_safe(); - clock_enable_sor0(); - clock_enable_sor1(); - clock_enable_kfuse(); - - kfuse_wait_ready(); - - // Configure Falcon. - TSEC(TSEC_DMACTL) = 0; - TSEC(TSEC_IRQMSET) = - TSEC_IRQMSET_EXT(0xFF) | - TSEC_IRQMSET_WDTMR | - TSEC_IRQMSET_HALT | - TSEC_IRQMSET_EXTERR | - TSEC_IRQMSET_SWGEN0 | - TSEC_IRQMSET_SWGEN1; - TSEC(TSEC_IRQDEST) = - TSEC_IRQDEST_EXT(0xFF) | - TSEC_IRQDEST_HALT | - TSEC_IRQDEST_EXTERR | - TSEC_IRQDEST_SWGEN0 | - TSEC_IRQDEST_SWGEN1; - TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN; - if (!_tsec_dma_wait_idle()) - { - res = -1; - goto out; - } - - // Load firmware or emulate memio environment for newer TSEC fw. - if (kb == KB_FIRMWARE_VERSION_620) - TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; - else - { - fwbuf = (u8 *)malloc(0x4000); - u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100); - memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size); - TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8; - } - - for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100) - { - if (!_tsec_dma_pa_to_internal_100(false, addr, addr)) - { - res = -2; - goto out_free; - } - } - - if (kb == KB_FIRMWARE_VERSION_620) - { - // Init SMMU translation for TSEC. - pdir = smmu_init_for_tsec(); - smmu_init(tsec_ctxt->secmon_base); - // Enable SMMU - if (!smmu_is_used()) - smmu_enable(); - - // Clock reset controller. - car = page_alloc(1); - memcpy(car, (void *)CLOCK_BASE, 0x1000); - car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; - smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); - - // Fuse driver. - fuse = page_alloc(1); - memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); - fuse[0x82C / 4] = 0; - fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1; - fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1; - smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); - - // Power management controller. - pmc = page_alloc(1); - smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); - - // Flow control. - flowctrl = page_alloc(1); - smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); - - // Security engine. - se = page_alloc(1); - memcpy(se, (void *)SE_BASE, 0x1000); - smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); - - // Memory controller. - mc = page_alloc(1); - memcpy(mc, (void *)MC_BASE, 0x1000); - mc[MC_IRAM_BOM / 4] = 0; - mc[MC_IRAM_TOM / 4] = 0x80000000; - smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); - - // IRAM - iram = page_alloc(0x30); - memcpy(iram, tsec_ctxt->pkg1, 0x30000); - // PKG1.1 magic offset. - pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)); - smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); - - // Exception vectors - evec = page_alloc(1); - smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); - } - - // Execute firmware. - HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; - TSEC(TSEC_STATUS) = 0; - TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. - TSEC(TSEC_BOOTVEC) = 0; - TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; - - if (kb == KB_FIRMWARE_VERSION_620) - { - u32 start = get_tmr_us(); - u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; - u32 key[16] = {0}; - u32 kidx = 0; - - while (*pkg11_magic_off != HOS_PKG11_MAGIC) - { - smmu_flush_all(); - - if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]) - { - k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; - key[kidx++] = k; - } - - // Failsafe. - if ((u32)get_tmr_us() - start > 125000) - break; - } - - if (kidx != 8) - { - res = -6; - smmu_deinit_for_tsec(); - - goto out_free; - } - - // Give some extra time to make sure PKG1.1 is decrypted. - msleep(50); - - memcpy(tsec_keys, &key, 0x20); - memcpy(tsec_ctxt->pkg1, iram, 0x30000); - - smmu_deinit_for_tsec(); - - // for (int i = 0; i < kidx; i++) - // gfx_printf("key %08X\n", key[i]); - - // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); - - // u32 errst = MC(MC_ERR_STATUS); - // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); - // gfx_printf(" type: %02X\n", errst >> 28); - // gfx_printf(" smmu: %02X\n", (errst >> 25) & 3); - // gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R"); - // gfx_printf(" cid: %02x\n", errst & 0xFF); - } - else - { - if (!_tsec_dma_wait_idle()) - { - res = -3; - goto out_free; - } - u32 timeout = get_tmr_ms() + 2000; - while (!TSEC(TSEC_STATUS)) - if (get_tmr_ms() > timeout) - { - res = -4; - goto out_free; - } - if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) - { - res = -5; - goto out_free; - } - - // Fetch result. - HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; - u32 buf[4]; - buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); - buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); - buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); - buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); - SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; - - memcpy(tsec_keys, &buf, 0x10); - } - -out_free:; - free(fwbuf); - -out:; - - // Disable clocks. - clock_disable_kfuse(); - clock_disable_sor1(); - clock_disable_sor0(); - clock_disable_sor_safe(); - clock_disable_tsec(); - bpmp_mmu_enable(); - bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); - - return res; -} diff --git a/bootloader/soc/bpmp.c b/bootloader/soc/bpmp.c deleted file mode 100644 index 550ebbe..0000000 --- a/bootloader/soc/bpmp.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 - * - * Copyright (c) 2019 CTCaer - * - * 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 "bpmp.h" -#include "clock.h" -#include "t210.h" -#include "../../common/memory_map.h" -#include "../utils/util.h" - -#define BPMP_MMU_CACHE_LINE_SIZE 0x20 - -#define BPMP_CACHE_CONFIG 0x0 -#define CFG_ENABLE_CACHE (1 << 0) -#define CFG_ENABLE_SKEW_ASSOC (1 << 1) -#define CFG_DISABLE_RANDOM_ALLOC (1 << 2) -#define CFG_FORCE_WRITE_THROUGH (1 << 3) -#define CFG_NEVER_ALLOCATE (1 << 6) -#define CFG_ENABLE_INTERRUPT (1 << 7) -#define CFG_MMU_TAG_MODE(x) (x << 8) -#define TAG_MODE_PARALLEL 0 -#define TAG_MODE_TAG_FIRST 1 -#define TAG_MODE_MMU_FIRST 2 -#define CFG_DISABLE_WRITE_BUFFER (1 << 10) -#define CFG_DISABLE_READ_BUFFER (1 << 11) -#define CFG_ENABLE_HANG_DETECT (1 << 12) -#define CFG_FULL_LINE_DIRTY (1 << 13) -#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14) -#define CFG_TAG_CHK_CLR_ERR (1 << 15) -#define CFG_DISABLE_SAMELINE (1 << 16) -#define CFG_OBS_BUS_EN (1 << 31) - -#define BPMP_CACHE_LOCK 0x4 -#define LOCK_LINE(x) (1 << x) - -#define BPMP_CACHE_SIZE 0xC -#define BPMP_CACHE_LFSR 0x10 - -#define BPMP_CACHE_TAG_STATUS 0x14 -#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0) -#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0 - -#define BPMP_CACHE_CLKEN_OVERRIDE 0x18 -#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0) -#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1) - -#define BPMP_CACHE_MAINT_ADDR 0x20 -#define BPMP_CACHE_MAINT_DATA 0x24 - -#define BPMP_CACHE_MAINT_REQ 0x28 -#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8) - -#define BPMP_CACHE_INT_MASK 0x40 -#define BPMP_CACHE_INT_CLEAR 0x44 -#define BPMP_CACHE_INT_RAW_EVENT 0x48 -#define BPMP_CACHE_INT_STATUS 0x4C -#define INT_MAINT_DONE (1 << 0) -#define INT_MAINT_ERROR (1 << 1) - -#define BPMP_CACHE_RB_CFG 0x80 -#define BPMP_CACHE_WB_CFG 0x84 - -#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0 -#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 - -#define BPMP_CACHE_MMU_CFG 0xAC -#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0) -#define MMU_CFG_SEQ_EN (1 << 1) -#define MMU_CFG_TLB_EN (1 << 2) -#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3) -#define MMU_CFG_ABORT_STORE_LAST (1 << 4) -#define MMU_CFG_CLR_ABORT (1 << 5) - -#define BPMP_CACHE_MMU_CMD 0xB0 -#define MMU_CMD_NOP 0 -#define MMU_CMD_INIT 1 -#define MMU_CMD_COPY_SHADOW 2 - -#define BPMP_CACHE_MMU_ABORT_STAT 0xB4 -#define ABORT_STAT_UNIT_MASK 0x7 -#define ABORT_STAT_UNIT_NONE 0 -#define ABORT_STAT_UNIT_CACHE 1 -#define ABORT_STAT_UNIT_SEQ 2 -#define ABORT_STAT_UNIT_TLB 3 -#define ABORT_STAT_UNIT_SEG 4 -#define ABORT_STAT_UNIT_FALLBACK 5 -#define ABORT_STAT_OVERLAP (1 << 3) -#define ABORT_STAT_ENTRY (0x1F << 4) -#define ABORT_STAT_TYPE_MASK (3 << 16) -#define ABORT_STAT_TYPE_EXE (0 << 16) -#define ABORT_STAT_TYPE_RD (1 << 16) -#define ABORT_STAT_TYPE_WR (2 << 16) -#define ABORT_STAT_SIZE (3 << 18) -#define ABORT_STAT_SEQ (1 << 20) -#define ABORT_STAT_PROT (1 << 21) - -#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8 -#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC - -#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) -#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) -#define MMU_EN_CACHED (1 << 0) -#define MMU_EN_EXEC (1 << 1) -#define MMU_EN_READ (1 << 2) -#define MMU_EN_WRITE (1 << 3) - -bpmp_mmu_entry_t mmu_entries[] = -{ - { DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }, - { IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true } -}; - -void bpmp_mmu_maintenance(u32 op, bool force) -{ - if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)) - return; - - BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE; - - // This is a blocking operation. - BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op; - - while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE)) - ; - - BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT); -} - -void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) -{ - if (idx > 31) - return; - - volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx); - - if (entry->enable) - { - mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE); - mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE); - mmu_entry->attr = entry->attr; - - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx); - - if (apply) - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; - } -} - -void bpmp_mmu_enable() -{ - if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE) - return; - - // Init BPMP MMU. - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT; - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions. - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST; - - // Init BPMP MMU entries. - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0; - for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++) - bpmp_mmu_set_entry(idx, &mmu_entries[idx], false); - - BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; - - // Invalidate cache. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true); - - // Enable cache. - BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH | - CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR; - - // HW bug. Invalidate cache again. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); -} - -void bpmp_mmu_disable() -{ - if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)) - return; - - // Clean and invalidate cache. - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - - // Disable cache. - BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; -} - -// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM, -// I2C host, DC/DSI/DISP. UART gives extra stress. -// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less. -const u8 pll_divn[] = { - 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB. - 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. - 90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB. - 92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB. - // Do not use for public releases! - //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB. -}; - -bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; - -void bpmp_clk_rate_get() -{ - bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3; - - if (clk_src_is_pllp) - bpmp_clock_set = BPMP_CLK_NORMAL; - else - { - bpmp_clock_set = BPMP_CLK_HIGH_BOOST; - - u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; - for (u32 i = 1; i < sizeof(pll_divn); i++) - { - if (pll_divn[i] == pll_divn_curr) - { - bpmp_clock_set = i; - break; - } - } - } -} - -void bpmp_clk_rate_set(bpmp_freq_t fid) -{ - if (fid > (BPMP_CLK_MAX - 1)) - fid = BPMP_CLK_MAX - 1; - - if (bpmp_clock_set == fid) - return; - - if (fid) - { - if (bpmp_clock_set) - { - // Restore to PLLP source during PLLC4 configuration. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. - msleep(1); // Wait a bit for clock source change. - } - - // Configure and enable PLLC. - clock_enable_pllc(pll_divn[fid]); - - // Set SCLK / HCLK / PCLK. - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle. - } - else - { - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle. - msleep(1); // Wait a bit for clock source change. - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK. - - // Disable PLLC to save power. - clock_disable_pllc(); - } - bpmp_clock_set = fid; -} - -// The following functions halt BPMP to reduce power while sleeping. -// They are not as accurate as RTC at big values but they guarantee time+ delay. -void bpmp_usleep(u32 us) -{ - u32 delay; - - // Each iteration takes 1us. - while (us) - { - delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; - us -= delay; - - FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; - } -} - -void bpmp_msleep(u32 ms) -{ - u32 delay; - - // Iteration time is variable. ~200 - 1000us. - while (ms) - { - delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; - ms -= delay; - - FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; - } -} - -void bpmp_halt() -{ - FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; -} diff --git a/bootloader/soc/bpmp.h b/bootloader/soc/bpmp.h deleted file mode 100644 index dce62cc..0000000 --- a/bootloader/soc/bpmp.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 - * - * Copyright (c) 2019 CTCaer - * - * 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 _BPMP_H_ -#define _BPMP_H_ - -#include "../utils/types.h" - -typedef enum -{ - BPMP_MMU_MAINT_NOP = 0, - BPMP_MMU_MAINT_CLEAN_PHY = 1, - BPMP_MMU_MAINT_INVALID_PHY = 2, - BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3, - BPMP_MMU_MAINT_CLEAN_LINE = 9, - BPMP_MMU_MAINT_INVALID_LINE = 10, - BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11, - BPMP_MMU_MAINT_CLEAN_WAY = 17, - BPMP_MMU_MAINT_INVALID_WAY = 18, - BPMP_MMU_MAINT_CLN_INV_WAY = 19 -} bpmp_maintenance_t; - -typedef struct _bpmp_mmu_entry_t -{ - u32 start_addr; - u32 end_addr; - u32 attr; - u32 enable; -} bpmp_mmu_entry_t; - -typedef enum -{ - BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB. - BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB. - BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB. - BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB. - //BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB. - BPMP_CLK_MAX -} bpmp_freq_t; - -#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST - -void bpmp_mmu_maintenance(u32 op, bool force); -void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); -void bpmp_mmu_enable(); -void bpmp_mmu_disable(); -void bpmp_clk_rate_get(); -void bpmp_clk_rate_set(bpmp_freq_t fid); -void bpmp_usleep(u32 us); -void bpmp_msleep(u32 ms); -void bpmp_halt(); - -#endif diff --git a/bootloader/soc/clock.c b/bootloader/soc/clock.c deleted file mode 100644 index ebbe572..0000000 --- a/bootloader/soc/clock.c +++ /dev/null @@ -1,590 +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 "../soc/clock.h" -#include "../soc/t210.h" -#include "../utils/util.h" -#include "../storage/sdmmc.h" - -/* - * CLOCK Peripherals: - * L 0 - 31 - * H 32 - 63 - * U 64 - 95 - * V 96 - 127 - * W 128 - 159 - * X 160 - 191 - * Y 192 - 223 - */ - -/* clock_t: reset, enable, source, index, clk_src, clk_div */ - -static const clock_t _clock_uart[] = { -/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 }, -/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 }, -/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 }, -/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 }, -/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 } -}; - -//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26. -static const clock_t _clock_i2c[] = { -/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz -/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz -/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz -/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz -/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz -/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz -}; - -static clock_t _clock_se = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 -}; - -static clock_t _clock_tzram = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0 -}; - -static clock_t _clock_host1x = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 -}; -static clock_t _clock_tsec = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 -}; -static clock_t _clock_sor_safe = { - CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0 -}; -static clock_t _clock_sor0 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0 -}; -static clock_t _clock_sor1 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 -}; -static clock_t _clock_kfuse = { - CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 -}; - -static clock_t _clock_cl_dvfs = { - CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0 -}; -static clock_t _clock_coresight = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 -}; - -static clock_t _clock_pwm = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. -}; - -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); - usleep(2); - - // 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(bool enable) -{ - CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28); -} - -void clock_enable_uart(u32 idx) -{ - clock_enable(&_clock_uart[idx]); -} - -void clock_enable_i2c(u32 idx) -{ - clock_enable(&_clock_i2c[idx]); -} - -void clock_disable_i2c(u32 idx) -{ - clock_disable(&_clock_i2c[idx]); -} - -void clock_enable_se() -{ - clock_enable(&_clock_se); -} - -void clock_enable_tzram() -{ - clock_enable(&_clock_tzram); -} - -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(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100; - usleep(10); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF; - usleep(20); -} - -void clock_disable_kfuse() -{ - clock_disable(&_clock_kfuse); -} - -void clock_enable_cl_dvfs() -{ - clock_enable(&_clock_cl_dvfs); -} - -void clock_disable_cl_dvfs() -{ - clock_disable(&_clock_cl_dvfs); -} - -void clock_enable_coresight() -{ - clock_enable(&_clock_coresight); -} - -void clock_disable_coresight() -{ - clock_disable(&_clock_coresight); -} - -void clock_enable_pwm() -{ - clock_enable(&_clock_pwm); -} - -void clock_disable_pwm() -{ - clock_disable(&_clock_pwm); -} - -void clock_enable_pllc(u32 divn) -{ - u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; - - // Check if already enabled and configured. - if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn)) - return; - - // Take PLLC out of reset and set basic misc parameters. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = - ((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM. - - // Disable PLL and IDDQ in case they are on. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; - usleep(10); - - // Set PLLC4 dividers. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. - - // Enable PLLC4 and wait for Phase and Frequency lock. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; - while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) - ; - - // Disable PLLC_OUT1, enable reset and set div to 1.5. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8); - - // Enable PLLC_OUT1 and bring it out of reset. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); - msleep(1); // Wait a bit for PLL to stabilize. -} - -void clock_disable_pllc() -{ - // Disable PLLC and PLLC_OUT1. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS; - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ; - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET; - usleep(10); -} - -#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; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; - break; - } -} - -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; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; - break; - } -} - -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 void _clock_sdmmc_set_enable(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; - break; - } -} - -static void _clock_sdmmc_clear_enable(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; - break; - } -} - -static u32 _clock_sdmmc_table[8] = { 0 }; - -#define PLLP_OUT0 0x0 -static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) -{ - u32 divisor = 0; - u32 source = PLLP_OUT0; - - // Get IO clock divisor. - switch (val) - { - case 25000: - *pout = 24728; - divisor = 31; // 16.5 div. - break; - case 26000: - *pout = 25500; - divisor = 30; // 16 div. - break; - case 40800: - *pout = 40800; - divisor = 18; // 10 div. - break; - case 50000: - *pout = 48000; - divisor = 15; // 8.5 div. - break; - case 52000: - *pout = 51000; - divisor = 14; // 8 div. - break; - case 100000: - *pout = 90667; - divisor = 7; // 4.5 div. - break; - case 200000: - *pout = 163200; - divisor = 3; // 2.5 div. - break; - case 208000: - *pout = 204000; - divisor = 2; // 2 div. - break; - default: - *pout = 24728; - divisor = 31; // 16.5 div. - } - - _clock_sdmmc_table[2 * id] = val; - _clock_sdmmc_table[2 * id + 1] = *pout; - - // Set SDMMC clock. - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | 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_host(pout, id, val); - if (is_enabled) - _clock_sdmmc_set_enable(id); - _clock_sdmmc_is_reset(id); - } -} - -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) -{ - // Get Card clock divisor. - 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; - break; - case 6: - case 8: - *pout = 25000; - *pdivisor = 1; - break; - case 7: - *pout = 50000; - *pdivisor = 1; - break; - case 10: - *pout = 100000; - *pdivisor = 1; - break; - 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_host(&div, id, val); - _clock_sdmmc_set_enable(id); - _clock_sdmmc_is_reset(id); - usleep((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/bootloader/soc/clock.h b/bootloader/soc/clock.h deleted file mode 100644 index 3679b46..0000000 --- a/bootloader/soc/clock.h +++ /dev/null @@ -1,201 +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 . - */ - -#ifndef _CLOCK_H_ -#define _CLOCK_H_ - -#include "../utils/types.h" - -/*! Clock registers. */ -#define CLK_RST_CONTROLLER_RST_SOURCE 0x0 -#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 -#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 -#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_PLLC_BASE 0x80 -#define CLK_RST_CONTROLLER_PLLC_OUT 0x84 -#define CLK_RST_CONTROLLER_PLLC_MISC 0x88 -#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C -#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 -#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 -#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C -#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 -#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 -#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 -#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC -#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 -#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 -#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 -#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC -#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 -#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 -#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_UARTA 0x178 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C -#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 -#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 -#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 -#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C -#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290 -#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 -#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C -#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0 -#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4 -#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8 -#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC -#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_H_CLR 0x30C -#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_H_CLR 0x32C -#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_RST_DEVICES_W 0x35C -#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_LVL2_CLK_GATE_OVRC 0x3A0 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C -#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 -#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 -#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 -#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 -#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C -#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 -#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 -#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 -#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C -#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 -#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 -#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C -#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 -#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 -#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 -#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 -#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 -#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 -#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 - -#define CLK_NO_SOURCE 0x0 - -/*! PLL control and status bits */ -#define PLLCX_BASE_ENABLE (1 << 30) -#define PLLCX_BASE_REF_DIS (1 << 29) -#define PLLCX_BASE_LOCK (1 << 27) - -#define PLLC_MISC_RESET (1 << 30) -#define PLLC_MISC1_IDDQ (1 << 27) -#define PLLC_OUT1_CLKEN (1 << 1) -#define PLLC_OUT1_RSTN_CLR (1 << 0) - -#define PLLC4_MISC_EN_LCKDET (1 << 30) -#define PLLC4_BASE_IDDQ (1 << 18) -#define PLLC4_OUT3_CLKEN (1 << 1) -#define PLLC4_OUT3_RSTN_CLR (1 << 0) - -/*! Generic clock descriptor. */ -typedef struct _clock_t -{ - u32 reset; - u32 enable; - u32 source; - u8 index; - u8 clk_src; - 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(bool enable); -void clock_enable_uart(u32 idx); -void clock_enable_i2c(u32 idx); -void clock_disable_i2c(u32 idx); -void clock_enable_se(); -void clock_enable_tzram(); -void clock_enable_host1x(); -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_disable_cl_dvfs(); -void clock_enable_coresight(); -void clock_disable_coresight(); -void clock_enable_pwm(); -void clock_disable_pwm(); -void clock_enable_pllc(u32 divn); -void clock_disable_pllc(); -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_card_clock_div(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/bootloader/soc/cluster.c b/bootloader/soc/cluster.c deleted file mode 100644 index 79538ed..0000000 --- a/bootloader/soc/cluster.c +++ /dev/null @@ -1,140 +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 "../soc/cluster.h" -#include "../soc/i2c.h" -#include "../soc/clock.h" -#include "../utils/util.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" - -void _cluster_enable_power() -{ - u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); - - // Enable cores power. - // 1-3.x: MAX77621_NFSR_ENABLE. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, - MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); - // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); -} - -int _cluster_pmc_enable_partition(u32 part, int enable) -{ - u32 part_mask = 1 << part; - u32 desired_state = enable << part; - - // Check if the partition has the state we want. - if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) - return 1; - - u32 i = 5001; - while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) - { - usleep(1); - i--; - if (i < 1) - return 0; - } - - // Toggle power gating. - PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; - - i = 5001; - while (i > 0) - { - if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) - break; - usleep(1); - i--; - } - - return 1; -} - -void cluster_boot_cpu0(u32 entry) -{ - // Set ACTIVE_CLUSER to FAST. - FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE; - - _cluster_enable_power(); - - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. - { - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. - usleep(2); - 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(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000)) - ; - - // 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(); - - // CAR2PMC_CPU_ACK_WIDTH should be set to 0. - CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; - - // Enable CPU rail. - _cluster_pmc_enable_partition(0, 1); - // Enable cluster 0 non-CPU. - _cluster_pmc_enable_partition(15, 1); - // Enable CE0. - _cluster_pmc_enable_partition(14, 1); - - // Request and wait for RAM repair. - FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; - while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2)) - ; - - EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; - - // Set reset vector. - SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; - SB(SB_AA64_RESET_HIGH) = 0; - // Non-secure reset vector write disable. - SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; - (void)SB(SB_CSR); - - // Tighten up the security aperture. - // MC(MC_TZ_SECURITY_CTRL) = 1; - - // Clear MSELECT reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; - // Clear NONCPU reset. - CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; - // Clear CPU0 reset. - // < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. - CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001; -} diff --git a/bootloader/soc/fuse.c b/bootloader/soc/fuse.c deleted file mode 100644 index 04d3612..0000000 --- a/bootloader/soc/fuse.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 shuffle2 - * Copyright (c) 2018 balika011 - * Copyright (c) 2019 CTCaer - * - * 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 "../soc/fuse.h" -#include "../soc/t210.h" - -#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) - -static const u32 evp_thunk_template[] = { - 0xe92d0007, // STMFD SP!, {R0-R2} - 0xe1a0200e, // MOV R2, LR - 0xe2422002, // SUB R2, R2, #2 - 0xe5922000, // LDR R2, [R2] - 0xe20220ff, // AND R2, R2, #0xFF - 0xe1a02082, // MOV R2, R2,LSL#1 - 0xe59f001c, // LDR R0, =evp_thunk_template - 0xe59f101c, // LDR R1, =thunk_end - 0xe0411000, // SUB R1, R1, R0 - 0xe59f0018, // LDR R0, =iram_evp_thunks - 0xe0800001, // ADD R0, R0, R1 - 0xe0822000, // ADD R2, R2, R0 - 0xe3822001, // ORR R2, R2, #1 - 0xe8bd0003, // LDMFD SP!, {R0,R1} - 0xe12fff12, // BX R2 - 0x001007b0, // off_1007EC DCD evp_thunk_template - 0x001007f8, // off_1007F0 DCD thunk_end - 0x40004c30, // off_1007F4 DCD iram_evp_thunks - // thunk_end is here -}; -static const u32 evp_thunk_template_len = sizeof(evp_thunk_template); - -// treated as 12bit values -static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11}; - -void fuse_disable_program() -{ - FUSE(FUSE_DISABLEREGPROGRAM) = 1; -} - -u32 fuse_read_odm(u32 idx) -{ - return FUSE(FUSE_RESERVED_ODMX(idx)); -} - -void fuse_wait_idle() -{ - u32 ctrl; - do - { - ctrl = FUSE(FUSE_CTRL); - } while (((ctrl >> 16) & 0x1f) != 4); -} - -u32 fuse_read(u32 addr) -{ - FUSE(FUSE_ADDR) = addr; - FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; - fuse_wait_idle(); - return FUSE(FUSE_RDATA); -} - -void fuse_read_array(u32 *words) -{ - for (u32 i = 0; i < 192; i++) - words[i] = fuse_read(i); -} - -static u32 _parity32_even(u32 *words, u32 count) -{ - u32 acc = words[0]; - for (u32 i = 1; i < count; i++) - { - acc ^= words[i]; - } - u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff; - u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8; - u32 x = hi ^ lo; - lo = ((x & 0xf) ^ (x >> 4)) & 3; - hi = ((x & 0xf) ^ (x >> 4)) >> 2; - x = hi ^ lo; - - return (x & 1) ^ (x >> 1); -} - -static int _patch_hash_one(u32 *word) -{ - u32 bits20_31 = *word & 0xfff00000; - u32 parity_bit = _parity32_even(&bits20_31, 1); - u32 hash = 0; - for (u32 i = 0; i < 12; i++) - { - if (*word & (1 << (20 + i))) - { - hash ^= hash_vals[i]; - } - } - if (hash == 0) - { - if (parity_bit == 0) - { - return 0; - } - *word ^= 1 << 24; - return 1; - } - if (parity_bit == 0) - { - return 3; - } - for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++) - { - if (hash_vals[i] == hash) - { - *word ^= 1 << (20 + i); - return 1; - } - } - return 2; -} - -static int _patch_hash_multi(u32 *words, u32 count) -{ - u32 parity_bit = _parity32_even(words, count); - u32 bits0_14 = words[0] & 0x7fff; - u32 bit15 = words[0] & 0x8000; - u32 bits16_19 = words[0] & 0xf0000; - - u32 hash = 0; - words[0] = bits16_19; - for (u32 i = 0; i < count; i++) - { - u32 w = words[i]; - if (w) - { - for (u32 bitpos = 0; bitpos < 32; bitpos++) - { - if ((w >> bitpos) & 1) - { - hash ^= 0x4000 + i * 32 + bitpos; - } - } - } - } - hash ^= bits0_14; - // stupid but this is what original code does. - // equivalent to original words[0] &= 0xfff00000 - words[0] = bits16_19 ^ bit15 ^ bits0_14; - - if (hash == 0) - { - if (parity_bit == 0) - { - return 0; - } - words[0] ^= 0x8000; - return 1; - } - if (parity_bit == 0) - { - return 3; - } - u32 bitcount = hash - 0x4000; - if (bitcount < 16 || bitcount >= count * 32) - { - u32 num_set = 0; - for (u32 bitpos = 0; bitpos < 15; bitpos++) - { - if ((hash >> bitpos) & 1) - { - num_set++; - } - } - if (num_set != 1) - { - return 2; - } - words[0] ^= hash; - return 1; - } - words[bitcount / 32] ^= 1 << (hash & 0x1f); - return 1; -} - -int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) -{ - u32 words[80]; - u32 word_count; - u32 word_addr; - u32 word0 = 0; - u32 total_read = 0; - - word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); - word_count &= 0x7F; - word_addr = 191; - - while (word_count) - { - total_read += word_count; - if (total_read >= ARRAYSIZE(words)) - { - break; - } - - for (u32 i = 0; i < word_count; i++) - words[i] = fuse_read(word_addr--); - - word0 = words[0]; - if (_patch_hash_multi(words, word_count) >= 2) - { - return 1; - } - u32 ipatch_count = (words[0] >> 16) & 0xF; - if (ipatch_count) - { - for (u32 i = 0; i < ipatch_count; i++) - { - u32 word = words[i + 1]; - u32 addr = (word >> 16) * 2; - u32 data = word & 0xFFFF; - - ipatch(addr, data); - } - } - words[0] = word0; - if ((word0 >> 25) == 0) - break; - if (_patch_hash_one(&word0) >= 2) - { - return 3; - } - word_count = word0 >> 25; - } - - return 0; -} - -int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) -{ - u32 words[80]; - u32 word_count; - u32 word_addr; - u32 word0 = 0; - u32 total_read = 0; - int evp_thunk_written = 0; - void *evp_thunk_dst_addr = 0; - - memset(iram_evp_thunks, 0, *iram_evp_thunks_len); - - word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); - word_count &= 0x7F; - word_addr = 191; - - while (word_count) - { - total_read += word_count; - if (total_read >= ARRAYSIZE(words)) - { - break; - } - - for (u32 i = 0; i < word_count; i++) - words[i] = fuse_read(word_addr--); - - word0 = words[0]; - if (_patch_hash_multi(words, word_count) >= 2) - { - return 1; - } - u32 ipatch_count = (words[0] >> 16) & 0xF; - u32 insn_count = word_count - ipatch_count - 1; - if (insn_count) - { - if (!evp_thunk_written) - { - evp_thunk_dst_addr = (void *)iram_evp_thunks; - - memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len); - evp_thunk_dst_addr += evp_thunk_template_len; - evp_thunk_written = 1; - *iram_evp_thunks_len = evp_thunk_template_len; - - //write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks); - } - - u32 thunk_patch_len = insn_count * sizeof(u32); - memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len); - evp_thunk_dst_addr += thunk_patch_len; - *iram_evp_thunks_len += thunk_patch_len; - } - words[0] = word0; - if ((word0 >> 25) == 0) - break; - if (_patch_hash_one(&word0) >= 2) - { - return 3; - } - word_count = word0 >> 25; - } - - return 0; -} - -bool fuse_check_patched_rcm() -{ - // Check if XUSB in use. - if (FUSE(FUSE_RESERVED_SW) & (1<<7)) - return true; - - // Check if RCM is ipatched. - u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; - u32 word_addr = 191; - - while (word_count) - { - u32 word0 = fuse_read(word_addr); - u32 ipatch_count = (word0 >> 16) & 0xF; - - for (u32 i = 0; i < ipatch_count; i++) - { - u32 word = fuse_read(word_addr - (i + 1)); - u32 addr = (word >> 16) * 2; - if (addr == 0x769A) - return true; - } - - word_addr -= word_count; - word_count = word0 >> 25; - } - - return false; -} diff --git a/bootloader/soc/fuse.h b/bootloader/soc/fuse.h deleted file mode 100644 index 9240b04..0000000 --- a/bootloader/soc/fuse.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 shuffle2 - * Copyright (c) 2018 balika011 - * - * 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 "../utils/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 -#define FUSE_SKU_INFO 0x110 -#define FUSE_CPU_SPEEDO_0_CALIB 0x114 -#define FUSE_CPU_IDDQ_CALIB 0x118 -#define FUSE_OPT_FT_REV 0x128 -#define FUSE_CPU_SPEEDO_1_CALIB 0x12C -#define FUSE_CPU_SPEEDO_2_CALIB 0x130 -#define FUSE_SOC_SPEEDO_0_CALIB 0x134 -#define FUSE_SOC_SPEEDO_1_CALIB 0x138 -#define FUSE_SOC_SPEEDO_2_CALIB 0x13C -#define FUSE_SOC_IDDQ_CALIB 0x140 -#define FUSE_OPT_CP_REV 0x190 -#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c -#define FUSE_PRIVATE_KEY0 0x1A4 -#define FUSE_PRIVATE_KEY1 0x1A8 -#define FUSE_PRIVATE_KEY2 0x1AC -#define FUSE_PRIVATE_KEY3 0x1B0 -#define FUSE_PRIVATE_KEY4 0x1B4 -#define FUSE_RESERVED_SW 0x1C0 -#define FUSE_SKU_DIRECT_CONFIG 0x1F4 -#define FUSE_OPT_VENDOR_CODE 0x200 -#define FUSE_OPT_FAB_CODE 0x204 -#define FUSE_OPT_LOT_CODE_0 0x208 -#define FUSE_OPT_LOT_CODE_1 0x20C -#define FUSE_OPT_WAFER_ID 0x210 -#define FUSE_OPT_X_COORDINATE 0x214 -#define FUSE_OPT_Y_COORDINATE 0x218 -#define FUSE_GPU_IDDQ_CALIB 0x228 - -/*! Fuse commands. */ -#define FUSE_READ 0x1 -#define FUSE_WRITE 0x2 -#define FUSE_SENSE 0x3 -#define FUSE_CMD_MASK 0x3 - -/*! Fuse cache registers. */ -#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) - -void fuse_disable_program(); -u32 fuse_read_odm(u32 idx); -void fuse_wait_idle(); -int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); -int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); -void fuse_read_array(u32 *words); -bool fuse_check_patched_rcm(); - -#endif diff --git a/bootloader/soc/gpio.c b/bootloader/soc/gpio.c deleted file mode 100644 index 053c43a..0000000 --- a/bootloader/soc/gpio.c +++ /dev/null @@ -1,94 +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 "../soc/gpio.h" -#include "../soc/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/bootloader/soc/hw_init.c b/bootloader/soc/hw_init.c deleted file mode 100644 index 809588b..0000000 --- a/bootloader/soc/hw_init.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * - * 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 "hw_init.h" -#include "bpmp.h" -#include "clock.h" -#include "fuse.h" -#include "gpio.h" -#include "i2c.h" -#include "pinmux.h" -#include "pmc.h" -#include "t210.h" -#include "uart.h" -#include "../gfx/di.h" -#include "../mem/mc.h" -#include "../mem/minerva.h" -#include "../mem/sdram.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../storage/sdmmc.h" -#include "../utils/util.h" - -extern sdmmc_t sd_sdmmc; -extern boot_cfg_t b_cfg; -extern volatile nyx_storage_t *nyx_str; - -/* - * CLK_OSC - 38.4 MHz crystal. - * CLK_M - 19.2 MHz (osc/2). - * CLK_S - 32.768 KHz (from PMIC). - * SCLK - 204MHz init (-> 408MHz -> OC). - * HCLK - 204MHz init (-> 408MHz -> OC). - * PCLK - 68MHz init (-> 136MHz -> OC/4). - */ - -void _config_oscillators() -{ - CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. - SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. - TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. - CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. - - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; - PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; - PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE. - - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable. - - PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) - - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). - CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. -} - -void _config_gpios() -{ - PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; - PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; - - // Set Joy-Con IsAttached direction. - PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; - - // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. -#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B - gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); -#endif -#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C - gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); -#endif - // Set Joy-Con IsAttached mode. - gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); - gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); - - // Enable input logic for Joy-Con IsAttached and UARTB/C TX pins. - 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); - - // Configure HOME as inputs. - // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; - // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); -} - -void _config_pmc_scratch() -{ - PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. - PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL - PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; -} - -void _mbist_workaround() -{ - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. - - // Set mux output to SOR1 clock switch. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; - // Enabled PLLD and set csi to PLLD for test pattern generation. - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; - - // Clear per-clock resets. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. - usleep(2); - - // I2S channels to master and disable SLCG. - I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE; - - DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE. - VIC(0x8C) = 0xFFFFFFFF; - usleep(2); - - // Set per-clock reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC. - - // Enable specific clocks and disable all others. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. - //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USBD ON. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA. - - // Disable clock gate overrides. - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; - - // Set child clock sources. - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. -} - -void _config_se_brom() -{ - // Skip SBK/SSK if sept was run. - if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) - { - // Bootrom part we skipped. - u32 sbk[4] = { - FUSE(FUSE_PRIVATE_KEY0), - FUSE(FUSE_PRIVATE_KEY1), - FUSE(FUSE_PRIVATE_KEY2), - FUSE(FUSE_PRIVATE_KEY3) - }; - // Set SBK to slot 14. - se_aes_key_set(14, sbk, 0x10); - - // Lock SBK from being read. - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E; - - // Lock SSK (although it's not set and unused anyways). - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; - } - - // This memset needs to happen here, else TZRAM will behave weirdly later on. - memset((void *)TZRAM_BASE, 0, 0x10000); - PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE; - SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; - - // Clear the boot reason to avoid problems later - PMC(APBDEV_PMC_SCRATCH200) = 0x0; - PMC(APBDEV_PMC_RST_STATUS) = 0x0; - APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); -} - -void _config_regulators() -{ - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, - (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. - - // Configure all Flexible Power Sequencers. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); - max77620_regulator_config_fps(REGULATOR_LDO4); - max77620_regulator_config_fps(REGULATOR_LDO8); - max77620_regulator_config_fps(REGULATOR_SD0); - max77620_regulator_config_fps(REGULATOR_SD1); - max77620_regulator_config_fps(REGULATOR_SD3); - - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, - (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ - - // Set vdd_core voltage to 1.125V. - max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); - - // Fix CPU/GPU after a L4T warmboot. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); - - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - // Enable low battery shutdown monitor for < 2800mV. - max77620_low_battery_monitor_config(); -} - -void config_hw() -{ - // Bootrom stuff we skipped by going through rcm. - _config_se_brom(); - //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; - SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. - PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC; - - _mbist_workaround(); - clock_enable_se(); - - // Enable fuse clock. - clock_enable_fuse(true); - - // Disable fuse programming. - fuse_disable_program(); - - mc_enable(); - - _config_oscillators(); - APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; - _config_gpios(); - -#ifdef DEBUG_UART_PORT - clock_enable_uart(DEBUG_UART_PORT); - uart_init(DEBUG_UART_PORT, 115200); -#endif - - clock_enable_cl_dvfs(); - - clock_enable_i2c(I2C_1); - clock_enable_i2c(I2C_5); - - clock_enable_tzram(); - - i2c_init(I2C_1); - i2c_init(I2C_5); - - _config_regulators(); - - _config_pmc_scratch(); // Missing from 4.x+ - - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). - - sdram_init(); - - bpmp_mmu_enable(); -} - -void reconfig_hw_workaround(bool extra_reconfig, u32 magic) -{ - // Flush and disable MMU. - bpmp_mmu_disable(); - bpmp_clk_rate_set(BPMP_CLK_NORMAL); - minerva_change_freq(FREQ_204); - nyx_str->mtc_cfg.init_done = 0; - - // Re-enable clocks to Audio Processing Engine as a workaround to hanging. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. - - if (extra_reconfig) - { - msleep(10); - PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; - - clock_disable_cl_dvfs(); - - // Disable Joy-con GPIOs. - gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO); - } - - // Power off display. - display_end(); - - // Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits. - if (magic == 0xBAADF00D) - { - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); - sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0); - clock_disable_cl_dvfs(); - - msleep(200); - } -} diff --git a/bootloader/soc/i2c.c b/bootloader/soc/i2c.c deleted file mode 100644 index d06d64a..0000000 --- a/bootloader/soc/i2c.c +++ /dev/null @@ -1,143 +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 - -#include "i2c.h" -#include "../utils/util.h" - -static u32 i2c_addrs[] = { - 0x7000C000, 0x7000C400, 0x7000C500, - 0x7000C700, 0x7000D000, 0x7000D100 -}; - -static void _i2c_wait(vu32 *base) -{ - base[I2C_CONFIG_LOAD] = 0x25; - for (u32 i = 0; i < 20; i++) - { - usleep(1); - if (!(base[I2C_CONFIG_LOAD] & 1)) - break; - } -} - -static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) -{ - if (size > 4) - return 0; - - u32 tmp = 0; - memcpy(&tmp, buf, size); - - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). - base[I2C_CMD_DATA1] = tmp; //Set value. - base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. - _i2c_wait(base); //Kick transaction. - - base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; - while (base[I2C_STATUS] & 0x100) - ; - - if (base[I2C_STATUS] << 28) - return 0; - - return 1; -} - -static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) -{ - if (size > 8) - return 0; - - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). - base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode. - _i2c_wait(base); // Kick transaction. - - base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; - while (base[I2C_STATUS] & 0x100) - ; - - if (base[I2C_STATUS] << 28) - return 0; - - u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. - if (size > 4) - { - memcpy(buf, &tmp, 4); - tmp = base[I2C_CMD_DATA2]; // Get MS value. - memcpy(buf + 4, &tmp, size - 4); - } - else - memcpy(buf, &tmp, size); - - return 1; -} - -void i2c_init(u32 idx) -{ - vu32 *base = (vu32 *)i2c_addrs[idx]; - - base[I2C_CLK_DIVISOR_REGISTER] = 0x50001; - base[I2C_BUS_CLEAR_CONFIG] = 0x90003; - _i2c_wait(base); - - for (u32 i = 0; i < 10; i++) - { - usleep(20000); - if (base[INTERRUPT_STATUS_REGISTER] & 0x800) - break; - } - - (vu32)base[I2C_BUS_CLEAR_STATUS]; - base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER]; -} - -int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) -{ - u8 tmp[4]; - - if (size > 3) - return 0; - - tmp[0] = y; - memcpy(tmp + 1, buf, size); - - return _i2c_send_pkt(idx, x, tmp, size + 1); -} - -int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y) -{ - int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); - if (res) - res = _i2c_recv_pkt(idx, buf, size, x); - return res; -} - -int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b) -{ - return i2c_send_buf_small(idx, x, y, &b, 1); -} - -u8 i2c_recv_byte(u32 idx, u32 x, u32 y) -{ - u8 tmp = 0; - i2c_recv_buf_small(&tmp, 1, idx, x, y); - return tmp; -} - diff --git a/bootloader/soc/kfuse.c b/bootloader/soc/kfuse.c deleted file mode 100644 index f2fde5a..0000000 --- a/bootloader/soc/kfuse.c +++ /dev/null @@ -1,56 +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 "../soc/kfuse.h" -#include "../soc/clock.h" -#include "../soc/t210.h" - -#pragma GCC push_options -#pragma GCC optimize ("Os") - -int kfuse_wait_ready() -{ - // Wait for KFUSE to finish init and verification of data. - while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) - ; - - if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) - return 0; - - return 1; -} - -int kfuse_read(u32 *buf) -{ - int res = 0; - - clock_enable_kfuse(); - - if (!kfuse_wait_ready()) - 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; -} - -#pragma GCC pop_options diff --git a/bootloader/soc/pmc.h b/bootloader/soc/pmc.h deleted file mode 100644 index 8cd9161..0000000 --- a/bootloader/soc/pmc.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 st4rk - * - * 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 _PMC_H_ -#define _PMC_H_ - -/*! PMC registers. */ -#define APBDEV_PMC_CNTRL 0x0 -#define PMC_CNTRL_MAIN_RST (1 << 4) -#define APBDEV_PMC_SEC_DISABLE 0x4 -#define APBDEV_PMC_PWRGATE_TOGGLE 0x30 -#define APBDEV_PMC_PWRGATE_STATUS 0x38 -#define APBDEV_PMC_NO_IOPOWER 0x44 -#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) -#define APBDEV_PMC_SCRATCH0 0x50 -#define APBDEV_PMC_SCRATCH1 0x54 -#define APBDEV_PMC_SCRATCH20 0xA0 -#define APBDEV_PMC_PWR_DET_VAL 0xE4 -#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12) -#define APBDEV_PMC_DDR_PWR 0xE8 -#define APBDEV_PMC_CRYPTO_OP 0xF4 -#define PMC_CRYPTO_OP_SE_ENABLE 0 -#define PMC_CRYPTO_OP_SE_DISABLE 1 -#define APBDEV_PMC_SCRATCH33 0x120 -#define APBDEV_PMC_SCRATCH40 0x13C -#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 -#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 -#define APBDEV_PMC_RST_STATUS 0x1B4 -#define APBDEV_PMC_IO_DPD_REQ 0x1B8 -#define APBDEV_PMC_IO_DPD2_REQ 0x1C0 -#define APBDEV_PMC_VDDP_SEL 0x1CC -#define APBDEV_PMC_DDR_CFG 0x1D0 -#define APBDEV_PMC_SCRATCH45 0x234 -#define APBDEV_PMC_SCRATCH46 0x238 -#define APBDEV_PMC_SCRATCH49 0x244 -#define APBDEV_PMC_TSC_MULT 0x2B4 -#define APBDEV_PMC_SEC_DISABLE2 0x2C4 -#define APBDEV_PMC_WEAK_BIAS 0x2C8 -#define APBDEV_PMC_REG_SHORT 0x2CC -#define APBDEV_PMC_SEC_DISABLE3 0x2D8 -#define APBDEV_PMC_SECURE_SCRATCH21 0x334 -#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10 -#define APBDEV_PMC_SECURE_SCRATCH32 0x360 -#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 -#define APBDEV_PMC_CNTRL2 0x440 -#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000 -#define APBDEV_PMC_IO_DPD3_REQ 0x45C -#define APBDEV_PMC_IO_DPD4_REQ 0x464 -#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 -#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC -#define APBDEV_PMC_DDR_CNTRL 0x4E4 -#define APBDEV_PMC_SEC_DISABLE4 0x5B0 -#define APBDEV_PMC_SEC_DISABLE5 0x5B4 -#define APBDEV_PMC_SEC_DISABLE6 0x5B8 -#define APBDEV_PMC_SEC_DISABLE7 0x5BC -#define APBDEV_PMC_SEC_DISABLE8 0x5C0 -#define APBDEV_PMC_SCRATCH188 0x810 -#define APBDEV_PMC_SCRATCH190 0x818 -#define APBDEV_PMC_SCRATCH200 0x840 - -#endif diff --git a/bootloader/soc/smmu.c b/bootloader/soc/smmu.c deleted file mode 100644 index fb096d4..0000000 --- a/bootloader/soc/smmu.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 balika011 - * - * 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 "smmu.h" -#include "../soc/cluster.h" -#include "../soc/t210.h" -#include "../mem/mc_t210.h" -#include "../utils/util.h" -#include "../utils/aarch64_util.h" - -bool smmu_used = false; -u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR; - -//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1; -u8 smmu_payload[] __attribute__((aligned(16))) = { - 0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010 - 0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1 - 0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1] - 0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS - 0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH - 0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop - 0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0 - 0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1] - 0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000 - 0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0 - 0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG - 0x00, 0x00, 0x00, 0x00, // 0x2C: - 0x00, 0x00, 0x00, 0x00, // 0x30: secmon address - 0x00, 0x00, 0x00, 0x00 // 0x34: -}; - -void *page_alloc(u32 num) -{ - u8 *res = _pageheap; - _pageheap += 0x1000 * num; - memset(res, 0, 0x1000 * num); - return res; -} - -u32 *smmu_alloc_pdir() -{ - u32 *pdir = (u32 *)page_alloc(1); - for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) - pdir[pdn] = _PDE_VACANT(pdn); - return pdir; -} - -void smmu_flush_regs() -{ - (void)MC(MC_SMMU_PTB_DATA); -} - -void smmu_flush_all() -{ - MC(MC_SMMU_PTC_FLUSH) = 0; - smmu_flush_regs(); - MC(MC_SMMU_TLB_FLUSH) = 0; - smmu_flush_regs(); -} - -void smmu_init(u32 secmon_base) -{ - MC(MC_SMMU_PTB_ASID) = 0; - MC(MC_SMMU_PTB_DATA) = 0; - MC(MC_SMMU_TLB_CONFIG) = 0x30000030; - MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F; - MC(MC_SMMU_PTC_FLUSH) = 0; - MC(MC_SMMU_TLB_FLUSH) = 0; - - // Set the secmon address - *(u32 *)(smmu_payload + 0x30) = secmon_base; -} - -void smmu_enable() -{ - if (smmu_used) - return; - - cluster_boot_cpu0((u32)smmu_payload); - smmu_used = true; - msleep(150); - - smmu_flush_all(); -} - -bool smmu_is_used() -{ - return smmu_used; -} - -void smmu_exit() -{ - *(u32 *)(smmu_payload + 0x14) = _NOP(); -} - -u32 *smmu_init_domain4(u32 dev_base, u32 asid) -{ - u32 *pdir = smmu_alloc_pdir(); - - MC(MC_SMMU_PTB_ASID) = asid; - MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR); - smmu_flush_regs(); - - MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid); - smmu_flush_regs(); - - return pdir; -} - -u32 *smmu_get_pte(u32 *pdir, u32 iova) -{ - u32 ptn = SMMU_ADDR_TO_PFN(iova); - u32 pdn = SMMU_ADDR_TO_PDN(iova); - u32 *ptbl; - - if (pdir[pdn] != _PDE_VACANT(pdn)) - ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT); - else - { - ptbl = (u32 *)page_alloc(1); - u32 addr = SMMU_PDN_TO_ADDR(pdn); - for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE) - ptbl[pn] = _PTE_VACANT(addr); - pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT); - smmu_flush_all(); - } - - return &ptbl[ptn % SMMU_PTBL_COUNT]; -} - -void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr) -{ - for (int i = 0; i < cnt; i++) - { - u32 *pte = smmu_get_pte(pdir, addr); - *pte = SMMU_ADDR_TO_PFN(page) | attr; - addr += 0x1000; - page += 0x1000; - } - smmu_flush_all(); -} - -u32 *smmu_init_for_tsec() -{ - return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1); -} - -void smmu_deinit_for_tsec() -{ - MC(MC_SMMU_PTB_ASID) = 1; - MC(MC_SMMU_PTB_DATA) = 0; - MC(MC_SMMU_TSEC_ASID) = 0; - smmu_flush_regs(); -} - diff --git a/bootloader/soc/smmu.h b/bootloader/soc/smmu.h deleted file mode 100644 index 827d58b..0000000 --- a/bootloader/soc/smmu.h +++ /dev/null @@ -1,82 +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 "../utils/types.h" - -#define SMMU_HEAP_ADDR 0xA0000000 - -#define MC_INTSTATUS 0x0 -#define MC_INTMASK 0x4 -#define MC_ERR_STATUS 0x8 -#define MC_ERR_ADR 0xc -#define MC_SMMU_CONFIG 0x10 -#define MC_SMMU_TLB_CONFIG 0x14 -#define MC_SMMU_PTC_CONFIG 0x18 -#define MC_SMMU_PTB_ASID 0x1c -#define MC_SMMU_PTB_DATA 0x20 -#define MC_SMMU_TLB_FLUSH 0x30 -#define MC_SMMU_PTC_FLUSH 0x34 -#define MC_SMMU_ASID_SECURITY 0x38 -#define MC_SMMU_TSEC_ASID 0x294 -#define MC_SMMU_TRANSLATION_ENABLE_0 0x228 -#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c -#define MC_SMMU_TRANSLATION_ENABLE_2 0x230 -#define MC_SMMU_TRANSLATION_ENABLE_3 0x234 -#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98 - -#define SMMU_PDE_NEXT_SHIFT 28 -#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29 -#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30 -#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31 -#define SMMU_PAGE_SHIFT 12 -#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT) -#define SMMU_PDIR_COUNT 1024 -#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT) -#define SMMU_PTBL_COUNT 1024 -#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT) -#define SMMU_PDIR_SHIFT 12 -#define SMMU_PDE_SHIFT 12 -#define SMMU_PTE_SHIFT 12 -#define SMMU_PFN_MASK 0x000FFFFF -#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) -#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) -#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22) -#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT) -#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT) -#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT) -#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT) -#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR) -#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR) -#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr)) -#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr)) - -void *page_alloc(u32 num); -u32 *smmu_alloc_pdir(); -void smmu_flush_regs(); -void smmu_flush_all(); -void smmu_init(u32 secmon_base); -void smmu_enable(); -bool smmu_is_used(); -void smmu_exit(); -u32 *smmu_init_domain4(u32 dev_base, u32 asid); -u32 *smmu_get_pte(u32 *pdir, u32 iova); -void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr); -u32 *smmu_init_for_tsec(); -void smmu_deinit_for_tsec(); diff --git a/bootloader/soc/t210.h b/bootloader/soc/t210.h deleted file mode 100644 index 85e42f4..0000000 --- a/bootloader/soc/t210.h +++ /dev/null @@ -1,231 +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 . -*/ - -#ifndef _T210_H_ -#define _T210_H_ - -#include "../utils/types.h" - -#define BOOTROM_BASE 0x100000 -#define IRAM_BASE 0x40000000 -#define HOST1X_BASE 0x50000000 -#define BPMP_CACHE_BASE 0x50040000 -#define DISPLAY_A_BASE 0x54200000 -#define DSI_BASE 0x54300000 -#define VIC_BASE 0x54340000 -#define TSEC_BASE 0x54500000 -#define SOR1_BASE 0x54580000 -#define TMR_BASE 0x60005000 -#define CLOCK_BASE 0x60006000 -#define FLOW_CTLR_BASE 0x60007000 -#define SYSREG_BASE 0x6000C000 -#define SB_BASE (SYSREG_BASE + 0x200) -#define GPIO_BASE 0x6000D000 -#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 IPATCH_BASE 0x6001DC00 -#define APB_MISC_BASE 0x70000000 -#define PINMUX_AUX_BASE 0x70003000 -#define UART_BASE 0x70006000 -#define PWM_BASE 0x7000A000 -#define RTC_BASE 0x7000E000 -#define PMC_BASE 0x7000E400 -#define SYSCTR0_BASE 0x700F0000 -#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 -#define CL_DVFS_BASE 0x70110000 -#define I2S_BASE 0x702D1000 -#define TZRAM_BASE 0x7C010000 - -#define _REG(base, off) *(vu32 *)((base) + (off)) - -#define HOST1X(off) _REG(HOST1X_BASE, off) -#define BPMP_CACHE_CTRL(off) _REG(BPMP_CACHE_BASE, off) -#define DISPLAY_A(off) _REG(DISPLAY_A_BASE, off) -#define DSI(off) _REG(DSI_BASE, off) -#define VIC(off) _REG(VIC_BASE, off) -#define TSEC(off) _REG(TSEC_BASE, off) -#define SOR1(off) _REG(SOR1_BASE, off) -#define TMR(off) _REG(TMR_BASE, off) -#define CLOCK(off) _REG(CLOCK_BASE, off) -#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 PWM(off) _REG(PWM_BASE, off) -#define RTC(off) _REG(RTC_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) -#define I2S(off) _REG(I2S_BASE, off) -#define CL_DVFS(off) _REG(CL_DVFS_BASE, off) -#define TEST_REG(off) _REG(0x0, off) - -/* HOST1X registers. */ -#define HOST1X_CH0_SYNC_BASE 0x2100 -#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4) -#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200) - -/*! EVP registers. */ -#define EVP_CPU_RESET_VECTOR 0x100 -#define EVP_COP_RESET_VECTOR 0x200 -#define EVP_COP_UNDEF_VECTOR 0x204 -#define EVP_COP_SWI_VECTOR 0x208 -#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C -#define EVP_COP_DATA_ABORT_VECTOR 0x210 -#define EVP_COP_RSVD_VECTOR 0x214 -#define EVP_COP_IRQ_VECTOR 0x218 -#define EVP_COP_FIQ_VECTOR 0x21C - -/*! Misc registers. */ -#define APB_MISC_PP_STRAPPING_OPT_A 0x08 -#define APB_MISC_PP_PINMUX_GLOBAL 0x40 -#define APB_MISC_GP_HIDREV 0x804 -#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 -#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 -#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 -#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC -#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 -#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 - -/*! System registers. */ -#define AHB_ARBITRATION_XBAR_CTRL 0xE0 -#define AHB_AHB_SPARE_REG 0x110 - -/*! Secure boot registers. */ -#define SB_CSR 0x0 -#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) -#define SB_CSR_PIROM_DISABLE (1 << 4) -#define SB_AA64_RESET_LOW 0x30 -#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0) -#define SB_AA64_RESET_HIGH 0x34 - -/*! SOR registers. */ -#define SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB 0x1E8 -#define SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB 0x21C -#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB 0x208 -#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB 0x20C - -/*! RTC registers. */ -#define APBDEV_RTC_SECONDS 0x8 -#define APBDEV_RTC_SHADOW_SECONDS 0xC -#define APBDEV_RTC_MILLI_SECONDS 0x10 - -/*! SYSCTR0 registers. */ -#define SYSCTR0_CNTFID0 0x20 -#define SYSCTR0_CNTCR 0x00 -#define SYSCTR0_COUNTERID0 0xFE0 -#define SYSCTR0_COUNTERID1 0xFE4 -#define SYSCTR0_COUNTERID2 0xFE8 -#define SYSCTR0_COUNTERID3 0xFEC -#define SYSCTR0_COUNTERID4 0xFD0 -#define SYSCTR0_COUNTERID5 0xFD4 -#define SYSCTR0_COUNTERID6 0xFD8 -#define SYSCTR0_COUNTERID7 0xFDC -#define SYSCTR0_COUNTERID8 0xFF0 -#define SYSCTR0_COUNTERID9 0xFF4 -#define SYSCTR0_COUNTERID10 0xFF8 -#define SYSCTR0_COUNTERID11 0xFFC - -/*! TMR registers. */ -#define TIMERUS_CNTR_1US (0x10 + 0x0) -#define TIMERUS_USEC_CFG (0x10 + 0x4) -#define TIMER_TMR9_TMR_PTV 0x80 -#define TIMER_EN (1 << 31) -#define TIMER_PER_EN (1 << 30) -#define TIMER_WDT4_CONFIG (0x100 + 0x80) -#define TIMER_SRC(TMR) (TMR & 0xF) -#define TIMER_PER(PER) ((PER & 0xFF) << 4) -#define TIMER_SYSRESET_EN (1 << 14) -#define TIMER_PMCRESET_EN (1 << 15) -#define TIMER_WDT4_COMMAND (0x108 + 0x80) -#define TIMER_START_CNT (1 << 0) -#define TIMER_CNT_DISABLE (1 << 1) -#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80) -#define TIMER_MAGIC_PTRN 0xC45A - -/*! I2S registers. */ -#define I2S1_CG 0x88 -#define I2S1_CTRL 0xA0 -#define I2S2_CG 0x188 -#define I2S2_CTRL 0x1A0 -#define I2S3_CG 0x288 -#define I2S3_CTRL 0x2A0 -#define I2S4_CG 0x388 -#define I2S4_CTRL 0x3A0 -#define I2S5_CG 0x488 -#define I2S5_CTRL 0x4A0 -#define I2S_CG_SLCG_ENABLE (1 << 0) -#define I2S_CTRL_MASTER_EN (1 << 10) - -/*! PWM registers. */ -#define PWM_CONTROLLER_PWM_CSR_0 0x00 -#define PWM_CONTROLLER_PWM_CSR_1 0x10 -#define PWM_CSR_EN (1 << 31) - -/*! Special registers. */ -#define EMC_SCRATCH0 0x324 -#define EMC_HEKA_UPD (1 << 30) -#define EMC_SEPT_RUN (1 << 31) - -/*! Flow controller registers. */ -#define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define HALT_COP_SEC (1 << 23) -#define HALT_COP_MSEC (1 << 24) -#define HALT_COP_USEC (1 << 25) -#define HALT_COP_JTAG (1 << 28) -#define HALT_COP_WAIT_EVENT (1 << 30) -#define HALT_COP_WAIT_IRQ (1 << 31) -#define HALT_COP_MAX_CNT 0xFF -#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 -#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 -#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C -#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 -#define FLOW_CTLR_CPU0_CSR 0x8 -#define FLOW_CTLR_CPU1_CSR 0x18 -#define FLOW_CTLR_CPU2_CSR 0x20 -#define FLOW_CTLR_CPU3_CSR 0x28 -#define FLOW_CTLR_RAM_REPAIR 0x40 -#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 - -#endif diff --git a/bootloader/soc/uart.c b/bootloader/soc/uart.c deleted file mode 100644 index 57694c4..0000000 --- a/bootloader/soc/uart.c +++ /dev/null @@ -1,167 +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 "../soc/uart.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -/* UART A, B, C, D and E. */ -static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 }; - -void uart_init(u32 idx, u32 baud) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - // Make sure no data is being sent. - uart_wait_idle(idx, UART_TX_IDLE); - - // Misc settings. - u32 rate = (8 * baud + 408000000) / (16 * baud); - uart->UART_IER_DLAB = 0; // Disable interrupts. - uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode. - uart->UART_THR_DLAB = (u8)rate; // Divisor latch LSB. - uart->UART_IER_DLAB = (u8)(rate >> 8); // Divisor latch MSB. - uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB. - (void)uart->UART_SPR; - - // Setup and flush fifo. - uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO; - (void)uart->UART_SPR; - usleep(20); - uart->UART_MCR = 0; // Disable hardware flow control. - usleep(96); - uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; - - // Wait 3 symbols for baudrate change. - usleep(3 * ((baud + 999999) / baud)); - uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE); -} - -void uart_wait_idle(u32 idx, u32 which) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - if (UART_TX_IDLE & which) - { - while (!(uart->UART_LSR & UART_LSR_TMTY)) - ; - } - if (UART_RX_IDLE & which) - { - while (uart->UART_LSR & UART_LSR_RDR) - ; - } -} - -void uart_send(u32 idx, const u8 *buf, u32 len) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - for (u32 i = 0; i != len; i++) - { - while (!(uart->UART_LSR & UART_LSR_THRE)) - ; - uart->UART_THR_DLAB = buf[i]; - }; -} - -u32 uart_recv(u32 idx, u8 *buf, u32 len) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - u32 timeout = get_tmr_us() + 1000; - u32 i; - - for (i = 0; ; i++) - { - while (!(uart->UART_LSR & UART_LSR_RDR)) - { - if (!len) - { - if (timeout < get_tmr_us()) - break; - } - else if (len < i) - break; - } - if (timeout < get_tmr_us()) - break; - - buf[i] = uart->UART_THR_DLAB; - timeout = get_tmr_us() + 1000; - }; - - return i ? (len ? (i - 1) : i) : 0; -} - -void uart_invert(u32 idx, bool enable, u32 invert_mask) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - if (enable) - uart->UART_IRDA_CSR |= invert_mask; - else - uart->UART_IRDA_CSR &= ~invert_mask; - (void)uart->UART_SPR; -} - -u32 uart_get_IIR(u32 idx) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - return uart->UART_IIR_FCR; -} - -void uart_set_IIR(u32 idx) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD; - (void)uart->UART_SPR; - uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD; - (void)uart->UART_SPR; -} - -void uart_empty_fifo(u32 idx, u32 which) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - uart->UART_MCR = 0; - (void)uart->UART_SPR; - usleep(96); - - uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; - (void)uart->UART_SPR; - usleep(18); - u32 tries = 0; - - if (UART_IIR_FCR_TX_CLR & which) - { - while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY) - { - tries++; - usleep(100); - } - tries = 0; - } - - if (UART_IIR_FCR_RX_CLR & which) - { - while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR) - { - tries++; - usleep(100); - } - } -} diff --git a/bootloader/soc/uart.h b/bootloader/soc/uart.h deleted file mode 100644 index 23dde13..0000000 --- a/bootloader/soc/uart.h +++ /dev/null @@ -1,86 +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 . -*/ - -#ifndef _UART_H_ -#define _UART_H_ - -#include "../utils/types.h" - -#define UART_A 0 -#define UART_B 1 -#define UART_C 2 -#define UART_D 3 -#define UART_E 4 - -#define BAUD_115200 115200 - -#define UART_TX_IDLE 0x1 -#define UART_RX_IDLE 0x2 - -#define UART_TX_FIFO_FULL 0x100 -#define UART_RX_FIFO_EMPTY 0x200 - -#define UART_INVERT_RXD 0x01 -#define UART_INVERT_TXD 0x02 -#define UART_INVERT_CTS 0x04 -#define UART_INVERT_RTS 0x08 - -#define UART_IER_DLAB_IE_EORD 0x20 - -#define UART_LCR_DLAB 0x80 -#define UART_LCR_STOP 0x4 -#define UART_LCR_WORD_LENGTH_8 0x3 - -#define UART_LSR_RDR 0x1 -#define UART_LSR_THRE 0x20 -#define UART_LSR_TMTY 0x40 -#define UART_LSR_FIFOE 0x80 - -#define UART_IIR_FCR_TX_CLR 0x4 -#define UART_IIR_FCR_RX_CLR 0x2 -#define UART_IIR_FCR_EN_FIFO 0x1 - -#define UART_MCR_RTS 0x2 -#define UART_MCR_DTR 0x1 - -typedef struct _uart_t -{ - /* 0x00 */ vu32 UART_THR_DLAB; - /* 0x04 */ vu32 UART_IER_DLAB; - /* 0x08 */ vu32 UART_IIR_FCR; - /* 0x0C */ vu32 UART_LCR; - /* 0x10 */ vu32 UART_MCR; - /* 0x14 */ vu32 UART_LSR; - /* 0x18 */ vu32 UART_MSR; - /* 0x1C */ vu32 UART_SPR; - /* 0x20 */ vu32 UART_IRDA_CSR; - /* 0x24 */ vu32 UART_RX_FIFO_CFG; - /* 0x28 */ vu32 UART_MIE; - /* 0x2C */ vu32 UART_VENDOR_STATUS; - /* 0x30 */ u8 _pad_30[0xC]; - /* 0x3C */ vu32 UART_ASR; -} uart_t; - -void uart_init(u32 idx, u32 baud); -void uart_wait_idle(u32 idx, u32 which); -void uart_send(u32 idx, const u8 *buf, u32 len); -u32 uart_recv(u32 idx, u8 *buf, u32 len); -void uart_invert(u32 idx, bool enable, u32 invert_mask); -u32 uart_get_IIR(u32 idx); -void uart_set_IIR(u32 idx); -void uart_empty_fifo(u32 idx, u32 which); - -#endif diff --git a/bootloader/start.S b/bootloader/start.S index 534f963..d1def0a 100644 --- a/bootloader/start.S +++ b/bootloader/start.S @@ -23,8 +23,8 @@ .extern memset .type memset, %function -.extern ipl_main -.type ipl_main, %function +.extern _irq_setup +.type _irq_setup, %function .globl _start .type _start, %function @@ -60,14 +60,15 @@ _reloc_ipl: BX R3 _real_start: - /* Initially, we place our stack in IRAM but will move it to SDRAM later. */ + /* Initially, we place our stack under relocator but will move it to under the payload. */ + /* This depends on application scope. */ LDR SP, =0x4003FF00 LDR R0, =__bss_start EOR R1, R1, R1 LDR R2, =__bss_end SUB R2, R2, R0 BL memset - BL ipl_main + BL _irq_setup B . .globl pivot_stack diff --git a/bootloader/storage/emummc.c b/bootloader/storage/emummc.c index e3eb7ae..64fe907 100644 --- a/bootloader/storage/emummc.c +++ b/bootloader/storage/emummc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,37 +17,31 @@ #include #include -#include "emummc.h" -#include "sdmmc.h" -#include "../config/config.h" -#include "../config/ini.h" -#include "../gfx/gfx.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/list.h" -#include "../utils/types.h" +#include -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; +#include "emummc.h" +#include "../config.h" +#include extern hekate_config h_cfg; - -extern bool sd_mount(); -extern void sd_unmount(); +emummc_cfg_t emu_cfg = { 0 }; void emummc_load_cfg() { - sd_mount(); emu_cfg.enabled = 0; emu_cfg.path = NULL; - emu_cfg.nintendo_path = NULL; emu_cfg.sector = 0; emu_cfg.id = 0; emu_cfg.file_based_part_size = 0; emu_cfg.active_part = 0; emu_cfg.fs_ver = 0; - emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + if (!emu_cfg.nintendo_path) + emu_cfg.nintendo_path = (char *)malloc(0x200); + if (!emu_cfg.emummc_file_based_path) + emu_cfg.emummc_file_based_path = (char *)malloc(0x200); + + emu_cfg.nintendo_path[0] = 0; + emu_cfg.emummc_file_based_path[0] = 0; LIST_INIT(ini_sections); if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) @@ -61,16 +55,16 @@ void emummc_load_cfg() LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) { - if (!strcmp("enabled", kv->key)) + if (!strcmp("enabled", kv->key)) emu_cfg.enabled = atoi(kv->val); - else if (!strcmp("sector", kv->key)) - emu_cfg.sector = strtol(kv->val, NULL, 16); - else if (!strcmp("id", kv->key)) - emu_cfg.id = strtol(kv->val, NULL, 16); - else if (!strcmp("path", kv->key)) - emu_cfg.path = kv->val; + else if (!strcmp("sector", kv->key)) + emu_cfg.sector = strtol(kv->val, NULL, 16); + else if (!strcmp("id", kv->key)) + emu_cfg.id = strtol(kv->val, NULL, 16); + else if (!strcmp("path", kv->key)) + emu_cfg.path = kv->val; else if (!strcmp("nintendo_path", kv->key)) - emu_cfg.nintendo_path = kv->val; + strcpy(emu_cfg.nintendo_path, kv->val); } break; } @@ -78,6 +72,52 @@ void emummc_load_cfg() } } +bool emummc_set_path(char *path) +{ + FIL fp; + bool found = false; + + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/raw_based"); + + if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + if (!f_read(&fp, &emu_cfg.sector, 4, NULL)) + if (emu_cfg.sector) + found = true; + } + else + { + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/file_based"); + + if (!f_stat(emu_cfg.emummc_file_based_path, NULL)) + { + emu_cfg.sector = 0; + emu_cfg.path = path; + + found = true; + } + } + + if (found) + { + emu_cfg.enabled = 1; + + // Get ID from path. + u32 id_from_path = 0; + u32 path_size = strlen(path); + if (path_size >= 4) + memcpy(&id_from_path, path + path_size - 4, 4); + emu_cfg.id = id_from_path; + + strcpy(emu_cfg.nintendo_path, path); + strcat(emu_cfg.nintendo_path, "/Nintendo"); + } + + return found; +} + static int emummc_raw_get_part_off(int part_idx) { switch (part_idx) @@ -92,20 +132,22 @@ static int emummc_raw_get_part_off(int part_idx) return 2; } -int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) +int emummc_storage_init_mmc() { FILINFO fno; - if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + emu_cfg.active_part = 0; + + // Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway. + if (!emmc_initialize(false)) return 2; - if (h_cfg.emummc_force_disable) + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) return 0; - emu_cfg.active_part = 0; if (!sd_mount()) goto out; - if (emu_cfg.enabled && !emu_cfg.sector) + if (!emu_cfg.sector) { strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); strcat(emu_cfg.emummc_file_based_path, "/eMMC"); @@ -132,19 +174,21 @@ out: return 1; } -int emummc_storage_end(sdmmc_storage_t *storage) +int emummc_storage_end() { - sd_unmount(); - sdmmc_storage_end(storage); + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + emmc_end(); + else + sd_end(); return 1; } -int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +int emummc_storage_read(u32 sector, u32 num_sectors, void *buf) { FIL fp; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - return sdmmc_storage_read(storage, sector, num_sectors, buf); + return sdmmc_storage_read(&emmc_storage, sector, num_sectors, buf); else if (emu_cfg.sector) { sector += emu_cfg.sector; @@ -185,11 +229,11 @@ int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, v return 1; } -int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +int emummc_storage_write(u32 sector, u32 num_sectors, void *buf) { FIL fp; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - return sdmmc_storage_write(storage, sector, num_sectors, buf); + return sdmmc_storage_write(&emmc_storage, sector, num_sectors, buf); else if (emu_cfg.sector) { sector += emu_cfg.sector; @@ -210,15 +254,13 @@ int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); } } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE)) - { - gfx_printf("e5\n"); return 0; - } + f_lseek(&fp, (u64)sector << 9); if (f_write(&fp, buf, (u64)num_sectors << 9, NULL)) { - gfx_printf("e6\n"); f_close(&fp); return 0; } @@ -228,13 +270,12 @@ int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, } } -int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) +int emummc_storage_set_mmc_partition(u32 partition) { emu_cfg.active_part = partition; + emmc_set_partition(partition); - if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - sdmmc_storage_set_mmc_partition(storage, partition); - else if (emu_cfg.sector) + if (!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.sector) return 1; else { diff --git a/bootloader/storage/emummc.h b/bootloader/storage/emummc.h index 5ef8cfd..617b36b 100644 --- a/bootloader/storage/emummc.h +++ b/bootloader/storage/emummc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,8 +17,7 @@ #ifndef EMUMMC_H #define EMUMMC_H -#include "sdmmc.h" -#include "../utils/types.h" +#include typedef enum { @@ -37,7 +36,7 @@ typedef struct _emummc_cfg_t { int enabled; u64 sector; - u16 id; + u32 id; char *path; char *nintendo_path; // Internal. @@ -47,13 +46,14 @@ typedef struct _emummc_cfg_t int fs_ver; } emummc_cfg_t; -emummc_cfg_t emu_cfg; +extern emummc_cfg_t emu_cfg; void emummc_load_cfg(); -int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); -int emummc_storage_end(sdmmc_storage_t *storage); -int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); -int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); -int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +bool emummc_set_path(char *path); +int emummc_storage_init_mmc(); +int emummc_storage_end(); +int emummc_storage_read(u32 sector, u32 num_sectors, void *buf); +int emummc_storage_write(u32 sector, u32 num_sectors, void *buf); +int emummc_storage_set_mmc_partition(u32 partition); #endif \ No newline at end of file diff --git a/bootloader/storage/mmc.h b/bootloader/storage/mmc.h deleted file mode 100644 index 0d87e35..0000000 --- a/bootloader/storage/mmc.h +++ /dev/null @@ -1,432 +0,0 @@ -/* - * 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_DEVICE_VERSION 262 /* RO, 2 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/bootloader/storage/nx_emmc.c b/bootloader/storage/nx_emmc.c deleted file mode 100644 index c35177e..0000000 --- a/bootloader/storage/nx_emmc.c +++ /dev/null @@ -1,78 +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 - -#include "nx_emmc.h" -#include "emummc.h" -#include "../mem/heap.h" -#include "../utils/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); - - emummc_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; - - // ASCII conversion. Copy only the LSByte of the UTF-16LE name. - for (u32 i = 0; i < 36; i++) - part->name[i] = ent->name[i]; - part->name[36] = 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 emummc_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/bootloader/storage/nx_emmc.h b/bootloader/storage/nx_emmc.h deleted file mode 100644 index 753d5aa..0000000 --- a/bootloader/storage/nx_emmc.h +++ /dev/null @@ -1,72 +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 . - */ - -#ifndef _NX_EMMC_H_ -#define _NX_EMMC_H_ - -#include "../utils/types.h" -#include "../utils/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; - char 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/bootloader/storage/sd.h b/bootloader/storage/sd.h deleted file mode 100644 index fafd322..0000000 --- a/bootloader/storage/sd.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * include/linux/mmc/sd.h - * - * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. - * Copyright (c) 2018 CTCaer - * - * 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 */ -#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ -#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ -#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ - -/* -* 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 */ -#define SD_SCR_BUS_WIDTH_1 (1<<0) -#define SD_SCR_BUS_WIDTH_4 (1<<2) - -/* -* SD bus widths -*/ -#define SD_BUS_WIDTH_1 0 -#define SD_BUS_WIDTH_4 2 - -/* -* SD bus speeds -*/ -#define UHS_SDR12_BUS_SPEED 0 -#define HIGH_SPEED_BUS_SPEED 1 -#define UHS_SDR25_BUS_SPEED 1 -#define UHS_SDR50_BUS_SPEED 2 -#define UHS_SDR104_BUS_SPEED 3 -#define UHS_DDR50_BUS_SPEED 4 -#define HS400_BUS_SPEED 5 - -#define SD_MODE_HIGH_SPEED (1 << HIGH_SPEED_BUS_SPEED) -#define SD_MODE_UHS_SDR12 (1 << UHS_SDR12_BUS_SPEED) -#define SD_MODE_UHS_SDR25 (1 << UHS_SDR25_BUS_SPEED) -#define SD_MODE_UHS_SDR50 (1 << UHS_SDR50_BUS_SPEED) -#define SD_MODE_UHS_SDR104 (1 << UHS_SDR104_BUS_SPEED) -#define SD_MODE_UHS_DDR50 (1 << UHS_DDR50_BUS_SPEED) - -#define SD_DRIVER_TYPE_B 0x01 -#define SD_DRIVER_TYPE_A 0x02 - -#define SD_SET_CURRENT_LIMIT_200 0 -#define SD_SET_CURRENT_LIMIT_400 1 -#define SD_SET_CURRENT_LIMIT_600 2 -#define SD_SET_CURRENT_LIMIT_800 3 - -/* -* 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/bootloader/storage/sdmmc.c b/bootloader/storage/sdmmc.c deleted file mode 100644 index d75e609..0000000 --- a/bootloader/storage/sdmmc.c +++ /dev/null @@ -1,1238 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * - * 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 "../../common/memory_map.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../utils/util.h" - -//#define DPRINTF(...) gfx_printf(__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 9 times on error. - u32 retries = 10; - do - { - if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) - goto out; - else - retries--; - - msleep(100); - } while (retries); - - return 0; - -out:; -DPRINTF("readwrite: %08X\n", blkcnt); - sector += blkcnt; - num_sectors -= blkcnt; - bbuf += 512 * blkcnt; - } - - return 1; -} - -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 = SD_OCR_CCS | SD_OCR_VDD_18; - break; - case SDMMC_POWER_3_3: - arg = SD_OCR_CCS | SD_OCR_VDD_27_34; - 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_ms() + 1500; - - while (1) - { - u32 cond = 0; - if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) - break; - - if (cond & MMC_CARD_BUSY) - { - if (cond & SD_OCR_CCS) - storage->has_sector_access = 1; - - return 1; - } - if (get_tmr_ms() > timeout) - break; - - usleep(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 void _mmc_storage_parse_cid(sdmmc_storage_t *storage) -{ - u32 *raw_cid = (u32 *)&(storage->raw_cid); - - switch (storage->csd.mmca_vsn) - { - case 0: /* MMC v1.0 - v1.2 */ - case 1: /* MMC v1.4 */ - storage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8); - storage->cid.manfid = unstuff_bits(raw_cid, 104, 24); - storage->cid.hwrev = unstuff_bits(raw_cid, 44, 4); - storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4); - storage->cid.serial = unstuff_bits(raw_cid, 16, 24); - break; - case 2: /* MMC v2.0 - v2.2 */ - case 3: /* MMC v3.1 - v3.3 */ - case 4: /* MMC v4 */ - storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); - storage->cid.card_bga = unstuff_bits(raw_cid, 112, 2); - storage->cid.oemid = unstuff_bits(raw_cid, 104, 8); - storage->cid.prv = unstuff_bits(raw_cid, 48, 8); - storage->cid.serial = unstuff_bits(raw_cid, 16, 32); - break; - default: - break; - } - - storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); - storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); - storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); - storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); - storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); - storage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8); - - storage->cid.month = unstuff_bits(raw_cid, 12, 4); - storage->cid.year = unstuff_bits(raw_cid, 8, 4) + 1997; - if (storage->ext_csd.rev >= 5) - { - if (storage->cid.year < 2010) - storage->cid.year += 16; - } -} - -static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) -{ - u32 *raw_csd = (u32 *)&(storage->raw_csd); - - storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); - storage->csd.structure = unstuff_bits(raw_csd, 126, 2); - storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); - storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); - storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); -} - -static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) -{ - storage->ext_csd.rev = buf[EXT_CSD_REV]; - storage->ext_csd.ext_struct = buf[EXT_CSD_STRUCTURE]; - storage->ext_csd.card_type = buf[EXT_CSD_CARD_TYPE]; - storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION]; - storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT]; - storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT]; - storage->ext_csd.sectors = *(u32 *)&buf[EXT_CSD_SEC_CNT]; - storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; - storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; - storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; - - storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; -} - -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); - _mmc_storage_parse_ext_csd(storage, buf); - - 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"); - storage->csd.busspeed = 52; - - 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"); - storage->csd.busspeed = 200; - - 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"); - storage->csd.busspeed = 400; - - 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"); - - usleep(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->raw_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->raw_csd)) - return 0; -DPRINTF("[MMC] got csd\n"); - _mmc_storage_parse_csd(storage); - - 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->raw_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; - } - free(ext_csd); -DPRINTF("[MMC] got ext_csd\n"); - _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd - //gfx_hexdump(0, ext_csd, 512); - - /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. - Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). - Additionally this works only when we put the device in idle mode which we don't after enabling it. */ - if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) - { - _mmc_storage_enable_bkops(storage); -DPRINTF("[MMC] BKOPS enabled\n"); - } - else - { -DPRINTF("[MMC] BKOPS disabled\n"); - } - - if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) - return 0; -DPRINTF("[MMC] succesfully switched to HS mode\n"); - - sdmmc_sd_clock_ctrl(storage->sdmmc, 1); - - 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 1; // The SD Card is version 1.X - - u32 resp = 0; - if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5)) - return 2; - - return (resp & 0xFF) == 0xAA ? 0 : 2; -} - -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; - // Support for Current > 150mA - u32 arg = (~is_version_1 & 1) ? SD_OCR_XPC : 0; - // Support for handling block-addressed SDHC cards - arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0; - // Support for 1.8V - arg |= (supports_low_voltage & ~is_version_1 & 1) ? SD_OCR_S18R : 0; - // This is needed for most cards. Do not set bit7 even if 1.8V is supported. - arg |= SD_OCR_VDD_32_33; - 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_ms() + 1500; - - while (1) - { - u32 cond = 0; - if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage)) - break; - if (cond & MMC_CARD_BUSY) - { - if (cond & SD_OCR_CCS) - storage->has_sector_access = 1; - - if (cond & SD_ROCR_S18A && 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_ms() > timeout) - break; - msleep(10); // Needs to be at least 10ms for some SD Cards - } - - 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_ms() + 1500; - - 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_ms() > timeout) - break; - usleep(1000); - } - - return 0; -} - -static void _sd_storage_parse_scr(sdmmc_storage_t *storage) -{ - // unstuff_bits can parse only 4 u32 - u32 resp[4]; - - resp[3] = *(u32 *)&storage->raw_scr[4]; - resp[2] = *(u32 *)&storage->raw_scr[0]; - - storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); - storage->scr.bus_widths = unstuff_bits(resp, 48, 4); - if (storage->scr.sda_vsn == SCR_SPEC_VER_2) - /* Check if Physical Layer Spec v3.0 is supported */ - storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); - if (storage->scr.sda_spec3) - storage->scr.cmds = unstuff_bits(resp, 32, 2); -} - -int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *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); - //Prepare buffer for unstuff_bits - for (int i = 0; i < 8; i+=4) - { - storage->raw_scr[i + 3] = buf[i]; - storage->raw_scr[i + 2] = buf[i + 1]; - storage->raw_scr[i + 1] = buf[i + 2]; - storage->raw_scr[i] = buf[i + 3]; - } - _sd_storage_parse_scr(storage); - //gfx_hexdump(0, storage->raw_scr, 8); - - 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 mode, int group, u32 arg) -{ - sdmmc_cmd_t cmdbuf; - u32 switchcmd = mode << 31 | 0x00FFFFFF; - switchcmd &= ~(0xF << (group * 4)); - switchcmd |= arg << (group * 4); - sdmmc_init_cmd(&cmdbuf, SD_SWITCH, switchcmd, 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); -} - -void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) -{ - u32 pwr = SD_SET_CURRENT_LIMIT_800; - _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - - while (pwr > 0) - { - pwr--; - _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - if (((buf[15] >> 4) & 0x0F) == pwr) - break; - } - - switch (pwr) - { - case SD_SET_CURRENT_LIMIT_800: -DPRINTF("[SD] power limit raised to 800mA\n"); - break; - case SD_SET_CURRENT_LIMIT_600: -DPRINTF("[SD] power limit raised to 600mA\n"); - break; - case SD_SET_CURRENT_LIMIT_400: -DPRINTF("[SD] power limit raised to 800mA\n"); - break; - default: - case SD_SET_CURRENT_LIMIT_200: -DPRINTF("[SD] power limit defaulted to 200mA\n"); - break; - } -} - -int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) -{ - if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) - return 0; -DPRINTF("[SD] SD supports switch to (U)HS check\n"); - - u32 type_out = buf[16] & 0xF; - if (type_out != hs_type) - return 0; -DPRINTF("[SD] SD supports selected (U)HS mode\n"); - - if ((((u16)buf[0] << 8) | buf[1]) < 0x320) - { - if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type)) - return 0; - - if (type_out != (buf[16] & 0xF)) - return 0; - } - - return 1; -} - -int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) -{ - // Try to raise the current limit to let the card perform better. - _sd_storage_set_current_limit(storage, buf); - - if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) - return 0; - - if (!_sd_storage_switch_get(storage, buf)) - return 0; - //gfx_hexdump(0, (u8 *)buf, 64); - - u32 hs_type = 0; - switch (type) - { - case 11: // SDR104. - // Fall through if not supported. - if (buf[13] & SD_MODE_UHS_SDR104) - { - type = 11; - hs_type = UHS_SDR104_BUS_SPEED; -DPRINTF("[SD] bus speed set to SDR104\n"); - storage->csd.busspeed = 104; - break; - } - case 10: // SDR50. - if (buf[13] & SD_MODE_UHS_SDR50) - { - type = 10; - hs_type = UHS_SDR50_BUS_SPEED; -DPRINTF("[SD] bus speed set to SDR50\n"); - storage->csd.busspeed = 50; - break; - } - case 8: // SDR12. - if (!(buf[13] & SD_MODE_UHS_SDR12)) - return 0; - type = 8; - hs_type = UHS_SDR12_BUS_SPEED; -DPRINTF("[SD] bus speed set to SDR12\n"); - storage->csd.busspeed = 12; - break; - default: - return 0; - break; - } - - if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) - return 0; -DPRINTF("[SD] SD card accepted UHS\n"); - if (!sdmmc_setup_clock(storage->sdmmc, type)) - return 0; -DPRINTF("[SD] setup clock\n"); - if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) - return 0; -DPRINTF("[SD] config tuning\n"); - return _sdmmc_storage_check_status(storage); -} - -int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) -{ - if (!_sd_storage_switch_get(storage, buf)) - return 0; - //gfx_hexdump(0, (u8 *)buf, 64); - if (!(buf[13] & SD_MODE_HIGH_SPEED)) - 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); -} - -static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) -{ - // unstuff_bits supports only 4 u32 so break into 2 x 16byte groups - u32 raw_ssr1[4]; - u32 raw_ssr2[4]; - - raw_ssr1[3] = *(u32 *)&storage->raw_ssr[12]; - raw_ssr1[2] = *(u32 *)&storage->raw_ssr[8]; - raw_ssr1[1] = *(u32 *)&storage->raw_ssr[4]; - raw_ssr1[0] = *(u32 *)&storage->raw_ssr[0]; - - raw_ssr2[3] = *(u32 *)&storage->raw_ssr[28]; - raw_ssr2[2] = *(u32 *)&storage->raw_ssr[24]; - raw_ssr2[1] = *(u32 *)&storage->raw_ssr[20]; - raw_ssr2[0] = *(u32 *)&storage->raw_ssr[16]; - - storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1; - switch(unstuff_bits(raw_ssr1, 440 - 384, 8)) - { - case 0: - storage->ssr.speed_class = 0; - break; - case 1: - storage->ssr.speed_class = 2; - break; - case 2: - storage->ssr.speed_class = 4; - break; - case 3: - storage->ssr.speed_class = 6; - break; - case 4: - storage->ssr.speed_class = 10; - break; - default: - storage->ssr.speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8); - break; - } - storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4); - storage->ssr.video_class = unstuff_bits(raw_ssr1, 384 - 384, 8); - - storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4); -} - -static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) -{ - sdmmc_cmd_t cmdbuf; - sdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, 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 (!(storage->csd.cmdclass & CCC_APP_SPEC)) - { -DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); - return 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); - //Prepare buffer for unstuff_bits - for (int i = 0; i < 64; i+=4) - { - storage->raw_ssr[i + 3] = buf[i]; - storage->raw_ssr[i + 2] = buf[i + 1]; - storage->raw_ssr[i + 1] = buf[i + 2]; - storage->raw_ssr[i] = buf[i + 3]; - } - _sd_storage_parse_ssr(storage); - //gfx_hexdump(0, storage->raw_ssr, 64); - - return _sdmmc_storage_check_result(tmp); -} - -static void _sd_storage_parse_cid(sdmmc_storage_t *storage) -{ - u32 *raw_cid = (u32 *)&(storage->raw_cid); - - storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); - storage->cid.oemid = unstuff_bits(raw_cid, 104, 16); - storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); - storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); - storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); - storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); - storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); - storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4); - storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4); - storage->cid.serial = unstuff_bits(raw_cid, 24, 32); - storage->cid.month = unstuff_bits(raw_cid, 8, 4); - storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000; -} - -static void _sd_storage_parse_csd(sdmmc_storage_t *storage) -{ - u32 *raw_csd = (u32 *)&(storage->raw_csd); - - storage->csd.structure = unstuff_bits(raw_csd, 126, 2); - storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); - storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); - storage->csd.write_protect = unstuff_bits(raw_csd, 12, 2); - switch(storage->csd.structure) - { - case 0: - storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); - break; - case 1: - storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22)); - storage->csd.capacity = storage->csd.c_size << 10; - storage->csd.read_blkbits = 9; - break; - } -} - -void sdmmc_storage_init_wait_sd() -{ - u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; - if (sd_poweroff_time < 100) - msleep(100 - sd_poweroff_time); -} - -int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) -{ - int is_version_1 = 0; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - - // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. - sdmmc_storage_init_wait_sd(); - - 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"); - - usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); - - if (!_sdmmc_storage_go_idle_state(storage)) - return 0; -DPRINTF("[SD] went to idle state\n"); - - is_version_1 = _sd_storage_send_if_cond(storage); - if (is_version_1 == 2) - return 0; -DPRINTF("[SD] after send if cond\n"); - - if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11)) - return 0; -DPRINTF("[SD] got op cond\n"); - - if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) - return 0; -DPRINTF("[SD] got cid\n"); - _sd_storage_parse_cid(storage); - - if (!_sd_storage_get_rca(storage)) - return 0; -DPRINTF("[SD] got rca (= %04X)\n", storage->rca); - - if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) - return 0; -DPRINTF("[SD] got csd\n"); - - //Parse CSD. - _sd_storage_parse_csd(storage); - switch (storage->csd.structure) - { - case 0: - storage->sec_cnt = storage->csd.capacity; - break; - case 1: - storage->sec_cnt = storage->csd.c_size << 10; - break; - default: -DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); - 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"); - - if (!_sd_storage_get_scr(storage, buf)) - return 0; - - //gfx_hexdump(0, storage->raw_scr, 8); -DPRINTF("[SD] got scr\n"); - - // Check if card supports a wider bus and if it's not SD Version 1.X - if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) - { - if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) - 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_uhs_low_volt(storage, type, buf)) - return 0; -DPRINTF("[SD] enabled UHS\n"); - } - else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) - { - if (!_sd_storage_enable_hs_high_volt(storage, buf)) - return 0; - -DPRINTF("[SD] enabled HS\n"); - storage->csd.busspeed = 25; - } - - sdmmc_sd_clock_ctrl(sdmmc, 1); - - // Parse additional card info from sd status. - if (_sd_storage_get_ssr(storage, buf)) - { -DPRINTF("[SD] got sd status\n"); - } - - 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 = 64; - 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"); - - usleep(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/bootloader/storage/sdmmc.h b/bootloader/storage/sdmmc.h deleted file mode 100644 index c8b8f96..0000000 --- a/bootloader/storage/sdmmc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../utils/types.h" -#include "sdmmc_driver.h" - -u32 sd_power_cycle_time_start; - -typedef struct _mmc_cid -{ - u32 manfid; - u8 prod_name[8]; - u8 card_bga; - u8 prv; - u32 serial; - u16 oemid; - u16 year; - u8 hwrev; - u8 fwrev; - u8 month; -} mmc_cid_t; - -typedef struct _mmc_csd -{ - u8 structure; - u8 mmca_vsn; - u16 cmdclass; - u32 c_size; - u32 r2w_factor; - u32 max_dtr; - u32 erase_size; /* In sectors */ - u32 read_blkbits; - u32 write_blkbits; - u32 capacity; - u8 write_protect; - u16 busspeed; -} mmc_csd_t; - -typedef struct _mmc_ext_csd -{ - u8 rev; - u32 sectors; - int bkops; /* background support bit */ - int bkops_en; /* manual bkops enable bit */ - u8 ext_struct; /* 194 */ - u8 card_type; /* 196 */ - u8 bkops_status; /* 246 */ - u16 dev_version; - u8 boot_mult; - u8 rpmb_mult; -} mmc_ext_csd_t; - -typedef struct _sd_scr -{ - u8 sda_vsn; - u8 sda_spec3; - u8 bus_widths; - u8 cmds; -} sd_scr_t; - -typedef struct _sd_ssr -{ - u8 bus_width; - u8 speed_class; - u8 uhs_grade; - u8 video_class; - u8 app_class; -} sd_ssr_t; - -/*! 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 raw_cid[0x10]; - u8 raw_csd[0x10]; - u8 raw_scr[8]; - u8 raw_ssr[0x40]; - mmc_cid_t cid; - mmc_csd_t csd; - mmc_ext_csd_t ext_csd; - sd_scr_t scr; - sd_ssr_t ssr; -} 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); -void sdmmc_storage_init_wait_sd(); -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/bootloader/storage/sdmmc_driver.c b/bootloader/storage/sdmmc_driver.c deleted file mode 100644 index 57d20f9..0000000 --- a/bootloader/storage/sdmmc_driver.c +++ /dev/null @@ -1,1148 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer - * - * 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 "mmc.h" -#include "sdmmc.h" -#include "../gfx/gfx.h" -#include "../power/max7762x.h" -#include "../soc/bpmp.h" -#include "../soc/clock.h" -#include "../soc/gpio.h" -#include "../soc/pinmux.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -//#define DPRINTF(...) gfx_printf(__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) -{ - u8 pwr = 0; - - switch (power) - { - case SDMMC_POWER_OFF: - sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER; - break; - case SDMMC_POWER_1_8: - sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; - pwr = 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; - pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; - break; - default: - return 0; - } - - if (power != SDMMC_POWER_OFF) - { - pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; - sdmmc->regs->pwrcon = pwr; - } - - 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->ventunctl0 &= 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); - switch (sdmmc->id) - { - case SDMMC_1: - if (power == SDMMC_POWER_OFF) - break; - if (power == SDMMC_POWER_1_8) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x304; // Up: 3, Dn: 4. - else if (power == SDMMC_POWER_3_3) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x808; // Up: 8, Dn: 8. - break; - case SDMMC_4: - APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0x3FFC) | 0x1040; - break; - } - //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->vendllcal |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 5; - while (sdmmc->regs->vendllcal & 0x80000000) - { - if (get_tmr_ms() > timeout) - { - res = 0; - goto out; - } - } - - timeout = get_tmr_ms() + 10; - while (sdmmc->regs->dllcfgstatus & 0x80000000) - { - if (get_tmr_ms() > 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. - bool should_enable_sd_clock = false; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = true; - 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; // Should this be 0xFFFB (~4) ? - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; - break; - case 2: - case 7: - sdmmc->regs->hostctl |= 4; - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; - break; - case 3: - case 11: - case 13: - case 14: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 4: - // Non standard. - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 8: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 10: - // T210 Errata for SDR50, the host must be set to SDR104. - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - } - - _sdmmc_get_clkcon(sdmmc); - - u32 tmp; - u16 divisor; - clock_sdmmc_get_card_clock_div(&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; - // CRC is stripped, so shifting is needed. - u32 tempreg; - for (int i = 0; i < 4; i++) - { - switch(i) - { - case 0: - tempreg = sdmmc->regs->rspreg3; - break; - case 1: - tempreg = sdmmc->regs->rspreg2; - break; - case 2: - tempreg = sdmmc->regs->rspreg1; - break; - case 3: - tempreg = sdmmc->regs->rspreg0; - break; - } - rsp[i] = tempreg << 8; - - if (i != 0) - rsp[i - 1] |= (tempreg >> 24) & 0xFF; - } - 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_ms() + 2000; - while (sdmmc->regs->swrst << 29 >> 30 && get_tmr_ms() < timeout) - ; -} - -static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) -{ - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 2000; - while(sdmmc->regs->prnsts & 1) // CMD inhibit. - if (get_tmr_ms() > timeout) - { - _sdmmc_reset(sdmmc); - return 0; - } - - if (wait_dat) - { - timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->prnsts & 2) // DAT inhibit. - if (get_tmr_ms() > 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_ms() + 2000; - while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level. - if (get_tmr_ms() > 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, bool 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, true); -} - -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); - usleep(1); - - _sdmmc_reset(sdmmc); - - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_us() + 5000; - while (get_tmr_us() < timeout) - { - if (sdmmc->regs->norintsts & 0x20) - { - sdmmc->regs->norintsts = 0x20; - sdmmc->regs->norintstsen &= 0xFFDF; - _sdmmc_get_clkcon(sdmmc); - usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); - return 1; - } - } - - _sdmmc_reset(sdmmc); - - sdmmc->regs->norintstsen &= 0xFFDF; - _sdmmc_get_clkcon(sdmmc); - usleep((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->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier. - sdmmc->regs->ventunctl0 |= 0x20000; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; - - for (u32 i = 0; i < max; i++) - { - _sdmmc_config_tuning_once(sdmmc, cmd); - if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) - break; - } - - if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) - 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_ms() + 2000; - while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) - { - if (get_tmr_ms() > timeout) - return 0; - } - - sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT; - sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; - - if (!(sdmmc->regs->capareg & 0x10000000)) - return 0; - - sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; - 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) -{ - bool should_enable_sd_clock = false; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = true; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - - if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000)) - { - sdmmc->regs->sdmemcmppadctl |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - } - - sdmmc->regs->autocalcfg |= 0xA0000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - - u32 timeout = get_tmr_ms() + 10; - while (sdmmc->regs->autocalcfg & 0x80000000) - { - if (get_tmr_ms() > 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_ms() + 2000; - 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_ms() > 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, false); - - 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; - - bool should_disable_sd_clock = false; - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - { - should_disable_sd_clock = true; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - } - - int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); - usleep((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; - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - 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_ms() + 1500; - 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) - { - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - 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_ms() < 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; - bool is_data_present = false; - if (req) - { - _sdmmc_config_dma(sdmmc, &blkcnt, req); - _sdmmc_enable_interrupts(sdmmc); - is_data_present = true; - } - else - { - _sdmmc_enable_interrupts(sdmmc); - is_data_present = false; - } - - _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) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //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); - usleep(100); - - // Check if SD card is inserted. - 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; // Enable deep loopback for SDMMC1 CLK pad. - PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED; - PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - - // 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) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //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); - - usleep(1000); - - // Enable SD card power. - max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); - max77620_regulator_enable(REGULATOR_LDO2, 1); - - usleep(1000); - - // For good measure. - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; - - usleep(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_card_clock_div(&clock, &divisor, type); - clock_sdmmc_enable(id, clock); - - sdmmc->clock_stopped = 0; - - //TODO: make this skip-able. - sdmmc->regs->iospare |= 0x80000; - sdmmc->regs->veniotrimctl &= 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); - // Disable SDMMC power. - _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); - - // Disable SD card power. - if (sdmmc->id == SDMMC_1) - { - gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); - max77620_regulator_enable(REGULATOR_LDO2, 0); - sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. - usleep(1000); // To power cycle, min 1ms without power is needed. - } - - _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); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - } - - int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); - usleep((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); - - // Enable schmitt trigger for better duty cycle and low jitter clock. - PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; - - 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); - msleep(5); - - if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) - { - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep(1000); - if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) - return 1; - } - - return 0; -} diff --git a/bootloader/storage/sdmmc_driver.h b/bootloader/storage/sdmmc_driver.h deleted file mode 100644 index cf9b9e1..0000000 --- a/bootloader/storage/sdmmc_driver.h +++ /dev/null @@ -1,126 +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 . - */ - -#ifndef _SDMMC_DRIVER_H_ -#define _SDMMC_DRIVER_H_ - -#include "../utils/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 - -/*! SDMMC host control 2 */ -#define SDHCI_CTRL_UHS_MASK 0xFFF8 -#define SDHCI_CTRL_VDD_330 0xFFF7 -#define SDHCI_CTRL_VDD_180 8 -#define SDHCI_CTRL_EXEC_TUNING 0x40 -#define SDHCI_CTRL_TUNED_CLK 0x80 -#define SDHCI_HOST_VERSION_4_EN 0x1000 -#define SDHCI_ADDRESSING_64BIT_EN 0x2000 -#define SDHCI_CTRL_PRESET_VAL_EN 0x8000 - -/*! SD bus speeds. */ -#define UHS_SDR12_BUS_SPEED 0 -#define HIGH_SPEED_BUS_SPEED 1 -#define UHS_SDR25_BUS_SPEED 1 -#define UHS_SDR50_BUS_SPEED 2 -#define UHS_SDR104_BUS_SPEED 3 -#define UHS_DDR50_BUS_SPEED 4 -#define HS400_BUS_SPEED 5 - -/*! 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/bootloader/storage/sdmmc_t210.h b/bootloader/storage/sdmmc_t210.h deleted file mode 100644 index e11c3ff..0000000 --- a/bootloader/storage/sdmmc_t210.h +++ /dev/null @@ -1,132 +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 . - */ - -#ifndef _SDMMC_T210_H_ -#define _SDMMC_T210_H_ - -#include "../utils/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 veniotrimctl; - vu32 vendllcal; - vu8 res7[8]; - vu32 dllcfgstatus; - vu32 ventunctl0; - vu32 field_1C4; - vu8 field_1C8[24]; - vu32 sdmemcmppadctl; - vu32 autocalcfg; - vu32 autocalintval; - vu32 autocalsts; - vu32 iospare; -} t210_sdmmc_t; - -#endif diff --git a/bootloader/utils/aarch64_util.h b/bootloader/utils/aarch64_util.h deleted file mode 100644 index a5002c0..0000000 --- a/bootloader/utils/aarch64_util.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer - * - * 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 _ARM64_H_ -#define _ARM64_H_ - -#include "types.h" - -#define LSL0 0 -#define LSL16 16 -#define LSL32 32 - -#define _PAGEOFF(x) ((x) & 0xFFFFF000) - -#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F)) -#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) -#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) -#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) -#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) -#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) -#define _NOP() 0xD503201F - -#endif diff --git a/bootloader/utils/dirlist.c b/bootloader/utils/dirlist.c deleted file mode 100644 index 2bb8eaf..0000000 --- a/bootloader/utils/dirlist.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2018 CTCaer - * - * 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 - -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../utils/types.h" - -char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles) -{ - u8 max_entries = 61; - - int res = 0; - u32 i = 0, j = 0, k = 0; - DIR dir; - FILINFO fno; - - char *dir_entries = (char *)calloc(max_entries, 256); - char *temp = (char *)calloc(1, 256); - - if (!pattern && !f_opendir(&dir, directory)) - { - for (;;) - { - res = f_readdir(&dir, &fno); - if (res || !fno.fname[0]) - break; - if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) - { - strcpy(dir_entries + (k * 256), fno.fname); - k++; - if (k > (max_entries - 1)) - break; - } - } - f_closedir(&dir); - } - else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0]) - { - do - { - if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) - { - strcpy(dir_entries + (k * 256), fno.fname); - k++; - if (k > (max_entries - 1)) - break; - } - res = f_findnext(&dir, &fno); - } while (fno.fname[0] && !res); - f_closedir(&dir); - } - - if (!k) - { - free(temp); - free(dir_entries); - - return NULL; - } - - // Reorder ini files by ASCII ordering. - for (i = 0; i < k - 1 ; i++) - { - for (j = i + 1; j < k; j++) - { - if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) - { - strcpy(temp, &dir_entries[i * 256]); - strcpy(&dir_entries[i * 256], &dir_entries[j * 256]); - strcpy(&dir_entries[j * 256], temp); - } - } - } - - free(temp); - - return dir_entries; -} diff --git a/bootloader/utils/list.h b/bootloader/utils/list.h deleted file mode 100644 index b891bb7..0000000 --- a/bootloader/utils/list.h +++ /dev/null @@ -1,96 +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 . - */ - -#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 and make sure that the list has at least one entry. */ -#define LIST_FOREACH_ENTRY(etype, iter, list, mn) \ - if ((list)->next != (list)) \ - 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/bootloader/utils/types.h b/bootloader/utils/types.h deleted file mode 100644 index e0c43fe..0000000 --- a/bootloader/utils/types.h +++ /dev/null @@ -1,99 +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 . -*/ - -#ifndef _TYPES_H_ -#define _TYPES_H_ - -#define NULL ((void *)0) - -#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ALIGN_DOWN(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 signed char s8; -typedef short s16; -typedef short SHORT; -typedef int s32; -typedef int INT; -typedef long LONG; -typedef long long int s64; -typedef unsigned char u8; -typedef unsigned char BYTE; -typedef unsigned short u16; -typedef unsigned short WORD; -typedef unsigned short WCHAR; -typedef unsigned int u32; -typedef unsigned int UINT; -typedef unsigned long DWORD; -typedef unsigned long long QWORD; -typedef unsigned long long int u64; -typedef volatile unsigned char vu8; -typedef volatile unsigned short vu16; -typedef volatile unsigned int vu32; - -typedef int bool; -#define true 1 -#define false 0 - -#define BOOT_CFG_AUTOBOOT_EN (1 << 0) -#define BOOT_CFG_FROM_LAUNCH (1 << 1) -#define BOOT_CFG_FROM_ID (1 << 2) -#define BOOT_CFG_SEPT_RUN (1 << 7) - -#define EXTRA_CFG_KEYS (1 << 0) -#define EXTRA_CFG_PAYLOAD (1 << 1) -#define EXTRA_CFG_MODULE (1 << 2) - -#define EXTRA_CFG_NYX_RELOAD (1 << 6) -#define EXTRA_CFG_NYX_DUMP (1 << 7) - -typedef struct __attribute__((__packed__)) _boot_cfg_t -{ - u8 boot_cfg; - u8 autoboot; - u8 autoboot_list; - u8 extra_cfg; - union - { - struct - { - char id[8]; - }; - u8 xt_str[0x80]; - }; -} boot_cfg_t; - -typedef struct __attribute__((__packed__)) _ipl_ver_meta_t -{ - u32 magic; - u32 version; - u16 rsvd0; - u16 rsvd1; -} ipl_ver_meta_t; - -typedef struct __attribute__((__packed__)) _reloc_meta_t -{ - u32 start; - u32 stack; - u32 end; - u32 ep; -} reloc_meta_t; - -#endif diff --git a/bootloader/utils/util.c b/bootloader/utils/util.c deleted file mode 100644 index cae1981..0000000 --- a/bootloader/utils/util.c +++ /dev/null @@ -1,139 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer -* -* 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 "util.h" -#include "../gfx/di.h" -#include "../mem/minerva.h" -#include "../power/max77620.h" -#include "../rtc/max77620-rtc.h" -#include "../soc/bpmp.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" - -#define USE_RTC_TIMER - -extern volatile nyx_storage_t *nyx_str; - -extern void sd_unmount(); - -u32 get_tmr_s() -{ - return RTC(APBDEV_RTC_SECONDS); -} - -u32 get_tmr_ms() -{ - // The registers must be read with the following order: - // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) - return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); -} - -u32 get_tmr_us() -{ - return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US -} - -void msleep(u32 ms) -{ -#ifdef USE_RTC_TIMER - u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); - // Casting to u32 is important! - while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) - ; -#else - bpmp_msleep(ms); -#endif -} - -void usleep(u32 us) -{ -#ifdef USE_RTC_TIMER - u32 start = TMR(TIMERUS_CNTR_1US); - - // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately. - if ((start + us) < start) - bpmp_usleep(us); - else - while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important! - ; -#else - bpmp_usleep(us); -#endif -} - -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) -{ - for(u32 i = 0; i < num_ops; i++) - base[ops[i].off] = ops[i].val; -} - -void panic(u32 val) -{ - // Set panic code. - PMC(APBDEV_PMC_SCRATCH200) = val; - //PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE; - TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN; - TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN; - TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN; - TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; - - while (true) - usleep(1); -} - -void reboot_normal() -{ - bpmp_mmu_disable(); - - sd_unmount(); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; - - panic(0x21); // Bypass fuse programming in package1. -} - -void reboot_rcm() -{ - bpmp_mmu_disable(); - - sd_unmount(); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; - - PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm. - PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; - - while (true) - bpmp_halt(); -} - -void power_off() -{ - sd_unmount(); - display_end(); - - // Stop the alarm, in case we injected and powered off too fast. - max77620_rtc_stop_alarm(); - - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); - - while (true) - bpmp_halt(); -} diff --git a/bootloader/utils/util.h b/bootloader/utils/util.h deleted file mode 100644 index cdddc85..0000000 --- a/bootloader/utils/util.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 _UTIL_H_ -#define _UTIL_H_ - -#include "types.h" -#include "../mem/minerva.h" - -typedef enum -{ - NYX_CFG_DUMP = (1 << 7), -} nyx_cfg_t; - -typedef enum -{ - ERR_LIBSYS_LP0 = (1 << 0), - ERR_SYSOLD_NYX = (1 << 1), - ERR_SYSOLD_MTC = (1 << 2), -} hekate_errors_t; - -#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ - ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) - -typedef struct _cfg_op_t -{ - u32 off; - u32 val; -} cfg_op_t; - -typedef struct _nyx_info_t -{ - u32 rsvd; - u32 errors; -} nyx_info_t; - -typedef struct _nyx_storage_t -{ - u32 version; - u32 cfg; - u8 irama[0x8000]; - u8 hekate[0x30000]; - u8 rsvd[0x800000 - sizeof(nyx_info_t)]; - nyx_info_t info; - mtc_config_t mtc_cfg; - emc_table_t mtc_table; -} nyx_storage_t; - -u32 get_tmr_us(); -u32 get_tmr_ms(); -u32 get_tmr_s(); -void usleep(u32 us); -void msleep(u32 ms); -void panic(u32 val); -void reboot_normal(); -void reboot_rcm(); -void power_off(); -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); - -#endif diff --git a/common/common_gfx.h b/common/common_gfx.h deleted file mode 100644 index b6dbdab..0000000 --- a/common/common_gfx.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Common Gfx Header - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * Copyright (c) 2018 M4xw - * - * 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 . -*/ - -#pragma once -//TODO: Move it to BDK -#include "../bootloader/utils/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 fntsz; - u32 x; - u32 y; - u32 savedx; - u32 savedy; - u32 fgcol; - int fillbg; - u32 bgcol; - bool mute; -} gfx_con_t; diff --git a/common/memory_map.h b/common/memory_map.h deleted file mode 100644 index 06dd63f..0000000 --- a/common/memory_map.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 _MEMORY_MAP_H_ -#define _MEMORY_MAP_H_ - -//#define IPL_STACK_TOP 0x4003FF00 -/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ -/* --- IPL: 0x40008000 - 0x40028000 --- */ -#define IPL_LOAD_ADDR 0x40008000 -#define IPL_SZ_MAX 0x20000 // 128KB. -//#define IRAM_LIB_ADDR 0x4002B000 -#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. -#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32. - -/* --- DRAM START --- */ -#define DRAM_START 0x80000000 -/* Do not write anything in this area */ -#define NYX_LOAD_ADDR 0x81000000 -#define NYX_SZ_MAX 0x1000000 -/* Stack theoretical max: 220MB */ -#define IPL_STACK_TOP 0x90010000 -#define IPL_HEAP_START 0x90020000 -#define IPL_HEAP_SZ 0x24FE0000 // 592MB. -/* --- Gap: 0xB5000000 - 0xB5FFFFFF --- */ - -// SDMMC DMA buffers -#define SDXC_BUF_ALIGNED 0xB6000000 -#define MIXD_BUF_ALIGNED 0xB7000000 -#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED -#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). -#define SDMMC_UPPER_BUFFER 0xB8000000 -#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. - -// Virtual disk / Chainloader buffers. -#define RAM_DISK_ADDR 0xC1000000 -#define RAM_DISK_SZ 0x20000000 -//#define DRAM_LIB_ADDR 0xE0000000 -/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. -/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */ - -// Nyx buffers. -#define NYX_STORAGE_ADDR 0xED000000 -#define NYX_RES_ADDR 0xEE000000 - -// Framebuffer addresses. -#define IPL_FB_ADDRESS 0xF0000000 -#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. -#define LOG_FB_ADDRESS 0xF0400000 -#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. -#define NYX_FB_ADDRESS 0xF0800000 -#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. - -// Nyx LvGL buffers. -#define NYX_LV_VDB_ADR 0xF0C00000 -#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. -#define NYX_LV_MEM_ADR 0xF1000000 -#define NYX_LV_MEM_SZ 0x8000000 - -// NX BIS driver sector cache. -#define NX_BIS_CACHE_ADDR 0xF9000000 -#define NX_BIS_CACHE_SZ 0x8800 -/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */ - -// #define EXT_PAYLOAD_ADDR 0xC03C0000 -// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -// #define COREBOOT_ADDR (0xD0000000 - 0x100000) - -// NYX -// #define EXT_PAYLOAD_ADDR 0xC0000000 -// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -// #define COREBOOT_ADDR (0xD0000000 - 0x100000) - -#endif diff --git a/loader/Makefile b/loader/Makefile new file mode 100644 index 0000000..c2a12c0 --- /dev/null +++ b/loader/Makefile @@ -0,0 +1,65 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/base_rules + +################################################################################ + +LDR_LOAD_ADDR := 0x40007000 +IPL_MAGIC := 0x43544349 #"ICTC" +include ../Versions.inc + +################################################################################ + +TARGET := loader +BUILDDIR := ../build +OUTPUTDIR := ../output +BDKDIR := bdk +BDKINC := -I../$(BDKDIR) +VPATH += $(dir $(wildcard ../$(BDKDIR)/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/)) + +# Main and graphics. +OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ + start.o loader.o lz.o \ +) + +################################################################################ + +CUSTOMDEFINES := -DBL_MAGIC=$(IPL_MAGIC) +CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_VER_RL=$(BLVERSION_REL) + +#TODO: Considering reinstating some of these when pointer warnings have been fixed. +WARNINGS := -Wall -Wsign-compare -Wno-array-bounds -Wno-stringop-overflow + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +CFLAGS = $(ARCH) -O2 -g -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) +LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=LDR_LOAD_ADDR=$(LDR_LOAD_ADDR) + +################################################################################ + +.PHONY: all clean + +all: $(TARGET).bin $(TOOLSLZ) $(TOOLSB2C) + +clean: + @rm -rf $(OBJS) + +$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf + @$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(PAYLOAD_NAME).bin + +$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) + @$(CC) $(LDFLAGS) -T link.ld $^ -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: %.c + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: %.S + @$(CC) $(CFLAGS) -c $< -o $@ + +$(OBJS): $(BUILDDIR)/$(TARGET) + +$(BUILDDIR)/$(TARGET): + @mkdir -p "$(BUILDDIR)" + @mkdir -p "$(BUILDDIR)/$(TARGET)" + @mkdir -p "$(OUTPUTDIR)" diff --git a/loader/link.ld b/loader/link.ld new file mode 100644 index 0000000..81e1085 --- /dev/null +++ b/loader/link.ld @@ -0,0 +1,30 @@ +ENTRY(_start) + +SECTIONS { + PROVIDE(__ipl_start = LDR_LOAD_ADDR); + . = __ipl_start; + .text : { + *(.text._start); + KEEP(*(._boot_cfg)); + KEEP(*(._ipl_version)); + KEEP(*(._octopus)); + *(.text*); + } + .data : { + *(.data*); + *(.rodata*); + *(._payload_00); + *(._payload_01); + + /* + * To mitigate bad injectors/chainloaders, + * miss-align binary size to account for version info. + * !If version text is not appended, then use ". = ALIGN(4)"! + */ + data_end_ua = .; + . = ((data_end_ua + 0x6 + 4 - 1) & ~(4 - 1)) - 6; + } + __ldr_end = .; + . = ALIGN(0x10); + __ipl_end = .; +} diff --git a/loader/loader.c b/loader/loader.c new file mode 100644 index 0000000..03bc63e --- /dev/null +++ b/loader/loader.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019-2024 CTCaer + * + * 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 + +#include "payload_00.h" +#include "payload_01.h" + +#include +#include +#include +#include + +// 0x4003D000: Safe for panic preserving, 0x40038000: Safe for debugging needs. +#define IPL_RELOC_TOP 0x40038000 +#define IPL_PATCHED_RELOC_SZ 0x94 + +boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; +const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = { + .magic = BL_MAGIC, + .version = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16) | ((BL_VER_RL) << 24), + .rsvd0 = 0, + .rsvd1 = 0 +}; + +const char __attribute__((section ("._octopus"))) octopus[] = + "\n" + " ___\n" + " .-' `'.\n" + " / \\\n" + " | ;\n" + " | | ___.--,\n" + " _.._ |0) = (0) | _.---'`__.-( (_.\n" + " __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `\"\"`\n" + " ( ,.--'` ',__ /./; ;, '.__.'` __\n" + " _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n" + " `---' .'.''-._.-'`_./ /\\ '. \\ _.--''````'''--._`-.__.'\n" + " | | .' _.-' | | \\ \\ '. `----`\n" + " \\ \\/ .' \\ \\ '. '-._)\n" + " \\/ / \\ \\ `=.__`'-.\n" + " / /\\ `) ) / / `\"\".`\\\n" + " , _.-'.'\\ \\ / / ( ( / /\n" + " `--'` ) ) .-'.' '.'. | (\n" + " (/` ( (` ) ) '-; [switchbrew]\n"; + +void loader_main() +{ + // Preliminary BPMP clocks init. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). + + // Set arbiter. + ARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x12412D1; + ARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x0000000; + ARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x220244A; + ARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320369B; + + // Get Payload size. + u32 payload_size = sizeof(payload_00) + sizeof(payload_01); // Actual payload size. + payload_size += (u32)payload_01 - (u32)payload_00 - sizeof(payload_00); // Add compiler alignment. + payload_size = ALIGN(payload_size, 4); // Align size to 4 bytes. + u32 *payload_addr = (u32 *)payload_00; + + // Relocate payload to a safer place. + u32 words = payload_size >> 2; + u32 *src = payload_addr + words - 1; + u32 *dst = (u32 *)(IPL_RELOC_TOP - 4); + while (words) + { + *dst = *src; + src--; + dst--; + words--; + } + + // Set source address of the first part. + u8 *src_addr = (void *)(IPL_RELOC_TOP - payload_size); + // Uncompress first part. + u32 dst_pos = LZ_Uncompress((const u8 *)src_addr, (u8 *)IPL_LOAD_ADDR, sizeof(payload_00)); + + // Set source address of the second part. Includes compiler alignment. + src_addr += (u32)payload_01 - (u32)payload_00; + // Uncompress second part. + LZ_Uncompress((const u8 *)src_addr, (u8 *)IPL_LOAD_ADDR + dst_pos, sizeof(payload_01)); + + // Copy over boot configuration storage. + memcpy((u8 *)(IPL_LOAD_ADDR + IPL_PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); + + // Chainload into uncompressed payload. + void (*ipl_ptr)() = (void *)IPL_LOAD_ADDR; + (*ipl_ptr)(); + + // Halt if we managed to get out of execution. + while (true) + ; +} diff --git a/loader/start.S b/loader/start.S new file mode 100644 index 0000000..1d7a661 --- /dev/null +++ b/loader/start.S @@ -0,0 +1,73 @@ +/* +* 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 loader_main +.type loader_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, =0x40007000 + LDR R0, =__ldr_end + BL loader_main + B . + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 diff --git a/modules/hekate_libsys_lp0/Makefile b/modules/hekate_libsys_lp0/Makefile index c0751f5..90efa07 100644 --- a/modules/hekate_libsys_lp0/Makefile +++ b/modules/hekate_libsys_lp0/Makefile @@ -7,14 +7,15 @@ include $(DEVKITARM)/base_rules TARGET := libsys_lp0 BUILD := ../../build/$(TARGET) OUTPUT := ../../output -VPATH = $(dir $(wildcard ./*/)) $(dir $(wildcard ./*/*/)) +BDKDIR := bdk +BDKINC := -I../../$(BDKDIR) OBJS = $(addprefix $(BUILD)/,\ sys_sdramlp0.o \ ) ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall -Wsign-compare $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc .PHONY: clean all @@ -22,11 +23,12 @@ LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc all: $(TARGET).bso $(BUILD)/%.o: ./%.c @mkdir -p "$(BUILD)" - $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(TARGET).bso: $(OBJS) - $(CC) $(LDFLAGS) -e _modInit $^ -o $(OUTPUT)/$(TARGET).bso - $(STRIP) -g $(OUTPUT)/$(TARGET).bso + @$(CC) $(LDFLAGS) -e _modInit $^ -o $(OUTPUT)/$(TARGET).bso + @$(STRIP) -g $(OUTPUT)/$(TARGET).bso + @echo -e "-------------\nBuilt module: "$(TARGET)".bso\n-------------" clean: @rm -rf $(OUTPUT)/$(TARGET).bso diff --git a/modules/hekate_libsys_lp0/pmc_lp0_t210.h b/modules/hekate_libsys_lp0/pmc_lp0_t210.h index 95dd033..c8a259a 100644 --- a/modules/hekate_libsys_lp0/pmc_lp0_t210.h +++ b/modules/hekate_libsys_lp0/pmc_lp0_t210.h @@ -16,7 +16,8 @@ #include "types.h" -struct tegra_pmc_regs { +struct tegra_pmc_regs +{ u32 cntrl; u32 sec_disable; u32 pmc_swrst; diff --git a/modules/hekate_libsys_lp0/sdram_lp0_param_t210.h b/modules/hekate_libsys_lp0/sdram_lp0_param_t210.h index c9237f2..fc4688a 100644 --- a/modules/hekate_libsys_lp0/sdram_lp0_param_t210.h +++ b/modules/hekate_libsys_lp0/sdram_lp0_param_t210.h @@ -20,8 +20,8 @@ * directly converting BCT config files (*.cfg) into C structure. */ -#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ -#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ +#ifndef __TEGRA210_SDRAM_PARAM_H__ +#define __TEGRA210_SDRAM_PARAM_H__ #include "types.h" @@ -57,7 +57,7 @@ enum /** * Defines the SDRAM parameter structure */ -struct sdram_params +struct sdram_params_t210 { /* Specifies the type of memory device */ diff --git a/nyx/nyx_gui/mem/sdram_param_t210.h b/modules/hekate_libsys_lp0/sdram_lp0_param_t210b01.h similarity index 91% rename from nyx/nyx_gui/mem/sdram_param_t210.h rename to modules/hekate_libsys_lp0/sdram_lp0_param_t210b01.h index d926fa4..924c766 100644 --- a/nyx/nyx_gui/mem/sdram_param_t210.h +++ b/modules/hekate_libsys_lp0/sdram_lp0_param_t210b01.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -9,35 +9,14 @@ * 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 __TEGRA210B01_SDRAM_PARAM_H__ +#define __TEGRA210B01_SDRAM_PARAM_H__ -#ifndef _SDRAM_PARAM_T210_H_ -#define _SDRAM_PARAM_T210_H_ +#include "types.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 +struct sdram_params_t210b01 { /* Specifies the type of memory device */ u32 memory_type; @@ -86,6 +65,54 @@ typedef struct _sdram_params u32 emc_bct_spare12; /* Spare BCT param */ u32 emc_bct_spare13; + /* Spare BCT param */ + u32 emc_bct_spare_secure0; + /* Spare BCT param */ + u32 emc_bct_spare_secure1; + /* Spare BCT param */ + u32 emc_bct_spare_secure2; + /* Spare BCT param */ + u32 emc_bct_spare_secure3; + /* Spare BCT param */ + u32 emc_bct_spare_secure4; + /* Spare BCT param */ + u32 emc_bct_spare_secure5; + /* Spare BCT param */ + u32 emc_bct_spare_secure6; + /* Spare BCT param */ + u32 emc_bct_spare_secure7; + /* Spare BCT param */ + u32 emc_bct_spare_secure8; + /* Spare BCT param */ + u32 emc_bct_spare_secure9; + /* Spare BCT param */ + u32 emc_bct_spare_secure10; + /* Spare BCT param */ + u32 emc_bct_spare_secure11; + /* Spare BCT param */ + u32 emc_bct_spare_secure12; + /* Spare BCT param */ + u32 emc_bct_spare_secure13; + /* Spare BCT param */ + u32 emc_bct_spare_secure14; + /* Spare BCT param */ + u32 emc_bct_spare_secure15; + /* Spare BCT param */ + u32 emc_bct_spare_secure16; + /* Spare BCT param */ + u32 emc_bct_spare_secure17; + /* Spare BCT param */ + u32 emc_bct_spare_secure18; + /* Spare BCT param */ + u32 emc_bct_spare_secure19; + /* Spare BCT param */ + u32 emc_bct_spare_secure20; + /* Spare BCT param */ + u32 emc_bct_spare_secure21; + /* Spare BCT param */ + u32 emc_bct_spare_secure22; + /* Spare BCT param */ + u32 emc_bct_spare_secure23; /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ u32 emc_clock_source; @@ -113,12 +140,13 @@ typedef struct _sdram_params /* 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; + u32 emc_auto_cal_config9; + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ u32 emc_auto_cal_vref_sel0; u32 emc_auto_cal_vref_sel1; @@ -199,11 +227,16 @@ typedef struct _sdram_params u32 emc_r2p; /* Specifies the value for EMC_W2P */ u32 emc_w2p; - /* Specifies the value for EMC_RD_RCD */ u32 emc_tppd; + u32 emc_trtm; + u32 emc_twtm; + u32 emc_tratm; + u32 emc_twatm; + u32 emc_tr2ref; u32 emc_ccdmw; + /* Specifies the value for EMC_RD_RCD */ u32 emc_rd_rcd; /* Specifies the value for EMC_WR_RCD */ u32 emc_wr_rcd; @@ -501,6 +534,8 @@ typedef struct _sdram_params u32 emc_pmacro_ddll_short_cmd_1; u32 emc_pmacro_ddll_short_cmd_2; + u32 emc_pmacro_ddll_periodic_offset; + /* * Specifies the delay after asserting CKE pin during a WarmBoot0 * sequence (in microseconds) @@ -605,8 +640,6 @@ typedef struct _sdram_params 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 */ @@ -676,7 +709,7 @@ typedef struct _sdram_params u32 emc_pmacro_vttgen_ctrl0; u32 emc_pmacro_vttgen_ctrl1; u32 emc_pmacro_vttgen_ctrl2; - + u32 emc_pmacro_dsr_vttgen_ctrl0; u32 emc_pmacro_brick_ctrl_rfu1; u32 emc_pmacro_cmd_brick_ctrl_fdpd; u32 emc_pmacro_brick_ctrl_rfu2; @@ -687,7 +720,6 @@ typedef struct _sdram_params 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; @@ -711,6 +743,28 @@ typedef struct _sdram_params u32 emc_pmacro_tx_sel_clk_src4; u32 emc_pmacro_tx_sel_clk_src5; + u32 emc_pmacro_perbit_fgcg_ctrl0; + u32 emc_pmacro_perbit_fgcg_ctrl1; + u32 emc_pmacro_perbit_fgcg_ctrl2; + u32 emc_pmacro_perbit_fgcg_ctrl3; + u32 emc_pmacro_perbit_fgcg_ctrl4; + u32 emc_pmacro_perbit_fgcg_ctrl5; + u32 emc_pmacro_perbit_rfu_ctrl0; + u32 emc_pmacro_perbit_rfu_ctrl1; + u32 emc_pmacro_perbit_rfu_ctrl2; + u32 emc_pmacro_perbit_rfu_ctrl3; + u32 emc_pmacro_perbit_rfu_ctrl4; + u32 emc_pmacro_perbit_rfu_ctrl5; + u32 emc_pmacro_perbit_rfu1_ctrl0; + u32 emc_pmacro_perbit_rfu1_ctrl1; + u32 emc_pmacro_perbit_rfu1_ctrl2; + u32 emc_pmacro_perbit_rfu1_ctrl3; + u32 emc_pmacro_perbit_rfu1_ctrl4; + u32 emc_pmacro_perbit_rfu1_ctrl5; + + u32 emc_pmacro_data_pi_ctrl; + u32 emc_pmacro_cmd_pi_ctrl; + u32 emc_pmacro_ddll_bypass; u32 emc_pmacro_ddll_pwrd0; @@ -926,6 +980,12 @@ typedef struct _sdram_params u32 mc_mts_carveout_size_mb; /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ u32 mc_mts_carveout_reg_ctrl; -} sdram_params_t; + + /* Specifies the clients that are allowed to access untranslated memory */ + u32 mc_untranslated_region_check; + + /* Just a place holder for special usage when there is no BCT for certain registers */ + u32 bct_na; +}; #endif diff --git a/modules/hekate_libsys_lp0/sys_sdramlp0.c b/modules/hekate_libsys_lp0/sys_sdramlp0.c index 44dffd4..c55819a 100644 --- a/modules/hekate_libsys_lp0/sys_sdramlp0.c +++ b/modules/hekate_libsys_lp0/sys_sdramlp0.c @@ -2,7 +2,7 @@ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * Copyright 2014 Google Inc. * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,17 +17,8 @@ #include "t210.h" #include "pmc_lp0_t210.h" #include "sdram_lp0_param_t210.h" -#include "../../common/common_module.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) -{ - struct sdram_params *sdram = (struct sdram_params *)params; - struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; +#include "sdram_lp0_param_t210b01.h" +#include #define pack(src, src_bits, dst, dst_bits) { \ u32 mask = 0xffffffff >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \ @@ -47,6 +38,16 @@ void sdram_lp0_save_params(const void *params) /* 32 bits version c macro */ #define c32(value, pmcreg) pmc->pmcreg = value +/* + * 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). + */ +static void _sdram_lp0_save_params_t210(const void *params) +{ + struct sdram_params_t210 *sdram = (struct sdram_params_t210 *)params; + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + //TODO: pkg1.1 (1.X - 3.X) reads them from MC. // Patch carveout parameters. /*sdram->McGeneralizedCarveout1Bom = 0; @@ -1114,7 +1115,7 @@ void sdram_lp0_save_params(const void *params) c32(0, scratch3); s(PllMInputDivider, 7:0, scratch3, 7:0); - c(0x3e, scratch3, 15:8); + c(0x3E, scratch3, 15:8); c(0, scratch3, 20:16); s(PllMKVCO, 0:0, scratch3, 21:21); s(PllMKCP, 1:0, scratch3, 23:22); @@ -1124,9 +1125,365 @@ void sdram_lp0_save_params(const void *params) c32(0, scratch4); s(PllMStableTime, 9:0, scratch4, 9:0); + s(PllMStableTime, 9:0, scratch4, 19:10); } +#pragma GCC diagnostic ignored "-Wparentheses" + +static void _sdram_lp0_save_params_t210b01(const void *params) +{ + struct sdram_params_t210b01 *sdram = (struct sdram_params_t210b01 *)params; + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + + u32 tmp = 0; + + sdram->mc_generalized_carveout1_cfg0 = 0; + sdram->mc_generalized_carveout2_cfg0 = 0; + sdram->mc_generalized_carveout3_cfg0 = 0; + sdram->mc_generalized_carveout4_cfg0 = 0; + sdram->mc_generalized_carveout5_cfg0 = 0; + + // Patch SDRAM parameters. + u32 t0 = 32 * sdram->emc_swizzle_rank0_byte0 >> 29 > 2 * sdram->emc_swizzle_rank0_byte0 >> 29; + u32 t1 = t0 & 0xFFFFFFEF | 16 * (32 * sdram->emc_swizzle_rank1_byte0 >> 29 > 2 * sdram->emc_swizzle_rank1_byte0 >> 29); + u32 t2 = t1 & 0xFFFFFFFD | 2 * (32 * sdram->emc_swizzle_rank0_byte1 >> 29 > 2 * sdram->emc_swizzle_rank0_byte1 >> 29); + u32 t3 = t2 & 0xFFFFFFDF | 32 * (32 * sdram->emc_swizzle_rank1_byte1 >> 29 > 2 * sdram->emc_swizzle_rank1_byte1 >> 29); + u32 t4 = t3 & 0xFFFFFFFB | 4 * (32 * sdram->emc_swizzle_rank0_byte2 >> 29 > 2 * sdram->emc_swizzle_rank0_byte2 >> 29); + u32 t5 = t4 & 0xFFFFFFBF | ((32 * sdram->emc_swizzle_rank1_byte2 >> 29 > 2 * sdram->emc_swizzle_rank1_byte2 >> 29) << 6); + u32 t6 = t5 & 0xFFFFFFF7 | 8 * (32 * sdram->emc_swizzle_rank0_byte3 >> 29 > 2 * sdram->emc_swizzle_rank0_byte3 >> 29); + u32 t7 = t6 & 0xFFFFFF7F | ((32 * sdram->emc_swizzle_rank1_byte3 >> 29 > 2 * sdram->emc_swizzle_rank1_byte3 >> 29) << 7); + sdram->swizzle_rank_byte_encode = t7; + sdram->emc_bct_spare2 = 0x40000DD8; + sdram->emc_bct_spare3 = t7; + + pmc->scratch6 = (sdram->emc_clock_source_dll << 20 >> 30 << 30) | (4 * ((sdram->emc_clock_source_dll >> 29 << 27) | ((sdram->emc_clock_source >> 29 << 24) | ((sdram->emc_clock_source_dll << 16) & 0xFFFFFF | ((sdram->emc_clock_source << 8) & 0xFFFF | pmc->scratch6 & 0xFFFF00FF) & 0xFF00FFFF) & 0xF8FFFFFF) & 0xC7FFFFFF) >> 2); + pmc->scratch7 = (sdram->emc_rc << 24) | ((sdram->emc_zqcal_lpddr4_warm_boot << 27 >> 31 << 23) | ((sdram->emc_zqcal_lpddr4_warm_boot << 30 >> 31 << 22) | ((sdram->emc_zqcal_lpddr4_warm_boot << 21) & 0x3FFFFF | ((sdram->clk_rst_pllm_misc20_override << 20) & 0x1FFFFF | ((sdram->clk_rst_pllm_misc20_override << 28 >> 31 << 19) | ((sdram->clk_rst_pllm_misc20_override << 27 >> 31 << 18) | ((sdram->clk_rst_pllm_misc20_override << 26 >> 31 << 17) | ((sdram->clk_rst_pllm_misc20_override << 21 >> 31 << 16) | ((sdram->clk_rst_pllm_misc20_override << 20 >> 31 << 15) | ((sdram->clk_rst_pllm_misc20_override << 19 >> 31 << 14) | ((sdram->clk_rst_pllm_misc20_override << 18 >> 31 << 13) | ((sdram->emc_clock_source << 15 >> 31 << 12) | ((sdram->emc_clock_source << 11 >> 31 << 11) | ((sdram->emc_clock_source << 12 >> 31 << 10) | ((sdram->emc_clock_source << 6 >> 31 << 9) | ((sdram->emc_clock_source << 16 >> 31 << 8) | ((32 * sdram->emc_clock_source >> 31 << 7) | ((16 * sdram->emc_clock_source >> 31 << 6) | (16 * (sdram->emc_zqcal_lpddr4_warm_boot >> 30) | (4 * (sdram->clk_rst_pllm_misc20_override << 29 >> 30) | ((sdram->clk_rst_pllm_misc20_override << 22 >> 30) | 4 * (pmc->scratch7 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFFFFFF; + pmc->scratch8 = (sdram->emc_pmacro_bg_bias_ctrl0 << 18 >> 30 << 30) | ((4 * pmc->scratch8) >> 2); + pmc->scratch14 = ((u8)(sdram->emc_cfg_pipe_clk) << 31) | (2 * (((u8)(sdram->emc_fdpd_ctrl_cmd_no_ramp) << 30) | pmc->scratch14 & 0xBFFFFFFF) >> 1); + pmc->scratch15 = (sdram->emc_qrst << 11 >> 27 << 27) | ((sdram->emc_qrst << 20) | pmc->scratch15 & 0xF80FFFFF) & 0x7FFFFFF; + pmc->scratch16 = ((u16)(sdram->emc_pmacro_cmd_tx_drive) << 18 >> 26 << 26) | (((u16)(sdram->emc_pmacro_cmd_tx_drive) << 20) | pmc->scratch16 & 0xFC0FFFFF) & 0x3FFFFFF; + pmc->scratch17 = (16 * sdram->emc_fbio_cfg8 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg8 >> 31 << 30) | ((sdram->emc_fbio_cfg8 << 6 >> 31 << 29) | ((sdram->emc_fbio_cfg8 << 7 >> 31 << 28) | ((sdram->emc_fbio_cfg8 << 8 >> 31 << 27) | ((sdram->emc_fbio_cfg8 << 9 >> 31 << 26) | ((sdram->emc_fbio_cfg8 << 10 >> 31 << 25) | ((sdram->emc_fbio_cfg8 << 11 >> 31 << 24) | ((sdram->emc_fbio_cfg8 << 12 >> 31 << 23) | ((sdram->emc_fbio_cfg8 << 13 >> 31 << 22) | ((sdram->emc_fbio_cfg8 << 14 >> 31 << 21) | ((sdram->emc_fbio_cfg8 << 15 >> 31 << 20) | pmc->scratch17 & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch18 = ((u16)(sdram->emc_txsr_dll) << 20) | pmc->scratch18 & 0xFFFFF; + pmc->scratch19 = (sdram->emc_txdsrvttgen << 20) | pmc->scratch19 & 0xFFFFF; + pmc->scratch22 = (sdram->emc_cfg_rsv >> 24 << 24) | ((sdram->emc_cfg_rsv >> 16 << 16) | ((sdram->emc_cfg_rsv << 16 >> 24 << 8) | (sdram->emc_cfg_rsv & 0xFF | (pmc->scratch22 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFFFFFF; + pmc->scratch23 = (sdram->emc_auto_cal_config >> 31 << 31) | (2 * ((2 * sdram->emc_auto_cal_config >> 31 << 30) | ((4 * sdram->emc_auto_cal_config >> 31 << 29) | ((8 * sdram->emc_auto_cal_config >> 28 << 25) | ((sdram->emc_auto_cal_config << 7 >> 31 << 24) | ((sdram->emc_auto_cal_config << 8 >> 27 << 19) | ((sdram->emc_auto_cal_config << 13 >> 29 << 16) | ((sdram->emc_auto_cal_config << 16 >> 27 << 11) | ((sdram->emc_auto_cal_config << 21 >> 31 << 10) | ((sdram->emc_auto_cal_config << 22 >> 31 << 9) | ((sdram->emc_auto_cal_config << 23 >> 31 << 8) | ((sdram->emc_auto_cal_config << 24 >> 31 << 7) | ((sdram->emc_auto_cal_config << 25 >> 31 << 6) | (32 * (sdram->emc_auto_cal_config << 26 >> 31) | (16 * (sdram->emc_auto_cal_config << 27 >> 31) | (8 * (sdram->emc_auto_cal_config << 28 >> 31) | (4 * (sdram->emc_auto_cal_config << 29 >> 31) | (2 * (sdram->emc_auto_cal_config << 30 >> 31) | (sdram->emc_auto_cal_config & 1 | 2 * (pmc->scratch23 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFF07FF) & 0xFFF8FFFF) & 0xFF07FFFF) & 0xFEFFFFFF) & 0xE1FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch24 = (sdram->emc_auto_cal_vref_sel0 >> 31 << 31) | (2 * ((2 * sdram->emc_auto_cal_vref_sel0 >> 25 << 24) | ((sdram->emc_auto_cal_vref_sel0 << 8 >> 31 << 23) | ((sdram->emc_auto_cal_vref_sel0 << 9 >> 25 << 16) | ((sdram->emc_auto_cal_vref_sel0 << 16 >> 31 << 15) | ((sdram->emc_auto_cal_vref_sel0 << 17 >> 25 << 8) | ((sdram->emc_auto_cal_vref_sel0 << 24 >> 31 << 7) | (sdram->emc_auto_cal_vref_sel0 & 0x7F | (pmc->scratch24 >> 7 << 7)) & 0xFFFFFF7F) & 0xFFFF80FF) & 0xFFFF7FFF) & 0xFF80FFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch25 = (sdram->emc_pmacro_brick_ctrl_rfu1 >> 16 << 16) | sdram->emc_pmacro_brick_ctrl_rfu1 & 0xFFFF; + pmc->scratch26 = (sdram->emc_pmacro_brick_ctrl_rfu2 >> 16 << 16) | sdram->emc_pmacro_brick_ctrl_rfu2 & 0xFFFF; + s32(emc_pmc_scratch1, scratch27); + s32(emc_pmc_scratch2, scratch28); + s32(emc_pmc_scratch3, scratch29); + pmc->scratch30 = (sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl0 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl0 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl0 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl0 & 3 | 4 * (pmc->scratch30 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch31 = (sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl1 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl1 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl1 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl1 & 3 | 4 * (pmc->scratch31 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch32 = (sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl2 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl2 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl2 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl2 & 3 | 4 * (pmc->scratch32 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch33 = (sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl3 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl3 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl3 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl3 & 3 | 4 * (pmc->scratch33 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch40 = (sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl4 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl4 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl4 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl4 & 3 | 4 * (pmc->scratch40 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch42 = (sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 30) | (4 * ((4 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 28) | ((16 * sdram->emc_pmacro_perbit_rfu_ctrl5 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 6 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 8 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 10 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 12 >> 30 << 18) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 14 >> 30 << 16) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 16 >> 30 << 14) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 18 >> 30 << 12) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 20 >> 30 << 10) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 22 >> 30 << 8) | ((sdram->emc_pmacro_perbit_rfu_ctrl5 << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 26 >> 30) | (4 * (sdram->emc_pmacro_perbit_rfu_ctrl5 << 28 >> 30) | (sdram->emc_pmacro_perbit_rfu_ctrl5 & 3 | 4 * (pmc->scratch42 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch44 = (sdram->mc_emem_arb_da_turns >> 24 << 24) | ((sdram->mc_emem_arb_da_turns >> 16 << 16) | ((sdram->mc_emem_arb_da_turns << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_turns & 0xFF | (pmc->scratch44 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFFFFFF; + pmc->scratch64 = ((u16)(sdram->mc_emem_arb_misc2) << 31) | (2 * ((sdram->emc_fbio_spare << 30) | ((sdram->emc_fbio_spare << 24 >> 26 << 24) | ((sdram->emc_fbio_spare << 16 >> 24 << 16) | ((sdram->emc_fbio_spare << 8 >> 24 << 8) | ((sdram->emc_fbio_spare >> 24) | (pmc->scratch64 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch65 = ((u16)(sdram->mc_da_cfg0) << 31 >> 1) | ((2 * sdram->mc_emem_arb_misc0 >> 29 << 27) | ((16 * sdram->mc_emem_arb_misc0 >> 31 << 26) | ((32 * sdram->mc_emem_arb_misc0 >> 26 << 20) | ((sdram->mc_emem_arb_misc0 << 11 >> 27 << 15) | ((sdram->mc_emem_arb_misc0 << 17 >> 25 << 8) | ((u8)sdram->mc_emem_arb_misc0 | (pmc->scratch65 >> 8 << 8)) & 0xFFFF80FF) & 0xFFF07FFF) & 0xFC0FFFFF) & 0xFBFFFFFF) & 0xC7FFFFFF) & 0xBFFFFFFF; + pmc->scratch66 = (sdram->emc_fdpd_ctrl_cmd >> 30 << 27) | ((4 * sdram->emc_fdpd_ctrl_cmd >> 31 << 26) | ((8 * sdram->emc_fdpd_ctrl_cmd >> 27 << 21) | ((sdram->emc_fdpd_ctrl_cmd << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_cmd << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_cmd << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_cmd | (pmc->scratch66 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xFBFFFFFF) & 0xE7FFFFFF; + pmc->scratch67 = ((u8)(sdram->emc_burst_refresh_num) << 28) | ((16 * sdram->emc_auto_cal_config2 >> 30 << 26) | ((sdram->emc_auto_cal_config2 << 6 >> 30 << 24) | ((sdram->emc_auto_cal_config2 << 8 >> 30 << 22) | ((sdram->emc_auto_cal_config2 << 10 >> 30 << 20) | ((sdram->emc_auto_cal_config2 << 12 >> 30 << 18) | ((sdram->emc_auto_cal_config2 << 14 >> 30 << 16) | ((sdram->emc_auto_cal_config2 << 16 >> 30 << 14) | ((sdram->emc_auto_cal_config2 << 18 >> 30 << 12) | ((sdram->emc_auto_cal_config2 << 20 >> 30 << 10) | ((sdram->emc_auto_cal_config2 << 22 >> 30 << 8) | ((sdram->emc_auto_cal_config2 << 24 >> 30 << 6) | (16 * (sdram->emc_auto_cal_config2 << 26 >> 30) | (4 * (sdram->emc_auto_cal_config2 << 28 >> 30) | (sdram->emc_auto_cal_config2 & 3 | 4 * (pmc->scratch67 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; + pmc->scratch68 = ((u8)(sdram->emc_tppd) << 28) | ((sdram->emc_cfg_dig_dll >> 31 << 27) | ((2 * sdram->emc_cfg_dig_dll >> 31 << 26) | ((16 * sdram->emc_cfg_dig_dll >> 31 << 25) | ((sdram->emc_cfg_dig_dll << 6 >> 22 << 15) | ((sdram->emc_cfg_dig_dll << 16 >> 31 << 14) | ((sdram->emc_cfg_dig_dll << 17 >> 31 << 13) | ((sdram->emc_cfg_dig_dll << 18 >> 30 << 11) | ((sdram->emc_cfg_dig_dll << 21 >> 29 << 8) | ((sdram->emc_cfg_dig_dll << 24 >> 30 << 6) | (32 * (sdram->emc_cfg_dig_dll << 26 >> 31) | (16 * (sdram->emc_cfg_dig_dll << 27 >> 31) | (8 * (sdram->emc_cfg_dig_dll << 28 >> 31) | (4 * (sdram->emc_cfg_dig_dll << 29 >> 31) | (2 * (sdram->emc_cfg_dig_dll << 30 >> 31) | (sdram->emc_cfg_dig_dll & 1 | 2 * (pmc->scratch68 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFF3F) & 0xFFFFF8FF) & 0xFFFFE7FF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFE007FFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; + pmc->scratch69 = (sdram->emc_r2r << 28) | ((sdram->emc_fdpd_ctrl_dq >> 30 << 26) | ((8 * sdram->emc_fdpd_ctrl_dq >> 27 << 21) | ((sdram->emc_fdpd_ctrl_dq << 8 >> 28 << 17) | ((sdram->emc_fdpd_ctrl_dq << 15 >> 27 << 12) | ((sdram->emc_fdpd_ctrl_dq << 20 >> 28 << 8) | ((u8)sdram->emc_fdpd_ctrl_dq | (pmc->scratch69 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFE0FFF) & 0xFFE1FFFF) & 0xFC1FFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; + pmc->scratch70 = (sdram->emc_w2w << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_0 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ib_vref_dq_0 & 0x7F | (pmc->scratch70 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; + pmc->scratch71 = (sdram->emc_pmacro_vttgen_ctrl0 << 12 >> 28 << 28) | ((2 * sdram->emc_pmacro_ib_vref_dq_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dq_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dq_1 << 17 >> 25 << 7) | ((pmc->scratch71 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dq_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; + pmc->scratch72 = (((sdram->emc_pmacro_ib_vref_dqs_0 << 17 >> 25 << 7) | ((pmc->scratch72 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_0 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF | (sdram->emc_pmacro_ib_vref_dqs_0 << 9 >> 25 << 14)) & 0xF01FFFFF | (2 * sdram->emc_pmacro_ib_vref_dqs_0 >> 25 << 21); + pmc->scratch73 = (2 * sdram->emc_pmacro_ib_vref_dqs_1 >> 25 << 21) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ib_vref_dqs_1 << 17 >> 25 << 7) | ((pmc->scratch73 >> 7 << 7) | sdram->emc_pmacro_ib_vref_dqs_1 & 0x7F) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; + pmc->scratch74 = (2 * sdram->emc_pmacro_ddll_short_cmd_0 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_0 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_0 & 0x7F | (pmc->scratch74 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; + pmc->scratch75 = (2 * sdram->emc_pmacro_ddll_short_cmd_1 >> 25 << 21) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 9 >> 25 << 14) | ((sdram->emc_pmacro_ddll_short_cmd_1 << 17 >> 25 << 7) | (sdram->emc_pmacro_ddll_short_cmd_1 & 0x7F | (pmc->scratch75 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF; + pmc->scratch76 = (sdram->emc_rp << 26) | ((4 * sdram->emc_dll_cfg0 >> 31 << 25) | ((8 * sdram->emc_dll_cfg0 >> 31 << 24) | ((16 * sdram->emc_dll_cfg0 >> 28 << 20) | ((sdram->emc_dll_cfg0 << 8 >> 28 << 16) | ((sdram->emc_dll_cfg0 << 12 >> 28 << 12) | ((sdram->emc_dll_cfg0 << 16 >> 28 << 8) | ((sdram->emc_dll_cfg0 << 20 >> 24) | (pmc->scratch76 >> 8 << 8)) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + tmp = (sdram->emc_pmacro_tx_pwrd0 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd0 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd0 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd0 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd0 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd0 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd0 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd0 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd0 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd0 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd0 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd0 & 1 | 2 * (pmc->scratch77 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF; + pmc->scratch77 = (sdram->emc_r2w << 26) | ((4 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd0 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd0 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd0 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd0 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd0 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd0 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd0 << 11 >> 31 << 17) | tmp & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd1 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd1 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd1 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd1 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd1 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd1 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd1 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd1 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd1 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd1 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd1 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd1 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd1 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd1 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd1 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd1 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd1 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd1 & 1 | 2 * (pmc->scratch78 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch78 = (sdram->emc_w2r << 26) | ((4 * sdram->emc_pmacro_tx_pwrd1 >> 31 << 25) | tmp) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd2 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd2 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd2 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd2 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd2 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd2 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd2 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd2 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd2 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd2 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd2 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd2 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd2 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd2 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd2 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd2 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd2 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd2 & 1 | 2 * (pmc->scratch79 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch79 = (sdram->emc_r2p << 26) | ((4 * sdram->emc_pmacro_tx_pwrd2 >> 31 << 25) | tmp) & 0x3FFFFFF; + tmp = (sdram->emc_pmacro_tx_pwrd3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd3 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd3 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd3 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd3 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd3 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd3 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd3 & 1 | 2 * (pmc->scratch80 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF; + pmc->scratch80 = ((u8)(sdram->emc_ccdmw) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 25) | ((8 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd3 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd3 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd3 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd3 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd3 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd3 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd3 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd3 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd3 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd3 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd3 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd3 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd3 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd3 << 22 >> 31 << 9) | tmp & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd4 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd4 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd4 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd4 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd4 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd4 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd4 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd4 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd4 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd4 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd4 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd4 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd4 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd4 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd4 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd4 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd4 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd4 & 1 | 2 * (pmc->scratch81 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch81 = ((u8)(sdram->emc_rd_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd4 >> 31 << 25) | tmp) & 0x3FFFFFF; + tmp = ((8 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 24) | ((32 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 23) | ((sdram->emc_pmacro_tx_pwrd5 << 6 >> 31 << 22) | ((sdram->emc_pmacro_tx_pwrd5 << 7 >> 31 << 21) | ((sdram->emc_pmacro_tx_pwrd5 << 8 >> 31 << 20) | ((sdram->emc_pmacro_tx_pwrd5 << 9 >> 31 << 19) | ((sdram->emc_pmacro_tx_pwrd5 << 10 >> 31 << 18) | ((sdram->emc_pmacro_tx_pwrd5 << 11 >> 31 << 17) | ((sdram->emc_pmacro_tx_pwrd5 << 12 >> 31 << 16) | ((sdram->emc_pmacro_tx_pwrd5 << 13 >> 31 << 15) | ((sdram->emc_pmacro_tx_pwrd5 << 14 >> 31 << 14) | ((sdram->emc_pmacro_tx_pwrd5 << 15 >> 31 << 13) | ((sdram->emc_pmacro_tx_pwrd5 << 18 >> 31 << 12) | ((sdram->emc_pmacro_tx_pwrd5 << 19 >> 31 << 11) | ((sdram->emc_pmacro_tx_pwrd5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_tx_pwrd5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_tx_pwrd5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_tx_pwrd5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_tx_pwrd5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_tx_pwrd5 << 26 >> 31) | (16 * (sdram->emc_pmacro_tx_pwrd5 << 27 >> 31) | (8 * (sdram->emc_pmacro_tx_pwrd5 << 28 >> 31) | (4 * (sdram->emc_pmacro_tx_pwrd5 << 29 >> 31) | (2 * (sdram->emc_pmacro_tx_pwrd5 << 30 >> 31) | (sdram->emc_pmacro_tx_pwrd5 & 1 | 2 * (pmc->scratch82 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF; + pmc->scratch82 = ((u16)(sdram->emc_wr_rcd) << 26) | ((4 * sdram->emc_pmacro_tx_pwrd5 >> 31 << 25) | tmp) & 0x3FFFFFF; + pmc->scratch83 = ((u8)(sdram->emc_config_sample_delay) << 25) | ((sdram->emc_auto_cal_channel >> 31 << 24) | ((2 * sdram->emc_auto_cal_channel >> 31 << 23) | ((4 * sdram->emc_auto_cal_channel >> 31 << 22) | ((16 * sdram->emc_auto_cal_channel >> 25 << 15) | ((sdram->emc_auto_cal_channel << 11 >> 27 << 10) | ((sdram->emc_auto_cal_channel << 20 >> 28 << 6) | (sdram->emc_auto_cal_channel & 0x3F | (pmc->scratch83 >> 6 << 6)) & 0xFFFFFC3F) & 0xFFFF83FF) & 0xFFC07FFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0x1FFFFFF; + pmc->scratch84 = (sdram->emc_sel_dpd_ctrl << 13 >> 29 << 29) | ((sdram->emc_sel_dpd_ctrl << 23 >> 31 << 28) | ((sdram->emc_sel_dpd_ctrl << 26 >> 31 << 27) | ((sdram->emc_sel_dpd_ctrl << 27 >> 31 << 26) | ((sdram->emc_sel_dpd_ctrl << 28 >> 31 << 25) | ((sdram->emc_sel_dpd_ctrl << 29 >> 31 << 24) | ((4 * sdram->emc_pmacro_rx_term >> 26 << 18) | ((sdram->emc_pmacro_rx_term << 10 >> 26 << 12) | ((sdram->emc_pmacro_rx_term << 18 >> 26 << 6) | (sdram->emc_pmacro_rx_term & 0x3F | (pmc->scratch84 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch85 = (4 * sdram->emc_obdly >> 30 << 30) | (4 * ((sdram->emc_obdly << 24) | ((4 * sdram->emc_pmacro_dq_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_dq_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_dq_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_dq_tx_drive & 0x3F | (pmc->scratch85 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); + pmc->scratch86 = (sdram->emc_pmacro_vttgen_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_vttgen_ctrl1 << 16 >> 26 << 24) | ((4 * sdram->emc_pmacro_ca_tx_drive >> 26 << 18) | ((sdram->emc_pmacro_ca_tx_drive << 10 >> 26 << 12) | ((sdram->emc_pmacro_ca_tx_drive << 18 >> 26 << 6) | (sdram->emc_pmacro_ca_tx_drive & 0x3F | (pmc->scratch86 >> 6 << 6)) & 0xFFFFF03F) & 0xFFFC0FFF) & 0xFF03FFFF) & 0xC0FFFFFF) >> 2); + pmc->scratch87 = (sdram->emc_pmacro_vttgen_ctrl2 >> 16 << 24) | ((16 * sdram->emc_pmacro_zcrtl >> 30 << 22) | ((sdram->emc_pmacro_zcrtl << 6 >> 30 << 20) | ((sdram->emc_pmacro_zcrtl << 8 >> 30 << 18) | ((sdram->emc_pmacro_zcrtl << 10 >> 30 << 16) | ((sdram->emc_pmacro_zcrtl << 12 >> 30 << 14) | ((sdram->emc_pmacro_zcrtl << 14 >> 30 << 12) | ((sdram->emc_pmacro_zcrtl << 16 >> 30 << 10) | ((sdram->emc_pmacro_zcrtl << 18 >> 30 << 8) | ((sdram->emc_pmacro_zcrtl << 20 >> 30 << 6) | (16 * (sdram->emc_pmacro_zcrtl << 22 >> 30) | (4 * (sdram->emc_pmacro_zcrtl << 24 >> 30) | ((sdram->emc_pmacro_zcrtl << 26 >> 30) | 4 * (pmc->scratch87 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFFFFFF; + pmc->scratch88 = (sdram->mc_emem_arb_timing_rc << 24) | ((sdram->emc_zcal_interval << 14) | ((sdram->emc_zcal_interval << 8 >> 18) | (pmc->scratch88 >> 14 << 14)) & 0xFF003FFF) & 0xFFFFFF; + pmc->scratch89 = ((u16)(sdram->mc_emem_arb_rsv) << 24) | ((sdram->emc_data_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft0 << 26 >> 29) | (sdram->emc_data_brlshft0 & 7 | 8 * (pmc->scratch89 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0xFFFFFF; + pmc->scratch90 = (sdram->emc_data_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_data_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_data_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_data_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_data_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_data_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_data_brlshft1 << 26 >> 29) | (sdram->emc_data_brlshft1 & 7 | 8 * (pmc->scratch90 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch91 = (sdram->emc_dqs_brlshft0 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft0 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft0 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft0 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft0 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft0 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft0 << 26 >> 29) | (sdram->emc_dqs_brlshft0 & 7 | 8 * (pmc->scratch91 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch92 = (sdram->emc_dqs_brlshft1 << 8 >> 29 << 21) | ((sdram->emc_dqs_brlshft1 << 11 >> 29 << 18) | ((sdram->emc_dqs_brlshft1 << 14 >> 29 << 15) | ((sdram->emc_dqs_brlshft1 << 17 >> 29 << 12) | ((sdram->emc_dqs_brlshft1 << 20 >> 29 << 9) | ((sdram->emc_dqs_brlshft1 << 23 >> 29 << 6) | (8 * (sdram->emc_dqs_brlshft1 << 26 >> 29) | (sdram->emc_dqs_brlshft1 & 7 | 8 * (pmc->scratch92 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch93 = (2 * sdram->emc_swizzle_rank0_byte0 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte0 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte0 & 7 | 8 * (pmc->scratch93 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF; + pmc->scratch94 = ((u8)(sdram->emc_cfg) << 27 >> 31 << 31) | (2 * ((sdram->emc_ras << 24) | ((2 * sdram->emc_swizzle_rank0_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte1 & 7 | 8 * (pmc->scratch94 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch95 = ((u8)(sdram->emc_cfg) << 26 >> 31 << 31) | (2 * ((sdram->emc_w2p << 24) | ((2 * sdram->emc_swizzle_rank0_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank0_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank0_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte2 & 7 | 8 * (pmc->scratch95 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch96 = ((u8)(sdram->emc_cfg) << 25 >> 31 << 31) | (2 * ((sdram->emc_qsafe << 24) | ((2 * sdram->emc_swizzle_rank0_byte3 >> 29 << 21) | (((sdram->emc_swizzle_rank0_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank0_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank0_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank0_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank0_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank0_byte3 & 7 | 8 * (pmc->scratch96 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank0_byte3 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch97 = ((u8)(sdram->emc_cfg) << 24 >> 31 << 31) | (2 * ((sdram->emc_rdv << 24) | ((2 * sdram->emc_swizzle_rank1_byte0 >> 29 << 21) | (((sdram->emc_swizzle_rank1_byte0 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte0 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte0 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte0 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte0 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte0 & 7 | 8 * (pmc->scratch97 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF | (32 * sdram->emc_swizzle_rank1_byte0 >> 29 << 18)) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch98 = ((u16)(sdram->emc_cfg) << 23 >> 31 << 31) | (2 * (((u16)(sdram->emc_rw2pden) << 24) | ((2 * sdram->emc_swizzle_rank1_byte1 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte1 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte1 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte1 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte1 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte1 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte1 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte1 & 7 | 8 * (pmc->scratch98 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch99 = ((u16)(sdram->emc_cfg) << 22 >> 31 << 31) | (2 * ((sdram->emc_tfaw << 24) | ((2 * sdram->emc_swizzle_rank1_byte2 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte2 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte2 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte2 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte2 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte2 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte2 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte2 & 7 | 8 * (pmc->scratch99 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch100 = (sdram->emc_cfg << 13 >> 31 << 31) | (2 * ((sdram->emc_tclkstable << 24) | ((2 * sdram->emc_swizzle_rank1_byte3 >> 29 << 21) | ((32 * sdram->emc_swizzle_rank1_byte3 >> 29 << 18) | ((sdram->emc_swizzle_rank1_byte3 << 9 >> 29 << 15) | ((sdram->emc_swizzle_rank1_byte3 << 13 >> 29 << 12) | ((sdram->emc_swizzle_rank1_byte3 << 17 >> 29 << 9) | ((sdram->emc_swizzle_rank1_byte3 << 21 >> 29 << 6) | (8 * (sdram->emc_swizzle_rank1_byte3 << 25 >> 29) | (sdram->emc_swizzle_rank1_byte3 & 7 | 8 * (pmc->scratch100 >> 3)) & 0xFFFFFFC7) & 0xFFFFFE3F) & 0xFFFFF1FF) & 0xFFFF8FFF) & 0xFFFC7FFF) & 0xFFE3FFFF) & 0xFF1FFFFF) & 0x80FFFFFF) >> 1); + tmp = 2 * (((u8)(sdram->emc_trtm) << 24) | ((16 * sdram->emc_cfg_pipe2 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe2 >> 31 << 22) | ((sdram->emc_cfg_pipe2 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe2 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe2 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe2 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe2 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe2 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe2 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe2 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe2 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe2 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe2 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe2 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe2 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe2 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe2 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe2 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe2 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe2 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe2 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe2 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe2 << 30 >> 31) | (sdram->emc_cfg_pipe2 & 1 | 2 * (pmc->scratch101 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; + pmc->scratch101 = (sdram->emc_cfg << 10 >> 31 << 31) | tmp; + tmp = (2 * (pmc->scratch102 >> 1) | sdram->emc_cfg_pipe1 & 1) & 0xFFFFFFFD; + pmc->scratch102 = (sdram->emc_cfg << 9 >> 31 << 31) | (2 * (((u8)(sdram->emc_twtm) << 24) | ((16 * sdram->emc_cfg_pipe1 >> 31 << 23) | ((32 * sdram->emc_cfg_pipe1 >> 31 << 22) | ((sdram->emc_cfg_pipe1 << 6 >> 31 << 21) | ((sdram->emc_cfg_pipe1 << 7 >> 31 << 20) | ((sdram->emc_cfg_pipe1 << 8 >> 31 << 19) | ((sdram->emc_cfg_pipe1 << 9 >> 31 << 18) | ((sdram->emc_cfg_pipe1 << 10 >> 31 << 17) | ((sdram->emc_cfg_pipe1 << 11 >> 31 << 16) | ((sdram->emc_cfg_pipe1 << 12 >> 31 << 15) | ((sdram->emc_cfg_pipe1 << 13 >> 31 << 14) | ((sdram->emc_cfg_pipe1 << 14 >> 31 << 13) | ((sdram->emc_cfg_pipe1 << 15 >> 31 << 12) | ((sdram->emc_cfg_pipe1 << 20 >> 31 << 11) | ((sdram->emc_cfg_pipe1 << 21 >> 31 << 10) | ((sdram->emc_cfg_pipe1 << 22 >> 31 << 9) | ((sdram->emc_cfg_pipe1 << 23 >> 31 << 8) | ((sdram->emc_cfg_pipe1 << 24 >> 31 << 7) | ((sdram->emc_cfg_pipe1 << 25 >> 31 << 6) | (32 * (sdram->emc_cfg_pipe1 << 26 >> 31) | (16 * (sdram->emc_cfg_pipe1 << 27 >> 31) | (8 * (sdram->emc_cfg_pipe1 << 28 >> 31) | (4 * (sdram->emc_cfg_pipe1 << 29 >> 31) | (2 * (sdram->emc_cfg_pipe1 << 30 >> 31) | tmp) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + tmp = 2 * (((u8)(sdram->emc_tratm) << 24) | ((sdram->emc_pmacro_ddll_pwrd0 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd0 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd0 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd0 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd0 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd0 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd0 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd0 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd0 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd0 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd0 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd0 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd0 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd0 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd0 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd0 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd0 << 30 >> 31) | 2 * (pmc->scratch103 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; + pmc->scratch103 = (sdram->emc_cfg << 8 >> 31 << 31) | tmp; + tmp = 2 * (((u8)(sdram->emc_twatm) << 24) | ((sdram->emc_pmacro_ddll_pwrd1 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd1 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd1 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd1 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd1 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd1 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd1 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd1 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd1 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd1 << 21 >> 31 << 7) | ((sdram->emc_pmacro_ddll_pwrd1 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd1 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd1 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd1 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd1 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd1 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd1 << 30 >> 31) | 2 * (pmc->scratch104 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1; + pmc->scratch104 = (sdram->emc_cfg << 7 >> 31 << 31) | tmp; + tmp = (sdram->emc_pmacro_ddll_pwrd2 << 22 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_pwrd2 << 24 >> 31) | (16 * (sdram->emc_pmacro_ddll_pwrd2 << 25 >> 31) | (8 * (sdram->emc_pmacro_ddll_pwrd2 << 27 >> 31) | (4 * (sdram->emc_pmacro_ddll_pwrd2 << 28 >> 31) | (2 * (sdram->emc_pmacro_ddll_pwrd2 << 29 >> 31) | ((sdram->emc_pmacro_ddll_pwrd2 << 30 >> 31) | 2 * (pmc->scratch105 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF; + pmc->scratch105 = (sdram->emc_cfg << 6 >> 31 << 31) | (2 * (((u8)(sdram->emc_tr2ref) << 24) | ((sdram->emc_pmacro_ddll_pwrd2 >> 31 << 23) | ((2 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 22) | ((8 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 21) | ((16 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 20) | ((32 * sdram->emc_pmacro_ddll_pwrd2 >> 31 << 19) | ((sdram->emc_pmacro_ddll_pwrd2 << 6 >> 31 << 18) | ((sdram->emc_pmacro_ddll_pwrd2 << 8 >> 31 << 17) | ((sdram->emc_pmacro_ddll_pwrd2 << 9 >> 31 << 16) | ((sdram->emc_pmacro_ddll_pwrd2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_pwrd2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_ddll_pwrd2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_ddll_pwrd2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_ddll_pwrd2 << 16 >> 31 << 11) | ((sdram->emc_pmacro_ddll_pwrd2 << 17 >> 31 << 10) | ((sdram->emc_pmacro_ddll_pwrd2 << 19 >> 31 << 9) | ((sdram->emc_pmacro_ddll_pwrd2 << 20 >> 31 << 8) | ((sdram->emc_pmacro_ddll_pwrd2 << 21 >> 31 << 7) | tmp & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch106 = (32 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_pdex2mrr) << 24) | ((8 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 23) | ((16 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_periodic_offset >> 31 << 21) | ((sdram->emc_pmacro_ddll_periodic_offset << 6 >> 31 << 20) | ((sdram->emc_pmacro_ddll_periodic_offset << 7 >> 31 << 19) | ((sdram->emc_pmacro_ddll_periodic_offset << 8 >> 31 << 18) | ((sdram->emc_pmacro_ddll_periodic_offset << 9 >> 31 << 17) | ((sdram->emc_pmacro_ddll_periodic_offset << 10 >> 31 << 16) | ((sdram->emc_pmacro_ddll_periodic_offset << 11 >> 31 << 15) | ((sdram->emc_pmacro_ddll_periodic_offset << 15 >> 31 << 14) | ((sdram->emc_pmacro_ddll_periodic_offset << 16 >> 31 << 13) | ((sdram->emc_pmacro_ddll_periodic_offset << 17 >> 31 << 12) | ((sdram->emc_pmacro_ddll_periodic_offset << 18 >> 31 << 11) | ((sdram->emc_pmacro_ddll_periodic_offset << 19 >> 31 << 10) | ((sdram->emc_pmacro_ddll_periodic_offset << 20 >> 31 << 9) | ((sdram->emc_pmacro_ddll_periodic_offset << 21 >> 31 << 8) | ((sdram->emc_pmacro_ddll_periodic_offset << 22 >> 31 << 7) | ((sdram->emc_pmacro_ddll_periodic_offset << 23 >> 31 << 6) | (sdram->emc_pmacro_ddll_periodic_offset & 0x3F | (pmc->scratch106 >> 6 << 6)) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + pmc->scratch107 = (8 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_clken_override << 15 >> 31 << 30) | ((sdram->emc_clken_override << 23 >> 31 << 29) | ((sdram->emc_clken_override << 24 >> 31 << 28) | ((sdram->emc_clken_override << 25 >> 31 << 27) | ((sdram->emc_clken_override << 28 >> 31 << 26) | ((sdram->emc_clken_override << 29 >> 31 << 25) | ((sdram->emc_clken_override << 30 >> 31 << 24) | ((sdram->mc_emem_arb_da_covers << 8 >> 24 << 16) | ((sdram->mc_emem_arb_da_covers << 16 >> 24 << 8) | (sdram->mc_emem_arb_da_covers & 0xFF | (pmc->scratch107 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch108 = (sdram->emc_rfc_pb << 23) | ((sdram->emc_xm2_comp_pad_ctrl >> 24 << 15) | ((sdram->emc_xm2_comp_pad_ctrl << 12 >> 24 << 7) | ((sdram->emc_xm2_comp_pad_ctrl << 20 >> 31 << 6) | (32 * (sdram->emc_xm2_comp_pad_ctrl << 22 >> 31) | (4 * (sdram->emc_xm2_comp_pad_ctrl << 25 >> 29) | (sdram->emc_xm2_comp_pad_ctrl & 3 | 4 * (pmc->scratch108 >> 2)) & 0xFFFFFFE3) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFF807F) & 0xFF807FFF) & 0x7FFFFF; + pmc->scratch109 = (sdram->emc_cfg_update >> 31 << 31) | (2 * ((2 * sdram->emc_cfg_update >> 31 << 30) | ((4 * sdram->emc_cfg_update >> 31 << 29) | ((8 * sdram->emc_cfg_update >> 31 << 28) | ((sdram->emc_cfg_update << 21 >> 30 << 26) | ((sdram->emc_cfg_update << 23 >> 31 << 25) | ((sdram->emc_cfg_update << 29 >> 30 << 23) | ((sdram->emc_cfg_update << 22) & 0x7FFFFF | ((sdram->emc_auto_cal_config3 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config3 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config3 << 17 >> 25 << 7) | ((pmc->scratch109 >> 7 << 7) | sdram->emc_auto_cal_config3 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFE7FFFFF) & 0xFDFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch110 = (sdram->emc_rfc << 22) | ((sdram->emc_auto_cal_config4 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config4 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config4 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config4 & 0x7F | (pmc->scratch110 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; + pmc->scratch111 = ((u16)(sdram->emc_txsr) << 22) | ((sdram->emc_auto_cal_config5 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config5 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config5 << 17 >> 25 << 7) | ((pmc->scratch111 >> 7 << 7) | sdram->emc_auto_cal_config5 & 0x7F) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0x3FFFFF; + pmc->scratch112 = (16 * sdram->emc_mc2emc_q >> 28 << 28) | ((sdram->emc_mc2emc_q << 21 >> 29 << 25) | ((sdram->emc_mc2emc_q << 22) & 0x1FFFFFF | ((sdram->emc_auto_cal_config6 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config6 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config6 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config6 & 0x7F | (pmc->scratch112 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xFFFFFFF; + pmc->scratch113 = (sdram->mc_emem_arb_ring1_throttle << 11 >> 27 << 27) | ((sdram->mc_emem_arb_ring1_throttle << 22) | ((sdram->emc_auto_cal_config7 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config7 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config7 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config7 & 0x7F | (pmc->scratch113 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xF83FFFFF) & 0x7FFFFFF; + pmc->scratch114 = (sdram->emc_auto_cal_config8 << 8 >> 28 << 18) | ((sdram->emc_auto_cal_config8 << 12 >> 28 << 14) | ((sdram->emc_auto_cal_config8 << 17 >> 25 << 7) | (sdram->emc_auto_cal_config8 & 0x7F | (pmc->scratch114 >> 7 << 7)) & 0xFFFFC07F) & 0xFFFC3FFF) & 0xFFC3FFFF; + pmc->scratch115 = (4 * sdram->emc_cfg >> 31 << 31) | (2 * (((u16)(sdram->emc_ar2pden) << 22) | ((sdram->emc_fbio_cfg7 << 10 >> 30 << 20) | ((sdram->emc_fbio_cfg7 << 12 >> 31 << 19) | ((sdram->emc_fbio_cfg7 << 13 >> 31 << 18) | ((sdram->emc_fbio_cfg7 << 14 >> 31 << 17) | ((sdram->emc_fbio_cfg7 << 15 >> 31 << 16) | ((sdram->emc_fbio_cfg7 << 16 >> 31 << 15) | ((sdram->emc_fbio_cfg7 << 17 >> 31 << 14) | ((sdram->emc_fbio_cfg7 << 18 >> 31 << 13) | ((sdram->emc_fbio_cfg7 << 19 >> 31 << 12) | ((sdram->emc_fbio_cfg7 << 20 >> 31 << 11) | ((sdram->emc_fbio_cfg7 << 21 >> 31 << 10) | ((sdram->emc_fbio_cfg7 << 22 >> 31 << 9) | ((sdram->emc_fbio_cfg7 << 23 >> 31 << 8) | ((sdram->emc_fbio_cfg7 << 24 >> 31 << 7) | ((sdram->emc_fbio_cfg7 << 25 >> 31 << 6) | (32 * (sdram->emc_fbio_cfg7 << 26 >> 31) | (16 * (sdram->emc_fbio_cfg7 << 27 >> 31) | (8 * (sdram->emc_fbio_cfg7 << 28 >> 31) | (4 * (sdram->emc_fbio_cfg7 << 29 >> 31) | (2 * (sdram->emc_fbio_cfg7 << 30 >> 31) | (sdram->emc_fbio_cfg7 & 1 | 2 * (pmc->scratch115 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFCFFFFF) & 0x803FFFFF) >> 1); + pmc->scratch123 = (2 * sdram->emc_cfg >> 31 << 31) | (2 * ((sdram->emc_rfc_slr << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_0 & 0x7FF | (pmc->scratch123 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); + pmc->scratch124 = (sdram->emc_cfg >> 31 << 31) | (2 * ((4 * sdram->emc_ibdly >> 30 << 29) | ((sdram->emc_ibdly << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_1 & 0x7FF | (pmc->scratch124 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch125 = (sdram->emc_fbio_cfg5 << 27 >> 31 << 31) | (2 * (((u16)(sdram->mc_emem_arb_timing_rfcpb) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_2 & 0x7FF | (pmc->scratch125 >> 11 << 11)) & 0xFFC007FF) & 0x803FFFFF) >> 1); + pmc->scratch126 = (sdram->emc_fbio_cfg5 << 16 >> 29 << 29) | ((sdram->emc_auto_cal_config9 << 25 >> 31 << 28) | ((sdram->emc_auto_cal_config9 << 26 >> 31 << 27) | ((sdram->emc_auto_cal_config9 << 27 >> 31 << 26) | ((sdram->emc_auto_cal_config9 << 28 >> 31 << 25) | ((sdram->emc_auto_cal_config9 << 29 >> 31 << 24) | ((sdram->emc_auto_cal_config9 << 30 >> 31 << 23) | ((sdram->emc_auto_cal_config9 << 22) & 0x7FFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_3 & 0x7FF | (pmc->scratch126 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch127 = ((u8)(sdram->emc_cfg2) << 26 >> 29 << 29) | ((sdram->emc_rdv_mask << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_4 & 0x7FF | (pmc->scratch127 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch128 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 27 >> 29 << 29) | (((u8)(sdram->emc_rdv_early_mask) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank0_5 & 0x7FF | (pmc->scratch128 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch129 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_rdv_early << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_0 & 0x7FF | (pmc->scratch129 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch130 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 17 >> 29 << 29) | ((4 * sdram->emc_quse_width >> 31 << 28) | ((8 * sdram->emc_quse_width >> 31 << 27) | ((sdram->emc_quse_width << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_1 & 0x7FF | (pmc->scratch130 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch131 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 12 >> 29 << 29) | (((u16)(sdram->emc_pmacro_ddll_short_cmd_2) << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_2 & 0x7FF | (pmc->scratch131 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch132 = (sdram->emc_pmacro_data_pad_tx_ctrl << 27 >> 29 << 29) | ((sdram->emc_pmacro_cmd_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_cmd_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_cmd_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_3 & 0x7FF | (pmc->scratch132 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch133 = (sdram->emc_pmacro_data_pad_tx_ctrl << 22 >> 29 << 29) | ((sdram->emc_pmacro_data_rx_term_mode << 18 >> 31 << 28) | ((sdram->emc_pmacro_data_rx_term_mode << 22 >> 30 << 26) | ((sdram->emc_pmacro_data_rx_term_mode << 26 >> 30 << 24) | ((sdram->emc_pmacro_data_rx_term_mode << 22) & 0xFFFFFF | ((32 * sdram->emc_pmacro_quse_ddll_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_4 & 0x7FF | (pmc->scratch133 >> 11 << 11)) & 0xFFC007FF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xEFFFFFFF) & 0x1FFFFFFF; + pmc->scratch134 = (sdram->emc_pmacro_data_pad_tx_ctrl << 17 >> 29 << 29) | ((sdram->mc_emem_arb_timing_rp << 22) | ((32 * sdram->emc_pmacro_quse_ddll_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_quse_ddll_rank1_5 & 0x7FF | (pmc->scratch134 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch135 = (sdram->emc_pmacro_data_pad_tx_ctrl << 12 >> 29 << 29) | ((sdram->mc_emem_arb_timing_ras << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_0 & 0x7FF | (pmc->scratch135 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x1FFFFFFF; + pmc->scratch136 = (sdram->emc_fbio_cfg5 << 23 >> 31 << 31) | (2 * ((sdram->emc_cfg << 14 >> 30 << 29) | ((sdram->mc_emem_arb_timing_faw << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_1 & 0x7FF | (pmc->scratch136 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch137 = (sdram->emc_fbio_cfg5 << 21 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 29) | ((sdram->mc_emem_arb_timing_rap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_2 & 0x7FF | (pmc->scratch137 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch138 = (sdram->emc_fbio_cfg5 << 19 >> 31 << 31) | (2 * ((sdram->emc_fbio_cfg5 << 28 >> 30 << 29) | ((sdram->mc_emem_arb_timing_wap2pre << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_3 & 0x7FF | (pmc->scratch138 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch139 = (sdram->emc_fbio_cfg5 << 7 >> 31 << 31) | (2 * ((16 * sdram->emc_cfg2 >> 30 << 29) | (((u8)(sdram->mc_emem_arb_timing_r2w) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_4 & 0x7FF | (pmc->scratch139 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0x9FFFFFFF) >> 1); + pmc->scratch140 = (16 * sdram->emc_fbio_cfg5 >> 31 << 31) | (2 * ((32 * sdram->emc_fbio_cfg5 >> 31 << 30) | ((sdram->emc_fbio_cfg5 << 6 >> 31 << 29) | (((u8)(sdram->mc_emem_arb_timing_w2r) << 22) & 0x1FFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank0_5 & 0x7FF | (pmc->scratch140 >> 11 << 11)) & 0xFFC007FF) & 0xE03FFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch141 = (sdram->emc_fbio_cfg5 << 8 >> 28 << 28) | (((u16)(sdram->emc_wdv) << 22) | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_0 & 0x7FF | (pmc->scratch141 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xFFFFFFF; + pmc->scratch142 = ((u8)(sdram->emc_cfg2) << 31) | (2 * ((sdram->emc_fbio_cfg5 >> 31 << 30) | ((2 * sdram->emc_fbio_cfg5 >> 31 << 29) | ((8 * sdram->emc_fbio_cfg5 >> 31 << 28) | ((sdram->emc_quse << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_1 & 0x7FF | (pmc->scratch142 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch143 = (((u16)(sdram->emc_cfg2) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg2) << 24) >> 31 << 30) | ((((u16)(sdram->emc_cfg2) << 29) >> 31 << 29) | ((((u16)(sdram->emc_cfg2) << 30) >> 31 << 28) | (((u8)(sdram->emc_pdex2wr) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_2 & 0x7FF | (pmc->scratch143 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch144 = (sdram->emc_cfg2 << 15 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 16 >> 31 << 30) | ((sdram->emc_cfg2 << 17 >> 31 << 29) | ((sdram->emc_cfg2 << 20 >> 31 << 28) | (((u8)(sdram->emc_pdex2rd) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_3 & 0x7FF | (pmc->scratch144 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch145 = (sdram->emc_cfg2 << 7 >> 31 << 31) | (2 * ((sdram->emc_cfg2 << 8 >> 31 << 30) | ((sdram->emc_cfg2 << 9 >> 31 << 29) | ((sdram->emc_cfg2 << 11 >> 31 << 28) | (((u16)(sdram->emc_pdex2che) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_4 & 0x7FF | (pmc->scratch145 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch146 = (2 * sdram->emc_cfg2 >> 31 << 31) | (2 * ((4 * sdram->emc_cfg2 >> 31 << 30) | (((sdram->emc_cfg2 << 6 >> 31 << 28) | (((u8)(sdram->emc_pchg2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dq_rank1_5 & 0x7FF | (pmc->scratch146 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (8 * sdram->emc_cfg2 >> 31 << 29)) & 0xBFFFFFFF) >> 1); + pmc->scratch147 = (((u8)(sdram->emc_cfg_pipe) << 29) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 30) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 31) >> 2) | ((sdram->emc_cfg2 >> 31 << 28) | (((u16)(sdram->emc_act2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch147 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch148 = (((u8)(sdram->emc_cfg_pipe) << 25) >> 31 << 31) | (2 * ((((u8)(sdram->emc_cfg_pipe) << 26) >> 31 << 30) | ((((u8)(sdram->emc_cfg_pipe) << 27) >> 31 << 29) | ((((u8)(sdram->emc_cfg_pipe) << 28) >> 31 << 28) | (((u16)(sdram->emc_cke2pden) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch148 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch149 = (((u16)(sdram->emc_cfg_pipe) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_cfg_pipe) << 22) >> 31 << 30) | ((((u16)(sdram->emc_cfg_pipe) << 23) >> 31 << 29) | ((((u16)(sdram->emc_cfg_pipe) << 24) >> 31 << 28) | ((sdram->emc_tcke << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch149 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch150 = (sdram->emc_cfg_pipe << 13 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 14 >> 31 << 30) | (((sdram->emc_cfg_pipe << 20 >> 31 << 28) | ((sdram->emc_trpab << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch150 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (sdram->emc_cfg_pipe << 15 >> 31 << 29)) & 0xBFFFFFFF) >> 1); + pmc->scratch151 = (sdram->emc_cfg_pipe << 9 >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 10 >> 31 << 30) | ((sdram->emc_cfg_pipe << 11 >> 31 << 29) | ((sdram->emc_cfg_pipe << 12 >> 31 << 28) | ((sdram->emc_einput << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_4 & 0x7FF | (pmc->scratch151 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch152 = (32 * sdram->emc_cfg_pipe >> 31 << 31) | (2 * ((sdram->emc_cfg_pipe << 6 >> 31 << 30) | ((sdram->emc_cfg_pipe << 7 >> 31 << 29) | ((sdram->emc_cfg_pipe << 8 >> 31 << 28) | ((sdram->emc_einput_duration << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank0_5 & 0x7FF | (pmc->scratch152 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch153 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 31) >> 2) | ((16 * sdram->emc_cfg_pipe >> 31 << 28) | ((sdram->emc_puterm_extra << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch153 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch154 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 26) >> 31 << 30) | (((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 28) >> 31 << 28) | ((sdram->emc_tckesr << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch154 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF | (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 27) >> 31 << 29)) & 0xBFFFFFFF) >> 1); + pmc->scratch155 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src0) << 24) >> 31 << 28) | ((sdram->emc_tpd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch155 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch156 = (sdram->emc_pmacro_tx_sel_clk_src0 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 15 >> 31 << 28) | ((sdram->emc_wdv_mask << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch156 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch157 = (sdram->emc_pmacro_tx_sel_clk_src0 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src0 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 11 >> 31 << 28) | (((u16)(sdram->emc_wdv_chk) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_4 & 0x7FF | (pmc->scratch157 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch158 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src0 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src0 << 7 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft0) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft0) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 >> 21 << 11) | (sdram->emc_pmacro_ob_ddll_long_dqs_rank1_5 & 0x7FF | (pmc->scratch158 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch159 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 27) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 28) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 29) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 30) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft1) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft1) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_0 & 0x7FF | (pmc->scratch159 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch160 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 23) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 24) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 25) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src1) << 26) >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft2) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft2) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_1 & 0x7FF | (pmc->scratch160 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch161 = (sdram->emc_pmacro_tx_sel_clk_src1 << 14 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 15 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 21 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 22 >> 31 << 28) | (((u8)(sdram->emc_cmd_brlshft3) << 26 >> 29 << 25) | (((u8)(sdram->emc_cmd_brlshft3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_2 & 0x7FF | (pmc->scratch161 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch162 = (sdram->emc_pmacro_tx_sel_clk_src1 << 10 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 11 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 12 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 13 >> 31 << 28) | (((u16)(sdram->emc_wev) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank0_3 & 0x7FF | (pmc->scratch162 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch163 = (sdram->emc_pmacro_tx_sel_clk_src1 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src1 << 7 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 8 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src1 << 9 >> 31 << 28) | (((u16)(sdram->emc_wsv) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_0 & 0x7FF | (pmc->scratch163 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch164 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 29) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 30) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 31) >> 2) | ((32 * sdram->emc_pmacro_tx_sel_clk_src1 >> 31 << 28) | (((u8)(sdram->emc_cfg3) << 25 >> 29 << 25) | (((u8)(sdram->emc_cfg3) << 22) & 0x1FFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_1 & 0x7FF | (pmc->scratch164 >> 11 << 11)) & 0xFFC007FF) & 0xFE3FFFFF) & 0xF1FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch165 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 25) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 26) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 27) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 28) >> 31 << 28) | ((sdram->emc_puterm_width << 23) & 0xFFFFFFF | ((sdram->emc_puterm_width >> 31 << 22) | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_2 & 0x7FF | (pmc->scratch165 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xF07FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch166 = (((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 21) >> 31 << 31) | (2 * ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 22) >> 31 << 30) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 23) >> 31 << 29) | ((((u16)(sdram->emc_pmacro_tx_sel_clk_src3) << 24) >> 31 << 28) | ((sdram->mc_emem_arb_timing_rcd << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 >> 21 << 11) | (sdram->emc_pmacro_ib_ddll_long_dqs_rank1_3 & 0x7FF | (pmc->scratch166 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch167 = (sdram->emc_pmacro_tx_sel_clk_src3 << 12 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 13 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 14 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 15 >> 31 << 28) | (((u16)(sdram->mc_emem_arb_timing_ccdmw) << 22) & 0xFFFFFFF | ((32 * sdram->emc_pmacro_ddll_long_cmd_0 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_0 & 0x7FF | (pmc->scratch167 >> 11 << 11)) & 0xFFC007FF) & 0xF03FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch168 = (sdram->emc_pmacro_tx_sel_clk_src3 << 8 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src3 << 9 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 10 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 11 >> 31 << 28) | ((sdram->mc_emem_arb_override << 28 >> 31 << 27) | (((sdram->mc_emem_arb_override << 21 >> 31 << 25) | ((sdram->mc_emem_arb_override << 15 >> 31 << 24) | ((32 * sdram->mc_emem_arb_override >> 31 << 23) | ((16 * sdram->mc_emem_arb_override >> 31 << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_1 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_1 & 0x7FF | (pmc->scratch168 >> 11 << 11)) & 0xFFC007FF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF | (sdram->mc_emem_arb_override << 27 >> 31 << 26)) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch169 = ((u16)(sdram->emc_rext) << 27) | (((u16)(sdram->emc_rrd) << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_2 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_2 & 0x7FF | (pmc->scratch169 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; + pmc->scratch170 = ((u16)(sdram->emc_wext) << 27) | ((sdram->emc_tclkstop << 22) | ((32 * sdram->emc_pmacro_ddll_long_cmd_3 >> 21 << 11) | (sdram->emc_pmacro_ddll_long_cmd_3 & 0x7FF | (pmc->scratch170 >> 11 << 11)) & 0xFFC007FF) & 0xF83FFFFF) & 0x7FFFFFF; + tmp = (32 * sdram->emc_pmacro_perbit_fgcg_ctrl0 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl0 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl0 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl0 & 1 | 2 * (pmc->scratch171 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF; + pmc->scratch171 = (sdram->emc_we_duration << 27) | ((sdram->emc_ref_ctrl2 >> 31 << 26) | ((32 * sdram->emc_ref_ctrl2 >> 29 << 23) | ((sdram->emc_ref_ctrl2 << 22) & 0x7FFFFF | tmp & 0xFFBFFFFF) & 0xFC7FFFFF) & 0xFBFFFFFF) & 0x7FFFFFF; + tmp = (sdram->emc_pmacro_pad_cfg_ctrl << 22 >> 31 << 28) | ((sdram->emc_pmacro_pad_cfg_ctrl << 27) & 0xFFFFFFF | ((sdram->emc_ws_duration << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl1 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl1 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl1 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl1 & 1 | 2 * (pmc->scratch172 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; + pmc->scratch172 = (sdram->emc_pmacro_pad_cfg_ctrl << 14 >> 30 << 30) | (4 * ((sdram->emc_pmacro_pad_cfg_ctrl << 18 >> 31 << 29) | tmp & 0xDFFFFFFF) >> 2); + pmc->scratch173 = ((u8)(sdram->mc_emem_arb_timing_r2r) << 27) | ((sdram->mc_emem_arb_timing_rrd << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl2 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl2 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl2 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl2 & 1 | 2 * (pmc->scratch173 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0x7FFFFFF; + tmp = 32 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl3 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl3 & 1 | 2 * (pmc->scratch174 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; + pmc->scratch174 = ((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30 >> 31 << 31) | (2 * (((u16)(sdram->emc_pmacro_tx_sel_clk_src2) << 30) | ((32 * sdram->emc_pmacro_tx_sel_clk_src3 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 6 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src3 << 7 >> 31 << 27) | (((u8)(sdram->mc_emem_arb_timing_w2w) << 22) & 0x7FFFFFF | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl3 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl3 << 25 >> 31 << 6) | tmp & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xF83FFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 28 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 29 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl4 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl4 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl4 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl4 & 1 | 2 * (pmc->scratch175 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF; + pmc->scratch175 = (sdram->emc_pmacro_tx_sel_clk_src2 << 15 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 21 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 22 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 23 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 24 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 25 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 26 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 27 >> 31 << 24) | tmp & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + tmp = (sdram->emc_pmacro_tx_sel_clk_src2 << 12 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 13 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 14 >> 31 << 22) | ((32 * sdram->emc_pmacro_perbit_fgcg_ctrl5 >> 31 << 21) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 6 >> 31 << 20) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 7 >> 31 << 19) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 8 >> 31 << 18) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 9 >> 31 << 17) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 10 >> 31 << 16) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 11 >> 31 << 15) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 12 >> 31 << 14) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 13 >> 31 << 13) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 14 >> 31 << 12) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 15 >> 31 << 11) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 21 >> 31 << 10) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 22 >> 31 << 9) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 23 >> 31 << 8) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 24 >> 31 << 7) | ((sdram->emc_pmacro_perbit_fgcg_ctrl5 << 25 >> 31 << 6) | (32 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 26 >> 31) | (16 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 27 >> 31) | (8 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 28 >> 31) | (4 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 29 >> 31) | (2 * (sdram->emc_pmacro_perbit_fgcg_ctrl5 << 30 >> 31) | (sdram->emc_pmacro_perbit_fgcg_ctrl5 & 1 | 2 * (pmc->scratch176 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; + pmc->scratch176 = (32 * sdram->emc_pmacro_tx_sel_clk_src2 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src2 << 6 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 8 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 9 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 10 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src2 << 11 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch177 = (sdram->emc_pmacro_tx_sel_clk_src4 << 22 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 23 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 24 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 25 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 26 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 27 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 28 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 29 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 30 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 22) & 0x7FFFFF | ((sdram->mc_emem_arb_cfg >> 28 << 18) | ((16 * sdram->mc_emem_arb_cfg >> 28 << 14) | ((sdram->mc_emem_arb_cfg << 11 >> 27 << 9) | (sdram->mc_emem_arb_cfg & 0x1FF | (pmc->scratch177 >> 9 << 9)) & 0xFFFFC1FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch178 = (sdram->emc_pmacro_tx_sel_clk_src4 << 7 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src4 << 8 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 9 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 10 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 11 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 12 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 13 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 14 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 15 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src4 << 21 >> 31 << 22) | ((sdram->mc_emem_arb_misc1 >> 28 << 18) | ((sdram->mc_emem_arb_misc1 << 6 >> 30 << 16) | ((sdram->mc_emem_arb_misc1 << 8 >> 29 << 13) | (16 * (sdram->mc_emem_arb_misc1 << 19 >> 23) | (8 * (sdram->mc_emem_arb_misc1 << 28 >> 31) | (4 * (sdram->mc_emem_arb_misc1 << 29 >> 31) | (2 * (sdram->mc_emem_arb_misc1 << 30 >> 31) | (sdram->mc_emem_arb_misc1 & 1 | 2 * (pmc->scratch178 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFE00F) & 0xFFFF1FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch179 = (sdram->emc_odt_write >> 31 << 31) | (2 * ((sdram->emc_odt_write << 20 >> 28 << 27) | ((sdram->emc_odt_write << 26 >> 31 << 26) | ((sdram->emc_odt_write << 27 >> 31 << 25) | ((sdram->emc_odt_write << 21) & 0x1FFFFFF | ((32 * sdram->emc_mrs_wait_cnt2 >> 21 << 10) | (sdram->emc_mrs_wait_cnt2 & 0x3FF | (pmc->scratch179 >> 10 << 10)) & 0xFFE003FF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); + pmc->scratch180 = (sdram->emc_pmacro_ib_rxrt << 21) | ((32 * sdram->emc_mrs_wait_cnt >> 21 << 10) | (sdram->emc_mrs_wait_cnt & 0x3FF | (pmc->scratch180 >> 10 << 10)) & 0xFFE003FF) & 0x1FFFFF; + pmc->scratch181 = ((u16)(sdram->emc_pmacro_ddll_long_cmd_4) << 21) | sdram->emc_auto_cal_interval & 0x1FFFFF; + pmc->scratch182 = (sdram->mc_emem_arb_outstanding_req >> 31 << 31) | (2 * ((2 * sdram->mc_emem_arb_outstanding_req >> 31 << 30) | ((sdram->mc_emem_arb_outstanding_req << 23 >> 2) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 9 >> 25 << 14) | ((sdram->emc_emem_arb_refpb_hp_ctrl << 17 >> 25 << 7) | (sdram->emc_emem_arb_refpb_hp_ctrl & 0x7F | (pmc->scratch182 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xC01FFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch183 = (4 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl0 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl0 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl0 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl0 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl0 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl0 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl0 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl0 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl0 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl0 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl0 << 20) & 0x1FFFFF | ((4 * sdram->emc_xm2_comp_pad_ctrl2 >> 26 << 14) | ((sdram->emc_xm2_comp_pad_ctrl2 << 10 >> 30 << 12) | ((sdram->emc_xm2_comp_pad_ctrl2 << 14 >> 31 << 11) | ((sdram->emc_xm2_comp_pad_ctrl2 << 15 >> 31 << 10) | ((sdram->emc_xm2_comp_pad_ctrl2 << 16 >> 30 << 8) | ((sdram->emc_xm2_comp_pad_ctrl2 << 18 >> 30 << 6) | (4 * (sdram->emc_xm2_comp_pad_ctrl2 << 26 >> 28) | (sdram->emc_xm2_comp_pad_ctrl2 & 3 | 4 * (pmc->scratch183 >> 2)) & 0xFFFFFFC3) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFF03FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch184 = (4 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl1 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl1 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl1 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl1 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl1 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl1 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl1 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl1 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl1 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl1 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl1 << 20) & 0x1FFFFF | ((sdram->emc_cfg_dig_dll_1 << 12 >> 28 << 16) | ((sdram->emc_cfg_dig_dll_1 << 16 >> 28 << 12) | ((sdram->emc_cfg_dig_dll_1 << 20 >> 26 << 6) | (2 * (sdram->emc_cfg_dig_dll_1 << 26 >> 27) | (sdram->emc_cfg_dig_dll_1 & 1 | 2 * (pmc->scratch184 >> 1)) & 0xFFFFFFC1) & 0xFFFFF03F) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch185 = (4 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 31) | (2 * ((8 * sdram->emc_pmacro_cmd_ctrl2 >> 31 << 30) | ((sdram->emc_pmacro_cmd_ctrl2 << 7 >> 31 << 29) | ((sdram->emc_pmacro_cmd_ctrl2 << 10 >> 31 << 28) | ((sdram->emc_pmacro_cmd_ctrl2 << 11 >> 31 << 27) | ((sdram->emc_pmacro_cmd_ctrl2 << 15 >> 31 << 26) | ((sdram->emc_pmacro_cmd_ctrl2 << 18 >> 31 << 25) | ((sdram->emc_pmacro_cmd_ctrl2 << 19 >> 31 << 24) | ((sdram->emc_pmacro_cmd_ctrl2 << 23 >> 31 << 23) | ((sdram->emc_pmacro_cmd_ctrl2 << 26 >> 31 << 22) | ((sdram->emc_pmacro_cmd_ctrl2 << 27 >> 31 << 21) | ((sdram->emc_pmacro_cmd_ctrl2 << 20) & 0x1FFFFF | ((sdram->emc_quse_brlshft0 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft0 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft0 << 22 >> 27) | (sdram->emc_quse_brlshft0 & 0x1F | 32 * (pmc->scratch185 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch186 = (sdram->emc_pmacro_dsr_vttgen_ctrl0 >> 8 << 24) | ((sdram->emc_pmacro_dsr_vttgen_ctrl0 << 20) | ((sdram->emc_quse_brlshft1 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft1 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft1 << 22 >> 27) | (sdram->emc_quse_brlshft1 & 0x1F | 32 * (pmc->scratch186 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFF0FFFFF) & 0xFFFFFF; + pmc->scratch187 = (sdram->emc_pmacro_perbit_rfu1_ctrl0 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl0 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft2 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft2 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft2 << 22 >> 27) | (sdram->emc_quse_brlshft2 & 0x1F | 32 * (pmc->scratch187 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch188 = (sdram->emc_pmacro_perbit_rfu1_ctrl1 << 10 >> 30 << 30) | (4 * ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 12 >> 30 << 28) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 14 >> 30 << 26) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 26 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 28 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl1 << 20) & 0x3FFFFF | ((sdram->emc_quse_brlshft3 << 12 >> 27 << 15) | ((sdram->emc_quse_brlshft3 << 17 >> 27 << 10) | (32 * (sdram->emc_quse_brlshft3 << 22 >> 27) | (sdram->emc_quse_brlshft3 & 0x1F | 32 * (pmc->scratch188 >> 5)) & 0xFFFFFC1F) & 0xFFFF83FF) & 0xFFF07FFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF) & 0xCFFFFFFF) >> 2); + pmc->scratch189 = (sdram->emc_trefbw << 18) | ((sdram->emc_dbg >> 31 << 17) | ((2 * sdram->emc_dbg >> 31 << 16) | ((4 * sdram->emc_dbg >> 31 << 15) | ((8 * sdram->emc_dbg >> 31 << 14) | ((16 * sdram->emc_dbg >> 30 << 12) | ((sdram->emc_dbg << 6 >> 31 << 11) | ((sdram->emc_dbg << 7 >> 31 << 10) | ((sdram->emc_dbg << 18 >> 31 << 9) | ((sdram->emc_dbg << 19 >> 31 << 8) | ((sdram->emc_dbg << 20 >> 31 << 7) | ((sdram->emc_dbg << 21 >> 31 << 6) | (32 * (sdram->emc_dbg << 22 >> 31) | (16 * (sdram->emc_dbg << 27 >> 31) | (8 * (sdram->emc_dbg << 28 >> 31) | (4 * (sdram->emc_dbg << 29 >> 31) | (2 * (sdram->emc_dbg << 30 >> 31) | (sdram->emc_dbg & 1 | 2 * (pmc->scratch189 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFCFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0x3FFFF; + pmc->scratch191 = (sdram->emc_qpop << 9 >> 25 << 25) | ((sdram->emc_qpop << 18) | ((sdram->emc_zcal_wait_cnt >> 31 << 17) | ((sdram->emc_zcal_wait_cnt << 10 >> 26 << 11) | (sdram->emc_zcal_wait_cnt & 0x7FF | (pmc->scratch191 >> 11 << 11)) & 0xFFFE07FF) & 0xFFFDFFFF) & 0xFE03FFFF) & 0x1FFFFFF; + pmc->scratch192 = (sdram->emc_pmacro_tx_sel_clk_src4 << 6 >> 31 << 31) | (2 * ((sdram->emc_pmacro_auto_cal_common << 15 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_common << 18 >> 26 << 24) | ((sdram->emc_pmacro_auto_cal_common << 18) & 0xFFFFFF | ((sdram->emc_zcal_mrw_cmd >> 30 << 16) | ((sdram->emc_zcal_mrw_cmd << 8 >> 24 << 8) | (sdram->emc_zcal_mrw_cmd & 0xFF | (pmc->scratch192 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFCFFFF) & 0xFF03FFFF) & 0xC0FFFFFF) & 0xBFFFFFFF) >> 1); + tmp = (sdram->emc_dll_cfg1 << 7 >> 31 << 17) | ((sdram->emc_dll_cfg1 << 10 >> 31 << 16) | ((sdram->emc_dll_cfg1 << 11 >> 31 << 15) | ((sdram->emc_dll_cfg1 << 14 >> 30 << 13) | ((sdram->emc_dll_cfg1 << 18 >> 31 << 12) | ((sdram->emc_dll_cfg1 << 19 >> 31 << 11) | ((pmc->scratch193 >> 11 << 11) | sdram->emc_dll_cfg1 & 0x7FF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFF9FFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF; + pmc->scratch193 = (sdram->emc_pmacro_tx_sel_clk_src5 << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src4 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl2 << 18) & 0xFFFFF | tmp & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl2 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch194 = (sdram->emc_pmacro_tx_sel_clk_src5 << 29 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 30 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 14 >> 30 << 24) | (((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl3 << 18) & 0xFFFFF | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_cmd_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_cmd_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch194 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 26 >> 30 << 22)) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl3 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch195 = (sdram->emc_pmacro_tx_sel_clk_src5 << 27 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 28 >> 31 << 30) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 10 >> 30 << 28) | (((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 14 >> 30 << 24) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 26 >> 30 << 22) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 28 >> 30 << 20) | ((sdram->emc_pmacro_perbit_rfu1_ctrl4 << 18) & 0xFFFFF | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 14 >> 30 << 16) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 16 >> 30 << 14) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 18 >> 30 << 12) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 20 >> 30 << 10) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 22 >> 30 << 8) | ((sdram->emc_pmacro_data_brick_ctrl_fdpd << 24 >> 30 << 6) | (16 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 26 >> 30) | (4 * (sdram->emc_pmacro_data_brick_ctrl_fdpd << 28 >> 30) | (sdram->emc_pmacro_data_brick_ctrl_fdpd & 3 | 4 * (pmc->scratch195 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFCF) & 0xFFFFFF3F) & 0xFFFFFCFF) & 0xFFFFF3FF) & 0xFFFFCFFF) & 0xFFFF3FFF) & 0xFFFCFFFF) & 0xFFF3FFFF) & 0xFFCFFFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xF3FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl4 << 12 >> 30 << 26)) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch196 = (sdram->emc_emem_arb_refpb_bank_ctrl >> 31 << 31) | (2 * ((sdram->emc_emem_arb_refpb_bank_ctrl << 17 >> 25 << 24) | ((sdram->emc_emem_arb_refpb_bank_ctrl << 17) & 0xFFFFFF | ((sdram->emc_dyn_self_ref_control >> 31 << 16) | (sdram->emc_dyn_self_ref_control & 0xFFFF | (pmc->scratch196 >> 16 << 16)) & 0xFFFEFFFF) & 0xFF01FFFF) & 0x80FFFFFF) >> 1); + pmc->scratch197 = (sdram->emc_pmacro_tx_sel_clk_src5 << 24 >> 31 << 31) | (2 * ((sdram->emc_pmacro_tx_sel_clk_src5 << 25 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 26 >> 31 << 29) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 10 >> 30 << 27) | (((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 14 >> 30 << 23) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 26 >> 30 << 21) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 28 >> 30 << 19) | ((sdram->emc_pmacro_perbit_rfu1_ctrl5 << 17) & 0x7FFFF | ((16 * sdram->emc_pmacro_cmd_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_cmd_pad_rx_ctrl & 3 | 4 * (pmc->scratch197 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFF9FFFF) & 0xFFE7FFFF) & 0xFF9FFFFF) & 0xFE7FFFFF) & 0xF9FFFFFF | (sdram->emc_pmacro_perbit_rfu1_ctrl5 << 12 >> 30 << 25)) & 0xE7FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch198 = (sdram->emc_pmacro_cmd_pad_tx_ctrl << 31) | (2 * ((32 * sdram->emc_pmacro_tx_sel_clk_src5 >> 31 << 30) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 6 >> 31 << 29) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 7 >> 31 << 28) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 8 >> 31 << 27) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 9 >> 31 << 26) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 10 >> 31 << 25) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 11 >> 31 << 24) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 12 >> 31 << 23) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 13 >> 31 << 22) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 14 >> 31 << 21) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 15 >> 31 << 20) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 21 >> 31 << 19) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 22 >> 31 << 18) | ((sdram->emc_pmacro_tx_sel_clk_src5 << 23 >> 31 << 17) | ((16 * sdram->emc_pmacro_data_pad_rx_ctrl >> 28 << 13) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 8 >> 31 << 12) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 9 >> 31 << 11) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 10 >> 31 << 10) | ((sdram->emc_pmacro_data_pad_rx_ctrl << 12 >> 28 << 6) | (32 * (sdram->emc_pmacro_data_pad_rx_ctrl << 16 >> 31) | (16 * (sdram->emc_pmacro_data_pad_rx_ctrl << 19 >> 31) | (4 * (sdram->emc_pmacro_data_pad_rx_ctrl << 26 >> 30) | (sdram->emc_pmacro_data_pad_rx_ctrl & 3 | 4 * (pmc->scratch198 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFC3F) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFE1FFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch199 = (8 * sdram->emc_cmd_q >> 27 << 27) | ((sdram->emc_cmd_q << 17 >> 29 << 24) | ((sdram->emc_cmd_q << 21 >> 29 << 21) | ((sdram->emc_cmd_q << 16) & 0x1FFFFF | (((u16)(sdram->emc_refresh) << 16 >> 22 << 6) | (sdram->emc_refresh & 0x3F | (pmc->scratch199 >> 6 << 6)) & 0xFFFF003F) & 0xFFE0FFFF) & 0xFF1FFFFF) & 0xF8FFFFFF) & 0x7FFFFFF; + pmc->scratch210 = (sdram->emc_auto_cal_vref_sel1 << 16 >> 31 << 31) | (2 * ((sdram->emc_auto_cal_vref_sel1 << 17 >> 25 << 24) | ((sdram->emc_auto_cal_vref_sel1 << 24 >> 31 << 23) | ((sdram->emc_auto_cal_vref_sel1 << 16) & 0x7FFFFF | (sdram->emc_acpd_control & 0xFFFF | (pmc->scratch210 >> 16 << 16)) & 0xFF80FFFF) & 0xFF7FFFFF) & 0x80FFFFFF) >> 1); + tmp = 8 * (sdram->emc_pmacro_auto_cal_cfg0 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg0 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg0 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg0 & 1 | 2 * (pmc->scratch211 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7; + tmp = (sdram->emc_pmacro_auto_cal_cfg1 << 7 >> 31 << 28) | ((sdram->emc_pmacro_auto_cal_cfg1 << 12 >> 31 << 27) | ((sdram->emc_pmacro_auto_cal_cfg1 << 13 >> 31 << 26) | ((sdram->emc_pmacro_auto_cal_cfg1 << 14 >> 31 << 25) | ((sdram->emc_pmacro_auto_cal_cfg1 << 15 >> 31 << 24) | ((sdram->emc_pmacro_auto_cal_cfg1 << 20 >> 31 << 23) | ((sdram->emc_pmacro_auto_cal_cfg1 << 21 >> 31 << 22) | ((sdram->emc_pmacro_auto_cal_cfg1 << 22 >> 31 << 21) | ((sdram->emc_pmacro_auto_cal_cfg1 << 23 >> 31 << 20) | ((sdram->emc_pmacro_auto_cal_cfg1 << 28 >> 31 << 19) | ((sdram->emc_pmacro_auto_cal_cfg1 << 29 >> 31 << 18) | ((sdram->emc_pmacro_auto_cal_cfg1 << 30 >> 31 << 17) | ((sdram->emc_pmacro_auto_cal_cfg1 << 16) & 0x1FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg0 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg0 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg0 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg0 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg0 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg0 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg0 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg0 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg0 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg0 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg0 << 23 >> 31) | tmp & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF; + pmc->scratch211 = (16 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 31) | (2 * ((32 * sdram->emc_pmacro_auto_cal_cfg1 >> 31 << 30) | ((sdram->emc_pmacro_auto_cal_cfg1 << 6 >> 31 << 29) | tmp & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->scratch212 = (sdram->emc_xm2_comp_pad_ctrl3 << 8 >> 28 << 28) | ((sdram->emc_xm2_comp_pad_ctrl3 << 14 >> 31 << 27) | ((sdram->emc_xm2_comp_pad_ctrl3 << 15 >> 31 << 26) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16 >> 30 << 24) | ((sdram->emc_xm2_comp_pad_ctrl3 << 18 >> 30 << 22) | ((sdram->emc_xm2_comp_pad_ctrl3 << 26 >> 28 << 18) | ((sdram->emc_xm2_comp_pad_ctrl3 << 16) & 0x3FFFF | ((16 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 15) | ((32 * sdram->emc_pmacro_auto_cal_cfg2 >> 31 << 14) | ((sdram->emc_pmacro_auto_cal_cfg2 << 6 >> 31 << 13) | ((sdram->emc_pmacro_auto_cal_cfg2 << 7 >> 31 << 12) | ((sdram->emc_pmacro_auto_cal_cfg2 << 12 >> 31 << 11) | ((sdram->emc_pmacro_auto_cal_cfg2 << 13 >> 31 << 10) | ((sdram->emc_pmacro_auto_cal_cfg2 << 14 >> 31 << 9) | ((sdram->emc_pmacro_auto_cal_cfg2 << 15 >> 31 << 8) | ((sdram->emc_pmacro_auto_cal_cfg2 << 20 >> 31 << 7) | ((sdram->emc_pmacro_auto_cal_cfg2 << 21 >> 31 << 6) | (32 * (sdram->emc_pmacro_auto_cal_cfg2 << 22 >> 31) | (16 * (sdram->emc_pmacro_auto_cal_cfg2 << 23 >> 31) | (8 * (sdram->emc_pmacro_auto_cal_cfg2 << 28 >> 31) | (4 * (sdram->emc_pmacro_auto_cal_cfg2 << 29 >> 31) | (2 * (sdram->emc_pmacro_auto_cal_cfg2 << 30 >> 31) | (sdram->emc_pmacro_auto_cal_cfg2 & 1 | 2 * (pmc->scratch212 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFCFFFF) & 0xFFC3FFFF) & 0xFF3FFFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xFFFFFFF; + pmc->scratch213 = ((u16)(sdram->emc_prerefresh_req_cnt) << 16) | (u16)(sdram->emc_cfg_dig_dll_period); + pmc->scratch214 = (sdram->emc_pmacro_data_pi_ctrl << 10 >> 26 << 26) | ((sdram->emc_pmacro_data_pi_ctrl << 19 >> 31 << 25) | ((sdram->emc_pmacro_data_pi_ctrl << 20 >> 28 << 21) | ((sdram->emc_pmacro_data_pi_ctrl << 27 >> 31 << 20) | ((sdram->emc_pmacro_data_pi_ctrl << 16) & 0xFFFFF | ((sdram->emc_pmacro_ddll_bypass >> 31 << 15) | ((2 * sdram->emc_pmacro_ddll_bypass >> 31 << 14) | ((4 * sdram->emc_pmacro_ddll_bypass >> 31 << 13) | ((16 * sdram->emc_pmacro_ddll_bypass >> 31 << 12) | ((32 * sdram->emc_pmacro_ddll_bypass >> 31 << 11) | ((sdram->emc_pmacro_ddll_bypass << 6 >> 31 << 10) | ((sdram->emc_pmacro_ddll_bypass << 7 >> 31 << 9) | ((sdram->emc_pmacro_ddll_bypass << 15 >> 31 << 8) | ((sdram->emc_pmacro_ddll_bypass << 16 >> 31 << 7) | ((sdram->emc_pmacro_ddll_bypass << 17 >> 31 << 6) | (32 * (sdram->emc_pmacro_ddll_bypass << 18 >> 31) | (16 * (sdram->emc_pmacro_ddll_bypass << 20 >> 31) | (8 * (sdram->emc_pmacro_ddll_bypass << 21 >> 31) | (4 * (sdram->emc_pmacro_ddll_bypass << 22 >> 31) | (2 * (sdram->emc_pmacro_ddll_bypass << 23 >> 31) | (sdram->emc_pmacro_ddll_bypass & 1 | 2 * (pmc->scratch214 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFF0FFFF) & 0xFFEFFFFF) & 0xFE1FFFFF) & 0xFDFFFFFF) & 0x3FFFFFF; + pmc->scratch215 = (sdram->emc_pmacro_cmd_pi_ctrl << 10 >> 26 << 10) | ((sdram->emc_pmacro_cmd_pi_ctrl << 19 >> 31 << 9) | (32 * (sdram->emc_pmacro_cmd_pi_ctrl << 20 >> 28) | (16 * (sdram->emc_pmacro_cmd_pi_ctrl << 27 >> 31) | (sdram->emc_pmacro_cmd_pi_ctrl & 0xF | 16 * (pmc->scratch215 >> 4)) & 0xFFFFFFEF) & 0xFFFFFE1F) & 0xFFFFFDFF) & 0xFFFF03FF; + tmp = (sdram->emc_pmacro_data_pad_tx_ctrl << 7 >> 31 << 24) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 8 >> 31 << 23) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 9 >> 31 << 22) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 10 >> 31 << 21) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15 >> 31 << 20) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 16 >> 31 << 19) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 21 >> 31 << 18) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 25 >> 31 << 17) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 26 >> 31 << 16) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 15) & 0xFFFF | ((2 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 14) | ((4 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 13) | ((8 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 12) | ((16 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 11) | ((32 * sdram->emc_pmacro_cmd_pad_tx_ctrl >> 31 << 10) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 6 >> 31 << 9) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 7 >> 31 << 8) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 8 >> 31 << 7) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 9 >> 31 << 6) | (32 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 10 >> 31) | (16 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 15 >> 31) | (8 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 16 >> 31) | (4 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 21 >> 31) | (2 * (sdram->emc_pmacro_cmd_pad_tx_ctrl << 25 >> 31) | ((sdram->emc_pmacro_cmd_pad_tx_ctrl << 26 >> 31) | 2 * (pmc->scratch216 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F) & 0xFFFFFEFF) & 0xFFFFFDFF) & 0xFFFFFBFF) & 0xFFFFF7FF) & 0xFFFFEFFF) & 0xFFFFDFFF) & 0xFFFFBFFF) & 0xFFFF7FFF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFFBFFFF) & 0xFFF7FFFF) & 0xFFEFFFFF) & 0xFFDFFFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF; + pmc->scratch9 = ((4 * pmc->scratch9) >> 2) | (sdram->emc_pin_gpio << 30); + pmc->scratch10 = ((4 * pmc->scratch10) >> 2) | (sdram->emc_pin_gpio_enable << 30); + pmc->scratch11 = ((4 * pmc->scratch11) >> 2) | (sdram->emc_dev_select << 30); + pmc->scratch12 = ((4 * pmc->scratch12) >> 2) | (sdram->emc_zcal_warm_cold_boot_enables << 30); + pmc->scratch13 = ((4 * pmc->scratch13) >> 2) | ((u16)(sdram->emc_cfg_dig_dll_period_warm_boot) << 30); + s32(emc_bct_spare13, scratch45); + s32(emc_bct_spare12, scratch46); + s32(emc_bct_spare7, scratch47); + s32(emc_bct_spare6, scratch48); + s32(emc_bct_spare5, scratch50); + s32(emc_bct_spare4, scratch51); + s32(emc_bct_spare3, scratch56); + s32(emc_bct_spare2, scratch57); + s32(emc_bct_spare1, scratch58); + s32(emc_bct_spare0, scratch59); + s32(emc_bct_spare9, scratch60); + s32(emc_bct_spare8, scratch61); + s32(boot_rom_patch_data, scratch62); + s32(boot_rom_patch_control, scratch63); + pmc->scratch65 = ((2 * pmc->scratch65) >> 1) | ((u16)(sdram->mc_clken_override_allwarm_boot) << 31); + pmc->scratch66 = pmc->scratch66 & 0x1FFFFFFF | ((u8)(sdram->emc_extra_refresh_num) << 29); + pmc->scratch72 = pmc->scratch72 & 0x8FFFFFFF | ((u16)(sdram->pmc_io_dpd3_req_wait) << 28) & 0x70000000; + pmc->scratch72 = ((2 * pmc->scratch72) >> 1) | ((u16)(sdram->emc_clken_override_allwarm_boot) << 31); + pmc->scratch73 = pmc->scratch73 & 0x8FFFFFFF | ((u8)(sdram->memory_type) << 28) & 0x70000000; + pmc->scratch73 = ((2 * pmc->scratch73) >> 1) | (sdram->emc_mrs_warm_boot_enable << 31); + pmc->scratch74 = pmc->scratch74 & 0x8FFFFFFF | (sdram->pmc_io_dpd4_req_wait << 28) & 0x70000000; + pmc->scratch74 = ((2 * pmc->scratch74) >> 1) | (sdram->clear_clock2_mc1 << 31); + pmc->scratch75 = pmc->scratch75 & 0xEFFFFFFF | (sdram->emc_warm_boot_extramode_reg_write_enable << 28) & 0x10000000; + pmc->scratch75 = pmc->scratch75 & 0xDFFFFFFF | (sdram->clk_rst_pllm_misc20_override_enable << 29) & 0x20000000; + pmc->scratch75 = pmc->scratch75 & 0xBFFFFFFF | ((u16)(sdram->emc_dbg_write_mux) << 30) & 0x40000000; + pmc->scratch75 = ((2 * pmc->scratch75) >> 1) | ((u16)(sdram->ahb_arbitration_xbar_ctrl_meminit_done) << 31); + pmc->scratch90 = pmc->scratch90 & 0xFFFFFF | (sdram->emc_timing_control_wait << 24); + pmc->scratch91 = pmc->scratch91 & 0xFFFFFF | (sdram->emc_zcal_warm_boot_wait << 24); + pmc->scratch92 = pmc->scratch92 & 0xFFFFFF | (sdram->warm_boot_wait << 24); + pmc->scratch93 = pmc->scratch93 & 0xFFFFFF | ((u16)(sdram->emc_pin_program_wait) << 24); + pmc->scratch114 = pmc->scratch114 & 0x3FFFFF | ((u16)(sdram->emc_auto_cal_wait) << 22); + pmc->scratch215 = (u16)pmc->scratch215 | ((u16)(sdram->swizzle_rank_byte_encode) << 16); + pmc->scratch216 = (2 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 30) | ((4 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 29) | ((8 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 28) | ((16 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 27) | ((32 * sdram->emc_pmacro_data_pad_tx_ctrl >> 31 << 26) | ((sdram->emc_pmacro_data_pad_tx_ctrl << 6 >> 31 << 25) | tmp & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF; + pmc->scratch5 = (sdram->emc_warm_boot_mrw_extra << 24) | ((sdram->emc_warm_boot_mrw_extra >> 16 << 16) | ((sdram->emc_mrw_lpddr2zcal_warm_boot << 8) & 0xFFFF | ((sdram->emc_mrw_lpddr2zcal_warm_boot << 8 >> 24) | (pmc->scratch5 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFFFFFF; + pmc->scratch6 = (16 * sdram->emc_warm_boot_mrw_extra >> 31 << 7) | ((32 * sdram->emc_warm_boot_mrw_extra >> 31 << 6) | (32 * (16 * sdram->emc_mrw_lpddr2zcal_warm_boot >> 31) | (16 * (32 * sdram->emc_mrw_lpddr2zcal_warm_boot >> 31) | (4 * (sdram->emc_warm_boot_mrw_extra >> 30) | ((sdram->emc_mrw_lpddr2zcal_warm_boot >> 30) | 4 * (pmc->scratch6 >> 2)) & 0xFFFFFFF3) & 0xFFFFFFEF) & 0xFFFFFFDF) & 0xFFFFFFBF) & 0xFFFFFF7F; + pmc->scratch8 = (sdram->emc_mrw6 >> 30 << 28) | ((16 * sdram->emc_mrw6 >> 31 << 27) | ((32 * sdram->emc_mrw6 >> 31 << 26) | ((sdram->emc_mrw6 << 6 >> 30 << 24) | ((sdram->emc_mrw6 << 8 >> 24 << 16) | ((sdram->emc_mrw6 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw6 | (pmc->scratch8 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch9 = (sdram->emc_mrw8 >> 30 << 28) | ((16 * sdram->emc_mrw8 >> 31 << 27) | ((32 * sdram->emc_mrw8 >> 31 << 26) | ((sdram->emc_mrw8 << 6 >> 30 << 24) | ((sdram->emc_mrw8 << 8 >> 24 << 16) | ((sdram->emc_mrw8 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw8 | (pmc->scratch9 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch10 = (sdram->emc_mrw9 >> 30 << 28) | ((16 * sdram->emc_mrw9 >> 31 << 27) | ((32 * sdram->emc_mrw9 >> 31 << 26) | ((sdram->emc_mrw9 << 6 >> 30 << 24) | ((sdram->emc_mrw9 << 8 >> 24 << 16) | ((sdram->emc_mrw9 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw9 | (pmc->scratch10 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch11 = (sdram->emc_mrw10 >> 30 << 28) | ((16 * sdram->emc_mrw10 >> 31 << 27) | ((32 * sdram->emc_mrw10 >> 31 << 26) | ((sdram->emc_mrw10 << 6 >> 30 << 24) | ((sdram->emc_mrw10 << 8 >> 24 << 16) | ((sdram->emc_mrw10 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw10 | (pmc->scratch11 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch12 = (sdram->emc_mrw12 >> 30 << 28) | ((16 * sdram->emc_mrw12 >> 31 << 27) | ((32 * sdram->emc_mrw12 >> 31 << 26) | ((sdram->emc_mrw12 << 6 >> 30 << 24) | ((sdram->emc_mrw12 << 8 >> 24 << 16) | ((sdram->emc_mrw12 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw12 | (pmc->scratch12 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch13 = (sdram->emc_mrw13 >> 30 << 28) | ((16 * sdram->emc_mrw13 >> 31 << 27) | ((32 * sdram->emc_mrw13 >> 31 << 26) | ((sdram->emc_mrw13 << 6 >> 30 << 24) | ((sdram->emc_mrw13 << 8 >> 24 << 16) | ((sdram->emc_mrw13 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw13 | (pmc->scratch13 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch14 = (sdram->emc_mrw14 >> 30 << 28) | ((16 * sdram->emc_mrw14 >> 31 << 27) | ((32 * sdram->emc_mrw14 >> 31 << 26) | ((sdram->emc_mrw14 << 6 >> 30 << 24) | ((sdram->emc_mrw14 << 8 >> 24 << 16) | ((sdram->emc_mrw14 << 16 >> 24 << 8) | ((u8)sdram->emc_mrw14 | (pmc->scratch14 >> 8 << 8)) & 0xFFFF00FF) & 0xFF00FFFF) & 0xFCFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xCFFFFFFF; + pmc->scratch15 = (sdram->emc_mrw1 >> 30 << 18) | ((16 * sdram->emc_mrw1 >> 31 << 17) | ((32 * sdram->emc_mrw1 >> 31 << 16) | ((sdram->emc_mrw1 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw1 | (pmc->scratch15 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + pmc->scratch16 = (sdram->emc_warm_boot_mrw_extra >> 30 << 18) | ((16 * sdram->emc_warm_boot_mrw_extra >> 31 << 17) | ((32 * sdram->emc_warm_boot_mrw_extra >> 31 << 16) | ((sdram->emc_warm_boot_mrw_extra << 8 >> 24 << 8) | ((u8)sdram->emc_warm_boot_mrw_extra | (pmc->scratch16 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + pmc->scratch17 = (sdram->emc_mrw2 >> 30 << 18) | ((16 * sdram->emc_mrw2 >> 31 << 17) | ((32 * sdram->emc_mrw2 >> 31 << 16) | ((sdram->emc_mrw2 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw2 | (pmc->scratch17 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + pmc->scratch18 = (sdram->emc_mrw3 >> 30 << 18) | ((16 * sdram->emc_mrw3 >> 31 << 17) | ((32 * sdram->emc_mrw3 >> 31 << 16) | ((sdram->emc_mrw3 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw3 | (pmc->scratch18 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + pmc->scratch19 = (sdram->emc_mrw4 >> 30 << 18) | ((16 * sdram->emc_mrw4 >> 31 << 17) | ((32 * sdram->emc_mrw4 >> 31 << 16) | ((sdram->emc_mrw4 << 8 >> 24 << 8) | ((u8)sdram->emc_mrw4 | (pmc->scratch19 >> 8 << 8)) & 0xFFFF00FF) & 0xFFFEFFFF) & 0xFFFDFFFF) & 0xFFF3FFFF; + pmc->secure_scratch8 = (sdram->emc_cmd_mapping_byte >> 28 << 28) | ((16 * sdram->emc_cmd_mapping_byte >> 28 << 24) | ((sdram->emc_cmd_mapping_byte << 8 >> 28 << 20) | ((sdram->emc_cmd_mapping_byte << 12 >> 28 << 16) | ((sdram->emc_cmd_mapping_byte << 16 >> 28 << 12) | ((sdram->emc_cmd_mapping_byte << 20 >> 28 << 8) | (16 * (sdram->emc_cmd_mapping_byte << 24 >> 28) | (sdram->emc_cmd_mapping_byte & 0xF | 16 * (pmc->secure_scratch8 >> 4)) & 0xFFFFFF0F) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xF0FFFFFF) & 0xFFFFFFF; + pmc->secure_scratch9 = (sdram->emc_pmacro_brick_mapping0 >> 28 << 28) | ((16 * sdram->emc_pmacro_brick_mapping0 >> 28 << 24) | ((sdram->emc_pmacro_brick_mapping0 << 8 >> 28 << 20) | ((sdram->emc_pmacro_brick_mapping0 << 12 >> 28 << 16) | ((sdram->emc_pmacro_brick_mapping0 << 16 >> 28 << 12) | ((sdram->emc_pmacro_brick_mapping0 << 20 >> 28 << 8) | (16 * (sdram->emc_pmacro_brick_mapping0 << 24 >> 28) | (sdram->emc_pmacro_brick_mapping0 & 0xF | 16 * (pmc->secure_scratch9 >> 4)) & 0xFFFFFF0F) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xF0FFFFFF) & 0xFFFFFFF; + pmc->secure_scratch10 = (sdram->emc_pmacro_brick_mapping1 >> 28 << 28) | ((16 * sdram->emc_pmacro_brick_mapping1 >> 28 << 24) | ((sdram->emc_pmacro_brick_mapping1 << 8 >> 28 << 20) | ((sdram->emc_pmacro_brick_mapping1 << 12 >> 28 << 16) | ((sdram->emc_pmacro_brick_mapping1 << 16 >> 28 << 12) | ((sdram->emc_pmacro_brick_mapping1 << 20 >> 28 << 8) | (16 * (sdram->emc_pmacro_brick_mapping1 << 24 >> 28) | (sdram->emc_pmacro_brick_mapping1 & 0xF | 16 * (pmc->secure_scratch10 >> 4)) & 0xFFFFFF0F) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xF0FFFFFF) & 0xFFFFFFF; + pmc->secure_scratch11 = (sdram->emc_pmacro_brick_mapping2 >> 28 << 28) | ((16 * sdram->emc_pmacro_brick_mapping2 >> 28 << 24) | ((sdram->emc_pmacro_brick_mapping2 << 8 >> 28 << 20) | ((sdram->emc_pmacro_brick_mapping2 << 12 >> 28 << 16) | ((sdram->emc_pmacro_brick_mapping2 << 16 >> 28 << 12) | ((sdram->emc_pmacro_brick_mapping2 << 20 >> 28 << 8) | (16 * (sdram->emc_pmacro_brick_mapping2 << 24 >> 28) | (sdram->emc_pmacro_brick_mapping2 & 0xF | 16 * (pmc->secure_scratch11 >> 4)) & 0xFFFFFF0F) & 0xFFFFF0FF) & 0xFFFF0FFF) & 0xFFF0FFFF) & 0xFF0FFFFF) & 0xF0FFFFFF) & 0xFFFFFFF; + s32(mc_video_protect_gpu_override0, secure_scratch12); + pmc->secure_scratch13 = ((u16)(sdram->emc_adr_cfg) << 31) | (2 * ((((u16)(sdram->mc_untranslated_region_check) << 22) >> 31 << 30) | ((((u16)(sdram->mc_untranslated_region_check) << 23) >> 31 << 29) | (((u16)(sdram->mc_untranslated_region_check) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd0_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_0 & 0x7F | (pmc->secure_scratch13 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch14 = (sdram->mc_video_protect_write_access << 30 >> 31 << 31) | (2 * ((sdram->mc_video_protect_write_access << 30) | ((sdram->mc_video_protect_bom_adr_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd0_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd0_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_1 & 0x7F | (pmc->secure_scratch14 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch15 = ((u16)(sdram->mc_mts_carveout_adr_hi) << 30) | (4 * ((sdram->mc_sec_carveout_adr_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_0 & 0x7F | (pmc->secure_scratch15 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); + pmc->secure_scratch16 = (sdram->mc_generalized_carveout3_bom_hi << 30) | (4 * ((sdram->mc_generalized_carveout5_bom_hi << 28) | ((2 * sdram->emc_cmd_mapping_cmd1_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd1_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_1 & 0x7F | (pmc->secure_scratch16 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); + pmc->secure_scratch17 = ((u16)(sdram->mc_generalized_carveout4_bom_hi) << 30) | (4 * (((u16)(sdram->mc_generalized_carveout2_bom_hi) << 28) | ((2 * sdram->emc_cmd_mapping_cmd2_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_0 & 0x7F | (pmc->secure_scratch17 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) >> 2); + pmc->secure_scratch18 = (sdram->emc_fbio_cfg8 << 16 >> 31 << 31) | (2 * (((u16)(sdram->emc_fbio_spare) << 30 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom_hi << 30 >> 2) | ((2 * sdram->emc_cmd_mapping_cmd2_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd2_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_1 & 0x7F | (pmc->secure_scratch18 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xCFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch19 = (sdram->mc_video_protect_vpr_override << 31) | (2 * (((u16)(sdram->mc_mts_carveout_reg_ctrl) << 30) | ((sdram->mc_sec_carveout_protect_write_access << 31 >> 2) | (((u16)(sdram->mc_emem_adr_cfg) << 28) & 0x1FFFFFFF | ((2 * sdram->emc_cmd_mapping_cmd3_0 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_0 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_0 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_0 & 0x7F | (pmc->secure_scratch19 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch20 = (sdram->mc_generalized_carveout2_cfg0 << 25 >> 28 << 28) | ((2 * sdram->emc_cmd_mapping_cmd3_1 >> 25 << 21) | ((sdram->emc_cmd_mapping_cmd3_1 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_1 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_1 & 0x7F | (pmc->secure_scratch20 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xF01FFFFF) & 0xFFFFFFF; + pmc->secure_scratch39 = (sdram->mc_video_protect_vpr_override << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 21 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout4_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout4_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout4_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout4_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout4_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout4_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout4_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout4_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout4_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout4_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout4_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout4_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout4_cfg0 & 1 | 2 * (pmc->secure_scratch39 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch40 = (sdram->mc_video_protect_vpr_override << 29 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 14 >> 28 << 27) | ((32 * sdram->mc_generalized_carveout5_cfg0 >> 31 << 26) | ((sdram->mc_generalized_carveout5_cfg0 << 6 >> 31 << 25) | ((sdram->mc_generalized_carveout5_cfg0 << 7 >> 31 << 24) | ((sdram->mc_generalized_carveout5_cfg0 << 8 >> 31 << 23) | ((sdram->mc_generalized_carveout5_cfg0 << 9 >> 31 << 22) | ((sdram->mc_generalized_carveout5_cfg0 << 10 >> 28 << 18) | ((sdram->mc_generalized_carveout5_cfg0 << 14 >> 28 << 14) | ((sdram->mc_generalized_carveout5_cfg0 << 18 >> 29 << 11) | ((sdram->mc_generalized_carveout5_cfg0 << 21 >> 28 << 7) | (8 * (sdram->mc_generalized_carveout5_cfg0 << 25 >> 28) | (4 * (sdram->mc_generalized_carveout5_cfg0 << 29 >> 31) | (2 * (sdram->mc_generalized_carveout5_cfg0 << 30 >> 31) | (sdram->mc_generalized_carveout5_cfg0 & 1 | 2 * (pmc->secure_scratch40 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFF87) & 0xFFFFF87F) & 0xFFFFC7FF) & 0xFFFC3FFF) & 0xFFC3FFFF) & 0xFFBFFFFF) & 0xFF7FFFFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch41 = (sdram->mc_generalized_carveout2_cfg0 << 18 >> 29 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 10 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd0_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd0_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd0_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd0_2 & 0x7F | (pmc->secure_scratch41 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; + pmc->secure_scratch42 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 25 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd1_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd1_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd1_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd1_2 & 0x7F | (pmc->secure_scratch42 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; + pmc->secure_scratch43 = ((u16)(sdram->mc_generalized_carveout3_cfg0) << 18 >> 29 << 29) | (((u16)(sdram->mc_generalized_carveout1_cfg0) << 21 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd2_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd2_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd2_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd2_2 & 0x7F | (pmc->secure_scratch43 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0x1FFFFFFF; + pmc->secure_scratch44 = (sdram->mc_video_protect_vpr_override << 24 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 25 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override << 28 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 14 >> 28 << 25) | ((16 * sdram->emc_cmd_mapping_cmd3_2 >> 28 << 21) | ((sdram->emc_cmd_mapping_cmd3_2 << 9 >> 25 << 14) | ((sdram->emc_cmd_mapping_cmd3_2 << 17 >> 25 << 7) | (sdram->emc_cmd_mapping_cmd3_2 & 0x7F | (pmc->secure_scratch44 >> 7 << 7)) & 0xFFFFC07F) & 0xFFE03FFF) & 0xFE1FFFFF) & 0xE1FFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch45 = (sdram->mc_emem_adr_cfg_dev0 << 12 >> 28 << 28) | ((sdram->mc_emem_adr_cfg_dev0 << 22 >> 30 << 26) | ((sdram->mc_emem_adr_cfg_dev0 << 23) & 0x3FFFFFF | ((sdram->mc_emem_adr_cfg_channel_mask >> 9) | (pmc->secure_scratch45 >> 23 << 23)) & 0xFC7FFFFF) & 0xF3FFFFFF) & 0xFFFFFFF; + pmc->secure_scratch46 = (sdram->mc_video_protect_vpr_override << 23 >> 31 << 31) | (2 * ((sdram->mc_emem_adr_cfg_dev1 << 12 >> 28 << 27) | ((sdram->mc_emem_adr_cfg_dev1 << 22 >> 30 << 25) | ((sdram->mc_emem_adr_cfg_dev1 << 22) & 0x1FFFFFF | ((sdram->mc_emem_adr_cfg_bank_mask0 >> 10) | (pmc->secure_scratch46 >> 22 << 22)) & 0xFE3FFFFF) & 0xF9FFFFFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch47 = (sdram->mc_video_protect_vpr_override << 20 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 22 >> 31 << 30) | (((u8)(sdram->mc_generalized_carveout3_cfg0) << 25 >> 28 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 10 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask1 >> 10) | (pmc->secure_scratch47 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch48 = (sdram->mc_video_protect_vpr_override << 16 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 17 >> 31 << 30) | ((sdram->mc_generalized_carveout3_cfg0 << 14 >> 28 << 26) | ((sdram->mc_generalized_carveout3_cfg0 << 21 >> 28 << 22) | ((sdram->mc_emem_adr_cfg_bank_mask2 >> 10) | (pmc->secure_scratch48 >> 22 << 22)) & 0xFC3FFFFF) & 0xC3FFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch49 = (sdram->mc_video_protect_vpr_override << 14 >> 31 << 31) | (2 * ((sdram->mc_emem_cfg >> 31 << 30) | ((sdram->mc_emem_cfg << 18 >> 2) | (sdram->mc_video_protect_gpu_override1 & 0xFFFF | (pmc->secure_scratch49 >> 16 << 16)) & 0xC000FFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch50 = (sdram->mc_video_protect_vpr_override << 12 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 13 >> 31 << 30) | ((sdram->mc_generalized_carveout1_bom >> 17 << 15) | ((sdram->mc_generalized_carveout3_bom >> 17) | (pmc->secure_scratch50 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch51 = (sdram->mc_video_protect_vpr_override << 10 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override << 11 >> 31 << 30) | ((sdram->mc_generalized_carveout2_bom >> 17 << 15) | ((sdram->mc_generalized_carveout4_bom >> 17) | (pmc->secure_scratch51 >> 15 << 15)) & 0xC0007FFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch52 = (sdram->mc_video_protect_vpr_override << 9 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout3_cfg0 << 10 >> 28 << 27) | ((sdram->mc_video_protect_bom >> 20 << 15) | ((sdram->mc_generalized_carveout5_bom >> 17) | (pmc->secure_scratch52 >> 15 << 15)) & 0xF8007FFF) & 0x87FFFFFF) >> 1); + pmc->secure_scratch53 = (sdram->mc_video_protect_vpr_override1 << 27 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 30 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 31 >> 2) | ((sdram->mc_video_protect_vpr_override >> 31 << 28) | ((2 * sdram->mc_video_protect_vpr_override >> 31 << 27) | ((4 * sdram->mc_video_protect_vpr_override >> 31 << 26) | ((32 * sdram->mc_video_protect_vpr_override >> 31 << 25) | ((sdram->mc_video_protect_vpr_override << 8 >> 31 << 24) | ((sdram->mc_sec_carveout_bom >> 20 << 12) | (sdram->mc_video_protect_size_mb & 0xFFF | (pmc->secure_scratch53 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch54 = (sdram->mc_video_protect_vpr_override1 << 19 >> 31 << 31) | (2 * ((sdram->mc_video_protect_vpr_override1 << 20 >> 31 << 30) | ((sdram->mc_video_protect_vpr_override1 << 21 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 22 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 23 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 24 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 25 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 26 >> 31 << 24) | ((sdram->mc_mts_carveout_bom >> 20 << 12) | (sdram->mc_sec_carveout_size_mb & 0xFFF | (pmc->secure_scratch54 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch55 = (sdram->mc_generalized_carveout2_cfg0 << 30 >> 31 << 31) | (2 * ((sdram->mc_generalized_carveout2_cfg0 << 30) | ((32 * sdram->mc_video_protect_vpr_override1 >> 31 << 29) | ((sdram->mc_video_protect_vpr_override1 << 6 >> 31 << 28) | ((sdram->mc_video_protect_vpr_override1 << 15 >> 31 << 27) | ((sdram->mc_video_protect_vpr_override1 << 16 >> 31 << 26) | ((sdram->mc_video_protect_vpr_override1 << 17 >> 31 << 25) | ((sdram->mc_video_protect_vpr_override1 << 18 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout4_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_mts_carveout_size_mb & 0xFFF | (pmc->secure_scratch55 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch56 = ((u16)(sdram->mc_generalized_carveout1_cfg0) << 30 >> 31 << 31) | (2 * (((u16)(sdram->mc_generalized_carveout1_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout2_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout2_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout2_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout2_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout2_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout2_cfg0 << 29 >> 31 << 24) | (((u16)(sdram->mc_generalized_carveout2_size_128kb) << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout3_size_128kb & 0xFFF | (pmc->secure_scratch56 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + pmc->secure_scratch57 = ((u8)(sdram->mc_generalized_carveout3_cfg0) << 30 >> 31 << 31) | (2 * (((u8)(sdram->mc_generalized_carveout3_cfg0) << 30) | ((32 * sdram->mc_generalized_carveout1_cfg0 >> 31 << 29) | ((sdram->mc_generalized_carveout1_cfg0 << 6 >> 31 << 28) | ((sdram->mc_generalized_carveout1_cfg0 << 7 >> 31 << 27) | ((sdram->mc_generalized_carveout1_cfg0 << 8 >> 31 << 26) | ((sdram->mc_generalized_carveout1_cfg0 << 9 >> 31 << 25) | ((sdram->mc_generalized_carveout1_cfg0 << 29 >> 31 << 24) | ((sdram->mc_generalized_carveout5_size_128kb << 12) & 0xFFFFFF | (sdram->mc_generalized_carveout1_size_128kb & 0xFFF | (pmc->secure_scratch57 >> 12 << 12)) & 0xFF000FFF) & 0xFEFFFFFF) & 0xFDFFFFFF) & 0xFBFFFFFF) & 0xF7FFFFFF) & 0xEFFFFFFF) & 0xDFFFFFFF) & 0xBFFFFFFF) >> 1); + + s32(mc_generalized_carveout1_access0, secure_scratch59); + s32(mc_generalized_carveout1_access1, secure_scratch60); + s32(mc_generalized_carveout1_access2, secure_scratch61); + s32(mc_generalized_carveout1_access3, secure_scratch62); + s32(mc_generalized_carveout1_access4, secure_scratch63); + s32(mc_generalized_carveout2_access0, secure_scratch64); + s32(mc_generalized_carveout2_access1, secure_scratch65); + s32(mc_generalized_carveout2_access2, secure_scratch66); + s32(mc_generalized_carveout2_access3, secure_scratch67); + s32(mc_generalized_carveout2_access4, secure_scratch68); + s32(mc_generalized_carveout3_access0, secure_scratch69); + s32(mc_generalized_carveout3_access1, secure_scratch70); + s32(mc_generalized_carveout3_access2, secure_scratch71); + s32(mc_generalized_carveout3_access3, secure_scratch72); + s32(mc_generalized_carveout3_access4, secure_scratch73); + s32(mc_generalized_carveout4_access0, secure_scratch74); + s32(mc_generalized_carveout4_access1, secure_scratch75); + s32(mc_generalized_carveout4_access2, secure_scratch76); + s32(mc_generalized_carveout4_access3, secure_scratch77); + s32(mc_generalized_carveout4_access4, secure_scratch78); + s32(mc_generalized_carveout5_access0, secure_scratch79); + s32(mc_generalized_carveout5_access1, secure_scratch80); + s32(mc_generalized_carveout5_access2, secure_scratch81); + s32(mc_generalized_carveout5_access3, secure_scratch82); + s32(mc_generalized_carveout1_force_internal_access0, secure_scratch84); + s32(mc_generalized_carveout1_force_internal_access1, secure_scratch85); + s32(mc_generalized_carveout1_force_internal_access2, secure_scratch86); + s32(mc_generalized_carveout1_force_internal_access3, secure_scratch87); + s32(mc_generalized_carveout1_force_internal_access4, secure_scratch88); + s32(mc_generalized_carveout2_force_internal_access0, secure_scratch89); + s32(mc_generalized_carveout2_force_internal_access1, secure_scratch90); + s32(mc_generalized_carveout2_force_internal_access2, secure_scratch91); + s32(mc_generalized_carveout2_force_internal_access3, secure_scratch92); + s32(mc_generalized_carveout2_force_internal_access4, secure_scratch93); + s32(mc_generalized_carveout3_force_internal_access0, secure_scratch94); + s32(mc_generalized_carveout3_force_internal_access1, secure_scratch95); + s32(mc_generalized_carveout3_force_internal_access2, secure_scratch96); + s32(mc_generalized_carveout3_force_internal_access3, secure_scratch97); + s32(mc_generalized_carveout3_force_internal_access4, secure_scratch98); + s32(mc_generalized_carveout4_force_internal_access0, secure_scratch99); + s32(mc_generalized_carveout4_force_internal_access1, secure_scratch100); + s32(mc_generalized_carveout4_force_internal_access2, secure_scratch101); + s32(mc_generalized_carveout4_force_internal_access3, secure_scratch102); + s32(mc_generalized_carveout4_force_internal_access4, secure_scratch103); + s32(mc_generalized_carveout5_force_internal_access0, secure_scratch104); + s32(mc_generalized_carveout5_force_internal_access1, secure_scratch105); + s32(mc_generalized_carveout5_force_internal_access2, secure_scratch106); + s32(mc_generalized_carveout5_force_internal_access3, secure_scratch107); + + pmc->secure_scratch58 = 32 * (32 * sdram->mc_generalized_carveout3_cfg0 >> 31) | (16 * (sdram->mc_generalized_carveout3_cfg0 << 6 >> 31) | (8 * (sdram->mc_generalized_carveout3_cfg0 << 7 >> 31) | (4 * (sdram->mc_generalized_carveout3_cfg0 << 8 >> 31) | (2 * (sdram->mc_generalized_carveout3_cfg0 << 9 >> 31) | ((sdram->mc_generalized_carveout3_cfg0 << 29 >> 31) | 2 * (pmc->secure_scratch58 >> 1)) & 0xFFFFFFFD) & 0xFFFFFFFB) & 0xFFFFFFF7) & 0xFFFFFFEF) & 0xFFFFFFDF; + pmc->scratch2 = (sdram->pllm_feedback_divider << 8) | ((u16)(sdram->pllm_post_divider) << 16) | sdram->pllm_input_divider | ((u16)(sdram->pllm_kvco) << 17) | ((u16)(sdram->pllm_kcp) << 18); + pmc->scratch35 = sdram->pllm_setup_control; + pmc->scratch3 = sdram->pllm_input_divider | ((u16)(sdram->pllm_kvco) << 21) | ((u16)(sdram->pllm_kcp) << 22) | 0x3E00; + pmc->scratch36 = sdram->pllm_setup_control; + pmc->scratch4 = (sdram->pllm_stable_time << 10) | sdram->pllm_stable_time; +} + +#pragma GCC diagnostic pop + void _modInit(void *sdram_config, bdkParams_t bp) { - sdram_lp0_save_params(sdram_config); + u32 chip_id = (APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF; + + if (chip_id != GP_HIDREV_MAJOR_T210B01) + _sdram_lp0_save_params_t210(sdram_config); + else + _sdram_lp0_save_params_t210b01(sdram_config); } diff --git a/modules/hekate_libsys_lp0/t210.h b/modules/hekate_libsys_lp0/t210.h index cb20e5e..b1a8549 100644 --- a/modules/hekate_libsys_lp0/t210.h +++ b/modules/hekate_libsys_lp0/t210.h @@ -92,6 +92,9 @@ /*! Misc registers. */ #define APB_MISC_PP_PINMUX_GLOBAL 0x40 +#define APB_MISC_GP_HIDREV 0x804 +#define GP_HIDREV_MAJOR_T210 0x1 +#define GP_HIDREV_MAJOR_T210B01 0x2 #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 #define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 diff --git a/modules/hekate_libsys_minerva/Makefile b/modules/hekate_libsys_minerva/Makefile index 90a2ab0..5e3f086 100644 --- a/modules/hekate_libsys_minerva/Makefile +++ b/modules/hekate_libsys_minerva/Makefile @@ -7,14 +7,15 @@ include $(DEVKITARM)/base_rules TARGET := libsys_minerva BUILD := ../../build/$(TARGET) OUTPUT := ../../output -VPATH = $(dir $(wildcard ./*/)) $(dir $(wildcard ./*/*/)) +BDKDIR := bdk +BDKINC := -I../../$(BDKDIR) OBJS = $(addprefix $(BUILD)/,\ sys_sdrammtc.o \ ) ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall -Wsign-compare $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc .PHONY: clean all @@ -22,11 +23,12 @@ LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc all: $(TARGET).bso $(BUILD)/%.o: ./%.c @mkdir -p "$(BUILD)" - $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(TARGET).bso: $(OBJS) - $(CC) $(LDFLAGS) -e _minerva_init $^ -o $(OUTPUT)/$(TARGET).bso - $(STRIP) -g $(OUTPUT)/$(TARGET).bso + @$(CC) $(LDFLAGS) -e _minerva_init $^ -o $(OUTPUT)/$(TARGET).bso + @$(STRIP) -g $(OUTPUT)/$(TARGET).bso + @echo -e "-------------\nBuilt module: "$(TARGET)".bso\n-------------" clean: @rm -rf $(OUTPUT)/$(TARGET).bso diff --git a/modules/hekate_libsys_minerva/mtc.h b/modules/hekate_libsys_minerva/mtc.h index a673d38..860c7d7 100644 --- a/modules/hekate_libsys_minerva/mtc.h +++ b/modules/hekate_libsys_minerva/mtc.h @@ -2,7 +2,7 @@ * Minerva Training Cell * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -44,16 +44,38 @@ #define EMC_CH1(off) _REG(EMC1_BASE, off) /* End of addresses and access macros */ -#define EMC_TABLE_SIZE_R7 49280 #define EMC_TABLE_ENTRY_SIZE_R7 4928 +#define EMC_TABLE_ENTRY_SIZE_R3 4300 +#define EMC_TABLE_SIZE_R7 (EMC_TABLE_ENTRY_SIZE_R7 * 7) #define EMC_STATUS_UPDATE_TIMEOUT 1000 #define EMC_PERIODIC_TRAIN_MS 100 #define EMC_TEMP_COMP_MS 1000 +/* Training types */ +#define NEEDS_TRAINING_CA BIT(0) +#define NEEDS_TRAINING_CA_VREF BIT(1) +#define NEEDS_TRAINING_QUSE BIT(2) +#define NEEDS_TRAINING_QUSE_VREF BIT(3) +#define NEEDS_TRAINING_WR BIT(4) +#define NEEDS_TRAINING_WR_VREF BIT(5) +#define NEEDS_TRAINING_RD BIT(6) +#define NEEDS_TRAINING_RD_VREF BIT(7) +#define NEEDS_TRAINING_SWAP_RANK BIT(8) +#define NEEDS_TRAINING_IN_SELF_REFRESH BIT(9) + +#define NEEDS_TRISTATE_TRAINING (NEEDS_TRAINING_CA | NEEDS_TRAINING_CA_VREF | \ + NEEDS_TRAINING_QUSE | NEEDS_TRAINING_WR | \ + NEEDS_TRAINING_WR_VREF | NEEDS_TRAINING_RD | \ + NEEDS_TRAINING_RD_VREF) +#define NEEDS_TRAINING_CA_COMBO (NEEDS_TRAINING_CA | NEEDS_TRAINING_CA_VREF) +#define NEEDS_TRAINING_QUSE_COMBO (NEEDS_TRAINING_QUSE | NEEDS_TRAINING_QUSE_VREF) +#define NEEDS_TRAINING_WR_COMBO (NEEDS_TRAINING_WR | NEEDS_TRAINING_WR_VREF) +#define NEEDS_TRAINING_RD_COMBO (NEEDS_TRAINING_RD | NEEDS_TRAINING_RD_VREF) + typedef struct { - s32 rate_to; - s32 rate_from; + u32 rate_to; + u32 rate_from; emc_table_t *mtc_table; u32 table_entries; emc_table_t *current_emc_table; @@ -63,7 +85,7 @@ typedef struct bool emc_2X_clk_src_is_pllmb; bool fsp_for_src_freq; bool train_ram_patterns; - bool init_done; + u32 init_done; } mtc_config_t; enum train_mode_t @@ -93,8 +115,8 @@ enum tree_update_mode_t enum emc_channels { - EMC_CH0 = 0, - EMC_CH1 = 1 + EMC_CHANNEL0 = 0, + EMC_CHANNEL1 = 1 }; enum EMC_2X_CLK_SRC @@ -139,7 +161,4 @@ void _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg); /* Over temp and periodic compensation, should not access EMC_MRR at the same time. */ u32 _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry); -/* Main function used to access all Minerva functions. */ -void _minerva_init(mtc_config_t *mtc_cfg, void* bp); - #endif diff --git a/modules/hekate_libsys_minerva/mtc_mc_emc_regs.h b/modules/hekate_libsys_minerva/mtc_mc_emc_regs.h index 7fa0c2a..569a9a1 100644 --- a/modules/hekate_libsys_minerva/mtc_mc_emc_regs.h +++ b/modules/hekate_libsys_minerva/mtc_mc_emc_regs.h @@ -179,7 +179,8 @@ #define TIMING_UPDATE_STALLED (1 << 23) #define MRR_DIVLD (1 << 20) #define IN_SELF_REFRESH_MASK (3 << 8) -#define IN_POWERDOWN_MASK (3 << 4) +#define IN_POWERDOWN_BOTH_MASK (3 << 4) +#define IN_POWERDOWN_1DEV_MASK (1 << 4) #define REQ_FIFO_EMPTY (1 << 0) #define EMC_CFG_2 0x2B8 diff --git a/modules/hekate_libsys_minerva/mtc_switch_tables.h b/modules/hekate_libsys_minerva/mtc_switch_tables.h index 2aaed05..3b9548f 100644 --- a/modules/hekate_libsys_minerva/mtc_switch_tables.h +++ b/modules/hekate_libsys_minerva/mtc_switch_tables.h @@ -20,933 +20,18 @@ #ifndef _MTC_SWITCH_TABLES_H_ #define _MTC_SWITCH_TABLES_H_ +#define DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH 0 +#define DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN 1 +#define DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT 2 +#define DRAM_4GB_COPPER_SAMSUNG 3 +#define DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH 4 +#define DRAM_4GB_COPPER_HYNIX 5 +#define DRAM_4GB_COPPER_MICRON 6 +#define DRAM_8GB_SAMSUNG_K4FBE3D4HM_MGXX 7 + // nx_abca2_0_3 and nx_abca2_1. For sdram ids 0,2,3,4 -static const unsigned char nx_abca2_0_3_10NoCfgVersion_V9_8_7_V1_6[49280] = +static const unsigned char nx_abca2_0_3_10NoCfgVersion_V9_8_7_V1_6[34496] = { - 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x34, 0x30, 0x38, 0x30, 0x30, 0x5F, 0x4E, 0x6F, 0x43, - 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, 0x37, - 0x5F, 0x56, 0x31, 0x2E, 0x36, 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, - 0x60, 0x9F, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70, - 0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x18, 0x40, - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 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, 0x0A, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, - 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, 0x0B, 0x08, - 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, - 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x29, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x29, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, - 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, - 0xFF, 0x0F, 0xFF, 0x0F, 0x3A, 0x02, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, - 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, - 0x0B, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x00, 0x04, 0x00, - 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, - 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, - 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, - 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48, - 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C, - 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, - 0x04, 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, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0xA0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x55, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, - 0x29, 0x00, 0x09, 0x00, 0x15, 0x00, 0x29, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x02, 0x03, 0xE0, 0xC1, - 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x3A, 0x02, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 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, - 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, 0x0B, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, - 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07, - 0x14, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, - 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, - 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 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, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x08, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x02, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, - 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, - 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0x29, 0x00, 0x09, 0x00, 0x15, 0x00, 0x29, 0x00, 0x0A, 0x00, 0x0B, 0x00, - 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x3A, 0x02, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 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, 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, 0x0B, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x14, 0x16, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, - 0x04, 0x04, 0x07, 0x07, 0x14, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, - 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, - 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, - 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x00, 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, - 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x30, - 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x48, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, - 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x29, 0x00, 0x09, 0x00, 0x15, 0x00, 0x29, 0x00, - 0x0A, 0x00, 0x0B, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, - 0x3A, 0x02, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, 0x0B, 0x60, 0x18, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, - 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, - 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, - 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, - 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 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, 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, 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, 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, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 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, 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, 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, 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, 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, 0x49, 0x92, 0x24, 0x00, - 0x49, 0x92, 0x24, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x06, 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, 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, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x02, 0x40, 0x13, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 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, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00, - 0x03, 0x03, 0xC3, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x76, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x3D, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x49, 0x00, 0xFF, 0x00, - 0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x12, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0x72, 0x51, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x36, 0x38, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F, 0x43, - 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, 0x37, - 0x5F, 0x56, 0x31, 0x2E, 0x36, 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, - 0xA0, 0x09, 0x01, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70, - 0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x80, 0x18, 0x40, - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 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, 0x0A, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, - 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, 0x0B, 0x08, - 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, - 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x44, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, - 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, - 0xFF, 0x0F, 0xFF, 0x0F, 0x09, 0x03, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, - 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, - 0x11, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x22, 0x00, 0x04, 0x00, - 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, - 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, - 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, - 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48, - 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C, - 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, - 0x04, 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, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x0A, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x55, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, - 0x44, 0x00, 0x09, 0x00, 0x15, 0x00, 0x44, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x02, 0x03, 0xE0, 0xC1, - 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x09, 0x03, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 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, - 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, 0x11, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, - 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07, - 0x22, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, - 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, - 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 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, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x08, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x02, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, - 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, - 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, 0x15, 0x00, 0x44, 0x00, 0x0A, 0x00, 0x11, 0x00, - 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x09, 0x03, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 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, 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, 0x11, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x14, 0x16, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, - 0x04, 0x04, 0x07, 0x07, 0x22, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, - 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, - 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, - 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x00, 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, - 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x30, - 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x48, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, - 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, 0x15, 0x00, 0x44, 0x00, - 0x0A, 0x00, 0x11, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, - 0x09, 0x03, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, 0x11, 0x60, 0x18, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x22, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, - 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, - 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, - 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, - 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 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, 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, 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, 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, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 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, 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, 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, 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, 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, 0x49, 0x92, 0x24, 0x00, - 0x49, 0x92, 0x24, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x06, 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, 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, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0xF0, 0x24, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 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, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00, - 0x03, 0x03, 0x63, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xC4, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x25, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x25, 0x00, 0xFF, 0x00, 0x49, 0x00, 0xFF, 0x00, - 0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0A, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0xE0, 0x29, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x30, 0x32, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F, - 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, - 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 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, - 0x70, 0x8E, 0x01, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70, - 0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x18, 0x40, - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 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, 0x0A, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, - 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, 0x0B, 0x08, - 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, - 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x66, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x66, 0x00, 0x0A, 0x00, 0x1A, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, - 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, - 0xFF, 0x0F, 0xFF, 0x0F, 0x0B, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, - 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, - 0x1A, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x32, 0x00, 0x04, 0x00, - 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, - 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, - 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, - 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48, - 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C, - 0x0C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, - 0x04, 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, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, - 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x8E, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x55, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, - 0x66, 0x00, 0x09, 0x00, 0x15, 0x00, 0x66, 0x00, 0x0A, 0x00, 0x1A, 0x00, 0x02, 0x03, 0xE0, 0xC1, - 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x0B, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 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, - 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, 0x1A, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07, - 0x32, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, - 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, - 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 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, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, - 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, - 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0x66, 0x00, 0x09, 0x00, 0x15, 0x00, 0x66, 0x00, 0x0A, 0x00, 0x1A, 0x00, - 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x0B, 0x04, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 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, 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, 0x1A, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x14, 0x16, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, - 0x04, 0x04, 0x07, 0x07, 0x32, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, - 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, - 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, - 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x00, 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, - 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x30, - 0x03, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x48, 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, - 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x66, 0x00, 0x09, 0x00, 0x15, 0x00, 0x66, 0x00, - 0x0A, 0x00, 0x1A, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, - 0x0B, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, 0x1A, 0x60, 0x18, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x32, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, - 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, - 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, - 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, - 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 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, 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, 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, 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, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 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, 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, 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, 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, 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, 0x49, 0x92, 0x24, 0x00, - 0x49, 0x92, 0x24, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 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, 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, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x50, 0x33, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 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, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00, - 0x03, 0x03, 0x03, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x26, 0x01, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x18, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x18, 0x00, 0xFF, 0x00, 0x49, 0x00, 0xFE, 0x00, - 0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xDA, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x06, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0xEA, 0x1A, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x32, 0x30, 0x34, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -3106,932 +2191,8 @@ static const unsigned char nx_abca2_0_3_10NoCfgVersion_V9_8_7_V1_6[49280] = }; // nx_abca2_2. For sdram id 1. -static const unsigned char nx_abca2_2_10NoCfgVersion_V9_8_7_V1_6[49280] = +static const unsigned char nx_abca2_2_10NoCfgVersion_V9_8_7_V1_6[34496] = { - 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x34, 0x30, 0x38, 0x30, 0x30, 0x5F, 0x4E, 0x6F, 0x43, - 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, 0x37, - 0x5F, 0x56, 0x31, 0x2E, 0x36, 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, - 0x60, 0x9F, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70, - 0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x18, 0x40, - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 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, 0x0A, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, - 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, 0x0B, 0x08, - 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, - 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x29, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x29, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, - 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, - 0xFF, 0x0F, 0xFF, 0x0F, 0x3A, 0x02, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, - 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, - 0x0B, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x00, 0x04, 0x00, - 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, - 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, - 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, - 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48, - 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C, - 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, - 0x04, 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, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, - 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0xA0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x55, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, - 0x29, 0x00, 0x09, 0x00, 0x15, 0x00, 0x29, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x02, 0x03, 0xE0, 0xC1, - 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x3A, 0x02, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 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, - 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, 0x0B, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, - 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07, - 0x14, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, - 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, - 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 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, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x08, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x02, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, - 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, - 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0x29, 0x00, 0x09, 0x00, 0x15, 0x00, 0x29, 0x00, 0x0A, 0x00, 0x0B, 0x00, - 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x3A, 0x02, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 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, 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, 0x0B, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x14, 0x16, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, - 0x04, 0x04, 0x07, 0x07, 0x14, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, - 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, - 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, - 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x00, 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, - 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x30, - 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x48, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, - 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x29, 0x00, 0x09, 0x00, 0x15, 0x00, 0x29, 0x00, - 0x0A, 0x00, 0x0B, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, - 0x3A, 0x02, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, 0x0B, 0x60, 0x18, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, - 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, - 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, - 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, - 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 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, 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, 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, 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, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 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, 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, 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, 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, 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, 0x49, 0x92, 0x24, 0x00, - 0x49, 0x92, 0x24, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x06, 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, 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, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x02, 0x40, 0x13, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 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, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00, - 0x03, 0x03, 0xC3, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x76, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x3D, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x49, 0x00, 0xFF, 0x00, - 0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x12, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0x72, 0x51, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x36, 0x38, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F, 0x43, - 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, 0x37, - 0x5F, 0x56, 0x31, 0x2E, 0x36, 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, - 0xA0, 0x09, 0x01, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70, - 0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x80, 0x18, 0x40, - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 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, 0x0A, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, - 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, 0x0B, 0x08, - 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, - 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x44, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, - 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, - 0xFF, 0x0F, 0xFF, 0x0F, 0x09, 0x03, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, - 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, - 0x11, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x22, 0x00, 0x04, 0x00, - 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, - 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, - 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, - 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48, - 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C, - 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, - 0x04, 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, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, - 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x0A, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x55, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, - 0x44, 0x00, 0x09, 0x00, 0x15, 0x00, 0x44, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x02, 0x03, 0xE0, 0xC1, - 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x09, 0x03, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 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, - 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, 0x11, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, - 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07, - 0x22, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, - 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, - 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 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, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x08, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x02, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, - 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, - 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, 0x15, 0x00, 0x44, 0x00, 0x0A, 0x00, 0x11, 0x00, - 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x09, 0x03, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 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, 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, 0x11, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x14, 0x16, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, - 0x04, 0x04, 0x07, 0x07, 0x22, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, - 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, - 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, - 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x00, 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, - 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x30, - 0x04, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x48, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, - 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, 0x15, 0x00, 0x44, 0x00, - 0x0A, 0x00, 0x11, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, - 0x09, 0x03, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, 0x11, 0x60, 0x18, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x22, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, - 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, - 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, - 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, - 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 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, 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, 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, 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, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 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, 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, 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, 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, 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, 0x49, 0x92, 0x24, 0x00, - 0x49, 0x92, 0x24, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x06, 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, 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, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0xF0, 0x24, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 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, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00, - 0x03, 0x03, 0x63, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xC4, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x25, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x25, 0x00, 0xFF, 0x00, 0x49, 0x00, 0xFF, 0x00, - 0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0A, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0xE0, 0x29, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x30, 0x32, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F, - 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, - 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 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, - 0x70, 0x8E, 0x01, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70, - 0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x18, 0x40, - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 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, 0x0A, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, - 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, 0x0B, 0x08, - 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, - 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x66, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x66, 0x00, 0x0A, 0x00, 0x1A, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, - 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, - 0xFF, 0x0F, 0xFF, 0x0F, 0x0B, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, - 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, - 0x1A, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x32, 0x00, 0x04, 0x00, - 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, - 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, - 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, - 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48, - 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C, - 0x0C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 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, 0x06, 0x00, 0x00, 0x00, - 0x04, 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, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, - 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x8E, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x55, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, - 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, - 0x66, 0x00, 0x09, 0x00, 0x15, 0x00, 0x66, 0x00, 0x0A, 0x00, 0x1A, 0x00, 0x02, 0x03, 0xE0, 0xC1, - 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x0B, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 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, - 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, 0x1A, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, - 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07, - 0x32, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, - 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, - 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, - 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 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, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, - 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, - 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, - 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x06, 0x00, 0x66, 0x00, 0x09, 0x00, 0x15, 0x00, 0x66, 0x00, 0x0A, 0x00, 0x1A, 0x00, - 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, - 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x0B, 0x04, 0x00, 0x80, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x04, 0x04, 0x10, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 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, 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, 0x1A, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x14, 0x14, 0x16, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, - 0x04, 0x04, 0x07, 0x07, 0x32, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, - 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, - 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, - 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, - 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0B, 0x00, 0x00, 0x00, 0x00, 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, - 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x30, - 0x03, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x71, 0x71, 0x03, 0x48, 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91, - 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 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, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, - 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x14, 0x00, 0x14, 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, 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, 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, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, - 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x66, 0x00, 0x09, 0x00, 0x15, 0x00, 0x66, 0x00, - 0x0A, 0x00, 0x1A, 0x00, 0x02, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, - 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, - 0x0B, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, - 0x04, 0x04, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 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, 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, 0x1A, 0x60, 0x18, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x32, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, - 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, - 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, - 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, - 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 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, 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, 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, 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, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x10, 0x00, 0x14, 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, 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, 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, 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, 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, 0x49, 0x92, 0x24, 0x00, - 0x49, 0x92, 0x24, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 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, 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, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x50, 0x33, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 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, 0x08, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00, - 0x03, 0x03, 0x03, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, - 0x1A, 0x00, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x26, 0x01, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x18, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x18, 0x00, 0xFF, 0x00, 0x49, 0x00, 0xFE, 0x00, - 0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xDA, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x06, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0xEA, 0x1A, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x32, 0x30, 0x34, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/modules/hekate_libsys_minerva/mtc_table.h b/modules/hekate_libsys_minerva/mtc_table.h index d66d0dd..f6aa716 100644 --- a/modules/hekate_libsys_minerva/mtc_table.h +++ b/modules/hekate_libsys_minerva/mtc_table.h @@ -24,8 +24,8 @@ typedef struct { - s32 pll_osc_in; - s32 pll_out; + u32 pll_osc_in; + u32 pll_out; u32 pll_feedback_div; u32 pll_input_div; u32 pll_post_div; @@ -33,230 +33,229 @@ typedef struct typedef struct { - u32 emc_rc_idx; - u32 emc_rfc_idx; - u32 emc_rfcpb_idx; - u32 emc_refctrl2_idx; - u32 emc_rfc_slr_idx; - u32 emc_ras_idx; - u32 emc_rp_idx; - u32 emc_r2w_idx; - u32 emc_w2r_idx; - u32 emc_r2p_idx; - u32 emc_w2p_idx; - u32 emc_r2r_idx; - u32 emc_tppd_idx; - u32 emc_ccdmw_idx; - u32 emc_rd_rcd_idx; - u32 emc_wr_rcd_idx; - u32 emc_rrd_idx; - u32 emc_rext_idx; - u32 emc_wext_idx; - u32 emc_wdv_chk_idx; - u32 emc_wdv_idx; - u32 emc_wsv_idx; - u32 emc_wev_idx; - u32 emc_wdv_mask_idx; - u32 emc_ws_duration_idx; - u32 emc_we_duration_idx; - u32 emc_quse_idx; - u32 emc_quse_width_idx; - u32 emc_ibdly_idx; - u32 emc_obdly_idx; - u32 emc_einput_idx; - u32 emc_mrw6_idx; - u32 emc_einput_duration_idx; - u32 emc_puterm_extra_idx; - u32 emc_puterm_width_idx; - u32 emc_qrst_idx; - u32 emc_qsafe_idx; - u32 emc_rdv_idx; - u32 emc_rdv_mask_idx; - u32 emc_rdv_early_idx; - u32 emc_rdv_early_mask_idx; - u32 emc_refresh_idx; - u32 emc_burst_refresh_num_idx; - u32 emc_pre_refresh_req_cnt_idx; - u32 emc_pdex2wr_idx; - u32 emc_pdex2rd_idx; - u32 emc_pchg2pden_idx; - u32 emc_act2pden_idx; - u32 emc_ar2pden_idx; - u32 emc_rw2pden_idx; - u32 emc_cke2pden_idx; - u32 emc_pdex2cke_idx; - u32 emc_pdex2mrr_idx; - u32 emc_txsr_idx; - u32 emc_txsrdll_idx; - u32 emc_tcke_idx; - u32 emc_tckesr_idx; - u32 emc_tpd_idx; - u32 emc_tfaw_idx; - u32 emc_trpab_idx; - u32 emc_tclkstable_idx; - u32 emc_tclkstop_idx; - u32 emc_mrw7_idx; - u32 emc_trefbw_idx; - u32 emc_odt_write_idx; - u32 emc_fbio_cfg5_idx; - u32 emc_fbio_cfg7_idx; - u32 emc_cfg_dig_dll_idx; - u32 emc_cfg_dig_dll_period_idx; - u32 emc_pmacro_ib_rxrt_idx; - u32 emc_cfg_pipe_1_idx; - u32 emc_cfg_pipe_2_idx; - u32 emc_pmacro_quse_ddll_rank0_4_idx; - u32 emc_pmacro_quse_ddll_rank0_5_idx; - u32 emc_pmacro_quse_ddll_rank1_4_idx; - u32 emc_pmacro_quse_ddll_rank1_5_idx; - u32 emc_mrw8_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx; - u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx; - u32 emc_pmacro_ddll_long_cmd_0_idx; - u32 emc_pmacro_ddll_long_cmd_1_idx; - u32 emc_pmacro_ddll_long_cmd_2_idx; - u32 emc_pmacro_ddll_long_cmd_3_idx; - u32 emc_pmacro_ddll_long_cmd_4_idx; - u32 emc_pmacro_ddll_short_cmd_0_idx; - u32 emc_pmacro_ddll_short_cmd_1_idx; - u32 emc_pmacro_ddll_short_cmd_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx; - u32 emc_txdsrvttgen_idx; - u32 emc_fdpd_ctrl_dq_idx; - u32 emc_fdpd_ctrl_cmd_idx; - u32 emc_fbio_spare_idx; - u32 emc_zcal_interval_idx; - u32 emc_zcal_wait_cnt_idx; - u32 emc_mrs_wait_cnt_idx; - u32 emc_mrs_wait_cnt2_idx; - u32 emc_auto_cal_channel_idx; - u32 emc_dll_cfg_0_idx; - u32 emc_dll_cfg_1_idx; - u32 emc_pmacro_autocal_cfg_common_idx; - u32 emc_pmacro_zctrl_idx; - u32 emc_cfg_idx; - u32 emc_cfg_pipe_idx; - u32 emc_dyn_self_ref_control_idx; - u32 emc_qpop_idx; - u32 emc_dqs_brlshft_0_idx; - u32 emc_dqs_brlshft_1_idx; - u32 emc_cmd_brlshft_2_idx; - u32 emc_cmd_brlshft_3_idx; - u32 emc_pmacro_pad_cfg_ctrl_idx; - u32 emc_pmacro_data_pad_rx_ctrl_idx; - u32 emc_pmacro_cmd_pad_rx_ctrl_idx; - u32 emc_pmacro_data_rx_term_mode_idx; - u32 emc_pmacro_cmd_rx_term_mode_idx; - u32 emc_pmacro_cmd_pad_tx_ctrl_idx; - u32 emc_pmacro_data_pad_tx_ctrl_idx; - u32 emc_pmacro_common_pad_tx_ctrl_idx; - u32 emc_pmacro_vttgen_ctrl_0_idx; - u32 emc_pmacro_vttgen_ctrl_1_idx; - u32 emc_pmacro_vttgen_ctrl_2_idx; - u32 emc_pmacro_brick_ctrl_rfu1_idx; - u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx; - u32 emc_pmacro_brick_ctrl_rfu2_idx; - u32 emc_pmacro_data_brick_ctrl_fdpd_idx; - u32 emc_pmacro_bg_bias_ctrl_0_idx; - u32 emc_cfg_3_idx; - u32 emc_pmacro_tx_pwrd_0_idx; - u32 emc_pmacro_tx_pwrd_1_idx; - u32 emc_pmacro_tx_pwrd_2_idx; - u32 emc_pmacro_tx_pwrd_3_idx; - u32 emc_pmacro_tx_pwrd_4_idx; - u32 emc_pmacro_tx_pwrd_5_idx; - u32 emc_config_sample_delay_idx; - u32 emc_pmacro_tx_sel_clk_src_0_idx; - u32 emc_pmacro_tx_sel_clk_src_1_idx; - u32 emc_pmacro_tx_sel_clk_src_2_idx; - u32 emc_pmacro_tx_sel_clk_src_3_idx; - u32 emc_pmacro_tx_sel_clk_src_4_idx; - u32 emc_pmacro_tx_sel_clk_src_5_idx; - u32 emc_pmacro_ddll_bypass_idx; - u32 emc_pmacro_ddll_pwrd_0_idx; - u32 emc_pmacro_ddll_pwrd_1_idx; - u32 emc_pmacro_ddll_pwrd_2_idx; - u32 emc_pmacro_cmd_ctrl_0_idx; - u32 emc_pmacro_cmd_ctrl_1_idx; - u32 emc_pmacro_cmd_ctrl_2_idx; - u32 emc_tr_timing_0_idx; - u32 emc_tr_dvfs_idx; - u32 emc_tr_ctrl_1_idx; - u32 emc_tr_rdv_idx; - u32 emc_tr_qpop_idx; - u32 emc_tr_rdv_mask_idx; - u32 emc_mrw14_idx; - u32 emc_tr_qsafe_idx; - u32 emc_tr_qrst_idx; - u32 emc_training_ctrl_idx; - u32 emc_training_settle_idx; - u32 emc_training_vref_settle_idx; - u32 emc_training_ca_fine_ctrl_idx; - u32 emc_training_ca_ctrl_misc_idx; - u32 emc_training_ca_ctrl_misc1_idx; - u32 emc_training_ca_vref_ctrl_idx; - u32 emc_training_quse_cors_ctrl_idx; - u32 emc_training_quse_fine_ctrl_idx; - u32 emc_training_quse_ctrl_misc_idx; - u32 emc_training_quse_vref_ctrl_idx; - u32 emc_training_read_fine_ctrl_idx; - u32 emc_training_read_ctrl_misc_idx; - u32 emc_training_read_vref_ctrl_idx; - u32 emc_training_write_fine_ctrl_idx; - u32 emc_training_write_ctrl_misc_idx; - u32 emc_training_write_vref_ctrl_idx; - u32 emc_training_mpc_idx; - u32 emc_mrw15_idx; + u32 emc_rc; + u32 emc_rfc; + u32 emc_rfcpb; + u32 emc_refctrl2; + u32 emc_rfc_slr; + u32 emc_ras; + u32 emc_rp; + u32 emc_r2w; + u32 emc_w2r; + u32 emc_r2p; + u32 emc_w2p; + u32 emc_r2r; + u32 emc_tppd; + u32 emc_ccdmw; + u32 emc_rd_rcd; + u32 emc_wr_rcd; + u32 emc_rrd; + u32 emc_rext; + u32 emc_wext; + u32 emc_wdv_chk; + u32 emc_wdv; + u32 emc_wsv; + u32 emc_wev; + u32 emc_wdv_mask; + u32 emc_ws_duration; + u32 emc_we_duration; + u32 emc_quse; + u32 emc_quse_width; + u32 emc_ibdly; + u32 emc_obdly; + u32 emc_einput; + u32 emc_mrw6; + u32 emc_einput_duration; + u32 emc_puterm_extra; + 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; + u32 emc_refresh; + u32 emc_burst_refresh_num; + u32 emc_pre_refresh_req_cnt; + u32 emc_pdex2wr; + u32 emc_pdex2rd; + u32 emc_pchg2pden; + u32 emc_act2pden; + u32 emc_ar2pden; + u32 emc_rw2pden; + u32 emc_cke2pden; + u32 emc_pdex2cke; + u32 emc_pdex2mrr; + u32 emc_txsr; + u32 emc_txsrdll; + u32 emc_tcke; + u32 emc_tckesr; + u32 emc_tpd; + u32 emc_tfaw; + u32 emc_trpab; + u32 emc_tclkstable; + u32 emc_tclkstop; + u32 emc_mrw7; + u32 emc_trefbw; + u32 emc_odt_write; + u32 emc_fbio_cfg5; + u32 emc_fbio_cfg7; + u32 emc_cfg_dig_dll; + u32 emc_cfg_dig_dll_period; + u32 emc_pmacro_ib_rxrt; + u32 emc_cfg_pipe_1; + u32 emc_cfg_pipe_2; + u32 emc_pmacro_quse_ddll_rank0_4; + u32 emc_pmacro_quse_ddll_rank0_5; + u32 emc_pmacro_quse_ddll_rank1_4; + u32 emc_pmacro_quse_ddll_rank1_5; + u32 emc_mrw8; + 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_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; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3; + u32 emc_txdsrvttgen; + u32 emc_fdpd_ctrl_dq; + u32 emc_fdpd_ctrl_cmd; + u32 emc_fbio_spare; + u32 emc_zcal_interval; + u32 emc_zcal_wait_cnt; + u32 emc_mrs_wait_cnt; + u32 emc_mrs_wait_cnt2; + u32 emc_auto_cal_channel; + u32 emc_dll_cfg_0; + u32 emc_dll_cfg_1; + u32 emc_pmacro_autocal_cfg_common; + u32 emc_pmacro_zctrl; + u32 emc_cfg; + u32 emc_cfg_pipe; + u32 emc_dyn_self_ref_control; + u32 emc_qpop; + u32 emc_dqs_brlshft_0; + u32 emc_dqs_brlshft_1; + u32 emc_cmd_brlshft_2; + u32 emc_cmd_brlshft_3; + u32 emc_pmacro_pad_cfg_ctrl; + 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_cmd_pad_tx_ctrl; + u32 emc_pmacro_data_pad_tx_ctrl; + u32 emc_pmacro_common_pad_tx_ctrl; + u32 emc_pmacro_vttgen_ctrl_0; + u32 emc_pmacro_vttgen_ctrl_1; + u32 emc_pmacro_vttgen_ctrl_2; + 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_ctrl_0; + u32 emc_cfg_3; + u32 emc_pmacro_tx_pwrd_0; + u32 emc_pmacro_tx_pwrd_1; + u32 emc_pmacro_tx_pwrd_2; + u32 emc_pmacro_tx_pwrd_3; + u32 emc_pmacro_tx_pwrd_4; + u32 emc_pmacro_tx_pwrd_5; + u32 emc_config_sample_delay; + u32 emc_pmacro_tx_sel_clk_src_0; + u32 emc_pmacro_tx_sel_clk_src_1; + u32 emc_pmacro_tx_sel_clk_src_2; + u32 emc_pmacro_tx_sel_clk_src_3; + u32 emc_pmacro_tx_sel_clk_src_4; + u32 emc_pmacro_tx_sel_clk_src_5; + u32 emc_pmacro_ddll_bypass; + u32 emc_pmacro_ddll_pwrd_0; + u32 emc_pmacro_ddll_pwrd_1; + u32 emc_pmacro_ddll_pwrd_2; + u32 emc_pmacro_cmd_ctrl_0; + u32 emc_pmacro_cmd_ctrl_1; + u32 emc_pmacro_cmd_ctrl_2; + u32 emc_tr_timing_0; + u32 emc_tr_dvfs; + u32 emc_tr_ctrl_1; + u32 emc_tr_rdv; + u32 emc_tr_qpop; + u32 emc_tr_rdv_mask; + u32 emc_mrw14; + u32 emc_tr_qsafe; + u32 emc_tr_qrst; + u32 emc_training_ctrl; + u32 emc_training_settle; + u32 emc_training_vref_settle; + u32 emc_training_ca_fine_ctrl; + u32 emc_training_ca_ctrl_misc; + u32 emc_training_ca_ctrl_misc1; + u32 emc_training_ca_vref_ctrl; + u32 emc_training_quse_cors_ctrl; + u32 emc_training_quse_fine_ctrl; + u32 emc_training_quse_ctrl_misc; + u32 emc_training_quse_vref_ctrl; + u32 emc_training_read_fine_ctrl; + u32 emc_training_read_ctrl_misc; + u32 emc_training_read_vref_ctrl; + u32 emc_training_write_fine_ctrl; + u32 emc_training_write_ctrl_misc; + u32 emc_training_write_vref_ctrl; + u32 emc_training_mpc; + u32 emc_mrw15; } burst_regs_t; - typedef struct { u32 burst_regs[221]; @@ -268,186 +267,186 @@ typedef struct typedef struct { - u32 ptfv_dqsosc_movavg_c0d0u0_idx; - u32 ptfv_dqsosc_movavg_c0d0u1_idx; - u32 ptfv_dqsosc_movavg_c0d1u0_idx; - u32 ptfv_dqsosc_movavg_c0d1u1_idx; - u32 ptfv_dqsosc_movavg_c1d0u0_idx; - u32 ptfv_dqsosc_movavg_c1d0u1_idx; - u32 ptfv_dqsosc_movavg_c1d1u0_idx; - u32 ptfv_dqsosc_movavg_c1d1u1_idx; - u32 ptfv_write_samples_idx; - u32 ptfv_dvfs_samples_idx; - u32 ptfv_movavg_weight_idx; - u32 ptfv_config_ctrl_idx; + u32 ptfv_dqsosc_movavg_c0d0u0; + u32 ptfv_dqsosc_movavg_c0d0u1; + u32 ptfv_dqsosc_movavg_c0d1u0; + u32 ptfv_dqsosc_movavg_c0d1u1; + u32 ptfv_dqsosc_movavg_c1d0u0; + u32 ptfv_dqsosc_movavg_c1d0u1; + u32 ptfv_dqsosc_movavg_c1d1u0; + u32 ptfv_dqsosc_movavg_c1d1u1; + u32 ptfv_write_samples; + u32 ptfv_dvfs_samples; + u32 ptfv_movavg_weight; + u32 ptfv_config_ctrl; } ptfv_list_table_t; typedef struct { - u32 emc0_mrw10_idx; - u32 emc1_mrw10_idx; - u32 emc0_mrw11_idx; - u32 emc1_mrw11_idx; - u32 emc0_mrw12_idx; - u32 emc1_mrw12_idx; - u32 emc0_mrw13_idx; - u32 emc1_mrw13_idx; + u32 emc0_mrw10; + u32 emc1_mrw10; + u32 emc0_mrw11; + u32 emc1_mrw11; + u32 emc0_mrw12; + u32 emc1_mrw12; + u32 emc0_mrw13; + u32 emc1_mrw13; } burst_reg_per_ch_t; typedef struct { - u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx; - u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx; - u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx; - u32 emc_pmacro_ib_vref_dqs_0_idx; - u32 emc_pmacro_ib_vref_dqs_1_idx; - u32 emc_pmacro_ib_vref_dq_0_idx; - u32 emc_pmacro_ib_vref_dq_1_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx; - u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx; - u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx; - u32 emc_pmacro_quse_ddll_rank0_0_idx; - u32 emc_pmacro_quse_ddll_rank0_1_idx; - u32 emc_pmacro_quse_ddll_rank0_2_idx; - u32 emc_pmacro_quse_ddll_rank0_3_idx; - u32 emc_pmacro_quse_ddll_rank1_0_idx; - u32 emc_pmacro_quse_ddll_rank1_1_idx; - u32 emc_pmacro_quse_ddll_rank1_2_idx; - u32 emc_pmacro_quse_ddll_rank1_3_idx; + 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_ib_ddll_short_dq_rank0_byte0_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1; + u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1; + u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2; + u32 emc_pmacro_ib_vref_dqs_0; + u32 emc_pmacro_ib_vref_dqs_1; + u32 emc_pmacro_ib_vref_dq_0; + u32 emc_pmacro_ib_vref_dq_1; + 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_short_dq_rank0_byte0_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1; + u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1; + u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2; + 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_rank1_0; + u32 emc_pmacro_quse_ddll_rank1_1; + u32 emc_pmacro_quse_ddll_rank1_2; + u32 emc_pmacro_quse_ddll_rank1_3; } trim_regs_t; typedef struct { - u32 emc_cmd_brlshft_0_idx; - u32 emc_cmd_brlshft_1_idx; - u32 emc0_data_brlshft_0_idx; - u32 emc1_data_brlshft_0_idx; - u32 emc0_data_brlshft_1_idx; - u32 emc1_data_brlshft_1_idx; - u32 emc_quse_brlshft_0_idx; - u32 emc_quse_brlshft_1_idx; - u32 emc_quse_brlshft_2_idx; - u32 emc_quse_brlshft_3_idx; + u32 emc_cmd_brlshft_0; + u32 emc_cmd_brlshft_1; + u32 emc0_data_brlshft_0; + u32 emc1_data_brlshft_0; + u32 emc0_data_brlshft_1; + u32 emc1_data_brlshft_1; + u32 emc_quse_brlshft_0; + u32 emc_quse_brlshft_1; + u32 emc_quse_brlshft_2; + u32 emc_quse_brlshft_3; } trim_perch_regs_t; typedef struct @@ -461,10 +460,10 @@ typedef struct typedef struct { - u32 emc0_training_opt_dqs_ib_vref_rank0_idx; - u32 emc1_training_opt_dqs_ib_vref_rank0_idx; - u32 emc0_training_opt_dqs_ib_vref_rank1_idx; - u32 emc1_training_opt_dqs_ib_vref_rank1_idx; + u32 emc0_training_opt_dqs_ib_vref_rank0; + u32 emc1_training_opt_dqs_ib_vref_rank0; + u32 emc0_training_opt_dqs_ib_vref_rank1; + u32 emc1_training_opt_dqs_ib_vref_rank1; } vref_perch_regs_t; typedef struct diff --git a/modules/hekate_libsys_minerva/sys_sdrammtc.c b/modules/hekate_libsys_minerva/sys_sdrammtc.c index 9b83b27..f447501 100644 --- a/modules/hekate_libsys_minerva/sys_sdrammtc.c +++ b/modules/hekate_libsys_minerva/sys_sdrammtc.c @@ -2,7 +2,7 @@ * Minerva Training Cell * DRAM Training for Tegra X1 SoC. Supports LPDDR4. * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,13 +23,17 @@ #include "mtc_mc_emc_regs.h" #include "mtc_switch_tables.h" #include "types.h" -#include "../../common/common_module.h" +#include #define EPRINTF(...) #define EPRINTFARGS(...) -bool emc_2X_clk_src_is_pllmb; -bool fsp_for_src_freq; +#define MAX_FREQ_T210 1600000 +//#define OVERCLOCK_FREQ 1862400 +//#define OVERCLOCK_VOLTAGE 1200000 // Default is 1100mV and in HOS 1125mV. + +#define PERF_HACK + bool train_ram_patterns; /* @@ -61,20 +65,38 @@ bool train_ram_patterns; static pllm_clk_config_t pllm_clk_config_table[] = { // pll_osc_in, pll_out, pll_feedback_div, pll_input_div, pll_post_div. - {38400, 297600, 93, 4, 2}, // ((38400 / 4) * 93) / 3 - {38400, 400000, 125, 4, 2}, // ((38400 / 4) * 125) / 3 - {38400, 408000, 85, 4, 1}, // ((38400 / 4) * 85) / 2 - {38400, 532800, 111, 4, 1}, // ((38400 / 4) * 111) / 2 - {38400, 665600, 104, 3, 1}, // ((38400 / 3) * 104) / 2 - {38400, 800000, 125, 3, 1}, // ((38400 / 3) * 125) / 2 - {38400, 931200, 97, 4, 0}, // (38400 / 4) * 97 - {38400, 1065600, 111, 4, 0}, // (38400 / 4) * 111 - {38400, 1200000, 125, 4, 0}, // (38400 / 4) * 125 - {38400, 1331200, 104, 3, 0}, // (38400 / 3) * 104 - {38400, 1459200, 76, 2, 0}, // (38400 / 2) * 76 - {38400, 1600000, 125, 3, 0}, // (38400 / 3) * 125 - {38400, 1862400, 97, 2, 0}, // (38400 / 2) * 97 - {38400, 2131200, 111, 2, 0}, // (38400 / 2) * 111 + // f_in, f_out, n, m, p. + // f_out = ((f_in / m) * n) / p. Example: 1600000 = (38400 / 2) * 97. + {38400, 297600, 93, 4, 2}, + {38400, 400000, 125, 4, 2}, + {38400, 408000, 85, 4, 1}, + {38400, 532800, 111, 4, 1}, + {38400, 665600, 104, 3, 1}, + {38400, 800000, 125, 3, 1}, + {38400, 931200, 97, 4, 0}, + {38400, 1065600, 111, 4, 0}, + {38400, 1200000, 125, 4, 0}, + {38400, 1331200, 104, 3, 0}, + {38400, 1459200, 76, 2, 0}, + {38400, 1600000, 125, 3, 0}, + {38400, 1728000, 90, 2, 0}, // Custom. Normalized 1733 MHz. + {38400, 1795200, 187, 4, 0}, // Custom. Normalized 1800 MHz. + {38400, 1862400, 97, 2, 0}, // JEDEC Standard. (T210 official max). + {38400, 1894400, 148, 3, 0}, // Custom. Normalized 1900 MHz. + {38400, 1932800, 151, 3, 0}, // Custom. Normalized 1933 MHz. + {38400, 1958400, 102, 2, 0}, // Custom. Normalized 1966 MHz. + {38400, 1996800, 104, 2, 0}, // Custom. Normalized 2000 MHz. + {38400, 2035200, 106, 2, 0}, // Custom. Normalized 2033 MHz. + {38400, 2064000, 215, 4, 0}, // Custom. Normalized 2066 MHz. + {38400, 2099200, 164, 3, 0}, // Custom. Normalized 2100 MHz. + {38400, 2131200, 111, 2, 0}, // JEDEC Standard. (T210B01 official max). + {38400, 2163200, 169, 3, 0}, // Custom. Normalized 2166 MHz. + {38400, 2188800, 114, 2, 0}, // Custom. Normalized 2200 MHz. + {38400, 2227200, 116, 2, 0}, // Custom. Normalized 2233 MHz. + {38400, 2265600, 118, 2, 0}, // Custom. Normalized 2266 MHz. + {38400, 2291200, 179, 3, 0}, // Custom. Normalized 2300 MHz. + {38400, 2329600, 182, 3, 0}, // Custom. Normalized 2333 MHz. + {38400, 2361600, 123, 2, 0}, // Custom. Normalized 2366 MHz. {0, 0, 0, 0, 0} }; @@ -1061,11 +1083,11 @@ static void _ccfifo_write(u32 addr, u32 data_val, u32 delay) //addr and delay ar EMC(EMC_CCFIFO_ADDR) = (addr & 0xffff) | ((delay & 0x7FFF) << 16) | (1 << 31); } -static bool _wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) +static bool _wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, u32 emc_channel) { bool err = true; - for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++) + for (u32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++) { if (emc_channel) { @@ -1093,39 +1115,38 @@ done: static void _request_mmr_data(u32 data, bool dual_channel) { EMC(EMC_MRR) = data; - _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CH0); + _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CHANNEL0); if (dual_channel) - _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CH1); + _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CHANNEL1); } -static u32 _start_periodic_compensation() +static void _start_periodic_compensation() { EMC(EMC_MPC) = 0x4B; - - return EMC(EMC_MPC); + (void)EMC(EMC_MPC); } -static bool _timing_update(s32 dual_channel) +static bool _timing_update(u32 dual_channel) { bool err = 0; EMC(EMC_TIMING_CONTROL) = 1; - err = _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CH0); + err = _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CHANNEL0); if (dual_channel) - err |= _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CH1); + err |= _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CHANNEL1); return err; } -static s32 _get_dram_temperature() +static u32 _get_dram_temperature() { - s32 mr4_0 = 0; - s32 mr4_1 = 0; + u32 mr4_0 = 0; + u32 mr4_1 = 0; bool channel1_enabled = (EMC(EMC_FBIO_CFG7) >> 2) & 1; u32 emc_cfg_o = EMC(EMC_CFG); - _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, false, EMC_CH0); + _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, false, EMC_CHANNEL0); if (emc_cfg_o & 0x20000000) { @@ -1133,7 +1154,7 @@ static s32 _get_dram_temperature() _timing_update(channel1_enabled); } - _request_mmr_data(0x80040000, EMC_CH0); + _request_mmr_data(0x80040000, EMC_CHANNEL0); mr4_0 = EMC(EMC_MRR) & 0xFFFF; if (mr4_0 < 0xF001) @@ -1146,8 +1167,8 @@ static s32 _get_dram_temperature() if (channel1_enabled) { - _request_mmr_data(0x40040000, EMC_CH1); - mr4_1 = EMC(EMC_MRR); + _request_mmr_data(0x40040000, EMC_CHANNEL1); + mr4_1 = EMC(EMC_MRR) & 0xFFFF; if (mr4_1 < 0xF001) mr4_1 &= 0x7; @@ -1168,25 +1189,24 @@ out: return mr4_0; } -static u32 _pllm_clk_base_cfg(s32 rate_KHz, u32 clk_src_emc, s32 emc_2X_clk_src_is_PLLMB) +static u32 _pllm_clk_base_cfg(u32 rate_KHz, u32 clk_src_emc, bool new_src_is_PLLMB) { u32 dividers = 0; - s32 i = 0; - s32 pll_ref = 38400; // Only 38.4MHz crystal is supported for T210. + u32 i = 0; + u32 pll_ref = 38400; // Only 38.4MHz crystal is supported for T210. - pllm_clk_config_t *pllm_clk_config; + pllm_clk_config_t *pllm_clk_config = NULL; for (i = 0; pllm_clk_config_table[i].pll_osc_in; i++) { - if (pllm_clk_config_table[i].pll_osc_in == pll_ref && pllm_clk_config_table[i].pll_out == rate_KHz) - break; + if (pllm_clk_config_table[i].pll_osc_in == pll_ref && (pllm_clk_config_table[i].pll_out - 19200) <= rate_KHz) + pllm_clk_config = &pllm_clk_config_table[i]; } - pllm_clk_config = &pllm_clk_config_table[i]; - if (pllm_clk_config->pll_osc_in) + if (pllm_clk_config && pllm_clk_config->pll_osc_in) { dividers = pllm_clk_config->pll_input_div | (pllm_clk_config->pll_feedback_div << 8) | ((pllm_clk_config->pll_post_div & 0x1F) << 20); - if (emc_2X_clk_src_is_PLLMB) + if (new_src_is_PLLMB) { CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) = dividers; CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) |= PLLM_ENABLE; @@ -1229,22 +1249,24 @@ static void _change_dll_src(emc_table_t *mtc_table_entry, u32 clk_src_emc) CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = dll_setting; - //OLD - u32 clk_enb_emc_dll = ((mtc_table_entry->clk_out_enb_x_0_clk_enb_emc_dll & 1) << 14) | (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) & 0xFFFFBFFF); - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = clk_enb_emc_dll; + // Commit clock write. + (void)CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X); + _usleep(2); - //NEW - // _usleep(2); - // if (mtc_table_entry->clk_out_enb_x_0_clk_enb_emc_dll) - // CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) |= 0x4000; - // else - // CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_CLR) |= 0x4000; - // _usleep(2); + // Enable/Disable EMC DLL. + if (mtc_table_entry->clk_out_enb_x_0_clk_enb_emc_dll) + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (1 << 14); + else + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_CLR) = (1 << 14); + + // Commit clock write. + (void)CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X); + _usleep(2); } static u32 _digital_dll_prelock(emc_table_t *mtc_table_entry, u32 needs_tristate_training, u32 selected_clk_src_emc) { - s32 dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); + u32 dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFF824) | 0x3C8; @@ -1256,8 +1278,8 @@ static u32 _digital_dll_prelock(emc_table_t *mtc_table_entry, u32 needs_tristate while (EMC_CH1(EMC_CFG_DIG_DLL) & 1) ; - EMC(EMC_DLL_CFG_0) = mtc_table_entry->burst_regs.emc_dll_cfg_0_idx; - EMC(EMC_DLL_CFG_1) = mtc_table_entry->burst_regs.emc_dll_cfg_1_idx; + EMC(EMC_DLL_CFG_0) = mtc_table_entry->burst_regs.emc_dll_cfg_0; + EMC(EMC_DLL_CFG_1) = mtc_table_entry->burst_regs.emc_dll_cfg_1; _change_dll_src(mtc_table_entry, selected_clk_src_emc); @@ -1305,20 +1327,7 @@ static void _digital_dll_disable() ; } -static void _digital_dll_enable(s32 channel1_enabled) -{ - EMC(EMC_CFG_DIG_DLL) |= 1; - - _timing_update(channel1_enabled); - - while (!(EMC(EMC_CFG_DIG_DLL) & 1)) - ; - if (channel1_enabled) - while (!(EMC_CH1(EMC_CFG_DIG_DLL) & 1)) - ; -} - -static void _digital_dll_enable_rs(s32 channel1_enabled) +static void _digital_dll_enable_rs(u32 channel1_enabled) { EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x89; @@ -1331,7 +1340,7 @@ static void _digital_dll_enable_rs(s32 channel1_enabled) ; } -static u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, s32 src_clock_period) +static u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, u32 src_clock_period) { u32 pmacro_cmd_pad; u32 pmacro_rfu1; @@ -1343,24 +1352,24 @@ static u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_ if (flip_backward) { - pmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = dst_emc_table_entry->burst_regs.emc_fbio_cfg5; + pmacro_common_tx = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl; } else { - pmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = (dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0x101) | src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = src_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = (dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x101) | src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = src_emc_table_entry->burst_regs.emc_fbio_cfg5; + pmacro_common_tx = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl; } u32 pmacro_cmd_pad_drvforceon = pmacro_cmd_pad | 0x4000000; - u32 ramp_down_wait = src_clock_period * 12 / 1000; + u32 ramp_down_wait = src_clock_period * 12; _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_drvforceon, 0); _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 | 0x100, 12); @@ -1368,23 +1377,21 @@ static u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_ if (src_clock_period >= 1000) // Dvfs high speed threshold. { _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xF800F800, (u32)(src_clk_per_pc + 19)); - ramp_down_wait = ramp_down_wait + 100 + (src_clock_period * 20 / 1000); + ramp_down_wait += 100000 + (src_clock_period * 20); } else { - ramp_down_wait += 100; if (src_clock_period >= 416) // Iobrick dcc threshold. _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, (u32)src_clk_per_pc); else { pmacro_dq_pad = (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200; - pmacro_cmd_pad_drvforceon = (pmacro_cmd_pad & 0xFEFEFDFD) | 0x4010200; + pmacro_cmd_pad_drvforceon = (pmacro_cmd_pad & 0xFAFEFDFD) | 0x4010200; _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_drvforceon, (u32)src_clk_per_pc); _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, 0); } - - ramp_down_wait += 200; + ramp_down_wait += 300000; _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, (u32)src_clk_per_pc); if (src_clock_period >= 416) // Iobrick dcc threshold. @@ -1401,16 +1408,16 @@ static u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_ _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xFFFFFFF0, (u32)src_clk_per_pc); else { - ramp_down_wait += 400; + ramp_down_wait += 400000; _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xFFFFFFFA, (u32)src_clk_per_pc); _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xFFFFFFF0, (u32)src_clk_per_pc); - _ccfifo_write(0, 0, (u32)src_clk_per_pc); + _ccfifo_write(EMC_INTSTATUS, 0, (u32)src_clk_per_pc); } return ramp_down_wait; } -static u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, u8 needs_training, s32 dst_clock_period) +static u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, u32 needs_training, u32 dst_clock_period) { u32 pmacro_cmd_pad; u32 pmacro_dq_pad; @@ -1424,46 +1431,46 @@ static u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_en if (flip_backward) { - pmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = src_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = src_emc_table_entry->burst_regs.emc_fbio_cfg5; + pmacro_common_tx = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl; } - else if (needs_training & 3) + else if (needs_training & NEEDS_TRAINING_CA_COMBO) { - pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->shadow_regs_ca_train.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = dst_emc_table_entry->shadow_regs_ca_train.emc_fbio_cfg5; + pmacro_common_tx = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_common_pad_tx_ctrl; } - else if (needs_training & 0xC) + else if (needs_training & NEEDS_TRAINING_QUSE_COMBO) { - pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->shadow_regs_quse_train.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = dst_emc_table_entry->shadow_regs_quse_train.emc_fbio_cfg5; + pmacro_common_tx = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_common_pad_tx_ctrl; } - else if (needs_training & 0xF0) + else if (needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO)) { - pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->shadow_regs_rdwr_train.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = dst_emc_table_entry->shadow_regs_rdwr_train.emc_fbio_cfg5; + pmacro_common_tx = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_common_pad_tx_ctrl; } else { - pmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; + pmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; + pmacro_dq_pad = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl; + pmacro_rfu1 = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1; + pmacro_cfg5 = dst_emc_table_entry->burst_regs.emc_fbio_cfg5; + pmacro_common_tx = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl; } - pmacro_cmd_pad_data = (pmacro_cmd_pad & 0xFEFEFDFD) | 0x4000000; + pmacro_cmd_pad_data = (pmacro_cmd_pad & 0xFAFEFDFD) | 0x4000000; if (dst_clock_period >= 1666) // Dvfs mid speed threshold. { @@ -1472,50 +1479,46 @@ static u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_en _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x600, 0); _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, 12); - ramp_up_wait = (dst_clock_period * 12) / 1000 + 0; + ramp_up_wait = (dst_clock_period * 12) + 0; } else { _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xA, 0); - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xF, (u32)dst_clk_per_pc); + _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xF, dst_clk_per_pc); if (dst_clock_period < 1000) // Dvfs high speed threshold. { if (dst_clock_period >= 416) // Iobrick dcc threshold. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, (u32)dst_clk_per_pc); + _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, dst_clk_per_pc); else { - pmacro_cmd_pad_data = (pmacro_cmd_pad & 0xFEFEFDFD) | 0x4010200; - pmacro_dq_pad = (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200; - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); + _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, (pmacro_cmd_pad & 0xFAFEFDFD) | 0x4010200, dst_clk_per_pc); + _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200, 0); _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, 0); } - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, (u32)dst_clk_per_pc); + _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, dst_clk_per_pc); if (dst_clock_period >= 416) // Iobrick dcc threshold. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, (u32)dst_clk_per_pc); + _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, dst_clk_per_pc); else { - pmacro_cmd_pad_data |= 0x1010202u; - pmacro_dq_pad |= 0x1010202; - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); + pmacro_cmd_pad_data = pmacro_cmd_pad | 0x5010202; + _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data, dst_clk_per_pc); + _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad | 0x1010202, 0); _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, 0); } - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, (u32)(dst_clk_per_pc + 9)); - - ramp_up_wait = 500 + (dst_clock_period * 10) / 1000; + ramp_up_wait = 500000 + (dst_clock_period * 10); } else // 1000 > dst_clock_period < 1666. { - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x6000600, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, (u32)(dst_clk_per_pc + 9)); + _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x6000600, dst_clk_per_pc); - ramp_up_wait = 200 + (dst_clock_period * 10) / 1000; + ramp_up_wait = 200000 + (dst_clock_period * 10); } + + _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, dst_clk_per_pc + 9); } _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data & 0xFBFFFFFF, 5); @@ -1523,113 +1526,108 @@ static u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_en return ramp_up_wait; } -static u32 _minerva_update_clock_tree_delay(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, s32 dram_dev_num, s32 channel1_enabled, enum tree_update_mode_t update_type) +static u32 _minerva_update_clock_tree_delay(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 dram_dev_num, u32 channel1_enabled, enum tree_update_mode_t update_type) { - s32 temp_ch0_0 = 0; - s32 temp_ch0_1 = 0; - s32 temp_ch1_0 = 0; - s32 temp_ch1_1 = 0; - - s32 dst_rate_mhz; - u32 cval = 0; - s32 tdel0_0 = 0; - s32 tdel0_1 = 0; - s32 tdel1_0 = 0; - s32 tdel1_1 = 0; - s32 tmp_tdel0_0 = 0; + u32 adelta = 0; + s32 tdelta = 0; + + u32 temp_ch0_0 = 0; + u32 temp_ch0_1 = 0; + u32 temp_ch1_0 = 0; + u32 temp_ch1_1 = 0; - temp_ch0_0 = 0x10624DD3; // div 1000 denominator - temp_ch0_1 = dst_emc_entry->rate_khz; - dst_rate_mhz = dst_emc_entry->rate_khz / 1000; u32 upd_type_bits = 1 << update_type; + u32 dst_rate_mhz = dst_emc_entry->rate_khz / 1000; + u32 src_rate_mhz = src_emc_entry->rate_khz / 1000; - u32 tval = 1000 * (1000 * _actual_osc_clocks(src_emc_entry->run_clocks) / (src_emc_entry->rate_khz / 1000)); - if (update_type <= PERIODIC_TRAINING_UPDATE) + u32 tval = 1000000 * _actual_osc_clocks(src_emc_entry->run_clocks) / 2; + + if (update_type > PERIODIC_TRAINING_UPDATE) + return 0; + + if (upd_type_bits & 0x5400) { - temp_ch0_1 = 1 << update_type; - temp_ch0_0 = 0x5400; - if (upd_type_bits & 0x5400) + _request_mmr_data(0x80130000, channel1_enabled); // Dev0 MRR 19. + u32 mrr = EMC(EMC_MRR); + temp_ch0_0 = (mrr & 0xFF) << 8; + temp_ch0_1 = mrr & 0xFF00; + if (channel1_enabled) { - _request_mmr_data(0x80130000, channel1_enabled); // Dev0 MRR 19. - temp_ch0_0 = (EMC(EMC_MRR) & 0xFF) << 8; - temp_ch0_1 = EMC(EMC_MRR) & 0xFF00; - if (channel1_enabled) - { - temp_ch1_0 = (EMC_CH1(EMC_MRR) & 0xFF) << 8; - temp_ch1_1 = EMC_CH1(EMC_MRR) & 0xFF00; - } + mrr = EMC_CH1(EMC_MRR); + temp_ch1_0 = (mrr & 0xFF) << 8; + temp_ch1_1 = mrr & 0xFF00; + } - _request_mmr_data(0x80120000, channel1_enabled); // Dev0 MRR 18. - temp_ch0_0 |= EMC(EMC_MRR) & 0xFF; - temp_ch0_1 |= (EMC(EMC_MRR) & 0xFF00) >> 8; - if (channel1_enabled) - { - temp_ch1_0 |= EMC_CH1(EMC_MRR) & 0xFF; - temp_ch1_1 |= (EMC_CH1(EMC_MRR) & 0xFF00) >> 8; - } + _request_mmr_data(0x80120000, channel1_enabled); // Dev0 MRR 18. + mrr = EMC(EMC_MRR); + temp_ch0_0 |= mrr & 0xFF; + temp_ch0_1 |= (mrr & 0xFF00) >> 8; + if (channel1_enabled) + { + mrr = EMC_CH1(EMC_MRR); + temp_ch1_0 |= mrr & 0xFF; + temp_ch1_1 |= (mrr & 0xFF00) >> 8; } } - //u32 delay = (u64)((u64)_actual_osc_clocks(src_emc_entry->run_clocks) * 1000000) / (u64)(src_emc_entry->rate_khz * 2); - cval = tval / (2 * temp_ch0_0); + cval = tval / (src_rate_mhz * temp_ch0_0); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx += 100 * cval; - tdel0_0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_td0_0; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: - tdel0_0 = 0; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_td0_0; break; } - tdel0_0 = dst_emc_entry->current_dram_clktree_c0d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / 100); - if (tdel0_0 < 0) - tdel0_0 = !tdel0_0; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel0_0 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c0d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / 100); + if (tdelta < 0) + tdelta *= -1; + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / 100; calc_td0_0: - cval = tval / (2 * temp_ch0_1); + cval = tval / (src_rate_mhz * temp_ch0_1); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_td1_0; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1637,38 +1635,38 @@ calc_td0_0: break; } - tdel0_1 = dst_emc_entry->current_dram_clktree_c0d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / 100); - if (tdel0_1 < 0) - tdel0_1 = !tdel0_1; - if (tdel0_1 > tdel0_0) - tdel0_0 = tdel0_1; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel0_1 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c0d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c0d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / 100; calc_td1_0: if (channel1_enabled) { - cval = tval / (2 * temp_ch1_0); + cval = tval / (src_rate_mhz * temp_ch1_0); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_td1_1; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1676,36 +1674,36 @@ calc_td1_0: break; } - tdel1_0 = dst_emc_entry->current_dram_clktree_c1d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / 100); - if (tdel1_0 < 0) - tdel1_0 = !tdel1_0; - if (tdel1_0 > tdel0_0) - tdel0_0 = tdel1_0; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel1_0 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c1d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c1d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / 100; calc_td1_1: - cval = tval / (2 * temp_ch1_1); + cval = tval / (src_rate_mhz * temp_ch1_1); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_dev2; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1713,13 +1711,13 @@ calc_td1_1: break; } - tdel1_1 = dst_emc_entry->current_dram_clktree_c1d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / 100); - if (tdel1_1 < 0) - tdel1_1 = !tdel1_1; - if (tdel1_1 > tdel0_0) - tdel0_0 = tdel1_1; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel1_1 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c1d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c1d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / 100; } calc_dev2: @@ -1729,45 +1727,49 @@ calc_dev2: if (update_type <= PERIODIC_TRAINING_UPDATE && upd_type_bits & 0x5400) { _request_mmr_data(0x40130000, channel1_enabled); // Dev1 MRR 19. - temp_ch0_0 = (EMC(EMC_MRR) & 0xFF) << 8; - temp_ch0_1 = EMC(EMC_MRR) & 0xFF00; + u32 mrr = EMC(EMC_MRR); + temp_ch0_0 = (mrr& 0xFF) << 8; + temp_ch0_1 = mrr & 0xFF00; if (channel1_enabled) { - temp_ch1_0 = (EMC_CH1(EMC_MRR) & 0xFF) << 8; - temp_ch1_1 = EMC_CH1(EMC_MRR) & 0xFF00; + mrr = EMC_CH1(EMC_MRR); + temp_ch1_0 = (mrr & 0xFF) << 8; + temp_ch1_1 = mrr & 0xFF00; } _request_mmr_data(0x40120000, channel1_enabled); // Dev1 MRR 18 - temp_ch0_0 |= EMC(EMC_MRR) & 0xFF; - temp_ch0_1 |= ((EMC(EMC_MRR) & 0xFF00) >> 8); + mrr = EMC(EMC_MRR); + temp_ch0_0 |= mrr & 0xFF; + temp_ch0_1 |= ((mrr & 0xFF00) >> 8); if (channel1_enabled) { - temp_ch1_0 |= EMC_CH1(EMC_MRR) & 0xFF; - temp_ch1_1 |= (EMC_CH1(EMC_MRR) & 0xFF00) >> 8; + mrr = EMC_CH1(EMC_MRR); + temp_ch1_0 |= mrr & 0xFF; + temp_ch1_1 |= (mrr & 0xFF00) >> 8; } } - cval = tval / (2 * temp_ch0_0); + cval = tval / (src_rate_mhz * temp_ch0_0); switch (update_type ) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_tmp_td0_1; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1775,36 +1777,36 @@ calc_dev2: break; } - tmp_tdel0_0 = dst_emc_entry->current_dram_clktree_c0d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / 100); - if (tmp_tdel0_0 < 0) - tmp_tdel0_0 = !tmp_tdel0_0; - if (tmp_tdel0_0 > tdel0_0) - tdel0_0 = tmp_tdel0_0; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tmp_tdel0_0 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c0d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c0d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / 100; calc_tmp_td0_1: - cval = tval / (2 * temp_ch0_1); + cval = tval / (src_rate_mhz * temp_ch0_1); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_tmp_td1_0; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1812,38 +1814,38 @@ calc_tmp_td0_1: break; } - tdel0_1 = dst_emc_entry->current_dram_clktree_c0d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / 100); - if (tdel0_1 < 0) - tdel0_1 = !tdel0_1; - if (tdel0_1 > tdel0_0) - tdel0_0 = tdel0_1; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel0_1 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c0d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c0d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / 100; calc_tmp_td1_0: if (channel1_enabled) { - cval = tval / (2 * temp_ch1_0); + cval = tval / (src_rate_mhz * temp_ch1_0); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto calc_tmp_td1_1; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1851,36 +1853,36 @@ calc_tmp_td1_0: break; } - tdel1_0 = dst_emc_entry->current_dram_clktree_c1d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / 100); - if (tdel1_0 < 0) - tdel1_0 = !tdel1_0; - if (tdel1_0 > tdel0_0) - tdel0_0 = tdel1_0; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel1_0 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c1d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / 100; calc_tmp_td1_1: - cval = tval / (2 * temp_ch1_1); + cval = tval / (src_rate_mhz * temp_ch1_1); switch (update_type) { case DVFS_PT1: case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx += 100 * cval; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 += 100 * cval; if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) goto out; break; case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples; break; case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / dst_emc_entry->ptfv_list.ptfv_write_samples; break; case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = + (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1) + / (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1); break; default: if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) @@ -1888,13 +1890,13 @@ calc_tmp_td1_1: break; } - tdel1_1 = dst_emc_entry->current_dram_clktree_c1d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / 100); - if (tdel1_1 < 0) - tdel1_1 = !tdel1_1; - if (tdel1_1 > tdel0_0) - tdel0_0 = tdel1_1; - if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdel1_1 << 7) / 1000000) > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / 100; + tdelta = dst_emc_entry->current_dram_clktree_c1d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / 100); + if (tdelta < 0) + tdelta *= -1; + if ((u32)tdelta > adelta) + adelta = tdelta; + if (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin) + dst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / 100; } out: @@ -1910,43 +1912,42 @@ out: dst_emc_entry->trained_dram_clktree_c1d1u1 = dst_emc_entry->current_dram_clktree_c1d1u1; } - return (u32)tdel0_0; + return (u32)adelta; } -static u32 _minerva_periodic_compensation_handler(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, s32 dram_dev_num, s32 channel1_enabled, enum comp_seq_t seq_type) +static u32 _minerva_periodic_compensation_handler(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 dram_dev_num, u32 channel1_enabled, enum comp_seq_t seq_type) { if (!dst_emc_entry->periodic_training) - return seq_type; + return 0; - u32 adel = 0; u32 delay = 1000 * _actual_osc_clocks(src_emc_entry->run_clocks) / src_emc_entry->rate_khz + 2; if (seq_type == DVFS_SEQUENCE) { - if (src_emc_entry->periodic_training && dst_emc_entry->ptfv_list.ptfv_config_ctrl_idx & 1) + if (src_emc_entry->periodic_training && dst_emc_entry->ptfv_list.ptfv_config_ctrl & 1) { - u32 samples = dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx * samples; + u32 samples = dst_emc_entry->ptfv_list.ptfv_dvfs_samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 * samples; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 * samples; } else { - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = 0; - for (u32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; i++) + for (u32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_dvfs_samples; i++) { _start_periodic_compensation(); _usleep(delay); @@ -1954,49 +1955,43 @@ static u32 _minerva_periodic_compensation_handler(emc_table_t *src_emc_entry, em } } - adel = _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_UPDATE); - - return adel; + return _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_UPDATE); } else if (seq_type == WRITE_TRAINING_SEQUENCE) { - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = 0; + dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = 0; - for (u32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_write_samples_idx; i++) + for (u32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_write_samples; i++) { _start_periodic_compensation(); _usleep(delay); _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_PT1); } - adel = _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_UPDATE); - - return adel; + return _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_UPDATE); } else if (seq_type == PERIODIC_TRAINING_SEQUENCE) { _start_periodic_compensation(); _usleep(delay); - adel = _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE); - - return adel; + return _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE); } return seq_type; } #define STORE_TRIM_VAL(chan, rank, reg, byte) \ - ((mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank##rank##_##reg##_idx >> \ + ((mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank##rank##_##reg >> \ EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE##byte##_SHIFT) & 0x7FF) \ + \ - (((mtc_table_entry->trim_perch_regs.emc##chan##_data_brlshft_##rank##_idx >> \ + (((mtc_table_entry->trim_perch_regs.emc##chan##_data_brlshft_##rank >> \ EMC_DATA_BRLSHFT_##rank##_RANK##rank##_BYTE##byte##_DATA_BRLSHFT_SHIFT) & 0x7) << 6) static u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_entry, u32 trim_emc_reg_addr) @@ -2036,30 +2031,31 @@ static u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_e case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3: case EMC_DATA_BRLSHFT_0: - tree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d0u0 - mtc_table_entry->trained_dram_clktree_c0d0u0) << 7; - tree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d0u1 - mtc_table_entry->trained_dram_clktree_c0d0u1) << 7; - tree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d0u0 - mtc_table_entry->trained_dram_clktree_c1d0u0) << 7; - tree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d0u1 - mtc_table_entry->trained_dram_clktree_c1d0u1) << 7; + tree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d0u0 - mtc_table_entry->trained_dram_clktree_c0d0u0) * 128; + tree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d0u1 - mtc_table_entry->trained_dram_clktree_c0d0u1) * 128; + tree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d0u0 - mtc_table_entry->trained_dram_clktree_c1d0u0) * 128; + tree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d0u1 - mtc_table_entry->trained_dram_clktree_c1d0u1) * 128; tree_delta_taps[0] = (tree_delta[0] * (s32)dst_rate_mhz) / 1000000; tree_delta_taps[1] = (tree_delta[1] * (s32)dst_rate_mhz) / 1000000; tree_delta_taps[2] = (tree_delta[2] * (s32)dst_rate_mhz) / 1000000; tree_delta_taps[3] = (tree_delta[3] * (s32)dst_rate_mhz) / 1000000; - for (s32 i = 0; i < 4; i++) + for (u32 i = 0; i < 4; i++) { - if ((tree_delta_taps[i] > mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * mtc_table_entry->tree_margin))) + // Check if tap exceeds margins and apply it. + if ((tree_delta_taps[i] > (s32)mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * (s32)mtc_table_entry->tree_margin))) { - new_trim[i * 2] += tree_delta_taps[i]; + new_trim[i * 2] += tree_delta_taps[i]; new_trim[i * 2 + 1] += tree_delta_taps[i]; } } if (trim_emc_reg_addr == EMC_DATA_BRLSHFT_0) { - for (s32 i = 0; i < 8; i++) + for (u32 i = 0; i < 8; i++) new_trim[i] /= 64; } else { - for (s32 i = 0; i < 8; i++) + for (u32 i = 0; i < 8; i++) new_trim[i] %= 64; } break; @@ -2068,33 +2064,36 @@ static u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_e case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3: case EMC_DATA_BRLSHFT_1: - tree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d1u0 - mtc_table_entry->trained_dram_clktree_c0d1u0) << 7; - tree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d1u1 - mtc_table_entry->trained_dram_clktree_c0d1u1) << 7; - tree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d1u0 - mtc_table_entry->trained_dram_clktree_c1d1u0) << 7; - tree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d1u1 - mtc_table_entry->trained_dram_clktree_c1d1u1) << 7; + tree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d1u0 - mtc_table_entry->trained_dram_clktree_c0d1u0) * 128; + tree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d1u1 - mtc_table_entry->trained_dram_clktree_c0d1u1) * 128; + tree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d1u0 - mtc_table_entry->trained_dram_clktree_c1d1u0) * 128; + tree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d1u1 - mtc_table_entry->trained_dram_clktree_c1d1u1) * 128; tree_delta_taps[0] = (tree_delta[0] * (s32)dst_rate_mhz) / 1000000; tree_delta_taps[1] = (tree_delta[1] * (s32)dst_rate_mhz) / 1000000; tree_delta_taps[2] = (tree_delta[2] * (s32)dst_rate_mhz) / 1000000; tree_delta_taps[3] = (tree_delta[3] * (s32)dst_rate_mhz) / 1000000; - for (s32 i = 0; i < 4; i++) + for (u32 i = 0; i < 4; i++) { - if ((tree_delta_taps[i] > mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * mtc_table_entry->tree_margin))) + // Check if tap exceeds margins and apply it. + if ((tree_delta_taps[i] > (s32)mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * (s32)mtc_table_entry->tree_margin))) { - new_trim[8 + i * 2] += tree_delta_taps[i]; + new_trim[8 + i * 2] += tree_delta_taps[i]; new_trim[8 + i * 2 + 1] += tree_delta_taps[i]; } } if (trim_emc_reg_addr == EMC_DATA_BRLSHFT_1) { - for (s32 i = 0; i < 8; i++) + for (u32 i = 0; i < 8; i++) new_trim[i + 8] /= 64; } else { - for (s32 i = 0; i < 8; i++) + for (u32 i = 0; i < 8; i++) new_trim[i + 8] %= 64; } break; + default: + break; } switch (trim_emc_reg_addr) @@ -2124,24 +2123,24 @@ static u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_e trimmer = (new_trim[14] & 0x7FF) | ((new_trim[15] & 0x7FF) << 16); break; case EMC_DATA_BRLSHFT_0: - trimmer = (new_trim[0] & 7) - | ((new_trim[1] & 7) << 3) - | ((new_trim[2] & 7) << 6) - | ((new_trim[3] & 7) << 9) - | ((new_trim[4] & 7) << 12) - | ((new_trim[5] & 7) << 15) - | ((new_trim[6] & 7) << 18) - | ((new_trim[7] & 7) << 21); + trimmer = ((new_trim[0] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT) + | ((new_trim[1] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT) + | ((new_trim[2] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT) + | ((new_trim[3] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT) + | ((new_trim[4] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT) + | ((new_trim[5] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT) + | ((new_trim[6] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT) + | ((new_trim[7] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT); break; case EMC_DATA_BRLSHFT_1: - trimmer = (new_trim[8] & 7) - | ((new_trim[9] & 7) << 3) - | ((new_trim[10] & 7) << 6) - | ((new_trim[11] & 7) << 9) - | ((new_trim[12] & 7) << 12) - | ((new_trim[13] & 7) << 15) - | ((new_trim[14] & 7) << 18) - | ((new_trim[15] & 7) << 21); + trimmer = ((new_trim[8] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT) + | ((new_trim[9] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT) + | ((new_trim[10] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT) + | ((new_trim[11] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT) + | ((new_trim[12] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT) + | ((new_trim[13] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT) + | ((new_trim[14] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT) + | ((new_trim[15] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT); break; default: break; @@ -2152,9 +2151,9 @@ static u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_e static bool _check_freq_changed(u32 dst_entry_rate_KHz, u32 dst_entry_clk_src_emc, u32 src_entry_rate_KHz, u32 src_entry_clk_src_emc) { - s64 dst_div_clock; - s64 src_div_clock; - s32 src_end_div_clk_ratio; + u64 dst_div_clock; + u64 src_div_clock; + u32 src_end_div_clk_ratio; u32 src_entry_emc_2X_clk_src = src_entry_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; u32 dst_entry_emc_2X_clk_src = dst_entry_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; @@ -2203,46 +2202,46 @@ static bool _check_freq_changed(u32 dst_entry_rate_KHz, u32 dst_entry_clk_src_em return false; } -static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training, s32 dram_dev_num, bool channel1_enabled) +static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training, u32 dram_dev_num, bool channel1_enabled) { - bool needs_ca_training = needs_training & 1; - bool needs_ca_vref_training = (needs_training >> 1) & 1; - bool needs_quse_training = (needs_training >> 2) & 1; - bool needs_quse_vref_training = (needs_training >> 3) & 1; - bool needs_wr_training = (needs_training >> 4) & 1; - bool needs_wr_vref_training = (needs_training >> 5) & 1; - bool needs_rd_training = (needs_training >> 6) & 1; - bool needs_rd_vref_training = (needs_training >> 7) & 1; - bool needs_training_in_self_refresh = (needs_training >> 9) & 1; + bool needs_ca_training = !!(needs_training & NEEDS_TRAINING_CA); + bool needs_ca_vref_training = !!(needs_training & NEEDS_TRAINING_CA_VREF); + bool needs_quse_training = !!(needs_training & NEEDS_TRAINING_QUSE); + bool needs_quse_vref_training = !!(needs_training & NEEDS_TRAINING_QUSE_VREF); + bool needs_wr_training = !!(needs_training & NEEDS_TRAINING_WR); + bool needs_wr_vref_training = !!(needs_training & NEEDS_TRAINING_WR_VREF); + bool needs_rd_training = !!(needs_training & NEEDS_TRAINING_RD); + bool needs_rd_vref_training = !!(needs_training & NEEDS_TRAINING_RD_VREF); + bool needs_training_in_self_refresh = !!(needs_training & NEEDS_TRAINING_IN_SELF_REFRESH); if (needs_ca_training) { - mtc_table_entry->trim_perch_regs.emc_cmd_brlshft_0_idx = EMC_CH0(EMC_CMD_BRLSHFT_0); - mtc_table_entry->trim_perch_regs.emc_cmd_brlshft_1_idx = channel1_enabled ? EMC_CH1(EMC_CMD_BRLSHFT_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) : 0; + mtc_table_entry->trim_perch_regs.emc_cmd_brlshft_0 = EMC_CH0(EMC_CMD_BRLSHFT_0); + mtc_table_entry->trim_perch_regs.emc_cmd_brlshft_1 = channel1_enabled ? EMC_CH1(EMC_CMD_BRLSHFT_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) : 0; if (needs_training_in_self_refresh) { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2); } } if (needs_ca_vref_training) { - mtc_table_entry->burst_reg_per_ch.emc0_mrw10_idx = (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF) | 0x880C0000; - mtc_table_entry->burst_reg_per_ch.emc1_mrw10_idx = (channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF : 0) | 0x880C0000; + mtc_table_entry->burst_reg_per_ch.emc0_mrw10 = (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF) | 0x880C0000; + mtc_table_entry->burst_reg_per_ch.emc1_mrw10 = (channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF : 0) | 0x880C0000; u32 mrw11_dev_selectn; if (dram_dev_num == TWO_RANK) @@ -2250,12 +2249,12 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training else mrw11_dev_selectn = 0xC80C0000; - mtc_table_entry->burst_reg_per_ch.emc0_mrw11_idx = + mtc_table_entry->burst_reg_per_ch.emc0_mrw11 = ((EMC_CH0(EMC_TRAINING_OPT_CA_VREF) >> 16) & 0xFF) | (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) >> 24 << 8) | (mrw11_dev_selectn & 0xFFFFFF00); - mtc_table_entry->burst_reg_per_ch.emc1_mrw11_idx = + mtc_table_entry->burst_reg_per_ch.emc1_mrw11 = (((channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) : 0) >> 16) & 0xFF) | ((channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) : 0) >> 24 << 8) | (mrw11_dev_selectn & 0xFFFFFF00); @@ -2263,23 +2262,23 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training if (needs_quse_training || needs_rd_training) { - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_0_idx = EMC_CH0(EMC_QUSE_BRLSHFT_0); - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_1_idx = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_1) : 0; + mtc_table_entry->trim_perch_regs.emc_quse_brlshft_0 = EMC_CH0(EMC_QUSE_BRLSHFT_0); + mtc_table_entry->trim_perch_regs.emc_quse_brlshft_1 = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_0_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_0); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_1_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_1); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_3) : 0; + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_0 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_0); + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_1 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_1); + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_3) : 0; if (dram_dev_num == TWO_RANK) { - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_2_idx = EMC_CH0(EMC_QUSE_BRLSHFT_2); - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_3_idx = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_3) : 0; + mtc_table_entry->trim_perch_regs.emc_quse_brlshft_2 = EMC_CH0(EMC_QUSE_BRLSHFT_2); + mtc_table_entry->trim_perch_regs.emc_quse_brlshft_3 = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_3) : 0; - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_0_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_0); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_1_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_1); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_3) : 0; + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_0 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_0); + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_1 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_1); + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_3) : 0; } } @@ -2306,84 +2305,84 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training ib_vref_dqs_1 |= (emc1_opt_dqs_array[i] + ((emc1_training_opt_dqs_ib_vref_rank1_val >> (8 * i)) & 0xFF)) >> 1 << (8 * i); } - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0_idx = ib_vref_dqs_0; - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1_idx = ib_vref_dqs_1; + mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0 = ib_vref_dqs_0; + mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1 = ib_vref_dqs_1; } else { - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0_idx = EMC(EMC_PMACRO_IB_VREF_DQS_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_VREF_DQS_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0 = EMC(EMC_PMACRO_IB_VREF_DQS_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_VREF_DQS_1) : 0; } } if (needs_rd_training) { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) : 0; if (dram_dev_num == TWO_RANK) { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) : 0; } if (needs_training_in_self_refresh) { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; if (dram_dev_num == TWO_RANK) { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2); + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; } } @@ -2405,7 +2404,7 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training if (mtc_table_entry->save_restore_mod_regs[3] & 0x80000000) ib_vref_dq_byte3_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[3] & 0x7F); - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_0_idx = + mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_0 = ((ib_vref_dq_byte0_icr & 0x7F) | (ib_vref_dq_byte1_icr & 0x7F) << 8) | ((ib_vref_dq_byte2_icr & 0x7F) << 16) @@ -2427,7 +2426,7 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training if (mtc_table_entry->save_restore_mod_regs[7] & 0x80000000) ib_vref_dq_byte7_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[7] & 0x7F); - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_1_idx = + mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_1 = ((ib_vref_dq_byte4_icr & 0x7F) | (ib_vref_dq_byte5_icr & 0x7F) << 8) | ((ib_vref_dq_byte6_icr & 0x7F) << 16) @@ -2437,81 +2436,81 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training if (needs_wr_training) { - mtc_table_entry->trim_perch_regs.emc0_data_brlshft_0_idx = EMC_CH0(EMC_DATA_BRLSHFT_0); - mtc_table_entry->trim_perch_regs.emc1_data_brlshft_0_idx = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_0) : 0; + mtc_table_entry->trim_perch_regs.emc0_data_brlshft_0 = EMC_CH0(EMC_DATA_BRLSHFT_0); + mtc_table_entry->trim_perch_regs.emc1_data_brlshft_0 = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_0) : 0; if (dram_dev_num == TWO_RANK) { - mtc_table_entry->trim_perch_regs.emc0_data_brlshft_1_idx = EMC_CH0(EMC_DATA_BRLSHFT_1); - mtc_table_entry->trim_perch_regs.emc1_data_brlshft_1_idx = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_1) : 0; + mtc_table_entry->trim_perch_regs.emc0_data_brlshft_1 = EMC_CH0(EMC_DATA_BRLSHFT_1); + mtc_table_entry->trim_perch_regs.emc1_data_brlshft_1 = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_1) : 0; } - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) : 0; if (dram_dev_num == TWO_RANK) { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) : 0; } if (needs_training_in_self_refresh) { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; if (dram_dev_num == TWO_RANK) { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2); + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; + mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; } } @@ -2556,15 +2555,15 @@ static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training if (dram_dev_num == TWO_RANK) mr13_dev_ext_cnt_sp_addr = 0x480E0000; - mtc_table_entry->burst_reg_per_ch.emc1_mrw12_idx = (u8)emc0_ib_vref_dq_byte10_modded_plus | 0x880E0000 | (emc0_ib_vref_dq_byte11_modded_plus << 8); - mtc_table_entry->burst_reg_per_ch.emc0_mrw12_idx = emc0_ib_vref_dq_byte8_modded_plus | 0x880E0000 | (emc0_mrw12_op_sp1 << 8); - mtc_table_entry->burst_reg_per_ch.emc0_mrw13_idx = emc0_ib_vref_dq_byte9_modded_a_plus << 8 | emc0_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr; - mtc_table_entry->burst_reg_per_ch.emc1_mrw13_idx = (emc1_mrw13_op_sp1 << 8) | emc1_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr; + mtc_table_entry->burst_reg_per_ch.emc1_mrw12 = (u8)emc0_ib_vref_dq_byte10_modded_plus | 0x880E0000 | (emc0_ib_vref_dq_byte11_modded_plus << 8); + mtc_table_entry->burst_reg_per_ch.emc0_mrw12 = emc0_ib_vref_dq_byte8_modded_plus | 0x880E0000 | (emc0_mrw12_op_sp1 << 8); + mtc_table_entry->burst_reg_per_ch.emc0_mrw13 = emc0_ib_vref_dq_byte9_modded_a_plus << 8 | emc0_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr; + mtc_table_entry->burst_reg_per_ch.emc1_mrw13 = (emc1_mrw13_op_sp1 << 8) | emc1_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr; } } } -s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 needs_training, u32 selected_clk_src_emc) +static u32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 needs_training, u32 selected_clk_src_emc) { u32 emc_dbg_o; u32 emc_pin_o; @@ -2576,47 +2575,51 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u u32 ramp_up_wait; u32 ramp_down_wait; u32 bg_regulator_mode_change; - u32 mr13_flip_fspop = 0; - u32 mr13_flip_fspwr = 0; //float - u32 mr13_catr_enable = 0; //float + u32 mr13_flip_fspop; + u32 mr13_flip_fspwr; + u32 mr13_catr_enable; - /* needs_training LOBYTE table var */ + /* needs_training flags */ /* - | bit | Description | - |-----|----------------------------| - | 0 | Needs CA training | - | 1 | Needs CA_VREF training | - | 2 | Needs QUSE training | - | 3 | Needs QUSE_VREF training | - | 4 | Needs WR training | - | 5 | Needs WR_VREF training | - | 6 | Needs RD training | - | 7 | Needs RD_VREF training | + | bit | Description | + |-----|----------------------------------| + | 0 | Needs CA training | + | 1 | Needs CA_VREF training | + | 2 | Needs QUSE training | + | 3 | Needs QUSE_VREF training | + | 4 | Needs WR training | + | 5 | Needs WR_VREF training | + | 6 | Needs RD training | + | 7 | Needs RD_VREF training | + | 8 | Needs SWAP_RANK training | + | 9 | Needs IN_SELF_REFRESH training | */ bool compensate_trimmer_applicable = false; - bool needs_ca_or_cavref_training = (needs_training & 3) != 0; - bool needs_tristate_training = (needs_training & 0xF7) != 0; - bool needs_ca_training = needs_training & 1; - bool needs_ca_vref_training = (needs_training >> 1) & 1; - bool needs_quse_training = (needs_training >> 2) & 1; - bool needs_quse_vref_training = (needs_training >> 3) & 1; - bool needs_wr_training = (needs_training >> 4) & 1; - bool needs_wr_vref_training = (needs_training >> 5) & 1; - bool needs_rd_training = (needs_training >> 6) & 1; - bool needs_rd_vref_training = (needs_training >> 7) & 1; - bool needs_swap_rank_training = (needs_training >> 8) & 1; + bool needs_ca_combo_training = !!(needs_training & NEEDS_TRAINING_CA_COMBO); + bool needs_tristate_training = !!(needs_training & NEEDS_TRISTATE_TRAINING); - bool zcal_resistor_shared = (src_emc_entry->burst_regs.emc_zcal_wait_cnt_idx >> 31) & 1; - bool enable_bg_regulator = (dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 1) ^ 1; - bool channel1_enabled = (src_emc_entry->burst_regs.emc_fbio_cfg7_idx >> 2) & 1; - s32 dram_type = EMC(EMC_FBIO_CFG5) & 3; - s32 dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1; + bool needs_ca_training = !!(needs_training & NEEDS_TRAINING_CA); + bool needs_ca_vref_training = !!(needs_training & NEEDS_TRAINING_CA_VREF); + bool needs_quse_training = !!(needs_training & NEEDS_TRAINING_QUSE); + bool needs_quse_vref_training = !!(needs_training & NEEDS_TRAINING_QUSE_VREF); + bool needs_wr_training = !!(needs_training & NEEDS_TRAINING_WR); + bool needs_wr_vref_training = !!(needs_training & NEEDS_TRAINING_WR_VREF); + bool needs_rd_training = !!(needs_training & NEEDS_TRAINING_RD); + bool needs_rd_vref_training = !!(needs_training & NEEDS_TRAINING_RD_VREF); + bool needs_swap_rank_training = !!(needs_training & NEEDS_TRAINING_SWAP_RANK); - s32 src_clock_period = 1000000000 / src_emc_entry->rate_khz; - s32 dst_clock_period = 1000000000 / dst_emc_entry->rate_khz; + bool zcal_resistor_shared = (src_emc_entry->burst_regs.emc_zcal_wait_cnt >> 31) & 1; + bool enable_bg_regulator = (dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 1) ^ 1; + bool channel1_enabled = (src_emc_entry->burst_regs.emc_fbio_cfg7 >> 2) & 1; + u32 dram_type = EMC(EMC_FBIO_CFG5) & 3; + u32 dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1; - fsp_for_src_freq = !fsp_for_src_freq; + u32 src_clock_period = 1000000000 / src_emc_entry->rate_khz; // In picoseconds. + u32 dst_clock_period = 1000000000 / dst_emc_entry->rate_khz; // In picoseconds. + + // Get current FSP op/write value. + bool enable_fsp_opwr = !(EMC(EMC_MRW3) & 0xC0); if (dram_type != DRAM_TYPE_LPDDR4) { @@ -2624,17 +2627,20 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u return 5; } - u32 tFC_lpddr4 = dst_emc_entry->dram_timings.t_fc_lpddr4; - s32 tZQCAL_lpddr4 = 1000; - if (src_clock_period <= 2000) - tZQCAL_lpddr4 = 1000 - tFC_lpddr4; - s32 tZQCAL_lpddr4_fc_adj = tZQCAL_lpddr4 * 1000 / dst_clock_period; + u32 tFC_lpddr4 = dst_emc_entry->dram_timings.t_fc_lpddr4 * 1000; + u32 tZQCAL_lpddr4 = 1000000; + if (dst_clock_period <= 2000) + tZQCAL_lpddr4 -= tFC_lpddr4; + s32 tZQCAL_lpddr4_fc_adj = tZQCAL_lpddr4 / dst_clock_period; + + (void)EMC(EMC_CFG); + (void)EMC(EMC_AUTO_CAL_CONFIG); // Step 1 - Pre DVFS SW sequence. EPRINTF("Step 1"); emc_dbg_o = EMC(EMC_DBG); emc_pin_o = EMC(EMC_PIN); - emc_cfg = dst_emc_entry->burst_regs.emc_cfg_idx & 0xFFFFFFF; + emc_cfg = dst_emc_entry->burst_regs.emc_cfg & 0xFFFFFFF; emc_sel_dpd_ctrl = dst_emc_entry->emc_sel_dpd_ctrl & 0xFFFFFEC3; emc_cfg_pipe_clk_o = EMC(EMC_CFG_PIPE_CLK); _digital_dll_disable(); @@ -2642,6 +2648,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u // Step 1.2 - Disable AUTOCAL temporarily. EPRINTF("Step 1.2"); EMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FF) | 0x600; + (void)EMC(EMC_AUTO_CAL_CONFIG); // Step 1.3 - Disable other power features. EPRINTF("Step 1.3"); @@ -2654,20 +2661,20 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u { if (dram_dev_num == TWO_RANK) { - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, false, EMC_CH0); + _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_BOTH_MASK, false, EMC_CHANNEL0); if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, false, EMC_CH1); + _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_BOTH_MASK, false, EMC_CHANNEL1); } else { - _wait_emc_status(EMC_EMC_STATUS, 0x10, false, EMC_CH0); + _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_1DEV_MASK, false, EMC_CHANNEL0); if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, 0x10, false, EMC_CH1); + _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_1DEV_MASK, false, EMC_CHANNEL1); } - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CH0); + _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CHANNEL0); if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CH1); + _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CHANNEL1); // Reset clock tree delays. dst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->trained_dram_clktree_c0d0u0; @@ -2679,9 +2686,9 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u dst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->trained_dram_clktree_c1d1u0; dst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->trained_dram_clktree_c1d1u1; - u32 adel = _minerva_periodic_compensation_handler(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_SEQUENCE); + u32 adelta = _minerva_periodic_compensation_handler(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_SEQUENCE); - if (((dst_emc_entry->rate_khz / 1000) << 7) * adel / 1000000 > dst_emc_entry->tree_margin) + if (((dst_emc_entry->rate_khz / 1000) * 128) * adelta / 1000000 > dst_emc_entry->tree_margin) compensate_trimmer_applicable = true; } @@ -2692,27 +2699,27 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u EMC(EMC_CFG_PIPE_CLK) = emc_cfg_pipe_clk_o | 1; // CLK_ALWAYS_ON. EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = dst_emc_entry->emc_fdpd_ctrl_cmd_no_ramp & 0xFFFFFFFE; - bg_regulator_mode_change = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx ^ dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx; + bg_regulator_mode_change = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 ^ dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0; bg_regulator_mode_change = (bg_regulator_mode_change | (bg_regulator_mode_change >> 2)) & 1; if (bg_regulator_mode_change) { EMC(EMC_DBG) = emc_dbg_o | 2; if (enable_bg_regulator) - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFE; + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFE; else - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFB; + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFB; } // Check if we need to turn on VREF generator. - if ((!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0x100) - && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0x100)) - || (!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 1) - && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 1))) + if ((!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x100) + && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x100)) + || (!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 1) + && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 1))) { EMC(EMC_PMACRO_DATA_PAD_TX_CTRL) = - (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 1) | (src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0xFFFFFFFE)) & 0xFFFFFEFF) - | (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx >> 8) & 0x1) << 8); + (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 1) | (src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0xFFFFFFFE)) & 0xFFFFFEFF) + | (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl >> 8) & 0x1) << 8); } _usleep(1); @@ -2721,7 +2728,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u // Step 2 - Prelock the DLL. EPRINTF("Step 2"); - if (dst_emc_entry->burst_regs.emc_cfg_dig_dll_idx & 1) + if (dst_emc_entry->burst_regs.emc_cfg_dig_dll & 1) _digital_dll_prelock(dst_emc_entry, needs_tristate_training, selected_clk_src_emc); // Prelock enabled for target frequency. else { @@ -2759,7 +2766,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u // Step 7 - Bug 200024907 - Patch RP R2P. EPRINTF("Step 7"); - if (needs_ca_or_cavref_training && dram_dev_num == TWO_RANK) + if (needs_ca_combo_training && dram_dev_num == TWO_RANK) EMC(EMC_PIN) = 0x107; u32 R2P_war = 0; @@ -2767,20 +2774,20 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u u32 RP_war = 0; u32 W2P_war = 0; - s32 nRTP = 8; // <= 1066MHz. - if (src_clock_period < 3759 // 1000 / 266MHz. - && src_clock_period < 1876 // 1000 / 533MHz. - && src_clock_period < 1250 // 1000 / 800MHz. - && src_clock_period < 938) // 1000 / 1066MHz. + u32 nRTP = 8; // <= 1066MHz. + if ( src_clock_period < 1000000 / 266 + && src_clock_period < 1000000 / 533 + && src_clock_period < 1000000 / 800 + && src_clock_period < 1000000 / 1066 ) nRTP = 10; // 1067MHz < x <= 1333MHz. - if (src_clock_period < 750) // 1000 / 1333MHz. + if (src_clock_period < 1000000 / 1333) nRTP = 12; // 1333MHz < x <= 1600MHz. - if (src_clock_period < 625) // 1000 / 1600MHz. + if (src_clock_period < 1000000 / 1600) nRTP = 14; // 1600MHz < x <= 1866MHz. - if (src_clock_period < 535) // 1000 / 1866MHz. + if (src_clock_period < 1000000 / 1866) nRTP = 16; // > 1866MHz - s32 tRPST = (src_emc_entry->emc_mrw >> 7) & 1; + u32 tRPST = (src_emc_entry->emc_mrw >> 7) & 1; u32 deltaTWATM = div_o3(7500, src_clock_period); if (deltaTWATM < 8) @@ -2788,33 +2795,33 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u u32 tRTM = src_emc_entry->dram_timings.rl + div_o3(3600, src_clock_period) + deltaTWATM + tRPST + nRTP + 1; - if (tRTM <= src_emc_entry->burst_regs.emc_rp_idx + src_emc_entry->burst_regs.emc_r2p_idx) + if (tRTM <= src_emc_entry->burst_regs.emc_rp + src_emc_entry->burst_regs.emc_r2p) { - TRPab_war = src_emc_entry->burst_regs.emc_trpab_idx; - R2P_war = src_emc_entry->burst_regs.emc_r2p_idx; - RP_war = src_emc_entry->burst_regs.emc_rp_idx; + TRPab_war = src_emc_entry->burst_regs.emc_trpab; + R2P_war = src_emc_entry->burst_regs.emc_r2p; + RP_war = src_emc_entry->burst_regs.emc_rp; } else { - R2P_war = tRTM - src_emc_entry->burst_regs.emc_rp_idx; - TRPab_war = src_emc_entry->burst_regs.emc_trpab_idx; - RP_war = src_emc_entry->burst_regs.emc_rp_idx; + R2P_war = tRTM - src_emc_entry->burst_regs.emc_rp; + TRPab_war = src_emc_entry->burst_regs.emc_trpab; + RP_war = src_emc_entry->burst_regs.emc_rp; if (R2P_war > 63) { RP_war = tRTM - 63; R2P_war = 63; - if (src_emc_entry->burst_regs.emc_trpab_idx < tRTM - 63) + if (src_emc_entry->burst_regs.emc_trpab < tRTM - 63) TRPab_war = tRTM - 63; else - TRPab_war = src_emc_entry->burst_regs.emc_trpab_idx; + TRPab_war = src_emc_entry->burst_regs.emc_trpab; } } if (RP_war >= deltaTWATM) - W2P_war = src_emc_entry->burst_regs.emc_w2p_idx; + W2P_war = src_emc_entry->burst_regs.emc_w2p; else { - u32 W2P_war_temp = deltaTWATM + src_emc_entry->burst_regs.emc_w2p_idx; + u32 W2P_war_temp = deltaTWATM + src_emc_entry->burst_regs.emc_w2p; W2P_war = W2P_war_temp - RP_war; if (W2P_war > 63) { @@ -2825,10 +2832,10 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u } } - if ( src_emc_entry->burst_regs.emc_w2p_idx != W2P_war - || src_emc_entry->burst_regs.emc_rp_idx != RP_war - || src_emc_entry->burst_regs.emc_r2p_idx != R2P_war - || src_emc_entry->burst_regs.emc_trpab_idx != TRPab_war) + if ( src_emc_entry->burst_regs.emc_w2p != W2P_war + || src_emc_entry->burst_regs.emc_rp != RP_war + || src_emc_entry->burst_regs.emc_r2p != R2P_war + || src_emc_entry->burst_regs.emc_trpab != TRPab_war) { EMC(EMC_DBG) = emc_dbg_o | 2; EMC(EMC_RP) = RP_war; @@ -2836,12 +2843,13 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u EMC(EMC_W2P) = W2P_war; EMC(EMC_TRPAB) = TRPab_war; EMC(EMC_DBG) = emc_dbg_o; + (void)EMC(EMC_TRPAB); _usleep(1); } // Step 7.2 - Program FSP reference registers and send MRWs to new FSPWR. EPRINTF("Step 7.2"); - if (fsp_for_src_freq) + if (enable_fsp_opwr) { mr13_flip_fspop = dst_emc_entry->emc_mrw3 | 0xC0; mr13_flip_fspwr = (dst_emc_entry->emc_mrw3 & 0xFFFFFF3F) | 0x40; @@ -2859,7 +2867,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u else mr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF) | 0x80000001; - if (needs_ca_or_cavref_training) + if (needs_ca_combo_training) { if (needs_swap_rank_training) mr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x80000000; @@ -2888,11 +2896,11 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u reg_addr = burst_regs_emc_addr_table[i]; if (needs_tristate_training) { - if (needs_ca_or_cavref_training) + if (needs_ca_combo_training) reg_val = dst_burst_regs->shadow_regs_ca_train[i]; - else if (needs_training & 0xC) + else if (needs_training & NEEDS_TRAINING_QUSE_COMBO) reg_val = dst_burst_regs->shadow_regs_quse_train[i]; - else if (needs_training & 0xF0) + else if (needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO)) reg_val = dst_burst_regs->shadow_regs_rdwr_train[i]; else continue; @@ -2925,24 +2933,24 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u { switch ( reg_addr ) { - case EMC_PMACRO_AUTOCAL_CFG_COMMON: - reg_val |= 0x10000; - break; - case EMC_PMACRO_DATA_PAD_TX_CTRL: - reg_val &= 0xFEFEFDFD; - break; - case EMC_PMACRO_CMD_PAD_TX_CTRL: - reg_val = (reg_val & 0xFAFEFDFD) | 0x4000000; - break; - case EMC_PMACRO_BRICK_CTRL_RFU1: - reg_val &= 0xF800F800; - break; - case EMC_PMACRO_COMMON_PAD_TX_CTRL: - reg_val &= 0xFFFFFFF0; - break; - case EMC_TRAINING_CTRL: - reg_val |= needs_swap_rank_training << 14;// bit15 is TR_IN_SELF_REFRESH - break; + case EMC_PMACRO_AUTOCAL_CFG_COMMON: + reg_val |= 0x10000; + break; + case EMC_PMACRO_DATA_PAD_TX_CTRL: + reg_val &= 0xFEFEFDFD; + break; + case EMC_PMACRO_CMD_PAD_TX_CTRL: + reg_val = (reg_val & 0xFAFEFDFD) | 0x4000000; + break; + case EMC_PMACRO_BRICK_CTRL_RFU1: + reg_val &= 0xF800F800; + break; + case EMC_PMACRO_COMMON_PAD_TX_CTRL: + reg_val &= 0xFFFFFFF0; + break; + case EMC_TRAINING_CTRL: + reg_val |= needs_swap_rank_training << 14;// bit15 is TR_IN_SELF_REFRESH + break; } } else @@ -3057,32 +3065,30 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u // Writing burst_mc_regs. for (u32 i = 0; dst_emc_entry->num_mc_regs > i; i++) MC(burst_mc_regs_addr_table[i]) = dst_emc_entry->burst_mc_regs[i]; - } - // Writing la_scale_regs. - //if ((dst_emc_entry->rate_khz < src_emc_entry->rate_khz) && dst_emc_entry->num_up_down) //NEW TODO - if ((dst_emc_entry->rate_khz < src_emc_entry->rate_khz) > needs_tristate_training) - { - for (u32 i = 0; dst_emc_entry->num_up_down > i; i++) - MC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i]; + // Writing la_scale_regs. + if (dst_emc_entry->rate_khz < src_emc_entry->rate_khz) + { + for (u32 i = 0; dst_emc_entry->num_up_down > i; i++) + MC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i]; + } } // Step 9 - LPDDR4. EPRINTF("Step 9"); - - EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval_idx & 0xFF000000; - EMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt_idx & 0xFFFFF800; + EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval & 0xFF000000; + EMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt & 0xFFFFF800; EMC(EMC_DBG) = emc_dbg_o | 0x40000002; - EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval_idx & 0xFF000000; + EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval & 0xFF000000; EMC(EMC_DBG) = emc_dbg_o; if (needs_tristate_training) { EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common_idx | 0x10000; + EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common | 0x10000; - if (needs_ca_or_cavref_training) - EMC(EMC_FBIO_CFG5) = src_emc_entry->burst_regs.emc_fbio_cfg5_idx | 0x8000000; + if (needs_ca_combo_training) + EMC(EMC_FBIO_CFG5) = src_emc_entry->burst_regs.emc_fbio_cfg5 | 0x8000000; EMC(EMC_DBG) = emc_dbg_o; @@ -3092,20 +3098,19 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u _ccfifo_write(EMC_DBG, (emc_dbg_o & 0xF3FFFFFF) | 0x4000000, 0); } - // Step 10 - Self refresh EPRINTF("Step 10"); _ccfifo_write(EMC_SELF_REF, 0x101, 0); - if (needs_ca_or_cavref_training < (src_clock_period <= 2000)) + if (!needs_ca_combo_training && (dst_clock_period <= 2000)) { _ccfifo_write(EMC_MRW3, mr13_flip_fspwr ^ 0x40, 0); - _ccfifo_write(EMC_MRW6, (src_emc_entry->burst_regs.emc_mrw6_idx & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw6_idx & 0xFFFF3F3F), 0); - _ccfifo_write(EMC_MRW14, (src_emc_entry->burst_regs.emc_mrw14_idx & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw14_idx & 0xFFFF0707), 0); + _ccfifo_write(EMC_MRW6, (src_emc_entry->burst_regs.emc_mrw6 & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw6 & 0xFFFF3F3F), 0); + _ccfifo_write(EMC_MRW14, (src_emc_entry->burst_regs.emc_mrw14 & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw14 & 0xFFFF0707), 0); if (dram_dev_num == TWO_RANK) { - _ccfifo_write(EMC_MRW7, (src_emc_entry->burst_regs.emc_mrw7_idx & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw7_idx & 0xFFFF3F3F), 0); - _ccfifo_write(EMC_MRW15, (src_emc_entry->burst_regs.emc_mrw15_idx & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw15_idx & 0xFFFF0707), 0); + _ccfifo_write(EMC_MRW7, (src_emc_entry->burst_regs.emc_mrw7 & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw7 & 0xFFFF3F3F), 0); + _ccfifo_write(EMC_MRW15, (src_emc_entry->burst_regs.emc_mrw15 & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw15 & 0xFFFF0707), 0); } if (dram_dev_num == ONE_RANK || zcal_resistor_shared) @@ -3117,7 +3122,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u } emc_dbg_val = emc_dbg_o; - u32 tRP_src_timing = src_emc_entry->dram_timings.t_rp * 1000 / src_clock_period; + u32 tRP_src_timing = (src_emc_entry->dram_timings.t_rp * 1000) / src_clock_period; bool in_self_refresh = false; u32 ref_delay = 0; @@ -3127,9 +3132,9 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u _ccfifo_write(EMC_DBG, emc_dbg_val, 0); } - if (needs_ca_or_cavref_training) + if (needs_ca_combo_training) { - _ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode_idx & 0xFFFFFCCC, 0); + _ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode & 0xFFFFFCCC, 0); if (dram_dev_num == TWO_RANK && needs_swap_rank_training) { @@ -3145,7 +3150,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u else { _ccfifo_write(EMC_MRW3, mr13_flip_fspop | 8, tRP_src_timing); - ref_delay = tFC_lpddr4 * 1000 / src_clock_period; + ref_delay = tFC_lpddr4 / src_clock_period; } _ccfifo_write(EMC_INTSTATUS, 0, ref_delay); @@ -3166,14 +3171,14 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u // Step 13 - Ramp up. EPRINTF("Step 13"); - ramp_up_wait = _dvfs_power_ramp_up(false, src_emc_entry, dst_emc_entry, needs_training & 0xFF, dst_clock_period); + ramp_up_wait = _dvfs_power_ramp_up(false, src_emc_entry, dst_emc_entry, needs_training, dst_clock_period); _ccfifo_write(EMC_DBG, emc_dbg_val, 0); // Step 14 - Bringup CKE pins. EPRINTF("Step 14"); u32 emc_pin_val_final = 0; - if (needs_ca_or_cavref_training) + if (needs_ca_combo_training) { emc_pin_val_final = emc_pin_o & 0xFFFFFFF8; if (dram_dev_num == TWO_RANK) @@ -3193,85 +3198,72 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u // Step 15 - Zqlatch. EPRINTF("Step 15"); - if (!needs_ca_or_cavref_training) + if (!needs_ca_combo_training) { - s32 zq_latch_dvfs_wait_time = 0; - s32 T_PDEX_timing_final = 0; - s32 T_PDEX_timing = div_o3(dst_emc_entry->dram_timings.t_pdex * 1000, dst_clock_period); + s32 zq_latch_dvfs_wait_time; + u32 T_PDEX_timing = div_o3(dst_emc_entry->dram_timings.t_pdex * 1000, dst_clock_period); - if (src_clock_period > 2000) - zq_latch_dvfs_wait_time = tZQCAL_lpddr4_fc_adj - T_PDEX_timing; + if (dst_clock_period > 2000) + zq_latch_dvfs_wait_time = (s32)tZQCAL_lpddr4_fc_adj - (s32)T_PDEX_timing; else zq_latch_dvfs_wait_time = - tZQCAL_lpddr4_fc_adj - (ramp_up_wait + ramp_down_wait) * 1000 / dst_clock_period; + (s32)tZQCAL_lpddr4_fc_adj - (ramp_up_wait + ramp_down_wait) / dst_clock_period; if (dram_dev_num == ONE_RANK) { - if (T_PDEX_timing < 0) - T_PDEX_timing = 0; - - if (src_clock_period > 2000) + if (dst_clock_period > 2000) _ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing); if (!needs_tristate_training) - { _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, T_PDEX_timing); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - _ccfifo_write(EMC_REF, 0, 0); - } + emc_zq_cal = 0x80000002; - if (zq_latch_dvfs_wait_time < 0) - zq_latch_dvfs_wait_time = 0; } else if (zcal_resistor_shared) { - if (src_clock_period > 2000) - { - T_PDEX_timing_final = T_PDEX_timing; - if (T_PDEX_timing < 0) - T_PDEX_timing_final = 0; - _ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing_final); - } + if (dst_clock_period > 2000) + _ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing); - T_PDEX_timing_final = zq_latch_dvfs_wait_time + T_PDEX_timing; + s32 T_PDEX_timing_final = zq_latch_dvfs_wait_time + (s32)T_PDEX_timing; - if ((zq_latch_dvfs_wait_time + T_PDEX_timing) < 0) + if (T_PDEX_timing_final < 0) T_PDEX_timing_final = 0; _ccfifo_write(EMC_ZQ_CAL, 0x80000002, T_PDEX_timing_final); _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); if (!needs_tristate_training) - { _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, 0); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - _ccfifo_write(EMC_REF, 0, 0); - } emc_zq_cal = 0x40000002; zq_latch_dvfs_wait_time = 1000000 / dst_clock_period; } else { - if (T_PDEX_timing < 0) - T_PDEX_timing = 0; - - if (src_clock_period > 2000) + if (dst_clock_period > 2000) _ccfifo_write(EMC_ZQ_CAL, 1, T_PDEX_timing); if (!needs_tristate_training) - { _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, T_PDEX_timing); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - _ccfifo_write(EMC_REF, 0, 0); - } emc_zq_cal = 2; - - if (zq_latch_dvfs_wait_time < 0) - zq_latch_dvfs_wait_time = 0; } + // Disable self-refresh. + if (!needs_tristate_training) + { +#ifdef PERF_HACK + // HACK: Setting ACTIVE_SELF_REF increases perf by 1-2%. + _ccfifo_write(EMC_SELF_REF, 0x100, 0); +#else + _ccfifo_write(EMC_SELF_REF, 0, 0); +#endif + _ccfifo_write(EMC_REF, 0, 0); + } + + if (zq_latch_dvfs_wait_time < 0) + zq_latch_dvfs_wait_time = 0; + _ccfifo_write(EMC_ZQ_CAL, emc_zq_cal, (u32)zq_latch_dvfs_wait_time); } @@ -3296,7 +3288,7 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u if (needs_wr_training) training_command |= (1 << 3); // WR: Initiates WR Training. if (needs_wr_vref_training) - training_command |= (1 << 6); // WR_VREF: Initiates OB (wrire) DRAM_VREF Training. + training_command |= (1 << 6); // WR_VREF: Initiates OB (write) DRAM_VREF Training. if (needs_rd_training) training_command |= (1 << 2); // RD: Initiates RD Training. if (needs_rd_vref_training) @@ -3309,15 +3301,15 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u { if (enable_bg_regulator) _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFE, 0); + src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFE, 0); else _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFB, 0); + src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFB, 0); } _ccfifo_write(EMC_SWITCH_BACK_CTRL, 1, 0); - if (!needs_ca_or_cavref_training || needs_swap_rank_training) + if (!needs_ca_combo_training || needs_swap_rank_training) { _ccfifo_write(EMC_MRW3, mr13_flip_fspop ^ 0xC0, 0); _ccfifo_write(EMC_INTSTATUS, 0, 1000000 / dst_clock_period); @@ -3341,13 +3333,13 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u else _ccfifo_write(EMC_PIN, (emc_pin_o & 0xFFFFFFF8) | 1, 0); - if (needs_ca_or_cavref_training) + if (needs_ca_combo_training) { _ccfifo_write(EMC_TR_CTRL_0, 0x4A, 200000 / src_clock_period); _ccfifo_write(EMC_TR_CTRL_0, 0x40, 1000000 / src_clock_period); _ccfifo_write(EMC_MRW3, mr13_catr_enable & 0xFFFFFFFE, 0); _ccfifo_write(EMC_INTSTATUS, 0, 1000000 / src_clock_period); - _ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode_idx, 0); + _ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode, 0); } _ccfifo_write(EMC_DBG, emc_dbg_o, 0); @@ -3355,40 +3347,19 @@ s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u _ccfifo_write(EMC_ZQ_CAL, 0x80000001, 0); _ccfifo_write(EMC_ZQ_CAL, 0x80000002, 1000000 / src_clock_period); - if (zcal_resistor_shared && dram_dev_num == TWO_RANK) + if ((!needs_ca_combo_training || needs_swap_rank_training) && dram_dev_num == TWO_RANK) { - if (!needs_ca_or_cavref_training || needs_swap_rank_training) - { - _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); - _ccfifo_write(EMC_ZQ_CAL, 0x40000002, 1000000 / src_clock_period); - if (!needs_ca_or_cavref_training) - _ccfifo_write(EMC_MRW3, ((mr13_flip_fspop ^ 0xC0) & 0xF3FFFFF7) | 0xC000000, 0); - } - - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - - goto step_19_2; - } - else if (dram_dev_num == TWO_RANK) - { - if (needs_ca_or_cavref_training && !needs_swap_rank_training) - { - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - - goto step_19_2; - } _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); _ccfifo_write(EMC_ZQ_CAL, 0x40000002, 1000000 / src_clock_period); } - if (!needs_ca_or_cavref_training) - _ccfifo_write(EMC_MRW3, ((mr13_flip_fspop ^ 0xC0) & 0xF3FFFFF7) | 0xC000000, 0); + if (!needs_ca_combo_training) + _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) ^ 0xC0000C0, 0); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); + _ccfifo_write(EMC_SELF_REF, 0, 0); // Was 0x100. } -step_19_2: // Step 19.2. EPRINTF("Step 19.2"); if (bg_regulator_mode_change) @@ -3400,14 +3371,14 @@ step_19_2: { bg_regulator_switch_complete_wait_clks = 1250000 / src_clock_period; _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx, bg_regulator_switch_complete_wait_clks); + src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0, bg_regulator_switch_complete_wait_clks); } else { - if (ramp_up_wait <= 1250) - bg_regulator_switch_complete_wait_clks = (1250 - ramp_up_wait) * 1000 / dst_clock_period; + if (ramp_up_wait <= 1250000) + bg_regulator_switch_complete_wait_clks = (1250000 - ramp_up_wait) / dst_clock_period; _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx, bg_regulator_switch_complete_wait_clks); + dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0, bg_regulator_switch_complete_wait_clks); } _ccfifo_write(EMC_DBG, emc_dbg_o, 0); @@ -3423,13 +3394,15 @@ step_19_2: _ccfifo_write(EMC_DBG, emc_dbg_o | 2, 0); if (needs_tristate_training) - _ccfifo_write(EMC_ZCAL_INTERVAL, src_emc_entry->burst_regs.emc_zcal_interval_idx, 0); + _ccfifo_write(EMC_ZCAL_INTERVAL, src_emc_entry->burst_regs.emc_zcal_interval, 0); - _ccfifo_write(EMC_CFG, dst_emc_entry->burst_regs.emc_cfg_idx & 0xEFFFFFFF, 0); + _ccfifo_write(EMC_CFG, dst_emc_entry->burst_regs.emc_cfg & 0xEFFFFFFF, 0); // Step 22 - Restore EMC_CFG_PIPE_CLK. EPRINTF("Step 22"); - _ccfifo_write(EMC_SEL_DPD_CTRL, src_emc_entry->emc_sel_dpd_ctrl, 0); + //if (needs_tristate_training && dram_type == DRAM_TYPE_LPDDR4)//////////////// + if (needs_tristate_training) + _ccfifo_write(EMC_SEL_DPD_CTRL, src_emc_entry->emc_sel_dpd_ctrl, 0); _ccfifo_write(EMC_DBG, emc_dbg_o, 0); _ccfifo_write(EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o, 0); @@ -3437,21 +3410,32 @@ step_19_2: if (bg_regulator_mode_change) { if (enable_bg_regulator) - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFB; + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFB; else - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFE; + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFE; } // Step 23 - Clock Change. EPRINTF("Step 23"); + // During training save current clock. if (needs_tristate_training) { - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE) = (u32)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC); - _change_dll_src(src_emc_entry, (u32)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC)); + u32 emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC); + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE) = emc_clk_src; + _change_dll_src(src_emc_entry, emc_clk_src); } - EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x88; + // Set CFG_DLL_MODE to RUN_PERIODIC. + EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x88; + (void)EMC(EMC_CFG_DIG_DLL); + + (void)EMC(EMC_FBIO_CFG7); + (void)MC(MC_EMEM_ADR_CFG); + (void)EMC(EMC_INTSTATUS); + + // Do clock change. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = selected_clk_src_emc; + (void)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC); if (_wait_emc_status(EMC_INTSTATUS, CLKCHANGE_COMPLETE_INT, true, 0)) return 4; // Clkchange handshake timeout error. @@ -3460,6 +3444,7 @@ step_19_2: EPRINTF("Step 24"); if (needs_tristate_training) { + (void)MC(MC_EMEM_ADR_CFG); emc_dbg_val = EMC(EMC_DBG); EMC(EMC_DBG) |= 1; @@ -3470,8 +3455,7 @@ step_19_2: // Step 25 - Program MC updown regs. EPRINTF("Step 25"); - //if (dst_emc_entry->rate_khz > src_emc_entry->rate_khz) //NEW TODO - if ((dst_emc_entry->rate_khz > src_emc_entry->rate_khz) > needs_tristate_training) + if ((dst_emc_entry->rate_khz > src_emc_entry->rate_khz) && !needs_tristate_training) { for (u32 i = 0; dst_emc_entry->num_up_down > i; i++) MC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i]; @@ -3486,15 +3470,15 @@ step_19_2: if (!in_self_refresh) { EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt_idx; - EMC(EMC_ZCAL_INTERVAL) = dst_emc_entry->burst_regs.emc_zcal_interval_idx; + EMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt; + EMC(EMC_ZCAL_INTERVAL) = dst_emc_entry->burst_regs.emc_zcal_interval; EMC(EMC_DBG) = emc_dbg_o; } // Step 27 - Restore EMC_CFG, FDPD regs. EPRINTF("Step 27"); EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg_idx; + EMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg; EMC(EMC_DBG) = emc_dbg_o; EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = dst_emc_entry->emc_fdpd_ctrl_cmd_no_ramp; EMC(EMC_SEL_DPD_CTRL) = dst_emc_entry->emc_sel_dpd_ctrl; @@ -3504,10 +3488,10 @@ step_19_2: if (needs_tristate_training) { EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg_idx; + EMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg; EMC(EMC_SEL_DPD_CTRL) = dst_emc_entry->emc_sel_dpd_ctrl; - EMC(EMC_ZCAL_WAIT_CNT) = src_emc_entry->burst_regs.emc_zcal_wait_cnt_idx; - EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval_idx; + EMC(EMC_ZCAL_WAIT_CNT) = src_emc_entry->burst_regs.emc_zcal_wait_cnt; + EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval; EMC(EMC_AUTO_CAL_CONFIG2) = src_emc_entry->emc_auto_cal_config2; EMC(EMC_AUTO_CAL_CONFIG3) = src_emc_entry->emc_auto_cal_config3; EMC(EMC_AUTO_CAL_CONFIG4) = src_emc_entry->emc_auto_cal_config4; @@ -3516,11 +3500,11 @@ step_19_2: EMC(EMC_AUTO_CAL_CONFIG7) = src_emc_entry->emc_auto_cal_config7; EMC(EMC_AUTO_CAL_CONFIG8) = src_emc_entry->emc_auto_cal_config8; EMC(EMC_DBG) = emc_dbg_o; - EMC(EMC_TR_DVFS) = dst_emc_entry->burst_regs.emc_tr_dvfs_idx & 0xFFFFFFFE; + EMC(EMC_TR_DVFS) = dst_emc_entry->burst_regs.emc_tr_dvfs & 0xFFFFFFFE; } EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common_idx; + EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common; EMC(EMC_DBG) = emc_dbg_o; // Step 29 - Power fix WAR. @@ -3530,16 +3514,13 @@ step_19_2: EMC(EMC_PMACRO_TRAINING_CTRL_1) = CH0_TRAINING_E_WRPTR; EMC(EMC_PMACRO_CFG_PM_GLOBAL_0) = 0; - // Step 30 - Re-enable autocal and Restore FSP to account for switch back (training). + // Step 30 - Re-enable autocal. EPRINTF("Step 30"); if (needs_tristate_training) - { EMC(EMC_AUTO_CAL_CONFIG) = src_emc_entry->emc_auto_cal_config; - fsp_for_src_freq = !fsp_for_src_freq; - } else { - if (dst_emc_entry->burst_regs.emc_cfg_dig_dll_idx & 1) + if (dst_emc_entry->burst_regs.emc_cfg_dig_dll & 1) _digital_dll_enable_rs(channel1_enabled); EMC(EMC_AUTO_CAL_CONFIG) = dst_emc_entry->emc_auto_cal_config; } @@ -3549,12 +3530,11 @@ step_19_2: static void _minerva_train_patterns(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, bool switch_rate, u32 selected_clk_src_emc) { - u32 needs_training_idx = 0; + u32 needs_training_num = 0; u32 emc_cfg_dig_dll_val = 0; u32 needs_training_emc_table[8] = {0}; u32 needs_training = dst_emc_entry->needs_training; - bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); // Must start as true. if (train_ram_patterns) @@ -3569,37 +3549,36 @@ static void _minerva_train_patterns(emc_table_t *src_emc_entry, emc_table_t *dst train_ram_patterns = false; } - if (needs_training && !dst_emc_entry->trained) + if (!dst_emc_entry->trained) { - needs_training_idx = needs_training & 3; - - if (needs_training & 3) + if (needs_training & NEEDS_TRAINING_CA_COMBO) { - needs_training_idx = 1; - needs_training_emc_table[0] = needs_training & 0x203; + needs_training_emc_table[needs_training_num++] = + needs_training & (NEEDS_TRAINING_CA_COMBO | NEEDS_TRAINING_IN_SELF_REFRESH); if (MC(MC_EMEM_ADR_CFG) & 1) // if mapping W8 (1KB page). - { - needs_training_idx = 2; - needs_training_emc_table[1] = needs_training & 0x303; - } + needs_training_emc_table[needs_training_num++] = + needs_training & (NEEDS_TRAINING_CA_COMBO | NEEDS_TRAINING_SWAP_RANK | NEEDS_TRAINING_IN_SELF_REFRESH); } - if (MC(MC_EMEM_ADR_CFG) & 1 && needs_training & 0xC) + if (needs_training & NEEDS_TRAINING_QUSE_COMBO) { - needs_training_emc_table[needs_training_idx] = needs_training & 0x20C; - needs_training_emc_table[needs_training_idx + 1] = needs_training & 0x204; - needs_training_idx += 2; + needs_training_emc_table[needs_training_num++] = + needs_training & (NEEDS_TRAINING_QUSE_COMBO | NEEDS_TRAINING_IN_SELF_REFRESH); + if (MC(MC_EMEM_ADR_CFG) & 1) + needs_training_emc_table[needs_training_num++] = + needs_training & (NEEDS_TRAINING_QUSE | NEEDS_TRAINING_IN_SELF_REFRESH); } - else if (needs_training & 0xC) - needs_training_emc_table[needs_training_idx++] = needs_training & 0x20C; - if (needs_training & 0xF0) - needs_training_emc_table[needs_training_idx++] = needs_training & 0x2F0; + if (needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO)) + needs_training_emc_table[needs_training_num++] = + needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO | NEEDS_TRAINING_IN_SELF_REFRESH); - for (u32 i = 0; needs_training_idx > i; i++) // Runs more than once for needs_training & 0xF + for (u32 i = 0; needs_training_num > i; i++) // Runs more than once for needs_training CA/QUSE/WR/RD. { _minerva_set_clock(src_emc_entry, dst_emc_entry, needs_training_emc_table[i], selected_clk_src_emc); + bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); + EMC(EMC_DBG) = (EMC(EMC_DBG) & 0xF3FFFFFF) | 0x8000000; EMC(EMC_CFG_UPDATE) = (EMC(EMC_CFG_UPDATE) & 0xFFFFFFF9) | 4; _timing_update(dual_channel); @@ -3610,7 +3589,7 @@ static void _minerva_train_patterns(emc_table_t *src_emc_entry, emc_table_t *dst _timing_update(dual_channel); emc_cfg_dig_dll_val = EMC(EMC_CFG_DIG_DLL) & 0xFFFFFFFE; - if (dst_emc_entry->burst_regs.emc_cfg_dig_dll_idx == 1) + if (dst_emc_entry->burst_regs.emc_cfg_dig_dll == 1) emc_cfg_dig_dll_val = EMC(EMC_CFG_DIG_DLL) | 1; EMC(EMC_CFG_DIG_DLL) = (emc_cfg_dig_dll_val & 0xFFFFFF3F) | 0x80; _timing_update(dual_channel); @@ -3619,16 +3598,16 @@ static void _minerva_train_patterns(emc_table_t *src_emc_entry, emc_table_t *dst ; // Bug 200024907. - EMC(EMC_RP) = src_emc_entry->burst_regs.emc_rp_idx; - EMC(EMC_R2P) = src_emc_entry->burst_regs.emc_r2p_idx; - EMC(EMC_W2P) = src_emc_entry->burst_regs.emc_w2p_idx; - EMC(EMC_TRPAB) = src_emc_entry->burst_regs.emc_trpab_idx; + EMC(EMC_RP) = src_emc_entry->burst_regs.emc_rp; + EMC(EMC_R2P) = src_emc_entry->burst_regs.emc_r2p; + EMC(EMC_W2P) = src_emc_entry->burst_regs.emc_w2p; + EMC(EMC_TRPAB) = src_emc_entry->burst_regs.emc_trpab; _timing_update(dual_channel); - } - dst_emc_entry->trained = 1; + EPRINTF("Trained"); + dst_emc_entry->trained = 1; } if (switch_rate) @@ -3637,7 +3616,7 @@ static void _minerva_train_patterns(emc_table_t *src_emc_entry, emc_table_t *dst void _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg) { - s32 dram_type = EMC(EMC_FBIO_CFG5) & 3; + u32 dram_type = EMC(EMC_FBIO_CFG5) & 3; // Only LPDDR chips are supported. if (dram_type != DRAM_TYPE_LPDDR4) @@ -3645,12 +3624,12 @@ void _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg) s32 dram_temp = _get_dram_temperature(); - if (mtc_cfg->prev_temp == dram_temp || dram_temp < 0) + if (dram_temp < 0 || mtc_cfg->prev_temp == (u32)dram_temp) return; - u32 refr = mtc_cfg->current_emc_table->burst_regs.emc_refresh_idx; - u32 pre_refr = mtc_cfg->current_emc_table->burst_regs.emc_pre_refresh_req_cnt_idx; - u32 dyn_self_ref = mtc_cfg->current_emc_table->burst_regs.emc_dyn_self_ref_control_idx; + u32 refr = mtc_cfg->current_emc_table->burst_regs.emc_refresh; + u32 pre_refr = mtc_cfg->current_emc_table->burst_regs.emc_pre_refresh_req_cnt; + u32 dyn_self_ref = mtc_cfg->current_emc_table->burst_regs.emc_dyn_self_ref_control; switch (dram_temp) { @@ -3661,7 +3640,7 @@ void _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg) case 3: if (mtc_cfg->prev_temp < 4) { - mtc_cfg->prev_temp = dram_temp; + mtc_cfg->prev_temp = (u32)dram_temp; return; } break; @@ -3692,137 +3671,144 @@ u32 _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry) { if (mtc_table_entry && mtc_table_entry->periodic_training) { - u32 val = 0; - s32 dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1; - bool channel1_enabled = (mtc_table_entry->burst_regs.emc_fbio_cfg7_idx >> 2) & 1; + u32 dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1; + u32 pd_mask = (dram_dev_num == TWO_RANK) ? IN_POWERDOWN_BOTH_MASK : IN_POWERDOWN_1DEV_MASK; + bool channel1_enabled = (mtc_table_entry->burst_regs.emc_fbio_cfg7 >> 2) & 1; - //u32 emc_dbg_o = EMC(EMC_DBG); + (void)EMC(EMC_DBG); + + // Safekeep current config. u32 emc_cfg_o = EMC(EMC_CFG); - u32 emc_cfg = emc_cfg_o & 0xFFFFFFF; + u32 emc_cfg_dig_dll_o = EMC(EMC_CFG_DIG_DLL); + u32 emc_cfg_update_o = EMC(EMC_CFG_UPDATE); - // Step 1 - Disable other power features. - EMC(EMC_CFG) = emc_cfg; + // Step 1 - Disable digital DLL. + EMC(EMC_CFG_DIG_DLL) = emc_cfg_dig_dll_o & 0xFFFFFFFE; - _digital_dll_disable(); + // Step 1.2 - Always update auto cal in clock change. + EMC(EMC_CFG_UPDATE) = (emc_cfg_update_o & 0xFFFFF9FF) | 0x400; - if (dram_dev_num == TWO_RANK) - { - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, 0, EMC_CH0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, 0, EMC_CH1); - } - else - { - _wait_emc_status(EMC_EMC_STATUS, 0x10, 0, 0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, 0x10, 0, EMC_CH1); - } + // Step 1.3 - Disable other power features. + EMC(EMC_CFG) = emc_cfg_o & 0xFFFFFFF; - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CH0); + // Timing update and wait for everything to power down. + _timing_update(channel1_enabled); + + _wait_emc_status(EMC_EMC_STATUS, pd_mask, 0, EMC_CHANNEL0); if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CH1); + _wait_emc_status(EMC_EMC_STATUS, pd_mask, 0, EMC_CHANNEL1); - //_wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, EMC_CH0); //v1.6 - //if (channel1_enabled) - // _wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, EMC_CH1); //v1.6 + _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CHANNEL0); + if (channel1_enabled) + _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CHANNEL1); - u32 emc_cfg_update = EMC(EMC_CFG_UPDATE); - EMC(EMC_CFG_UPDATE) = (emc_cfg_update & 0xFFFFF9FF) | 0x400; + _wait_emc_status(EMC_CFG_DIG_DLL, 1, 0, EMC_CHANNEL0); + if (channel1_enabled) + _wait_emc_status(EMC_CFG_DIG_DLL, 1, 0, EMC_CHANNEL1); // Step 2 - Osc kick off - this assumes training and dvfs have set correct MR23. _start_periodic_compensation(); // Step 3 - Let dram capture its clock tree delays. - _usleep(1000 * _actual_osc_clocks(mtc_table_entry->run_clocks) / mtc_table_entry->rate_khz + 1); + _usleep(1000 * _actual_osc_clocks(mtc_table_entry->run_clocks) / mtc_table_entry->rate_khz + 2); // Step 4 - Check delta wrt previous values (save value if margin exceeds what is set in table). - u32 adel = _minerva_update_clock_tree_delay(mtc_table_entry, mtc_table_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE); + u32 adelta = _minerva_update_clock_tree_delay(mtc_table_entry, mtc_table_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE); // Step 5 - Apply compensation w.r.t. trained values (if clock tree has drifted more than the set margin). - if (adel && ((mtc_table_entry->rate_khz / 1000) << 7) * adel / 1000000 > mtc_table_entry->tree_margin) + if (adelta && ((mtc_table_entry->rate_khz / 1000) * 128) * adelta / 1000000 > mtc_table_entry->tree_margin) { for (u32 i = 0; i < 10; i++) { - val = _minerva_apply_periodic_compensation_trimmer(mtc_table_entry, periodic_training_addr[i]); - EMC(periodic_training_addr[i]) = val; + EMC(periodic_training_addr[i]) = + _minerva_apply_periodic_compensation_trimmer(mtc_table_entry, periodic_training_addr[i]); } } + // Step 6 - Restore other power features. EMC(EMC_CFG) = emc_cfg_o; - // Step 6 - Timing update to apply the new trimmers. + // Step 6.1 - Restore the DLL. + EMC(EMC_CFG_DIG_DLL) = emc_cfg_dig_dll_o; + + // Step 6.2 - Timing update for applying the new trimmers. _timing_update(channel1_enabled); - // Step 6.1 - Restore the UPDATE_DLL_IN_UPDATE field. - EMC(EMC_CFG_UPDATE) = emc_cfg_update; - - // Step 6.2 - Restore the DLL. - _digital_dll_enable(channel1_enabled); + // Step 6.3 - Restore the UPDATE_DLL_IN_UPDATE field. + EMC(EMC_CFG_UPDATE) = emc_cfg_update_o; } return 0; } -s32 _minerva_set_rate(mtc_config_t *mtc_cfg) +static u32 _minerva_set_rate(mtc_config_t *mtc_cfg) { - s32 src_emc_entry_idx = 0; - s32 dst_emc_entry_idx = 999; - s32 table_entry_rate; + u32 src_emc_entry_idx = 999; + u32 dst_emc_entry_idx = 999; u32 selected_clk_src_emc; - u32 selected_emc_2x_clk_src; + u32 emc_clk_src; bool freq_changed = false; + bool src_is_pllmb; emc_table_t *src_emc_entry; emc_table_t *dst_emc_entry; + if (mtc_cfg->table_entries > 900) + return 4; + for (u32 i = 0; i < mtc_cfg->table_entries; i++) { - table_entry_rate = mtc_cfg->mtc_table[i].rate_khz; + u32 table_entry_rate = mtc_cfg->mtc_table[i].rate_khz; if (mtc_cfg->rate_from == table_entry_rate) src_emc_entry_idx = i; if (mtc_cfg->rate_to == table_entry_rate) dst_emc_entry_idx = i; } + if (src_emc_entry_idx >= mtc_cfg->table_entries) + return 4; + + if (dst_emc_entry_idx >= mtc_cfg->table_entries) + return 4; + src_emc_entry = (emc_table_t *)&mtc_cfg->mtc_table[src_emc_entry_idx]; dst_emc_entry = (emc_table_t *)&mtc_cfg->mtc_table[dst_emc_entry_idx]; - s32 src_rate_khz = src_emc_entry->rate_khz; - s32 dst_rate_khz = dst_emc_entry->rate_khz; + u32 src_rate_khz = src_emc_entry->rate_khz; + u32 dst_rate_khz = dst_emc_entry->rate_khz; u32 src_clk_src_emc = src_emc_entry->clk_src_emc; u32 dst_clk_src_emc = dst_emc_entry->clk_src_emc; - if (mtc_cfg->table_entries > 900) - return 4; - freq_changed = _check_freq_changed(dst_rate_khz, dst_clk_src_emc, src_rate_khz, src_clk_src_emc); EPRINTFARGS("Requested freq change from %d to %d.", src_rate_khz, dst_rate_khz); + // Get current clock source. + emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) >> EMC_2X_CLK_SRC_SHIFT; + src_is_pllmb = emc_clk_src == PLLMB_UD || emc_clk_src == PLLMB_OUT0; + if (freq_changed) { - selected_emc_2x_clk_src = src_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - if (selected_emc_2x_clk_src & 3) + if (emc_clk_src == PLLM_UD || + emc_clk_src == PLLM_OUT0) // Clock source is PLLM. Switch based on src_is_pllmb. { - if (selected_emc_2x_clk_src - PLLMB_UD <= 1) - emc_2X_clk_src_is_pllmb = 0; + src_is_pllmb = !src_is_pllmb; } - else + else if (emc_clk_src == PLLMB_UD || + emc_clk_src == PLLMB_OUT0) // Clock source is PLLMB. Switch to PLLM. { - emc_2X_clk_src_is_pllmb = !emc_2X_clk_src_is_pllmb; + src_is_pllmb = false; } - selected_clk_src_emc = _pllm_clk_base_cfg(dst_rate_khz, dst_clk_src_emc, emc_2X_clk_src_is_pllmb); + selected_clk_src_emc = _pllm_clk_base_cfg(dst_rate_khz, dst_clk_src_emc, src_is_pllmb); } else { selected_clk_src_emc = dst_clk_src_emc; - selected_emc_2x_clk_src = selected_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - if (selected_emc_2x_clk_src != PLLMB_OUT0 && selected_emc_2x_clk_src) + emc_clk_src = selected_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; + if (src_is_pllmb) { - if (selected_emc_2x_clk_src - PLLM_UD <= PLLC_OUT0 && emc_2X_clk_src_is_pllmb) + if (emc_clk_src == PLLM_UD || emc_clk_src == PLLMB_UD) selected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_UD << EMC_2X_CLK_SRC_SHIFT); - } - else if (emc_2X_clk_src_is_pllmb) - { - selected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_OUT0 << EMC_2X_CLK_SRC_SHIFT); + else if (emc_clk_src == PLLM_OUT0 || emc_clk_src == PLLMB_OUT0) + selected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_OUT0 << EMC_2X_CLK_SRC_SHIFT); } } @@ -3837,8 +3823,6 @@ s32 _minerva_set_rate(mtc_config_t *mtc_cfg) return 0; case OP_TRAIN: _minerva_train_patterns(src_emc_entry, dst_emc_entry, false, selected_clk_src_emc); - if (freq_changed) - emc_2X_clk_src_is_pllmb = !emc_2X_clk_src_is_pllmb; return 0; case OP_TRAIN_SWITCH: _minerva_train_patterns(src_emc_entry, dst_emc_entry, true, selected_clk_src_emc); @@ -3854,21 +3838,59 @@ s32 _minerva_set_rate(mtc_config_t *mtc_cfg) static void _minerva_get_table(mtc_config_t *mtc_cfg) { + memset(mtc_cfg->mtc_table, 0, EMC_TABLE_ENTRY_SIZE_R7 * 10); + switch (mtc_cfg->sdram_id) { - case 1: + case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN: memcpy(mtc_cfg->mtc_table, nx_abca2_2_10NoCfgVersion_V9_8_7_V1_6, EMC_TABLE_SIZE_R7); break; - case 0: - case 2: - case 3: - case 4: + case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH: + case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT: + case DRAM_4GB_COPPER_SAMSUNG: + case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH: + case DRAM_8GB_SAMSUNG_K4FBE3D4HM_MGXX: default: memcpy(mtc_cfg->mtc_table, nx_abca2_0_3_10NoCfgVersion_V9_8_7_V1_6, EMC_TABLE_SIZE_R7); + if (mtc_cfg->sdram_id == DRAM_8GB_SAMSUNG_K4FBE3D4HM_MGXX) + { + for (u32 i = 0; i < EMC_TABLE_SIZE_R7 / EMC_TABLE_ENTRY_SIZE_R7; i++) + { + emc_table_t *table = &mtc_cfg->mtc_table[i]; + u32 period = 1000000000 / table->rate_khz; + + table->burst_regs.emc_rfc = 280000 / period; + table->shadow_regs_ca_train.emc_rfc = 280000 / period; + table->shadow_regs_quse_train.emc_rfc = 280000 / period; + table->shadow_regs_rdwr_train.emc_rfc = 280000 / period; + + table->burst_regs.emc_rfcpb = 140000 / period; + table->shadow_regs_ca_train.emc_rfcpb = 140000 / period; + table->shadow_regs_quse_train.emc_rfcpb = 140000 / period; + table->shadow_regs_rdwr_train.emc_rfcpb = 140000 / period; + + table->burst_regs.emc_txsr = 287500 / period; + table->shadow_regs_ca_train.emc_txsr = 287500 / period; + table->shadow_regs_quse_train.emc_txsr = 287500 / period; + table->shadow_regs_rdwr_train.emc_txsr = 287500 / period; + + table->burst_regs.emc_txsrdll = table->burst_regs.emc_txsr; + table->shadow_regs_ca_train.emc_txsrdll = table->shadow_regs_ca_train.emc_txsr; + table->shadow_regs_quse_train.emc_txsrdll = table->shadow_regs_quse_train.emc_txsr; + table->shadow_regs_rdwr_train.emc_txsrdll = table->shadow_regs_rdwr_train.emc_txsr; + + table->burst_regs.emc_dyn_self_ref_control &= 0x7FFFFFFF; + table->shadow_regs_ca_train.emc_dyn_self_ref_control &= 0x7FFFFFFF; + table->shadow_regs_quse_train.emc_dyn_self_ref_control &= 0x7FFFFFFF; + table->shadow_regs_rdwr_train.emc_dyn_self_ref_control &= 0x7FFFFFFF; + + table->dram_timings.t_rfc = 280; + } + } break; } - mtc_cfg->table_entries = 10; + mtc_cfg->table_entries = EMC_TABLE_SIZE_R7 / EMC_TABLE_ENTRY_SIZE_R7; mtc_cfg->rate_to = 0; mtc_cfg->rate_from = 0; mtc_cfg->train_mode = 0; @@ -3876,36 +3898,40 @@ static void _minerva_get_table(mtc_config_t *mtc_cfg) mtc_cfg->current_emc_table = NULL; // Important! - mtc_cfg->emc_2X_clk_src_is_pllmb = false; - mtc_cfg->fsp_for_src_freq = false; mtc_cfg->train_ram_patterns = true; mtc_cfg->init_done = MTC_INIT_MAGIC; } -void _minerva_init(mtc_config_t *mtc_cfg, void* bp) +void _minerva_init(mtc_config_t *mtc_cfg, bdkParams_t bp) { EPRINTF("-- Minerva Training Cell --"); train_ram_patterns = mtc_cfg->train_ram_patterns; - fsp_for_src_freq = mtc_cfg->fsp_for_src_freq; - emc_2X_clk_src_is_pllmb = mtc_cfg->emc_2X_clk_src_is_pllmb; if (mtc_cfg->init_done != MTC_INIT_MAGIC) { if (mtc_cfg->init_done == MTC_NEW_MAGIC) + { _minerva_get_table(mtc_cfg); +#ifdef OVERCLOCK_VOLTAGE + // Set SD1 regulator voltage. + if ((bp->extension_magic & 0xF0FFFFFF) == IANOS_EXT0) + bp->reg_voltage_set(1, OVERCLOCK_VOLTAGE); +#endif + } return; } - // If this is set, it needs to be managed. Changing freq from OC to a lower - // must have the rate_from set to 2131200 and not 1600000 - // bool overclock = true; +#ifdef OVERCLOCK_FREQ + // Change max rate in table. + mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz = OVERCLOCK_FREQ; - // if (overclock && mtc_cfg->rate_to == 1600000) - // { - // mtc_cfg->rate_to = 2131200; - // mtc_cfg->mtc_table[9].rate_khz = 2131200; - // } + // Change rates for OC RAM. + if (mtc_cfg->rate_from == MAX_FREQ_T210) + mtc_cfg->rate_from = OVERCLOCK_FREQ; + if (mtc_cfg->rate_to == MAX_FREQ_T210) + mtc_cfg->rate_to = OVERCLOCK_FREQ; +#endif switch (mtc_cfg->train_mode) { @@ -3931,7 +3957,13 @@ void _minerva_init(mtc_config_t *mtc_cfg, void* bp) break; } +#ifdef OVERCLOCK_FREQ + // Restore rates for OC RAM. + if (mtc_cfg->rate_from == OVERCLOCK_FREQ) + mtc_cfg->rate_from = MAX_FREQ_T210; + if (mtc_cfg->rate_to == OVERCLOCK_FREQ) + mtc_cfg->rate_to = MAX_FREQ_T210; +#endif + mtc_cfg->train_ram_patterns = train_ram_patterns; - mtc_cfg->fsp_for_src_freq = fsp_for_src_freq; - mtc_cfg->emc_2X_clk_src_is_pllmb = emc_2X_clk_src_is_pllmb; } diff --git a/modules/hekate_libsys_minerva/types.h b/modules/hekate_libsys_minerva/types.h index 9a4d414..00c7662 100644 --- a/modules/hekate_libsys_minerva/types.h +++ b/modules/hekate_libsys_minerva/types.h @@ -20,6 +20,7 @@ #define NULL ((void *)0) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define BIT(n) (1U << (n)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/modules/simple_sample/Makefile b/modules/simple_sample/Makefile index d1aa6c9..2c0d7d7 100644 --- a/modules/simple_sample/Makefile +++ b/modules/simple_sample/Makefile @@ -7,15 +7,22 @@ include $(DEVKITARM)/base_rules TARGET := module_sample BUILD := ../../build/$(TARGET) OUTPUT := ../../output -VPATH = $(dir $(wildcard ./*/)) $(dir $(wildcard ./*/*/)) +SOURCEDIR = simple_sample +BDKDIR := bdk +BDKINC := -I../../$(BDKDIR) +VPATH = $(dir ./) $(dir $(wildcard ./*/)) OBJS = $(addprefix $(BUILD)/,\ module_sample.o \ gfx.o \ ) +GFX_INC := '"../modules/$(SOURCEDIR)/gfx/gfx.h"' + +CUSTOMDEFINES := -DGFX_INC=$(GFX_INC) + ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) +CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc .PHONY: clean all @@ -23,11 +30,12 @@ LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc all: $(TARGET).bso $(BUILD)/%.o: ./%.c @mkdir -p "$(BUILD)" - $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(TARGET).bso: $(OBJS) - $(CC) $(LDFLAGS) -e _modInit $^ -o $(OUTPUT)/$(TARGET).bso - $(STRIP) -g $(OUTPUT)/$(TARGET).bso + @$(CC) $(LDFLAGS) -e _modInit $^ -o $(OUTPUT)/$(TARGET).bso + @$(STRIP) -g $(OUTPUT)/$(TARGET).bso + @echo -e "-------------\nBuilt module: "$(TARGET)".bso\n-------------" clean: @rm -rf $(OUTPUT)/$(TARGET).bso diff --git a/modules/simple_sample/gfx/gfx.c b/modules/simple_sample/gfx/gfx.c index 9a154bc..0557f45 100644 --- a/modules/simple_sample/gfx/gfx.c +++ b/modules/simple_sample/gfx/gfx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +19,10 @@ #include #include "gfx.h" +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) @@ -117,110 +121,111 @@ static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) }; -void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride) +void gfx_clear_grey(u8 color) { - ctxt->fb = fb; - ctxt->width = width; - ctxt->height = height; - ctxt->stride = stride; + memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); } -void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color) +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) { - memset(ctxt->fb, color, 0x3C0000); + memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); } -void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color) +void gfx_clear_color(u32 color) { - for (u32 i = 0; i < ctxt->height * ctxt->stride; i++) - ctxt->fb[i] = color; + for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) + gfx_ctxt.fb[i] = color; } -void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height) +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) { - memset(ctxt->fb + pos_x * ctxt->stride, color, height * 4 * ctxt->stride); + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; } -void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt) +void gfx_con_init() { - con->gfx_ctxt = ctxt; - con->fntsz = 16; - con->x = 0; - con->y = 0; - con->savedx = 0; - con->savedy = 0; - con->fgcol = 0xFFCCCCCC; - con->fillbg = 0; - con->bgcol = 0xFF1B1B1B; - con->mute = 0; + gfx_con.gfx_ctxt = &gfx_ctxt; + gfx_con.fntsz = 16; + gfx_con.x = 0; + gfx_con.y = 0; + gfx_con.savedx = 0; + gfx_con.savedy = 0; + gfx_con.fgcol = 0xFFCCCCCC; + gfx_con.fillbg = 1; + gfx_con.bgcol = 0xFF1B1B1B; + gfx_con.mute = 0; } -void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol) +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) { - con->fgcol = fgcol; - con->fillbg = fillbg; - con->bgcol = bgcol; + gfx_con.fgcol = fgcol; + gfx_con.fillbg = fillbg; + gfx_con.bgcol = bgcol; } -void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y) +void gfx_con_getpos(u32 *x, u32 *y) { - *x = con->x; - *y = con->y; + *x = gfx_con.x; + *y = gfx_con.y; } -void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y) +void gfx_con_setpos(u32 x, u32 y) { - con->x = x; - con->y = y; + gfx_con.x = x; + gfx_con.y = y; } -void gfx_putc(gfx_con_t *con, char c) +void gfx_putc(char c) { // Duplicate code for performance reasons. - switch (con->fntsz) + switch (gfx_con.fntsz) { case 16: if (c >= 32 && c <= 126) { u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; - u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride; + u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; - for (u32 i = 0; i < 16; i+=2) + for (u32 i = 0; i < 16; i += 2) { - u8 v = *cbuf++; + u8 v = *cbuf; for (u32 k = 0; k < 2; k++) { for (u32 j = 0; j < 8; j++) { if (v & 1) { - *fb = con->fgcol; + *fb = gfx_con.fgcol; fb++; - *fb = con->fgcol; + *fb = gfx_con.fgcol; } - else if (con->fillbg) + else if (gfx_con.fillbg) { - *fb = con->bgcol; + *fb = gfx_con.bgcol; fb++; - *fb = con->bgcol; + *fb = gfx_con.bgcol; } else fb++; v >>= 1; fb++; } - fb += con->gfx_ctxt->stride - 16; + fb += gfx_ctxt.stride - 16; v = *cbuf; } + cbuf++; } - con->x += 16; + gfx_con.x += 16; } else if (c == '\n') { - con->x = 0; - con->y +=16; - if (con->y > con->gfx_ctxt->height - 16) - con->y = 0; + gfx_con.x = 0; + gfx_con.y += 16; + if (gfx_con.y > gfx_ctxt.height - 16) + gfx_con.y = 0; } break; case 8: @@ -228,44 +233,44 @@ void gfx_putc(gfx_con_t *con, char c) if (c >= 32 && c <= 126) { u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; - u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride; + u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * 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; + *fb = gfx_con.fgcol; + else if (gfx_con.fillbg) + *fb = gfx_con.bgcol; v >>= 1; fb++; } - fb += con->gfx_ctxt->stride - 8; + fb += gfx_ctxt.stride - 8; } - con->x += 8; + gfx_con.x += 8; } else if (c == '\n') { - con->x = 0; - con->y += 8; - if (con->y > con->gfx_ctxt->height - 8) - con->y = 0; + gfx_con.x = 0; + gfx_con.y += 8; + if (gfx_con.y > gfx_ctxt.height - 8) + gfx_con.y = 0; } break; } } -void gfx_puts(gfx_con_t *con, const char *s) +void gfx_puts(char *s) { - if (!s || con->mute) + if (!s || gfx_con.mute) return; for (; *s; s++) - gfx_putc(con, *s); + gfx_putc(*s); } -static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt) +static void _gfx_putn(u32 v, int base, char fill, int fcnt) { char buf[65]; static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; @@ -293,37 +298,37 @@ static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt) } } - gfx_puts(con, p); + gfx_puts(p); } -void gfx_put_small_sep(gfx_con_t *con) +void gfx_put_small_sep() { - u8 prevFontSize = con->fntsz; - con->fntsz = 8; - gfx_putc(con, '\n'); - con->fntsz = prevFontSize; + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; } -void gfx_put_big_sep(gfx_con_t *con) +void gfx_put_big_sep() { - u8 prevFontSize = con->fntsz; - con->fntsz = 16; - gfx_putc(con, '\n'); - con->fntsz = prevFontSize; + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 16; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; } -void gfx_printf(gfx_con_t *con, const char *fmt, ...) +void gfx_printf(const char *fmt, ...) { - if (con->mute) + if (gfx_con.mute) return; va_list ap; int fill, fcnt; va_start(ap, fmt); - while(*fmt) + while (*fmt) { - if(*fmt == '%') + if (*fmt == '%') { fmt++; fill = 0; @@ -347,40 +352,40 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...) switch(*fmt) { case 'c': - gfx_putc(con, va_arg(ap, u32)); + gfx_putc(va_arg(ap, u32)); break; case 's': - gfx_puts(con, va_arg(ap, char *)); + gfx_puts(va_arg(ap, char *)); break; case 'd': - _gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt); + _gfx_putn(va_arg(ap, u32), 10, fill, fcnt); break; case 'p': case 'P': case 'x': case 'X': - _gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt); + _gfx_putn(va_arg(ap, u32), 16, fill, fcnt); break; case 'k': - con->fgcol = va_arg(ap, u32); + gfx_con.fgcol = va_arg(ap, u32); break; case 'K': - con->bgcol = va_arg(ap, u32); - con->fillbg = 1; + gfx_con.bgcol = va_arg(ap, u32); + gfx_con.fillbg = 1; break; case '%': - gfx_putc(con, '%'); + gfx_putc('%'); break; case '\0': goto out; default: - gfx_putc(con, '%'); - gfx_putc(con, *fmt); + gfx_putc('%'); + gfx_putc(*fmt); break; } } else - gfx_putc(con, *fmt); + gfx_putc(*fmt); fmt++; } @@ -388,33 +393,33 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...) va_end(ap); } -void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len) +void gfx_hexdump(u32 base, const u8 *buf, u32 len) { - if (con->mute) + if (gfx_con.mute) return; - u8 prevFontSize = con->fntsz; - con->fntsz = 8; - for(u32 i = 0; i < len; i++) + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + for (u32 i = 0; i < len; i++) { - if(i % 0x10 == 0) + if (i % 0x10 == 0) { - if(i != 0) + if (i != 0) { - gfx_puts(con, "| "); - for(u32 j = 0; j < 0x10; j++) + gfx_puts("| "); + for (u32 j = 0; j < 0x10; j++) { u8 c = buf[i - 0x10 + j]; - if(c >= 32 && c <= 126) - gfx_putc(con, c); + if (c >= 32 && c <= 126) + gfx_putc(c); else - gfx_putc(con, '.'); + gfx_putc('.'); } - gfx_putc(con, '\n'); + gfx_putc('\n'); } - gfx_printf(con, "%08x: ", base + i); + gfx_printf("%08x: ", base + i); } - gfx_printf(con, "%02x ", buf[i]); + gfx_printf("%02x ", buf[i]); if (i == len - 1) { int ln = len % 0x10 != 0; @@ -423,22 +428,22 @@ void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len) { k = (len & 0xF) - 1; for (u32 j = 0; j < 0x10 - k; j++) - gfx_puts(con, " "); + gfx_puts(" "); } - gfx_puts(con, "| "); - for(u32 j = 0; j < (ln ? k : k + 1); j++) + gfx_puts("| "); + for (u32 j = 0; j < (ln ? k : k + 1); j++) { u8 c = buf[i - k + j]; - if(c >= 32 && c <= 126) - gfx_putc(con, c); + if (c >= 32 && c <= 126) + gfx_putc(c); else - gfx_putc(con, '.'); + gfx_putc('.'); } - gfx_putc(con, '\n'); + gfx_putc('\n'); } } - gfx_putc(con, '\n'); - con->fntsz = prevFontSize; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; } static int abs(int x) @@ -448,12 +453,12 @@ static int abs(int x) return x; } -void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color) +void gfx_set_pixel(u32 x, u32 y, u32 color) { - ctxt->fb[x + y * ctxt->stride] = color; + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; } -void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color) +void gfx_line(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; @@ -461,7 +466,7 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color) while (1) { - gfx_set_pixel(ctxt, x0, y0, color); + gfx_set_pixel(x0, y0, color); if (x0 == x1 && y0 == y1) break; e2 = err; @@ -478,51 +483,46 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color) } } -void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) { u32 pos = 0; for (u32 y = pos_y; y < (pos_y + size_y); y++) { for (u32 x = pos_x; x < (pos_x + size_x); x++) { - memset(&ctxt->fb[x + y*ctxt->stride], buf[pos], 4); + memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4); pos++; } } } -void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) { u32 pos = 0; for (u32 y = pos_y; y < (pos_y + size_y); y++) { for (u32 x = pos_x; x < (pos_x + size_x); x++) { - ctxt->fb[x + y*ctxt->stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); pos+=3; } } } -void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) { - u32 pos = 0; + u32 *ptr = (u32 *)buf; for (u32 y = pos_y; y < (pos_y + size_y); y++) - { for (u32 x = pos_x; x < (pos_x + size_x); x++) - { - ctxt->fb[x + y*ctxt->stride] = buf[pos]; - pos+=1; - } - } + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++; } -void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) { for (u32 y = pos_y; y < (pos_y + size_y); y++) { for (u32 x = pos_x; x < (pos_x + size_x); x++) - ctxt->fb[x + y*ctxt->stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x]; + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x]; } } diff --git a/modules/simple_sample/gfx/gfx.h b/modules/simple_sample/gfx/gfx.h index ecf42c9..ddcfd74 100644 --- a/modules/simple_sample/gfx/gfx.h +++ b/modules/simple_sample/gfx/gfx.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it @@ -19,28 +19,59 @@ #ifndef _GFX_H_ #define _GFX_H_ -#include "../../../common/common_gfx.h" +#include -void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride); -void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color); -void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height); -void gfx_clear_color(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); +#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) +#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) +#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) +#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) -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); -void gfx_put_small_sep(gfx_con_t *con); -void gfx_put_big_sep(gfx_con_t *con); -void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +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 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); +void gfx_clear_grey(u8 color); +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height); +void gfx_clear_color(u32 color); +void gfx_con_init(); +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol); +void gfx_con_getpos(u32 *x, u32 *y); +void gfx_con_setpos(u32 x, u32 y); +void gfx_putc(char c); +void gfx_puts(char *s); +void gfx_printf(const char *fmt, ...); +void gfx_hexdump(u32 base, const u8 *buf, u32 len); + +void gfx_set_pixel(u32 x, u32 y, u32 color); +void gfx_line(int x0, int y0, int x1, int y1, u32 color); +void gfx_put_small_sep(); +void gfx_put_big_sep(); +void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); #endif diff --git a/modules/simple_sample/module_sample.c b/modules/simple_sample/module_sample.c index 51b3681..a113644 100644 --- a/modules/simple_sample/module_sample.c +++ b/modules/simple_sample/module_sample.c @@ -2,11 +2,17 @@ 2018 - M4xw */ -#include "../../common/common_module.h" -#include "../../common/common_gfx.h" -#include "gfx/gfx.h" +#include +#include +#include void _modInit(void *moduleConfig, bdkParams_t bp) { - gfx_puts(bp->gfxCon, "Hello World!"); + memcpy(&gfx_con, bp->gfxCon, sizeof(gfx_con_t)); + memcpy(&gfx_ctxt, bp->gfxCtx, sizeof(gfx_ctxt_t)); + + gfx_puts("Hello World!"); + + memcpy(bp->gfxCon, &gfx_con, sizeof(gfx_con_t)); + memcpy(bp->gfxCtx, &gfx_ctxt, sizeof(gfx_ctxt_t)); } diff --git a/nyx/Makefile b/nyx/Makefile index af144ab..71709c5 100644 --- a/nyx/Makefile +++ b/nyx/Makefile @@ -16,25 +16,31 @@ TARGET := nyx BUILDDIR := ./../build OUTPUTDIR := ./../output SOURCEDIR = nyx_gui -VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) +BDKDIR := bdk +BDKINC := -I../$(BDKDIR) +VPATH = $(dir $(wildcard ./$(SOURCEDIR)/)) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) VPATH += $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/*/)) +VPATH += $(dir $(wildcard ../$(BDKDIR)/)) $(dir $(wildcard ../$(BDKDIR)/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/*/)) # Main and graphics. OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ - start.o \ + start.o exception_handlers.o \ nyx.o heap.o \ gfx.o \ - gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o \ + gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o gui_tools_partition_manager.o \ fe_emummc_tools.o fe_emmc_tools.o \ ) # Hardware. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ - bpmp.o clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \ - fuse.o kfuse.o minerva.o \ - sdmmc.o sdmmc_driver.o \ - bq24193.o max17050.o max7762x.o max77620-rtc.o regulator_5v.o \ - touch.o tmp451.o fan.o \ + bpmp.o ccplex.o clock.o di.o vic.o i2c.o irq.o timer.o \ + gpio.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \ + fuse.o kfuse.o \ + mc.o sdram.o minerva.o ramdisk.o \ + sdmmc.o sdmmc_driver.o emmc.o sd.o nx_emmc_bis.o \ + bm92t36.o bq24193.o max17050.o max7762x.o max77620-rtc.o regulator_5v.o \ + touch.o joycon.o tmp451.o fan.o \ + usbd.o xusbd.o usb_descriptors.o usb_gadget_ums.o usb_gadget_hid.o \ hw_init.o \ ) @@ -47,38 +53,52 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ # Horizon. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ - nx_emmc.o \ - hos.o pkg1.o pkg2.o sept.o \ + hos.o pkg1.o pkg2.o \ ) # Libraries. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ diskio.o ff.o ffunicode.o ffsystem.o \ - elfload.o elfreloc_arm.o \ + elfload.o elfreloc_arm.o blz.o \ lv_group.o lv_indev.o lv_obj.o lv_refr.o lv_style.o lv_vdb.o \ lv_draw.o lv_draw_rbasic.o lv_draw_vbasic.o lv_draw_arc.o lv_draw_img.o \ lv_draw_label.o lv_draw_line.o lv_draw_rect.o lv_draw_triangle.o \ lv_hal_disp.o lv_hal_indev.o lv_hal_tick.o \ interui_20.o interui_30.o ubuntu_mono.o hekate_symbol_20.o hekate_symbol_30.o hekate_symbol_120.o lv_font_builtin.o \ lv_anim.o lv_area.o lv_circ.o lv_color.o lv_font.o lv_ll.o lv_math.o lv_mem.o lv_task.o lv_txt.o lv_gc.o \ - lv_bar.o lv_btn.o lv_btnm.o lv_cb.o lv_cont.o lv_ddlist.o lv_img.o lv_kb.o lv_label.o lv_line.o lv_list.o lv_lmeter.o lv_mbox.o \ + lv_bar.o lv_btn.o lv_btnm.o lv_cb.o lv_cont.o lv_ddlist.o lv_img.o lv_label.o lv_line.o lv_list.o lv_lmeter.o lv_mbox.o \ lv_page.o lv_roller.o lv_slider.o lv_sw.o lv_tabview.o lv_ta.o lv_win.o lv_log.o lv_imgbtn.o \ lv_theme.o lv_theme_hekate.o \ ) +GFX_INC := '"../nyx/$(SOURCEDIR)/gfx/gfx.h"' +FFCFG_INC := '"../nyx/$(SOURCEDIR)/libs/fatfs/ffconf.h"' + ################################################################################ -CUSTOMDEFINES += -DNYX_LOAD_ADDR=$(NYX_LOAD_ADDR) -DNYX_MAGIC=$(NYX_MAGIC) -CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_RESERVED=$(NYXVERSION_RSVD) +CUSTOMDEFINES := -DNYX_LOAD_ADDR=$(NYX_LOAD_ADDR) -DNYX_MAGIC=$(NYX_MAGIC) +CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_VER_RL=$(NYXVERSION_REL) -# 0: UART_A, 1: UART_B. -#CUSTOMDEFINES += -DDEBUG_UART_PORT=1 +# BDK defines. +CUSTOMDEFINES += -DBDK_MC_ENABLE_AHB_REDIRECT -DBDK_MINERVA_CFG_FROM_RAM -DBDK_HW_EXTRA_DEINIT -DBDK_SDMMC_EXTRA_PRINT +CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) #CUSTOMDEFINES += -DDEBUG -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork -CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) -CFLAGS += -g +# UART Logging: Max baudrate 12.5M. Disables Joycon on Nyx if UARTB or UARTC. +# DEBUG_UART_PORT - 0: UART_A, 1: UART_B, 2: UART_C. +#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=0 + +# LvGL UART LOG. +#CUSTOMDEFINES += -DDEBUG_UART_LV_LOG + +#TODO: Considering reinstating some of these when pointer warnings have been fixed. +WARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow +#-fno-delete-null-pointer-checks +#-Wstack-usage=byte-size -fstack-usage + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork $(WARNINGS) +CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=NYX_LOAD_ADDR=$(NYX_LOAD_ADDR) ################################################################################ @@ -86,8 +106,11 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs .PHONY: all clean all: $(TARGET).bin - @echo -n "Nyx size is " - @wc -c < $(OUTPUTDIR)/$(TARGET).bin + @echo "--------------------------------------" + @echo -n "Nyx size: " + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) + @echo $(BIN_SIZE)" Bytes" + @echo "--------------------------------------" clean: @rm -rf $(OBJS) @@ -95,16 +118,23 @@ clean: @rm -rf $(OUTPUTDIR) $(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf - $(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@ + @$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) - $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + @printf "$(TARGET) was built with the following flags:\nCFLAGS: $(CFLAGS)\nLDFLAGS: $(LDFLAGS)\n" $(BUILDDIR)/$(TARGET)/%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ + @echo Building $@ + @$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@ $(BUILDDIR)/$(TARGET)/%.o: %.S + @echo Building $@ + @$(CC) $(CFLAGS) -c $< -o $@ + +$(OBJS): $(BUILDDIR)/$(TARGET) + +$(BUILDDIR)/$(TARGET): @mkdir -p "$(BUILDDIR)" @mkdir -p "$(BUILDDIR)/$(TARGET)" @mkdir -p "$(OUTPUTDIR)" - $(CC) $(CFLAGS) -c $< -o $@ diff --git a/nyx/README_RES.md b/nyx/README_RES.md index ada08fe..f4f54e3 100644 --- a/nyx/README_RES.md +++ b/nyx/README_RES.md @@ -2,11 +2,19 @@ The background for Nyx, must be a 1280 x 720 32-bit BMP. Alpha blending is taken into account. For that reason, if a solid background is required, that value must be 0xFF. There are sites that can produce the correct bmp. -The icons supported are 192 x 192 32-bit BMP. You can utilize transparency at will and make nice mixes with the button background. +The icons supported are 192 x 192 32-bit BMP. You can utilize transparency at will and make nice mixes with the button background. + +Additionally, using the `icon={sd path}`, the icon will get colorized if the name ends in `_hue.bmp`. That only works nicely if the icon is a white layout with transparency. + +If `_nobox.bmp` is used then the button background is removed. Useful for icon themes that aim for a specific style. + +A combo of both can be enabled via `_hue_nobox.bmp` suffix. + +The default system icons (`icon_switch.bmp` and `icon_payload.bmp`) can be replaced with white layouts that have transparency. They can also be replaced with normal icons if the following exist: `icon_switch_custom.bmp` or/and `icon_payload_custom.bmp` ## How to configure The background must go to /bootloader/res/background.bmp -The icons can be utilized either via `[boot entries names]` -> `boot entries names.bmp` or by using `icon={sd path}`, which should point at a bmp. +The icons can be utilized either via `[boot entries names]` -> `boot entries names.bmp` or by using `icon={sd path}` (preferred method), which should point at a bmp. diff --git a/nyx/nyx_gui/config/config.c b/nyx/nyx_gui/config.c similarity index 55% rename from nyx/nyx_gui/config/config.c rename to nyx/nyx_gui/config.c index dad9301..b70d437 100644 --- a/nyx/nyx_gui/config/config.c +++ b/nyx/nyx_gui/config.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,49 +17,54 @@ #include #include +#include + #include "config.h" -#include "ini.h" -#include "../gfx/gfx.h" -#include "../libs/fatfs/ff.h" -#include "../soc/fuse.h" -#include "../soc/t210.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/util.h" +#include extern hekate_config h_cfg; -extern bool sd_mount(); -extern void sd_unmount(bool deinit); +extern nyx_config n_cfg; void set_default_configuration() { - h_cfg.autoboot = 0; + h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; + + h_cfg.autoboot = 0; h_cfg.autoboot_list = 0; - h_cfg.bootwait = 3; - h_cfg.verification = 1; - h_cfg.se_keygen_done = 0; - h_cfg.sbar_time_keeping = 0; - h_cfg.backlight = 100; - h_cfg.autohosoff = 0; - h_cfg.autonogc = 1; - h_cfg.updater2p = 0; - h_cfg.brand = NULL; - h_cfg.tagline = NULL; + h_cfg.bootwait = 3; + h_cfg.noticker = 0; + h_cfg.backlight = 100; + h_cfg.autohosoff = h_cfg.t210b01 ? 1 : 0; + h_cfg.autonogc = 1; + h_cfg.updater2p = 0; + h_cfg.bootprotect = 0; + h_cfg.errors = 0; - h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; + h_cfg.eks = NULL; h_cfg.rcm_patched = fuse_check_patched_rcm(); + h_cfg.autorcm_enabled = false; h_cfg.emummc_force_disable = false; sd_power_cycle_time_start = 0; } +void set_nyx_default_configuration() +{ + n_cfg.theme_bg = 0x2D2D2D; + n_cfg.theme_color = 167; + n_cfg.entries_5_col = 0; + n_cfg.timeoff = 0; + n_cfg.home_screen = 0; + n_cfg.verification = 1; + n_cfg.ums_emmc_rw = 0; + n_cfg.jc_disable = 0; + n_cfg.jc_force_right = 0; + n_cfg.bpmp_clock = 0; +} + int create_config_entry() { - if (!sd_mount()) - return 1; - - char lbuf[32]; + char lbuf[64]; FIL fp; bool mainIniFound = false; @@ -87,41 +92,50 @@ int create_config_entry() if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) return 1; + // Add config entry. f_puts("[config]\nautoboot=", &fp); itoa(h_cfg.autoboot, lbuf, 10); f_puts(lbuf, &fp); + f_puts("\nautoboot_list=", &fp); itoa(h_cfg.autoboot_list, lbuf, 10); f_puts(lbuf, &fp); + /* + * Clamp value to default if it exceeds 20s to protect against corruption. + * Allow up to 20s though for use in cases where user needs lots of time. + * For example dock-only use and r2p with enough time to reach dock and cancel it. + */ + if (h_cfg.bootwait > 20) + h_cfg.bootwait = 3; f_puts("\nbootwait=", &fp); itoa(h_cfg.bootwait, lbuf, 10); f_puts(lbuf, &fp); - f_puts("\nverification=", &fp); - itoa(h_cfg.verification, lbuf, 10); - f_puts(lbuf, &fp); + f_puts("\nbacklight=", &fp); itoa(h_cfg.backlight, lbuf, 10); f_puts(lbuf, &fp); + + f_puts("\nnoticker=", &fp); + itoa(h_cfg.noticker, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautohosoff=", &fp); itoa(h_cfg.autohosoff, lbuf, 10); f_puts(lbuf, &fp); + f_puts("\nautonogc=", &fp); itoa(h_cfg.autonogc, lbuf, 10); f_puts(lbuf, &fp); + f_puts("\nupdater2p=", &fp); itoa(h_cfg.updater2p, lbuf, 10); f_puts(lbuf, &fp); - if (h_cfg.brand) - { - f_puts("\nbrand=", &fp); - f_puts(h_cfg.brand, &fp); - } - if (h_cfg.tagline) - { - f_puts("\ntagline=", &fp); - f_puts(h_cfg.tagline, &fp); - } + + f_puts("\nbootprotect=", &fp); + itoa(h_cfg.bootprotect, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\n", &fp); if (mainIniFound) @@ -162,11 +176,78 @@ int create_config_entry() break; } } + + ini_free(&ini_sections); } f_close(&fp); - sd_unmount(false); return 0; } +int create_nyx_config_entry(bool force_unmount) +{ + bool sd_mounted = sd_get_card_mounted(); + + if (!sd_mount()) + return 1; + + char lbuf[64]; + FIL fp; + + // Make sure that bootloader folder exists. + f_mkdir("bootloader"); + + if (f_open(&fp, "bootloader/nyx.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + return 1; + + // Add config entry. + f_puts("[config]\nthemebg=", &fp); + itoa(n_cfg.theme_bg, lbuf, 16); + f_puts(lbuf, &fp); + + f_puts("\nthemecolor=", &fp); + itoa(n_cfg.theme_color, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\nentries5col=", &fp); + itoa(n_cfg.entries_5_col, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\ntimeoff=", &fp); + itoa(n_cfg.timeoff, lbuf, 16); + f_puts(lbuf, &fp); + + f_puts("\nhomescreen=", &fp); + itoa(n_cfg.home_screen, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\nverification=", &fp); + itoa(n_cfg.verification, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\numsemmcrw=", &fp); + itoa(n_cfg.ums_emmc_rw, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\njcdisable=", &fp); + itoa(n_cfg.jc_disable, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\njcforceright=", &fp); + itoa(n_cfg.jc_force_right, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\nbpmpclock=", &fp); + itoa(n_cfg.bpmp_clock, lbuf, 10); + f_puts(lbuf, &fp); + + f_puts("\n", &fp); + + f_close(&fp); + + if (force_unmount || !sd_mounted) + sd_unmount(); + + return 0; +} diff --git a/bootloader/config/config.h b/nyx/nyx_gui/config.h similarity index 69% rename from bootloader/config/config.h rename to nyx/nyx_gui/config.h index a6fbc5c..d2076e8 100644 --- a/bootloader/config/config.h +++ b/nyx/nyx_gui/config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +17,9 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#include "../utils/types.h" +#include + +#include "hos/hos.h" typedef struct _hekate_config { @@ -25,29 +27,38 @@ typedef struct _hekate_config u32 autoboot; u32 autoboot_list; u32 bootwait; - u32 verification; + u32 noticker; u32 backlight; u32 autohosoff; u32 autonogc; u32 updater2p; - char *brand; - char *tagline; + u32 bootprotect; // Global temporary config. - bool se_keygen_done; - bool sept_run; + bool t210b01; bool emummc_force_disable; bool rcm_patched; - u32 sbar_time_keeping; + bool autorcm_enabled; u32 errors; + hos_eks_mbr_t *eks; } hekate_config; +typedef struct _nyx_config +{ + u32 theme_bg; + u32 theme_color; + u32 entries_5_col; + u32 timeoff; + u32 home_screen; + u32 verification; + u32 ums_emmc_rw; + u32 jc_disable; + u32 jc_force_right; + u32 bpmp_clock; +} nyx_config; + void set_default_configuration(); +void set_nyx_default_configuration(); int create_config_entry(); -void config_autoboot(); -void config_bootdelay(); -void config_verification(); -void config_backlight(); -void config_auto_hos_poweroff(); -void config_nogc(); +int create_nyx_config_entry(bool force_unmount); #endif /* _CONFIG_H_ */ diff --git a/nyx/nyx_gui/frontend/fe_emmc_tools.c b/nyx/nyx_gui/frontend/fe_emmc_tools.c index d8fd361..2264f8a 100644 --- a/nyx/nyx_gui/frontend/fe_emmc_tools.c +++ b/nyx/nyx_gui/frontend/fe_emmc_tools.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 Rajko Stojadinovic - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,54 +21,63 @@ #include #include +#include + #include "gui.h" #include "fe_emmc_tools.h" #include "fe_emummc_tools.h" -#include "../../../common/memory_map.h" -#include "../config/config.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" +#include "../config.h" +#include #define NUM_SECTORS_PER_ITER 8192 // 4MB Cache. #define OUT_FILENAME_SZ 128 #define HASH_FILENAME_SZ (OUT_FILENAME_SZ + 11) // 11 == strlen(".sha256sums") -#define SHA256_SZ 0x20 -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; -extern hekate_config h_cfg; +extern nyx_config n_cfg; -extern bool sd_mount(); -extern void sd_unmount(bool deinit); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); +extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); -static void get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_idx, bool backup) +static void _get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_idx, bool backup) { sd_mount(); - u8 *mbr = (u8 *)malloc(0x200); + mbr_t *mbr = (mbr_t *)zalloc(sizeof(mbr_t)); sdmmc_storage_read(&sd_storage, 0, 1, mbr); - memcpy(mbr, mbr + 0x1BE, 0x40); - *part_idx = 0; int i = 0; u32 curr_part_size = 0; + // Find first partition with emuMMC GPP. for (i = 1; i < 4; i++) { - curr_part_size = *(u32 *)&mbr[0x0C + (0x10 * i)]; - *sector_start = *(u32 *)&mbr[0x08 + (0x10 * i)]; - u8 type = mbr[0x04 + (0x10 * i)]; - if ((curr_part_size >= *sector_size) && *sector_start && type != 0x83 && (!backup || type == 0xE0)) - break; + curr_part_size = mbr->partitions[i].size_sct; + *sector_start = mbr->partitions[i].start_sct; + u8 type = mbr->partitions[i].type; + u32 sector_size_safe = backup ? 0x400000 : (*sector_size) + 0x8000; // 2GB min safe size for backup. + if ((curr_part_size >= sector_size_safe) && (*sector_start) && type != 0x83 && (!backup || type == 0xE0)) + { + if (backup) + { + u8 gpt_check[SD_BLOCKSIZE] = { 0 }; + sdmmc_storage_read(&sd_storage, (*sector_start) + 0xC001, 1, gpt_check); + if (!memcmp(gpt_check, "EFI PART", 8)) + { + *sector_size = curr_part_size; + *sector_start = (*sector_start) + 0x8000; + break; + } + sdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt_check); + if (!memcmp(gpt_check, "EFI PART", 8)) + { + *sector_size = curr_part_size; + break; + } + } + else + break; + } } + free(mbr); + if (i < 4) *part_idx = i; else @@ -76,43 +85,33 @@ static void get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_i *sector_start = 0; *sector_size = 0; *part_idx = 0; - goto out; } - if (!backup) - *sector_start = *sector_start + 0x8000; - else + // Get emuMMC GPP size. + if (backup && *part_idx && *sector_size) { - *sector_size = curr_part_size; - sdmmc_storage_read(&sd_storage, *sector_start + 0xC001, 1, mbr); - if (!memcmp(mbr, "EFI PART", 8)) - { - *sector_start = *sector_start + 0x8000; - goto out; - } - sdmmc_storage_read(&sd_storage, *sector_start + 0x4001, 1, mbr); - if (!memcmp(mbr, "EFI PART", 8)) - goto out; + gpt_t *gpt = (gpt_t *)zalloc(sizeof(gpt_t)); + sdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt); - sdmmc_storage_read(&sd_storage, *sector_start + 0x4003, 1, mbr); - if (!memcmp(mbr, "EFI PART", 8)) - { - *sector_start = *sector_start + 2; - goto out; - } + u32 new_size = gpt->header.alt_lba + 1; + if (*sector_size > new_size) + *sector_size = new_size; + else + *sector_size = 0; + + free(gpt); } - -out: - free(mbr); + else if (!backup && *part_idx) + *sector_start = (*sector_start) + 0x8000; } -static lv_obj_t *create_mbox_text(char *text, bool button_ok) +static lv_obj_t *create_mbox_text(const char *text, bool button_ok) { lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char * mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); @@ -138,24 +137,23 @@ static void _update_filename(char *outFilename, u32 sdPathLen, u32 currPartIdx) itoa(currPartIdx, &outFilename[sdPathLen], 10); } -static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part) +static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lba_curr, const char *outFilename, const emmc_part_t *part) { FIL fp; FIL hashFp; u8 sparseShouldVerify = 4; - u32 btn = 0; u32 prevPct = 200; u32 sdFileSector = 0; int res = 0; - const char hexa[] = "0123456789abcdef"; + static const char hexa[] = "0123456789abcdef"; DWORD *clmt = NULL; - u8 hashEm[SHA256_SZ]; - u8 hashSd[SHA256_SZ]; + u8 hashEm[SE_SHA_256_SIZE]; + u8 hashSd[SE_SHA_256_SIZE]; if (f_open(&fp, outFilename, FA_READ) == FR_OK) { - if (h_cfg.verification == 3) + if (n_cfg.verification == 3) { char hashFilename[HASH_FILENAME_SZ]; strncpy(hashFilename, outFilename, OUT_FILENAME_SZ - 1); @@ -167,7 +165,7 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 f_close(&fp); s_printf(gui->txt_buf, - "#FF0000 Hash file could not be written (error %d)!#\n" + "\n#FF0000 Hash file could not be written (error %d)!#\n" "#FF0000 Aborting..#\n", res); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -176,7 +174,7 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 } char chunkSizeAscii[10]; - itoa(NUM_SECTORS_PER_ITER * NX_EMMC_BLOCKSIZE, chunkSizeAscii, 10); + itoa(NUM_SECTORS_PER_ITER * EMMC_BLOCKSIZE, chunkSizeAscii, 10); chunkSizeAscii[9] = '\0'; f_puts("# chunksize: ", &hashFp); @@ -192,12 +190,12 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); lv_bar_set_value(gui->bar, pct); lv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_teal_bg); - lv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, lv_theme_get_current()->bar.indic); + lv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_teal_ind); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); - clmt = f_expand_cltbl(&fp, 0x400000, 0); + clmt = f_expand_cltbl(&fp, SZ_4M, 0); u32 num = 0; while (totalSectorsVer > 0) @@ -207,12 +205,12 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 // Check every time or every 4. // Every 4 protects from fake sd, sector corruption and frequent I/O corruption. // Full provides all that, plus protection from extremely rare I/O corruption. - if ((h_cfg.verification >= 2) || !(sparseShouldVerify % 4)) + if ((n_cfg.verification >= 2) || !(sparseShouldVerify % 4)) { if (!sdmmc_storage_read(storage, lba_curr, num, bufEm)) { s_printf(gui->txt_buf, - "#FF0000 Failed to read %d blocks (@LBA %08X),#\n" + "\n#FF0000 Failed to read %d blocks (@LBA %08X),#\n" "#FF0000 from eMMC! Verification failed..#\n", num, lba_curr); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -220,19 +218,19 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 free(clmt); f_close(&fp); - if (h_cfg.verification == 3) + if (n_cfg.verification == 3) f_close(&hashFp); return 1; } - + manual_system_maintenance(false); se_calc_sha256(hashEm, NULL, bufEm, num << 9, 0, SHA_INIT_HASH, false); f_lseek(&fp, (u64)sdFileSector << (u64)9); if (f_read_fast(&fp, bufSd, num << 9)) { s_printf(gui->txt_buf, - "#FF0000 Failed to read %d blocks (@LBA %08X),#\n" + "\n#FF0000 Failed to read %d blocks (@LBA %08X),#\n" "#FF0000 from SD card! Verification failed..#\n", num, lba_curr); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -240,20 +238,20 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 free(clmt); f_close(&fp); - if (h_cfg.verification == 3) + if (n_cfg.verification == 3) f_close(&hashFp); return 1; } - + manual_system_maintenance(false); se_calc_sha256_finalize(hashEm, NULL); - se_calc_sha256(hashSd, NULL, bufSd, num << 9, 0, SHA_INIT_HASH, true); - res = memcmp(hashEm, hashSd, 0x10); + se_calc_sha256_oneshot(hashSd, bufSd, num << 9); + res = memcmp(hashEm, hashSd, SE_SHA_256_SIZE / 2); if (res) { s_printf(gui->txt_buf, - "#FF0000 SD & eMMC data (@LBA %08X) do not match!#\n" + "\n#FF0000 SD & eMMC data (@LBA %08X) do not match!#\n" "\n#FF0000 Verification failed..#\n", lba_curr); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -261,23 +259,23 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 free(clmt); f_close(&fp); - if (h_cfg.verification == 3) + if (n_cfg.verification == 3) f_close(&hashFp); return 1; } - if (h_cfg.verification == 3) + if (n_cfg.verification == 3) { // Transform computed hash to readable hexadecimal - char hashStr[SHA256_SZ * 2 + 1]; + char hashStr[SE_SHA_256_SIZE * 2 + 1]; char *hashStrPtr = hashStr; - for (int i = 0; i < SHA256_SZ; i++) + for (int i = 0; i < SE_SHA_256_SIZE; i++) { *(hashStrPtr++) = hexa[hashSd[i] >> 4]; *(hashStrPtr++) = hexa[hashSd[i] & 0x0F]; } - hashStr[SHA256_SZ * 2] = '\0'; + hashStr[SE_SHA_256_SIZE * 2] = '\0'; f_puts(hashStr, &hashFp); f_puts("\n", &hashFp); @@ -289,18 +287,20 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 { lv_bar_set_value(gui->bar, pct); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); prevPct = pct; } + manual_system_maintenance(false); + lba_curr += num; totalSectorsVer -= num; sdFileSector += num; sparseShouldVerify++; - btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP); - if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP)) + // Check for cancellation combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) { s_printf(gui->txt_buf, "#FFDD00 Verification was cancelled!#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -321,14 +321,14 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lv_bar_set_value(gui->bar, pct); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); return 0; } else { - s_printf(gui->txt_buf, "#FFDD00 File not found or could not be loaded!#\n#FFDD00 Verification failed..#\n"); + s_printf(gui->txt_buf, "\n#FFDD00 File not found or could not be loaded!#\n#FFDD00 Verification failed..#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -338,31 +338,55 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 bool partial_sd_full_unmount = false; -static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part) +static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, sdmmc_storage_t *storage, emmc_part_t *part) { - const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF; - const u32 SECTORS_TO_MIB_COEFF = 11; + static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF; + static const u32 SECTORS_TO_MIB_COEFF = 11; partial_sd_full_unmount = false; u32 multipartSplitSize = (1u << 31); + u32 lba_end = part->lba_end; u32 totalSectors = part->lba_end - part->lba_start + 1; u32 currPartIdx = 0; u32 numSplitParts = 0; u32 maxSplitParts = 0; - u32 btn = 0; bool isSmallSdCard = false; bool partialDumpInProgress = false; int res = 0; char *outFilename = sd_path; u32 sdPathLen = strlen(sd_path); + u32 sector_start = 0, part_idx = 0; + u32 sector_size = totalSectors; + u32 sd_sector_off = 0; + FIL partialIdxFp; char partialIdxFilename[12]; strcpy(partialIdxFilename, "partial.idx"); + if (gui->raw_emummc) + { + _get_valid_partition(§or_start, §or_size, &part_idx, true); + if (!part_idx || !sector_size) + { + s_printf(gui->txt_buf, "\n#FFDD00 Failed to find a partition...#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + return 0; + } + sd_sector_off = sector_start + (0x2000 * active_part); + if (active_part == 2) + { + // Set new total sectors and lba end sector for percentage calculations. + totalSectors = sector_size; + lba_end = sector_size + part->lba_start - 1; + } + } + s_printf(gui->txt_buf, "#96FF00 SD Card free space:# %d MiB\n#96FF00 Total backup size:# %d MiB\n\n", - sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, + (u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF), totalSectors >> SECTORS_TO_MIB_COEFF); lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -377,7 +401,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192) multipartSplitSize = (1u << 30); // Maximum parts fitting the free space available. - maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE); + maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / EMMC_BLOCKSIZE); // Check if the USER partition or the RAW eMMC fits the sd card free space. if (totalSectors > (sd_fs.free_clst * sd_fs.csize)) @@ -398,7 +422,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t } } // Check if we are continuing a previous raw eMMC or USER partition backup in progress. - if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) + if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) { s_printf(gui->txt_buf, "\n#AEFD14 Partial Backup in progress. Continuing...#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -431,9 +455,9 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t } // Check if filesystem is FAT32 or the free space is smaller and backup in parts. - if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) || isSmallSdCard) + if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) || isSmallSdCard) { - u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE; + u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE; numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors; outFilename[sdPathLen++] = '.'; @@ -487,15 +511,15 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t // Continue from where we left, if Partial Backup in progress. if (partialDumpInProgress) { - lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE); - totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE); + lba_curr += currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE); + totalSectors -= currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE); lbaStartPart = lba_curr; // Update the start LBA for verification. } u64 totalSize = (u64)((u64)totalSectors << 9); if (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT)) - clmt = f_expand_cltbl(&fp, 0x400000, totalSize); + clmt = f_expand_cltbl(&fp, SZ_4M, totalSize); else - clmt = f_expand_cltbl(&fp, 0x400000, MIN(totalSize, multipartSplitSize)); + clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize)); u32 num = 0; u32 pct = 0; @@ -511,7 +535,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t memset(&fp, 0, sizeof(fp)); currPartIdx++; - if (h_cfg.verification) + if (n_cfg.verification && !gui->raw_emummc) { // Verify part. if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part)) @@ -539,7 +563,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t } else { - s_printf(gui->txt_buf, "#FF0000 Error creating partial.idx file!#\n"); + s_printf(gui->txt_buf, "\n#FF0000 Error creating partial.idx file!#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -565,12 +589,10 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t // Create next part. s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path)); - lv_label_ins_text(gui->label_info, - strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path) - 1), - gui->txt_buf); lv_label_cut_text(gui->label_info, - strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path) - 1), + strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, strlen(outFilename + strlen(gui->base_path)) + 1); + lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); lbaStartPart = lba_curr; res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE); @@ -586,17 +608,34 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t bytesWritten = 0; totalSize = (u64)((u64)totalSectors << 9); - clmt = f_expand_cltbl(&fp, 0x400000, MIN(totalSize, multipartSplitSize)); + clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize)); } retryCount = 0; num = MIN(totalSectors, NUM_SECTORS_PER_ITER); - while (!sdmmc_storage_read(storage, lba_curr, num, buf)) + + int res_read; + if (!gui->raw_emummc) + res_read = !sdmmc_storage_read(storage, lba_curr, num, buf); + else + res_read = !sdmmc_storage_read(&sd_storage, lba_curr + sd_sector_off, num, buf); + + while (res_read) { - s_printf(gui->txt_buf, - "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" - "#FFDD00 from eMMC (try %d). #", - num, lba_curr, ++retryCount); + if (!gui->raw_emummc) + { + s_printf(gui->txt_buf, + "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" + "#FFDD00 from eMMC (try %d). #", + num, lba_curr, ++retryCount); + } + else + { + s_printf(gui->txt_buf, + "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" + "#FFDD00 from emuMMC @ %08X (try %d). #", + num, lba_curr + sd_sector_off, lba_curr, ++retryCount); + } lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -620,8 +659,9 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t manual_system_maintenance(true); } } + manual_system_maintenance(false); - res = f_write_fast(&fp, buf, NX_EMMC_BLOCKSIZE * num); + res = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num); if (res) { @@ -635,12 +675,15 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t return 0; } - pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); + + manual_system_maintenance(false); + + pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(lba_end - part->lba_start); if (pct != prevPct) { lv_bar_set_value(gui->bar, pct); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); prevPct = pct; @@ -648,7 +691,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t lba_curr += num; totalSectors -= num; - bytesWritten += num * NX_EMMC_BLOCKSIZE; + bytesWritten += num * EMMC_BLOCKSIZE; // Force a flush after a lot of data if not splitting. if (numSplitParts == 0 && bytesWritten >= multipartSplitSize) @@ -657,8 +700,8 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t bytesWritten = 0; } - btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP); - if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP)) + // Check for cancellation combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) { s_printf(gui->txt_buf, "\n#FFDD00 The backup was cancelled!#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -681,7 +724,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t f_close(&fp); free(clmt); - if (h_cfg.verification) + if (n_cfg.verification && !gui->raw_emummc) { // Verify last part or single file backup. if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part)) @@ -717,52 +760,55 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) int res = 0; u32 timer = 0; - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); gui->txt_buf = txt_buf; - s_printf(txt_buf, ""); - lv_label_set_array_text(gui->label_log, txt_buf, 0x1000); - lv_label_set_static_text(gui->label_info, "Checking for available free space..."); + txt_buf[0] = 0; + lv_label_set_text(gui->label_log, txt_buf); + + lv_label_set_text(gui->label_info, "Checking for available free space..."); manual_system_maintenance(true); - // Do a reinit to refresh tuning. - sd_unmount(true); - if (!sd_mount()) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init SD!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#"); goto out; } // Get SD Card free space for Partial Backup. f_getfree("", &sd_fs.free_clst, NULL); - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); goto out; } int i = 0; char sdPath[OUT_FILENAME_SZ]; // Create Restore folders, if they do not exist. - emmcsn_path_impl(sdPath, "/restore", "", &storage); - emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage); - emmcsn_path_impl(sdPath, "", "", &storage); + emmcsn_path_impl(sdPath, "/restore", "", &emmc_storage); + emmcsn_path_impl(sdPath, "/restore/emummc", "", &emmc_storage); + emmcsn_path_impl(sdPath, "/restore/partitions", "", &emmc_storage); + + // Set folder to backup/{emmc_sn}. + emmcsn_path_impl(sdPath, "", "", &emmc_storage); gui->base_path = (char *)malloc(strlen(sdPath) + 1); strcpy(gui->base_path, sdPath); timer = get_tmr_s(); if (dumpType & PART_BOOT) { - const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; + const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17; + const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB for emuMMC. emmc_part_t bootPart; memset(&bootPart, 0, sizeof(bootPart)); bootPart.lba_start = 0; - bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; + if (!gui->raw_emummc) + bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1; + else + bootPart.lba_end = BOOT_PART_SECTORS - 1; for (i = 0; i < 2; i++) { strcpy(bootPart.name, "BOOT"); @@ -771,15 +817,20 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", i, bootPart.name, bootPart.lba_start, bootPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, bootPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); - sdmmc_storage_set_mmc_partition(&storage, i + 1); + emmc_set_partition(i + 1); - emmcsn_path_impl(sdPath, "", bootPart.name, &storage); - res = _dump_emmc_part(gui, sdPath, &storage, &bootPart); + // Set filename to backup/{emmc_sn}/BOOT0/1 or backup/{emmc_sn}/emummc/BOOT0/1. + if (!gui->raw_emummc) + emmcsn_path_impl(sdPath, "", bootPart.name, &emmc_storage); + else + emmcsn_path_impl(sdPath, "/emummc", bootPart.name, &emmc_storage); + + res = _dump_emmc_part(gui, sdPath, i, &emmc_storage, &bootPart); if (!res) s_printf(txt_buf, "#FFDD00 Failed!#\n"); @@ -793,16 +844,16 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW)) { - sdmmc_storage_set_mmc_partition(&storage, 0); + emmc_set_partition(EMMC_GPP); if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER)) { - emmcsn_path_impl(sdPath, "/partitions", "", &storage); + emmcsn_path_impl(sdPath, "/partitions", "", &emmc_storage); gui->base_path = (char *)malloc(strlen(sdPath) + 1); strcpy(gui->base_path, sdPath); LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); + emmc_gpt_parse(&gpt); LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) { if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER")) @@ -812,14 +863,14 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", i, part->name, part->lba_start, part->lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, part->name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); i++; - emmcsn_path_impl(sdPath, "/partitions", part->name, &storage); - res = _dump_emmc_part(gui, sdPath, &storage, part); + emmcsn_path_impl(sdPath, "/partitions", part->name, &emmc_storage); + res = _dump_emmc_part(gui, sdPath, 0, &emmc_storage, part); // If a part failed, don't continue. if (!res) { @@ -833,13 +884,13 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); } - nx_emmc_gpt_free(&gpt); + emmc_gpt_free(&gpt); } if (dumpType & PART_RAW) { // Get GP partition size dynamically. - const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt; + const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt; emmc_part_t rawPart; memset(&rawPart, 0, sizeof(rawPart)); @@ -849,15 +900,20 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) { s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", i, rawPart.name, rawPart.lba_start, rawPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, rawPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); i++; - emmcsn_path_impl(sdPath, "", rawPart.name, &storage); - res = _dump_emmc_part(gui, sdPath, &storage, &rawPart); + // Set filename to backup/{emmc_sn}/rawnand.bin or backup/{emmc_sn}/emummc/rawnand.bin. + if (!gui->raw_emummc) + emmcsn_path_impl(sdPath, "", rawPart.name, &emmc_storage); + else + emmcsn_path_impl(sdPath, "/emummc", rawPart.name, &emmc_storage); + + res = _dump_emmc_part(gui, sdPath, 2, &emmc_storage, &rawPart); if (!res) s_printf(txt_buf, "#FFDD00 Failed!#\n"); @@ -871,33 +927,34 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui) } timer = get_tmr_s() - timer; - sdmmc_storage_end(&storage); + emmc_end(); - if (res && h_cfg.verification) + if (res && n_cfg.verification && !gui->raw_emummc) s_printf(txt_buf, "Time taken: %dm %ds.\n#96FF00 Finished and verified!#", timer / 60, timer % 60); else if (res) s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60); else s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60); - lv_label_set_array_text(gui->label_finish, txt_buf, 0x1000); + lv_label_set_text(gui->label_finish, txt_buf); out: free(txt_buf); free(gui->base_path); if (!partial_sd_full_unmount) - sd_unmount(false); + sd_unmount(); else { partial_sd_full_unmount = false; - sd_unmount(true); + sd_end(); } } static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part) { - const u32 SECTORS_TO_MIB_COEFF = 11; + static const u32 SECTORS_TO_MIB_COEFF = 11; + u32 lba_end = part->lba_end; u32 totalSectors = part->lba_end - part->lba_start + 1; u32 currPartIdx = 0; u32 numSplitParts = 0; @@ -920,99 +977,133 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa bool use_multipart = false; bool check_4MB_aligned = true; - if (allow_multi_part) + if (!allow_multi_part) + goto multipart_not_allowed; + + // Check to see if there is a combined file and if so then use that. + if (f_stat(outFilename, &fno)) { - // Check to see if there is a combined file and if so then use that. - if (f_stat(outFilename, &fno)) + // If not, check if there are partial files and the total size matches. + s_printf(gui->txt_buf, "\nNo single file, checking for part files...\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + outFilename[sdPathLen++] = '.'; + + _update_filename(outFilename, sdPathLen, numSplitParts); + + s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#", + gui->base_path, outFilename + strlen(gui->base_path)); + lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); + + // Stat total size of the part files. + while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors) { - // If not, check if there are partial files and the total size matches. - s_printf(gui->txt_buf, "\nNo single file, checking for part files...\n"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); - manual_system_maintenance(true); - - outFilename[sdPathLen++] = '.'; - _update_filename(outFilename, sdPathLen, numSplitParts); - s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#", - gui->base_path, outFilename + strlen(gui->base_path)); + s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path)); + lv_label_cut_text(gui->label_info, + strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, + strlen(outFilename + strlen(gui->base_path)) + 1); lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); - - // Stat total size of the part files. - while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors) - { - _update_filename(outFilename, sdPathLen, numSplitParts); - - s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path)); - lv_label_ins_text(gui->label_info, - strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, - gui->txt_buf); - lv_label_cut_text(gui->label_info, - strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, - strlen(outFilename + strlen(gui->base_path)) + 1); - manual_system_maintenance(true); - - if (f_stat(outFilename, &fno) && !gui->raw_emummc) - { - s_printf(gui->txt_buf, "#FFDD00 Error (%d) file not found#\n#FFDD00 %s.#\n#FFDD00 Aborting...#", res, outFilename); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); - manual_system_maintenance(true); - - return 0; - } - else if (f_stat(outFilename, &fno) && gui->raw_emummc) - { - totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9); - } - else - { - totalCheckFileSize += (u64)fno.fsize; - - if (check_4MB_aligned && (((u64)fno.fsize) % 0x400000)) - { - s_printf(gui->txt_buf, "#FFDD00 The split file must be a#\n#FFDD00 multiple of 4 MiB.#\n#FFDD00 Aborting...#", res, outFilename); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); - manual_system_maintenance(true); - - return 0; - } - - check_4MB_aligned = false; - } - - numSplitParts++; - } - - s_printf(gui->txt_buf, "%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9)); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); - if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors) + if ((u32)((u64)totalCheckFileSize >> (u64)9) > totalSectors) { - s_printf(gui->txt_buf, "#FF0000 Size of SD Card split backup does not match,#\n#FF0000 eMMC's selected part size!#\n"); + s_printf(gui->txt_buf, "\n#FF8000 Size of SD Card split backup exceeds#\n#FF8000 eMMC's selected part size!#\n#FFDD00 Aborting...#"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); return 0; } + else if (f_stat(outFilename, &fno)) + { + if (!gui->raw_emummc) + { + s_printf(gui->txt_buf, "\n#FFDD00 Error (%d) file not found#\n#FFDD00 %s.#\n\n", res, outFilename); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + // Attempt a smaller restore. + if (numSplitParts) + break; + } + else + { + // Set new total sectors and lba end sector for percentage calculations. + totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9); + lba_end = totalSectors + part->lba_start - 1; + } + + // Restore folder is empty. + if (!numSplitParts) + { + s_printf(gui->txt_buf, "\n#FFDD00 Restore folder is empty.#\n\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + return 0; + } + } else { - use_multipart = true; - _update_filename(outFilename, sdPathLen, 0); + totalCheckFileSize += (u64)fno.fsize; + + if (check_4MB_aligned && (((u64)fno.fsize) % SZ_4M)) + { + s_printf(gui->txt_buf, "\n#FFDD00 The split file must be a#\n#FFDD00 multiple of 4 MiB.#\n#FFDD00 Aborting...#"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + return 0; + } + + check_4MB_aligned = false; } + + numSplitParts++; } + + s_printf(gui->txt_buf, "%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9)); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors) + { + lv_obj_t *warn_mbox_bg = create_mbox_text( + "#FF8000 Size of SD Card split backup does not match#\n#FF8000 eMMC's selected part size!#\n\n" + "#FFDD00 The backup might be corrupted,#\n#FFDD00 or missing files!#\n#FFDD00 Aborting is suggested!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false); + manual_system_maintenance(true); + + if (!(btn_wait() & BTN_POWER)) + { + lv_obj_del(warn_mbox_bg); + s_printf(gui->txt_buf, "\n#FF0000 Size of SD Card split backup does not match#\n#FF0000 eMMC's selected part size!#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + return 0; + } + lv_obj_del(warn_mbox_bg); + + // Set new total sectors and lba end sector for percentage calculations. + totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9); + lba_end = totalSectors + part->lba_start - 1; + } + use_multipart = true; + _update_filename(outFilename, sdPathLen, 0); } +multipart_not_allowed: res = f_open(&fp, outFilename, FA_READ); if (use_multipart) { s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path)); - lv_label_ins_text(gui->label_info, - strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, - gui->txt_buf); lv_label_cut_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, strlen(outFilename + strlen(gui->base_path)) + 1); + lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); } else @@ -1037,13 +1128,13 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa manual_system_maintenance(true); } - return 0; + return -1; } else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size. { - if (!gui->raw_emummc) + if (((u32)((u64)f_size(&fp) >> (u64)9)) > totalSectors) { - s_printf(gui->txt_buf, "\n#FF0000 Size of the SD Card backup does not match,#\n#FF0000 eMMC's selected part size.#\n", res); + s_printf(gui->txt_buf, "\n#FF8000 Size of SD Card backup exceeds#\n#FF8000 eMMC's selected part size!#\n#FFDD00 Aborting...#"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -1051,8 +1142,30 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa return 0; } - else - totalSectors = (u32)((u64)f_size(&fp) >> (u64)9); + else if (!gui->raw_emummc) + { + lv_obj_t *warn_mbox_bg = create_mbox_text( + "#FF8000 Size of the SD Card backup does not match#\n#FF8000 eMMC's selected part size!#\n\n" + "#FFDD00 The backup might be corrupted!#\n#FFDD00 Aborting is suggested!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false); + manual_system_maintenance(true); + + if (!(btn_wait() & BTN_POWER)) + { + lv_obj_del(warn_mbox_bg); + s_printf(gui->txt_buf, "\n#FF0000 Size of the SD Card backup does not match#\n#FF0000 eMMC's selected part size.#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + f_close(&fp); + + return 0; + } + lv_obj_del(warn_mbox_bg); + } + // Set new total sectors and lba end sector for percentage calculations. + totalSectors = (u32)((u64)f_size(&fp) >> (u64)9); + lba_end = totalSectors + part->lba_start - 1; } else { @@ -1073,7 +1186,7 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa u32 num = 0; u32 pct = 0; - DWORD *clmt = f_expand_cltbl(&fp, 0x400000, 0); + DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0); u32 sector_start = 0, part_idx = 0; u32 sector_size = totalSectors; @@ -1081,10 +1194,10 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa if (gui->raw_emummc) { - get_valid_partition(§or_start, §or_size, &part_idx, false); - if (!part_idx) + _get_valid_partition(§or_start, §or_size, &part_idx, false); + if (!part_idx || !sector_size) { - s_printf(gui->txt_buf, "#FFDD00 Failed to find a partition...#\n"); + s_printf(gui->txt_buf, "\n#FFDD00 Failed to find a partition...#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -1106,12 +1219,12 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa memset(&fp, 0, sizeof(fp)); currPartIdx++; - if (h_cfg.verification && !gui->raw_emummc) + if (n_cfg.verification && !gui->raw_emummc) { // Verify part. if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part)) { - s_printf(gui->txt_buf, "#FFDD00 Please try again...#\n"); + s_printf(gui->txt_buf, "\n#FFDD00 Please try again...#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -1123,12 +1236,10 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa // Read from next part. s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path)); - lv_label_ins_text(gui->label_info, - strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, - gui->txt_buf); lv_label_cut_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1, strlen(outFilename + strlen(gui->base_path)) + 1); + lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); lbaStartPart = lba_curr; @@ -1137,7 +1248,7 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa res = f_open(&fp, outFilename, FA_READ); if (res) { - s_printf(gui->txt_buf, "#FF0000 Error (%d) while opening file#\n#FFDD00 %s!#\n", res, outFilename); + s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while opening file#\n#FFDD00 %s!#\n", res, outFilename); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -1145,19 +1256,20 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa } fileSize = (u64)f_size(&fp); bytesWritten = 0; - clmt = f_expand_cltbl(&fp, 0x400000, 0); + clmt = f_expand_cltbl(&fp, SZ_4M, 0); } retryCount = 0; num = MIN(totalSectors, NUM_SECTORS_PER_ITER); res = f_read_fast(&fp, buf, num << 9); + manual_system_maintenance(false); if (res) { s_printf(gui->txt_buf, "\n#FF0000 Fatal error (%d) when reading from SD!#\n" - "#FF0000 Your device may be in an inoperative state!#\n" + "#FF0000 This device may be in an inoperative state!#\n" "#FFDD00 Please try again now!#\n", res); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -1170,10 +1282,13 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa res = !sdmmc_storage_write(storage, lba_curr, num, buf); else res = !sdmmc_storage_write(&sd_storage, lba_curr + sd_sector_off, num, buf); + + manual_system_maintenance(false); + while (res) { s_printf(gui->txt_buf, - "#FFDD00 Error reading %d blocks @ LBA %08X,#\n" + "\n#FFDD00 Error writing %d blocks @ LBA %08X,#\n" "#FFDD00 from eMMC (try %d). #", num, lba_curr, ++retryCount); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -1183,7 +1298,7 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa if (retryCount >= 3) { s_printf(gui->txt_buf, "#FF0000 Aborting...#\n" - "#FF0000 Your device may be in an inoperative state!#\n" + "#FF0000 This device may be in an inoperative state!#\n" "#FFDD00 Please try again now!#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -1202,20 +1317,21 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa res = !sdmmc_storage_write(storage, lba_curr, num, buf); else res = !sdmmc_storage_write(&sd_storage, lba_curr + sd_sector_off, num, buf); + manual_system_maintenance(false); } - pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); + pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(lba_end - part->lba_start); if (pct != prevPct) { lv_bar_set_value(gui->bar, pct); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); prevPct = pct; } lba_curr += num; totalSectors -= num; - bytesWritten += num * NX_EMMC_BLOCKSIZE; + bytesWritten += num * EMMC_BLOCKSIZE; } lv_bar_set_value(gui->bar, 100); lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%"); @@ -1225,7 +1341,7 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa f_close(&fp); free(clmt); - if (h_cfg.verification && !gui->raw_emummc) + if (n_cfg.verification && !gui->raw_emummc) { // Verify restored data. if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part)) @@ -1266,16 +1382,16 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui) int res = 0; u32 timer = 0; - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); gui->txt_buf = txt_buf; - s_printf(txt_buf, ""); - lv_label_set_array_text(gui->label_log, txt_buf, 0x1000); + + txt_buf[0] = 0; + lv_label_set_text(gui->label_log, txt_buf); manual_system_maintenance(true); - sd_unmount(true); s_printf(txt_buf, - "#FFDD00 This may render your device inoperative!#\n\n" + "#FFDD00 This may render the device inoperative!#\n\n" "#FFDD00 Are you really sure?#"); if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL)) { @@ -1303,10 +1419,9 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui) lv_mbox_set_text(warn_mbox, txt_buf); manual_system_maintenance(true); - u32 btn = btn_wait(); - if (!(btn & BTN_POWER)) + if (!(btn_wait() & BTN_POWER)) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Restore operation was aborted!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Restore operation was aborted!#"); lv_obj_del(warn_mbox_bg); goto out; } @@ -1315,34 +1430,38 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui) if (!sd_mount()) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init SD!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#"); goto out; } - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); goto out; } int i = 0; char sdPath[OUT_FILENAME_SZ]; - - emmcsn_path_impl(sdPath, "/restore", "", &storage); + if (!gui->raw_emummc) + emmcsn_path_impl(sdPath, "/restore", "", &emmc_storage); + else + emmcsn_path_impl(sdPath, "/restore/emummc", "", &emmc_storage); gui->base_path = (char *)malloc(strlen(sdPath) + 1); strcpy(gui->base_path, sdPath); timer = get_tmr_s(); if (restoreType & PART_BOOT) { - const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; + const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17; + const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB for emuMMC. emmc_part_t bootPart; memset(&bootPart, 0, sizeof(bootPart)); bootPart.lba_start = 0; - bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; + if (!gui->raw_emummc) + bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1; + else + bootPart.lba_end = BOOT_PART_SECTORS - 1; for (i = 0; i < 2; i++) { strcpy(bootPart.name, "BOOT"); @@ -1351,64 +1470,73 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui) s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n", i, bootPart.name, bootPart.lba_start, bootPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, bootPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); - sdmmc_storage_set_mmc_partition(&storage, i + 1); + emmc_set_partition(i + 1); - emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage); - res = _restore_emmc_part(gui, sdPath, i, &storage, &bootPart, false); + if (!gui->raw_emummc) + emmcsn_path_impl(sdPath, "/restore", bootPart.name, &emmc_storage); + else + emmcsn_path_impl(sdPath, "/restore/emummc", bootPart.name, &emmc_storage); + res = _restore_emmc_part(gui, sdPath, i, &emmc_storage, &bootPart, false); if (!res) s_printf(txt_buf, "#FFDD00 Failed!#\n"); - else + else if (res > 0) s_printf(txt_buf, "Done!\n"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + if (res >= 0) + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + else + res = 0; manual_system_maintenance(true); } } if (restoreType & PART_GP_ALL) { - emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage); + emmcsn_path_impl(sdPath, "/restore/partitions", "", &emmc_storage); gui->base_path = (char *)malloc(strlen(sdPath) + 1); strcpy(gui->base_path, sdPath); - sdmmc_storage_set_mmc_partition(&storage, 0); + emmc_set_partition(EMMC_GPP); LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); + emmc_gpt_parse(&gpt); LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) { s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n", i, part->name, part->lba_start, part->lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, part->name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); i++; - emmcsn_path_impl(sdPath, "/restore/partitions", part->name, &storage); - res = _restore_emmc_part(gui, sdPath, 0, &storage, part, false); + emmcsn_path_impl(sdPath, "/restore/partitions", part->name, &emmc_storage); + res = _restore_emmc_part(gui, sdPath, 0, &emmc_storage, part, false); if (!res) s_printf(txt_buf, "#FFDD00 Failed!#\n"); - else + else if (res > 0) s_printf(txt_buf, "Done!\n"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + if (res >= 0) + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + else + res = 0; manual_system_maintenance(true); } - nx_emmc_gpt_free(&gpt); + emmc_gpt_free(&gpt); } if (restoreType & PART_RAW) { // Get GP partition size dynamically. - const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt; + const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt; emmc_part_t rawPart; memset(&rawPart, 0, sizeof(rawPart)); @@ -1418,39 +1546,45 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui) { s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n", i, rawPart.name, rawPart.lba_start, rawPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, rawPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); i++; - emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage); - res = _restore_emmc_part(gui, sdPath, 2, &storage, &rawPart, true); + if (!gui->raw_emummc) + emmcsn_path_impl(sdPath, "/restore", rawPart.name, &emmc_storage); + else + emmcsn_path_impl(sdPath, "/restore/emummc", rawPart.name, &emmc_storage); + res = _restore_emmc_part(gui, sdPath, 2, &emmc_storage, &rawPart, true); if (!res) s_printf(txt_buf, "#FFDD00 Failed!#\n"); - else + else if (res > 0) s_printf(txt_buf, "Done!\n"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + if (res >= 0) + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + else + res = 0; manual_system_maintenance(true); } } timer = get_tmr_s() - timer; - sdmmc_storage_end(&storage); + emmc_end(); - if (res && h_cfg.verification) + if (res && n_cfg.verification && !gui->raw_emummc) s_printf(txt_buf, "Time taken: %dm %ds.\n#96FF00 Finished and verified!#", timer / 60, timer % 60); else if (res) s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60); else s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60); - lv_label_set_array_text(gui->label_finish, txt_buf, 0x1000); + lv_label_set_text(gui->label_finish, txt_buf); out: free(txt_buf); free(gui->base_path); - sd_unmount(false); + sd_unmount(); } diff --git a/nyx/nyx_gui/frontend/fe_emmc_tools.h b/nyx/nyx_gui/frontend/fe_emmc_tools.h index 146472d..cb4aba5 100644 --- a/nyx/nyx_gui/frontend/fe_emmc_tools.h +++ b/nyx/nyx_gui/frontend/fe_emmc_tools.h @@ -22,11 +22,11 @@ typedef enum { - PART_BOOT = (1 << 0), - PART_SYSTEM = (1 << 1), - PART_USER = (1 << 2), - PART_RAW = (1 << 3), - PART_GP_ALL = (1 << 7) + PART_BOOT = BIT(0), + PART_SYSTEM = BIT(1), + PART_USER = BIT(2), + PART_RAW = BIT(3), + PART_GP_ALL = BIT(7) } emmcPartType_t; void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui); diff --git a/nyx/nyx_gui/frontend/fe_emummc_tools.c b/nyx/nyx_gui/frontend/fe_emummc_tools.c index d6a3d6f..2fd7006 100644 --- a/nyx/nyx_gui/frontend/fe_emummc_tools.c +++ b/nyx/nyx_gui/frontend/fe_emummc_tools.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 Rajko Stojadinovic - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,29 +21,60 @@ #include #include +#include + #include "gui.h" #include "fe_emummc_tools.h" -#include "../config/config.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" +#include "../config.h" +#include +#include -#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache. #define OUT_FILENAME_SZ 128 +#define NAND_PATROL_SECTOR 0xC20 +#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache. -#define MBR_1ST_PART_TYPE_OFF 0x1C2 - -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; extern hekate_config h_cfg; +extern volatile boot_cfg_t *b_cfg; -extern bool sd_mount(); -extern void sd_unmount(bool deinit); +void load_emummc_cfg(emummc_cfg_t *emu_info) +{ + memset(emu_info, 0, sizeof(emummc_cfg_t)); + + // Parse emuMMC configuration. + LIST_INIT(ini_sections); + if (!ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) + return; + + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "emummc")) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("enabled", kv->key)) + emu_info->enabled = atoi(kv->val); + else if (!strcmp("sector", kv->key)) + emu_info->sector = strtol(kv->val, NULL, 16); + else if (!strcmp("id", kv->key)) + emu_info->id = strtol(kv->val, NULL, 16); + else if (!strcmp("path", kv->key)) + { + emu_info->path = (char *)malloc(strlen(kv->val) + 1); + strcpy(emu_info->path, kv->val); + } + else if (!strcmp("nintendo_path", kv->key)) + { + emu_info->nintendo_path = (char *)malloc(strlen(kv->val) + 1); + strcpy(emu_info->nintendo_path, kv->val); + } + } + + break; + } + } + + ini_free(&ini_sections); +} void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path) { @@ -62,7 +93,7 @@ void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path) itoa(part_idx, lbuf, 10); f_puts(lbuf, &fp); } - else if(path) + else if (path) f_puts("1", &fp); else f_puts("0", &fp); @@ -80,7 +111,15 @@ void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path) f_puts("\npath=", &fp); f_puts(path, &fp); } - f_puts("\nid=0x0000", &fp); + + // Get ID from path. + u32 id_from_path = 0; + if (path && strlen(path) >= 4) + memcpy(&id_from_path, path + strlen(path) - 4, 4); + f_puts("\nid=0x", &fp); + itoa(id_from_path, lbuf, 16); + f_puts(lbuf, &fp); + f_puts("\nnintendo_path=", &fp); if (path) { @@ -93,7 +132,7 @@ void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path) f_close(&fp); } -static void _update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx) +void update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx) { if (currPartIdx < 10) { @@ -104,7 +143,7 @@ static void _update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 cur itoa(currPartIdx, &outFilename[sdPathLen], 10); } -static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part) +static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, const emmc_part_t *part) { static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF; static const u32 SECTORS_TO_MIB_COEFF = 11; @@ -117,8 +156,8 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto char *outFilename = sd_path; u32 sdPathLen = strlen(sd_path); - s_printf(gui->txt_buf, "#96FF00 SD Card free space:# %d MiB\n#96FF00 Total backup size:# %d MiB\n\n", - sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, + s_printf(gui->txt_buf, "#96FF00 SD Card free space:# %d MiB\n#96FF00 Total size:# %d MiB\n\n", + (u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF), totalSectors >> SECTORS_TO_MIB_COEFF); lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -130,21 +169,21 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto // Check if the USER partition or the RAW eMMC fits the sd card free space. if (totalSectors > (sd_fs.free_clst * sd_fs.csize)) { - s_printf(gui->txt_buf, "\n#FFDD00 Not enough free space for Partial Backup!#\n"); + s_printf(gui->txt_buf, "\n#FFDD00 Not enough free space for file based emuMMC!#\n"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); return 0; } - // Check if filesystem is FAT32 or the free space is smaller and backup in parts. - if (totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) + // Check if filesystem is FAT32 or the free space is smaller and dump in parts. + if (totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) { - u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE; + u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE; numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors; - // Continue from where we left, if Partial Backup in progress. - _update_emummc_base_folder(outFilename, sdPathLen, 0); + // Get first part filename. + update_emummc_base_folder(outFilename, sdPathLen, 0); } FIL fp; @@ -173,9 +212,9 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto u64 totalSize = (u64)((u64)totalSectors << 9); if (totalSize <= FAT32_FILESIZE_LIMIT) - clmt = f_expand_cltbl(&fp, 0x400000, totalSize); + clmt = f_expand_cltbl(&fp, SZ_4M, totalSize); else - clmt = f_expand_cltbl(&fp, 0x400000, MIN(totalSize, multipartSplitSize)); + clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize)); u32 num = 0; u32 pct = 0; @@ -191,18 +230,18 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto memset(&fp, 0, sizeof(fp)); currPartIdx++; - _update_emummc_base_folder(outFilename, sdPathLen, currPartIdx); + update_emummc_base_folder(outFilename, sdPathLen, currPartIdx); // Create next part. s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path)); - lv_label_ins_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - 3, gui->txt_buf); lv_label_cut_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - 3, 3); + lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE); if (res) { - s_printf(gui->txt_buf, "#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename); + s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -212,15 +251,32 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto bytesWritten = 0; totalSize = (u64)((u64)totalSectors << 9); - clmt = f_expand_cltbl(&fp, 0x400000, MIN(totalSize, multipartSplitSize)); + clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize)); + } + + // Check for cancellation combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + s_printf(gui->txt_buf, "\n#FFDD00 The emuMMC was cancelled!#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + f_close(&fp); + free(clmt); + f_unlink(outFilename); + + msleep(1000); + + return 0; } retryCount = 0; num = MIN(totalSectors, NUM_SECTORS_PER_ITER); + while (!sdmmc_storage_read(storage, lba_curr, num, buf)) { s_printf(gui->txt_buf, - "#FFDD00 Error reading %d blocks @ LBA %08X,#\n" + "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" "#FFDD00 from eMMC (try %d). #", num, lba_curr, ++retryCount); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); @@ -241,12 +297,17 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto } else { - s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n"); + s_printf(gui->txt_buf, "#FFDD00 Retrying...#"); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); } } - res = f_write_fast(&fp, buf, NX_EMMC_BLOCKSIZE * num); + + manual_system_maintenance(false); + + res = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num); + + manual_system_maintenance(false); if (res) { @@ -265,7 +326,7 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto { lv_bar_set_value(gui->bar, pct); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); prevPct = pct; @@ -273,7 +334,7 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto lba_curr += num; totalSectors -= num; - bytesWritten += num * NX_EMMC_BLOCKSIZE; + bytesWritten += num * EMMC_BLOCKSIZE; // Force a flush after a lot of data if not splitting. if (numSplitParts == 0 && bytesWritten >= multipartSplitSize) @@ -281,12 +342,14 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto f_sync(&fp); bytesWritten = 0; } + + manual_system_maintenance(false); } lv_bar_set_value(gui->bar, 100); lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%"); manual_system_maintenance(true); - // Backup operation ended successfully. + // Operation ended successfully. f_close(&fp); free(clmt); @@ -299,32 +362,30 @@ void dump_emummc_file(emmc_tool_gui_t *gui) int base_len = 0; u32 timer = 0; - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); + gui->base_path = (char *)malloc(OUT_FILENAME_SZ); gui->txt_buf = txt_buf; - s_printf(txt_buf, ""); - lv_label_set_array_text(gui->label_log, txt_buf, 0x1000); + + txt_buf[0] = 0; + lv_label_set_text(gui->label_log, txt_buf); manual_system_maintenance(true); - sd_unmount(true); - if (!sd_mount()) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init SD!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#"); goto out; } - lv_label_set_static_text(gui->label_info, "Checking for available free space..."); + lv_label_set_text(gui->label_info, "Checking for available free space..."); manual_system_maintenance(true); - // Get SD Card free space for Partial Backup. + // Get SD Card free space for file based emuMMC. f_getfree("", &sd_fs.free_clst, NULL); - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); goto out; } @@ -334,12 +395,11 @@ void dump_emummc_file(emmc_tool_gui_t *gui) f_mkdir("emuMMC"); strcpy(sdPath, "emuMMC/SD"); base_len = strlen(sdPath); - gui->base_path = (char *)malloc(OUT_FILENAME_SZ); for (int j = 0; j < 100; j++) { - _update_emummc_base_folder(sdPath, base_len, j); - if(f_stat(sdPath, NULL) == FR_NO_FILE) + update_emummc_base_folder(sdPath, base_len, j); + if (f_stat(sdPath, NULL) == FR_NO_FILE) break; } @@ -350,12 +410,13 @@ void dump_emummc_file(emmc_tool_gui_t *gui) strcpy(gui->base_path, sdPath); timer = get_tmr_s(); - const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; + const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB. emmc_part_t bootPart; memset(&bootPart, 0, sizeof(bootPart)); bootPart.lba_start = 0; - bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; + bootPart.lba_end = BOOT_PART_SECTORS - 1; + for (i = 0; i < 2; i++) { strcpy(bootPart.name, "BOOT"); @@ -364,15 +425,15 @@ void dump_emummc_file(emmc_tool_gui_t *gui) s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", i, bootPart.name, bootPart.lba_start, bootPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, bootPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); - sdmmc_storage_set_mmc_partition(&storage, i + 1); + emmc_set_partition(i + 1); strcat(sdPath, bootPart.name); - res = _dump_emummc_file_part(gui, sdPath, &storage, &bootPart); + res = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &bootPart); if (!res) { @@ -389,38 +450,37 @@ void dump_emummc_file(emmc_tool_gui_t *gui) } // Get GP partition size dynamically. - sdmmc_storage_set_mmc_partition(&storage, 0); + emmc_set_partition(EMMC_GPP); // Get GP partition size dynamically. - const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt; + const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt; emmc_part_t rawPart; memset(&rawPart, 0, sizeof(rawPart)); rawPart.lba_start = 0; rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1; strcpy(rawPart.name, "GPP"); - { - s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", - i, rawPart.name, rawPart.lba_start, rawPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); - s_printf(txt_buf, "%02d: %s... ", i, rawPart.name); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); - manual_system_maintenance(true); - res = _dump_emummc_file_part(gui, sdPath, &storage, &rawPart); + s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", + i, rawPart.name, rawPart.lba_start, rawPart.lba_end); + lv_label_set_text(gui->label_info, txt_buf); + s_printf(txt_buf, "%02d: %s... ", i, rawPart.name); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + manual_system_maintenance(true); - if (!res) - s_printf(txt_buf, "#FFDD00 Failed!#\n"); - else - s_printf(txt_buf, "Done!\n"); + res = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &rawPart); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); - manual_system_maintenance(true); - } + if (!res) + s_printf(txt_buf, "#FFDD00 Failed!#\n"); + else + s_printf(txt_buf, "Done!\n"); + + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + manual_system_maintenance(true); out_failed: timer = get_tmr_s() - timer; - sdmmc_storage_end(&storage); + emmc_end(); if (res) { @@ -438,17 +498,23 @@ out_failed: else s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60); - lv_label_set_array_text(gui->label_finish, txt_buf, 0x1000); + lv_label_set_text(gui->label_finish, txt_buf); out: free(txt_buf); free(gui->base_path); - sd_unmount(false); + sd_unmount(); } -static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, sdmmc_storage_t *storage, emmc_part_t *part) +static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, emmc_part_t *part, u32 resized_count) { - u32 totalSectors = part->lba_end - part->lba_start + 1; + u32 num = 0; + u32 pct = 0; + u32 prevPct = 200; + int retryCount = 0; + u32 sd_sector_off = sd_part_off + (0x2000 * active_part); + u32 lba_curr = part->lba_start; + u8 *buf = (u8 *)MIXD_BUF_ALIGNED; s_printf(gui->txt_buf, "\n\n\n"); lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); @@ -458,31 +524,56 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%"); manual_system_maintenance(true); - s_printf(gui->txt_buf, "#96FF00 Base folder:#\n%s\n#96FF00 Partition offset:# #FF8000 0x%08X#", gui->base_path, sd_part_off); lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); - u8 *buf = (u8 *)MIXD_BUF_ALIGNED; - u32 sd_sector_off = sd_part_off + (0x2000 * active_part); - u32 lba_curr = part->lba_start; - u32 prevPct = 200; - int retryCount = 0; - - u32 num = 0; - u32 pct = 0; - lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER); lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER); + u32 user_offset = 0; + + if (resized_count) + { + // Get USER partition info. + LIST_INIT(gpt_parsed); + emmc_gpt_parse(&gpt_parsed); + emmc_part_t *user_part = emmc_part_find(&gpt_parsed, "USER"); + if (!user_part) + { + s_printf(gui->txt_buf, "\n#FFDD00 USER partition not found!#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + return 0; + } + + user_offset = user_part->lba_start; + part->lba_end = user_offset - 1; + emmc_gpt_free(&gpt_parsed); + } + + u32 totalSectors = part->lba_end - part->lba_start + 1; while (totalSectors > 0) { + // Check for cancellation combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + s_printf(gui->txt_buf, "\n#FFDD00 The emuMMC was cancelled!#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + msleep(1000); + + return 0; + } + retryCount = 0; num = MIN(totalSectors, NUM_SECTORS_PER_ITER); // Read data from eMMC. - while (!sdmmc_storage_read(storage, lba_curr, num, buf)) + while (!sdmmc_storage_read(&emmc_storage, lba_curr, num, buf)) { s_printf(gui->txt_buf, "\n#FFDD00 Error reading %d blocks @LBA %08X,#\n" @@ -507,9 +598,11 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part manual_system_maintenance(true); } } - retryCount = 0; + + manual_system_maintenance(false); // Write data to SD card. + retryCount = 0; while (!sdmmc_storage_write(&sd_storage, sd_sector_off + lba_curr, num, buf)) { s_printf(gui->txt_buf, @@ -535,12 +628,15 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part manual_system_maintenance(true); } } + + manual_system_maintenance(false); + pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); if (pct != prevPct) { lv_bar_set_value(gui->bar, pct); s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct); - lv_label_set_array_text(gui->label_pct, gui->txt_buf, 32); + lv_label_set_text(gui->label_pct, gui->txt_buf); manual_system_maintenance(true); prevPct = pct; @@ -553,44 +649,228 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%"); manual_system_maintenance(true); - // Hide the partition. + // Set partition type to emuMMC (0xE0). if (active_part == 2) { - u8 *mbr = (u8 *)malloc(0x200); - sdmmc_storage_read(&sd_storage, 0, 1, mbr); - mbr[MBR_1ST_PART_TYPE_OFF + (0x10 * part_idx)] = 0xE0; - sdmmc_storage_write(&sd_storage, 0, 1, mbr); - free(mbr); + mbr_t mbr; + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + mbr.partitions[part_idx].type = 0xE0; + sdmmc_storage_write(&sd_storage, 0, 1, &mbr); + } + + if (resized_count) + { + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, "Done!\n"); + + // Calculate USER size and set it for FatFS. + u32 user_sectors = resized_count - user_offset - 33; + user_sectors = ALIGN_DOWN(user_sectors, 0x20); // Align down to cluster size. + disk_set_info(DRIVE_EMU, SET_SECTOR_COUNT, &user_sectors); + + // Initialize BIS for emuMMC. BIS keys should be already in place. + emmc_part_t user_part = {0}; + user_part.lba_start = user_offset; + user_part.lba_end = user_offset + user_sectors - 1; + strcpy(user_part.name, "USER"); + nx_emmc_bis_init(&user_part, true, sd_sector_off); + + s_printf(gui->txt_buf, "Formatting USER... \n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + // Format USER partition. + u8 *buff = malloc(SZ_4M); + int mkfs_error = f_mkfs("emu:", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M); + free(buff); + + // Mount sd card back. + sd_mount(); + + if (mkfs_error) + { + s_printf(gui->txt_buf, "#FF0000 Failed (%d)!#\nPlease try again...\n", mkfs_error); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + + return 0; + } + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, "Done!\n"); + + // Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK. + nx_emmc_bis_end(); + hos_bis_keys_clear(); + + s_printf(gui->txt_buf, "Writing new GPT... "); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + manual_system_maintenance(true); + + // Read MBR, GPT and backup GPT. + mbr_t mbr; + gpt_t *gpt = zalloc(sizeof(gpt_t)); + gpt_header_t gpt_hdr_backup; + sdmmc_storage_read(&emmc_storage, 0, 1, &mbr); + sdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt); + sdmmc_storage_read(&emmc_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup); + + // Find USER partition. + u32 gpt_entry_idx = 0; + for (gpt_entry_idx = 0; gpt_entry_idx < gpt->header.num_part_ents; gpt_entry_idx++) + if (!memcmp(gpt->entries[gpt_entry_idx].name, (char[]) { 'U', 0, 'S', 0, 'E', 0, 'R', 0 }, 8)) + break; + + if (gpt_entry_idx >= gpt->header.num_part_ents) + { + s_printf(gui->txt_buf, "\n#FF0000 No USER partition...#\nPlease try again...\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + free(gpt); + + return 0; + } + + // Set new emuMMC size and USER size. + mbr.partitions[0].size_sct = resized_count; + gpt->entries[gpt_entry_idx].lba_end = user_part.lba_end; + + // Update Main GPT. + gpt->header.alt_lba = resized_count - 1; + gpt->header.last_use_lba = resized_count - 34; + gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents); + gpt->header.crc32 = 0; // Set to 0 for calculation. + gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size); + + // Update Backup GPT. + gpt_hdr_backup.my_lba = resized_count - 1; + gpt_hdr_backup.part_ent_lba = resized_count - 33; + gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32; + gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation. + gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size); + + // Write main GPT. + sdmmc_storage_write(&sd_storage, sd_sector_off + gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt); + + // Write backup GPT partition table. + sdmmc_storage_write(&sd_storage, sd_sector_off + gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries); + + // Write backup GPT header. + sdmmc_storage_write(&sd_storage, sd_sector_off + gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup); + + // Write MBR. + sdmmc_storage_write(&sd_storage, sd_sector_off, 1, &mbr); + + // Clear nand patrol. + memset(buf, 0, EMMC_BLOCKSIZE); + sdmmc_storage_write(&sd_storage, sd_part_off + NAND_PATROL_SECTOR, 1, buf); + + free(gpt); } return 1; } -void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start) +static int _emummc_raw_derive_bis_keys(emmc_tool_gui_t *gui, u32 resized_count) +{ + if (!resized_count) + return 1; + + bool error = false; + + char *txt_buf = (char *)malloc(SZ_16K); + txt_buf[0] = 0; + + // Generate BIS keys. + hos_bis_keygen(); + + u8 *cal0_buff = malloc(SZ_64K); + + // Read and decrypt CAL0 for validation of working BIS keys. + emmc_set_partition(EMMC_GPP); + LIST_INIT(gpt); + emmc_gpt_parse(&gpt); + emmc_part_t *cal0_part = emmc_part_find(&gpt, "PRODINFO"); // check if null + nx_emmc_bis_init(cal0_part, false, 0); + nx_emmc_bis_read(0, 0x40, cal0_buff); + nx_emmc_bis_end(); + emmc_gpt_free(&gpt); + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buff; + + // Check keys validity. + if (memcmp(&cal0->magic, "CAL0", 4)) + { + // Clear EKS keys. + hos_eks_clear(HOS_KB_VERSION_MAX); + + strcpy(txt_buf, "#FFDD00 BIS keys validation failed!#\n"); + error = true; + } + + free(cal0_buff); + + if (error) + { + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222Close", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + + lv_mbox_set_text(mbox, "#C7EA46 BIS Keys Generation#"); + + lv_obj_t * lb_desc = lv_label_create(mbox, NULL); + lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); + lv_label_set_recolor(lb_desc, true); + lv_label_set_style(lb_desc, &monospace_text); + lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4); + + lv_label_set_text(lb_desc, txt_buf); + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + free(txt_buf); + + return 0; + } + + free(txt_buf); + + return 1; +} + +void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count) { int res = 0; u32 timer = 0; - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); + gui->base_path = (char *)malloc(OUT_FILENAME_SZ); gui->txt_buf = txt_buf; - s_printf(txt_buf, ""); - lv_label_set_array_text(gui->label_log, txt_buf, 0x1000); + + txt_buf[0] = 0; + lv_label_set_text(gui->label_log, txt_buf); manual_system_maintenance(true); - sd_unmount(true); - if (!sd_mount()) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init SD!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#"); goto out; } - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { - lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); + lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#"); + goto out; + } + + if (!_emummc_raw_derive_bis_keys(gui, resized_count)) + { + s_printf(gui->txt_buf, "#FFDD00 For formatting USER partition,#\n#FFDD00 BIS keys are needed!#\n"); + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); + emmc_end(); goto out; } @@ -599,18 +879,22 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start) // Create Restore folders, if they do not exist. f_mkdir("emuMMC"); s_printf(sdPath, "emuMMC/RAW%d", part_idx); - gui->base_path = (char *)malloc(OUT_FILENAME_SZ); f_mkdir(sdPath); strcat(sdPath, "/"); strcpy(gui->base_path, sdPath); timer = get_tmr_s(); - const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; + const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB. emmc_part_t bootPart; memset(&bootPart, 0, sizeof(bootPart)); bootPart.lba_start = 0; - bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; + bootPart.lba_end = BOOT_PART_SECTORS - 1; + + // Clear partition start. + memset((u8 *)MIXD_BUF_ALIGNED, 0, SZ_16M); + sdmmc_storage_write(&sd_storage, sector_start - 0x8000, 0x8000, (u8 *)MIXD_BUF_ALIGNED); + for (i = 0; i < 2; i++) { strcpy(bootPart.name, "BOOT"); @@ -619,15 +903,15 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start) s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", i, bootPart.name, bootPart.lba_start, bootPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, bootPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); - sdmmc_storage_set_mmc_partition(&storage, i + 1); + emmc_set_partition(i + 1); strcat(sdPath, bootPart.name); - res = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &storage, &bootPart); + res = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &bootPart, 0); if (!res) { @@ -643,10 +927,10 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start) strcpy(sdPath, gui->base_path); } - sdmmc_storage_set_mmc_partition(&storage, 0); + emmc_set_partition(EMMC_GPP); // Get GP partition size dynamically. - const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt; + const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt; emmc_part_t rawPart; memset(&rawPart, 0, sizeof(rawPart)); @@ -656,12 +940,12 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start) { s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n", i, rawPart.name, rawPart.lba_start, rawPart.lba_end); - lv_label_set_array_text(gui->label_info, txt_buf, 0x1000); + lv_label_set_text(gui->label_info, txt_buf); s_printf(txt_buf, "%02d: %s... ", i, rawPart.name); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); manual_system_maintenance(true); - res = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &storage, &rawPart); + res = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &rawPart, resized_count); if (!res) s_printf(txt_buf, "#FFDD00 Failed!#\n"); @@ -674,7 +958,7 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start) out_failed: timer = get_tmr_s() - timer; - sdmmc_storage_end(&storage); + emmc_end(); if (res) { @@ -692,10 +976,10 @@ out_failed: else s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60); - lv_label_set_array_text(gui->label_finish, txt_buf, 0x1000); + lv_label_set_text(gui->label_finish, txt_buf); out: free(txt_buf); free(gui->base_path); - sd_unmount(false); + sd_unmount(); } diff --git a/nyx/nyx_gui/frontend/fe_emummc_tools.h b/nyx/nyx_gui/frontend/fe_emummc_tools.h index 1685a42..5564156 100644 --- a/nyx/nyx_gui/frontend/fe_emummc_tools.h +++ b/nyx/nyx_gui/frontend/fe_emummc_tools.h @@ -20,8 +20,19 @@ #include "gui.h" +typedef struct _emummc_cfg_t +{ + int enabled; + u32 sector; + u16 id; + char *path; + char *nintendo_path; +} emummc_cfg_t; + +void load_emummc_cfg(emummc_cfg_t *emu_info); void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path); void dump_emummc_file(emmc_tool_gui_t *gui); -void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start); +void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count); +void update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx); #endif diff --git a/nyx/nyx_gui/frontend/gui.c b/nyx/nyx_gui/frontend/gui.c index 134a05c..47bef3b 100644 --- a/nyx/nyx_gui/frontend/gui.c +++ b/nyx/nyx_gui/frontend/gui.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,85 +16,207 @@ #include +#include + #include "gui.h" #include "gui_emummc_tools.h" #include "gui_tools.h" #include "gui_info.h" #include "gui_options.h" -#include "../libs/lvgl/lv_themes/lv_theme_hekate.h" -#include "../libs/lvgl/lvgl.h" +#include +#include #include "../gfx/logos-gui.h" -#include "../config/config.h" -#include "../config/ini.h" -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../input/touch.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../mem/minerva.h" -#include "../power/bq24193.h" -#include "../power/max17050.h" -#include "../rtc/max77620-rtc.h" -#include "../soc/bpmp.h" -#include "../soc/hw_init.h" -#include "../soc/t210.h" -#include "../storage/sdmmc.h" -#include "../thermal/fan.h" -#include "../thermal/tmp451.h" -#include "../utils/dirlist.h" -#include "../utils/sprintf.h" -#include "../utils/types.h" -#include "../utils/util.h" +#include "../config.h" +#include extern hekate_config h_cfg; -extern volatile nyx_storage_t *nyx_str; +extern nyx_config n_cfg; extern volatile boot_cfg_t *b_cfg; +extern volatile nyx_storage_t *nyx_str; extern lv_res_t launch_payload(lv_obj_t *list); -extern bool get_sd_card_removed(); -extern bool sd_mount(); -extern void sd_unmount(bool deinit); -void *sd_file_read(const char *path, u32 *fsize); -int sd_save_to_file(void *buf, u32 size, const char *filename); static bool disp_init_done = false; -static bool do_reload = false; +static bool do_auto_reload = false; -typedef struct _gui_status_bar_ctx +lv_style_t hint_small_style; +lv_style_t hint_small_style_white; +lv_style_t monospace_text; + +lv_obj_t *payload_list; +lv_obj_t *autorcm_btn; +lv_obj_t *close_btn; + +lv_img_dsc_t *icon_switch; +lv_img_dsc_t *icon_payload; +lv_img_dsc_t *icon_lakka; + +lv_img_dsc_t *hekate_bg; + +lv_style_t btn_transp_rel, btn_transp_pr, btn_transp_tgl_rel, btn_transp_tgl_pr; +lv_style_t ddlist_transp_bg, ddlist_transp_sel; +lv_style_t tabview_btn_pr, tabview_btn_tgl_pr; + +lv_style_t mbox_darken; + +char *text_color; + +typedef struct _jc_lv_driver_t { - lv_obj_t *mid; - lv_obj_t *time_temp; - lv_obj_t *temp_symbol; - lv_obj_t *temp_degrees; - lv_obj_t *battery; - lv_obj_t *battery_more; -} gui_status_bar_ctx; + lv_indev_t *indev_jc; + lv_indev_t *indev_touch; +// LV_INDEV_READ_PERIOD * JC_CAL_MAX_STEPS = 264 ms. +#define JC_CAL_MAX_STEPS 8 + u32 calibration_step; + u16 cx_max; + u16 cx_min; + u16 cy_max; + u16 cy_min; + s16 pos_x; + s16 pos_y; + s16 pos_last_x; + s16 pos_last_y; + lv_obj_t *cursor; + u32 cursor_timeout; + bool cursor_hidden; + u32 console_timeout; +} jc_lv_driver_t; -static gui_status_bar_ctx status_bar; +static jc_lv_driver_t jc_drv_ctx; + +gui_status_bar_ctx status_bar; static void _nyx_disp_init() { + vic_surface_t vic_sfc; + vic_sfc.src_buf = NYX_FB2_ADDRESS; + vic_sfc.dst_buf = NYX_FB_ADDRESS; + vic_sfc.width = 1280; + vic_sfc.height = 720; + vic_sfc.pix_fmt = VIC_PIX_FORMAT_X8R8G8B8; + vic_sfc.rotation = VIC_ROTATION_270; + + // Set hardware rotation via VIC. + vic_init(); + vic_set_surface(&vic_sfc); + + // Turn off backlight to hide the transition. display_backlight_brightness(0, 1000); - display_init_framebuffer(); + + // Rotate and copy the first frame. + vic_compose(); + + // Switch to new window configuration. + display_init_window_a_pitch_vic(); + + // Enable logging on window D. + display_init_window_d_console(); + // Switch back the backlight. display_backlight_brightness(h_cfg.backlight - 20, 1000); } +static void _save_log_to_bmp(char *fname) +{ + u32 *fb_ptr = (u32 *)LOG_FB_ADDRESS; + + // Check if there's log written. + bool log_changed = false; + for (u32 i = 0; i < 0xCD000; i++) + { + if (fb_ptr[i] != 0) + { + log_changed = true; + break; + } + } + + if (!log_changed) + return; + + const u32 file_size = LOG_FB_SZ + 0x36; + u8 *bitmap = malloc(file_size); + + // Reconstruct FB for bottom-top, landscape bmp. Rotation: 656x1280 -> 1280x656. + u32 *fb = malloc(LOG_FB_SZ); + for (int x = 1279; x > - 1; x--) + { + for (int y = 655; y > -1; y--) + fb[y * 1280 + x] = *fb_ptr++; + } + + manual_system_maintenance(true); + + memcpy(bitmap + 0x36, fb, LOG_FB_SZ); + + typedef struct _bmp_t + { + u16 magic; + u32 size; + u32 rsvd; + u32 data_off; + u32 hdr_size; + u32 width; + u32 height; + u16 planes; + u16 pxl_bits; + u32 comp; + u32 img_size; + u32 res_h; + u32 res_v; + u64 rsvd2; + } __attribute__((packed)) bmp_t; + + bmp_t *bmp = (bmp_t *)bitmap; + + bmp->magic = 0x4D42; + bmp->size = file_size; + bmp->rsvd = 0; + bmp->data_off = 0x36; + bmp->hdr_size = 40; + bmp->width = 1280; + bmp->height = 656; + bmp->planes = 1; + bmp->pxl_bits = 32; + bmp->comp = 0; + bmp->img_size = LOG_FB_SZ; + bmp->res_h = 2834; + bmp->res_v = 2834; + bmp->rsvd2 = 0; + + char path[0x80]; + strcpy(path, "bootloader/screenshots"); + s_printf(path + strlen(path), "/nyx%s_log.bmp", fname); + sd_save_to_file(bitmap, file_size, path); + + free(bitmap); + free(fb); +} + static void _save_fb_to_bmp() { - if (do_reload) + // Disallow screenshots if less than 2s passed. + static u32 timer = 0; + if (get_tmr_ms() < timer) return; - const u32 file_size = 0x384000 + 0x36; - u8 *bitmap = malloc(file_size); - u32 *fb = malloc(0x384000); - u32 *fb_ptr = (u32 *)NYX_FB_ADDRESS; + if (do_auto_reload) + goto exit; - // Reconstruct FB for bottom-top, landscape bmp. - for (u32 x = 0; x < 1280; x++) + // Invalidate data. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + const u32 file_size = NYX_FB_SZ + 0x36; + u8 *bitmap = malloc(file_size); + u32 *fb = malloc(NYX_FB_SZ); + u32 *fb_ptr = (u32 *)NYX_FB2_ADDRESS; + u32 line_bytes = 1280 * sizeof(u32); + + // Reconstruct FB for bottom-top, landscape bmp. No rotation. + for (int y = 719; y > -1; y--) { - for (int y = 719; y > -1; y--) - fb[y * 1280 + x] = *fb_ptr++; + memcpy(&fb[y * 1280], fb_ptr, line_bytes); + fb_ptr += line_bytes / sizeof(u32); } // Create notification box. @@ -104,9 +226,15 @@ static void _save_fb_to_bmp() lv_obj_set_width(mbox, LV_DPI * 4); lv_obj_set_top(mbox, true); lv_obj_align(mbox, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + // Capture effect. + display_backlight_brightness(255, 100); + msleep(150); + display_backlight_brightness(h_cfg.backlight - 20, 100); + manual_system_maintenance(true); - memcpy(bitmap + 0x36, fb, 0x384000); + memcpy(bitmap + 0x36, fb, NYX_FB_SZ); typedef struct _bmp_t { @@ -138,7 +266,7 @@ static void _save_fb_to_bmp() bmp->planes = 1; bmp->pxl_bits = 32; bmp->comp = 0; - bmp->img_size = 0x384000; + bmp->img_size = NYX_FB_SZ; bmp->res_h = 2834; bmp->res_v = 2834; bmp->rsvd2 = 0; @@ -147,24 +275,48 @@ static void _save_fb_to_bmp() char path[0x80]; - strcpy(path, "bootloader/screenshots"); + strcpy(path, "bootloader"); f_mkdir(path); - s_printf(path + strlen(path), "/screen_%08X.bmp", get_tmr_us()); - sd_save_to_file(bitmap, file_size, path); - sd_unmount(false); + strcat(path, "/screenshots"); + f_mkdir(path); + + // Create date/time name. + char fname[32]; + rtc_time_t time; + max77620_rtc_get_time_adjusted(&time); + s_printf(fname, "%04d%02d%02d_%02d%02d%02d", time.year, time.month, time.day, time.hour, time.min, time.sec); + s_printf(path + strlen(path), "/nyx%s.bmp", fname); + + // Save screenshot and log. + int res = sd_save_to_file(bitmap, file_size, path); + if (!res) + _save_log_to_bmp(fname); + + sd_unmount(); free(bitmap); free(fb); - lv_mbox_set_text(mbox, SYMBOL_CAMERA" #96FF00 Screenshot saved!#"); + if (!res) + lv_mbox_set_text(mbox, SYMBOL_CAMERA" #96FF00 Screenshot saved!#"); + else + lv_mbox_set_text(mbox, SYMBOL_WARNING" #FFDD00 Screenshot failed!#"); manual_system_maintenance(true); lv_mbox_start_auto_close(mbox, 4000); + +exit: + // Set timer to 2s. + timer = get_tmr_ms() + 2000; } static void _disp_fb_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t *color_p) { - // Draw to framebuffer. - gfx_set_rect_land_pitch((u32 *)NYX_FB_ADDRESS, (u32 *)color_p, x1, y1, x2, y2); //pitch + // Draw to intermediate non-rotated framebuffer. + gfx_set_rect_pitch((u32 *)NYX_FB2_ADDRESS, (u32 *)color_p, 1280, x1, y1, x2, y2); + + // Rotate and copy to visible framebuffer. + if (disp_init_done) + vic_compose(); // Check if display init was done. If it's the first big draw, init. if (!disp_init_done && ((x2 - x1 + 1) > 600)) @@ -177,16 +329,39 @@ static void _disp_fb_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const } static touch_event touchpad; +static bool touch_enabled; +static bool console_enabled = false; static bool _fts_touch_read(lv_indev_data_t *data) { - touch_poll(&touchpad); + if (touch_enabled) + touch_poll(&touchpad); + else + return false; // Take a screenshot if 3 fingers. if (touchpad.fingers > 2) { _save_fb_to_bmp(); - msleep(200); + + data->state = LV_INDEV_STATE_REL; + return false; + } + + if (console_enabled) + { + // Print input debugging in console. + gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy, &gfx_con.savedcol); + gfx_con_setpos(32, 638, GFX_COL_AUTO); + gfx_con.fntsz = 8; + gfx_printf("x: %4d, y: %4d | z: %3d | ", touchpad.x, touchpad.y, touchpad.z); + gfx_printf("1: %02X, 2: %02X, 3: %02X, ", touchpad.raw[1], touchpad.raw[2], touchpad.raw[3]); + gfx_printf("4: %02X, 5: %02X, 6: %02X, 7: %02X", + touchpad.raw[4], touchpad.raw[5], touchpad.raw[6], touchpad.raw[7]); + gfx_con_setpos(gfx_con.savedx, gfx_con.savedy, gfx_con.savedcol); + gfx_con.fntsz = 16; + + return false; } // Always set touch points. @@ -215,6 +390,235 @@ static bool _fts_touch_read(lv_indev_data_t *data) return false; // No buffering so no more data read. } +static bool _jc_virt_mouse_read(lv_indev_data_t *data) +{ + // Poll Joy-Con. + jc_gamepad_rpt_t *jc_pad = joycon_poll(); + + if (!jc_pad) + { + data->state = LV_INDEV_STATE_REL; + return false; + } + + // Take a screenshot if Capture button is pressed. + if (jc_pad->cap) + { + _save_fb_to_bmp(); + + data->state = LV_INDEV_STATE_REL; + return false; + } + + // Calibrate left stick. + if (jc_drv_ctx.calibration_step != JC_CAL_MAX_STEPS) + { + if (n_cfg.jc_force_right) + { + if (jc_pad->conn_r + && jc_pad->rstick_x > 0x400 && jc_pad->rstick_y > 0x400 + && jc_pad->rstick_x < 0xC00 && jc_pad->rstick_y < 0xC00) + { + jc_drv_ctx.calibration_step++; + jc_drv_ctx.cx_max = jc_pad->rstick_x + 0x96; + jc_drv_ctx.cx_min = jc_pad->rstick_x - 0x96; + jc_drv_ctx.cy_max = jc_pad->rstick_y + 0x96; + jc_drv_ctx.cy_min = jc_pad->rstick_y - 0x96; + jc_drv_ctx.cursor_timeout = 0; + } + } + else if (jc_pad->conn_l + && jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400 + && jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00) + { + jc_drv_ctx.calibration_step++; + jc_drv_ctx.cx_max = jc_pad->lstick_x + 0x96; + jc_drv_ctx.cx_min = jc_pad->lstick_x - 0x96; + jc_drv_ctx.cy_max = jc_pad->lstick_y + 0x96; + jc_drv_ctx.cy_min = jc_pad->lstick_y - 0x96; + jc_drv_ctx.cursor_timeout = 0; + } + + if (jc_drv_ctx.calibration_step != JC_CAL_MAX_STEPS) + { + data->state = LV_INDEV_STATE_REL; + return false; + } + } + + // Re-calibrate on disconnection. + if (n_cfg.jc_force_right && !jc_pad->conn_r) + jc_drv_ctx.calibration_step = 0; + else if (!n_cfg.jc_force_right && !jc_pad->conn_l) + jc_drv_ctx.calibration_step = 0; + + // Set button presses. + if (jc_pad->a || jc_pad->zl || jc_pad->zr) + data->state = LV_INDEV_STATE_PR; + else + data->state = LV_INDEV_STATE_REL; + + // Enable console. + if (jc_pad->plus || jc_pad->minus) + { + if (((u32)get_tmr_ms() - jc_drv_ctx.console_timeout) > 1000) + { + if (!console_enabled) + { + display_window_d_console_enable(); + console_enabled = true; + gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy, &gfx_con.savedcol); + gfx_con_setpos(964, 630, GFX_COL_AUTO); + gfx_printf("Press -/+ to close"); + gfx_con_setpos(gfx_con.savedx, gfx_con.savedy, gfx_con.savedcol); + } + else + { + display_window_d_console_disable(); + console_enabled = false; + } + + jc_drv_ctx.console_timeout = get_tmr_ms(); + } + + data->state = LV_INDEV_STATE_REL; + return false; + } + + if (console_enabled) + { + // Print input debugging in console. + gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy, &gfx_con.savedcol); + gfx_con_setpos(32, 630, GFX_COL_AUTO); + gfx_con.fntsz = 8; + gfx_printf("x: %4X, y: %4X | rx: %4X, ry: %4X | b: %06X | bt: %d %d", + jc_pad->lstick_x, jc_pad->lstick_y, jc_pad->rstick_x, jc_pad->rstick_y, + jc_pad->buttons, jc_pad->batt_info_l, jc_pad->batt_info_r); + gfx_con_setpos(gfx_con.savedx, gfx_con.savedy, gfx_con.savedcol); + gfx_con.fntsz = 16; + + data->state = LV_INDEV_STATE_REL; + return false; + } + + // Calculate new cursor position. + if (!n_cfg.jc_force_right) + { + // Left stick X. + if (jc_pad->lstick_x <= jc_drv_ctx.cx_max && jc_pad->lstick_x >= jc_drv_ctx.cx_min) + jc_drv_ctx.pos_x += 0; + else if (jc_pad->lstick_x > jc_drv_ctx.cx_max) + jc_drv_ctx.pos_x += ((jc_pad->lstick_x - jc_drv_ctx.cx_max) / 30); + else + jc_drv_ctx.pos_x -= ((jc_drv_ctx.cx_min - jc_pad->lstick_x) / 30); + + // Left stick Y. + if (jc_pad->lstick_y <= jc_drv_ctx.cy_max && jc_pad->lstick_y >= jc_drv_ctx.cy_min) + jc_drv_ctx.pos_y += 0; + else if (jc_pad->lstick_y > jc_drv_ctx.cy_max) + { + s16 val = (jc_pad->lstick_y - jc_drv_ctx.cy_max) / 30; + // Hoag has inverted Y axis. + if (jc_pad->sio_mode) + val *= -1; + jc_drv_ctx.pos_y -= val; + } + else + { + s16 val = (jc_drv_ctx.cy_min - jc_pad->lstick_y) / 30; + // Hoag has inverted Y axis. + if (jc_pad->sio_mode) + val *= -1; + jc_drv_ctx.pos_y += val; + } + } + else + { + // Right stick X. + if (jc_pad->rstick_x <= jc_drv_ctx.cx_max && jc_pad->rstick_x >= jc_drv_ctx.cx_min) + jc_drv_ctx.pos_x += 0; + else if (jc_pad->rstick_x > jc_drv_ctx.cx_max) + jc_drv_ctx.pos_x += ((jc_pad->rstick_x - jc_drv_ctx.cx_max) / 30); + else + jc_drv_ctx.pos_x -= ((jc_drv_ctx.cx_min - jc_pad->rstick_x) / 30); + + // Right stick Y. + if (jc_pad->rstick_y <= jc_drv_ctx.cy_max && jc_pad->rstick_y >= jc_drv_ctx.cy_min) + jc_drv_ctx.pos_y += 0; + else if (jc_pad->rstick_y > jc_drv_ctx.cy_max) + { + s16 val = (jc_pad->rstick_y - jc_drv_ctx.cy_max) / 30; + // Hoag has inverted Y axis. + if (jc_pad->sio_mode) + val *= -1; + jc_drv_ctx.pos_y -= val; + } + else + { + s16 val = (jc_drv_ctx.cy_min - jc_pad->rstick_y) / 30; + // Hoag has inverted Y axis. + if (jc_pad->sio_mode) + val *= -1; + jc_drv_ctx.pos_y += val; + } + } + + // Ensure value inside screen limits. + if (jc_drv_ctx.pos_x < 0) + jc_drv_ctx.pos_x = 0; + else if (jc_drv_ctx.pos_x > 1279) + jc_drv_ctx.pos_x = 1279; + + if (jc_drv_ctx.pos_y < 0) + jc_drv_ctx.pos_y = 0; + else if (jc_drv_ctx.pos_y > 719) + jc_drv_ctx.pos_y = 719; + + // Set cursor position. + data->point.x = jc_drv_ctx.pos_x; + data->point.y = jc_drv_ctx.pos_y; + + // Auto hide cursor. + if (jc_drv_ctx.pos_x != jc_drv_ctx.pos_last_x || jc_drv_ctx.pos_y != jc_drv_ctx.pos_last_y) + { + jc_drv_ctx.pos_last_x = jc_drv_ctx.pos_x; + jc_drv_ctx.pos_last_y = jc_drv_ctx.pos_y; + + jc_drv_ctx.cursor_hidden = false; + jc_drv_ctx.cursor_timeout = get_tmr_ms(); + lv_indev_set_cursor(jc_drv_ctx.indev_jc, jc_drv_ctx.cursor); + + // Un hide cursor. + lv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, false); + } + else + { + if (!jc_drv_ctx.cursor_hidden) + { + if (((u32)get_tmr_ms() - jc_drv_ctx.cursor_timeout) > 3000) + { + // Remove cursor and hide it. + lv_indev_set_cursor(jc_drv_ctx.indev_jc, NULL); + lv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, true); + lv_obj_set_opa_scale(jc_drv_ctx.cursor, LV_OPA_TRANSP); + + jc_drv_ctx.cursor_hidden = true; + } + } + else + data->state = LV_INDEV_STATE_REL; // Ensure that no clicks are allowed. + } + + if (jc_pad->b && close_btn) + { + lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK); + close_btn_action(close_btn); + close_btn = NULL; + } + + return false; // No buffering so no more data read. +} + typedef struct _system_maintenance_tasks_t { union @@ -235,7 +639,7 @@ void manual_system_maintenance(bool refresh) for (u32 task_idx = 0; task_idx < (sizeof(system_maintenance_tasks_t) / sizeof(lv_task_t *)); task_idx++) { lv_task_t *task = system_tasks.tasks[task_idx]; - if(task && (lv_tick_elaps(task->last_run) >= task->period)) + if (task && (lv_tick_elaps(task->last_run) >= task->period)) { task->last_run = lv_tick_get(); task->task(task->param); @@ -247,7 +651,8 @@ void manual_system_maintenance(bool refresh) lv_img_dsc_t *bmp_to_lvimg_obj(const char *path) { - u8 *bitmap = sd_file_read(path, NULL); + u32 fsize; + u8 *bitmap = sd_file_read(path, &fsize); if (!bitmap) return NULL; @@ -273,7 +678,8 @@ lv_img_dsc_t *bmp_to_lvimg_obj(const char *path) // Sanity check. if (bitmap[0] == 'B' && bitmap[1] == 'M' && - bitmap[28] == 32) // Only 32 bit BMPs allowed. + bitmap[28] == 32 && // Only 32 bit BMPs allowed. + bmpData.size <= fsize) { // Check if non-default Bottom-Top. bool flipped = false; @@ -289,7 +695,7 @@ lv_img_dsc_t *bmp_to_lvimg_obj(const char *path) img_desc->header.always_zero = 0; img_desc->header.w = bmpData.size_x; img_desc->header.h = bmpData.size_y; - img_desc->header.cf = (bitmap[28] == 32) ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR; + img_desc->header.cf = (bitmap[28] == 32) ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR; // Only LV_IMG_CF_TRUE_COLOR_ALPHA is actually allowed. img_desc->data_size = bmpData.size - bmpData.offset; img_desc->data = (u8 *)offset_copy; @@ -342,20 +748,23 @@ lv_res_t nyx_generic_onoff_toggle(lv_obj_t *btn) if (!(lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL)) { strcat(label_text, "#D0D0D0 OFF#"); - lv_label_set_array_text(label_btn, label_text, 64); + lv_label_set_text(label_btn, label_text); } else { - strcat(label_text, "#00FFC9 ON #"); - lv_label_set_array_text(label_btn, label_text, 64); + s_printf(label_text, "%s%s%s", label_text, text_color, " ON #"); + lv_label_set_text(label_btn, label_text); } } else { if (!(lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL)) - lv_label_set_static_text(label_btn, "#D0D0D0 OFF#"); + lv_label_set_text(label_btn, "#D0D0D0 OFF#"); else - lv_label_set_static_text(label_btn, "#00FFC9 ON #"); + { + s_printf(label_text, "%s%s", text_color, " ON #"); + lv_label_set_text(label_btn, label_text); + } } return LV_RES_OK; @@ -371,6 +780,64 @@ lv_res_t mbox_action(lv_obj_t *btns, const char *txt) return LV_RES_INV; } +bool nyx_emmc_check_battery_enough() +{ + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) + return true; + + int batt_volt = 0; + + max17050_get_property(MAX17050_VCELL, &batt_volt); + + if (batt_volt && batt_volt < 3650) + { + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_mbox_set_text(mbox, + "#FF8000 Battery Check#\n\n" + "#FFDD00 Battery is not enough to carry on#\n" + "#FFDD00 with selected operation!#\n\n" + "Charge to at least #C7EA46 3650 mV#, and try again!"); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return false; + } + + return true; +} + +static void _nyx_sd_card_issues_warning(void *param) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_mbox_set_text(mbox, + "#FF8000 SD Card Issues Warning#\n\n" + "#FFDD00 The SD Card is initialized in 1-bit mode!#\n" + "#FFDD00 This might mean detached or broken connector!#\n\n" + "You might want to check\n#C7EA46 Console Info# -> #C7EA46 microSD#"); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); +} + void nyx_window_toggle_buttons(lv_obj_t *win, bool disable) { lv_win_ext_t * ext = lv_obj_get_ext_attr(win); @@ -400,12 +867,19 @@ void nyx_window_toggle_buttons(lv_obj_t *win, bool disable) } } +lv_res_t nyx_win_close_action_custom(lv_obj_t * btn) +{ + close_btn = NULL; + + return lv_win_close_action(btn); +} + lv_obj_t *nyx_create_standard_window(const char *win_title) { static lv_style_t win_bg_style; lv_style_copy(&win_bg_style, &lv_style_plain); - win_bg_style.body.main_color = LV_COLOR_HEX(0x2D2D2D);// TODO: COLOR_HOS_BG + win_bg_style.body.main_color = lv_theme_get_current()->bg->body.main_color; win_bg_style.body.grad_color = win_bg_style.body.main_color; lv_obj_t *win = lv_win_create(lv_scr_act(), NULL); @@ -413,7 +887,25 @@ lv_obj_t *nyx_create_standard_window(const char *win_title) lv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style); lv_obj_set_size(win, LV_HOR_RES, LV_VER_RES); - lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", lv_win_close_action); + close_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", nyx_win_close_action_custom); + + return win; +} + +lv_obj_t *nyx_create_window_custom_close_btn(const char *win_title, lv_action_t rel_action) +{ + static lv_style_t win_bg_style; + + lv_style_copy(&win_bg_style, &lv_style_plain); + win_bg_style.body.main_color = lv_theme_get_current()->bg->body.main_color; + win_bg_style.body.grad_color = win_bg_style.body.main_color; + + lv_obj_t *win = lv_win_create(lv_scr_act(), NULL); + lv_win_set_title(win, win_title); + lv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style); + lv_obj_set_size(win, LV_HOR_RES, LV_VER_RES); + + close_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", rel_action); return win; } @@ -430,15 +922,34 @@ static void _launch_hos(u8 autoboot, u8 autoboot_list) void (*main_ptr)() = (void *)nyx_str->hekate; - sd_unmount(true); + sd_end(); - reconfig_hw_workaround(false, 0); + hw_deinit(false, 0); (*main_ptr)(); } -static void _reload_nyx() +void reload_nyx(lv_obj_t *obj, bool force) { + if (!force) + { + sd_mount(); + + // Check that Nyx still exists. + if (f_stat("bootloader/sys/nyx.bin", NULL)) + { + sd_unmount(); + + // Remove lvgl object in case of being invoked from a window. + if (obj) + lv_obj_del(obj); + + do_auto_reload = false; + + return; + } + } + b_cfg->boot_cfg = BOOT_CFG_AUTOBOOT_EN; b_cfg->autoboot = 0; b_cfg->autoboot_list = 0; @@ -446,12 +957,9 @@ static void _reload_nyx() void (*main_ptr)() = (void *)nyx_str->hekate; - sd_unmount(true); + sd_end(); - reconfig_hw_workaround(false, 0); - - // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. - sdmmc_storage_init_wait_sd(); + hw_deinit(false, 0); (*main_ptr)(); } @@ -459,7 +967,7 @@ static void _reload_nyx() static lv_res_t reload_action(lv_obj_t *btns, const char *txt) { if (!lv_btnm_get_pressed(btns)) - _reload_nyx(); + reload_nyx(NULL, false); return mbox_action(btns, txt); } @@ -471,10 +979,17 @@ static lv_res_t _removed_sd_action(lv_obj_t *btns, const char *txt) switch (btnidx) { case 0: - reboot_rcm(); + if (h_cfg.rcm_patched) + power_set_state(POWER_OFF_REBOOT); + else + power_set_state(REBOOT_RCM); break; case 1: - power_off(); + power_set_state(POWER_OFF_RESET); + break; + case 2: + sd_end(); + do_auto_reload = false; break; } @@ -483,32 +998,64 @@ static lv_res_t _removed_sd_action(lv_obj_t *btns, const char *txt) static void _check_sd_card_removed(void *params) { + static lv_obj_t *dark_bg = NULL; + // The following checks if SDMMC_1 is initialized. // If yes and card was removed, shows a message box, // that will reload Nyx, when the card is inserted again. - if (!do_reload && get_sd_card_removed()) + if (!do_auto_reload && sd_get_card_removed()) { - lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + dark_bg = lv_obj_create(lv_scr_act(), NULL); lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char * mbox_btn_map[] = { "\221Reboot (RCM)", "\221Power Off", "" }; + static const char * mbox_btn_map[] = { "\221Reboot (RCM)", "\221Power Off", "\221Do not reload", "" }; + static const char * mbox_btn_map_rcm_patched[] = { "\221Reboot", "\221Power Off", "\221Do not reload", "" }; lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); - lv_obj_set_width(mbox, LV_HOR_RES * 4 / 9); + lv_obj_set_width(mbox, LV_HOR_RES * 6 / 9); - lv_mbox_set_text(mbox, "\n#FF8000 SD card was removed!#\n\n#96FF00 Nyx will reload after inserting it.#\n"); - lv_mbox_add_btns(mbox, mbox_btn_map, _removed_sd_action); + lv_mbox_set_text(mbox, "\n#FF8000 SD card was removed!#\n\n#96FF00 Nyx will reload after inserting it.#\n\nReminder that you can use UMS instead of removing it.\n"); + lv_mbox_add_btns(mbox, h_cfg.rcm_patched ? mbox_btn_map_rcm_patched : mbox_btn_map, _removed_sd_action); lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_set_top(mbox, true); - do_reload = true; + do_auto_reload = true; } // If in reload state and card was inserted, reload nyx. - if (do_reload && !get_sd_card_removed()) - _reload_nyx(); + if (do_auto_reload && !sd_get_card_removed()) + reload_nyx(dark_bg, false); +} + +lv_task_t *task_emmc_errors; +static void _nyx_emmc_issues_warning(void *params) +{ + if (emmc_get_mode() < EMMC_MMC_HS400) + { + // Remove task. + lv_task_del(task_emmc_errors); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_mbox_set_text(mbox, + "#FF8000 eMMC Issues Warning#\n\n" + "#FFDD00 Your eMMC is initialized in a slower mode!#\n" + "#FFDD00 This might mean hardware issues!#\n\n" + "You might want to check\n#C7EA46 Console Info# -> #C7EA46 eMMC#"); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + } } static lv_res_t _reboot_action(lv_obj_t *btns, const char *txt) @@ -518,10 +1065,13 @@ static lv_res_t _reboot_action(lv_obj_t *btns, const char *txt) switch (btnidx) { case 0: - reboot_normal(); + power_set_state(REBOOT_BYPASS_FUSES); break; case 1: - reboot_rcm(); + if (h_cfg.rcm_patched) + power_set_state(POWER_OFF_REBOOT); + else + power_set_state(REBOOT_RCM); break; } @@ -531,7 +1081,7 @@ static lv_res_t _reboot_action(lv_obj_t *btns, const char *txt) static lv_res_t _poweroff_action(lv_obj_t *btns, const char *txt) { if (!lv_btnm_get_pressed(btns)) - power_off(); + power_set_state(POWER_OFF_RESET); return mbox_action(btns, txt); } @@ -547,7 +1097,8 @@ static lv_res_t _create_mbox_reload(lv_obj_t *btn) lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES * 4 / 10); - lv_mbox_set_text(mbox, "#FF8000 Do you really want#\n#FF8000 to reload hekate?#"); + lv_mbox_set_text(mbox, "#FF8000 Do you really want#\n#FF8000 to reload hekate & Nyx?#\n\n" + "This also checks\n#96FF00 bootloader/update.bin#\nfor hekate updates"); lv_mbox_add_btns(mbox, mbox_btn_map, reload_action); @@ -564,13 +1115,18 @@ static lv_res_t _create_mbox_reboot(lv_obj_t *btn) lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); static const char * mbox_btn_map[] = { "\221OFW", "\221RCM", "\221Cancel", "" }; + static const char * mbox_btn_map_autorcm[] = { "\261OFW", "\221RCM", "\221Cancel", "" }; + static const char * mbox_btn_map_patched[] = { "\221OFW", "\221Normal", "\221Cancel", "" }; lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES / 2); lv_mbox_set_text(mbox, "#FF8000 Choose where to reboot:#"); - lv_mbox_add_btns(mbox, mbox_btn_map, _reboot_action); + if (h_cfg.rcm_patched) + lv_mbox_add_btns(mbox, mbox_btn_map_patched, _reboot_action); + else + lv_mbox_add_btns(mbox, !h_cfg.autorcm_enabled ? mbox_btn_map : mbox_btn_map_autorcm, _reboot_action); lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_set_top(mbox, true); @@ -617,7 +1173,7 @@ void nyx_create_onoff_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, co btn_onoff_pr_hos_style.body.opa = 35; } else - btn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(0x3D3D3D); + btn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D); btn_onoff_pr_hos_style.body.grad_color = btn_onoff_pr_hos_style.body.main_color; btn_onoff_pr_hos_style.text.color = th->btn.pr->text.color; btn_onoff_pr_hos_style.body.empty = 0; @@ -639,10 +1195,9 @@ void nyx_create_onoff_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, co lv_obj_set_width(btn, lv_obj_get_width(parent)); lv_btn_set_toggle(btn, true); - lv_label_set_text(label_btn, btn_name); - lv_label_set_static_text(label_btnsw, "#D0D0D0 OFF#"); + lv_label_set_text(label_btnsw, "#D0D0D0 OFF#"); lv_obj_align(label_btn, btn, LV_ALIGN_IN_LEFT_MID, LV_DPI / 4, 0); lv_obj_align(label_btnsw, btn, LV_ALIGN_IN_RIGHT_MID, -LV_DPI / 4, -LV_DPI / 10); @@ -668,7 +1223,7 @@ static void _create_text_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, btn_onoff_pr_hos_style.body.opa = 35; } else - btn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(0x3D3D3D); + btn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D); btn_onoff_pr_hos_style.body.grad_color = btn_onoff_pr_hos_style.body.main_color; btn_onoff_pr_hos_style.text.color = th->btn.pr->text.color; btn_onoff_pr_hos_style.body.empty = 0; @@ -695,11 +1250,13 @@ static void _create_tab_about(lv_theme_t * th, lv_obj_t * parent) lv_obj_t * lbl_credits = lv_label_create(parent, NULL); lv_obj_align(lbl_credits, NULL, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 2, LV_DPI / 2); - lv_ta_set_style(lbl_credits, LV_TA_STYLE_BG, &monospace_text); + lv_label_set_style(lbl_credits, &monospace_text); lv_label_set_recolor(lbl_credits, true); lv_label_set_static_text(lbl_credits, - "hekate (c) 2018 naehrwert, st4rk\n\n" - "CTCaer mod (c) 2018 CTCaer\n" + "#C7EA46 hekate# (c) 2018, #C7EA46 naehrwert#, #C7EA46 st4rk#\n" + " (c) 2018-2025, #C7EA46 CTCaer#\n" + "\n" + "#C7EA46 Nyx# (c) 2019-2025, #C7EA46 CTCaer#\n" "\n" "Thanks to: #00CCFF derrek, nedwill, plutoo, #\n" " #00CCFF shuffle2, smea, thexyz, yellows8 #\n" @@ -707,23 +1264,24 @@ static void _create_tab_about(lv_theme_t * th, lv_obj_t * parent) "Greetings to: fincs, hexkyz, SciresM,\n" " Shiny Quagsire, WinterMute\n" "\n" - "Open source and free packages used:\n\n" + "Open source and free packages used: \n" // Label width alignment padding. + " - Littlev Graphics Library,\n" + " Copyright (c) 2016-2018, Gabor Kiss-Vamosi\n\n" " - FatFs R0.13c,\n" - " Copyright (c) 2018, ChaN\n\n" + " Copyright (c) 2006-2018, ChaN\n" + " Copyright (c) 2018-2022, CTCaer\n\n" " - bcl-1.2.0,\n" " Copyright (c) 2003-2006, Marcus Geelnard\n\n" - " - Atmosphere (Exosphere types/panic, proc id patches),\n" - " Copyright (c) 2018-2019, Atmosphere-NX\n\n" + " - blz,\n" + " Copyright (c) 2018, SciresM\n\n" " - elfload,\n" " Copyright (c) 2014, Owen Shepherd\n" - " Copyright (c) 2018, M4xw\n\n" - " - Littlev Graphics Library,\n" - " Copyright (c) 2016 Gabor Kiss-Vamosi" + " Copyright (c) 2018, M4xw" ); lv_obj_t * lbl_octopus = lv_label_create(parent, NULL); lv_obj_align(lbl_octopus, lbl_credits, LV_ALIGN_OUT_RIGHT_TOP, -LV_DPI / 10, 0); - lv_ta_set_style(lbl_octopus, LV_TA_STYLE_BG, &monospace_text); + lv_label_set_style(lbl_octopus, &monospace_text); lv_label_set_recolor(lbl_octopus, true); lv_label_set_static_text(lbl_octopus, @@ -756,47 +1314,44 @@ static void _create_tab_about(lv_theme_t * th, lv_obj_t * parent) lv_obj_align(ctcaer_img, lbl_octopus, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI * 2 / 3); char version[32]; - s_printf(version, "Nyx v%d.%d.%d", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF); + s_printf(version, "Nyx %s%d.%d.%d%c", NYX_VER_RL ? "v" : "", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF, NYX_VER_RL > 'A' ? NYX_VER_RL : 0); lv_obj_t * lbl_ver = lv_label_create(parent, NULL); lv_obj_align(lbl_ver, ctcaer_img, LV_ALIGN_OUT_BOTTOM_RIGHT, -LV_DPI / 20, LV_DPI / 4); - lv_ta_set_style(lbl_ver, LV_TA_STYLE_BG, &monospace_text); + lv_label_set_style(lbl_ver, &monospace_text); lv_label_set_text(lbl_ver, version); } static void _update_status_bar(void *params) { - char *label = (char *)malloc(64); + static char *label = NULL; - u16 soc_temp; - u32 batt_percent; - int charge_status; - int batt_volt; - int batt_curr; + u16 soc_temp = 0; + u32 batt_percent = 0; + int charge_status = 0; + int batt_volt = 0; + int batt_curr = 0; rtc_time_t time; // Get sensor data. - max77620_rtc_get_time(&time); + max77620_rtc_get_time_adjusted(&time); soc_temp = tmp451_get_soc_temp(false); bq24193_get_property(BQ24193_ChargeStatus, &charge_status); max17050_get_property(MAX17050_RepSOC, (int *)&batt_percent); max17050_get_property(MAX17050_VCELL, &batt_volt); max17050_get_property(MAX17050_Current, &batt_curr); - // Enable fan if more than 46 oC. - u32 soc_temp_dec = (soc_temp >> 8); - if (soc_temp_dec > 51) - set_fan_duty(102); - else if (soc_temp_dec > 46) - set_fan_duty(51); - else if (soc_temp_dec < 40) - set_fan_duty(0); + // Enable fan if more than 41 oC. + u32 soc_temp_dec = soc_temp >> 8; + fan_set_from_temp(soc_temp_dec); + + if (!label) + label = (char *)malloc(512); - //! TODO: Parse time and use offset. // Set time and SoC temperature. s_printf(label, "%02d:%02d "SYMBOL_DOT" "SYMBOL_TEMPERATURE" %02d.%d", time.hour, time.min, soc_temp_dec, (soc_temp & 0xFF) / 10); - lv_label_set_array_text(status_bar.time_temp, label, 64); + lv_label_set_text(status_bar.time_temp, label); lv_obj_realign(status_bar.temp_symbol); lv_obj_realign(status_bar.temp_degrees); @@ -806,36 +1361,32 @@ static void _update_status_bar(void *params) u8 batt_level = (batt_percent >> 8) & 0xFF; if (batt_level > 80) - s_printf(label + strlen(label), SYMBOL_BATTERY_FULL); + strcat(label, SYMBOL_BATTERY_FULL); else if (batt_level > 60) - s_printf(label + strlen(label), SYMBOL_BATTERY_3); + strcat(label, SYMBOL_BATTERY_3); else if (batt_level > 40) - s_printf(label + strlen(label), SYMBOL_BATTERY_2); + strcat(label, SYMBOL_BATTERY_2); else if (batt_level > 15) - s_printf(label + strlen(label), SYMBOL_BATTERY_1); + strcat(label, SYMBOL_BATTERY_1); else - s_printf(label + strlen(label), "#FF3C28 "SYMBOL_BATTERY_EMPTY"#"); + strcat(label, "#FF3C28 "SYMBOL_BATTERY_EMPTY"#"); + // Set charging symbol. if (charge_status) - s_printf(label + strlen(label), " #FFDD00 "SYMBOL_CHARGE"#"); + strcat(label, " #FFDD00 "SYMBOL_CHARGE"#"); - lv_label_set_array_text(status_bar.battery, label, 64); + lv_label_set_text(status_bar.battery, label); lv_obj_realign(status_bar.battery); // Set battery current draw and voltage. - if (batt_curr >= 0) - s_printf(label, "#96FF00 +%d", batt_curr / 1000); - else - s_printf(label, "#FF3C28 -%d", (~batt_curr + 1) / 1000); + s_printf(label, "#%s%d", batt_curr >= 0 ? "96FF00 +" : "FF3C28 ", batt_curr / 1000); bool voltage_empty = batt_volt < 3200; s_printf(label + strlen(label), " mA# (%s%d mV%s)", voltage_empty ? "#FF8000 " : "", batt_volt, voltage_empty ? " "SYMBOL_WARNING"#" : ""); - lv_label_set_array_text(status_bar.battery_more, label, 64); + lv_label_set_text(status_bar.battery_more, label); lv_obj_realign(status_bar.battery_more); - - free(label); } static lv_res_t _create_mbox_payloads(lv_obj_t *btn) @@ -844,7 +1395,7 @@ static lv_res_t _create_mbox_payloads(lv_obj_t *btn) lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char * mbox_btn_map[] = { "\211", "\222Cancel", "\211", "" }; + static const char * mbox_btn_map[] = { "\251", "\222Cancel", "\251", "" }; lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES * 5 / 9); @@ -865,23 +1416,20 @@ static lv_res_t _create_mbox_payloads(lv_obj_t *btn) goto out_end; } - char *dir = (char *)malloc(256); - strcpy(dir, "bootloader/payloads"); - - char *filelist = dirlist(dir, NULL, false, false); - sd_unmount(false); + dirlist_t *filelist = dirlist("bootloader/payloads", NULL, false, false); + sd_unmount(); u32 i = 0; - if (filelist) { while (true) { - if (!filelist[i * 256]) + if (!filelist->name[i]) break; - lv_list_add(list, NULL, &filelist[i * 256], launch_payload); + lv_list_add(list, NULL, filelist->name[i], launch_payload); i++; } + free(filelist); } out_end: @@ -892,8 +1440,15 @@ out_end: return LV_RES_OK; } +typedef struct _launch_menu_entries_t +{ + lv_obj_t *btn[20]; + lv_obj_t *label[20]; +} launch_menu_entries_t; -static lv_obj_t *launch_ctxt[16]; +static launch_menu_entries_t launch_ctxt; +static lv_obj_t *launch_bg = NULL; +static bool launch_bg_done = false; static lv_res_t _launch_more_cfg_action(lv_obj_t *btn) { @@ -907,20 +1462,21 @@ static lv_res_t _launch_more_cfg_action(lv_obj_t *btn) static lv_res_t _win_launch_close_action(lv_obj_t * btn) { // Cleanup icons. - lv_btn_ext_t *ext; - lv_obj_t *btn_tmp; - for (u32 i = 0; i < 16; i += 2) + for (u32 i = 0; i < (n_cfg.entries_5_col ? 10 : 8); i++) { - btn_tmp = launch_ctxt[i]; - ext = lv_obj_get_ext_attr(btn_tmp); + lv_obj_t *btns = launch_ctxt.btn[i]; + lv_btn_ext_t *ext = lv_obj_get_ext_attr(btns); if (ext->idx) { - btn_tmp = lv_obj_get_child(btn_tmp, NULL); - lv_img_dsc_t *tmp = (lv_img_dsc_t *)lv_img_get_src(btn_tmp); + // This gets latest object, which is the button overlay. So iterate 2 times. + lv_obj_t * img = lv_obj_get_child(btns, NULL); + img = lv_obj_get_child(btns, img); + + lv_img_dsc_t *src = (lv_img_dsc_t *)lv_img_get_src(img); // Avoid freeing base icons. - if ((tmp != icon_switch) && (tmp != icon_payload) && (tmp != icon_lakka)) - free(tmp); + if ((src != icon_switch) && (src != icon_payload)) + free(src); } } @@ -928,23 +1484,53 @@ static lv_res_t _win_launch_close_action(lv_obj_t * btn) lv_obj_del(win); + if (n_cfg.home_screen && !launch_bg_done && hekate_bg) + { + lv_obj_set_opa_scale_enable(launch_bg, true); + lv_obj_set_opa_scale(launch_bg, LV_OPA_TRANSP); + //if (launch_bg) + // lv_obj_del(launch_bg); //! TODO: Find why it hangs. + launch_bg_done = true; + } + + close_btn = NULL; + return LV_RES_INV; } -lv_obj_t *create_window_launch(const char *win_title) +static lv_obj_t *create_window_launch(const char *win_title) { - static lv_style_t win_bg_style; + static lv_style_t win_bg_style, win_header; lv_style_copy(&win_bg_style, &lv_style_plain); - win_bg_style.body.main_color = LV_COLOR_HEX(0x2D2D2D);// TODO: COLOR_HOS_BG + win_bg_style.body.main_color = lv_theme_get_current()->bg->body.main_color; win_bg_style.body.grad_color = win_bg_style.body.main_color; + if (n_cfg.home_screen && !launch_bg_done && hekate_bg) + { + lv_obj_t *img = lv_img_create(lv_scr_act(), NULL); + lv_img_set_src(img, hekate_bg); + + launch_bg = img; + } + lv_obj_t *win = lv_win_create(lv_scr_act(), NULL); lv_win_set_title(win, win_title); - lv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style); + lv_obj_set_size(win, LV_HOR_RES, LV_VER_RES); - lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", _win_launch_close_action); + if (n_cfg.home_screen && !launch_bg_done && hekate_bg) + { + lv_style_copy(&win_header, lv_theme_get_current()->win.header); + win_header.body.opa = LV_OPA_TRANSP; + + win_bg_style.body.opa = LV_OPA_TRANSP; + lv_win_set_style(win, LV_WIN_STYLE_HEADER, &win_header); + } + + lv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style); + + close_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", _win_launch_close_action); return win; } @@ -971,12 +1557,12 @@ static lv_res_t logs_onoff_toggle(lv_obj_t *btn) if (!launch_logs_enable) { strcat(label_text, "#D0D0D0 OFF#"); - lv_label_set_array_text(label_btn, label_text, 64); + lv_label_set_text(label_btn, label_text); } else { - strcat(label_text, "#00FFC9 ON #"); - lv_label_set_array_text(label_btn, label_text, 64); + s_printf(label_text, "%s%s%s", label_text, text_color, " ON #"); + lv_label_set_text(label_btn, label_text); } return LV_RES_OK; @@ -988,24 +1574,49 @@ typedef struct _launch_button_pos_t u16 btn_y; u16 lbl_x; u16 lbl_y; - } launch_button_pos_t; -static const launch_button_pos_t launch_button_pos[8] = { +static const launch_button_pos_t launch_button_pos8[8] = { + // First row. { 19, 36, 0, 245 }, { 340, 36, 321, 245 }, { 661, 36, 642, 245 }, { 982, 36, 963, 245 }, + // Second row. { 19, 313, 0, 522 }, { 340, 313, 321, 522 }, { 661, 313, 642, 522 }, { 982, 313, 963, 522 } }; +static const launch_button_pos_t launch_button_pos10[10] = { + // First row. + { 19, 36, 0, 245}, + {260, 36, 241, 245}, + {501, 36, 482, 245}, + {742, 36, 723, 245}, + {983, 36, 964, 245}, + // Second row. + { 19, 313, 0, 522}, + {260, 313, 241, 522}, + {501, 313, 482, 522}, + {742, 313, 723, 522}, + {983, 313, 964, 522} +}; + static lv_res_t _create_window_home_launch(lv_obj_t *btn) { + const u32 max_entries = n_cfg.entries_5_col ? 10 : 8; + const launch_button_pos_t *launch_button_pos = n_cfg.entries_5_col ? launch_button_pos10 : launch_button_pos8; + char *icon_path; + static lv_style_t btn_home_noborder_rel; + lv_style_copy(&btn_home_noborder_rel, lv_theme_get_current()->btn.rel); + btn_home_noborder_rel.body.opa = LV_OPA_0; + btn_home_noborder_rel.body.border.width = 4; + btn_home_noborder_rel.body.border.opa = LV_OPA_0; + static lv_style_t btn_home_transp_rel; lv_style_copy(&btn_home_transp_rel, lv_theme_get_current()->btn.rel); btn_home_transp_rel.body.opa = LV_OPA_0; @@ -1024,10 +1635,28 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn) lv_obj_t *win; bool more_cfg = false; - if (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)),"#00EDBA Launch#")) - more_cfg = true; + bool combined_cfg = false; + if (btn) + { + if (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)) + 8,"Launch#")) + more_cfg = true; + } + else + { + switch (n_cfg.home_screen) + { + case 1: // All configs. + combined_cfg = true; + break; + case 3: // More configs + more_cfg = true; + break; + } + } - if (!more_cfg) + if (!btn) + win = create_window_launch(SYMBOL_GPS" hekate - Launch"); + else if (!more_cfg) win = create_window_launch(SYMBOL_GPS" Launch"); else win = create_window_launch(SYMBOL_GPS" More Configurations"); @@ -1038,20 +1667,18 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn) lv_cont_set_fit(lv_page_get_scrl(lv_win_get_content(win)), false, false); lv_page_set_scrl_height(lv_win_get_content(win), 572); + lv_btn_ext_t * ext; lv_obj_t *btn_boot_entry; lv_obj_t *boot_entry_lbl_cont; lv_obj_t *boot_entry_label; bool no_boot_entries = false; - u32 max_entries = 8; - lv_btn_ext_t * ext; - // Create CFW buttons. // Buttons are 200 x 200 with 4 pixel borders. // Icons must be <= 192 x 192. // Create first Button. btn_boot_entry = lv_btn_create(win, NULL); - launch_ctxt[0] = btn_boot_entry; + launch_ctxt.btn[0] = btn_boot_entry; lv_obj_set_size(btn_boot_entry, 200, 200); lv_obj_set_pos(btn_boot_entry, launch_button_pos[0].btn_x, launch_button_pos[0].btn_y); lv_obj_set_opa_scale(btn_boot_entry, LV_OPA_0); @@ -1061,8 +1688,8 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn) boot_entry_lbl_cont = lv_cont_create(win, NULL); boot_entry_label = lv_label_create(boot_entry_lbl_cont, NULL); lv_obj_set_style(boot_entry_label, &hint_small_style_white); - lv_label_set_static_text(boot_entry_label, ""); - launch_ctxt[1] = boot_entry_label; + lv_label_set_text(boot_entry_label, ""); + launch_ctxt.label[0] = boot_entry_label; lv_cont_set_fit(boot_entry_lbl_cont, false, false); lv_cont_set_layout(boot_entry_lbl_cont, LV_LAYOUT_CENTER); @@ -1071,128 +1698,226 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn) lv_obj_set_style(boot_entry_lbl_cont, &btn_label_home_transp); // Create the rest of the buttons. - for (u32 btn_idx = 2; btn_idx < 16; btn_idx += 2) + for (u32 btn_idx = 1; btn_idx < (n_cfg.entries_5_col ? 10 : 8); btn_idx++) { btn_boot_entry = lv_btn_create(win, btn_boot_entry); - launch_ctxt[btn_idx] = btn_boot_entry; - lv_obj_set_pos(btn_boot_entry, launch_button_pos[btn_idx >> 1].btn_x, launch_button_pos[btn_idx >> 1].btn_y); + launch_ctxt.btn[btn_idx] = btn_boot_entry; + lv_obj_set_pos(btn_boot_entry, launch_button_pos[btn_idx].btn_x, launch_button_pos[btn_idx].btn_y); boot_entry_lbl_cont = lv_cont_create(win, boot_entry_lbl_cont); boot_entry_label = lv_label_create(boot_entry_lbl_cont, boot_entry_label); - lv_obj_set_pos(boot_entry_lbl_cont, launch_button_pos[btn_idx >> 1].lbl_x, launch_button_pos[btn_idx >> 1].lbl_y); - launch_ctxt[btn_idx + 1] = boot_entry_label; + lv_obj_set_pos(boot_entry_lbl_cont, launch_button_pos[btn_idx].lbl_x, launch_button_pos[btn_idx].lbl_y); + launch_ctxt.label[btn_idx] = boot_entry_label; } + // Create colorized icon style based on its parent style. + static lv_style_t img_style; + lv_style_copy(&img_style, &lv_style_plain); + img_style.image.color = lv_color_hsv_to_rgb(n_cfg.theme_color, 100, 100); + img_style.image.intense = LV_OPA_COVER; + // Parse ini boot entries and set buttons/icons. - char *tmp_path = calloc(0x80, 1); + char *tmp_path = malloc(1024); + u32 curr_btn_idx = 0; // Active buttons. LIST_INIT(ini_sections); - if (sd_mount()) + + if (!sd_mount()) + goto failed_sd_mount; + + // Check if we use custom system icons. + bool icon_sw_custom = !f_stat("bootloader/res/icon_switch_custom.bmp", NULL); + bool icon_pl_custom = !f_stat("bootloader/res/icon_payload_custom.bmp", NULL); + + // Choose what to parse. + bool ini_parse_success = false; + if (!more_cfg) + ini_parse_success = ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false); + else + ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true); + + if (combined_cfg && !ini_parse_success) { - // Choose what to parse. - bool ini_parse_success = false; - if (!more_cfg) - ini_parse_success = ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false); - else - ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true); +ini_parsing: + list_init(&ini_sections); + ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true); + more_cfg = true; + } - if (ini_parse_success) + if (!ini_parse_success) + goto ini_parse_failed; + + // Iterate to all boot entries and load icons. + u32 entry_idx = 1; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "config") || (ini_sec->type != INI_CHOICE)) + continue; + + icon_path = NULL; + bool payload = false; + bool img_colorize = false; + bool img_noborder = false; + lv_img_dsc_t *bmp = NULL; + lv_obj_t *img = NULL; + + // Check for icons. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) { - // Iterate to all boot entries and load icons. - u32 i = 1, x = 0; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + if (!strcmp("icon", kv->key)) + icon_path = kv->val; + else if (!strcmp("payload", kv->key)) + payload = true; + } + + // If icon not found, check res folder for section_name.bmp. + // If not, use defaults. + if (!icon_path) + { + s_printf(tmp_path, "bootloader/res/%s.bmp", ini_sec->name); + bmp = bmp_to_lvimg_obj(tmp_path); + if (!bmp) { - if (!strcmp(ini_sec->name, "config") || (ini_sec->type != INI_CHOICE)) - continue; - - icon_path = NULL; - bool payload = false; - lv_img_dsc_t *bmp = NULL; - lv_obj_t *img = NULL; - - // Check for icons. - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - if (!strcmp("icon", kv->key)) - icon_path = kv->val; - else if (!strcmp("payload", kv->key)) - payload = true; - } - - // If icon not found, check res folder for section_name.bmp. - // If not, use defaults. - if (!icon_path) - { - s_printf(tmp_path, "bootloader/res/%s.bmp", ini_sec->name); - bmp = bmp_to_lvimg_obj(tmp_path); - if (!bmp) - { - if (!strcmp(ini_sec->name, "Lakka")) - bmp = icon_lakka; - else if (payload) - bmp = icon_payload; - } - } - else - bmp = bmp_to_lvimg_obj(icon_path); - - // Enable button. - lv_obj_set_opa_scale(launch_ctxt[x], LV_OPA_COVER); - - // Default to switch logo if no icon found at all. - if (!bmp) - bmp = icon_switch; - - //Set icon. + s_printf(tmp_path, "bootloader/res/%s_hue_nobox.bmp", ini_sec->name); + bmp = bmp_to_lvimg_obj(tmp_path); if (bmp) { - img = lv_img_create(launch_ctxt[x], NULL); - lv_img_set_src(img, bmp); + img_noborder = true; + img_colorize = true; + } + if (!bmp) + { + s_printf(tmp_path, "bootloader/res/%s_hue.bmp", ini_sec->name); + bmp = bmp_to_lvimg_obj(tmp_path); + if (bmp) + img_colorize = true; + } + if (!bmp) + { + s_printf(tmp_path, "bootloader/res/%s_nobox.bmp", ini_sec->name); + bmp = bmp_to_lvimg_obj(tmp_path); + if (bmp) + img_noborder = true; } - - // Add button mask/radius and align icon. - lv_obj_t *btn = lv_btn_create(launch_ctxt[x], NULL); - lv_obj_set_size(btn, 200, 200); - lv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_home_transp_rel); - lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_home_transp_pr); - if (img) - lv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0); - - // Set autoboot index. - ext = lv_obj_get_ext_attr(btn); - ext->idx = i; - ext = lv_obj_get_ext_attr(launch_ctxt[x]); // Redundancy. - ext->idx = i; - - // Set action. - if (!more_cfg) - lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_action); - else - lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_more_cfg_action); - - // Set button's label text. - lv_label_set_array_text(launch_ctxt[x + 1], ini_sec->name, strlen(ini_sec->name)); - lv_obj_set_opa_scale(launch_ctxt[x + 1], LV_OPA_COVER); - - // Set rolling text if name is big. - if (strlen(ini_sec->name) > 22) - lv_label_set_long_mode(boot_entry_label, LV_LABEL_LONG_ROLL); - - i++; - x += 2; - - if (i > max_entries) - break; } - if (i < 2) - no_boot_entries = true; + + if (!bmp && payload) + { + bmp = icon_payload; + + if (!icon_pl_custom) + img_colorize = true; + } } else - no_boot_entries = true; + { + bmp = bmp_to_lvimg_obj(icon_path); + + // Check if both colorization and border are enabled. + if (bmp && strlen(icon_path) > 14 && !memcmp(icon_path + strlen(icon_path) - 14, "_hue_nobox", 10)) + { + img_colorize = true; + img_noborder = true; + } + else + { + // Check if colorization is enabled. + if (bmp && strlen(icon_path) > 8 && !memcmp(icon_path + strlen(icon_path) - 8, "_hue", 4)) + img_colorize = true; + + // Check if no border is enabled. + if (bmp && strlen(icon_path) > 10 && !memcmp(icon_path + strlen(icon_path) - 10, "_nobox", 6)) + img_noborder = true; + } + } + + // Enable button. + lv_obj_set_opa_scale(launch_ctxt.btn[curr_btn_idx], LV_OPA_COVER); + + // Default to switch logo if no icon found at all. + if (!bmp) + { + bmp = icon_switch; + + if (!icon_sw_custom) + img_colorize = true; + } + + //Set icon. + if (bmp) + { + img = lv_img_create(launch_ctxt.btn[curr_btn_idx], NULL); + + if (img_colorize) + lv_img_set_style(img, &img_style); + + lv_img_set_src(img, bmp); + } + + // Add button mask/radius and align icon. + lv_obj_t *btns = lv_btn_create(launch_ctxt.btn[curr_btn_idx], NULL); + u32 btn_width = 200; + u32 btn_height = 200; + if (img_noborder) + { + btn_width = bmp->header.w + 4; + btn_height = bmp->header.h + 4; + + if (btn_width > 200) + btn_width = 200; + if (btn_height > 200) + btn_height = 200; + + lv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_REL, &btn_home_noborder_rel); + lv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_PR, &btn_home_noborder_rel); + } + lv_obj_set_size(btns, btn_width, btn_height); + lv_btn_set_style(btns, LV_BTN_STYLE_REL, img_noborder ? &btn_home_noborder_rel : &btn_home_transp_rel); + lv_btn_set_style(btns, LV_BTN_STYLE_PR, &btn_home_transp_pr); + if (img) + lv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0); + if (img_noborder) + lv_obj_align(btns, NULL, LV_ALIGN_CENTER, 0, 0); + + // Set autoboot index. + ext = lv_obj_get_ext_attr(btns); + ext->idx = entry_idx; + ext = lv_obj_get_ext_attr(launch_ctxt.btn[curr_btn_idx]); // Redundancy. + ext->idx = entry_idx; + + // Set action. + if (!more_cfg) + lv_btn_set_action(btns, LV_BTN_ACTION_CLICK, _launch_action); + else + lv_btn_set_action(btns, LV_BTN_ACTION_CLICK, _launch_more_cfg_action); + + // Set button's label text. + lv_label_set_text(launch_ctxt.label[curr_btn_idx], ini_sec->name); + lv_obj_set_opa_scale(launch_ctxt.label[curr_btn_idx], LV_OPA_COVER); + + // Set rolling text if name is big. + if (strlen(ini_sec->name) > 22) + lv_label_set_long_mode(launch_ctxt.label[curr_btn_idx], LV_LABEL_LONG_ROLL); + + entry_idx++; + curr_btn_idx++; + + // Check if we exceed max buttons. + if (curr_btn_idx >= max_entries) + break; } - else + + ini_free(&ini_sections); + +ini_parse_failed: + // Reiterate the loop with more cfgs if combined. + if (combined_cfg && (curr_btn_idx < (n_cfg.entries_5_col ? 10 : 8)) && !more_cfg) + goto ini_parsing; + +failed_sd_mount: + if (curr_btn_idx < 1) no_boot_entries = true; - sd_unmount(false); + sd_unmount(); free(tmp_path); @@ -1205,14 +1930,14 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn) { lv_label_set_static_text(label_error, "#FFDD00 No main boot entries found...#\n" - "You can use the following entry to boot stock,\n" + "Check that #96FF00 bootloader/hekate_ipl.ini# has boot entries\n" "or use #C7EA46 More configs# button for more boot entries."); } else { lv_label_set_static_text(label_error, "#FFDD00 No .ini or boot entries found...#\n" - "Check that a .ini file exists in #96FF00 /bootloader/ini/#,\n" + "Check that a .ini file exists in #96FF00 bootloader/ini/#\n" "and that it contains at least one entry."); } @@ -1228,10 +1953,13 @@ static void _create_tab_home(lv_theme_t *th, lv_obj_t *parent) lv_page_set_scrl_fit(parent, false, false); lv_page_set_scrl_height(parent, 592); + char btn_colored_text[64]; + // Set brand label. lv_obj_t *label_brand = lv_label_create(parent, NULL); lv_label_set_recolor(label_brand, true); - lv_label_set_static_text(label_brand, "#00EDBA hekate#"); + s_printf(btn_colored_text, "%s%s", text_color, " hekate#"); + lv_label_set_text(label_brand, btn_colored_text); lv_obj_set_pos(label_brand, 50, 48); // Set tagline label. @@ -1254,7 +1982,8 @@ static void _create_tab_home(lv_theme_t *th, lv_obj_t *parent) lv_obj_t *label_btn = lv_label_create(btn_launch, NULL); lv_label_set_recolor(label_btn, true); lv_obj_set_style(label_btn, &icons); - lv_label_set_static_text(label_btn, "#00EDBA "SYMBOL_DOT"#"); + s_printf(btn_colored_text, "%s%s", text_color, " "SYMBOL_DOT"#"); + lv_label_set_text(label_btn, btn_colored_text); lv_btn_set_action(btn_launch, LV_BTN_ACTION_CLICK, _create_window_home_launch); lv_obj_set_size(btn_launch, 256, 256); lv_obj_set_pos(btn_launch, 50, 160); @@ -1262,38 +1991,49 @@ static void _create_tab_home(lv_theme_t *th, lv_obj_t *parent) lv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28); lv_obj_t *label_btn2 = lv_label_create(btn_launch, NULL); lv_label_set_recolor(label_btn2, true); - lv_label_set_static_text(label_btn2, "#00EDBA Launch#"); + s_printf(btn_colored_text, "%s%s", text_color, " Launch#"); + lv_label_set_text(label_btn2, btn_colored_text); lv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174); // More Configs button. lv_obj_t *btn_more_cfg = lv_btn_create(parent, btn_launch); label_btn = lv_label_create(btn_more_cfg, label_btn); - lv_label_set_static_text(label_btn, "#00EDBA "SYMBOL_CLOCK"#"); + s_printf(btn_colored_text, "%s%s", text_color, " "SYMBOL_CLOCK"#"); + lv_label_set_text(label_btn, btn_colored_text); lv_btn_set_action(btn_more_cfg, LV_BTN_ACTION_CLICK, _create_window_home_launch); lv_btn_set_layout(btn_more_cfg, LV_LAYOUT_OFF); lv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28); label_btn2 = lv_label_create(btn_more_cfg, label_btn2); - lv_label_set_static_text(label_btn2, "#00EDBA More Configs#"); + s_printf(btn_colored_text, "%s%s", text_color, " More Configs#"); + lv_label_set_text(label_btn2, btn_colored_text); lv_obj_set_pos(btn_more_cfg, 341, 160); lv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174); // Quick Launch button. // lv_obj_t *btn_quick_launch = lv_btn_create(parent, NULL); - // label_btn = lv_label_create(btn_quick_launch, label_btn); - // lv_label_set_static_text(label_btn, SYMBOL_EDIT" Quick Launch"); + // lv_obj_t *label_quick_launch = lv_label_create(btn_quick_launch, NULL); + // lv_label_set_static_text(label_quick_launch, SYMBOL_EDIT" Quick Launch"); // lv_obj_set_width(btn_quick_launch, 256); // lv_obj_set_pos(btn_quick_launch, 343, 448); // lv_btn_set_action(btn_quick_launch, LV_BTN_ACTION_CLICK, NULL); + lv_obj_t *btn_nyx_options = lv_btn_create(parent, NULL); + _create_text_button(th, NULL, btn_nyx_options, SYMBOL_SETTINGS" Nyx Settings", NULL); + //lv_obj_set_width(btn_nyx_options, 256); + lv_btn_set_action(btn_nyx_options, LV_BTN_ACTION_CLICK, create_win_nyx_options); + lv_obj_align(btn_nyx_options, NULL, LV_ALIGN_IN_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 12); + // Payloads button. lv_obj_t *btn_payloads = lv_btn_create(parent, btn_launch); label_btn = lv_label_create(btn_payloads, label_btn); - lv_label_set_static_text(label_btn, "#00EDBA "SYMBOL_OK"#"); + s_printf(btn_colored_text, "%s%s", text_color, " "SYMBOL_OK"#"); + lv_label_set_text(label_btn, btn_colored_text); lv_btn_set_action(btn_payloads, LV_BTN_ACTION_CLICK, _create_mbox_payloads); lv_btn_set_layout(btn_payloads, LV_LAYOUT_OFF); lv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28); label_btn2 = lv_label_create(btn_payloads, label_btn2); - lv_label_set_static_text(label_btn2, "#00EDBA Payloads#"); + s_printf(btn_colored_text, "%s%s", text_color, " Payloads#"); + lv_label_set_text(label_btn2, btn_colored_text); lv_obj_set_pos(btn_payloads, 632, 160); lv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174); @@ -1306,13 +2046,15 @@ static void _create_tab_home(lv_theme_t *th, lv_obj_t *parent) // emuMMC manage button. lv_obj_t *btn_emummc = lv_btn_create(parent, btn_launch); label_btn = lv_label_create(btn_emummc, label_btn); - lv_label_set_static_text(label_btn, "#00EDBA "SYMBOL_LIST"#"); - lv_btn_set_action(btn_emummc, LV_BTN_ACTION_CLICK,create_win_emummc_tools); + s_printf(btn_colored_text, "%s%s", text_color, " "SYMBOL_LIST"#"); + lv_label_set_text(label_btn, btn_colored_text); + lv_btn_set_action(btn_emummc, LV_BTN_ACTION_CLICK, create_win_emummc_tools); lv_btn_set_layout(btn_emummc, LV_LAYOUT_OFF); lv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28); lv_obj_set_pos(btn_emummc, 959, 160); label_btn2 = lv_label_create(btn_emummc, label_btn2); - lv_label_set_static_text(label_btn2, "#00EDBA emuMMC#"); + s_printf(btn_colored_text, "%s%s", text_color, " emuMMC#"); + lv_label_set_text(label_btn2, btn_colored_text); lv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174); // Create bottom right power buttons. @@ -1332,11 +2074,14 @@ static void _create_tab_home(lv_theme_t *th, lv_obj_t *parent) static lv_res_t _save_options_action(lv_obj_t *btn) { - static const char * mbox_btn_map[] = {"\211", "\222OK!", "\211", ""}; + static const char * mbox_btn_map[] = {"\251", "\222OK!", "\251", ""}; lv_obj_t * mbox = lv_mbox_create(lv_scr_act(), NULL); lv_mbox_set_recolor_text(mbox, true); - int res = !create_config_entry(); + int res = 0; + + if (sd_mount()) + res = !create_config_entry(); if (res) lv_mbox_set_text(mbox, "#FF8000 hekate Configuration#\n\n#96FF00 The configuration was saved to sd card!#"); @@ -1345,6 +2090,10 @@ static lv_res_t _save_options_action(lv_obj_t *btn) lv_mbox_add_btns(mbox, mbox_btn_map, NULL); lv_obj_set_top(mbox, true); + nyx_options_clear_ini_changes_made(); + + sd_unmount(); + return LV_RES_OK; } @@ -1352,6 +2101,7 @@ static void _create_status_bar(lv_theme_t * th) { static lv_obj_t *status_bar_bg; status_bar_bg = lv_cont_create(lv_layer_top(), NULL); + status_bar.bar_bg = status_bar_bg; static lv_style_t status_bar_style; lv_style_copy(&status_bar_style, &lv_style_plain_color); @@ -1365,34 +2115,34 @@ static void _create_status_bar(lv_theme_t * th) // Battery percentages. lv_obj_t *lbl_battery = lv_label_create(status_bar_bg, NULL); lv_label_set_recolor(lbl_battery, true); - lv_label_set_static_text(lbl_battery, " "SYMBOL_DOT" 00.0% "SYMBOL_BATTERY_1" #FFDD00 "SYMBOL_CHARGE"#"); + lv_label_set_text(lbl_battery, " "SYMBOL_DOT" 00.0% "SYMBOL_BATTERY_1" #FFDD00 "SYMBOL_CHARGE"#"); lv_obj_align(lbl_battery, NULL, LV_ALIGN_IN_RIGHT_MID, -LV_DPI * 6 / 11, 0); status_bar.battery = lbl_battery; // Amperages, voltages. lbl_battery = lv_label_create(status_bar_bg, lbl_battery); lv_obj_set_style(lbl_battery, &hint_small_style_white); - lv_label_set_static_text(lbl_battery, "#96FF00 +0 mA# (0 mV)"); + lv_label_set_text(lbl_battery, "#96FF00 +0 mA# (0 mV)"); lv_obj_align(lbl_battery, status_bar.battery, LV_ALIGN_OUT_LEFT_MID, -LV_DPI / 25, -1); status_bar.battery_more = lbl_battery; lv_obj_t *lbl_left = lv_label_create(status_bar_bg, NULL); - lv_label_set_static_text(lbl_left, SYMBOL_CLOCK" "); + lv_label_set_text(lbl_left, SYMBOL_CLOCK" "); lv_obj_align(lbl_left, NULL, LV_ALIGN_IN_LEFT_MID, LV_DPI * 6 / 11, 0); // Time, temperature. lv_obj_t *lbl_time_temp = lv_label_create(status_bar_bg, NULL); - lv_label_set_static_text(lbl_time_temp, "00:00 "SYMBOL_DOT" "SYMBOL_TEMPERATURE" 00.0"); + lv_label_set_text(lbl_time_temp, "00:00 "SYMBOL_DOT" "SYMBOL_TEMPERATURE" 00.0"); lv_obj_align(lbl_time_temp, lbl_left, LV_ALIGN_OUT_RIGHT_MID, 0, 0); status_bar.time_temp = lbl_time_temp; lbl_left = lv_label_create(status_bar_bg, NULL); - lv_label_set_static_text(lbl_left, " "SYMBOL_DOT); + lv_label_set_text(lbl_left, " "SYMBOL_DOT); lv_obj_align(lbl_left, lbl_time_temp, LV_ALIGN_OUT_RIGHT_MID, 0, -LV_DPI / 14); status_bar.temp_symbol = lbl_left; lv_obj_t *lbl_degrees = lv_label_create(status_bar_bg, NULL); - lv_label_set_static_text(lbl_degrees, "C"); + lv_label_set_text(lbl_degrees, "C"); lv_obj_align(lbl_degrees, lbl_left, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 50, LV_DPI / 14); status_bar.temp_degrees = lbl_degrees; @@ -1404,16 +2154,55 @@ static void _create_status_bar(lv_theme_t * th) lv_obj_set_size(btn_mid, LV_DPI * 5 / 2, LV_DPI / 2); lv_obj_align(btn_mid, NULL, LV_ALIGN_CENTER, 0, 0); status_bar.mid = btn_mid; - lv_obj_set_opa_scale(status_bar.mid, LV_OPA_0); - lv_obj_set_opa_scale_enable(status_bar.mid, true); - lv_obj_set_click(status_bar.mid, false); + lv_obj_set_opa_scale(btn_mid, LV_OPA_0); + lv_obj_set_opa_scale_enable(btn_mid, true); + lv_obj_set_click(btn_mid, false); lv_btn_set_action(btn_mid, LV_BTN_ACTION_CLICK, _save_options_action); } +static lv_res_t _create_mbox_save_changes_action(lv_obj_t *btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + mbox_action(btns, txt); + + if (!btn_idx) + _save_options_action(NULL); + + return LV_RES_INV; +} + +void nyx_check_ini_changes() +{ + if (nyx_options_get_ini_changes_made()) + { + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\222Save", "\222Cancel", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_mbox_set_text(mbox, + "#FF8000 Main configuration#\n\n" + "You changed the configuration!\n\n" + "Do you want to save it?"); + + lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_save_changes_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + nyx_options_clear_ini_changes_made(); + } +} + static lv_res_t _show_hide_save_button(lv_obj_t *tv, uint16_t tab_idx) { if (tab_idx == 4) // Options. { + lv_btn_set_action(status_bar.mid, LV_BTN_ACTION_CLICK, _save_options_action); lv_obj_set_opa_scale(status_bar.mid, LV_OPA_COVER); lv_obj_set_click(status_bar.mid, true); } @@ -1423,6 +2212,8 @@ static lv_res_t _show_hide_save_button(lv_obj_t *tv, uint16_t tab_idx) lv_obj_set_click(status_bar.mid, false); } + nyx_check_ini_changes(); + return LV_RES_OK; } @@ -1442,9 +2233,9 @@ static void _nyx_set_default_styles(lv_theme_t * th) hint_small_style_white.text.font = &interui_20; lv_style_copy(&monospace_text, &lv_style_plain); - monospace_text.body.main_color = LV_COLOR_HEX(0x1b1b1b); - monospace_text.body.grad_color = LV_COLOR_HEX(0x1b1b1b); - monospace_text.body.border.color = LV_COLOR_HEX(0x1b1b1b); + monospace_text.body.main_color = LV_COLOR_HEX(0x1B1B1B); + monospace_text.body.grad_color = LV_COLOR_HEX(0x1B1B1B); + monospace_text.body.border.color = LV_COLOR_HEX(0x1B1B1B); monospace_text.body.border.width = 0; monospace_text.body.opa = LV_OPA_TRANSP; monospace_text.text.color = LV_COLOR_HEX(0xD8D8D8); @@ -1491,6 +2282,21 @@ static void _nyx_set_default_styles(lv_theme_t * th) tabview_btn_tgl_pr.body.main_color = LV_COLOR_HEX(0xFFFFFF); tabview_btn_tgl_pr.body.grad_color = tabview_btn_tgl_pr.body.main_color; tabview_btn_tgl_pr.body.opa = 35; + + lv_color_t tmp_color = lv_color_hsv_to_rgb(n_cfg.theme_color, 100, 100); + text_color = malloc(32); + s_printf(text_color, "#%06X", (u32)(tmp_color.full & 0xFFFFFF)); +} + +lv_task_t *task_bpmp_clock; +void first_time_bpmp_clock(void *param) +{ + // Remove task. + lv_task_del(task_bpmp_clock); + + // Max clock seems fine. Save it. + n_cfg.bpmp_clock = 1; + create_nyx_config_entry(false); } static void _nyx_main_menu(lv_theme_t * th) @@ -1511,8 +2317,8 @@ static void _nyx_main_menu(lv_theme_t * th) lv_obj_t *cnr = lv_cont_create(scr, NULL); static lv_style_t base_bg_style; lv_style_copy(&base_bg_style, &lv_style_plain_color); - base_bg_style.body.main_color = LV_COLOR_HEX(0x2D2D2D); - base_bg_style.body.grad_color = LV_COLOR_HEX(0x2D2D2D); + base_bg_style.body.main_color = th->bg->body.main_color; + base_bg_style.body.grad_color = base_bg_style.body.main_color; lv_cont_set_style(cnr, &base_bg_style); lv_obj_set_size(cnr, LV_HOR_RES, LV_VER_RES); @@ -1534,7 +2340,9 @@ static void _nyx_main_menu(lv_theme_t * th) // Add all tabs content. char version[32]; - s_printf(version, "hekate v%d.%d.%d", nyx_str->version & 0xFF, (nyx_str->version >> 8) & 0xFF, (nyx_str->version >> 16) & 0xFF); + char rel = (nyx_str->version >> 24) & 0xFF; + s_printf(version, "hekate %s%d.%d.%d%c", + rel ? "v" : "", nyx_str->version & 0xFF, (nyx_str->version >> 8) & 0xFF, (nyx_str->version >> 16) & 0xFF, rel > 'A' ? rel : 0); lv_obj_t *tab_about = lv_tabview_add_tab(tv, version); lv_obj_t *tab_home = lv_tabview_add_tab(tv, SYMBOL_HOME" Home"); @@ -1569,6 +2377,9 @@ static void _nyx_main_menu(lv_theme_t * th) lv_task_create(_check_sd_card_removed, 2000, LV_TASK_PRIO_LOWEST, NULL); + task_emmc_errors = lv_task_create(_nyx_emmc_issues_warning, 2000, LV_TASK_PRIO_LOWEST, NULL); + lv_task_ready(task_emmc_errors); + // Create top level global line separators. lv_obj_t *line = lv_cont_create(lv_layer_top(), NULL); @@ -1592,13 +2403,24 @@ static void _nyx_main_menu(lv_theme_t * th) // Option save button. lv_tabview_set_tab_load_action(tv, _show_hide_save_button); - // If we rebooted to run sept for dumping, lunch dump immediately. - if (nyx_str->cfg & NYX_CFG_DUMP) + // Check if Nyx was launched with a function set. + if (nyx_str->cfg & NYX_CFG_UMS) { - nyx_str->cfg &= ~(NYX_CFG_DUMP); - lv_task_t *task_run_dump = lv_task_create(sept_run_dump, LV_TASK_ONESHOT, LV_TASK_PRIO_MID, NULL); - lv_task_once(task_run_dump); + nyx_str->cfg &= ~(NYX_CFG_UMS); + lv_task_t *task_run_ums = lv_task_create(nyx_run_ums, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, (void *)&nyx_str->cfg); + lv_task_once(task_run_ums); } + else if (n_cfg.home_screen) + _create_window_home_launch(NULL); + + if (!n_cfg.timeoff) + { + lv_task_t *task_run_clock = lv_task_create(first_time_clock_edit, LV_TASK_ONESHOT, LV_TASK_PRIO_MID, NULL); + lv_task_once(task_run_clock); + } + + if (!n_cfg.bpmp_clock) + task_bpmp_clock = lv_task_create(first_time_bpmp_clock, 10000, LV_TASK_PRIO_LOWEST, NULL); } void nyx_load_and_run() @@ -1614,26 +2436,71 @@ void nyx_load_and_run() disp_drv.disp_flush = _disp_fb_flush; lv_disp_drv_register(&disp_drv); + // Initialize Joy-Con. + if (!n_cfg.jc_disable) + { + lv_task_t *task_jc_init_hw = lv_task_create(jc_init_hw, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL); + lv_task_once(task_jc_init_hw); + } + lv_indev_drv_t indev_drv_jc; + lv_indev_drv_init(&indev_drv_jc); + indev_drv_jc.type = LV_INDEV_TYPE_POINTER; + indev_drv_jc.read = _jc_virt_mouse_read; + memset(&jc_drv_ctx, 0, sizeof(jc_lv_driver_t)); + jc_drv_ctx.indev_jc = lv_indev_drv_register(&indev_drv_jc); + close_btn = NULL; + // Initialize touch. - touch_power_on(); + touch_enabled = touch_power_on(); lv_indev_drv_t indev_drv_touch; lv_indev_drv_init(&indev_drv_touch); indev_drv_touch.type = LV_INDEV_TYPE_POINTER; indev_drv_touch.read = _fts_touch_read; - lv_indev_drv_register(&indev_drv_touch); + jc_drv_ctx.indev_touch = lv_indev_drv_register(&indev_drv_touch); touchpad.touch = false; // Initialize temperature sensor. tmp451_init(); - //Set the theme. - //! TODO: Finish theme support. - lv_theme_t *th = lv_theme_hekate_init(167, NULL); + // Set hekate theme based on chosen hue. + lv_theme_t *th = lv_theme_hekate_init(n_cfg.theme_bg, n_cfg.theme_color, NULL); lv_theme_set_current(th); // Create main menu _nyx_main_menu(th); - while (true) - lv_task_handler(); + jc_drv_ctx.cursor = lv_img_create(lv_scr_act(), NULL); + lv_img_set_src(jc_drv_ctx.cursor, &touch_cursor); + lv_obj_set_opa_scale(jc_drv_ctx.cursor, LV_OPA_TRANSP); + lv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, true); + + // Check if sd card issues. + if (sd_get_mode() == SD_1BIT_HS25) + { + lv_task_t *task_run_sd_errors = lv_task_create(_nyx_sd_card_issues_warning, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL); + lv_task_once(task_run_sd_errors); + } + + // Gui loop. + if (h_cfg.t210b01) + { + // Minerva not supported on T210B01 yet. Slight power saving via spinlock. + while (true) + { + lv_task_handler(); + usleep(400); + } + } + else + { + // Alternate DRAM frequencies. Saves 280 mW. + while (true) + { + minerva_change_freq(FREQ_1600); // Takes 295 us. + + lv_task_handler(); + + minerva_change_freq(FREQ_800); // Takes 80 us. + } + } } diff --git a/nyx/nyx_gui/frontend/gui.h b/nyx/nyx_gui/frontend/gui.h index f867df9..3f13444 100644 --- a/nyx/nyx_gui/frontend/gui.h +++ b/nyx/nyx_gui/frontend/gui.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +17,7 @@ #ifndef _GUI_H_ #define _GUI_H_ -#include "../libs/lvgl/lvgl.h" +#include typedef struct _emmc_tool_gui_t { @@ -27,35 +27,56 @@ typedef struct _emmc_tool_gui_t lv_obj_t *label_finish; lv_obj_t *bar; lv_style_t *bar_teal_bg; + lv_style_t *bar_teal_ind; lv_style_t *bar_white_ind; char *txt_buf; - char *base_path; + char *base_path; bool raw_emummc; } emmc_tool_gui_t; -lv_style_t hint_small_style; -lv_style_t hint_small_style_white; -lv_style_t monospace_text; +typedef struct _gui_status_bar_ctx +{ + lv_obj_t *bar_bg; + lv_obj_t *mid; + lv_obj_t *time_temp; + lv_obj_t *temp_symbol; + lv_obj_t *temp_degrees; + lv_obj_t *battery; + lv_obj_t *battery_more; +} gui_status_bar_ctx; -lv_obj_t *payload_list; -lv_obj_t *autorcm_btn; +extern lv_style_t hint_small_style; +extern lv_style_t hint_small_style_white; +extern lv_style_t monospace_text; -lv_img_dsc_t *icon_switch; -lv_img_dsc_t *icon_payload; -lv_img_dsc_t *icon_lakka; +extern lv_obj_t *payload_list; +extern lv_obj_t *autorcm_btn; +extern lv_obj_t *close_btn; -lv_img_dsc_t *hekate_bg; +extern lv_img_dsc_t *icon_switch; +extern lv_img_dsc_t *icon_payload; +extern lv_img_dsc_t *icon_lakka; -lv_style_t btn_transp_rel, btn_transp_pr, btn_transp_tgl_rel, btn_transp_tgl_pr; -lv_style_t ddlist_transp_bg, ddlist_transp_sel; -lv_style_t tabview_btn_pr, tabview_btn_tgl_pr; +extern lv_img_dsc_t *hekate_bg; -lv_style_t mbox_darken; +extern lv_style_t btn_transp_rel, btn_transp_pr, btn_transp_tgl_rel, btn_transp_tgl_pr; +extern lv_style_t ddlist_transp_bg, ddlist_transp_sel; +extern lv_style_t tabview_btn_pr, tabview_btn_tgl_pr; +extern lv_style_t mbox_darken; + +extern char *text_color; + +extern gui_status_bar_ctx status_bar; + +void reload_nyx(); lv_img_dsc_t *bmp_to_lvimg_obj(const char *path); lv_res_t mbox_action(lv_obj_t * btns, const char * txt); +bool nyx_emmc_check_battery_enough(); +lv_res_t nyx_win_close_action_custom(lv_obj_t * btn); void nyx_window_toggle_buttons(lv_obj_t *win, bool disable); lv_obj_t *nyx_create_standard_window(const char *win_title); +lv_obj_t *nyx_create_window_custom_close_btn(const char *win_title, lv_action_t rel_action); void nyx_create_onoff_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, const char *btn_name, lv_action_t action, bool transparent); lv_res_t nyx_generic_onoff_toggle(lv_obj_t *btn); void manual_system_maintenance(bool refresh); diff --git a/nyx/nyx_gui/frontend/gui_emmc_tools.c b/nyx/nyx_gui/frontend/gui_emmc_tools.c index acb54de..9a4df69 100644 --- a/nyx/nyx_gui/frontend/gui_emmc_tools.c +++ b/nyx/nyx_gui/frontend/gui_emmc_tools.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,30 +16,22 @@ #include +#include + #include "gui.h" #include "gui_emmc_tools.h" #include "gui_tools.h" #include "fe_emmc_tools.h" -#include "../config/config.h" +#include "../config.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" #include "../hos/hos.h" -#include "../hos/sept.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../soc/fuse.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" +#include extern boot_cfg_t b_cfg; extern hekate_config h_cfg; -extern bool sd_mount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); +extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); typedef struct _emmc_backup_buttons_t { @@ -110,20 +102,25 @@ static void _create_window_backup_restore(emmcPartType_t type, const char* win_l lv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10); emmc_tool_gui_ctxt.label_info = label_info; - static lv_style_t bar_teal_bg, bar_white_ind; + static lv_style_t bar_teal_bg, bar_teal_ind, bar_white_ind; lv_style_copy(&bar_teal_bg, lv_theme_get_current()->bar.bg); bar_teal_bg.body.main_color = LV_COLOR_HEX(0x005a47); bar_teal_bg.body.grad_color = bar_teal_bg.body.main_color; + lv_style_copy(&bar_teal_ind, lv_theme_get_current()->bar.indic); + bar_teal_ind.body.main_color = LV_COLOR_HEX(0x00FFC9); + bar_teal_ind.body.grad_color = bar_teal_ind.body.main_color; + lv_style_copy(&bar_white_ind, lv_theme_get_current()->bar.indic); bar_white_ind.body.main_color = LV_COLOR_HEX(0xF0F0F0); bar_white_ind.body.grad_color = bar_white_ind.body.main_color; emmc_tool_gui_ctxt.bar_teal_bg = &bar_teal_bg; + emmc_tool_gui_ctxt.bar_teal_ind = &bar_teal_ind; emmc_tool_gui_ctxt.bar_white_ind = &bar_white_ind; - lv_obj_t * bar = lv_bar_create(h1, NULL); + lv_obj_t *bar = lv_bar_create(h1, NULL); lv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5); lv_bar_set_range(bar, 0, 100); lv_bar_set_value(bar, 0); @@ -158,7 +155,7 @@ static void _create_window_backup_restore(emmcPartType_t type, const char* win_l // Refresh AutoRCM button. if (emmc_btn_ctxt.restore && (type == PART_BOOT) && !emmc_btn_ctxt.raw_emummc) { - if (get_autorcm_status(false)) + if (get_set_autorcm_status(false)) lv_btn_set_state(autorcm_btn, LV_BTN_STATE_TGL_REL); else lv_btn_set_state(autorcm_btn, LV_BTN_STATE_REL); @@ -174,6 +171,9 @@ static void _create_window_backup_restore(emmcPartType_t type, const char* win_l static lv_res_t _emmc_backup_buttons_decider(lv_obj_t *btn) { + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + char *win_label = lv_label_get_text(lv_obj_get_child(btn, NULL)); if (emmc_btn_ctxt.emmc_boot == btn) @@ -215,7 +215,7 @@ static lv_res_t _emmc_backup_buttons_raw_toggle(lv_obj_t *btn) lv_obj_realign(emmc_btn_ctxt.emmc_boot); if (!emmc_btn_ctxt.restore) - lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" eMMC RAW GPP"); + lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_UPLOAD" eMMC RAW GPP"); else lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" eMMC RAW GPP"); lv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp); @@ -240,21 +240,13 @@ static lv_res_t _emmc_backup_buttons_raw_toggle(lv_obj_t *btn) else // Backup/Restore from and to emuMMC. { if (!emmc_btn_ctxt.restore) - { lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD" SD emuMMC BOOT0 & BOOT1"); - lv_obj_set_click(emmc_btn_ctxt.emmc_boot, false); - lv_btn_set_state(emmc_btn_ctxt.emmc_boot, LV_BTN_STATE_INA); - } else lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD" SD emuMMC BOOT0 & BOOT1"); lv_obj_realign(emmc_btn_ctxt.emmc_boot); if (!emmc_btn_ctxt.restore) - { - lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" SD emuMMC RAW GPP"); - lv_obj_set_click(emmc_btn_ctxt.emmc_raw_gpp, false); - lv_btn_set_state(emmc_btn_ctxt.emmc_raw_gpp, LV_BTN_STATE_INA); - } + lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_UPLOAD" SD emuMMC RAW GPP"); else lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" SD emuMMC RAW GPP"); lv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp); @@ -333,15 +325,15 @@ lv_res_t create_window_backup_restore_tool(lv_obj_t *btn) if (!emmc_btn_ctxt.restore) { lv_label_set_static_text(label_txt2, - "Allows you to backup your BOOT physical partitions.\n" - "They contain your BCT, keys and various package1.\n" + "Allows you to backup the BOOT physical partitions.\n" + "They contain the BCT, keys and various package1.\n" "#FF8000 These are paired with the RAW GPP backup.#"); } else { lv_label_set_static_text(label_txt2, - "Allows you to restore your BOOT physical partitions.\n" - "They contain your BCT, keys and various package1.\n" + "Allows you to restore the BOOT physical partitions.\n" + "They contain the BCT, keys and various package1.\n" "#FF8000 These are paired with the RAW GPP restore.#"); } lv_obj_set_style(label_txt2, &hint_small_style); @@ -363,14 +355,14 @@ lv_res_t create_window_backup_restore_tool(lv_obj_t *btn) if (!emmc_btn_ctxt.restore) { lv_label_set_static_text(label_txt2, - "Allows you to backup your GPP physical partition.\n" + "Allows you to backup the GPP physical partition.\n" "It contains, CAL0, various package2, SYSTEM, USER, etc.\n" "#FF8000 This is paired with the BOOT0/1 backups.#"); } else { lv_label_set_static_text(label_txt2, - "Allows you to restore your GPP physical partition.\n" + "Allows you to restore the GPP physical partition.\n" "It contains, CAL0, various package2, SYSTEM, USER, etc.\n" "#FF8000 This is paired with the BOOT0/1 restore.#"); } diff --git a/nyx/nyx_gui/frontend/gui_emmc_tools.h b/nyx/nyx_gui/frontend/gui_emmc_tools.h index 1bc031f..91aa2cd 100644 --- a/nyx/nyx_gui/frontend/gui_emmc_tools.h +++ b/nyx/nyx_gui/frontend/gui_emmc_tools.h @@ -17,7 +17,7 @@ #ifndef _GUI_EMMC_TOOLS_H_ #define _GUI_EMMC_TOOLS_H_ -#include "../libs/lvgl/lvgl.h" +#include lv_res_t create_window_backup_restore_tool(lv_obj_t *btn); diff --git a/nyx/nyx_gui/frontend/gui_emummc_tools.c b/nyx/nyx_gui/frontend/gui_emummc_tools.c index f91e30c..4182b22 100644 --- a/nyx/nyx_gui/frontend/gui_emummc_tools.c +++ b/nyx/nyx_gui/frontend/gui_emummc_tools.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,38 +16,50 @@ #include +#include + #include "gui.h" #include "fe_emummc_tools.h" -#include "../config/ini.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../storage/sdmmc.h" -#include "../utils/dirlist.h" -#include "../utils/list.h" -#include "../utils/sprintf.h" -#include "../utils/types.h" +#include "gui_tools_partition_manager.h" +#include -extern sdmmc_t sd_sdmmc; -extern sdmmc_storage_t sd_storage; +extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); -extern bool sd_mount(); -extern void sd_unmount(bool deinit); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); +typedef struct _mbr_ctxt_t +{ + u32 available; + u32 sector[3]; + u32 resized_cnt[3]; -#define MBR_1ST_PART_TYPE_OFF 0x1C2 + int part_idx; + u32 sector_start; +} mbr_ctxt_t; -static int part_idx; -static u32 sector_start; +static bool emummc_backup; +static mbr_ctxt_t mbr_ctx; +static lv_obj_t *emummc_manage_window; +static lv_res_t (*emummc_tools)(lv_obj_t *btn); + +static lv_res_t _action_emummc_window_close(lv_obj_t *btn) +{ + nyx_win_close_action_custom(btn); + + // Delete and relaunch main emuMMC window. + lv_obj_del(emummc_manage_window); + (*emummc_tools)(NULL); + + return LV_RES_INV; +} static void _create_window_emummc() { emmc_tool_gui_t emmc_tool_gui_ctxt; lv_obj_t *win; - if (!part_idx) - win = nyx_create_standard_window(SYMBOL_DRIVE" Create SD File emuMMC"); + if (!mbr_ctx.part_idx) + win = nyx_create_window_custom_close_btn(SYMBOL_DRIVE" Create SD File emuMMC", _action_emummc_window_close); else - win = nyx_create_standard_window(SYMBOL_DRIVE" Create SD Partition emuMMC"); + win = nyx_create_window_custom_close_btn(SYMBOL_DRIVE" Create SD Partition emuMMC", _action_emummc_window_close); //Disable buttons. nyx_window_toggle_buttons(win, true); @@ -94,7 +106,7 @@ static void _create_window_emummc() lv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10); emmc_tool_gui_ctxt.label_info = label_info; - lv_obj_t * bar = lv_bar_create(h1, NULL); + lv_obj_t *bar = lv_bar_create(h1, NULL); lv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5); lv_bar_set_range(bar, 0, 100); lv_bar_set_value(bar, 0); @@ -119,28 +131,64 @@ static void _create_window_emummc() lv_obj_align(label_finish, bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 9 / 20); emmc_tool_gui_ctxt.label_finish = label_finish; - if (!part_idx) + if (!mbr_ctx.part_idx) dump_emummc_file(&emmc_tool_gui_ctxt); else - dump_emummc_raw(&emmc_tool_gui_ctxt, part_idx, sector_start); + dump_emummc_raw(&emmc_tool_gui_ctxt, mbr_ctx.part_idx, mbr_ctx.sector_start, mbr_ctx.resized_cnt[mbr_ctx.part_idx - 1]); nyx_window_toggle_buttons(win, false); } +static lv_res_t _create_emummc_raw_format(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + // Create partition window. + if (!btn_idx) + create_window_partition_manager(btns); + + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; + + return LV_RES_INV; +} static lv_res_t _create_emummc_raw_action(lv_obj_t * btns, const char * txt) { int btn_idx = lv_btnm_get_pressed(btns); lv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns)); - if (!btn_idx) + mbr_ctx.sector_start = 0x8000; // Protective offset. + + switch (btn_idx) + { + case 0: + mbr_ctx.part_idx = 1; + mbr_ctx.sector_start += mbr_ctx.sector[0]; + break; + case 1: + mbr_ctx.part_idx = 2; + mbr_ctx.sector_start += mbr_ctx.sector[1]; + break; + case 2: + mbr_ctx.part_idx = 3; + mbr_ctx.sector_start += mbr_ctx.sector[2]; + break; + default: + break; + } + + if (btn_idx < 3) { lv_obj_set_style(bg, &lv_style_transp); _create_window_emummc(); } - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; mbox_action(btns, txt); @@ -153,68 +201,109 @@ static void _create_mbox_emummc_raw() lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" }; - static const char *mbox_btn_map2[] = { "\211", "OK", "\211", "" }; + static const char *mbox_btn_format[] = { "\222Continue", "\222Cancel", "" }; + static char *mbox_btn_parts[] = { "\262Part 1", "\262Part 2", "\262Part 3", "\222Cancel", "" }; lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); - char *txt_buf = (char *)malloc(0x500); - u8 *mbr = (u8 *)malloc(0x200); + char *txt_buf = (char *)malloc(SZ_16K); + mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t)); + + memset(&mbr_ctx, 0, sizeof(mbr_ctxt_t)); sd_mount(); sdmmc_storage_read(&sd_storage, 0, 1, mbr); - sd_unmount(false); - memcpy(mbr, mbr + 0x1BE, 0x40); + sd_unmount(); - sdmmc_storage_t storage; - sdmmc_t sdmmc; - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + emmc_initialize(false); + + u32 emmc_size_safe = emmc_storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1. + + emmc_end(); for (int i = 1; i < 4; i++) { - u32 curr_part_size = *(u32 *)&mbr[0x0C + (0x10 * i)]; - sector_start = *(u32 *)&mbr[0x08 + (0x10 * i)]; - u8 type = mbr[0x04 + (0x10 * i)]; - if ((curr_part_size >= (storage.sec_cnt + 0xC000)) && sector_start && type != 0x83) //! TODO: For now it skips linux partitions. + u32 part_size = mbr->partitions[i].size_sct; + u32 part_start = mbr->partitions[i].start_sct; + u8 part_type = mbr->partitions[i].type; + + // Skip Linux, GPT (Android) and SFD partitions. + bool valid_part = (part_type != 0x83) && (part_type != 0xEE) && (part_type != 0xFF); + + // Check if at least 4GB and start above 16MB. + if ((part_size >= 0x80F000) && part_start > 0x8000 && valid_part) { - part_idx = i; - sector_start += 0x8000; - break; + mbr_ctx.available |= BIT(i - 1); + mbr_ctx.sector[i - 1] = part_start; + + // Only allow up to 16GB resized emuMMC. + if (part_size <= 0x2010000) + mbr_ctx.resized_cnt[i - 1] = part_size - 0xC000; // Save sectors count without protective size and BOOT0/1. + else if (part_size >= emmc_size_safe) + mbr_ctx.resized_cnt[i - 1] = 0; + else + { + mbr_ctx.available &= ~BIT(i - 1); + mbr_ctx.sector[i - 1] = 0; + } } } - sdmmc_storage_end(&storage); - - if (part_idx) + if (mbr_ctx.available) { s_printf(txt_buf, - "#C7EA46 Found applicable partition: [Part %d]!#\n" - "#FF8000 Do you want to continue?#\n\n", part_idx); + "#C7EA46 Found applicable partition(s)!#\n" + "#FF8000 Choose a partition to continue:#\n\n"); } else - s_printf(txt_buf, "Failed to find applicable partition!\n\n"); + s_printf(txt_buf, "#FFDD00 Failed to find applicable partition!#\n\n"); s_printf(txt_buf + strlen(txt_buf), "Partition table:\n" - "Part 0: Type: %02x, Start: %08x, Size: %08x\n" - "Part 1: Type: %02x, Start: %08x, Size: %08x\n" - "Part 2: Type: %02x, Start: %08x, Size: %08x\n" - "Part 3: Type: %02x, Start: %08x, Size: %08x\n", - mbr[0x04], *(u32 *)&mbr[0x08], *(u32 *)&mbr[0x0C], - mbr[0x14], *(u32 *)&mbr[0x18], *(u32 *)&mbr[0x1C], - mbr[0x24], *(u32 *)&mbr[0x28], *(u32 *)&mbr[0x2C], - mbr[0x34], *(u32 *)&mbr[0x38], *(u32 *)&mbr[0x3C]); + "#C0C0C0 Part 0: Type: %02x, Start: %08x, Size: %08x#\n" + "#%s Part 1: Type: %02x, Start: %08x, Size: %08x#\n" + "#%s Part 2: Type: %02x, Start: %08x, Size: %08x#\n" + "#%s Part 3: Type: %02x, Start: %08x, Size: %08x#", + mbr->partitions[0].type, mbr->partitions[0].start_sct, mbr->partitions[0].size_sct, + (mbr_ctx.available & BIT(0)) ? (mbr_ctx.resized_cnt[0] ? "FFDD00" : "C7EA46") : "C0C0C0", + mbr->partitions[1].type, mbr->partitions[1].start_sct, mbr->partitions[1].size_sct, + (mbr_ctx.available & BIT(1)) ? (mbr_ctx.resized_cnt[1] ? "FFDD00" : "C7EA46") : "C0C0C0", + mbr->partitions[2].type, mbr->partitions[2].start_sct, mbr->partitions[2].size_sct, + (mbr_ctx.available & BIT(2)) ? (mbr_ctx.resized_cnt[2] ? "FFDD00" : "C7EA46") : "C0C0C0", + mbr->partitions[3].type, mbr->partitions[3].start_sct, mbr->partitions[3].size_sct); + if (mbr_ctx.resized_cnt[0] || mbr_ctx.resized_cnt[1] || mbr_ctx.resized_cnt[2]) + strcat(txt_buf, "\n\n#FFDD00 Note:# Yellow entries have USER partition resized."); + + if (!mbr_ctx.available) + strcat(txt_buf, "\n#FF8000 Do you want to partition the SD card?#\n" + "#FF8000 (You will be asked on how to proceed)#"); lv_mbox_set_text(mbox, txt_buf); free(txt_buf); free(mbr); - if (part_idx) - lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_raw_action); + if (mbr_ctx.available) + { + // Check available partitions and enable the corresponding buttons. + if (mbr_ctx.available & 1) + mbox_btn_parts[0][0] = '\222'; + else + mbox_btn_parts[0][0] = '\262'; + if (mbr_ctx.available & 2) + mbox_btn_parts[1][0] = '\222'; + else + mbox_btn_parts[1][0] = '\262'; + if (mbr_ctx.available & 4) + mbox_btn_parts[2][0] = '\222'; + else + mbox_btn_parts[2][0] = '\262'; + + lv_mbox_add_btns(mbox, (const char **)mbox_btn_parts, _create_emummc_raw_action); + } else - lv_mbox_add_btns(mbox, mbox_btn_map2, mbox_action); + lv_mbox_add_btns(mbox, mbox_btn_format, _create_emummc_raw_format); lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_set_top(mbox, true); @@ -225,8 +314,8 @@ static lv_res_t _create_emummc_action(lv_obj_t * btns, const char * txt) int btn_idx = lv_btnm_get_pressed(btns); lv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns)); - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; switch (btn_idx) { @@ -236,7 +325,6 @@ static lv_res_t _create_emummc_action(lv_obj_t * btns, const char * txt) break; case 1: _create_mbox_emummc_raw(); - // if available. have max 3 buttons. if selected and used, ask to use the backup tool. break; } @@ -247,6 +335,9 @@ static lv_res_t _create_emummc_action(lv_obj_t * btns, const char * txt) static lv_res_t _create_mbox_emummc_create(lv_obj_t *btn) { + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); @@ -259,7 +350,7 @@ static lv_res_t _create_mbox_emummc_create(lv_obj_t *btn) lv_mbox_set_text(mbox, "Welcome to #C7EA46 emuMMC# creation tool!\n\n" "Please choose what type of emuMMC you want to create.\n" - "#FF8000 SD File# is saved as files in your FAT partition.\n" + "#FF8000 SD File# is saved as files in the FAT partition.\n" "#FF8000 SD Partition# is saved as raw image in an available partition."); lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_action); @@ -272,16 +363,48 @@ static lv_res_t _create_mbox_emummc_create(lv_obj_t *btn) static void _change_raw_emummc_part_type() { - u8 *mbr = (u8 *)malloc(0x200); + mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t)); sdmmc_storage_read(&sd_storage, 0, 1, mbr); - mbr[MBR_1ST_PART_TYPE_OFF + (0x10 * part_idx)] = 0xE0; + mbr->partitions[mbr_ctx.part_idx].type = 0xE0; sdmmc_storage_write(&sd_storage, 0, 1, mbr); free(mbr); } +static lv_res_t _save_emummc_cfg_mig_mbox_action(lv_obj_t *btns, const char *txt) +{ + // Delete main emuMMC and popup windows and relaunch main emuMMC window. + lv_obj_del(emummc_manage_window); + mbox_action(btns, txt); + + (*emummc_tools)(NULL); + + return LV_RES_INV; +} + +static void _create_emummc_migrated_mbox() +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 4); + + lv_mbox_set_text(mbox, + "#FF8000 emuMMC Configuration#\n\n" + "#96FF00 The emuMMC configuration#\n#96FF00 was saved to sd card!#"); + + lv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mig_mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); +} + static void _migrate_sd_raw_based() { - sector_start = 2; + mbr_ctx.sector_start = 2; sd_mount(); f_mkdir("emuMMC"); @@ -290,17 +413,18 @@ static void _migrate_sd_raw_based() f_rename("Emutendo", "emuMMC/ER00/Nintendo"); FIL fp; f_open(&fp, "emuMMC/ER00/raw_based", FA_CREATE_ALWAYS | FA_WRITE); - f_write(&fp, §or_start, 4, NULL); + f_write(&fp, &mbr_ctx.sector_start, 4, NULL); f_close(&fp); - save_emummc_cfg(1, sector_start, "emuMMC/ER00"); - sd_unmount(false); + save_emummc_cfg(1, mbr_ctx.sector_start, "emuMMC/ER00"); + _create_emummc_migrated_mbox(); + sd_unmount(); } static void _migrate_sd_raw_emummc_based() { char *tmp = (char *)malloc(0x80); - s_printf(tmp, "emuMMC/RAW%d", part_idx); + s_printf(tmp, "emuMMC/RAW%d", mbr_ctx.part_idx); sd_mount(); f_mkdir("emuMMC"); @@ -310,19 +434,19 @@ static void _migrate_sd_raw_emummc_based() FIL fp; if (!f_open(&fp, tmp, FA_CREATE_ALWAYS | FA_WRITE)) { - f_write(&fp, §or_start, 4, NULL); + f_write(&fp, &mbr_ctx.sector_start, 4, NULL); f_close(&fp); } - s_printf(tmp, "emuMMC/RAW%d", part_idx); + s_printf(tmp, "emuMMC/RAW%d", mbr_ctx.part_idx); _change_raw_emummc_part_type(); - save_emummc_cfg(part_idx, sector_start, tmp); - + save_emummc_cfg(mbr_ctx.part_idx, mbr_ctx.sector_start, tmp); + _create_emummc_migrated_mbox(); free(tmp); - sd_unmount(false); + sd_unmount(); } static void _migrate_sd_file_based() @@ -358,57 +482,88 @@ static void _migrate_sd_file_based() free(path2); save_emummc_cfg(0, 0, "emuMMC/EF00"); - sd_unmount(false); + _create_emummc_migrated_mbox(); + sd_unmount(); } static void _migrate_sd_backup_file_based() { + char *emu_path = (char *)malloc(128); + char *parts_path = (char *)malloc(128); + char *backup_path = (char *)malloc(128); + char *backup_file_path = (char *)malloc(128); + sd_mount(); f_mkdir("emuMMC"); - f_mkdir("emuMMC/BK00"); - f_mkdir("emuMMC/BK00/eMMC"); + + strcpy(emu_path, "emuMMC/BK"); + u32 base_len = strlen(emu_path); + + for (int j = 0; j < 100; j++) + { + update_emummc_base_folder(emu_path, base_len, j); + if (f_stat(emu_path, NULL) == FR_NO_FILE) + break; + } + base_len = strlen(emu_path); + + f_mkdir(emu_path); + strcat(emu_path, "/eMMC"); + f_mkdir(emu_path); FIL fp; + // Create file based flag. + strcpy(emu_path + base_len, "/file_based"); f_open(&fp, "emuMMC/BK00/file_based", FA_CREATE_ALWAYS | FA_WRITE); f_close(&fp); - char *path = (char *)malloc(128); - char *path2 = (char *)malloc(128); - char *path3 = (char *)malloc(128); + if (!emummc_backup) + emmcsn_path_impl(backup_path, "", "", NULL); + else + emmcsn_path_impl(backup_path, "/emummc", "", NULL); - emmcsn_path_impl(path, "", "", NULL); + // Move BOOT0. + s_printf(backup_file_path, "%s/BOOT0", backup_path); + strcpy(emu_path + base_len, "/eMMC/BOOT0"); + f_rename(backup_file_path, emu_path); - s_printf(path2, "%s/BOOT0", path); - f_rename(path2, "emuMMC/BK00/eMMC/BOOT0"); - - s_printf(path2, "%s/BOOT1", path); - f_rename(path2, "emuMMC/BK00/eMMC/BOOT1"); + // Move BOOT1. + s_printf(backup_file_path, "%s/BOOT1", backup_path); + strcpy(emu_path + base_len, "/eMMC/BOOT1"); + f_rename(backup_file_path, emu_path); + // Move raw GPP. bool multipart = false; - s_printf(path2, "%s/rawnand.bin", path); + s_printf(backup_file_path, "%s/rawnand.bin", backup_path); - if(f_stat(path2, NULL)) + if (f_stat(backup_file_path, NULL)) multipart = true; if (!multipart) - f_rename(path2, "emuMMC/BK00/eMMC/00"); + { + strcpy(emu_path + base_len, "/eMMC/00"); + f_rename(backup_file_path, emu_path); + } else { + emu_path[base_len] = 0; for (int i = 0; i < 32; i++) { - s_printf(path2, "%s/rawnand.bin.%02d", path, i); - s_printf(path3, "emuMMC/BK00/eMMC/%02d", i); - if (f_rename(path2, path3)) + s_printf(backup_file_path, "%s/rawnand.bin.%02d", backup_path, i); + s_printf(parts_path, "%s/eMMC/%02d", emu_path, i); + if (f_rename(backup_file_path, parts_path)) break; } } - free(path); - free(path2); - free(path3); + free(emu_path); + free(parts_path); + free(backup_path); + free(backup_file_path); save_emummc_cfg(0, 0, "emuMMC/BK00"); - sd_unmount(false); + _create_emummc_migrated_mbox(); + sd_unmount(); } static lv_res_t _create_emummc_mig1_action(lv_obj_t * btns, const char * txt) @@ -423,8 +578,8 @@ static lv_res_t _create_emummc_mig1_action(lv_obj_t * btns, const char * txt) break; } - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; mbox_action(btns, txt); @@ -440,8 +595,8 @@ static lv_res_t _create_emummc_mig0_action(lv_obj_t * btns, const char * txt) break; } - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; mbox_action(btns, txt); @@ -457,8 +612,8 @@ static lv_res_t _create_emummc_mig2_action(lv_obj_t * btns, const char * txt) break; } - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; mbox_action(btns, txt); @@ -474,8 +629,8 @@ static lv_res_t _create_emummc_mig3_action(lv_obj_t * btns, const char * txt) break; } - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; mbox_action(btns, txt); @@ -491,164 +646,109 @@ static lv_res_t _create_emummc_mig4_action(lv_obj_t * btns, const char * txt) break; } - part_idx = 0; - sector_start = 0; + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; mbox_action(btns, txt); return LV_RES_INV; } -static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn) +bool em_raw; +bool em_file; +static lv_res_t _create_emummc_migrate_action(lv_obj_t * btns, const char * txt) { + bool backup = false; + bool emummc = false; + + switch (lv_btnm_get_pressed(btns)) + { + case 0: + backup = true; + break; + case 1: + emummc = true; + break; + case 2: + break; + case 3: + mbox_action(btns, txt); + return LV_RES_INV; + } + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" }; static const char *mbox_btn_map1[] = { "\222SD File", "\222SD Partition", "\222Cancel", "" }; - static const char *mbox_btn_map3[] = { "\211", "OK", "\211", "" }; + static const char *mbox_btn_map3[] = { "\251", "OK", "\251", "" }; lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); - char *txt_buf = (char *)malloc(0x500); - u8 *mbr = (u8 *)malloc(0x200); - u8 *efi_part = (u8 *)malloc(0x200); - - sd_mount(); - sdmmc_storage_read(&sd_storage, 0, 1, mbr); - - memcpy(mbr, mbr + 0x1BE, 0x40); - - sdmmc_storage_t storage; - sdmmc_t sdmmc; - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); - - bool backup = false; - bool emummc = false; - bool file_based = false; - bool em = false; - sector_start = 0; - part_idx = 0; - - for (int i = 1; i < 4; i++) - { - sector_start = *(u32 *)&mbr[0x08 + (0x10 * i)]; - if (sector_start) - { - sdmmc_storage_read(&sd_storage, sector_start + 0xC001, 1, efi_part); - if (!memcmp(efi_part, "EFI PART", 8)) - { - sector_start += 0x8000; - emummc = true; - part_idx = i; - break; - } - else - { - sdmmc_storage_read(&sd_storage, sector_start + 0x4001, 1, efi_part); - if (!memcmp(efi_part, "EFI PART", 8)) - { - emummc = true; - part_idx = i; - break; - } - } - } - } - - //! TODO: What about unallocated - - if (!part_idx) - { - sdmmc_storage_read(&sd_storage, 0x4003, 1, efi_part); - if (!memcmp(efi_part, "EFI PART", 8)) - em = true; - } - - s_printf(txt_buf, "%c%c%c%c%s", 's', 'x', 'o','s', "/emunand/boot0.bin"); - - if(!f_stat(txt_buf, NULL)) - file_based = true; - - bool rawnand_backup_found = false; - - emmcsn_path_impl(txt_buf, "", "BOOT0", &storage); - if(!f_stat(txt_buf, NULL)) - backup = true; - - emmcsn_path_impl(txt_buf, "", "rawnand.bin", &storage); - if(!f_stat(txt_buf, NULL)) - rawnand_backup_found = true; - - emmcsn_path_impl(txt_buf, "", "rawnand.bin.00", &storage); - if(!f_stat(txt_buf, NULL)) - rawnand_backup_found = true; - - if (backup && rawnand_backup_found) - backup = true; - else - backup = false; - - sd_unmount(false); - sdmmc_storage_end(&storage); + char *txt_buf = (char *)malloc(SZ_16K); if (backup) { - s_printf(txt_buf, - "#C7EA46 Found suitable backup for emuMMC!#\n" - "#FF8000 Do you want to migrate it?#\n\n"); + if (!emummc_backup) + s_printf(txt_buf, + "#C7EA46 Found suitable eMMC backup!#\n\n" + "#FF8000 Do you want to migrate it?#\n"); + else + s_printf(txt_buf, + "#C7EA46 Found suitable emuMMC backup!#\n\n" + "#FF8000 Do you want to migrate it?#\n"); lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig4_action); } else if (emummc) { s_printf(txt_buf, - "#C7EA46 Found SD Partition based emuMMC!#\n" - "#FF8000 Do you want to repair the config for it?#\n\n"); + "#C7EA46 Found SD Partition based emuMMC!#\n\n" + "#FF8000 Do you want to repair the config and partition type for it?#\n"); lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig3_action); } - else if (em && !file_based) + else if (em_raw && em_file) { s_printf(txt_buf, - "#C7EA46 Found foreign SD Partition emunand!#\n" - "#FF8000 Do you want to migrate it?#\n\n"); + "#C7EA46 Found both foreign SD File and Partition emunand!#\n\n" + "#FF8000 Choose what to migrate:#\n"); + lv_mbox_add_btns(mbox, mbox_btn_map1, _create_emummc_mig1_action); + } + else if (em_raw) + { + s_printf(txt_buf, + "#C7EA46 Found foreign SD Partition emunand!#\n\n" + "#FF8000 Do you want to migrate it?#\n"); lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig2_action); } - else if (!em && file_based) + else if (em_file) { s_printf(txt_buf, - "#C7EA46 Found foreign SD File emunand!#\n" - "#FF8000 Do you want to migrate it?#\n\n"); + "#C7EA46 Found foreign SD File emunand!#\n\n" + "#FF8000 Do you want to migrate it?#\n"); lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig0_action); } - else if (em && file_based) - { - s_printf(txt_buf, - "#C7EA46 Found both foreign SD File and Partition emunand!#\n" - "#FF8000 Choose what to migrate:#\n\n"); - lv_mbox_add_btns(mbox, mbox_btn_map1, _create_emummc_mig1_action); - } else { - s_printf(txt_buf, "No emuMMC or foreign emunand found!\n\n"); + s_printf(txt_buf, "No emuMMC or foreign emunand found!\n"); lv_mbox_add_btns(mbox, mbox_btn_map3, mbox_action); } lv_mbox_set_text(mbox, txt_buf); free(txt_buf); - free(mbr); - free(efi_part); lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_set_top(mbox, true); - return LV_RES_OK; + mbox_action(btns, txt); + + return LV_RES_INV; } typedef struct _emummc_images_t { - char *dirlist; + dirlist_t *dirlist; u32 part_sector[3]; u32 part_type[3]; u32 part_end[3]; @@ -656,14 +756,150 @@ typedef struct _emummc_images_t lv_obj_t *win; } emummc_images_t; +static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static char *mbox_btn_map[] = { "\262Backup", "\262Fix RAW", "\262Emunand", "\222Cancel", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, + "Welcome to #C7EA46 emuMMC# migration tool!\n\n" + "Please choose what type of migration you want to do.\n" + "Anything that was not found will have the button disabled."); + + char *path_buf = (char *)malloc(0x512); + mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t)); + u8 *efi_part = (u8 *)malloc(0x200); + + sd_mount(); + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + + emmc_initialize(false); + + em_raw = false; + em_file = false; + bool backup = false; + bool emummc = false; + bool rawnand_backup = false; + + mbr_ctx.sector_start = 0; + mbr_ctx.part_idx = 0; + + // Try to find a partition based emuMMC. + for (int i = 1; i < 4; i++) + { + mbr_ctx.sector_start = mbr->partitions[i].start_sct; + + if (!mbr_ctx.sector_start) + continue; + + sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0xC001, 1, efi_part); + if (!memcmp(efi_part, "EFI PART", 8)) + { + mbr_ctx.sector_start += 0x8000; + emummc = true; + mbr_ctx.part_idx = i; + break; + } + else + { + sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0x4001, 1, efi_part); + if (!memcmp(efi_part, "EFI PART", 8)) + { + emummc = true; + mbr_ctx.part_idx = i; + break; + } + } + } + + if (!mbr_ctx.part_idx) + { + sdmmc_storage_read(&sd_storage, 0x4003, 1, efi_part); + if (!memcmp(efi_part, "EFI PART", 8)) + em_raw = true; + } + + s_printf(path_buf, "%c%c%c%c%s", 's', 'x', 'o','s', "/emunand/boot0.bin"); + + if (!f_stat(path_buf, NULL)) + em_file = true; + + emummc_backup = false; + + emmcsn_path_impl(path_buf, "", "BOOT0", &emmc_storage); + if (!f_stat(path_buf, NULL)) + backup = true; + + emmcsn_path_impl(path_buf, "", "rawnand.bin", &emmc_storage); + if (!f_stat(path_buf, NULL)) + rawnand_backup = true; + + emmcsn_path_impl(path_buf, "", "rawnand.bin.00", &emmc_storage); + if (!f_stat(path_buf, NULL)) + rawnand_backup = true; + + backup = backup && rawnand_backup; + + if (!backup) + { + rawnand_backup = false; + emummc_backup = true; + + emmcsn_path_impl(path_buf, "/emummc", "BOOT0", &emmc_storage); + if (!f_stat(path_buf, NULL)) + backup = true; + + emmcsn_path_impl(path_buf, "/emummc", "rawnand.bin", &emmc_storage); + if (!f_stat(path_buf, NULL)) + rawnand_backup = true; + + emmcsn_path_impl(path_buf, "/emummc", "rawnand.bin.00", &emmc_storage); + if (!f_stat(path_buf, NULL)) + rawnand_backup = true; + + backup = backup && rawnand_backup; + } + + sd_unmount(); + emmc_end(); + + // Check available types and enable the corresponding buttons. + if (backup) + mbox_btn_map[0][0] = '\222'; + else + mbox_btn_map[0][0] = '\262'; + if (emummc) + mbox_btn_map[1][0] = '\222'; + else + mbox_btn_map[1][0] = '\262'; + if (em_raw || em_file) + mbox_btn_map[2][0] = '\222'; + else + mbox_btn_map[2][0] = '\262'; + + free(path_buf); + free(mbr); + free(efi_part); + + lv_mbox_add_btns(mbox, (const char **)mbox_btn_map, _create_emummc_migrate_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + static emummc_images_t *emummc_img; -static lv_obj_t *emummc_manage_window; - -static lv_res_t (*emummc_tools)(lv_obj_t *btn); - static lv_res_t _save_emummc_cfg_mbox_action(lv_obj_t *btns, const char *txt) { + // Free components, delete main emuMMC and popup windows and relaunch main emuMMC window. free(emummc_img->dirlist); lv_obj_del(emummc_img->win); lv_obj_del(emummc_manage_window); @@ -682,7 +918,7 @@ static void _create_emummc_saved_mbox() lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char *mbox_btn_map[] = { "\211", "OK", "\211", "" }; + static const char *mbox_btn_map[] = { "\251", "OK", "\251", "" }; lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES / 9 * 4); @@ -714,7 +950,7 @@ static lv_res_t _save_raw_emummc_cfg_action(lv_obj_t * btn) } _create_emummc_saved_mbox(); - sd_unmount(false); + sd_unmount(); return LV_RES_INV; } @@ -723,7 +959,7 @@ static lv_res_t _save_disable_emummc_cfg_action(lv_obj_t * btn) { save_emummc_cfg(0, 0, NULL); _create_emummc_saved_mbox(); - sd_unmount(false); + sd_unmount(); return LV_RES_INV; } @@ -732,12 +968,12 @@ static lv_res_t _save_file_emummc_cfg_action(lv_obj_t *btn) { save_emummc_cfg(0, 0, lv_list_get_btn_text(btn)); _create_emummc_saved_mbox(); - sd_unmount(false); + sd_unmount(); return LV_RES_INV; } -static lv_res_t _create_change_emummc_window() +static lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller) { lv_obj_t *win = nyx_create_standard_window(SYMBOL_SETTINGS" Change emuMMC"); lv_win_add_btn(win, NULL, SYMBOL_POWER" Disable", _save_disable_emummc_cfg_action); @@ -747,19 +983,18 @@ static lv_res_t _create_change_emummc_window() emummc_img = malloc(sizeof(emummc_images_t)); emummc_img->win = win; - u8 *mbr = (u8 *)malloc(0x200); - char *path = malloc(256); + mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t)); + char *path = malloc(512); sdmmc_storage_read(&sd_storage, 0, 1, mbr); - memcpy(mbr, mbr + 0x1BE, 0x40); memset(emummc_img->part_path, 0, 3 * 128); for (int i = 1; i < 4; i++) { - emummc_img->part_sector[i - 1] = *(u32 *)&mbr[0x08 + (0x10 * i)]; - emummc_img->part_end[i - 1] = emummc_img->part_sector[i - 1] + *(u32 *)&mbr[0x0C + (0x10 * i)] - 1; - emummc_img->part_type[i - 1] = mbr[0x04 + (0x10 * i)]; + emummc_img->part_sector[i - 1] = mbr->partitions[i].start_sct; + emummc_img->part_end[i - 1] = emummc_img->part_sector[i - 1] + mbr->partitions[i].size_sct - 1; + emummc_img->part_type[i - 1] = mbr->partitions[i].type; } free(mbr); @@ -773,11 +1008,11 @@ static lv_res_t _create_change_emummc_window() FIL fp; // Check for sd raw partitions, based on the folders in /emuMMC. - while (emummc_img->dirlist[emummc_idx * 256]) + while (emummc_img->dirlist->name[emummc_idx]) { - s_printf(path, "emuMMC/%s/raw_based", &emummc_img->dirlist[emummc_idx * 256]); + s_printf(path, "emuMMC/%s/raw_based", emummc_img->dirlist->name[emummc_idx]); - if(!f_stat(path, NULL)) + if (!f_stat(path, NULL)) { f_open(&fp, path, FA_READ); u32 curr_list_sector = 0; @@ -788,21 +1023,21 @@ static lv_res_t _create_change_emummc_window() if ((curr_list_sector == 2) || (emummc_img->part_sector[0] && curr_list_sector >= emummc_img->part_sector[0] && curr_list_sector < emummc_img->part_end[0] && emummc_img->part_type[0] != 0x83)) { - s_printf(&emummc_img->part_path[0], "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]); + s_printf(&emummc_img->part_path[0], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]); emummc_img->part_sector[0] = curr_list_sector; emummc_img->part_end[0] = 0; } else if (emummc_img->part_sector[1] && curr_list_sector >= emummc_img->part_sector[1] && curr_list_sector < emummc_img->part_end[1] && emummc_img->part_type[1] != 0x83) { - s_printf(&emummc_img->part_path[1 * 128], "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]); + s_printf(&emummc_img->part_path[1 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]); emummc_img->part_sector[1] = curr_list_sector; emummc_img->part_end[1] = 0; } else if (emummc_img->part_sector[2] && curr_list_sector >= emummc_img->part_sector[2] && curr_list_sector < emummc_img->part_end[2] && emummc_img->part_type[2] != 0x83) { - s_printf(&emummc_img->part_path[2 * 128], "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]); + s_printf(&emummc_img->part_path[2 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]); emummc_img->part_sector[2] = curr_list_sector; emummc_img->part_end[2] = 0; } @@ -814,19 +1049,19 @@ static lv_res_t _create_change_emummc_window() u32 file_based_idx = 0; // Sanitize the directory list with sd file based ones. - while (emummc_img->dirlist[emummc_idx * 256]) + while (emummc_img->dirlist->name[emummc_idx]) { - s_printf(path, "emuMMC/%s/file_based", &emummc_img->dirlist[emummc_idx * 256]); + s_printf(path, "emuMMC/%s/file_based", emummc_img->dirlist->name[emummc_idx]); - if(!f_stat(path, NULL)) + if (!f_stat(path, NULL)) { - char *tmp = &emummc_img->dirlist[emummc_idx * 256]; - memcpy(&emummc_img->dirlist[file_based_idx * 256], tmp, strlen(tmp) + 1); + char *tmp = emummc_img->dirlist->name[emummc_idx]; + memcpy(emummc_img->dirlist->name[file_based_idx], tmp, strlen(tmp) + 1); file_based_idx++; } emummc_idx++; } - emummc_img->dirlist[file_based_idx * 256] = 0; + emummc_img->dirlist->name[file_based_idx] = NULL; out0:; static lv_style_t h_style; @@ -861,7 +1096,7 @@ out0:; lv_btn_ext_t *ext; lv_obj_t *btn_label = NULL; lv_obj_t *lv_desc = NULL; - char *txt_buf = malloc(0x500); + char *txt_buf = malloc(SZ_16K); // Create RAW buttons. for (u32 raw_btn_idx = 0; raw_btn_idx < 3; raw_btn_idx++) @@ -877,7 +1112,7 @@ out0:; if (emummc_img->part_type[raw_btn_idx] != 0x83) { s_printf(txt_buf, "SD RAW %d", raw_btn_idx + 1); - lv_label_set_array_text(btn_label, txt_buf, 32); + lv_label_set_text(btn_label, txt_buf); } if (!emummc_img->part_sector[raw_btn_idx] || emummc_img->part_type[raw_btn_idx] == 0x83 || !emummc_img->part_path[raw_btn_idx * 128]) @@ -905,9 +1140,10 @@ out0:; lv_obj_set_style(lv_desc, &hint_small_style); s_printf(txt_buf, "Sector start: 0x%08X\nFolder: %s", emummc_img->part_sector[raw_btn_idx], &emummc_img->part_path[raw_btn_idx * 128]); - lv_label_set_array_text(lv_desc, txt_buf, 0x500); + lv_label_set_text(lv_desc, txt_buf); lv_obj_align(lv_desc, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5); } + free(txt_buf); // Create SD File Based container. lv_obj_t *h2 = lv_cont_create(win, NULL); @@ -942,9 +1178,9 @@ out0:; emummc_idx = 0; // Add file based to the list. - while (emummc_img->dirlist[emummc_idx * 256]) + while (emummc_img->dirlist->name[emummc_idx]) { - s_printf(path, "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]); + s_printf(path, "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]); lv_list_add(list_sd_based, NULL, path, _save_file_emummc_cfg_action); @@ -953,7 +1189,7 @@ out0:; out1: free(path); - sd_unmount(false); + sd_unmount(); return LV_RES_OK; } @@ -961,56 +1197,17 @@ out1: lv_res_t create_win_emummc_tools(lv_obj_t *btn) { lv_obj_t *win = nyx_create_standard_window(SYMBOL_EDIT" emuMMC Manage"); + + // Set resources to be managed by other windows. emummc_manage_window = win; - emummc_tools = (void *)create_win_emummc_tools; - typedef struct _emummc_cfg_t - { - int enabled; - u32 sector; - u16 id; - char *path; - char *nintendo_path; - } emummc_cfg_t; - - emummc_cfg_t emu_info; - sd_mount(); - emu_info.enabled = 0; - emu_info.sector = 0; - emu_info.id = 0; - emu_info.path = NULL; - emu_info.nintendo_path = NULL; + emummc_cfg_t emu_info; + load_emummc_cfg(&emu_info); - //! TODO: Always update that info when something was changed. - // Parse emuMMC configuration. - LIST_INIT(ini_sections); - if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) - { - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - if (!strcmp(ini_sec->name, "emummc")) - { - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - if (!strcmp("enabled", kv->key)) - emu_info.enabled = atoi(kv->val); - else if (!strcmp("sector", kv->key)) - emu_info.sector = strtol(kv->val, NULL, 16); - else if (!strcmp("id", kv->key)) - emu_info.id = strtol(kv->val, NULL, 16); - else if (!strcmp("path", kv->key)) - emu_info.path = kv->val; - else if (!strcmp("nintendo_path", kv->key)) - emu_info.nintendo_path = kv->val; - } - } - } - } - - sd_unmount(false); + sd_unmount(); static lv_style_t h_style; lv_style_copy(&h_style, &lv_style_transp); @@ -1048,7 +1245,7 @@ lv_res_t create_win_emummc_tools(lv_obj_t *btn) lv_obj_t *label_txt2 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt2, true); - char *txt_buf = (char *)malloc(0x200); + char *txt_buf = (char *)malloc(SZ_16K); if (emu_info.enabled) { @@ -1059,13 +1256,17 @@ lv_res_t create_win_emummc_tools(lv_obj_t *btn) s_printf(txt_buf, "#00DDFF Type:# SD File\n#00DDFF Base folder:# %s\n#00DDFF Nintendo folder:# %s", emu_info.path ? emu_info.path : "", emu_info.nintendo_path ? emu_info.nintendo_path : ""); - lv_label_set_array_text(label_txt2, txt_buf, 0x200); + lv_label_set_text(label_txt2, txt_buf); } else { lv_label_set_static_text(label_txt2, "emuMMC is disabled and eMMC will be used for boot.\n\n"); } + if (emu_info.path) + free(emu_info.path); + if (emu_info.nintendo_path) + free(emu_info.nintendo_path); free(txt_buf); lv_obj_set_style(label_txt2, &hint_small_style); @@ -1126,7 +1327,6 @@ lv_res_t create_win_emummc_tools(lv_obj_t *btn) lv_obj_set_style(label_txt4, &hint_small_style); lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); - //! TODO: Move it to a window with multiple choices. // Create Migrate emuMMC button. lv_obj_t *btn4 = lv_btn_create(h2, btn2); label_btn = lv_label_create(btn4, NULL); @@ -1140,8 +1340,6 @@ lv_res_t create_win_emummc_tools(lv_obj_t *btn) lv_label_set_static_text(label_txt4, "Migrate a backup to a #C7EA46 SD File# or repair existing #C7EA46 SD Raw Partition#.\n" "Additionally it allows you to migrate from other emunand\nsolutions."); - //"Move between #C7EA46 SD File# and #C7EA46 SD Raw Partition# emuMMC.\n" - //"Additionally it allows you to migrate from other emunand\nsolutions."); lv_obj_set_style(label_txt4, &hint_small_style); lv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); diff --git a/nyx/nyx_gui/frontend/gui_emummc_tools.h b/nyx/nyx_gui/frontend/gui_emummc_tools.h index 84cdb6d..d25bb32 100644 --- a/nyx/nyx_gui/frontend/gui_emummc_tools.h +++ b/nyx/nyx_gui/frontend/gui_emummc_tools.h @@ -17,7 +17,7 @@ #ifndef _GUI_EMUMMC_TOOLS_H_ #define _GUI_EMUMMC_TOOLS_H_ -#include "../libs/lvgl/lvgl.h" +#include lv_res_t create_win_emummc_tools(lv_obj_t *btn); diff --git a/nyx/nyx_gui/frontend/gui_info.c b/nyx/nyx_gui/frontend/gui_info.c index 4826eec..d7351ab 100644 --- a/nyx/nyx_gui/frontend/gui_info.c +++ b/nyx/nyx_gui/frontend/gui_info.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -16,60 +16,47 @@ * along with this program. If not, see . */ +#include + #include "gui.h" +#include "../config.h" #include "../hos/hos.h" #include "../hos/pkg1.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../power/bq24193.h" -#include "../power/max17050.h" -#include "../sec/tsec.h" -#include "../soc/fuse.h" -#include "../soc/kfuse.h" -#include "../soc/i2c.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../storage/mmc.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" +#include + +#include #define SECTORS_TO_MIB_COEFF 11 -extern sdmmc_storage_t sd_storage; -extern FATFS sd_fs; +extern hekate_config h_cfg; +extern volatile boot_cfg_t *b_cfg; +extern volatile nyx_storage_t *nyx_str; -extern bool sd_mount(); -extern void sd_unmount(bool deinit); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); +extern lv_res_t launch_payload(lv_obj_t *list); +extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); static lv_res_t _create_window_dump_done(int error, char *dump_filenames) { - lv_style_t *darken; - darken = (lv_style_t *)malloc(sizeof(lv_style_t)); - lv_style_copy(darken, &lv_style_plain); - darken->body.main_color = LV_COLOR_BLACK; - darken->body.grad_color = darken->body.main_color; - darken->body.opa = LV_OPA_30; - lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); - lv_obj_set_style(dark_bg, darken); + lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char * mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_4K); if (error) s_printf(txt_buf, "#FFDD00 Failed to dump to# %s#FFDD00 !#\nError: %d", dump_filenames, error); else - s_printf(txt_buf, "Dumping to SD card finished!\nFiles: #C7EA46 backup/{emmc_sn}/dumps/#%s", dump_filenames); + { + char *sn = emmcsn_path_impl(NULL, NULL, NULL, NULL); + s_printf(txt_buf, "Dumping to SD card finished!\nFiles: #C7EA46 backup/%s/dumps/#\n%s", sn, dump_filenames); + } lv_mbox_set_text(mbox, txt_buf); + free(txt_buf); lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text. @@ -79,6 +66,32 @@ static lv_res_t _create_window_dump_done(int error, char *dump_filenames) return LV_RES_OK; } +static lv_res_t _cal0_dump_window_action(lv_obj_t *btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + mbox_action(btns, txt); + + if (btn_idx == 1) + { + int error = !sd_mount(); + + if (!error) + { + char path[64]; + emmcsn_path_impl(path, "/dumps", "cal0.bin", NULL); + error = sd_save_to_file((u8 *)cal0_buf, SZ_32K, path); + + sd_unmount(); + } + + _create_window_dump_done(error, "cal0.bin"); + } + + return LV_RES_INV; +} + + static lv_res_t _battery_dump_window_action(lv_obj_t * btn) { int error = !sd_mount(); @@ -86,30 +99,14 @@ static lv_res_t _battery_dump_window_action(lv_obj_t * btn) if (!error) { char path[64]; - u8 *buf = (u8 *)malloc(0x100 * 2); + void *buf = malloc(0x100 * 2); - // Unlock model table. - u16 unlock = 0x59; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2); - unlock = 0xC4; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2); - - // Dump all battery fuel gauge registers. - for (int i = 0; i < 0x200; i += 2) - { - i2c_recv_buf_small(buf + i, 2, I2C_1, MAXIM17050_I2C_ADDR, i >> 1); - msleep(1); - } - - // Lock model table. - unlock = 0; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2); - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2); + max17050_dump_regs(buf); emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL); error = sd_save_to_file((u8 *)buf, 0x200, path); - sd_unmount(false); + sd_unmount(); } _create_window_dump_done(error, "fuel_gauge.bin"); @@ -137,48 +134,67 @@ static lv_res_t _bootrom_dump_window_action(lv_obj_t * btn) error = 255; emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL); - int res = sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path); + int res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path); if (!error) error = res; - u32 ipatch_backup[14]; - memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup)); - memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup)); + u32 ipatch_cam[IPATCH_CAM_ENTRIES + 1]; + memcpy(ipatch_cam, (void *)IPATCH_BASE, sizeof(ipatch_cam)); + memset((void*)IPATCH_BASE, 0, sizeof(ipatch_cam)); // Zeroing valid entries is enough but zero everything. emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL); - res = sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path); + res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path); if (!error) error = res; - memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup)); + memcpy((void*)IPATCH_BASE, ipatch_cam, sizeof(ipatch_cam)); - sd_unmount(false); + sd_unmount(); } _create_window_dump_done(error, "evp_thunks.bin, bootrom_patched.bin, bootrom_unpatched.bin"); - return LV_RES_OK; } static lv_res_t _fuse_dump_window_action(lv_obj_t * btn) { + const u32 fuse_array_size = (h_cfg.t210b01 ? FUSE_ARRAY_WORDS_NUM_B01 : FUSE_ARRAY_WORDS_NUM) * sizeof(u32); + int error = !sd_mount(); if (!error) { - char path[64]; - emmcsn_path_impl(path, "/dumps", "fuse_cached.bin", NULL); - error = sd_save_to_file((u8 *)0x7000F900, 0x300, path); + char path[128]; + if (!h_cfg.t210b01) + { + emmcsn_path_impl(path, "/dumps", "fuse_cached_t210.bin", NULL); + error = sd_save_to_file((u8 *)0x7000F900, 0x300, path); + } + else + { + emmcsn_path_impl(path, "/dumps", "fuse_cached_t210b01_x898.bin", NULL); + error = sd_save_to_file((u8 *)0x7000F898, 0x68, path); + emmcsn_path_impl(path, "/dumps", "fuse_cached_t210b01_x900.bin", NULL); + if (!error) + error = sd_save_to_file((u8 *)0x7000F900, 0x300, path); + } - u32 words[192]; + u32 words[FUSE_ARRAY_WORDS_NUM_B01]; fuse_read_array(words); - emmcsn_path_impl(path, "/dumps", "fuse_array_raw.bin", NULL); - int res = sd_save_to_file((u8 *)words, sizeof(words), path); + if (!h_cfg.t210b01) + emmcsn_path_impl(path, "/dumps", "fuse_array_raw_t210.bin", NULL); + else + emmcsn_path_impl(path, "/dumps", "fuse_array_raw_t210b01.bin", NULL); + int res = sd_save_to_file((u8 *)words, fuse_array_size, path); if (!error) error = res; - sd_unmount(false); + sd_unmount(); } - _create_window_dump_done(error, "fuse_cached.bin, fuse_array_raw.bin"); + + if (!h_cfg.t210b01) + _create_window_dump_done(error, "fuse_cached_t210.bin, fuse_array_raw_t210.bin"); + else + _create_window_dump_done(error, "fuse_cached_t210b01_x*.bin, fuse_array_raw_t210b01.bin"); return LV_RES_OK; } @@ -197,7 +213,7 @@ static lv_res_t _kfuse_dump_window_action(lv_obj_t * btn) emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL); error = sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path); - sd_unmount(false); + sd_unmount(); } _create_window_dump_done(error, "kfuses.bin"); @@ -205,28 +221,155 @@ static lv_res_t _kfuse_dump_window_action(lv_obj_t * btn) return LV_RES_OK; } -static u32 tsec_keys[8]; - -static lv_res_t _tsec_keys_dump_window_action(lv_obj_t * btn) +static lv_res_t _create_mbox_cal0(lv_obj_t *btn) { - int error = !sd_mount(); - if (!error) - { - char path[64]; - emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL); - error = sd_save_to_file(tsec_keys, 0x10 * 2, path); + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - sd_unmount(false); + static const char * mbox_btn_map[] = { "\251", "\222Dump", "\222Close", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + + lv_mbox_set_text(mbox, "#C7EA46 CAL0 Info#"); + + char *txt_buf = (char *)malloc(SZ_16K); + txt_buf[0] = 0; + + lv_obj_t * lb_desc = lv_label_create(mbox, NULL); + lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); + lv_label_set_recolor(lb_desc, true); + lv_label_set_style(lb_desc, &monospace_text); + lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4); + + sd_mount(); + + // Dump CAL0. + int cal0_res = hos_dump_cal0(); + + // Check result. Don't error if hash doesn't match. + if (cal0_res == 1) + { + lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); + + goto out; } - _create_window_dump_done(error, "tsec_keys.bin"); + else if (cal0_res == 2) + { + lv_label_set_text(lb_desc, "#FFDD00 CAL0 is corrupt or wrong keys!#\n"); + goto out; + } + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf; + + u32 hash[8]; + se_calc_sha256_oneshot(hash, (u8 *)cal0 + 0x40, cal0->body_size); + + s_printf(txt_buf, + "#FF8000 CAL0 Version:# %d\n" + "#FF8000 Update Count:# %d\n" + "#FF8000 Serial Number:# %s\n" + "#FF8000 WLAN MAC:# %02X:%02X:%02X:%02X:%02X:%02X\n" + "#FF8000 Bluetooth MAC:# %02X:%02X:%02X:%02X:%02X:%02X\n" + "#FF8000 Battery LOT:# %s (%d)\n" + "#FF8000 LCD Vendor:# ", + cal0->version, cal0->update_cnt, cal0->serial_number, + cal0->wlan_mac[0], cal0->wlan_mac[1], cal0->wlan_mac[2], cal0->wlan_mac[3], cal0->wlan_mac[4], cal0->wlan_mac[5], + cal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5], + cal0->battery_lot, cal0->battery_ver); + + // Prepare display info. + u32 display_id = (cal0->lcd_vendor & 0xFF) << 8 | (cal0->lcd_vendor & 0xFF0000) >> 16; + switch (display_id) + { + case PANEL_JDI_LAM062M109A: + strcat(txt_buf, "JDI LAM062M109A"); + break; + case PANEL_JDI_LPM062M326A: + strcat(txt_buf, "JDI LPM062M326A"); + break; + case PANEL_INL_P062CCA_AZ1: + strcat(txt_buf, "InnoLux P062CCA-AZX"); + break; + case PANEL_AUO_A062TAN01: + strcat(txt_buf, "AUO A062TAN0X"); + break; + case PANEL_INL_2J055IA_27A: + strcat(txt_buf, "InnoLux 2J055IA-27A"); + break; + case PANEL_AUO_A055TAN01: + strcat(txt_buf, "AUO A055TAN0X"); + break; + case PANEL_SHP_LQ055T1SW10: + strcat(txt_buf, "Sharp LQ055T1SW10"); + break; + case PANEL_SAM_AMS699VC01: + strcat(txt_buf, "Samsung AMS699VC01"); + break; + default: + switch (cal0->lcd_vendor & 0xFF) + { + case 0: + case PANEL_JDI_XXX062M: + strcat(txt_buf, "JDI "); + break; + case (PANEL_INL_P062CCA_AZ1 & 0xFF): + strcat(txt_buf, "InnoLux "); + break; + case (PANEL_AUO_A062TAN01 & 0xFF): + strcat(txt_buf, "AUO "); + break; + case (PANEL_SAM_AMS699VC01 & 0xFF): + strcat(txt_buf, "Samsung "); + break; + } + strcat(txt_buf, "Unknown"); + break; + } + + s_printf(txt_buf + strlen(txt_buf), + " (%06X)\n#FF8000 Touch Vendor:# %d\n" + "#FF8000 IMU Type/Mount:# %d / %d\n" + "#FF8000 Stick L/R Type:# %02X / %02X\n", + cal0->lcd_vendor, cal0->touch_ic_vendor_id, + cal0->console_6axis_sensor_type, cal0->console_6axis_sensor_mount_type, + cal0->analog_stick_type_l, cal0->analog_stick_type_r); + + bool valid_cal0 = !memcmp(hash, cal0->body_sha256, 0x20); + s_printf(txt_buf + strlen(txt_buf), "#FF8000 SHA256 Hash Match:# %s", valid_cal0 ? "Pass" : "Failed"); + + lv_label_set_text(lb_desc, txt_buf); + +out: + free(txt_buf); + sd_unmount(); + + lv_mbox_add_btns(mbox, mbox_btn_map, _cal0_dump_window_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); return LV_RES_OK; } -static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) +static lv_obj_t *hw_info_ver = NULL; +static lv_res_t _action_win_hw_info_status_close(lv_obj_t *btn) { - lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" Cached fuses Info"); + if (hw_info_ver) + { + lv_obj_del(hw_info_ver); + hw_info_ver = NULL; + } + + return nyx_win_close_action_custom(btn); +} + +static lv_res_t _create_window_hw_info_status(lv_obj_t *btn) +{ + lv_obj_t *win = nyx_create_window_custom_close_btn(SYMBOL_CHIP" HW & Fuses Info", _action_win_hw_info_status_close); lv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD" Dump fuses", _fuse_dump_window_action); + lv_win_add_btn(win, NULL, SYMBOL_INFO" CAL0 Info", _create_mbox_cal0); lv_obj_t *desc = lv_cont_create(win, NULL); lv_obj_set_size(desc, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5); @@ -234,19 +377,29 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) lv_obj_t * lb_desc = lv_label_create(desc, NULL); lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); lv_label_set_recolor(lb_desc, true); - lv_ta_set_style(lb_desc, LV_TA_STYLE_BG, &monospace_text); + lv_label_set_style(lb_desc, &monospace_text); + + char version[32]; + s_printf(version, "%s%d.%d.%d%c", NYX_VER_RL ? "v" : "", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF, NYX_VER_RL > 'A' ? NYX_VER_RL : 0); + lv_obj_t * lbl_ver = lv_label_create(lv_scr_act(), NULL); + lv_label_set_style(lbl_ver, &hint_small_style_white); + lv_label_set_text(lbl_ver, version); + lv_obj_align(lbl_ver, status_bar.bar_bg, LV_ALIGN_OUT_TOP_RIGHT, -LV_DPI * 9 / 23, -LV_DPI * 2 / 13); + hw_info_ver = lbl_ver; lv_label_set_static_text(lb_desc, - "#00DDFF Detailed Info:#\n" - "SKU:\n" - "DRAM ID:\n" + "#FF8000 SoC:#\n" + "#FF8000 SKU:#\n" + "#FF8000 DRAM ID:#\n" "#FF8000 Burnt Fuses (ODM 7/6):#\n" - "Secure Boot key (SBK):\n" - "Device key (DK):\n" + "ODM Fields (4, 6, 7):\n" + "Secure Boot Key (SBK):\n" + "Device Key (DK):\n" + "Public Key (PK SHA256):\n\n" + "HOS Keygen Revision:\n" "USB Stack:\n" "Final Test Revision:\n" "Chip Probing Revision:\n" - "Bootrom ipatches size:\n" "CPU Speedo 0 (CPU Val):\n" "CPU Speedo 1:\n" "CPU Speedo 2 (GPU Val):\n" @@ -259,7 +412,6 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) "Vendor Code:\n" "FAB Code:\n" "LOT Code 0:\n" - "LOT Code 1:\n" "Wafer ID:\n" "X Coordinate:\n" "Y Coordinate:" @@ -267,46 +419,213 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); lv_obj_t *val = lv_cont_create(win, NULL); - lv_obj_set_size(val, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5); + lv_obj_set_size(val, LV_HOR_RES / 7 * 2 + LV_DPI / 11, LV_VER_RES - (LV_DPI * 11 / 7) - 5); lv_obj_t * lb_val = lv_label_create(val, lb_desc); - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); // Decode fuses. - u8 burntFuses7 = 0; - u8 burntFuses6 = 0; - u32 odm4 = fuse_read_odm(4); - u8 dram_id = (odm4 >> 3) & 0x1F; - char dram_man[16] = {0}; - switch (dram_id) + char *sku; + char dram_man[64]; + char fuses_hos_version[64]; + u8 dram_id = fuse_read_dramid(true); + + switch (fuse_read_hw_type()) { - case 0: - case 4: - s_printf(dram_man, "Samsung %s", (!dram_id) ? "4GB" : "6GB"); + case FUSE_NX_HW_TYPE_ICOSA: + sku = "Icosa - Odin"; break; - case 1: - strcpy(dram_man, "Hynix 4GB"); + case FUSE_NX_HW_TYPE_IOWA: + sku = "Iowa - Modin"; break; - case 2: - strcpy(dram_man, "Micron 4GB"); + case FUSE_NX_HW_TYPE_HOAG: + sku = "Hoag - Vali"; + break; + case FUSE_NX_HW_TYPE_AULA: + sku = "Aula - Fric"; break; default: - strcpy(dram_man, "Unknown"); + sku = "#FF8000 Unknown#"; break; } - for (u32 i = 0; i < 32; i++) + // Prepare dram id info. + if (!h_cfg.t210b01) { - if ((fuse_read_odm(7) >> i) & 1) - burntFuses7++; + switch (dram_id) + { + // LPDDR4 3200Mbps. + case LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH: + strcpy(dram_man, "Samsung K4F6E304HB-MGCH 4GB"); + break; + case LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE: + strcpy(dram_man, "Hynix H9HCNNNBPUMLHR-NLE 4GB"); + break; + case LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC: + strcpy(dram_man, "Micron MT53B512M32D2NP-062 WT:C"); + break; + case LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH: + strcpy(dram_man, "Samsung K4FHE3D4HM-MGCH 6GB"); + break; + case LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX: + strcpy(dram_man, "Samsung K4FBE3D4HM-MGXX 8GB"); + break; + default: + strcpy(dram_man, "#FF8000 Unknown#"); + break; + } } - for (u32 i = 0; i < 32; i++) + else { - if ((fuse_read_odm(6) >> i) & 1) - burntFuses6++; + switch (dram_id) + { + // LPDDR4X 3733Mbps. + case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ: + case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ: + strcpy(dram_man, "Samsung K4U6E3S4AM-MGCJ 4GB"); + break; + case LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ: + case LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ: + strcpy(dram_man, "Samsung K4UBE3D4AM-MGCJ 8GB"); + break; + case LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME: + case LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME: + strcpy(dram_man, "Hynix H9HCNNNBKMMLHR-NME 4GB"); + break; + case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE: // 4266Mbps. + case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE: // 4266Mbps. + strcpy(dram_man, "Micron MT53E512M32D2NP-046 WT:E"); + break; + + // LPDDR4X 4266Mbps + case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL: + case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL: + case LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL: + strcpy(dram_man, "Samsung K4U6E3S4AA-MGCL 4GB"); + break; + case LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL: + case LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL: + case LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL: + strcpy(dram_man, "Samsung K4UBE3D4AA-MGCL 8GB"); + break; + case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL: + case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL: + case LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL: + strcpy(dram_man, "Samsung K4U6E3S4AB-MGCL 4GB"); + break; + case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF: + case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF: + case LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF: + strcpy(dram_man, "Micron MT53E512M32D2NP-046 WT:F"); + break; + case LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper. + case LPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper. + case LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper. + strcpy(dram_man, "Hynix H9HCNNNBKMMLXR-NEE 4GB"); + break; + case LPDDR4X_IOWA_4GB_HYNIX_H54G46CYRBX267: + case LPDDR4X_HOAG_4GB_HYNIX_H54G46CYRBX267: + case LPDDR4X_AULA_4GB_HYNIX_H54G46CYRBX267: + strcpy(dram_man, "Hynix H54G46CYRBX267 4GB"); + break; + case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB: + case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB: + case LPDDR4X_AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB: + strcpy(dram_man, "Micron MT53E512M32D1NP-046 WT:B"); + break; + + default: + strcpy(dram_man, "#FF8000 Contact me!#"); + break; + } } + // Count burnt fuses. + u8 burnt_fuses_7 = bit_count(fuse_read_odm(7)); + u8 burnt_fuses_6 = bit_count(fuse_read_odm(6)); + + // Check if overburnt. + u8 burnt_fuses_hos = (fuse_read_odm(7) & ~bit_count_mask(burnt_fuses_7)) ? 255 : burnt_fuses_7; + + //! TODO: Update on anti-downgrade fuses change. + switch (burnt_fuses_hos) + { + case 0: + strcpy(fuses_hos_version, "#96FF00 Golden sample#"); + break; + case 1: + strcpy(fuses_hos_version, "1.0.0"); + break; + case 2: + strcpy(fuses_hos_version, "2.0.0 - 2.3.0"); + break; + case 3: + strcpy(fuses_hos_version, "3.0.0"); + break; + case 4: + strcpy(fuses_hos_version, "3.0.1 - 3.0.2"); + break; + case 5: + strcpy(fuses_hos_version, "4.0.0 - 4.1.0"); + break; + case 6: + strcpy(fuses_hos_version, "5.0.0 - 5.1.0"); + break; + case 7: + strcpy(fuses_hos_version, "6.0.0 - 6.1.0"); + break; + case 8: + strcpy(fuses_hos_version, "6.2.0"); + break; + case 9: + strcpy(fuses_hos_version, "7.0.0 - 8.0.1"); + break; + case 10: + strcpy(fuses_hos_version, "8.1.0 - 8.1.1"); + break; + case 11: + strcpy(fuses_hos_version, "9.0.0 - 9.0.1"); + break; + case 12: + strcpy(fuses_hos_version, "9.1.0 - 9.2.0"); + break; + case 13: + strcpy(fuses_hos_version, "10.0.0 - 10.2.0"); + break; + case 14: + strcpy(fuses_hos_version, "11.0.0 - 12.0.1"); + break; + case 15: + strcpy(fuses_hos_version, "12.0.2 - 13.2.0"); + break; + case 16: + strcpy(fuses_hos_version, "13.2.1 - 14.1.2"); + break; + case 17: + strcpy(fuses_hos_version, "15.0.0 - 15.0.1"); + break; + case 18: + strcpy(fuses_hos_version, "16.0.0 - 16.1.0"); + break; + case 19: + strcpy(fuses_hos_version, "17.0.0 - 18.1.0"); + break; + case 20: + strcpy(fuses_hos_version, "19.0.0 - 19.0.1"); + break; + case 21: + strcpy(fuses_hos_version, "20.0.0+"); + break; + case 255: + strcpy(fuses_hos_version, "#FFD000 Overburnt#"); + break; + default: + strcpy(fuses_hos_version, "#FF8000 Unknown#"); + break; + } + + // Calculate LOT. u32 lot_code0 = (FUSE(FUSE_OPT_LOT_CODE_0) & 0xFFFFFFF) << 2; u32 lot_bin = 0; for (int i = 0; i < 5; ++i) @@ -317,29 +636,39 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) lot_code0 <<= 6; } + u32 chip_id = APB_MISC(APB_MISC_GP_HIDREV); // Parse fuses and display them. s_printf(txt_buf, - "\n%X - %s - %s\n%d - %s\n%d - %d\n%08X%08X%08X%08X\n%08X\n" - "%s\n%d.%02d (0x%X)\n%d.%02d (0x%X)\n%d\n%d\n%d\n%d\n%d\n0x%X\n%d\n%d\n%d\n%d\n" - "%d\n%d\n%d (0x%X)\n%d\n%d\n%d\n%d", - FUSE(FUSE_SKU_INFO), odm4 & 0x10000 ? "Mariko" : "Erista", (fuse_read_odm(4) & 3) ? "Dev" : "Retail", - dram_id, dram_man, burntFuses7, burntFuses6, + "%02X - %s - M%d A%02d\n" + "%X - %s - %s\n%02d - %s\n%d | %d - HOS: %s\n%08X %08X %08X\n%08X%08X%08X%08X\n%08X\n%08X%08X%08X%08X\n%08X%08X%08X%08X\n%d\n" + "%s\n%d.%02d (0x%X)\n%d.%02d (0x%X)\n%d\n%d\n%d\n%d\n0x%X\n%d\n%d (%d)\n%d (%d)\n%d (%d)\n" + "%d\n%d\n%d (0x%X)\n%d\n%d\n%d", + (chip_id >> 8) & 0xFF, + hw_get_chip_id() == GP_HIDREV_MAJOR_T210 ? "T210 (Erista)" : "T210B01 (Mariko)", + (chip_id >> 4) & 0xF, (chip_id >> 16) & 0xF, + FUSE(FUSE_SKU_INFO), sku, fuse_read_hw_state() ? "Dev" : "Retail", + dram_id, dram_man, burnt_fuses_7, burnt_fuses_6, fuses_hos_version, + fuse_read_odm(4), fuse_read_odm(6), fuse_read_odm(7), byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY4)), - (FUSE(FUSE_RESERVED_SW) & 0x80) ? "XUSB" : "USB 2.0", + byte_swap_32(FUSE(FUSE_PUBLIC_KEY0)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY1)), + byte_swap_32(FUSE(FUSE_PUBLIC_KEY2)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY3)), + byte_swap_32(FUSE(FUSE_PUBLIC_KEY4)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY5)), + byte_swap_32(FUSE(FUSE_PUBLIC_KEY6)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY7)), + fuse_read_odm_keygen_rev(), + ((FUSE(FUSE_RESERVED_SW) & 0x80) || h_cfg.t210b01) ? "XUSB" : "USB2", (FUSE(FUSE_OPT_FT_REV) >> 5) & 0x3F, FUSE(FUSE_OPT_FT_REV) & 0x1F, FUSE(FUSE_OPT_FT_REV), (FUSE(FUSE_OPT_CP_REV) >> 5) & 0x3F, FUSE(FUSE_OPT_CP_REV) & 0x1F, FUSE(FUSE_OPT_CP_REV), - FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F, FUSE(FUSE_CPU_SPEEDO_0_CALIB), FUSE(FUSE_CPU_SPEEDO_1_CALIB), FUSE(FUSE_CPU_SPEEDO_2_CALIB), FUSE(FUSE_SOC_SPEEDO_0_CALIB), FUSE(FUSE_SOC_SPEEDO_1_CALIB), FUSE(FUSE_SOC_SPEEDO_2_CALIB), - FUSE(FUSE_CPU_IDDQ_CALIB), FUSE(FUSE_SOC_IDDQ_CALIB), FUSE(FUSE_GPU_IDDQ_CALIB), + FUSE(FUSE_CPU_IDDQ_CALIB), FUSE(FUSE_CPU_IDDQ_CALIB) * 4, + FUSE(FUSE_SOC_IDDQ_CALIB), FUSE(FUSE_SOC_IDDQ_CALIB) * 4, + FUSE(FUSE_GPU_IDDQ_CALIB), FUSE(FUSE_GPU_IDDQ_CALIB) * 5, FUSE(FUSE_OPT_VENDOR_CODE), FUSE(FUSE_OPT_FAB_CODE), lot_bin, FUSE(FUSE_OPT_LOT_CODE_0), - FUSE(FUSE_OPT_LOT_CODE_1), FUSE(FUSE_OPT_WAFER_ID), FUSE(FUSE_OPT_X_COORDINATE), FUSE(FUSE_OPT_Y_COORDINATE)); + FUSE(FUSE_OPT_WAFER_ID), FUSE(FUSE_OPT_X_COORDINATE), FUSE(FUSE_OPT_Y_COORDINATE)); - lv_label_set_array_text(lb_val, txt_buf, 0x1000); - - free(txt_buf); + lv_label_set_text(lb_val, txt_buf); lv_obj_set_width(lb_val, lv_obj_get_width(val)); lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); @@ -351,15 +680,376 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) lv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK); lv_label_set_recolor(lb_desc2, true); + // Prepare DRAM info. + emc_mr_data_t ram_vendor = sdram_read_mrx(MR5_MAN_ID); + emc_mr_data_t ram_rev0 = sdram_read_mrx(MR6_REV_ID1); + emc_mr_data_t ram_rev1 = sdram_read_mrx(MR7_REV_ID2); + emc_mr_data_t ram_density = sdram_read_mrx(MR8_DENSITY); + u32 ranks = EMC(EMC_ADR_CFG) + 1; + u32 channels = (EMC(EMC_FBIO_CFG7) >> 1) & 3; + channels = (channels & 1) + ((channels & 2) >> 1); + s_printf(txt_buf, "#00DDFF %s SDRAM ##FF8000 (Module 0 | 1):#\n#FF8000 Vendor:# ", h_cfg.t210b01 ? "LPDDR4X" : "LPDDR4"); + switch (ram_vendor.chip0.rank0_ch0) + { + case 1: + strcat(txt_buf, "Samsung"); + break; +/* + case 5: + strcat(txt_buf, "Nanya"); + break; +*/ + case 6: + strcat(txt_buf, "Hynix"); + break; +/* + case 8: + strcat(txt_buf, "Winbond"); + break; + case 9: + strcat(txt_buf, "ESMT"); + break; + case 19: + strcat(txt_buf, "CXMT"); + break; + case 26: + strcat(txt_buf, "Xi'an UniIC"); + break; + case 27: + strcat(txt_buf, "ISSI"); + break; + case 28: + strcat(txt_buf, "JSC"); + break; + case 197: + strcat(txt_buf, "SINKER"); + break; + case 229: + strcat(txt_buf, "Dosilicon"); + break; + case 248: + strcat(txt_buf, "Fidelix"); + break; + case 249: + strcat(txt_buf, "Ultra Memory"); + break; + case 253: + strcat(txt_buf, "AP Memory"); + break; + */ + case 255: + strcat(txt_buf, "Micron"); + break; + default: + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Unknown# (%d)", ram_vendor.chip0.rank0_ch0); + break; + } + strcat(txt_buf, " #FF8000 |# "); + switch (ram_vendor.chip1.rank0_ch0) + { + case 1: + strcat(txt_buf, "Samsung"); + break; + case 6: + strcat(txt_buf, "Hynix"); + break; + case 255: + strcat(txt_buf, "Micron"); + break; + default: + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Unknown# (%d)", ram_vendor.chip1.rank0_ch0); + break; + } + + s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 Rev ID:# %X.%02X #FF8000 |# %X.%02X\n#FF8000 Density:# ", + ram_rev0.chip0.rank0_ch0, ram_rev1.chip0.rank0_ch0, ram_rev0.chip1.rank0_ch0, ram_rev1.chip1.rank0_ch0); + + u32 actual_ranks = (ram_vendor.chip0.rank0_ch0 == ram_vendor.chip0.rank1_ch0 && + ram_vendor.chip0.rank0_ch1 == ram_vendor.chip0.rank1_ch1 && + ram_rev0.chip0.rank0_ch0 == ram_rev0.chip0.rank1_ch0 && + ram_rev0.chip0.rank0_ch1 == ram_rev0.chip0.rank1_ch1 && + ram_rev1.chip0.rank0_ch0 == ram_rev1.chip0.rank1_ch0 && + ram_rev1.chip0.rank0_ch1 == ram_rev1.chip0.rank1_ch1 && + ram_density.chip0.rank0_ch0 == ram_density.chip0.rank1_ch0 && + ram_density.chip0.rank0_ch1 == ram_density.chip0.rank1_ch1) + ? 2 : 1; + bool rank_bad = ranks != actual_ranks; + s_printf(txt_buf + strlen(txt_buf), "%s %d x %s", rank_bad ? "#FFDD00" : "", actual_ranks * channels, rank_bad ? "#" : ""); + + switch ((ram_density.chip0.rank0_ch0 & 0x3C) >> 2) + { + case 2: + strcat(txt_buf, "512MB"); + break; + case 3: + strcat(txt_buf, "768MB"); + break; + case 4: + strcat(txt_buf, "1GB"); + break; + case 5: + strcat(txt_buf, "1.5GB"); + break; + case 6: + strcat(txt_buf, "2GB"); + break; + default: + s_printf(txt_buf + strlen(txt_buf), "Unk (%d)", (ram_density.chip0.rank0_ch0 & 0x3C) >> 2); + break; + } + + actual_ranks = (ram_vendor.chip1.rank0_ch0 == ram_vendor.chip1.rank1_ch0 && + ram_vendor.chip1.rank0_ch1 == ram_vendor.chip1.rank1_ch1 && + ram_rev0.chip1.rank0_ch0 == ram_rev0.chip1.rank1_ch0 && + ram_rev0.chip1.rank0_ch1 == ram_rev0.chip1.rank1_ch1 && + ram_rev1.chip1.rank0_ch0 == ram_rev1.chip1.rank1_ch0 && + ram_rev1.chip1.rank0_ch1 == ram_rev1.chip1.rank1_ch1 && + ram_density.chip1.rank0_ch0 == ram_density.chip1.rank1_ch0 && + ram_density.chip1.rank0_ch1 == ram_density.chip1.rank1_ch1) + ? 2 : 1; + rank_bad = ranks != actual_ranks; + + s_printf(txt_buf + strlen(txt_buf), " #FF8000 |# %s %d x %s", rank_bad ? "#FFDD00" : "", actual_ranks * channels, rank_bad ? "#" : ""); + + switch ((ram_density.chip1.rank0_ch0 & 0x3C) >> 2) + { + case 2: + strcat(txt_buf, "512MB"); + break; + case 3: + strcat(txt_buf, "768MB"); + break; + case 4: + strcat(txt_buf, "1GB"); + break; + case 5: + strcat(txt_buf, "1.5GB"); + break; + case 6: + strcat(txt_buf, "2GB"); + break; + default: + s_printf(txt_buf + strlen(txt_buf), "Unk (%d)", (ram_density.chip1.rank0_ch0 & 0x3C) >> 2); + break; + } + strcat(txt_buf, "\n\n"); + + // Prepare display info. + u8 display_rev = (nyx_str->info.disp_id >> 8) & 0xFF; + u32 display_id = ((nyx_str->info.disp_id >> 8) & 0xFF00) | (nyx_str->info.disp_id & 0xFF); + + strcat(txt_buf, "#00DDFF Display Panel:#\n#FF8000 Model:# "); + + switch (display_id) + { + case PANEL_JDI_LAM062M109A: + strcat(txt_buf, "JDI LAM062M109A"); + break; + case PANEL_JDI_LPM062M326A: + strcat(txt_buf, "JDI LPM062M326A"); + break; + case PANEL_INL_P062CCA_AZ1: + strcat(txt_buf, "InnoLux P062CCA"); + switch (display_rev) + { + case 0x93: + strcat(txt_buf, "-AZ1"); + break; + case 0x95: + strcat(txt_buf, "-AZ2"); + break; + case 0x96: + strcat(txt_buf, "-AZ3"); + break; + case 0x97: + strcat(txt_buf, "-???"); + break; + case 0x98: + strcat(txt_buf, "-???"); + break; + case 0x99: + strcat(txt_buf, "-???"); + break; + default: + strcat(txt_buf, " #FFDD00 Contact me!#"); + break; + } + break; + case PANEL_AUO_A062TAN01: + strcat(txt_buf, "AUO A062TAN"); + switch (display_rev) + { + case 0x93: + strcat(txt_buf, "00"); + break; + case 0x94: + strcat(txt_buf, "01"); + break; + case 0x95: + strcat(txt_buf, "02"); + break; + case 0x96: + strcat(txt_buf, "??"); + break; + case 0x97: + strcat(txt_buf, "??"); + break; + case 0x98: + strcat(txt_buf, "??"); + break; + default: + strcat(txt_buf, " #FFDD00 Contact me!#"); + break; + } + break; + case PANEL_INL_2J055IA_27A: + strcat(txt_buf, "InnoLux 2J055IA-27A"); + break; + case PANEL_AUO_A055TAN01: + strcat(txt_buf, "AUO A055TAN"); + s_printf(txt_buf + strlen(txt_buf), "%02d", display_rev - 0x92); + break; + case PANEL_SHP_LQ055T1SW10: + strcat(txt_buf, "Sharp LQ055T1SW10"); + break; + case PANEL_SAM_AMS699VC01: + strcat(txt_buf, "Samsung AMS699VC01"); + break; + case PANEL_OEM_CLONE_6_2: + strcat(txt_buf, "#FFDD00 OEM Clone 6.2\"#"); + break; + case PANEL_OEM_CLONE_5_5: + strcat(txt_buf, "#FFDD00 OEM Clone 5.5\"#"); + break; + case PANEL_OEM_CLONE: + strcat(txt_buf, "#FFDD00 OEM Clone#"); + break; + case 0xCCCC: + strcat(txt_buf, "#FFDD00 Failed to get info!#"); + break; + default: + switch (display_id & 0xFF) + { + case PANEL_JDI_XXX062M: + strcat(txt_buf, "JDI "); + break; + case (PANEL_INL_P062CCA_AZ1 & 0xFF): + strcat(txt_buf, "InnoLux "); + break; + case (PANEL_AUO_A062TAN01 & 0xFF): + strcat(txt_buf, "AUO "); + break; + case (PANEL_SAM_AMS699VC01 & 0xFF): + strcat(txt_buf, "Samsung "); + break; + } + strcat(txt_buf, "Unknown #FFDD00 Contact me!#"); + break; + } + + s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 ID:# #96FF00 %02X# %02X #96FF00 %02X#", + nyx_str->info.disp_id & 0xFF, (nyx_str->info.disp_id >> 8) & 0xFF, (nyx_str->info.disp_id >> 16) & 0xFF); + + touch_fw_info_t touch_fw; + touch_panel_info_t *touch_panel; + bool panel_ic_paired = false; + + // Prepare touch panel/ic info. + if (!touch_get_fw_info(&touch_fw)) + { + strcat(txt_buf, "\n\n#00DDFF Touch Panel:#\n#FF8000 Model:# "); + + touch_panel = touch_get_panel_vendor(); + if (touch_panel) + { + if ((u8)touch_panel->idx == (u8)-2) // Touch panel not found, print gpios. + { + s_printf(txt_buf + strlen(txt_buf), "%2X%2X%2X #FFDD00 Contact me!#", + touch_panel->gpio0, touch_panel->gpio1, touch_panel->gpio2); + touch_panel = NULL; + } + else + strcat(txt_buf, touch_panel->vendor); + } + else + strcat(txt_buf, "#FFDD00 Error!#"); + + s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 ID:# %02X.%02X.%02X.%02X (", + (touch_fw.fw_id >> 24) & 0xFF, (touch_fw.fw_id >> 16) & 0xFF, (touch_fw.fw_id >> 8) & 0xFF, touch_fw.fw_id & 0xFF); + + // Check panel pair info. + switch (touch_fw.fw_id) + { + case 0x00100100: + strcat(txt_buf, "4CD60D/0"); + if (touch_panel) + panel_ic_paired = (u8)touch_panel->idx == (u8)-1; + break; + case 0x00100200: // 4CD 1602. + case 0x00120100: + case 0x32000001: + strcat(txt_buf, "4CD60D/1"); + if (touch_panel) + panel_ic_paired = touch_panel->idx == 0; // NISSHA NFT-K12D. + break; + // case 0x98000004: // New 6.2" panel? + // case 0x50000001: + // case 0x50000002: + // strcat(txt_buf, "FST2 UNK"); + // if (touch_panel) + // panel_ic_paired = touch_panel->idx == 0; + // break; + case 0x001A0300: + case 0x32000102: + strcat(txt_buf, "4CD60D/2"); + if (touch_panel) + panel_ic_paired = touch_panel->idx == 1; // GiS GGM6 B2X. + break; + case 0x00290100: + case 0x32000302: + strcat(txt_buf, "4CD60D/3"); + if (touch_panel) + panel_ic_paired = touch_panel->idx == 2; // NISSHA NBF-K9A. + break; + case 0x31051820: + case 0x32000402: + strcat(txt_buf, "4CD60D/4"); + if (touch_panel) + panel_ic_paired = touch_panel->idx == 3; // GiS 5.5". + break; + case 0x32000501: + case 0x33000502: + case 0x33000503: + case 0x33000510: + strcat(txt_buf, "4CD60D/5"); + if (touch_panel) + panel_ic_paired = touch_panel->idx == 4; // Samsung BH2109. + break; + default: + strcat(txt_buf, "#FF8000 Contact me#"); + break; + } + + s_printf(txt_buf + strlen(txt_buf), " - %s)\n#FF8000 FTB ver:# %04X\n#FF8000 FW rev:# %04X", + panel_ic_paired ? "Paired" : "#FFDD00 Error#", + touch_fw.ftb_ver, + byte_swap_16(touch_fw.fw_rev)); // Byte swapping makes more sense here. + } + else + strcat(txt_buf, "\n\n#FFDD00 Failed to get touch info!#"); + // Check if patched unit. if (!fuse_check_patched_rcm()) - lv_label_set_static_text(lb_desc2, "#96FF00 Your unit is exploitable#\n#96FF00 to the RCM bug!#"); + strcat(txt_buf, "\n\n#96FF00 This unit is exploitable#\n#96FF00 to the RCM bug!#"); else - lv_label_set_static_text(lb_desc2, "#FF8000 Your unit is patched#\n#FF8000 to the RCM bug!#"); + strcat(txt_buf, "\n\n#FF8000 This unit is patched#\n#FF8000 to the RCM bug!#"); + + lv_label_set_text(lb_desc2, txt_buf); + + free(txt_buf); lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); - lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0); - lv_label_set_align(lb_desc2, LV_LABEL_ALIGN_CENTER); + lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 4, 0); return LV_RES_OK; } @@ -367,18 +1057,21 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn) static char *ipatches_txt; static void _ipatch_process(u32 offset, u32 value) { - s_printf(ipatches_txt + strlen(ipatches_txt), "%6X %4X ", BOOTROM_BASE + offset, value); + s_printf(ipatches_txt + strlen(ipatches_txt), "%6X %4X ", IROM_BASE + offset, value); u8 lo = value & 0xFF; switch (value >> 8) { case 0x20: s_printf(ipatches_txt + strlen(ipatches_txt), "MOVS R0, ##0x%02X", lo); break; + case 0x21: + s_printf(ipatches_txt + strlen(ipatches_txt), "MOVS R1, ##0x%02X", lo); + break; case 0xDF: s_printf(ipatches_txt + strlen(ipatches_txt), "SVC ##0x%02X", lo); break; } - s_printf(ipatches_txt + strlen(ipatches_txt), "\n"); + strcat(ipatches_txt, "\n"); } static lv_res_t _create_window_bootrom_info_status(lv_obj_t *btn) @@ -392,9 +1085,9 @@ static lv_res_t _create_window_bootrom_info_status(lv_obj_t *btn) lv_obj_t * lb_desc = lv_label_create(desc, NULL); lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); lv_label_set_recolor(lb_desc, true); - lv_ta_set_style(lb_desc, LV_TA_STYLE_BG, &monospace_text); + lv_label_set_style(lb_desc, &monospace_text); - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_4K); ipatches_txt = txt_buf; s_printf(txt_buf, "#00DDFF Ipatches:#\n#FF8000 Address "SYMBOL_DOT" Val "SYMBOL_DOT" Instruction#\n"); @@ -402,7 +1095,7 @@ static lv_res_t _create_window_bootrom_info_status(lv_obj_t *btn) if (res != 0) s_printf(txt_buf + strlen(txt_buf), "#FFDD00 Failed to read ipatches. Error: %d#", res); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + lv_label_set_text(lb_desc, txt_buf); free(txt_buf); @@ -411,141 +1104,589 @@ static lv_res_t _create_window_bootrom_info_status(lv_obj_t *btn) return LV_RES_OK; } -static lv_res_t _create_window_tsec_keys_status(lv_obj_t *btn) +static lv_res_t _launch_lockpick_action(lv_obj_t *btns, const char * txt) { - u32 retries = 0; + int btn_idx = lv_btnm_get_pressed(btns); - tsec_ctxt_t tsec_ctxt; - sdmmc_storage_t storage; - sdmmc_t sdmmc; + mbox_action(btns, txt); - lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" TSEC Keys"); + if (btn_idx == 1) + { + lv_obj_t *list = lv_list_create(NULL, NULL); + lv_obj_set_size(list, 1, 1); + lv_list_set_single_mode(list, true); + lv_list_add(list, NULL, "Lockpick_RCM.bin", NULL); + lv_obj_t *btn; + btn = lv_list_get_prev_btn(list, NULL); + launch_payload(btn); + lv_obj_del(list); + } - //Disable buttons. - nyx_window_toggle_buttons(win, true); + return LV_RES_INV; +} - lv_obj_t *desc = lv_cont_create(win, NULL); - lv_obj_set_size(desc, LV_HOR_RES / 2 / 2, LV_VER_RES - (LV_DPI * 11 / 6)); - //lv_obj_align(desc, win, LV_ALIGN_ou_TOP_LEFT, 0, 40); +static lv_res_t _create_mbox_lockpick(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - lv_obj_t * lb_desc = lv_label_create(desc, NULL); + static const char * mbox_btn_map[] = { "\251", "\222Continue", "\222Close", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_mbox_set_text(mbox, "#FF8000 Lockpick RCM#\n\nThis will launch Lockpick RCM.\nDo you want to continue?\n\n" + "To return back from lockpick use\n#96FF00 Reboot to hekate#."); + + lv_mbox_add_btns(mbox, mbox_btn_map, _launch_lockpick_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_emmc_sandisk_report(lv_obj_t * btn) +{ + static lv_style_t h_style; + lv_style_copy(&h_style, &lv_style_transp); + h_style.body.padding.inner = 0; + h_style.body.padding.hor = LV_DPI - (LV_DPI / 4); + h_style.body.padding.ver = LV_DPI / 6; + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222Close", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 8); + + lv_mbox_set_text(mbox, "#C7EA46 Sandisk Device Report#"); + + u8 *buf = zalloc(EMMC_BLOCKSIZE); + char *txt_buf = (char *)malloc(SZ_32K); + char *txt_buf2 = (char *)malloc(SZ_32K); + txt_buf[0] = 0; + txt_buf2[0] = 0; + + // Create SoC Info container. + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_style(h1, &h_style); + lv_cont_set_fit(h1, false, true); + lv_obj_set_width(h1, (LV_HOR_RES / 9) * 7); + lv_obj_set_click(h1, false); + lv_cont_set_layout(h1, LV_LAYOUT_OFF); + + lv_obj_t * lb_desc = lv_label_create(h1, NULL); lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); lv_label_set_recolor(lb_desc, true); - lv_ta_set_style(lb_desc, LV_TA_STYLE_BG, &monospace_text); + lv_label_set_style(lb_desc, &monospace_text); + lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4); - // Read package1. - char *build_date = malloc(32); - u8 *pkg1 = (u8 *)malloc(0x40000); - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); - sdmmc_storage_end(&storage); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1, build_date); + lv_obj_t * lb_desc2 = lv_label_create(h1, NULL); + lv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK); + lv_label_set_recolor(lb_desc2, true); + lv_label_set_style(lb_desc2, &monospace_text); + lv_obj_set_width(lb_desc2, LV_HOR_RES / 9 * 3); + lv_obj_align(lb_desc2, lb_desc, LV_ALIGN_OUT_RIGHT_TOP, 0, 0); - char *txt_buf = (char *)malloc(0x500); - char *txt_buf2 = (char *)malloc(0x500); - s_printf(txt_buf, "#00DDFF Found pkg1 ('%s')#\n", build_date); - free(build_date); - if (!pkg1_id) + if (!emmc_initialize(false)) { - s_printf(txt_buf + strlen(txt_buf), "#FFDD00 Unknown pkg1 version for reading#\n#FFDD00 TSEC firmware!#"); - lv_label_set_array_text(lb_desc, txt_buf, 0x500); - lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); + lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); goto out; } - lv_label_set_array_text(lb_desc, txt_buf, 0x500); - lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); - lv_obj_t *val = lv_cont_create(win, NULL); - lv_obj_set_size(val, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 6)); + int res = sdmmc_storage_vendor_sandisk_report(&emmc_storage, buf); + emmc_end(); - lv_obj_t * lb_val = lv_label_create(val, lb_desc); - lv_ta_set_style(lb_val, LV_TA_STYLE_BG, &monospace_text); - - lv_label_set_static_text(lb_val, "Please wait..."); - lv_obj_set_width(lb_val, lv_obj_get_width(val)); - lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); - manual_system_maintenance(true); - - tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off; - tsec_ctxt.pkg1 = pkg1; - tsec_ctxt.pkg11_off = pkg1_id->pkg11_off; - tsec_ctxt.secmon_base = pkg1_id->secmon_base; - - if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600) - tsec_ctxt.size = 0xF00; - else if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - tsec_ctxt.size = 0x2900; - else if (pkg1_id->kb == KB_FIRMWARE_VERSION_700) + if (!res) { - tsec_ctxt.size = 0x3000; - // Exit after TSEC key generation. - *((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8; + lv_label_set_text(lb_desc, "#FFDD00 Device Report not supported!#"); + lv_label_set_text(lb_desc2, " "); + + goto out; + } + + mmc_sandisk_report_t *rpt = (mmc_sandisk_report_t *)buf; + + u8 fw_update_date[13] = {0}; + u8 fw_update_time[9] = {0}; + memcpy(fw_update_date, rpt->fw_update_date, sizeof(rpt->fw_update_date)); + memcpy(fw_update_time, rpt->fw_update_time, sizeof(rpt->fw_update_time)); + + s_printf(txt_buf, + "#00DDFF Device report#\n" + //"#FF8000 Average Erases SYS:# %d\n" + "#FF8000 Average Erases SLC:# %d\n" + "#FF8000 Average Erases MLC:# %d\n" + //"#FF8000 Read Reclaims SYS:# %d\n" + "#FF8000 Read Reclaims SLC:# %d\n" + "#FF8000 Read Reclaims MLC:# %d\n" + "#FF8000 Bad Blocks Factory:# %d\n" + "#FF8000 Bad Blocks SYS:# %d\n" + "#FF8000 Bad Blocks SLC:# %d\n" + "#FF8000 Bad Blocks MLC:# %d\n" + "#FF8000 FW Updates:# %d\n" + "#FF8000 FW Buildtime:# %s %s\n" + "#FF8000 Total Writes:# %d MB\n" + //"#FF8000 Voltage Drops:# %d\n" + //"#FF8000 Voltage Droops:# %d\n" + //"#FF8000 VD Failed Recovers:# %d\n" + //"#FF8000 VD Recover Operations:# %d\n" + "#FF8000 Total Writes SLC:# %d MB\n" + "#FF8000 Total Writes MLC:# %d MB\n" + "#FF8000 BigFile limit status:# %d\n" + "#FF8000 Average Erases Hybrid:# %d", + + //rpt->avg_erase_cycles_sys, + rpt->avg_erase_cycles_slc, + rpt->avg_erase_cycles_mlc, + //rpt->read_reclaim_cnt_sys, + rpt->read_reclaim_cnt_slc, + rpt->read_reclaim_cnt_mlc, + rpt->bad_blocks_factory, + rpt->bad_blocks_sys, + rpt->bad_blocks_slc, + rpt->bad_blocks_mlc, + rpt->fw_updates_cnt, + fw_update_date, + fw_update_time, + rpt->total_writes_100mb * 100, + //rpt->vdrops, + //rpt->vdroops, + //rpt->vdrops_failed_data_rec, + //rpt->vdrops_data_rec_ops, + rpt->total_writes_slc_100mb * 100, + rpt->total_writes_mlc_100mb * 100, + rpt->mlc_bigfile_mode_limit_exceeded, + rpt->avg_erase_cycles_hybrid); + + u8 advanced_report = 0; + for (u32 i = 0; i < sizeof(mmc_sandisk_advanced_report_t); i++) + advanced_report |= *(u8 *)((u8 *)&rpt->advanced + i); + + if (advanced_report) + { + s_printf(txt_buf2, + "#00DDFF Advanced Health Status#\n" + "#FF8000 Power ups:# %d\n" + //"#FF8000 Maximum Erases SYS:# %d\n" + "#FF8000 Maximum Erases SLC:# %d\n" + "#FF8000 Maximum Erases MLC:# %d\n" + //"#FF8000 Minimum Erases SYS:# %d\n" + "#FF8000 Minimum Erases SLC:# %d\n" + "#FF8000 Minimum Erases MLC:# %d\n" + "#FF8000 Maximum Erases EUDA:# %d\n" + "#FF8000 Minimum Erases EUDA:# %d\n" + "#FF8000 Average Erases EUDA:# %d\n" + "#FF8000 Read Reclaims EUDA:# %d\n" + "#FF8000 Bad Blocks EUDA:# %d\n" + //"#FF8000 Pre EOL State EUDA:# %d\n" + //"#FF8000 Pre EOL State SYS:# %d\n" + //"#FF8000 Pre EOL State MLC:# %d\n" + "#FF8000 Uncorrectable ECC:# %d\n" + "#FF8000 Temperature Now:# %d oC\n" + //"#FF8000 Temperature Min:# %d oC\n" + "#FF8000 Temperature Max:# %d oC\n" + "#FF8000 Health Level EUDA:# %d%%\n" + //"#FF8000 Health Level SYS:# %d%%\n" + "#FF8000 Health Level MLC:# %d%%", + + rpt->advanced.power_inits, + //rpt->advanced.max_erase_cycles_sys, + rpt->advanced.max_erase_cycles_slc, + rpt->advanced.max_erase_cycles_mlc, + //rpt->advanced.min_erase_cycles_sys, + rpt->advanced.min_erase_cycles_slc, + rpt->advanced.min_erase_cycles_mlc, + rpt->advanced.max_erase_cycles_euda, + rpt->advanced.min_erase_cycles_euda, + rpt->advanced.avg_erase_cycles_euda, + rpt->advanced.read_reclaim_cnt_euda, + rpt->advanced.bad_blocks_euda, + //rpt->advanced.pre_eol_euda, + //rpt->advanced.pre_eol_sys, + //rpt->advanced.pre_eol_mlc, + rpt->advanced.uncorrectable_ecc, + rpt->advanced.temperature_now, + //rpt->advanced.temperature_min, + rpt->advanced.temperature_max, + rpt->advanced.health_pct_euda ? 101 - rpt->advanced.health_pct_euda : 0, + //rpt->advanced.health_pct_sys ? 101 - rpt->advanced.health_pct_sys : 0, + rpt->advanced.health_pct_mlc ? 101 - rpt->advanced.health_pct_mlc : 0); } else - tsec_ctxt.size = 0x3300; + strcpy(txt_buf2, "#00DDFF Advanced Health Status#\n#FFDD00 Empty!#"); - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size); - tsec_ctxt.fw = tsec_paged; - } - - int res = 0; - - while (tsec_query((u8 *)tsec_keys, pkg1_id->kb, &tsec_ctxt) < 0) - { - memset(tsec_keys, 0x00, 0x20); - - retries++; - - if (retries > 3) - { - res = -1; - break; - } - } - - s_printf(txt_buf + strlen(txt_buf), "#C7EA46 TSEC Key:#\n"); - if (res >= 0) - { - s_printf(txt_buf2, "\n%08X%08X%08X%08X\n", - byte_swap_32(tsec_keys[0]), byte_swap_32(tsec_keys[1]), byte_swap_32(tsec_keys[2]), byte_swap_32(tsec_keys[3])); - - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - { - s_printf(txt_buf + strlen(txt_buf), "#C7EA46 TSEC root:#\n"); - s_printf(txt_buf2 + strlen(txt_buf2), "%08X%08X%08X%08X\n", - byte_swap_32(tsec_keys[4]), byte_swap_32(tsec_keys[5]), byte_swap_32(tsec_keys[6]), byte_swap_32(tsec_keys[7])); - } - lv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD" Dump Keys", _tsec_keys_dump_window_action); - } - else - { - s_printf(txt_buf2, "Error: %x", res); - } - - lv_label_set_array_text(lb_desc, txt_buf, 0x500); - - lv_label_set_array_text(lb_val, txt_buf2, 0x500); + lv_label_set_text(lb_desc, txt_buf); + lv_label_set_text(lb_desc2, txt_buf2); out: - free(pkg1); - free(txt_buf); - free(txt_buf2); + free(buf); + free (txt_buf); + free (txt_buf2); - nyx_window_toggle_buttons(win, false); + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text. + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); return LV_RES_OK; } +static lv_res_t _create_mbox_benchmark(bool sd_bench) +{ + sdmmc_storage_t *storage; + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES * 3 / 7); + + char *txt_buf = (char *)malloc(SZ_16K); + + s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads] Abort: VOL- & VOL+", sd_bench ? "SD Card" : "eMMC"); + + lv_mbox_set_text(mbox, txt_buf); + txt_buf[0] = 0; + + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_fit(h1, false, true); + lv_cont_set_style(h1, &lv_style_transp_tight); + lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI / 10); + + lv_obj_t *lbl_status = lv_label_create(h1, NULL); + lv_label_set_style(lbl_status, &monospace_text); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, " "); + lv_obj_align(lbl_status, h1, LV_ALIGN_IN_TOP_MID, 0, 0); + + lv_obj_t *bar = lv_bar_create(mbox, NULL); + lv_obj_set_size(bar, LV_DPI * 2, LV_DPI / 5); + lv_bar_set_range(bar, 0, 100); + lv_bar_set_value(bar, 0); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + manual_system_maintenance(true); + + int res = 0; + + if (sd_bench) + { + storage = &sd_storage; + + // Re-initialize to update trimmers. + sd_end(); + res = !sd_mount(); + } + else + { + storage = &emmc_storage; + res = !emmc_initialize(false); + if (!res) + emmc_set_partition(EMMC_GPP); + } + + if (res) + { + lv_mbox_set_text(mbox, "#FFDD00 Failed to init Storage!#"); + goto out; + } + + // Set benchmark parameters. + const u32 sct_blk_seq = 0x8000; // 16MB. A2 spec denotes 4MB, but using older big AU. + const u32 sct_blk_4kb = 8; // 4KB. + const u32 sct_rem_seq = 0x200000; // 1GB. A2 spec. + const u32 sct_rem_4kb = 0x80000; // 256MB. A2 spec. + const u32 sct_num_1mb = 0x800; // 1MB. + const u32 size_bytes_seq = sct_rem_seq * SDMMC_DAT_BLOCKSIZE; + const u32 size_bytes_4kb = sct_rem_4kb * SDMMC_DAT_BLOCKSIZE; + + // Set calculation divider. 1000 or 1024. (Does not affect IOPS). + u32 mb_div = 1000; // Unfortunately most software uses fake MB. + + char *mbs_text; + switch (mb_div) + { + case 1000: + mbs_text = "MB/s"; + break; + case 1024: + mbs_text = "MiB/s"; + break; + } + + // Set actual div in MB/MiB. + mb_div *= mb_div; + + int error = 0; + u32 iters = 3; + u32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, sct_blk_seq); // Align to block. + if (storage->sec_cnt < 0xC00000) + iters -= 2; // 4GB card. + + u32 rnd_off_cnt = sct_rem_4kb / sct_blk_4kb; + u32 *random_offsets = malloc(rnd_off_cnt * sizeof(u32)); + u32 *times_taken_4k = malloc(rnd_off_cnt * sizeof(u32)); + + for (u32 iter_curr = 0; iter_curr < iters; iter_curr++) + { + u32 pct = 0; + u32 prevPct = 200; + u32 timer = 0; + u32 lba_curr = 0; + u32 sector_off = offset_chunk_start * iter_curr; + u32 sector_num = sct_blk_seq; + u32 data_remaining = sct_rem_seq; + + s_printf(txt_buf + strlen(txt_buf), "#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\n", iter_curr + 1, sector_off); + + u32 render_min_ms = 66; + u32 render_timer = get_tmr_ms() + render_min_ms; + while (data_remaining) + { + u32 time_taken = get_tmr_us(); + error = !sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED); + time_taken = get_tmr_us() - time_taken; + timer += time_taken; + + manual_system_maintenance(false); + data_remaining -= sector_num; + lba_curr += sector_num; + + pct = (lba_curr * 100) / sct_rem_seq; + if (pct != prevPct && render_timer < get_tmr_ms()) + { + lv_bar_set_value(bar, pct); + manual_system_maintenance(true); + render_timer = get_tmr_ms() + render_min_ms; + + prevPct = pct; + + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + error = -1; + } + + if (error) + goto error; + } + lv_bar_set_value(bar, 100); + + // Calculate rate for transfer. + u32 rate_1k = (u64)size_bytes_seq * 1000 * 1000 * 1000 / mb_div / timer; + s_printf(txt_buf + strlen(txt_buf), " SEQ 16MB - Rate: #C7EA46 %3d.%02d %s#", + rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text); + lv_label_set_text(lbl_status, txt_buf); + lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + pct = 0; + prevPct = 200; + timer = 0; + lba_curr = 0; + sector_num = sct_blk_4kb; + data_remaining = sct_rem_4kb; + + u32 loop_idx = 0; + render_timer = get_tmr_ms() + render_min_ms; + while (data_remaining) + { + u32 time_taken = get_tmr_us(); + error = !sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED); + time_taken = get_tmr_us() - time_taken; + + timer += time_taken; + times_taken_4k[loop_idx++] = time_taken; + + manual_system_maintenance(false); + data_remaining -= sector_num; + lba_curr += sector_num; + + pct = (lba_curr * 100) / sct_rem_4kb; + if (pct != prevPct && render_timer < get_tmr_ms()) + { + lv_bar_set_value(bar, pct); + manual_system_maintenance(true); + render_timer = get_tmr_ms() + render_min_ms; + + prevPct = pct; + + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + error = -1; + } + + if (error) + goto error; + } + lv_bar_set_value(bar, 100); + + qsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s. + + u32 pct95 = 0; + for (u32 i = 0; i < loop_idx * 95 / 100; i++) + pct95 += times_taken_4k[i]; + pct95 /= loop_idx * 95 / 100; + + u32 pct05 = 0; + for (u32 i = 0; i < loop_idx * 5 / 100; i++) + pct05 += times_taken_4k[loop_idx - 1 - i]; + pct05 /= loop_idx * 5 / 100; + + // Calculate rate and IOPS for transfer. + rate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer; + u32 iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000; + s_printf(txt_buf + strlen(txt_buf), " AVG #C7EA46 95th# #FF3C28 5th#\n"); + s_printf(txt_buf + strlen(txt_buf), " SEQ 4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \n", + rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05); + lv_label_set_text(lbl_status, txt_buf); + lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + u32 lba_idx = 0; + u32 random_numbers[4]; + for (u32 i = 0; i < rnd_off_cnt; i += 4) + { + // Generate new random numbers. + while (!se_gen_prng128(random_numbers)) + ; + // Clamp offsets to 256MB range. + random_offsets[i + 0] = random_numbers[0] % sct_rem_4kb; + random_offsets[i + 1] = random_numbers[1] % sct_rem_4kb; + random_offsets[i + 2] = random_numbers[2] % sct_rem_4kb; + random_offsets[i + 3] = random_numbers[3] % sct_rem_4kb; + } + + pct = 0; + prevPct = 200; + timer = 0; + data_remaining = sct_rem_4kb; + + loop_idx = 0; + render_timer = get_tmr_ms() + render_min_ms; + while (data_remaining) + { + u32 time_taken = get_tmr_us(); + error = !sdmmc_storage_read(storage, sector_off + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED); + time_taken = get_tmr_us() - time_taken; + + timer += time_taken; + times_taken_4k[loop_idx++] = time_taken; + + manual_system_maintenance(false); + data_remaining -= sector_num; + lba_idx++; + + pct = (lba_idx * 100) / rnd_off_cnt; + if (pct != prevPct && render_timer < get_tmr_ms()) + { + lv_bar_set_value(bar, pct); + manual_system_maintenance(true); + render_timer = get_tmr_ms() + render_min_ms; + + prevPct = pct; + + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + error = -1; + } + + if (error) + goto error; + } + lv_bar_set_value(bar, 100); + + qsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s. + + pct95 = 0; + for (u32 i = 0; i < loop_idx * 95 / 100; i++) + pct95 += times_taken_4k[i]; + pct95 /= loop_idx * 95 / 100; + + pct05 = 0; + for (u32 i = 0; i < loop_idx * 5 / 100; i++) + pct05 += times_taken_4k[loop_idx - 1 - i]; + pct05 /= loop_idx * 5 / 100; + + // Calculate rate and IOPS for transfer. + rate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer; + iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000; + s_printf(txt_buf + strlen(txt_buf), " RND 4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \n", + rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05); + if (iter_curr == iters - 1) + txt_buf[strlen(txt_buf) - 1] = 0; // Cut off last new line. + lv_label_set_text(lbl_status, txt_buf); + lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + } + +error: + free(random_offsets); + free(times_taken_4k); + + if (error) + { + if (error == -1) + s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 Aborted!#"); + else + s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 IO Error occurred!#"); + + lv_label_set_text(lbl_status, txt_buf); + lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0); + } + + lv_obj_del(bar); + + if (sd_bench && error && error != -1) + sd_end(); + if (sd_bench) + { + if (error && error != -1) + sd_end(); + else + sd_unmount(); + } + else + emmc_end(); + +out: + s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads]", sd_bench ? "SD Card" : "eMMC"); + lv_mbox_set_text(mbox, txt_buf); + free(txt_buf); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text. + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_emmc_bench(lv_obj_t * btn) +{ + _create_mbox_benchmark(false); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_sd_bench(lv_obj_t * btn) +{ + _create_mbox_benchmark(true); + + return LV_RES_OK; +} static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn) { lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" Internal eMMC Info"); + lv_win_add_btn(win, NULL, SYMBOL_CHIP" Benchmark", _create_mbox_emmc_bench); lv_obj_t *desc = lv_cont_create(win, NULL); lv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5); @@ -554,137 +1695,252 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn) lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); lv_label_set_recolor(lb_desc, true); - sdmmc_storage_t storage; - sdmmc_t sdmmc; + char *txt_buf = (char *)malloc(SZ_16K); + txt_buf[0] = '\n'; + txt_buf[1] = 0; + u16 *emmc_errors; - char *txt_buf = (char *)malloc(0x1000); - - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { - lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); + lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); - } - else - { - u16 card_type; - u32 speed = 0; + emmc_errors = emmc_get_error_count(); - s_printf(txt_buf, "\n%X\n%X\n%02X\n%c%c%c%c%c%c\n%X\n%04X\n%02d/%04d\n\n", - storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid, - storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2], - storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5], - storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year); - - card_type = storage.ext_csd.card_type; - char card_type_support[96]; - card_type_support[0] = 0; - if (card_type & EXT_CSD_CARD_TYPE_HS_26) - { - strcat(card_type_support, "HS26"); - speed = (26 << 16) | 26; - } - if (card_type & EXT_CSD_CARD_TYPE_HS_52) - { - strcat(card_type_support, ", HS52"); - speed = (52 << 16) | 52; - } - if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) - { - strcat(card_type_support, ", DDR52 1.8V"); - speed = (52 << 16) | 104; - } - if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) - { - strcat(card_type_support, ", HS200 1.8V"); - speed = (200 << 16) | 200; - } - if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) - { - strcat(card_type_support, ", HS400 1.8V"); - speed = (200 << 16) | 400; - } - - s_printf(txt_buf + strlen(txt_buf), - "#00DDFF V1.%d#\n%02X\n1.%d\n%02X\n%d MB/s (%d MHz)\n%d MB/s\n%s", - storage.ext_csd.ext_struct, storage.csd.mmca_vsn, storage.ext_csd.rev, - storage.csd.cmdclass, speed & 0xFFFF, (speed >> 16) & 0xFFFF, - storage.csd.busspeed, card_type_support); - - lv_label_set_static_text(lb_desc, - "#00DDFF CID:#\n" - "Vendor ID:\n" - "Card/BGA:\n" - "OEM ID:\n" - "Model:\n" - "Prd Rev:\n" - "S/N:\n" - "Month/Year:\n\n" - "#00DDFF Ext CSD#\n" - "Spec Version:\n" - "Extended Rev:\n" - "Cmd Classes:\n" - "Max Rate:\n" - "Current Rate:\n" - "Type Support:" - ); - lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); - - lv_obj_t *val = lv_cont_create(win, NULL); - lv_obj_set_size(val, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5); - - lv_obj_t * lb_val = lv_label_create(val, lb_desc); - - lv_label_set_array_text(lb_val, txt_buf, 0x1000); - - lv_obj_set_width(lb_val, lv_obj_get_width(val)); - lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); - - lv_obj_t *desc2 = lv_cont_create(win, NULL); - lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5); - - lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc); - lv_ta_set_style(lb_desc2, LV_TA_STYLE_BG, &monospace_text); - - u32 boot_size = storage.ext_csd.boot_mult << 17; - u32 rpmb_size = storage.ext_csd.rpmb_mult << 17; - s_printf(txt_buf, "#00DDFF eMMC Physical Partitions:#\n"); - s_printf(txt_buf + strlen(txt_buf), "1: #96FF00 BOOT0# Size: %5d KiB (Sect: 0x%08X)\n", boot_size / 1024, boot_size / 512); - s_printf(txt_buf + strlen(txt_buf), "2: #96FF00 BOOT1# Size: %5d KiB (Sect: 0x%08X)\n", boot_size / 1024, boot_size / 512); - s_printf(txt_buf + strlen(txt_buf), "3: #96FF00 RPMB# Size: %5d KiB (Sect: 0x%08X)\n", rpmb_size / 1024, rpmb_size / 512); - s_printf(txt_buf + strlen(txt_buf), "0: #96FF00 GPP# Size: %5d MiB (Sect: 0x%08X)\n\n", storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt); - s_printf(txt_buf + strlen(txt_buf), "#00DDFF GPP (eMMC USER) Partition Table:#\n"); - - sdmmc_storage_set_mmc_partition(&storage, 0); - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - int gpp_idx = 0; - LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) - { - if (gpp_idx < 2) - { - s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#", gpp_idx++, part->name); - if (gpp_idx < 2) - s_printf(txt_buf + strlen(txt_buf), " "); - s_printf(txt_buf + strlen(txt_buf), " Size: %d MiB (Sect: 0x%4X), Range: %06X-%06X\n", - (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, - part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end); - } - else - { - s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#\n Size: %6d MiB (Sect: 0x%07X), Range: %07X-%07X\n", - gpp_idx++, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, - part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end); - } - - } - nx_emmc_gpt_free(&gpt); - - lv_label_set_array_text(lb_desc2, txt_buf, 0x1000); - lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); - lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 6, 0); + goto out_error; } - sdmmc_storage_end(&storage); + u32 speed = 0; + char *rsvd_blocks; + char life_a_txt[8]; + char life_b_txt[8]; + u32 cache = emmc_storage.ext_csd.cache_size; + u32 life_a = emmc_storage.ext_csd.dev_life_est_a; + u32 life_b = emmc_storage.ext_csd.dev_life_est_b; + u16 card_type = emmc_storage.ext_csd.card_type; + char card_type_support[96]; + card_type_support[0] = 0; + + // Identify manufacturer. Only official eMMCs. + switch (emmc_storage.cid.manfid) + { + case 0x11: + strcat(txt_buf, "Toshiba "); + break; + case 0x15: + strcat(txt_buf, "Samsung "); + break; + case 0x45: // Unofficial. + strcat(txt_buf, "SanDisk "); + lv_win_add_btn(win, NULL, SYMBOL_FILE_ALT" Device Report", _create_mbox_emmc_sandisk_report); + break; + case 0x90: + strcat(txt_buf, "SK Hynix "); + break; + default: + strcat(txt_buf, "Unknown "); + break; + } + + s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c%c (%02X)\n%d.%d\n%04X\n%02d/%04d\n\n", + emmc_storage.cid.manfid, + emmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2], + emmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4], emmc_storage.cid.prod_name[5], + emmc_storage.cid.oemid, + emmc_storage.cid.prv & 0xF, emmc_storage.cid.prv >> 4, + emmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year); + + if (card_type & EXT_CSD_CARD_TYPE_HS_26) + { + strcat(card_type_support, "HS26"); + speed = (26 << 16) | 26; + } + if (card_type & EXT_CSD_CARD_TYPE_HS_52) + { + strcat(card_type_support, ", HS52"); + speed = (52 << 16) | 52; + } + if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) + { + strcat(card_type_support, ", DDR52 1.8V"); + speed = (52 << 16) | 104; + } + if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) + { + strcat(card_type_support, ", HS200 1.8V"); + speed = (200 << 16) | 200; + } + if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) + { + strcat(card_type_support, ", HS400 1.8V"); + speed = (200 << 16) | 400; + } + + strcpy(life_a_txt, "-"); + strcpy(life_b_txt, "-"); + + // Normalize cells life. + if (life_a) // SK Hynix is 0 (undefined). + { + life_a--; + life_a = (10 - life_a) * 10; + s_printf(life_a_txt, "%d%%", life_a); + } + + if (life_b) // Toshiba is 0 (undefined). + { + life_b--; + life_b = (10 - life_b) * 10; + s_printf(life_b_txt, "%d%%", life_b); + } + + switch (emmc_storage.ext_csd.pre_eol_info) + { + case 1: + rsvd_blocks = "Normal (< 80%)"; + break; + case 2: + rsvd_blocks = "Warning (> 80%)"; + break; + case 3: + rsvd_blocks = "Critical (> 90%)"; + break; + default: + rsvd_blocks = "#FF8000 Unknown#"; + break; + } + + s_printf(txt_buf + strlen(txt_buf), + "#00DDFF V1.%d (rev 1.%d)#\n%02X\n%d MB/s (%d MHz)\n%d MB/s\n%s\n%d %s\n%d MiB\nA: %s, B: %s\n%s", + emmc_storage.ext_csd.ext_struct, emmc_storage.ext_csd.rev, + emmc_storage.csd.cmdclass, speed & 0xFFFF, (speed >> 16) & 0xFFFF, + emmc_storage.csd.busspeed, card_type_support, + !(cache % 1024) ? (cache / 1024) : cache, !(cache % 1024) ? "MiB" : "KiB", + emmc_storage.ext_csd.max_enh_mult * EMMC_BLOCKSIZE / 1024, + life_a_txt, life_b_txt, rsvd_blocks); + + lv_label_set_static_text(lb_desc, + "#00DDFF CID:#\n" + "Vendor ID:\n" + "Model:\n" + "Prod Rev:\n" + "S/N:\n" + "Month/Year:\n\n" + "#00DDFF Ext CSD:#\n" + "Cmd Classes:\n" + "Max Rate:\n" + "Current Rate:\n" + "Type Support:\n\n" + "Write Cache:\n" + "Enhanced Area:\n" + "Estimated Life:\n" + "Reserved Used:" + ); + lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); + + lv_obj_t *val = lv_cont_create(win, NULL); + lv_obj_set_size(val, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5); + + lv_obj_t * lb_val = lv_label_create(val, lb_desc); + + lv_label_set_text(lb_val, txt_buf); + + lv_obj_set_width(lb_val, lv_obj_get_width(val)); + lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_t *desc2 = lv_cont_create(win, NULL); + lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5); + + lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc); + lv_label_set_style(lb_desc2, &monospace_text); + + u32 boot_size = emmc_storage.ext_csd.boot_mult << 17; + u32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17; + strcpy(txt_buf, "#00DDFF eMMC Physical Partitions:#\n"); + s_printf(txt_buf + strlen(txt_buf), "1: #96FF00 BOOT0# Size: %6d KiB Sectors: 0x%08X\n", boot_size / 1024, boot_size / EMMC_BLOCKSIZE); + s_printf(txt_buf + strlen(txt_buf), "2: #96FF00 BOOT1# Size: %6d KiB Sectors: 0x%08X\n", boot_size / 1024, boot_size / EMMC_BLOCKSIZE); + s_printf(txt_buf + strlen(txt_buf), "3: #96FF00 RPMB# Size: %6d KiB Sectors: 0x%08X\n", rpmb_size / 1024, rpmb_size / EMMC_BLOCKSIZE); + s_printf(txt_buf + strlen(txt_buf), "0: #96FF00 GPP# Size: %6d MiB Sectors: 0x%08X\n", emmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt); + strcat(txt_buf, "\n#00DDFF GPP (eMMC USER) Partition Table:#\n"); + + emmc_set_partition(EMMC_GPP); + LIST_INIT(gpt); + emmc_gpt_parse(&gpt); + + u32 idx = 0; + int lines_left = 20; + s_printf(txt_buf + strlen(txt_buf), "#FFBA00 Idx Name Size Offset Sectors#\n"); + LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) + { + int lines = strlen(part->name) > 25 ? 2 : 1; + if ((lines_left - lines) <= 0) + { + strcat(txt_buf, "#FFDD00 Table does not fit on screen!#"); + break; + } + + if (lines == 2) + { + s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#\n %6d MiB %8Xh %8Xh\n", + part->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, + part->lba_start, part->lba_end - part->lba_start + 1); + } + else + { + s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %.25s# %6d MiB %8Xh %8Xh\n", + part->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, + part->lba_start, part->lba_end - part->lba_start + 1); + } + + lines_left -= lines; + idx++; + } + if (!idx) + strcat(txt_buf, "#FFDD00 Partition table is empty!#"); + + emmc_gpt_free(&gpt); + + lv_label_set_text(lb_desc2, txt_buf); + lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); + lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 6, 0); + + emmc_errors = emmc_get_error_count(); + if (emmc_get_mode() < EMMC_MMC_HS400 || + emmc_errors[EMMC_ERROR_INIT_FAIL] || + emmc_errors[EMMC_ERROR_RW_FAIL] || + emmc_errors[EMMC_ERROR_RW_RETRY]) + { +out_error: + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + s_printf(txt_buf, + "#FF8000 eMMC Issues Warning#\n\n" + "#FFDD00 Your eMMC is initialized in a slower mode,#\n" + "#FFDD00 or init/read/write errors occurred!#\n" + "#FFDD00 This might mean hardware issues!#\n\n" + "#00DDFF Bus Speed:# %d MB/s\n\n" + "#00DDFF SDMMC4 Errors:#\n" + "Init fails: %d\n" + "Read/Write fails: %d\n" + "Read/Write errors: %d", + emmc_storage.csd.busspeed, + emmc_errors[EMMC_ERROR_INIT_FAIL], + emmc_errors[EMMC_ERROR_RW_FAIL], + emmc_errors[EMMC_ERROR_RW_RETRY]); + + lv_mbox_set_text(mbox, txt_buf); + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + } + + emmc_end(); free(txt_buf); return LV_RES_OK; @@ -693,15 +1949,16 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn) static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn) { lv_obj_t *win = nyx_create_standard_window(SYMBOL_SD" microSD Card Info"); + lv_win_add_btn(win, NULL, SYMBOL_SD" Benchmark", _create_mbox_sd_bench); lv_obj_t *desc = lv_cont_create(win, NULL); - lv_obj_set_size(desc, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 7) * 5 / 2); + lv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2); lv_obj_t * lb_desc = lv_label_create(desc, NULL); lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK); lv_label_set_recolor(lb_desc, true); - lv_label_set_static_text(lb_desc, "#D4FF00 Please wait...#"); + lv_label_set_text(lb_desc, "#D4FF00 Please wait...#"); lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); // Disable buttons. @@ -710,127 +1967,384 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn) manual_system_maintenance(true); if (!sd_mount()) - lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init SD!#"); - else { - lv_label_set_static_text(lb_desc, - "#00DDFF Card IDentification:#\n" - "Vendor ID:\n" - "OEM ID:\n" - "Model:\n" - "HW rev:\n" - "FW rev:\n" - "S/N:\n" - "Month/Year:" - ); - - lv_obj_t *val = lv_cont_create(win, NULL); - lv_obj_set_size(val, LV_HOR_RES / 9 * 2, LV_VER_RES - (LV_DPI * 11 / 7) * 5 / 2); - - lv_obj_t * lb_val = lv_label_create(val, lb_desc); - - char *txt_buf = (char *)malloc(0x1000); - - s_printf(txt_buf,"\n%02x\n%c%c\n%c%c%c%c%c\n%X\n%X\n%08x\n%02d/%04d", - sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF, - sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2], - sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4], - sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial, - sd_storage.cid.month, sd_storage.cid.year); - - lv_label_set_array_text(lb_val, txt_buf, 0x1000); - - lv_obj_set_width(lb_val, lv_obj_get_width(val)); - lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); - - lv_obj_t *desc2 = lv_cont_create(win, NULL); - lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 2, LV_VER_RES - (LV_DPI * 11 / 7) * 5 / 2); - - lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc); - - lv_label_set_static_text(lb_desc2, - "#00DDFF Card-Specific Data#\n" - "Cmd Classes:\n" - "Capacity:\n" - "Bus Width:\n" - "Current Rate:\n" - "Speed Class:\n" - "UHS Grade:\n" - "Video Class:\n" - "App perf class:\n" - "Write Protect:" - ); - lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); - lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0); - - lv_obj_t *val2 = lv_cont_create(win, NULL); - lv_obj_set_size(val2, LV_HOR_RES / 13 * 3, LV_VER_RES - (LV_DPI * 11 / 7) * 5 / 2); - - lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc); - - - s_printf(txt_buf, - "#00DDFF v%d.0#\n%02X\n%d MiB\n%d\n%d MB/s (%d MHz)\n%d\nU%d\nV%d\nA%d\n%d", - sd_storage.csd.structure + 1, sd_storage.csd.cmdclass, sd_storage.sec_cnt >> 11, - sd_storage.ssr.bus_width, sd_storage.csd.busspeed, - (sd_storage.csd.busspeed > 10) ? (sd_storage.csd.busspeed * 2) : 50, - sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, - sd_storage.ssr.app_class, sd_storage.csd.write_protect); - - lv_label_set_array_text(lb_val2, txt_buf, 0x1000); - - lv_obj_set_width(lb_val2, lv_obj_get_width(val2)); - lv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0); - - lv_obj_t *line_sep = lv_line_create(win, NULL); - static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 12, 0} }; - lv_line_set_points(line_sep, line_pp, 2); - lv_line_set_style(line_sep, lv_theme_get_current()->line.decor); - lv_obj_align(line_sep, desc, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 410 / 100, LV_DPI / 5); - - lv_obj_t *desc3 = lv_cont_create(win, NULL); - lv_obj_set_size(desc3, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4); - - lv_obj_t * lb_desc3 = lv_label_create(desc3, lb_desc); - - lv_label_set_static_text(lb_desc3, "#D4FF00 Acquiring FAT volume info...#"); - - lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3)); - lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); - - manual_system_maintenance(true); - - f_getfree("", &sd_fs.free_clst, NULL); - - lv_label_set_static_text(lb_desc3, - "#00DDFF Found FAT volume:#\n" - "Filesystem:\n" - "Cluster:\n" - "Free:" - ); - lv_obj_set_size(desc3, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4); - lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3)); - lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); - - lv_obj_t *val3 = lv_cont_create(win, NULL); - lv_obj_set_size(val3, LV_HOR_RES / 13 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4); - - lv_obj_t * lb_val3 = lv_label_create(val3, lb_desc); - - s_printf(txt_buf, "\n%s\n%d KiB\n%d MiB", - sd_fs.fs_type == FS_EXFAT ? ("exFAT "SYMBOL_SHRK) : ("FAT32"), - (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512, - sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF); - - lv_label_set_array_text(lb_val3, txt_buf, 0x1000); - - lv_obj_set_width(lb_val3, lv_obj_get_width(val3)); - lv_obj_align(val3, desc3, LV_ALIGN_OUT_RIGHT_MID, 0, 0); - - free(txt_buf); - sd_unmount(false); + lv_label_set_text(lb_desc, "#FFDD00 Failed to init SD!#"); + goto failed; } + lv_label_set_text(lb_desc, + "#00DDFF Card ID:#\n" + "Vendor ID:\n" + "Model:\n" + "OEM ID:\n" + "HW rev:\n" + "FW rev:\n" + "S/N:\n" + "Month/Year:\n\n" + "Max Power:\n" + "Initial bus:" + ); + + lv_obj_t *val = lv_cont_create(win, NULL); + lv_obj_set_size(val, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2); + + lv_obj_t * lb_val = lv_label_create(val, lb_desc); + + char *txt_buf = (char *)malloc(SZ_16K); + txt_buf[0] = '\n'; + txt_buf[1] = 0; + + // Identify manufacturer. + switch (sd_storage.cid.manfid) + { + case 0x00: + strcat(txt_buf, "Fake "); + break; + case 0x01: + strcat(txt_buf, "Panasonic "); + break; + case 0x02: + strcat(txt_buf, "Toshiba "); + break; + case 0x03: + if (!memcmp(&sd_storage.cid.oemid, "DW", 2)) + strcat(txt_buf, "Western Digital "); // WD. + else + strcat(txt_buf, "SanDisk "); + break; + case 0x06: + strcat(txt_buf, "Ritek "); + break; + case 0x09: + strcat(txt_buf, "ATP "); + break; + case 0x13: + strcat(txt_buf, "Kingmax "); + break; + case 0x19: + strcat(txt_buf, "Dynacard "); + break; + case 0x1A: + strcat(txt_buf, "Power Quotient "); + break; + case 0x1B: + strcat(txt_buf, "Samsung "); + break; + case 0x1D: + strcat(txt_buf, "AData "); + break; + case 0x27: + strcat(txt_buf, "Phison "); + break; + case 0x28: + strcat(txt_buf, "Barun Electronics "); + break; + case 0x31: + strcat(txt_buf, "Silicon Power "); + break; + case 0x41: + strcat(txt_buf, "Kingston "); + break; + case 0x51: + strcat(txt_buf, "STEC "); + break; + case 0x5D: + strcat(txt_buf, "SwissBit "); + break; + case 0x61: + strcat(txt_buf, "Netlist "); + break; + case 0x63: + strcat(txt_buf, "Cactus "); + break; + case 0x73: + strcat(txt_buf, "Bongiovi "); + break; + case 0x74: + strcat(txt_buf, "Jiaelec "); + break; + case 0x76: + strcat(txt_buf, "Patriot "); + break; + case 0x82: + strcat(txt_buf, "Jiang Tay "); + break; + case 0x83: + strcat(txt_buf, "Netcom "); + break; + case 0x84: + strcat(txt_buf, "Strontium "); + break; + case 0x9C: + if (!memcmp(&sd_storage.cid.oemid, "OS", 2)) + strcat(txt_buf, "Sony "); // SO. + else + strcat(txt_buf, "Barun Electronics "); // BE. + break; + case 0x9F: + strcat(txt_buf, "Taishin "); + break; + case 0xAD: + strcat(txt_buf, "Longsys "); + break; + default: + strcat(txt_buf, "Unknown "); + break; + } + + // UHS-I max power limit is 400mA, no matter what the card says. + u32 max_power_nominal = sd_storage.max_power > 400 ? 400 : sd_storage.max_power; + + s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c\n%c%c (%04X)\n%X\n%X\n%08x\n%02d/%04d\n\n%d mW (%d mA)\n", + sd_storage.cid.manfid, + sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2], + sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4], + (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF, sd_storage.cid.oemid, + sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial, + sd_storage.cid.month, sd_storage.cid.year, + max_power_nominal * 3600 / 1000, sd_storage.max_power); + + switch (nyx_str->info.sd_init) + { + case SD_1BIT_HS25: + strcat(txt_buf, "HS25 1bit"); + break; + case SD_4BIT_HS25: + strcat(txt_buf, "HS25"); + break; + case SD_UHS_SDR82: // Report as SDR104. + case SD_UHS_SDR104: + strcat(txt_buf, "SDR104"); + break; + case 0: + default: + strcat(txt_buf, "Undefined"); + break; + } + + lv_label_set_text(lb_val, txt_buf); + + lv_obj_set_width(lb_val, lv_obj_get_width(val)); + lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_t *desc2 = lv_cont_create(win, NULL); + lv_obj_set_size(desc2, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2); + + lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc); + + lv_label_set_static_text(lb_desc2, + "#00DDFF Card-Specific Data#\n" + "Cmd Classes:\n" + "Capacity:\n" + "Capacity (LBA):\n" + "Bus Width:\n" + "Current Rate:\n" + "Speed Class:\n" + "UHS Classes:\n" + "Max Bus Speed:\n\n" + "Write Protect:" + ); + lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); + lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0); + + lv_obj_t *val2 = lv_cont_create(win, NULL); + lv_obj_set_size(val2, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2); + + lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc); + + char *wp_info; + switch (sd_storage.csd.write_protect) + { + case 1: + wp_info = "Temporary"; + break; + case 2: + case 3: + wp_info = "Permanent"; + break; + default: + wp_info = "None"; + break; + } + + bool uhs_au_mb = false; + u32 uhs_au_size = sd_storage_get_ssr_au(&sd_storage); + if (uhs_au_size >= 1024) + { + uhs_au_mb = true; + uhs_au_size /= 1024; + } + + sd_func_modes_t fmodes = { 0 }; + sd_storage_get_fmodes(&sd_storage, NULL, &fmodes); + + char *bus_speed; + if (fmodes.cmd_system & SD_MODE_UHS_DDR200) + bus_speed = "DDR200"; + else if (fmodes.access_mode & SD_MODE_UHS_SDR104) + bus_speed = "SDR104"; + else if (fmodes.access_mode & SD_MODE_UHS_SDR50) + bus_speed = "SDR50"; + else if (fmodes.access_mode & SD_MODE_UHS_DDR50) + bus_speed = "DDR50"; + else if (fmodes.access_mode & SD_MODE_UHS_SDR25) + bus_speed = "SDR25"; + else + bus_speed = "SDR12"; + + char *cpe = NULL; + if (sd_storage.ssr.app_class == 2) + { + u8 *buf = zalloc(512); + + // Directly get and parse ext reg for performance enhance. + sd_storage_parse_perf_enhance(&sd_storage, 2, 0, 0, buf); + + bool has_perf_enhance = sd_storage.ser.cache && + sd_storage.ser.cmdq && + sd_storage.ser.cache == sd_storage.ser.cache_ext && + sd_storage.ser.cmdq == sd_storage.ser.cmdq_ext; + if (has_perf_enhance) + cpe = "#FFDD00 "; // CMDQ/CACHE support via a quirk. + else + cpe = "#FF3C28 "; // Broken. + + // Get and parse ext reg for performance enhance in spec. + sd_storage_get_ext_regs(&sd_storage, buf); + + if (sd_storage.ser.valid) + { + has_perf_enhance = sd_storage.ser.cache && + sd_storage.ser.cmdq && + sd_storage.ser.cache == sd_storage.ser.cache_ext && + sd_storage.ser.cmdq == sd_storage.ser.cmdq_ext; + + if (has_perf_enhance) + cpe = NULL; // CMDQ/CACHE support in spec. + else + cpe = "#FF3C28 "; // Broken. + } + + free(buf); + } + + s_printf(txt_buf, + "#00DDFF v%d.0#\n" + "%02X\n" + "%d MiB\n" + "%X (CP %X)\n" + "%d\n" + "%d MB/s (%d MHz)\n" + "%d (AU: %d %s\n" + "U%d V%d %sA%d%s\n" + "%s\n\n" + "%s", + sd_storage.csd.structure + 1, + sd_storage.csd.cmdclass, + sd_storage.sec_cnt >> 11, + sd_storage.sec_cnt, sd_storage.ssr.protected_size >> 9, + sd_storage.ssr.bus_width, + sd_storage.csd.busspeed, + (sd_storage.csd.busspeed > 10) ? (sd_storage.csd.busspeed * 2) : 50, + sd_storage.ssr.speed_class, uhs_au_size, uhs_au_mb ? "MiB)" : "KiB)", + sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, cpe ? cpe : "", sd_storage.ssr.app_class, cpe ? "#" : "", + bus_speed, + wp_info); + + lv_label_set_text(lb_val2, txt_buf); + + lv_obj_set_width(lb_val2, lv_obj_get_width(val2)); + lv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_t *line_sep = lv_line_create(win, NULL); + static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 12, 0} }; + lv_line_set_points(line_sep, line_pp, 2); + lv_line_set_style(line_sep, lv_theme_get_current()->line.decor); + lv_obj_align(line_sep, desc, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 410 / 100, LV_DPI / 7); + + lv_obj_t *desc3 = lv_cont_create(win, NULL); + lv_obj_set_size(desc3, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4); + + lv_obj_t * lb_desc3 = lv_label_create(desc3, lb_desc); + lv_label_set_text(lb_desc3, "#D4FF00 Acquiring info...#"); + lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3)); + + lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + + manual_system_maintenance(true); + + lv_obj_set_size(desc3, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4); + lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + + lv_obj_t *val3 = lv_cont_create(win, NULL); + lv_obj_set_size(val3, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4); + + lv_obj_t * lb_val3 = lv_label_create(val3, lb_desc); + lv_label_set_text(lb_val3, ""); + + lv_obj_align(val3, desc3, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_t *desc4 = lv_cont_create(win, NULL); + lv_obj_set_size(desc4, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4); + + lv_obj_t * lb_desc4 = lv_label_create(desc4, lb_desc); + lv_label_set_text(lb_desc4, " "); + lv_obj_set_width(lb_desc4, lv_obj_get_width(desc4)); + + lv_label_set_text(lb_desc4, + "#00DDFF SDMMC1 Errors:#\n" + "Init fails:\n" + "Read/Write fails:\n" + "Read/Write errors:" + ); + lv_obj_set_size(desc4, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 4); + lv_obj_set_width(lb_desc4, lv_obj_get_width(desc4)); + lv_obj_align(desc4, val3, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0); + + lv_obj_t *val4 = lv_cont_create(win, NULL); + lv_obj_set_size(val4, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 4); + + lv_obj_t * lb_val4 = lv_label_create(val4, lb_desc); + + u16 *sd_errors = sd_get_error_count(); + s_printf(txt_buf, "\n%d (%d)\n%d (%d)\n%d (%d)", + sd_errors[SD_ERROR_INIT_FAIL], nyx_str->info.sd_errors[SD_ERROR_INIT_FAIL], + sd_errors[SD_ERROR_RW_FAIL], nyx_str->info.sd_errors[SD_ERROR_RW_FAIL], + sd_errors[SD_ERROR_RW_RETRY], nyx_str->info.sd_errors[SD_ERROR_RW_RETRY]); + + lv_label_set_text(lb_val4, txt_buf); + + lv_obj_set_width(lb_val4, lv_obj_get_width(val4)); + lv_obj_align(val4, desc4, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + manual_system_maintenance(true); + + f_getfree("", &sd_fs.free_clst, NULL); + + lv_label_set_text(lb_desc3, + "#00DDFF Found FAT FS:#\n" + "Filesystem:\n" + "Cluster:\n" + "Size free/total:" + ); + + lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3)); + + s_printf(txt_buf, "\n%s\n%d %s\n%d/%d MiB", + sd_fs.fs_type == FS_EXFAT ? ("exFAT "SYMBOL_SHRK) : ("FAT32"), + (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : SD_BLOCKSIZE, + (sd_fs.csize > 1) ? "KiB" : "B", + (u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF), + (u32)(sd_fs.n_fatent * sd_fs.csize >> SECTORS_TO_MIB_COEFF)); + + lv_label_set_text(lb_val3, txt_buf); + + lv_obj_set_width(lb_val3, lv_obj_get_width(val3)); + + free(txt_buf); + sd_unmount(); + +failed: nyx_window_toggle_buttons(win, false); return LV_RES_OK; @@ -851,7 +2365,6 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) lv_label_set_static_text(lb_desc, "#00DDFF Fuel Gauge IC Info:#\n" "Capacity now:\n" - "Capacity now:\n" "Capacity full:\n" "Capacity (design):\n" "Current now:\n" @@ -862,6 +2375,9 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) "Max voltage reached:\n" "Empty voltage:\n" "Battery temp:\n\n" + "#00DDFF PMIC IC Info:#\n" + "Main PMIC:\n\n" + "CPU/GPU PMIC:\n" ); lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); @@ -870,37 +2386,33 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) lv_obj_t * lb_val = lv_label_create(val, lb_desc); - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); int value = 0; + int cap_pct = 0; - max17050_get_property(MAX17050_RepSOC, &value); - s_printf(txt_buf, "\n%d %\n", value >> 8); - + // Fuel gauge IC info. + max17050_get_property(MAX17050_RepSOC, &cap_pct); max17050_get_property(MAX17050_RepCap, &value); - s_printf(txt_buf + strlen(txt_buf), "%d mAh\n", value); + s_printf(txt_buf, "\n%d mAh [%d %%]\n", value, cap_pct >> 8); max17050_get_property(MAX17050_FullCAP, &value); s_printf(txt_buf + strlen(txt_buf), "%d mAh\n", value); max17050_get_property(MAX17050_DesignCap, &value); - s_printf(txt_buf + strlen(txt_buf), "%d mAh\n", value); + bool design_cap_init = value == 1000; + s_printf(txt_buf + strlen(txt_buf), "%s%d mAh%s\n", + design_cap_init ? "#FF8000 " : "", value, design_cap_init ? " - Init "SYMBOL_WARNING"#" : ""); max17050_get_property(MAX17050_Current, &value); - if (value >= 0) - s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value / 1000); - else - s_printf(txt_buf + strlen(txt_buf), "-%d mA\n", (~value + 1) / 1000); + s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value / 1000); max17050_get_property(MAX17050_AvgCurrent, &value); - if (value >= 0) - s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value / 1000); - else - s_printf(txt_buf + strlen(txt_buf), "-%d mA\n", (~value + 1) / 1000); + s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value / 1000); max17050_get_property(MAX17050_VCELL, &value); bool voltage_empty = value < 3200; s_printf(txt_buf + strlen(txt_buf), "%s%d mV%s\n", - voltage_empty ? "#FF8000 " : "", value, voltage_empty ? " "SYMBOL_WARNING"#" : ""); + voltage_empty ? "#FF8000 " : "", value, voltage_empty ? " - Low "SYMBOL_WARNING"#" : ""); max17050_get_property(MAX17050_OCVInternal, &value); s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value); @@ -915,12 +2427,38 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value); max17050_get_property(MAX17050_TEMP, &value); - if (value >= 0) - s_printf(txt_buf + strlen(txt_buf), "%d.%d oC\n", value / 10, value % 10); - else - s_printf(txt_buf + strlen(txt_buf), "-%d.%d oC\n", (~value + 1) / 10, (~value + 1) % 10); + s_printf(txt_buf + strlen(txt_buf), "%d.%d oC\n\n\n", value / 10, (value >= 0 ? value : (~value + 1)) % 10); - lv_label_set_array_text(lb_val, txt_buf, 0x1000); + // Main Pmic IC info. + value = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4); + u32 main_pmic_version = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID3) & 0xF; + + if (value == 0x35) + s_printf(txt_buf + strlen(txt_buf), "max77620 v%d\nErista OTP\n", main_pmic_version); + else if (value == 0x53) + s_printf(txt_buf + strlen(txt_buf), "max77620 v%d\nMariko OTP\n", main_pmic_version); + else + s_printf(txt_buf + strlen(txt_buf), "max77620 v%d\n#FF8000 Unknown OTP# (%02X)\n", main_pmic_version, value); + + // CPU/GPU/DRAM Pmic IC info. + u32 cpu_gpu_pmic_type = h_cfg.t210b01 ? (FUSE(FUSE_RESERVED_ODM28_B01) & 1) + 1 : 0; + switch (cpu_gpu_pmic_type) + { + case 0: + s_printf(txt_buf + strlen(txt_buf), "max77621 v%d", + i2c_recv_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_REG_CHIPID1)); + break; + case 1: + s_printf(txt_buf + strlen(txt_buf), "max77812-2 v%d", // High power GPU. 2 Outputs, phases 3 1. + i2c_recv_byte(I2C_5, MAX77812_PHASE31_CPU_I2C_ADDR, MAX77812_REG_VERSION) & 7); + break; + case 2: + s_printf(txt_buf + strlen(txt_buf), "max77812-3 v%d.0", // Low power GPU. 3 Outputs, phases 2 1 1. + i2c_recv_byte(I2C_5, MAX77812_PHASE211_CPU_I2C_ADDR, MAX77812_REG_VERSION) & 7); + break; + } + + lv_label_set_text(lb_val, txt_buf); lv_obj_set_width(lb_val, lv_obj_get_width(val)); lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0); @@ -932,13 +2470,16 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) lv_label_set_static_text(lb_desc2, "#00DDFF Battery Charger IC Info:#\n" - "Input voltage limit:\n" "Input current limit:\n" - "Min voltage limit:\n" - "Fast charge current limit:\n" + "System voltage limit:\n" + "Charge current limit:\n" "Charge voltage limit:\n" "Charge status:\n" - "Temperature status:" + "Temperature status:\n\n" + "#00DDFF USB-PD IC Info:#\n" + "Connection status:\n" + "Input Wattage Limit:\n" + "USB-PD Profiles:" ); lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0); @@ -948,11 +2489,10 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc); - bq24193_get_property(BQ24193_InputVoltageLimit, &value); - s_printf(txt_buf, "\n%d mV\n", value); - - bq24193_get_property(BQ24193_InputCurrentLimit, &value); - s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value); + // Charger IC info. + int iinlim = 0; + bq24193_get_property(BQ24193_InputCurrentLimit, &iinlim); + s_printf(txt_buf, "\n%d mA\n", iinlim); bq24193_get_property(BQ24193_SystemMinimumVoltage, &value); s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value); @@ -967,16 +2507,16 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) switch (value) { case 0: - s_printf(txt_buf + strlen(txt_buf), "Not charging\n"); + strcat(txt_buf, "Not charging\n"); break; case 1: - s_printf(txt_buf + strlen(txt_buf), "Pre-charging\n"); + strcat(txt_buf, "Pre-charging\n"); break; case 2: - s_printf(txt_buf + strlen(txt_buf), "Fast charging\n"); + strcat(txt_buf, "Fast charging\n"); break; case 3: - s_printf(txt_buf + strlen(txt_buf), "Charge terminated\n"); + strcat(txt_buf, "Charge terminated\n"); break; default: s_printf(txt_buf + strlen(txt_buf), "Unknown (%d)\n", value); @@ -987,26 +2527,56 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) switch (value) { case 0: - s_printf(txt_buf + strlen(txt_buf), "Normal"); + strcat(txt_buf, "Normal"); break; case 2: - s_printf(txt_buf + strlen(txt_buf), "Warm"); + strcat(txt_buf, "Warm"); break; case 3: - s_printf(txt_buf + strlen(txt_buf), "Cool"); + strcat(txt_buf, "Cool"); break; case 5: - s_printf(txt_buf + strlen(txt_buf), "Cold"); + strcat(txt_buf, "#FF8000 Cold#"); break; case 6: - s_printf(txt_buf + strlen(txt_buf), "Hot"); + strcat(txt_buf, "#FF8000 Hot#"); break; default: s_printf(txt_buf + strlen(txt_buf), "Unknown (%d)", value); break; } - lv_label_set_array_text(lb_val2, txt_buf, 0x1000); + // USB-PD IC info. + bool inserted; + u32 wattage = 0; + usb_pd_objects_t usb_pd; + bm92t36_get_sink_info(&inserted, &usb_pd); + strcat(txt_buf, "\n\n\n"); + strcat(txt_buf, inserted ? "Connected" : "Disconnected"); + + // Select 5V is no PD contract. + wattage = iinlim * (usb_pd.pdo_no ? usb_pd.selected_pdo.voltage : 5); + + s_printf(txt_buf + strlen(txt_buf), "\n%d.%d W", wattage / 1000, (wattage % 1000) / 100); + + if (!usb_pd.pdo_no) + strcat(txt_buf, "\nNon PD"); + + // Limit to 6 profiles so it can fit. + usb_pd.pdo_no = MIN(usb_pd.pdo_no, 6); + + for (u32 i = 0; i < usb_pd.pdo_no; i++) + { + bool selected = + usb_pd.pdos[i].amperage == usb_pd.selected_pdo.amperage && + usb_pd.pdos[i].voltage == usb_pd.selected_pdo.voltage; + s_printf(txt_buf + strlen(txt_buf), "\n%s%d mA, %2d V%s", + selected ? "#D4FF00 " : "", + usb_pd.pdos[i].amperage, usb_pd.pdos[i].voltage, + selected ? "#" : ""); + } + + lv_label_set_text(lb_val2, txt_buf); lv_obj_set_width(lb_val2, lv_obj_get_width(val2)); lv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0); @@ -1016,6 +2586,45 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn) return LV_RES_OK; } +static bool _lockpick_exists_check() +{ + #define LOCKPICK_MAGIC_OFFSET 0x118 + #define LOCKPICK_VERSION_OFFSET 0x11C + #define LOCKPICK_MAGIC 0x4B434F4C // LOCK. + #define LOCKPICK_MIN_VERSION 0x1090500 // 1.9.5. + + bool found = false; + void *buf = malloc(0x200); + if (sd_mount()) + { + FIL fp; + if (f_open(&fp, "bootloader/payloads/Lockpick_RCM.bin", FA_READ)) + goto out; + + // Read Lockpick payload and check versioning. + if (f_read(&fp, buf, 0x200, NULL)) + { + f_close(&fp); + + goto out; + } + + u32 magic = *(u32 *)(buf + LOCKPICK_MAGIC_OFFSET); + u32 version = byte_swap_32(*(u32 *)(buf + LOCKPICK_VERSION_OFFSET) - 0x303030); + + if (magic == LOCKPICK_MAGIC && version >= LOCKPICK_MIN_VERSION) + found = true; + + f_close(&fp); + } + +out: + free(buf); + sd_unmount(); + + return found; +} + void create_tab_info(lv_theme_t *th, lv_obj_t *parent) { lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY); @@ -1038,7 +2647,7 @@ void create_tab_info(lv_theme_t *th, lv_obj_t *parent) lv_label_set_static_text(label_sep, ""); lv_obj_t *label_txt = lv_label_create(h1, NULL); - lv_label_set_static_text(label_txt, "SoC Info"); + lv_label_set_static_text(label_txt, "SoC & HW Info"); lv_obj_set_style(label_txt, th->label.prim); lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, 0); @@ -1064,15 +2673,30 @@ void create_tab_info(lv_theme_t *th, lv_obj_t *parent) // Create TSEC Keys button. lv_obj_t *btn2 = lv_btn_create(h1, btn); label_btn = lv_label_create(btn2, NULL); - lv_label_set_static_text(label_btn, SYMBOL_KEY" TSEC Keys"); - lv_obj_align(btn2, btn, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 4 / 9, 0); - lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_window_tsec_keys_status); + lv_label_set_static_text(label_btn, SYMBOL_KEY" Lockpick"); + lv_obj_align(btn2, btn, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 11 / 15, 0); + lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_mbox_lockpick); + + bool lockpick_found = _lockpick_exists_check(); + if (!lockpick_found) + lv_btn_set_state(btn2, LV_BTN_STATE_INA); lv_obj_t *label_txt2 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt2, true); - lv_label_set_static_text(label_txt2, - "View Ipatches and dump the unpatched and patched versions\nof BootROM.\n" - "Or view and dump the device's TSEC Keys.\n"); + + if (lockpick_found) + { + lv_label_set_static_text(label_txt2, + "View Ipatches and dump the unpatched and patched versions\nof BootROM.\n" + "Or dump every single key via #C7EA46 Lockpick RCM#.\n"); + } + else + { + lv_label_set_static_text(label_txt2, + "View Ipatches and dump the unpatched and patched versions\nof BootROM. Or dump every single key via #C7EA46 Lockpick RCM#.\n" + "#FFDD00 bootloader/payloads/Lockpick_RCM.bin is missing or old!#\n"); + } + lv_obj_set_style(label_txt2, &hint_small_style); lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); @@ -1088,23 +2712,23 @@ void create_tab_info(lv_theme_t *th, lv_obj_t *parent) lv_obj_t *btn3 = lv_btn_create(h1, btn); label_btn = lv_label_create(btn3, NULL); lv_btn_set_fit(btn3, true, true); - lv_label_set_static_text(label_btn, SYMBOL_CIRCUIT" Fuses "); + lv_label_set_static_text(label_btn, SYMBOL_CIRCUIT" HW & Fuses"); lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 2); - lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_fuses_info_status); + lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_hw_info_status); // Create KFuses button. lv_obj_t *btn4 = lv_btn_create(h1, btn); label_btn = lv_label_create(btn4, NULL); lv_label_set_static_text(label_btn, SYMBOL_SHUFFLE" KFuses"); - lv_obj_align(btn4, btn3, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 123 / 100, 0); + lv_obj_align(btn4, btn3, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 46 / 100, 0); lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _kfuse_dump_window_action); lv_obj_t *label_txt4 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt4, true); lv_label_set_static_text(label_txt4, - "View and dump your cached fuses and KFuses.\n" - "Fuses contain info about your SoC and device and KFuses\n" - "contain downstream and upstream HDCP keys used by HDMI."); + "View and dump the cached #C7EA46 Fuses# and #C7EA46 KFuses#.\n" + "Fuses contain info about the SoC/SKU and KFuses HDCP keys.\n" + "You can also see info about #C7EA46 DRAM#, #C7EA46 Screen# and #C7EA46 Touch panel#."); lv_obj_set_style(label_txt4, &hint_small_style); lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); @@ -1152,8 +2776,8 @@ void create_tab_info(lv_theme_t *th, lv_obj_t *parent) lv_obj_t *label_txt5 = lv_label_create(h2, NULL); lv_label_set_recolor(label_txt5, true); lv_label_set_static_text(label_txt5, - "View info about your eMMC or microSD and additionally\n" - "view their partition list and info."); + "View info about the eMMC or microSD and their partition list.\n" + "Additionally you can benchmark read speeds."); lv_obj_set_style(label_txt5, &hint_small_style); lv_obj_align(label_txt5, btn5, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); diff --git a/nyx/nyx_gui/frontend/gui_info.h b/nyx/nyx_gui/frontend/gui_info.h index f729957..d0f102e 100644 --- a/nyx/nyx_gui/frontend/gui_info.h +++ b/nyx/nyx_gui/frontend/gui_info.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,8 +17,9 @@ #ifndef _GUI_INFO_H_ #define _GUI_INFO_H_ -#include "../libs/lvgl/lvgl.h" +#include void create_tab_info(lv_theme_t *th, lv_obj_t *parent); +int dump_cal0(); #endif diff --git a/nyx/nyx_gui/frontend/gui_options.c b/nyx/nyx_gui/frontend/gui_options.c index 2cfca4c..15feeac 100644 --- a/nyx/nyx_gui/frontend/gui_options.c +++ b/nyx/nyx_gui/frontend/gui_options.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,25 +14,43 @@ * along with this program. If not, see . */ +#include + +#include + #include "gui.h" -#include "../config/config.h" -#include "../config/ini.h" -#include "../gfx/di.h" -#include "../libs/lvgl/lvgl.h" -#include "../utils/list.h" -#include "../utils/types.h" +#include "gui_info.h" +#include "../config.h" +#include +#include + +#define CLOCK_MIN_YEAR 2025 +#define CLOCK_MAX_YEAR (CLOCK_MIN_YEAR + 10) +#define CLOCK_YEARLIST "2025\n2026\n2027\n2028\n2029\n2030\n2031\n2032\n2033\n2034\n2035" extern hekate_config h_cfg; - -extern bool sd_mount(); -extern void sd_unmount(bool deinit); +extern nyx_config n_cfg; static lv_obj_t *autoboot_btn; static bool autoboot_first_time = true; +static bool ini_changes_made = false; +static bool nyx_changes_made = false; + +void nyx_options_clear_ini_changes_made() +{ + ini_changes_made = false; +} + +bool nyx_options_get_ini_changes_made() +{ + return ini_changes_made; +} + static lv_res_t auto_hos_poweroff_toggle(lv_obj_t *btn) { h_cfg.autohosoff = !h_cfg.autohosoff; + ini_changes_made = true; if (!h_cfg.autohosoff) lv_btn_set_state(btn, LV_BTN_STATE_REL); @@ -47,6 +65,7 @@ static lv_res_t auto_hos_poweroff_toggle(lv_obj_t *btn) static lv_res_t auto_nogc_toggle(lv_obj_t *btn) { h_cfg.autonogc = !h_cfg.autonogc; + ini_changes_made = true; if (!h_cfg.autonogc) lv_btn_set_state(btn, LV_BTN_STATE_REL); @@ -58,6 +77,21 @@ static lv_res_t auto_nogc_toggle(lv_obj_t *btn) return LV_RES_OK; } +static lv_res_t _update_r2p_action(lv_obj_t *btn) +{ + h_cfg.updater2p = !h_cfg.updater2p; + ini_changes_made = true; + + if (!h_cfg.updater2p) + lv_btn_set_state(btn, LV_BTN_STATE_REL); + else + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + + nyx_generic_onoff_toggle(btn); + + return LV_RES_OK; +} + static lv_res_t _win_autoboot_close_action(lv_obj_t * btn) { if (!h_cfg.autoboot) @@ -71,6 +105,8 @@ static lv_res_t _win_autoboot_close_action(lv_obj_t * btn) lv_obj_del(win); + close_btn = NULL; + return LV_RES_INV; } @@ -79,7 +115,7 @@ lv_obj_t *create_window_autoboot(const char *win_title) static lv_style_t win_bg_style; lv_style_copy(&win_bg_style, &lv_style_plain); - win_bg_style.body.main_color = LV_COLOR_HEX(0x2D2D2D);// TODO: COLOR_HOS_BG + win_bg_style.body.main_color = LV_COLOR_HEX(theme_bg_color); win_bg_style.body.grad_color = win_bg_style.body.main_color; lv_obj_t *win = lv_win_create(lv_scr_act(), NULL); @@ -87,16 +123,16 @@ lv_obj_t *create_window_autoboot(const char *win_title) lv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style); lv_obj_set_size(win, LV_HOR_RES, LV_VER_RES); - lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", _win_autoboot_close_action); + close_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", _win_autoboot_close_action); return win; } -// TODO: instant update of button for these. static lv_res_t _autoboot_disable_action(lv_obj_t *btn) { h_cfg.autoboot = 0; h_cfg.autoboot_list = 0; + ini_changes_made = true; lv_btn_set_state(autoboot_btn, LV_BTN_STATE_REL); nyx_generic_onoff_toggle(autoboot_btn); @@ -105,6 +141,8 @@ static lv_res_t _autoboot_disable_action(lv_obj_t *btn) lv_obj_del(win); + close_btn = NULL; + return LV_RES_OK; } @@ -114,6 +152,7 @@ static lv_res_t _autoboot_enable_main_action(lv_obj_t *btn) { h_cfg.autoboot = lv_list_get_btn_index(auto_main_list, btn) + 1; h_cfg.autoboot_list = 0; + ini_changes_made = true; lv_btn_set_state(autoboot_btn, LV_BTN_STATE_TGL_REL); nyx_generic_onoff_toggle(autoboot_btn); @@ -123,6 +162,8 @@ static lv_res_t _autoboot_enable_main_action(lv_obj_t *btn) obj = lv_obj_get_parent(obj); lv_obj_del(obj); + close_btn = NULL; + return LV_RES_INV; } @@ -130,6 +171,7 @@ static lv_res_t _autoboot_enable_more_action(lv_obj_t *btn) { h_cfg.autoboot = lv_list_get_btn_index(auto_more_list, btn) + 1; h_cfg.autoboot_list = 1; + ini_changes_made = true; lv_btn_set_state(autoboot_btn, LV_BTN_STATE_TGL_REL); nyx_generic_onoff_toggle(autoboot_btn); @@ -139,6 +181,8 @@ static lv_res_t _autoboot_enable_more_action(lv_obj_t *btn) obj = lv_obj_get_parent(obj); lv_obj_del(obj); + close_btn = NULL; + return LV_RES_INV; } @@ -185,6 +229,7 @@ static void _create_autoboot_window() sd_mount(); + // Parse hekate main configuration. LIST_INIT(ini_sections); if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) { @@ -195,6 +240,8 @@ static void _create_autoboot_window() lv_list_add(list_main, NULL, ini_sec->name, _autoboot_enable_main_action); } + + ini_free(&ini_sections); } // More configuration container. @@ -226,6 +273,7 @@ static void _create_autoboot_window() lv_obj_set_size(list_more_cfg, LV_HOR_RES * 4 / 10, LV_VER_RES * 4 / 7); lv_list_set_single_mode(list_more_cfg, true); + // Parse all .ini files in ini folder. LIST_INIT(ini_list_sections); if (ini_parse(&ini_list_sections, "bootloader/ini", true)) { @@ -236,9 +284,11 @@ static void _create_autoboot_window() lv_list_add(list_more_cfg, NULL, ini_sec->name, _autoboot_enable_more_action); } + + ini_free(&ini_list_sections); } - sd_unmount(false); + sd_unmount(); } static lv_res_t _autoboot_hide_delay_action(lv_obj_t *btn) @@ -259,7 +309,12 @@ static lv_res_t _autoboot_hide_delay_action(lv_obj_t *btn) static lv_res_t _autoboot_delay_action(lv_obj_t *ddlist) { - h_cfg.bootwait = lv_ddlist_get_selected(ddlist); + u32 new_selection = lv_ddlist_get_selected(ddlist); + if (h_cfg.bootwait != new_selection) + { + h_cfg.bootwait = new_selection; + ini_changes_made = true; + } return LV_RES_OK; } @@ -268,13 +323,1039 @@ static lv_res_t _slider_brightness_action(lv_obj_t * slider) { display_backlight_brightness(lv_slider_get_value(slider) - 20, 0); h_cfg.backlight = lv_slider_get_value(slider); + ini_changes_made = true; return LV_RES_OK; } static lv_res_t _data_verification_action(lv_obj_t *ddlist) { - h_cfg.verification = lv_ddlist_get_selected(ddlist); + u32 new_selection = lv_ddlist_get_selected(ddlist); + if (n_cfg.verification != new_selection) + { + n_cfg.verification = new_selection; + nyx_changes_made = true; + } + + return LV_RES_OK; +} + +static lv_res_t _entries_columns_action(lv_obj_t *btn) +{ + n_cfg.entries_5_col = !n_cfg.entries_5_col; + nyx_changes_made = true; + + if (!n_cfg.entries_5_col) + lv_btn_set_state(btn, LV_BTN_STATE_REL); + else + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + + nyx_generic_onoff_toggle(btn); + + return LV_RES_OK; +} + +static lv_res_t _save_nyx_options_action(lv_obj_t *btn) +{ + static const char * mbox_btn_map[] = {"\251", "\222OK!", "\251", ""}; + lv_obj_t * mbox = lv_mbox_create(lv_scr_act(), NULL); + lv_mbox_set_recolor_text(mbox, true); + + int res = !create_nyx_config_entry(true); + + nyx_changes_made = false; + + if (res) + lv_mbox_set_text(mbox, "#FF8000 Nyx Configuration#\n\n#96FF00 The configuration was saved to sd card!#"); + else + lv_mbox_set_text(mbox, "#FF8000 Nyx Configuration#\n\n#FFDD00 Failed to save the configuration#\n#FFDD00 to sd card!#"); + lv_mbox_add_btns(mbox, mbox_btn_map, NULL); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +void create_flat_button(lv_obj_t *parent, lv_obj_t *btn, lv_color_t color, lv_action_t action) +{ + lv_style_t *btn_onoff_rel_hos_style = malloc(sizeof(lv_style_t)); + lv_style_t *btn_onoff_pr_hos_style = malloc(sizeof(lv_style_t)); + lv_style_copy(btn_onoff_rel_hos_style, lv_theme_get_current()->btn.rel); + btn_onoff_rel_hos_style->body.main_color = color; + btn_onoff_rel_hos_style->body.grad_color = btn_onoff_rel_hos_style->body.main_color; + btn_onoff_rel_hos_style->body.padding.hor = 0; + btn_onoff_rel_hos_style->body.radius = 0; + + lv_style_copy(btn_onoff_pr_hos_style, lv_theme_get_current()->btn.pr); + btn_onoff_pr_hos_style->body.main_color = color; + btn_onoff_pr_hos_style->body.grad_color = btn_onoff_pr_hos_style->body.main_color; + btn_onoff_pr_hos_style->body.padding.hor = 0; + btn_onoff_pr_hos_style->body.border.color = LV_COLOR_GRAY; + btn_onoff_pr_hos_style->body.border.width = 4; + btn_onoff_pr_hos_style->body.radius = 0; + + lv_btn_set_style(btn, LV_BTN_STYLE_REL, btn_onoff_rel_hos_style); + lv_btn_set_style(btn, LV_BTN_STYLE_PR, btn_onoff_pr_hos_style); + lv_btn_set_style(btn, LV_BTN_STYLE_TGL_REL, btn_onoff_rel_hos_style); + lv_btn_set_style(btn, LV_BTN_STYLE_TGL_PR, btn_onoff_pr_hos_style); + + lv_btn_set_fit(btn, false, true); + lv_obj_set_width(btn, lv_obj_get_height(btn)); + lv_btn_set_toggle(btn, true); + + if (action) + lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, action); +} + +typedef struct _color_test_ctxt +{ + u32 bg; + u16 hue; + lv_obj_t *window; + lv_obj_t *header1; + lv_obj_t *header2; + lv_obj_t *label; + lv_obj_t *icons; + lv_obj_t *slider; + lv_obj_t *button; + lv_obj_t *hue_slider; + lv_obj_t *hue_label; +} color_test_ctxt; + +color_test_ctxt color_test; + +static lv_res_t _save_theme_color_action(lv_obj_t *btn) +{ + n_cfg.theme_bg = color_test.bg; + n_cfg.theme_color = color_test.hue; + + // Save nyx config. + create_nyx_config_entry(true); + + reload_nyx(NULL, false); + + return LV_RES_OK; +} + +static void _show_new_nyx_color(u32 bg, u16 hue, bool update_bg) +{ + lv_color_t bgc = LV_COLOR_HEX(bg); + lv_color_t bgc_light = LV_COLOR_HEX(bg ? (bg + 0x101010) : 0x2D2D2D); + lv_color_t bg_border = LV_COLOR_HEX(bg ? (bg + 0x202020) : 0x3D3D3D); + lv_color_t color = lv_color_hsv_to_rgb(hue, 100, 100); + + if (update_bg) + { + static lv_style_t win_bg_test; + lv_style_copy(&win_bg_test, lv_win_get_style(color_test.window, LV_WIN_STYLE_BG)); + win_bg_test.body.main_color = bgc; + win_bg_test.body.grad_color = win_bg_test.body.main_color; + lv_win_set_style(color_test.window, LV_WIN_STYLE_BG, &win_bg_test); + + static lv_style_t win_hdr_test; + lv_style_copy(&win_hdr_test, lv_win_get_style(color_test.window, LV_WIN_STYLE_HEADER)); + win_hdr_test.body.main_color = bgc; + win_hdr_test.body.grad_color = win_hdr_test.body.main_color; + lv_win_set_style(color_test.window, LV_WIN_STYLE_HEADER, &win_hdr_test); + + static lv_style_t hdr1_bg_test; + lv_style_copy(&hdr1_bg_test, lv_cont_get_style(color_test.header1)); + hdr1_bg_test.body.main_color = bgc; + hdr1_bg_test.body.grad_color = hdr1_bg_test.body.main_color; + lv_cont_set_style(color_test.header1, &hdr1_bg_test); + + static lv_style_t hdr2_bg_test; + lv_style_copy(&hdr2_bg_test, lv_cont_get_style(color_test.header2)); + hdr2_bg_test.body.main_color = bgc; + hdr2_bg_test.body.grad_color = hdr2_bg_test.body.main_color; + lv_cont_set_style(color_test.header2, &hdr2_bg_test); + } + else + { + static lv_style_t txt_test; + lv_style_copy(&txt_test, lv_label_get_style(color_test.label)); + txt_test.text.color = color; + lv_obj_set_style(color_test.label, &txt_test); + lv_obj_set_style(color_test.icons, &txt_test); + } + + static lv_style_t btn_tgl_pr_test; + lv_style_copy(&btn_tgl_pr_test, lv_btn_get_style(color_test.button, LV_BTN_STATE_TGL_PR)); + btn_tgl_pr_test.body.main_color = bgc_light; + btn_tgl_pr_test.body.grad_color = btn_tgl_pr_test.body.main_color; + btn_tgl_pr_test.body.border.color = color; + btn_tgl_pr_test.text.color = color; + lv_btn_set_style(color_test.button, LV_BTN_STATE_TGL_PR, &btn_tgl_pr_test); + + static lv_style_t slider_bg, slider_test, slider_ind; + lv_style_copy(&slider_bg, lv_slider_get_style(color_test.slider, LV_SLIDER_STYLE_BG)); + lv_style_copy(&slider_test, lv_slider_get_style(color_test.slider, LV_SLIDER_STYLE_KNOB)); + lv_style_copy(&slider_ind, lv_slider_get_style(color_test.slider, LV_SLIDER_STYLE_INDIC)); + slider_bg.body.main_color = bg_border; + slider_bg.body.grad_color = slider_bg.body.main_color; + slider_test.body.main_color = color; + slider_test.body.grad_color = slider_test.body.main_color; + slider_ind.body.main_color = lv_color_hsv_to_rgb(hue, 100, 72); + slider_ind.body.grad_color = slider_ind.body.main_color; + lv_slider_set_style(color_test.slider, LV_SLIDER_STYLE_BG, &slider_bg); + lv_slider_set_style(color_test.slider, LV_SLIDER_STYLE_KNOB, &slider_test); + lv_slider_set_style(color_test.slider, LV_SLIDER_STYLE_INDIC, &slider_ind); +} + +static lv_res_t _slider_hue_action(lv_obj_t *slider) +{ + if (color_test.hue != lv_slider_get_value(slider)) + { + color_test.hue = lv_slider_get_value(slider); + _show_new_nyx_color(color_test.bg, color_test.hue, false); + char hue[8]; + s_printf(hue, "%03d", color_test.hue); + lv_label_set_text(color_test.hue_label, hue); + } + + return LV_RES_OK; +} + +static lv_res_t _preset_bg_action(lv_obj_t *btn) +{ + //! TODO: Support a range? + if (color_test.bg) + color_test.bg = 0; + else + color_test.bg = COLOR_HOS_BG; + _show_new_nyx_color(color_test.bg, color_test.hue, true); + + return LV_RES_OK; +} + +static lv_res_t _preset_hue_action(lv_obj_t *btn) +{ + lv_btn_ext_t *ext = lv_obj_get_ext_attr(btn); + + if (color_test.hue != ext->idx) + { + color_test.hue = ext->idx; + _show_new_nyx_color(color_test.bg, color_test.hue, false); + char hue[8]; + s_printf(hue, "%03d", color_test.hue); + lv_label_set_text(color_test.hue_label, hue); + lv_bar_set_value(color_test.hue_slider, color_test.hue); + } + + return LV_RES_OK; +} + +static const u16 theme_colors[17] = { + 4, 13, 23, 33, 43, 54, 66, 89, 124, 167, 187, 200, 208, 231, 261, 291, 341 +}; + +static lv_res_t _create_window_nyx_colors(lv_obj_t *btn) +{ + lv_obj_t *win = nyx_create_standard_window(SYMBOL_COPY" Nyx Color Theme"); + lv_win_add_btn(win, NULL, SYMBOL_HINT" Toggle Background", _preset_bg_action); + lv_win_add_btn(win, NULL, SYMBOL_SAVE" Save & Reload", _save_theme_color_action); + color_test.window = win; + + // Set current theme colors. + color_test.bg = n_cfg.theme_bg; + color_test.hue = n_cfg.theme_color; + + lv_obj_t *sep = lv_label_create(win, NULL); + lv_label_set_static_text(sep, ""); + lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(win, NULL); + lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES / 7); + color_test.header1 = h1; + + // Create color preset buttons. + lv_obj_t *color_btn = lv_btn_create(h1, NULL); + lv_btn_ext_t *ext = lv_obj_get_ext_attr(color_btn); + ext->idx = theme_colors[0]; + create_flat_button(h1, color_btn, lv_color_hsv_to_rgb(theme_colors[0], 100, 100), _preset_hue_action); + lv_obj_t *color_btn2; + + for (u32 i = 1; i < 17; i++) + { + color_btn2 = lv_btn_create(h1, NULL); + ext = lv_obj_get_ext_attr(color_btn2); + ext->idx = theme_colors[i]; + create_flat_button(h1, color_btn2, lv_color_hsv_to_rgb(theme_colors[i], 100, 100), _preset_hue_action); + lv_obj_align(color_btn2, color_btn, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + color_btn = color_btn2; + } + + lv_obj_align(h1, sep, LV_ALIGN_OUT_BOTTOM_MID, 0, LV_DPI / 4); + + // Create hue slider. + lv_obj_t * slider = lv_slider_create(win, NULL); + lv_obj_set_width(slider, 1070); + lv_obj_set_height(slider, LV_DPI * 4 / 10); + lv_bar_set_range(slider, 0, 359); + lv_bar_set_value(slider, color_test.hue); + lv_slider_set_action(slider, _slider_hue_action); + lv_obj_align(slider, h1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + color_test.hue_slider = slider; + + // Create hue label. + lv_obj_t *hue_text_label = lv_label_create(win, NULL); + lv_obj_align(hue_text_label, slider, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 24 / 100, 0); + char hue[8]; + s_printf(hue, "%03d", color_test.hue); + lv_label_set_text(hue_text_label, hue); + color_test.hue_label = hue_text_label; + + // Create sample text. + lv_obj_t *h2 = lv_cont_create(win, NULL); + lv_obj_set_size(h2, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES / 3); + lv_obj_align(h2, slider, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI); + color_test.header2 = h2; + + lv_obj_t *lbl_sample = lv_label_create(h2, NULL); + lv_label_set_static_text(lbl_sample, "Sample:"); + + lv_obj_t *lbl_test = lv_label_create(h2, NULL); + lv_label_set_long_mode(lbl_test, LV_LABEL_LONG_BREAK); + lv_label_set_static_text(lbl_test, + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip ex ea commodo consequat."); + lv_obj_set_width(lbl_test, lv_obj_get_width(h2) - LV_DPI * 6 / 10); + lv_obj_align(lbl_test, lbl_sample, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5); + color_test.label = lbl_test; + + // Create sample icons. + lv_obj_t *lbl_icons = lv_label_create(h2, NULL); + lv_label_set_static_text(lbl_icons, + SYMBOL_BRIGHTNESS SYMBOL_CHARGE SYMBOL_FILE SYMBOL_DRIVE SYMBOL_FILE_CODE + SYMBOL_EDIT SYMBOL_HINT SYMBOL_DRIVE SYMBOL_KEYBOARD SYMBOL_POWER); + lv_obj_align(lbl_icons, lbl_test, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 2 / 5); + color_test.icons = lbl_icons; + + // Create sample slider. + lv_obj_t *slider_test = lv_slider_create(h2, NULL); + lv_obj_align(slider_test, lbl_test, LV_ALIGN_OUT_BOTTOM_MID, 0, LV_DPI * 2 / 5); + lv_obj_set_click(slider_test, false); + lv_bar_set_value(slider_test, 60); + color_test.slider = slider_test; + + // Create sample button. + lv_obj_t *btn_test = lv_btn_create(h2, NULL); + lv_btn_set_state(btn_test, LV_BTN_STATE_TGL_PR); + lv_obj_align(btn_test, lbl_test, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 5); + lv_label_create(btn_test, NULL); + lv_obj_set_click(btn_test, false); + color_test.button = btn_test; + + _show_new_nyx_color(color_test.bg, color_test.hue, false); + + return LV_RES_OK; +} + +typedef struct _time_edit_obj_t +{ + lv_obj_t *year; + lv_obj_t *month; + lv_obj_t *day; + lv_obj_t *hour; + lv_obj_t *min; +} time_edit_obj_t; + +time_edit_obj_t clock_ctxt; + +static lv_res_t _action_clock_edit(lv_obj_t *btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + if (btn_idx == 1) + { + rtc_time_t time; + max77620_rtc_get_time(&time); + u32 epoch = max77620_rtc_date_to_epoch(&time); + + u32 year = lv_roller_get_selected(clock_ctxt.year); + u32 month = lv_roller_get_selected(clock_ctxt.month) + 1; + u32 day = lv_roller_get_selected(clock_ctxt.day) + 1; + u32 hour = lv_roller_get_selected(clock_ctxt.hour); + u32 min = lv_roller_get_selected(clock_ctxt.min); + + switch (month) + { + case 2: + if (!(year % 4) && day > 29) + day = 29; + else if (day > 28) + day = 28; + break; + case 4: + case 6: + case 9: + case 11: + if (day > 30) + day = 30; + break; + } + + time.year = year + CLOCK_MIN_YEAR; + time.month = month; + time.day = day; + time.hour = hour; + time.min = min; + + u32 new_epoch = max77620_rtc_date_to_epoch(&time); + + // Stored in u32 and allow overflow for integer offset casting. + n_cfg.timeoff = new_epoch - epoch; + + // If canceled set 1 for invalidating first boot clock edit. + if (!n_cfg.timeoff) + n_cfg.timeoff = 1; + else + max77620_rtc_set_epoch_offset((int)n_cfg.timeoff); + + nyx_changes_made = true; + } + + mbox_action(btns, txt); + + return LV_RES_INV; +} + +static lv_res_t _action_clock_edit_save(lv_obj_t *btns, const char * txt) +{ + _action_clock_edit(btns, txt); + + // Save if changes were made. + if (nyx_changes_made) + _save_nyx_options_action(NULL); + + return LV_RES_INV; +} + +static lv_res_t _create_mbox_clock_edit(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222Done", "\222Cancel", "\251", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "Enter #C7EA46 Date# and #C7EA46 Time# for Nyx\nThis will not alter the actual HW clock!"); + + // Get current time. + rtc_time_t time; + max77620_rtc_get_time_adjusted(&time); + + // Normalize year if out of range. + if (time.year < CLOCK_MIN_YEAR) + time.year = CLOCK_MIN_YEAR; + else if (time.year > CLOCK_MAX_YEAR) + time.year = CLOCK_MAX_YEAR; + + time.year -= CLOCK_MIN_YEAR; + + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_fit(h1, true, true); + + // Create year roller. + lv_obj_t *roller_year = lv_roller_create(h1, NULL); + lv_roller_set_options(roller_year, CLOCK_YEARLIST); + lv_roller_set_selected(roller_year, time.year, false); + lv_roller_set_visible_row_count(roller_year, 3); + clock_ctxt.year = roller_year; + + // Create month roller. + lv_obj_t *roller_month = lv_roller_create(h1, roller_year); + lv_roller_set_options(roller_month, + "January\n" + "February\n" + "March\n" + "April\n" + "May\n" + "June\n" + "July\n" + "August\n" + "September\n" + "October\n" + "November\n" + "December"); + lv_roller_set_selected(roller_month, time.month - 1, false); + lv_obj_align(roller_month, roller_year, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + clock_ctxt.month = roller_month; + + // Create day roller. + static char days[256]; + days[0] = 0; + for (u32 i = 1; i < 32; i++) + s_printf(days + strlen(days), " %d \n", i); + days[strlen(days) - 1] = 0; + lv_obj_t *roller_day = lv_roller_create(h1, roller_year); + lv_roller_set_options(roller_day, days); + lv_roller_set_selected(roller_day, time.day - 1, false); + lv_obj_align(roller_day, roller_month, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + clock_ctxt.day = roller_day; + + // Create hours roller. + static char hours[256]; + hours[0] = 0; + for (u32 i = 0; i < 24; i++) + s_printf(hours + strlen(hours), " %d \n", i); + hours[strlen(hours) - 1] = 0; + lv_obj_t *roller_hour = lv_roller_create(h1, roller_year); + lv_roller_set_options(roller_hour, hours); + lv_roller_set_selected(roller_hour, time.hour, false); + lv_obj_align(roller_hour, roller_day, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0); + clock_ctxt.hour = roller_hour; + + // Create minutes roller. + static char minutes[512]; + minutes[0] = 0; + for (u32 i = 0; i < 60; i++) + s_printf(minutes + strlen(minutes), " %02d \n", i); + minutes[strlen(minutes) - 1] = 0; + lv_obj_t *roller_minute = lv_roller_create(h1, roller_year); + lv_roller_set_options(roller_minute, minutes); + lv_roller_set_selected(roller_minute, time.min, false); + lv_obj_align(roller_minute, roller_hour, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + clock_ctxt.min = roller_minute; + + // If btn is empty, save options also because it was launched from boot. + lv_mbox_add_btns(mbox, mbox_btn_map, btn ? _action_clock_edit : _action_clock_edit_save); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +void first_time_clock_edit(void *param) +{ + _create_mbox_clock_edit(NULL); +} + +static lv_res_t _joycon_info_dump_action(lv_obj_t * btn) +{ + FIL fp; + int error = 0; + int cal_error = 0; + bool is_l_hos = false; + bool is_r_hos = false; + bool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG; + jc_gamepad_rpt_t *jc_pad = jc_get_bt_pairing_info(&is_l_hos, &is_r_hos); + + char *data = (char *)malloc(SZ_16K); + char *txt_buf = (char *)malloc(SZ_4K); + + if (!nx_hoag && !jc_pad) + error = 255; + + // Try 2 times to get factory calibration data. + for (u32 i = 0; i < 2; i++) + { + if (!error) + cal_error = hos_dump_cal0(); + if (!cal_error) + break; + } + + if (cal_error && nx_hoag) + error = cal_error; + + if (error) + goto disabled_or_cal0_issue; + + if (nx_hoag) + goto save_data; + + // Count valid joycon. + u32 joycon_found = jc_pad->bt_conn_l.type ? 1 : 0; + if (jc_pad->bt_conn_r.type) + joycon_found++; + + // Reset PC based for dumping. + jc_pad->bt_conn_l.type = is_l_hos ? jc_pad->bt_conn_l.type : 0; + jc_pad->bt_conn_r.type = is_r_hos ? jc_pad->bt_conn_r.type : 0; + +save_data: + error = !sd_mount() ? 5 : 0; + + if (!error) + { + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf; + + f_mkdir("switchroot"); + + if (!nx_hoag) + { + // Save binary dump. + memcpy(data, &jc_pad->bt_conn_l, sizeof(jc_bt_conn_t)); + memcpy(data + sizeof(jc_bt_conn_t), &jc_pad->bt_conn_r, sizeof(jc_bt_conn_t)); + + error = sd_save_to_file((u8 *)data, sizeof(jc_bt_conn_t) * 2, "switchroot/joycon_mac.bin") ? 4 : 0; + + // Save readable dump. + jc_bt_conn_t *bt = &jc_pad->bt_conn_l; + s_printf(data, + "[joycon_00]\ntype=%d\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n" + "host=%02X:%02X:%02X:%02X:%02X:%02X\n" + "ltk=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n\n", + bt->type, bt->mac[0], bt->mac[1], bt->mac[2], bt->mac[3], bt->mac[4], bt->mac[5], + bt->host_mac[0], bt->host_mac[1], bt->host_mac[2], bt->host_mac[3], bt->host_mac[4], bt->host_mac[5], + bt->ltk[0], bt->ltk[1], bt->ltk[2], bt->ltk[3], bt->ltk[4], bt->ltk[5], bt->ltk[6], bt->ltk[7], + bt->ltk[8], bt->ltk[9], bt->ltk[10], bt->ltk[11], bt->ltk[12], bt->ltk[13], bt->ltk[14], bt->ltk[15]); + bt = &jc_pad->bt_conn_r; + s_printf(data + strlen(data), + "[joycon_01]\ntype=%d\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n" + "host=%02X:%02X:%02X:%02X:%02X:%02X\n" + "ltk=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", + bt->type, bt->mac[0], bt->mac[1], bt->mac[2], bt->mac[3], bt->mac[4], bt->mac[5], + bt->host_mac[0], bt->host_mac[1], bt->host_mac[2], bt->host_mac[3], bt->host_mac[4], bt->host_mac[5], + bt->ltk[0], bt->ltk[1], bt->ltk[2], bt->ltk[3], bt->ltk[4], bt->ltk[5], bt->ltk[6], bt->ltk[7], + bt->ltk[8], bt->ltk[9], bt->ltk[10], bt->ltk[11], bt->ltk[12], bt->ltk[13], bt->ltk[14], bt->ltk[15]); + + if (!error) + error = f_open(&fp, "switchroot/joycon_mac.ini", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0; + if (!error) + { + f_puts(data, &fp); + f_close(&fp); + } + + f_mkdir("switchroot"); + + // Save IMU Calibration data. + if (!error && !cal_error) + { + s_printf(data, + "imu_type=%d\n\n" + "acc_cal_off_x=0x%X\n" + "acc_cal_off_y=0x%X\n" + "acc_cal_off_z=0x%X\n" + "acc_cal_scl_x=0x%X\n" + "acc_cal_scl_y=0x%X\n" + "acc_cal_scl_z=0x%X\n\n" + + "gyr_cal_off_x=0x%X\n" + "gyr_cal_off_y=0x%X\n" + "gyr_cal_off_z=0x%X\n" + "gyr_cal_scl_x=0x%X\n" + "gyr_cal_scl_y=0x%X\n" + "gyr_cal_scl_z=0x%X\n\n" + + "device_bt_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", + cal0->console_6axis_sensor_type, + cal0->acc_offset[0], cal0->acc_offset[1], cal0->acc_offset[2], + cal0->acc_scale[0], cal0->acc_scale[1], cal0->acc_scale[2], + cal0->gyro_offset[0], cal0->gyro_offset[1], cal0->gyro_offset[2], + cal0->gyro_scale[0], cal0->gyro_scale[1], cal0->gyro_scale[2], + cal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5]); + + error = f_open(&fp, "switchroot/switch.cal", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0; + if (!error) + { + f_puts(data, &fp); + f_close(&fp); + } + } + } + else + { + jc_calib_t *stick_cal_l = (jc_calib_t *)cal0->analog_stick_cal_l; + jc_calib_t *stick_cal_r = (jc_calib_t *)cal0->analog_stick_cal_r; + + // Save Lite Gamepad and IMU Calibration data. + // Actual max/min are right/left and up/down offsets. + s_printf(data, + "lite_cal_l_type=0x%X\n" + "lite_cal_lx_lof=0x%X\n" + "lite_cal_lx_cnt=0x%X\n" + "lite_cal_lx_rof=0x%X\n" + "lite_cal_ly_dof=0x%X\n" + "lite_cal_ly_cnt=0x%X\n" + "lite_cal_ly_uof=0x%X\n\n" + + "lite_cal_r_type=0x%X\n" + "lite_cal_rx_lof=0x%X\n" + "lite_cal_rx_cnt=0x%X\n" + "lite_cal_rx_rof=0x%X\n" + "lite_cal_ry_dof=0x%X\n" + "lite_cal_ry_cnt=0x%X\n" + "lite_cal_ry_uof=0x%X\n\n" + + "imu_type=%d\n\n" + "acc_cal_off_x=0x%X\n" + "acc_cal_off_y=0x%X\n" + "acc_cal_off_z=0x%X\n" + "acc_cal_scl_x=0x%X\n" + "acc_cal_scl_y=0x%X\n" + "acc_cal_scl_z=0x%X\n\n" + + "gyr_cal_off_x=0x%X\n" + "gyr_cal_off_y=0x%X\n" + "gyr_cal_off_z=0x%X\n" + "gyr_cal_scl_x=0x%X\n" + "gyr_cal_scl_y=0x%X\n" + "gyr_cal_scl_z=0x%X\n\n" + + "device_bt_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", + cal0->analog_stick_type_l, + stick_cal_l->x_min, stick_cal_l->x_center, stick_cal_l->x_max, + stick_cal_l->y_min, stick_cal_l->y_center, stick_cal_l->y_max, + cal0->analog_stick_type_r, + stick_cal_r->x_min, stick_cal_r->x_center, stick_cal_r->x_max, + stick_cal_r->y_min, stick_cal_r->y_center, stick_cal_r->y_max, + cal0->console_6axis_sensor_type, + cal0->acc_offset[0], cal0->acc_offset[1], cal0->acc_offset[2], + cal0->acc_scale[0], cal0->acc_scale[1], cal0->acc_scale[2], + cal0->gyro_offset[0], cal0->gyro_offset[1], cal0->gyro_offset[2], + cal0->gyro_scale[0], cal0->gyro_scale[1], cal0->gyro_scale[2], + cal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5]); + if (!error) + error = f_open(&fp, "switchroot/switch.cal", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0; + if (!error) + { + f_puts(data, &fp); + f_close(&fp); + } + } + + sd_unmount(); + } + +disabled_or_cal0_issue:; + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + + if (!error) + { + if (!nx_hoag) + { + s_printf(txt_buf, + "Dumping to SD card finished!\n" + "Saved to: #C7EA46 switchroot/joycon_mac.[bin/ini]#\n\n"); + + bool success = true; + + // Check if pairing info was found. + if (joycon_found == 2) + strcat(txt_buf, "#C7EA46 Success!#\n#C7EA46 Found 2 out of 2 Joy-Con pairing data!#\n"); + else + { + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Failed!#\n#FF8000 Warning:# Found #FFDD00 %d out of 2# pairing data!\n", joycon_found); + success = false; + } + + // Check if pairing was done in HOS. + if (is_l_hos && is_r_hos) + strcat(txt_buf, "#C7EA46 Both pairing data are HOS based!#"); + else if (!is_l_hos && is_r_hos) + { + strcat(txt_buf, "#FF8000 Warning:# #FFDD00 Left# pairing data is not HOS based!"); + success = false; + } + else if (is_l_hos && !is_r_hos) + { + strcat(txt_buf, "#FF8000 Warning:# #FFDD00 Right# pairing data is not HOS based!"); + success = false; + } + else + { + strcat(txt_buf, "#FF8000 Warning:# #FFDD00 No# pairing data is HOS based!"); + success = false; + } + + if (!success) + strcat(txt_buf, + "\n\n#FFDD00 Make sure that both Joy-Con are connected,#\n" + "#FFDD00 and that you paired them in HOS!#"); + + if (cal_error) + s_printf(txt_buf + strlen(txt_buf), "\n\n#FF8000 Warning: Failed (%d) to get IMU calibration!#", cal_error); + } + else + { + s_printf(txt_buf, + "Dumping to SD card finished!\n" + "Saved to: #C7EA46 switchroot/switch.cal#\n\n"); + strcat(txt_buf, "#C7EA46 Success!#\n#C7EA46 Found Lite Gamepad data!#\n"); + } + } + else + { + if (!nx_hoag) + s_printf(txt_buf, "#FFDD00 Failed to dump Joy-Con pairing info!#\n#FFDD00 Error: %d#", error); + else + s_printf(txt_buf, "#FFDD00 Failed to get Lite Gamepad info!#\n#FFDD00 Error: %d#", error); + } + + lv_mbox_set_text(mbox, txt_buf); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text. + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + free(txt_buf); + free(data); + + return LV_RES_OK; +} + +static lv_res_t _home_screen_action(lv_obj_t *ddlist) +{ + u32 new_selection = lv_ddlist_get_selected(ddlist); + if (n_cfg.home_screen != new_selection) + { + n_cfg.home_screen = new_selection; + nyx_changes_made = true; + } + + return LV_RES_OK; +} + +static lv_res_t _action_nyx_options_save(lv_obj_t *btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + mbox_action(btns, txt); + + if (!btn_idx) + _save_nyx_options_action(NULL); + + return LV_RES_INV; +} + +static void _check_nyx_changes() +{ + if (nyx_changes_made) + { + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char * mbox_btn_map[] = { "\222Save", "\222Cancel", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_mbox_set_text(mbox, + "#FF8000 Nyx configuration#\n\n" + "You changed the configuration!\n\n" + "Do you want to save it?"); + + lv_mbox_add_btns(mbox, mbox_btn_map, _action_nyx_options_save); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + nyx_changes_made = false; + } +} + +static lv_res_t _action_win_nyx_options_close(lv_obj_t *btn) +{ + // Hide status bar options save button. + lv_obj_set_opa_scale(status_bar.mid, LV_OPA_0); + lv_obj_set_click(status_bar.mid, false); + + lv_res_t res = nyx_win_close_action_custom(btn); + + _check_nyx_changes(); + + return res; +} + +lv_res_t create_win_nyx_options(lv_obj_t *parrent_btn) +{ + lv_theme_t *th = lv_theme_get_current(); + + lv_obj_t *win = nyx_create_window_custom_close_btn(SYMBOL_HOME" Nyx Settings", _action_win_nyx_options_close); + + static lv_style_t h_style; + lv_style_copy(&h_style, &lv_style_transp); + h_style.body.padding.inner = 0; + h_style.body.padding.hor = LV_DPI - (LV_DPI / 4); + h_style.body.padding.ver = LV_DPI / 6; + + // Create containers to keep content inside. + lv_obj_t * sw_h2 = lv_cont_create(win, NULL); + lv_cont_set_style(sw_h2, &h_style); + lv_cont_set_fit(sw_h2, false, true); + lv_obj_set_width(sw_h2, (LV_HOR_RES / 9) * 4); + lv_obj_set_click(sw_h2, false); + lv_cont_set_layout(sw_h2, LV_LAYOUT_OFF); + + lv_obj_t * sw_h3 = lv_cont_create(win, NULL); + lv_cont_set_style(sw_h3, &h_style); + lv_cont_set_fit(sw_h3, false, true); + lv_obj_set_width(sw_h3, (LV_HOR_RES / 9) * 4); + lv_obj_set_click(sw_h3, false); + lv_cont_set_layout(sw_h3, LV_LAYOUT_OFF); + lv_obj_align(sw_h3, sw_h2, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 11 / 25, 0); + + lv_obj_t * l_cont = lv_cont_create(sw_h2, NULL); + lv_cont_set_style(l_cont, &lv_style_transp_tight); + lv_cont_set_fit(l_cont, true, true); + lv_obj_set_click(l_cont, false); + lv_cont_set_layout(l_cont, LV_LAYOUT_OFF); + lv_obj_set_opa_scale(l_cont, LV_OPA_40); + + lv_obj_t *label_sep = lv_label_create(sw_h2, NULL); + lv_label_set_static_text(label_sep, ""); + + // Create theme button. + lv_obj_t *btn = lv_btn_create(sw_h2, NULL); + lv_obj_t *label_btn = lv_label_create(btn, NULL); + lv_btn_set_fit(btn, true, true); + lv_label_set_static_text(label_btn, SYMBOL_COPY" Color Theme"); + lv_obj_align(btn, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 5 + 3); + lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_nyx_colors); + + lv_obj_t *label_txt2 = lv_label_create(sw_h2, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, "Select a color for all #00FFC8 highlights# in Nyx.\n"); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 8); + + // Create home screen settings list. + lv_obj_t *line_sep = lv_line_create(sw_h2, NULL); + static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} }; + lv_line_set_points(line_sep, line_pp, 2); + lv_line_set_style(line_sep, th->line.decor); + lv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4); + + lv_obj_t *label_txt = lv_label_create(l_cont, NULL); + lv_label_set_static_text(label_txt, SYMBOL_HOME" Home Screen"); + lv_obj_set_style(label_txt, th->label.prim); + lv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); + + lv_obj_t *ddlist = lv_ddlist_create(l_cont, NULL); + lv_obj_set_top(ddlist, true); + lv_ddlist_set_draw_arrow(ddlist, true); + lv_ddlist_set_options(ddlist, + "Main menu \n" + "All Configs\n" + "Launch\n" + "More Configs"); + lv_ddlist_set_selected(ddlist, n_cfg.home_screen); + lv_ddlist_set_action(ddlist, _home_screen_action); + lv_obj_align(ddlist, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 2 / 3, 0); + + label_txt2 = lv_label_create(l_cont, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Select what screen to show on Nyx boot.\n" + "#FF8000 All Configs:# #C7EA46 Combines More configs into Launch empty slots.#\n" + "#FF8000 Launch / More Configs:# #C7EA46 Uses the classic divided view.#"); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4); + + line_sep = lv_line_create(sw_h2, line_sep); + lv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4); + + // Create entries per line button. + lv_obj_t *btn2 = lv_btn_create(sw_h2, NULL); + nyx_create_onoff_button(th, sw_h2, btn2, SYMBOL_GPS" Extended Boot Entries", _entries_columns_action, true); + lv_obj_align(btn2, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10); + if (n_cfg.entries_5_col) + lv_btn_set_state(btn2, LV_BTN_STATE_TGL_REL); + nyx_generic_onoff_toggle(btn2); + + label_txt2 = lv_label_create(sw_h2, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Sets the boot entries per line to 5. (Default is 4)\n" + "#C7EA46 This allows a total of 10 boot entries to be shown in Launch#\n" + "#C7EA46 and More Configs sections.#\n\n\n"); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 12); + + // Create the second column. + label_sep = lv_label_create(sw_h3, NULL); + lv_label_set_static_text(label_sep, ""); + + // Create Dump Joy-Con BT button. + lv_obj_t *btn3 = lv_btn_create(sw_h3, NULL); + lv_obj_t *label_btn3 = lv_label_create(btn3, NULL); + lv_btn_set_fit(btn3, true, true); + lv_label_set_static_text(label_btn3, SYMBOL_DOWNLOAD" Dump Joy-Con BT"); + lv_obj_align(btn3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 3); + lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _joycon_info_dump_action); + + label_txt2 = lv_label_create(sw_h3, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Allows you to save the Switch and Joy-Con MAC addresses\n" + "and the LTKs associated with them. For #C7EA46 Android# and #C7EA46 Linux#."); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4); + + line_sep = lv_line_create(sw_h3, line_sep); + lv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4); + + // Create Backup/Restore Verification list. + label_txt = lv_label_create(sw_h3, NULL); + lv_label_set_static_text(label_txt, SYMBOL_MODULES_ALT" Data Verification"); + lv_obj_set_style(label_txt, th->label.prim); + lv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); + + lv_obj_t *ddlist2 = lv_ddlist_create(sw_h3, NULL); + lv_obj_set_top(ddlist2, true); + lv_ddlist_set_draw_arrow(ddlist2, true); + lv_ddlist_set_options(ddlist2, + "Off (Fastest)\n" + "Sparse (Fast) \n" + "Full (Slow)\n" + "Full (Hashes)"); + lv_ddlist_set_selected(ddlist2, n_cfg.verification); + lv_obj_align(ddlist2, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 3 / 8, 0); + lv_ddlist_set_action(ddlist2, _data_verification_action); + + label_txt2 = lv_label_create(sw_h3, NULL); + lv_label_set_static_text(label_txt2, "Set the type of data verification done for backup and restore.\n" + "Can be canceled without losing the backup/restore.\n"); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4); + + line_sep = lv_line_create(sw_h3, line_sep); + lv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4); + + // Create clock edit button. + lv_obj_t *btn5 = lv_btn_create(sw_h3, NULL); + lv_obj_t *label_btn5 = lv_label_create(btn5, NULL); + lv_btn_set_fit(btn5, true, true); + lv_label_set_static_text(label_btn5, SYMBOL_CLOCK" Clock (Offset)"); + lv_obj_align(btn5, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); + lv_btn_set_action(btn5, LV_BTN_ACTION_CLICK, _create_mbox_clock_edit); + + label_txt2 = lv_label_create(sw_h3, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Change clock offset manually.\n" + "#C7EA46 The entered Date and Time will be converted to an offset#\n" + "#C7EA46 automatically. This will be also used for FatFS operations.#"); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn5, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4); + + // Enable save options button in status bar and set action. + lv_btn_set_action(status_bar.mid, LV_BTN_ACTION_CLICK, _save_nyx_options_action); + lv_obj_set_opa_scale(status_bar.mid, LV_OPA_COVER); + lv_obj_set_click(status_bar.mid, true); + + lv_obj_set_top(l_cont, true); // Set the ddlist container at top. + lv_obj_set_parent(ddlist, l_cont); // Reorder ddlist. + lv_obj_set_top(ddlist, true); + lv_obj_set_top(ddlist2, true); return LV_RES_OK; } @@ -388,8 +1469,7 @@ void create_tab_options(lv_theme_t *th, lv_obj_t *parent) // Create Auto NoGC button. lv_obj_t *btn2 = lv_btn_create(sw_h2, NULL); - nyx_create_onoff_button(th, sw_h2, btn2, SYMBOL_SHRK" Auto NoGC", auto_nogc_toggle, true); - + nyx_create_onoff_button(th, sw_h2, btn2, SYMBOL_CHIP" Auto NoGC", auto_nogc_toggle, true); lv_obj_align(btn2, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10); label_txt2 = lv_label_create(sw_h2, NULL); @@ -441,50 +1521,33 @@ void create_tab_options(lv_theme_t *th, lv_obj_t *parent) line_sep = lv_line_create(sw_h3, line_sep); lv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4); - // Create Backup/Restore Verification list. - label_txt = lv_label_create(sw_h3, NULL); - lv_label_set_static_text(label_txt, SYMBOL_MODULES_ALT" Data Verification"); - lv_obj_set_style(label_txt, th->label.prim); - lv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); - - lv_obj_t *ddlist2 = lv_ddlist_create(sw_h3, NULL); - lv_obj_set_top(ddlist2, true); - lv_ddlist_set_draw_arrow(ddlist2, true); - lv_ddlist_set_options(ddlist2, - "Off (Fastest)\n" - "Sparse (Fast) \n" - "Full (Slow)\n" - "Full (Hashes)"); - lv_ddlist_set_selected(ddlist2, h_cfg.verification); - lv_obj_align(ddlist2, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 3 / 8, 0); - lv_ddlist_set_action(ddlist2, _data_verification_action); - - if (hekate_bg) - { - lv_ddlist_set_style(ddlist2, LV_DDLIST_STYLE_BG, &ddlist_transp_bg); - lv_ddlist_set_style(ddlist2, LV_DDLIST_STYLE_BGO, &ddlist_transp_bg); - lv_ddlist_set_style(ddlist2, LV_DDLIST_STYLE_PR, &ddlist_transp_sel); - lv_ddlist_set_style(ddlist2, LV_DDLIST_STYLE_SEL, &ddlist_transp_sel); - } + // Create Update r2p button. + lv_obj_t *btn4 = lv_btn_create(sw_h3, NULL); + nyx_create_onoff_button(th, sw_h3, btn4, SYMBOL_REFRESH" Update Reboot 2 Payload", _update_r2p_action, true); + lv_obj_align(btn4, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10); label_txt2 = lv_label_create(sw_h3, NULL); - lv_label_set_static_text(label_txt2, "Set the type of data verification done for backup and restore.\n" - "Can be canceled without losing the backup/restore.\n\n\n\n"); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "If #FF8000 FSS0# is used in the selected boot entry, the reboot 2 payload\n" + "binary will be checked and forced to be updated to hekate.\n\n\n\n"); lv_obj_set_style(label_txt2, &hint_small_style); - lv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4); + lv_obj_align(label_txt2, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 12); // Set default loaded states. if (h_cfg.autohosoff) lv_btn_set_state(btn3, LV_BTN_STATE_TGL_REL); if (h_cfg.autonogc) lv_btn_set_state(btn2, LV_BTN_STATE_TGL_REL); + if (h_cfg.updater2p) + lv_btn_set_state(btn4, LV_BTN_STATE_TGL_REL); nyx_generic_onoff_toggle(btn2); nyx_generic_onoff_toggle(btn3); + nyx_generic_onoff_toggle(btn4); _autoboot_hide_delay_action(btn); lv_obj_set_top(l_cont, true); // Set the ddlist container at top. lv_obj_set_parent(ddlist, l_cont); // Reorder ddlist. lv_obj_set_top(ddlist, true); - lv_obj_set_top(ddlist2, true); } diff --git a/nyx/nyx_gui/frontend/gui_options.h b/nyx/nyx_gui/frontend/gui_options.h index a19eec7..0fee5e0 100644 --- a/nyx/nyx_gui/frontend/gui_options.h +++ b/nyx/nyx_gui/frontend/gui_options.h @@ -17,8 +17,12 @@ #ifndef _GUI_OPTIONS_H_ #define _GUI_OPTIONS_H_ -#include "../libs/lvgl/lvgl.h" +#include +void nyx_options_clear_ini_changes_made(); +bool nyx_options_get_ini_changes_made(); +void first_time_clock_edit(void *param); +lv_res_t create_win_nyx_options(lv_obj_t *parrent_btn); void create_tab_options(lv_theme_t *th, lv_obj_t *parent); #endif diff --git a/nyx/nyx_gui/frontend/gui_tools.c b/nyx/nyx_gui/frontend/gui_tools.c index 9f145e9..3229814 100644 --- a/nyx/nyx_gui/frontend/gui_tools.c +++ b/nyx/nyx_gui/frontend/gui_tools.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,80 +17,118 @@ #include +#include + #include "gui.h" +#include "gui_tools.h" +#include "gui_tools_partition_manager.h" #include "gui_emmc_tools.h" -#include "../config/config.h" +#include "fe_emummc_tools.h" +#include "../config.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" #include "../hos/hos.h" -#include "../hos/sept.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../soc/fuse.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" +#include extern volatile boot_cfg_t *b_cfg; extern hekate_config h_cfg; +extern nyx_config n_cfg; -extern bool sd_mount(); -extern void sd_unmount(bool deinit); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); -extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); +lv_obj_t *ums_mbox; -bool get_autorcm_status(bool change) +extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage); + +static lv_obj_t *_create_container(lv_obj_t *parent) { - u8 corr_mod_byte0; - sdmmc_storage_t storage; - sdmmc_t sdmmc; + static lv_style_t h_style; + lv_style_copy(&h_style, &lv_style_transp); + h_style.body.padding.inner = 0; + h_style.body.padding.hor = LV_DPI - (LV_DPI / 4); + h_style.body.padding.ver = LV_DPI / 6; + + lv_obj_t *h1 = lv_cont_create(parent, NULL); + lv_cont_set_style(h1, &h_style); + lv_cont_set_fit(h1, false, true); + lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4); + lv_obj_set_click(h1, false); + lv_cont_set_layout(h1, LV_LAYOUT_OFF); + + return h1; +} + +bool get_set_autorcm_status(bool toggle) +{ + u32 sector; + u8 corr_mod0, mod1; bool enabled = false; - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + if (h_cfg.t210b01) + return false; + + emmc_initialize(false); u8 *tempbuf = (u8 *)malloc(0x200); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf); + emmc_set_partition(EMMC_BOOT0); + sdmmc_storage_read(&emmc_storage, 0x200 / EMMC_BLOCKSIZE, 1, tempbuf); - if ((fuse_read_odm(4) & 3) != 3) - corr_mod_byte0 = 0xF7; - else - corr_mod_byte0 = 0x37; + // Get the correct RSA modulus byte masks. + nx_emmc_get_autorcm_masks(&corr_mod0, &mod1); - if (tempbuf[0x10] != corr_mod_byte0) + // Check if 2nd byte of modulus is correct. + if (tempbuf[0x11] != mod1) + goto out; + + if (tempbuf[0x10] != corr_mod0) enabled = true; - // Change autorcm status if requested. - if (change) + // Toggle autorcm status if requested. + if (toggle) { - int i, sect = 0; - u8 randomXor = 0; - - for (i = 0; i < 4; i++) + // Iterate BCTs. + for (u32 i = 0; i < 4; i++) { - sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE; - sdmmc_storage_read(&storage, sect, 1, tempbuf); + sector = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset. + sdmmc_storage_read(&emmc_storage, sector, 1, tempbuf); if (!enabled) - { - do - { - randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking. - } while (!randomXor); // Avoid the lottery. - - tempbuf[0x10] ^= randomXor; - } + tempbuf[0x10] = 0; else - tempbuf[0x10] = corr_mod_byte0; - sdmmc_storage_write(&storage, sect, 1, tempbuf); + tempbuf[0x10] = corr_mod0; + sdmmc_storage_write(&emmc_storage, sector, 1, tempbuf); } - enabled = !(enabled); + enabled = !enabled; } + // Check if RCM is patched and protect from a possible brick. + if (enabled && h_cfg.rcm_patched && hw_get_chip_id() != GP_HIDREV_MAJOR_T210B01) + { + // Iterate BCTs. + for (u32 i = 0; i < 4; i++) + { + sector = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset. + sdmmc_storage_read(&emmc_storage, sector, 1, tempbuf); + + // Check if 2nd byte of modulus is correct. + if (tempbuf[0x11] != mod1) + continue; + + // If AutoRCM is enabled, disable it. + if (tempbuf[0x10] != corr_mod0) + { + tempbuf[0x10] = corr_mod0; + + sdmmc_storage_write(&emmc_storage, sector, 1, tempbuf); + } + } + + enabled = false; + } + +out: free(tempbuf); - sdmmc_storage_end(&storage); + emmc_end(); + + h_cfg.autorcm_enabled = enabled; return enabled; } @@ -101,11 +139,11 @@ static lv_res_t _create_mbox_autorcm_status(lv_obj_t *btn) lv_obj_set_style(dark_bg, &mbox_darken); lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); - static const char * mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); lv_mbox_set_recolor_text(mbox, true); - bool enabled = get_autorcm_status(true); + bool enabled = get_set_autorcm_status(true); if (enabled) { @@ -135,34 +173,701 @@ static lv_res_t _create_mbox_autorcm_status(lv_obj_t *btn) return LV_RES_OK; } -static int _fix_attributes(u32 *ufidx, lv_obj_t *lb_val, char *path, u32 *total, u32 hos_folder, u32 check_first_run) +static lv_res_t _create_mbox_hid(usb_ctxt_t *usbs) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\262Close", "\251", "" }; + static const char *mbox_btn_map2[] = { "\251", "\222Close", "\251", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + char *txt_buf = malloc(SZ_4K); + + s_printf(txt_buf, "#FF8000 HID Emulation#\n\n#C7EA46 Device:# "); + + if (usbs->type == USB_HID_GAMEPAD) + strcat(txt_buf, "Gamepad"); + else + strcat(txt_buf, "Touchpad"); + + lv_mbox_set_text(mbox, txt_buf); + free(txt_buf); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, " "); + usbs->label = (void *)lbl_status; + + lv_obj_t *lbl_tip = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_tip, true); + lv_label_set_static_text(lbl_tip, "Note: To end it, press #C7EA46 L3# + #C7EA46 HOME# or remove the cable."); + lv_obj_set_style(lbl_tip, &hint_small_style); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + usb_device_gadget_hid(usbs); + + lv_mbox_add_btns(mbox, mbox_btn_map2, mbox_action); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_ums(usb_ctxt_t *usbs) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\262Close", "\251", "" }; + static const char *mbox_btn_map2[] = { "\251", "\222Close", "\251", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + char *txt_buf = malloc(SZ_4K); + + s_printf(txt_buf, "#FF8000 USB Mass Storage#\n\n#C7EA46 Device:# "); + + if (usbs->type == MMC_SD) + { + switch (usbs->partition) + { + case 0: + strcat(txt_buf, "SD Card"); + break; + case EMMC_GPP + 1: + strcat(txt_buf, "emuMMC GPP"); + break; + case EMMC_BOOT0 + 1: + strcat(txt_buf, "emuMMC BOOT0"); + break; + case EMMC_BOOT1 + 1: + strcat(txt_buf, "emuMMC BOOT1"); + break; + } + } + else + { + switch (usbs->partition) + { + case EMMC_GPP + 1: + strcat(txt_buf, "eMMC GPP"); + break; + case EMMC_BOOT0 + 1: + strcat(txt_buf, "eMMC BOOT0"); + break; + case EMMC_BOOT1 + 1: + strcat(txt_buf, "eMMC BOOT1"); + break; + } + } + + lv_mbox_set_text(mbox, txt_buf); + free(txt_buf); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, " "); + usbs->label = (void *)lbl_status; + + lv_obj_t *lbl_tip = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_tip, true); + if (!usbs->ro) + { + if (usbs->type == MMC_SD) + { + lv_label_set_static_text(lbl_tip, + "Note: To end it, #C7EA46 safely eject# from inside the OS.\n" + " #FFDD00 DO NOT remove the cable!#"); + } + else + { + lv_label_set_static_text(lbl_tip, + "Note: To end it, #C7EA46 safely eject# from inside the OS.\n" + " #FFDD00 If it's not mounted, you might need to remove the cable!#"); + } + } + else + { + lv_label_set_static_text(lbl_tip, + "Note: To end it, #C7EA46 safely eject# from inside the OS\n" + " or by removing the cable!#"); + } + lv_obj_set_style(lbl_tip, &hint_small_style); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + // Dim backlight. + display_backlight_brightness(20, 1000); + + usb_device_gadget_ums(usbs); + + // Restore backlight. + display_backlight_brightness(h_cfg.backlight - 20, 1000); + + lv_mbox_add_btns(mbox, mbox_btn_map2, mbox_action); + + ums_mbox = dark_bg; + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_ums_error(int error) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + switch (error) + { + case 1: + lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Error mounting SD Card!#"); + break; + case 2: + lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 No emuMMC found active!#"); + break; + case 3: + lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Active emuMMC is not partition based!#"); + break; + } + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +static void usb_gadget_set_text(void *lbl, const char *text) +{ + lv_label_set_text((lv_obj_t *)lbl, text); + manual_system_maintenance(true); +} + +static lv_res_t _action_hid_jc(lv_obj_t *btn) +{ + // Reduce BPMP, RAM and backlight and power off SDMMC1 to conserve power. + sd_end(); + minerva_change_freq(FREQ_800); + bpmp_clk_rate_relaxed(true); + display_backlight_brightness(10, 1000); + + usb_ctxt_t usbs; + usbs.type = USB_HID_GAMEPAD; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + + _create_mbox_hid(&usbs); + + // Restore BPMP, RAM and backlight. + minerva_change_freq(FREQ_1600); + bpmp_clk_rate_relaxed(false); + display_backlight_brightness(h_cfg.backlight - 20, 1000); + + return LV_RES_OK; +} + +/* +static lv_res_t _action_hid_touch(lv_obj_t *btn) +{ + // Reduce BPMP, RAM and backlight and power off SDMMC1 to conserve power. + sd_end(); + minerva_change_freq(FREQ_800); + bpmp_clk_rate_relaxed(true); + display_backlight_brightness(10, 1000); + + usb_ctxt_t usbs; + usbs.type = USB_HID_TOUCHPAD; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + + _create_mbox_hid(&usbs); + + // Restore BPMP, RAM and backlight. + minerva_change_freq(FREQ_1600); + bpmp_clk_rate_relaxed(false); + display_backlight_brightness(h_cfg.backlight - 20, 1000); + + return LV_RES_OK; +} +*/ + +static bool usb_msc_emmc_read_only; +lv_res_t action_ums_sd(lv_obj_t *btn) +{ + usb_ctxt_t usbs; + usbs.type = MMC_SD; + usbs.partition = 0; + usbs.offset = 0; + usbs.sectors = 0; + usbs.ro = 0; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + + _create_mbox_ums(&usbs); + + return LV_RES_OK; +} + +static lv_res_t _action_ums_emmc_boot0(lv_obj_t *btn) +{ + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + + usb_ctxt_t usbs; + usbs.type = MMC_EMMC; + usbs.partition = EMMC_BOOT0 + 1; + usbs.offset = 0; + usbs.sectors = 0; + usbs.ro = usb_msc_emmc_read_only; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + + _create_mbox_ums(&usbs); + + return LV_RES_OK; +} + +static lv_res_t _action_ums_emmc_boot1(lv_obj_t *btn) +{ + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + + usb_ctxt_t usbs; + usbs.type = MMC_EMMC; + usbs.partition = EMMC_BOOT1 + 1; + usbs.offset = 0; + usbs.sectors = 0; + usbs.ro = usb_msc_emmc_read_only; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + + _create_mbox_ums(&usbs); + + return LV_RES_OK; +} + +static lv_res_t _action_ums_emmc_gpp(lv_obj_t *btn) +{ + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + + usb_ctxt_t usbs; + usbs.type = MMC_EMMC; + usbs.partition = EMMC_GPP + 1; + usbs.offset = 0; + usbs.sectors = 0; + usbs.ro = usb_msc_emmc_read_only; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + + _create_mbox_ums(&usbs); + + return LV_RES_OK; +} + +static lv_res_t _action_ums_emuemmc_boot0(lv_obj_t *btn) +{ + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + + usb_ctxt_t usbs; + + int error = !sd_mount(); + if (!error) + { + emummc_cfg_t emu_info; + load_emummc_cfg(&emu_info); + + error = 2; + if (emu_info.enabled) + { + error = 3; + if (emu_info.sector) + { + error = 0; + usbs.offset = emu_info.sector; + } + } + + if (emu_info.path) + free(emu_info.path); + if (emu_info.nintendo_path) + free(emu_info.nintendo_path); + } + sd_unmount(); + + if (error) + _create_mbox_ums_error(error); + else + { + usbs.type = MMC_SD; + usbs.partition = EMMC_BOOT0 + 1; + usbs.sectors = 0x2000; // Forced 4MB. + usbs.ro = usb_msc_emmc_read_only; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + _create_mbox_ums(&usbs); + } + + return LV_RES_OK; +} + +static lv_res_t _action_ums_emuemmc_boot1(lv_obj_t *btn) +{ + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + + usb_ctxt_t usbs; + + int error = !sd_mount(); + if (!error) + { + emummc_cfg_t emu_info; + load_emummc_cfg(&emu_info); + + error = 2; + if (emu_info.enabled) + { + error = 3; + if (emu_info.sector) + { + error = 0; + usbs.offset = emu_info.sector + 0x2000; + } + } + + if (emu_info.path) + free(emu_info.path); + if (emu_info.nintendo_path) + free(emu_info.nintendo_path); + } + sd_unmount(); + + if (error) + _create_mbox_ums_error(error); + else + { + usbs.type = MMC_SD; + usbs.partition = EMMC_BOOT1 + 1; + usbs.sectors = 0x2000; // Forced 4MB. + usbs.ro = usb_msc_emmc_read_only; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + _create_mbox_ums(&usbs); + } + + return LV_RES_OK; +} + +static lv_res_t _action_ums_emuemmc_gpp(lv_obj_t *btn) +{ + if (!nyx_emmc_check_battery_enough()) + return LV_RES_OK; + + usb_ctxt_t usbs; + + int error = !sd_mount(); + if (!error) + { + emummc_cfg_t emu_info; + load_emummc_cfg(&emu_info); + + error = 2; + if (emu_info.enabled) + { + error = 3; + if (emu_info.sector) + { + error = 1; + usbs.offset = emu_info.sector + 0x4000; + + u8 *gpt = malloc(SD_BLOCKSIZE); + if (sdmmc_storage_read(&sd_storage, usbs.offset + 1, 1, gpt)) + { + if (!memcmp(gpt, "EFI PART", 8)) + { + error = 0; + usbs.sectors = *(u32 *)(gpt + 0x20) + 1; // Backup LBA + 1. + } + } + } + } + + if (emu_info.path) + free(emu_info.path); + if (emu_info.nintendo_path) + free(emu_info.nintendo_path); + } + sd_unmount(); + + if (error) + _create_mbox_ums_error(error); + else + { + usbs.type = MMC_SD; + usbs.partition = EMMC_GPP + 1; + usbs.ro = usb_msc_emmc_read_only; + usbs.system_maintenance = &manual_system_maintenance; + usbs.set_text = &usb_gadget_set_text; + _create_mbox_ums(&usbs); + } + + return LV_RES_OK; +} + +void nyx_run_ums(void *param) +{ + u32 *cfg = (u32 *)param; + + u8 type = (*cfg) >> 24; + *cfg = *cfg & (~NYX_CFG_EXTRA); + + // Disable read only flag. + usb_msc_emmc_read_only = false; + + switch (type) + { + case NYX_UMS_SD_CARD: + action_ums_sd(NULL); + break; + case NYX_UMS_EMMC_BOOT0: + _action_ums_emmc_boot0(NULL); + break; + case NYX_UMS_EMMC_BOOT1: + _action_ums_emmc_boot1(NULL); + break; + case NYX_UMS_EMMC_GPP: + _action_ums_emmc_gpp(NULL); + break; + case NYX_UMS_EMUMMC_BOOT0: + _action_ums_emuemmc_boot0(NULL); + break; + case NYX_UMS_EMUMMC_BOOT1: + _action_ums_emuemmc_boot1(NULL); + break; + case NYX_UMS_EMUMMC_GPP: + _action_ums_emuemmc_gpp(NULL); + break; + } +} + +static lv_res_t _emmc_read_only_toggle(lv_obj_t *btn) +{ + nyx_generic_onoff_toggle(btn); + + usb_msc_emmc_read_only = lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL ? 1 : 0; + + return LV_RES_OK; +} + +static lv_res_t _create_window_usb_tools(lv_obj_t *parent) +{ + lv_obj_t *win = nyx_create_standard_window(SYMBOL_USB" USB Tools"); + + static lv_style_t h_style; + lv_style_copy(&h_style, &lv_style_transp); + h_style.body.padding.inner = 0; + h_style.body.padding.hor = LV_DPI - (LV_DPI / 4); + h_style.body.padding.ver = LV_DPI / 9; + + // Create USB Mass Storage container. + lv_obj_t *h1 = lv_cont_create(win, NULL); + lv_cont_set_style(h1, &h_style); + lv_cont_set_fit(h1, false, true); + lv_obj_set_width(h1, (LV_HOR_RES / 9) * 5); + lv_obj_set_click(h1, false); + lv_cont_set_layout(h1, LV_LAYOUT_OFF); + + lv_obj_t *label_sep = lv_label_create(h1, NULL); + lv_label_set_static_text(label_sep, ""); + + lv_obj_t *label_txt = lv_label_create(h1, NULL); + lv_label_set_static_text(label_txt, "USB Mass Storage"); + lv_obj_set_style(label_txt, lv_theme_get_current()->label.prim); + lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10); + + lv_obj_t *line_sep = lv_line_create(h1, NULL); + static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} }; + lv_line_set_points(line_sep, line_pp, 2); + lv_line_set_style(line_sep, lv_theme_get_current()->line.decor); + lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8); + + // Create SD UMS button. + lv_obj_t *btn1 = lv_btn_create(h1, NULL); + lv_obj_t *label_btn = lv_label_create(btn1, NULL); + lv_btn_set_fit(btn1, true, true); + lv_label_set_static_text(label_btn, SYMBOL_SD" SD Card"); + + lv_obj_align(btn1, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, action_ums_sd); + + lv_obj_t *label_txt2 = lv_label_create(h1, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Allows you to mount the SD Card to a PC/Phone.\n" + "#C7EA46 All operating systems are supported. Access is# #FF8000 Read/Write.#"); + + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + // Create RAW GPP button. + lv_obj_t *btn_gpp = lv_btn_create(h1, btn1); + label_btn = lv_label_create(btn_gpp, NULL); + lv_label_set_static_text(label_btn, SYMBOL_CHIP" eMMC RAW GPP"); + lv_obj_align(btn_gpp, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn_gpp, LV_BTN_ACTION_CLICK, _action_ums_emmc_gpp); + + // Create BOOT0 button. + lv_obj_t *btn_boot0 = lv_btn_create(h1, btn1); + label_btn = lv_label_create(btn_boot0, NULL); + lv_label_set_static_text(label_btn, "BOOT0"); + lv_obj_align(btn_boot0, btn_gpp, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0); + lv_btn_set_action(btn_boot0, LV_BTN_ACTION_CLICK, _action_ums_emmc_boot0); + + // Create BOOT1 button. + lv_obj_t *btn_boot1 = lv_btn_create(h1, btn1); + label_btn = lv_label_create(btn_boot1, NULL); + lv_label_set_static_text(label_btn, "BOOT1"); + lv_obj_align(btn_boot1, btn_boot0, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0); + lv_btn_set_action(btn_boot1, LV_BTN_ACTION_CLICK, _action_ums_emmc_boot1); + + // Create emuMMC RAW GPP button. + lv_obj_t *btn_emu_gpp = lv_btn_create(h1, btn1); + label_btn = lv_label_create(btn_emu_gpp, NULL); + lv_label_set_static_text(label_btn, SYMBOL_MODULES_ALT" emu RAW GPP"); + lv_obj_align(btn_emu_gpp, btn_gpp, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn_emu_gpp, LV_BTN_ACTION_CLICK, _action_ums_emuemmc_gpp); + + // Create emuMMC BOOT0 button. + lv_obj_t *btn_emu_boot0 = lv_btn_create(h1, btn1); + label_btn = lv_label_create(btn_emu_boot0, NULL); + lv_label_set_static_text(label_btn, "BOOT0"); + lv_obj_align(btn_emu_boot0, btn_boot0, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn_emu_boot0, LV_BTN_ACTION_CLICK, _action_ums_emuemmc_boot0); + + // Create emuMMC BOOT1 button. + lv_obj_t *btn_emu_boot1 = lv_btn_create(h1, btn1); + label_btn = lv_label_create(btn_emu_boot1, NULL); + lv_label_set_static_text(label_btn, "BOOT1"); + lv_obj_align(btn_emu_boot1, btn_boot1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn_emu_boot1, LV_BTN_ACTION_CLICK, _action_ums_emuemmc_boot1); + + label_txt2 = lv_label_create(h1, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Allows you to mount the eMMC/emuMMC.\n" + "#C7EA46 Default access is# #FF8000 read-only.#"); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn_emu_gpp, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + lv_obj_t *h_write = lv_cont_create(win, NULL); + lv_cont_set_style(h_write, &h_style); + lv_cont_set_fit(h_write, false, true); + lv_obj_set_width(h_write, (LV_HOR_RES / 9) * 2); + lv_obj_set_click(h_write, false); + lv_cont_set_layout(h_write, LV_LAYOUT_OFF); + lv_obj_align(h_write, label_txt2, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0); + + // Create read/write access button. + lv_obj_t *btn_write_access = lv_btn_create(h_write, NULL); + nyx_create_onoff_button(lv_theme_get_current(), h_write, + btn_write_access, SYMBOL_EDIT" Read-Only", _emmc_read_only_toggle, false); + if (!n_cfg.ums_emmc_rw) + lv_btn_set_state(btn_write_access, LV_BTN_STATE_TGL_REL); + _emmc_read_only_toggle(btn_write_access); + + // Create USB Input Devices container. + lv_obj_t *h2 = lv_cont_create(win, NULL); + lv_cont_set_style(h2, &h_style); + lv_cont_set_fit(h2, false, true); + lv_obj_set_width(h2, (LV_HOR_RES / 9) * 3); + lv_obj_set_click(h2, false); + lv_cont_set_layout(h2, LV_LAYOUT_OFF); + lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0); + + label_sep = lv_label_create(h2, NULL); + lv_label_set_static_text(label_sep, ""); + + lv_obj_t *label_txt3 = lv_label_create(h2, NULL); + lv_label_set_static_text(label_txt3, "USB Input Devices"); + lv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim); + lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 4 / 21); + + line_sep = lv_line_create(h2, line_sep); + lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8); + + // Create Gamepad button. + lv_obj_t *btn3 = lv_btn_create(h2, NULL); + label_btn = lv_label_create(btn3, NULL); + lv_btn_set_fit(btn3, true, true); + lv_label_set_static_text(label_btn, SYMBOL_CIRCUIT" Gamepad"); + lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); + lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _action_hid_jc); + + lv_obj_t *label_txt4 = lv_label_create(h2, NULL); + lv_label_set_recolor(label_txt4, true); + lv_label_set_static_text(label_txt4, + "Plug-in the Joy-Con and convert the device\n" + "into a gamepad for PC or Phone.\n" + "#C7EA46 Needs both Joy-Con in order to function.#"); + + lv_obj_set_style(label_txt4, &hint_small_style); + lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); +/* + // Create Touchpad button. + lv_obj_t *btn4 = lv_btn_create(h2, btn1); + label_btn = lv_label_create(btn4, NULL); + lv_label_set_static_text(label_btn, SYMBOL_KEYBOARD" Touchpad"); + lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _action_hid_touch); + lv_btn_set_state(btn4, LV_BTN_STATE_INA); + + label_txt4 = lv_label_create(h2, NULL); + lv_label_set_recolor(label_txt4, true); + lv_label_set_static_text(label_txt4, + "Control the PC via the device\'s touchscreen.\n" + "#C7EA46 Two fingers tap acts like a# #FF8000 Right click##C7EA46 .#\n"); + lv_obj_set_style(label_txt4, &hint_small_style); + lv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); +*/ + return LV_RES_OK; +} + +static int _fix_attributes(lv_obj_t *lb_val, char *path, u32 *total) { FRESULT res; DIR dir; u32 dirLength = 0; static FILINFO fno; - if (check_first_run) - { - // Read file attributes. - res = f_stat(path, &fno); - if (res != FR_OK) - return res; - - // Check if archive bit is set. - if (fno.fattrib & AM_ARC) - { - *(u32 *)total = *(u32 *)total + 1; - f_chmod(path, 0, AM_ARC); - } - } - // Open directory. res = f_opendir(&dir, path); if (res != FR_OK) return res; dirLength = strlen(path); + + // Hard limit path to 1024 characters. Do not result to error. + if (dirLength > 1024) + { + total[2]++; + goto out; + } + for (;;) { // Clear file or folder path. @@ -175,48 +880,48 @@ static int _fix_attributes(u32 *ufidx, lv_obj_t *lb_val, char *path, u32 *total, if (res != FR_OK || fno.fname[0] == 0) break; - // Skip official Nintendo dir if started from root. - if (!hos_folder && !strcmp(fno.fname, "Nintendo")) - continue; - // Set new directory or file. memcpy(&path[dirLength], "/", 1); - memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1); - - // Check if archive bit is set. - if (fno.fattrib & AM_ARC) - { - *total = *total + 1; - f_chmod(path, 0, AM_ARC); - - if (*ufidx == 0) - lv_label_set_array_text(lb_val, path, 256); - *ufidx += 1; - if (*ufidx > 9) - *ufidx = 0; - } - - manual_system_maintenance(true); + strcpy(&path[dirLength + 1], fno.fname); // Is it a directory? if (fno.fattrib & AM_DIR) { - // Set archive bit to NCA folders. - if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca")) + // Check if it's a HOS single file folder. + strcat(path, "/00"); + bool is_hos_special = !f_stat(path, NULL); + path[strlen(path) - 3] = 0; + + // Set archive bit to HOS single file folders. + if (is_hos_special) { - *total = *total + 1; - f_chmod(path, AM_ARC, AM_ARC); + if (!(fno.fattrib & AM_ARC)) + { + if (!f_chmod(path, AM_ARC, AM_ARC)) + total[0]++; + else + total[3]++; + } } - lv_label_set_array_text(lb_val, path, 256); + else if (fno.fattrib & AM_ARC) // If not, clear the archive bit. + { + if (!f_chmod(path, 0, AM_ARC)) + total[1]++; + else + total[3]++; + } + + lv_label_set_text(lb_val, path); manual_system_maintenance(true); // Enter the directory. - res = _fix_attributes(ufidx, lb_val, path, total, hos_folder, 0); + res = _fix_attributes(lb_val, path, total); if (res != FR_OK) break; } } +out: f_closedir(&dir); return res; @@ -224,17 +929,7 @@ static int _fix_attributes(u32 *ufidx, lv_obj_t *lb_val, char *path, u32 *total, static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn) { - lv_obj_t *win; - - // Find which was called and set window's title. - bool nintendo_folder = false; - if (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)), SYMBOL_COPY" Unset archive bit")) - nintendo_folder = true; - - if (!nintendo_folder) - win = nyx_create_standard_window(SYMBOL_COPY" Unset archive bit (except Nintendo folder)"); - else - win = nyx_create_standard_window(SYMBOL_COPY" Fix archive bit (Nintendo folder)"); + lv_obj_t *win = nyx_create_standard_window(SYMBOL_COPY" Fix Archive Bit (All folders)"); // Disable buttons. nyx_window_toggle_buttons(win, true); @@ -248,15 +943,12 @@ static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn) if (!sd_mount()) { - lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init SD!#"); + lv_label_set_text(lb_desc, "#FFDD00 Failed to init SD!#"); lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); } else { - if (!nintendo_folder) - lv_label_set_static_text(lb_desc, "#00DDFF Traversing all SD card files!#\nThis may take some time..."); - else - lv_label_set_static_text(lb_desc, "#00DDFF Traversing all Nintendo files!#\nThis may take some time..."); + lv_label_set_text(lb_desc, "#00DDFF Traversing all SD card files!#\nThis may take some time..."); lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); lv_obj_t *val = lv_cont_create(win, NULL); @@ -264,32 +956,17 @@ static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn) lv_obj_t * lb_val = lv_label_create(val, lb_desc); - char path[256]; + char *path = malloc(0x1000); path[0] = 0; - lv_label_set_static_text(lb_val, ""); + lv_label_set_text(lb_val, ""); lv_obj_set_width(lb_val, lv_obj_get_width(val)); lv_obj_align(val, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); - u32 total = 0; + u32 total[4] = { 0 }; + _fix_attributes(lb_val, path, total); - if (!nintendo_folder) - path[0] = 0; - else - strcpy(path, "Nintendo"); - - u32 ufidx = 0; - - _fix_attributes(&ufidx, lb_val, path, &total, nintendo_folder, nintendo_folder); - - // Also fix the emuMMC Nintendo folders. - if (nintendo_folder) - { - strcpy(path, "emuMMC"); - _fix_attributes(&ufidx, lb_val, path, &total, nintendo_folder, nintendo_folder); - } - - sd_unmount(false); + sd_unmount(); lv_obj_t *desc2 = lv_cont_create(win, NULL); lv_obj_set_size(desc2, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4); @@ -297,11 +974,24 @@ static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn) char *txt_buf = (char *)malloc(0x500); - s_printf(txt_buf, "#96FF00 Total archive bits fixed:# #FF8000 %d!#", total); + if (!total[0] && !total[1]) + s_printf(txt_buf, "#96FF00 Done! No change was needed.#"); + else + s_printf(txt_buf, "#96FF00 Done! Archive bits fixed:# #FF8000 %d unset and %d set!#", total[1], total[0]); - lv_label_set_array_text(lb_desc2, txt_buf, 0x500); + // Check errors. + if (total[2] || total[3]) + { + s_printf(txt_buf, "\n\n#FFDD00 Errors: folder accesses: %d, arc bit fixes: %d!#\n" + "#FFDD00 Filesystem should be checked for errors.#", + total[2], total[3]); + } + + lv_label_set_text(lb_desc2, txt_buf); lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2)); lv_obj_align(desc2, val, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 0); + + free(path); } // Enable buttons. @@ -310,6 +1000,125 @@ static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn) return LV_RES_OK; } +static lv_res_t _create_mbox_fix_touchscreen(lv_obj_t *btn) +{ + int res = 0; + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + char *txt_buf = malloc(SZ_16K); + strcpy(txt_buf, "#FF8000 Don't touch the screen!#\n\nThe tuning process will start in "); + u32 text_idx = strlen(txt_buf); + lv_mbox_set_text(mbox, txt_buf); + + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + lv_mbox_set_text(mbox, + "#FFDD00 Warning: Only run this if you really have issues!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort."); + manual_system_maintenance(true); + + if (!(btn_wait() & BTN_POWER)) + goto out; + + manual_system_maintenance(true); + lv_mbox_set_text(mbox, txt_buf); + + u32 seconds = 5; + while (seconds) + { + s_printf(txt_buf + text_idx, "%d seconds...", seconds); + lv_mbox_set_text(mbox, txt_buf); + manual_system_maintenance(true); + msleep(1000); + seconds--; + } + + u8 err[2]; + if (!touch_panel_ito_test(err)) + goto ito_failed; + + if (!err[0] && !err[1]) + { + res = touch_execute_autotune(); + if (res) + goto out; + } + else + { + touch_sense_enable(); + + s_printf(txt_buf, "#FFFF00 ITO Test: "); + switch (err[0]) + { + case ITO_FORCE_OPEN: + strcat(txt_buf, "Force Open"); + break; + case ITO_SENSE_OPEN: + strcat(txt_buf, "Sense Open"); + break; + case ITO_FORCE_SHRT_GND: + strcat(txt_buf, "Force Short to GND"); + break; + case ITO_SENSE_SHRT_GND: + strcat(txt_buf, "Sense Short to GND"); + break; + case ITO_FORCE_SHRT_VCM: + strcat(txt_buf, "Force Short to VDD"); + break; + case ITO_SENSE_SHRT_VCM: + strcat(txt_buf, "Sense Short to VDD"); + break; + case ITO_FORCE_SHRT_FORCE: + strcat(txt_buf, "Force Short to Force"); + break; + case ITO_SENSE_SHRT_SENSE: + strcat(txt_buf, "Sense Short to Sense"); + break; + case ITO_F2E_SENSE: + strcat(txt_buf, "Force Short to Sense"); + break; + case ITO_FPC_FORCE_OPEN: + strcat(txt_buf, "FPC Force Open"); + break; + case ITO_FPC_SENSE_OPEN: + strcat(txt_buf, "FPC Sense Open"); + break; + default: + strcat(txt_buf, "Unknown"); + break; + + } + s_printf(txt_buf + strlen(txt_buf), " (%d), Chn: %d#\n\n", err[0], err[1]); + strcat(txt_buf, "#FFFF00 The touchscreen calibration failed!"); + lv_mbox_set_text(mbox, txt_buf); + goto out2; + } + +ito_failed: + touch_sense_enable(); + +out: + if (res) + lv_mbox_set_text(mbox, "#C7EA46 The touchscreen calibration finished!"); + else + lv_mbox_set_text(mbox, "#FFFF00 The touchscreen calibration failed!"); + +out2: + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + free(txt_buf); + + return LV_RES_OK; +} + static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) { lv_obj_t *win = nyx_create_standard_window(SYMBOL_MODULES" Dump package1/2"); @@ -328,106 +1137,99 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) if (!sd_mount()) { - lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init SD!#"); + lv_label_set_text(lb_desc, "#FFDD00 Failed to init SD!#"); goto out_end; } char path[128]; - u8 *pkg1 = (u8 *)calloc(1, 0x40000); - u8 *warmboot = (u8 *)calloc(1, 0x40000); - u8 *secmon = (u8 *)calloc(1, 0x40000); - u8 *loader = (u8 *)calloc(1, 0x40000); - u8 *pkg2 = NULL; u8 kb = 0; + u8 *pkg1 = (u8 *)zalloc(SZ_256K); + u8 *warmboot = (u8 *)zalloc(SZ_256K); + u8 *secmon = (u8 *)zalloc(SZ_256K); + u8 *loader = (u8 *)zalloc(SZ_256K); + u8 *pkg2 = NULL; - char *txt_buf = (char *)malloc(0x1000); - char *txt_buf2 = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_16K); - tsec_ctxt_t tsec_ctxt; - - sdmmc_storage_t storage; - sdmmc_t sdmmc; - - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + if (!emmc_initialize(false)) { - lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); + lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); goto out_free; } - sdmmc_storage_set_mmc_partition(&storage, 1); + emmc_set_partition(EMMC_BOOT0); // Read package1. + static const u32 BOOTLOADER_SIZE = SZ_256K; + static const u32 BOOTLOADER_MAIN_OFFSET = 0x100000; + static const u32 HOS_KEYBLOBS_OFFSET = 0x180000; + char *build_date = malloc(32); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1, build_date); + u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header. + sdmmc_storage_read(&emmc_storage, BOOTLOADER_MAIN_OFFSET / EMMC_BLOCKSIZE, BOOTLOADER_SIZE / EMMC_BLOCKSIZE, pkg1); + + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset, build_date); s_printf(txt_buf, "#00DDFF Found pkg1 ('%s')#\n\n", build_date); free(build_date); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); - // Dump package1 in its encrypted state if unknown. + // Dump package1 in its encrypted state. + emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &emmc_storage); + bool res = sd_save_to_file(pkg1, BOOTLOADER_SIZE, path); + + // Exit if unknown. if (!pkg1_id) { - s_printf(txt_buf + strlen(txt_buf), - "#FFDD00 Unknown pkg1 version for reading#\n#FFDD00 TSEC firmware!#"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "#FFDD00 Unknown pkg1 version!#"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); - emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &storage); - if (sd_save_to_file(pkg1, 0x40000, path)) - goto out_free; - - s_printf(txt_buf + strlen(txt_buf), "\nEncrypted pkg1 dumped to pkg1_enc.bin"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); - manual_system_maintenance(true); + if (!res) + { + strcat(txt_buf, "\nEncrypted pkg1 dumped to pkg1_enc.bin"); + lv_label_set_text(lb_desc, txt_buf); + manual_system_maintenance(true); + } goto out_free; } - const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20); - kb = pkg1_id->kb; - if (!h_cfg.se_keygen_done) + tsec_ctxt_t tsec_ctxt = {0}; + tsec_ctxt.fw = (void *)(pkg1 + pkg1_id->tsec_off); + tsec_ctxt.pkg1 = (void *)pkg1; + tsec_ctxt.pkg11_off = pkg1_id->pkg11_off; + + // Read keyblob. + u8 *keyblob = (u8 *)zalloc(EMMC_BLOCKSIZE); + sdmmc_storage_read(&emmc_storage, HOS_KEYBLOBS_OFFSET / EMMC_BLOCKSIZE + kb, 1, keyblob); + + // Decrypt. + hos_keygen(keyblob, kb, &tsec_ctxt); + free(keyblob); + + if (h_cfg.t210b01 || kb <= HOS_KB_VERSION_600) { - tsec_ctxt.fw = (void *)(pkg1 + pkg1_id->tsec_off); - tsec_ctxt.pkg1 = (void *)pkg1; - tsec_ctxt.pkg11_off = pkg1_id->pkg11_off; - tsec_ctxt.secmon_base = pkg1_id->secmon_base; - - if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) + if (!pkg1_decrypt(pkg1_id, pkg1)) { - b_cfg->autoboot = 0; - b_cfg->autoboot_list = 0; - - if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb)) - { - lv_label_set_static_text(lb_desc, "#FFDD00 Failed to run sept#\n"); - goto out_free; - } + strcat(txt_buf, "#FFDD00 Pkg1 decryption failed!#\n"); + if (h_cfg.t210b01) + strcat(txt_buf, "#FFDD00 Is BEK missing?#\n"); + lv_label_set_text(lb_desc, txt_buf); + goto out_free; } - - // Read keyblob. - u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); - sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob); - - // Decrypt. - keygen(keyblob, kb, &tsec_ctxt); - if (kb <= KB_FIRMWARE_VERSION_600) - h_cfg.se_keygen_done = 1; - free(keyblob); } - if (kb <= KB_FIRMWARE_VERSION_600) - pkg1_decrypt(pkg1_id, pkg1); - - if (kb <= KB_FIRMWARE_VERSION_620) + if (h_cfg.t210b01 || kb <= HOS_KB_VERSION_620) { - pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1); + pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1 + pk1_offset); + pk11_hdr_t *hdr_pk11 = (pk11_hdr_t *)(pkg1 + pk1_offset + pkg1_id->pkg11_off + 0x20); // Display info. s_printf(txt_buf + strlen(txt_buf), @@ -436,80 +1238,99 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) "#C7EA46 Secure monitor size: #0x%05X\n" "#C7EA46 Warmboot addr: #0x%05X\n" "#C7EA46 Warmboot size: #0x%05X\n\n", - hdr->ldr_size, pkg1_id->secmon_base, hdr->sm_size, pkg1_id->warmboot_base, hdr->wb_size); + hdr_pk11->ldr_size, pkg1_id->secmon_base, hdr_pk11->sm_size, pkg1_id->warmboot_base, hdr_pk11->wb_size); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump package1.1. - emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage); - if (sd_save_to_file(pkg1, 0x40000, path)) + emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &emmc_storage); + if (sd_save_to_file(pkg1, SZ_256K, path)) goto out_free; - s_printf(txt_buf + strlen(txt_buf), "pkg1 dumped to pkg1_decr.bin\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "pkg1 dumped to pkg1_decr.bin\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump nxbootloader. - emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage); - if (sd_save_to_file(loader, hdr->ldr_size, path)) + emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &emmc_storage); + if (sd_save_to_file(loader, hdr_pk11->ldr_size, path)) goto out_free; - s_printf(txt_buf + strlen(txt_buf), "NX Bootloader dumped to nxloader.bin\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "NX Bootloader dumped to nxloader.bin\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump secmon. - emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage); - if (sd_save_to_file(secmon, hdr->sm_size, path)) + emmcsn_path_impl(path, "/pkg1", "secmon.bin", &emmc_storage); + if (sd_save_to_file(secmon, hdr_pk11->sm_size, path)) goto out_free; - s_printf(txt_buf + strlen(txt_buf), "Secure Monitor dumped to secmon.bin\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "Secure Monitor dumped to secmon.bin\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump warmboot. - emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage); - if (sd_save_to_file(warmboot, hdr->wb_size, path)) + emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &emmc_storage); + if (sd_save_to_file(warmboot, hdr_pk11->wb_size, path)) goto out_free; - s_printf(txt_buf + strlen(txt_buf), "Warmboot dumped to warmboot.bin\n\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + // If T210B01, save a copy of decrypted warmboot binary also. + if (h_cfg.t210b01) + { + + se_aes_iv_clear(13); + se_aes_crypt_cbc(13, DECRYPT, warmboot + 0x330, hdr_pk11->wb_size - 0x330, + warmboot + 0x330, hdr_pk11->wb_size - 0x330); + emmcsn_path_impl(path, "/pkg1", "warmboot_dec.bin", &emmc_storage); + if (sd_save_to_file(warmboot, hdr_pk11->wb_size, path)) + goto out_free; + } + strcat(txt_buf, "Warmboot dumped to warmboot.bin\n\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); } // Dump package2.1. - sdmmc_storage_set_mmc_partition(&storage, 0); + emmc_set_partition(EMMC_GPP); // Parse eMMC GPT. LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); + emmc_gpt_parse(&gpt); // Find package2 partition. - emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); + emmc_part_t *pkg2_part = emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); if (!pkg2_part) goto out; // Read in package2 header and get package2 real size. - u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); + u8 *tmp = (u8 *)malloc(EMMC_BLOCKSIZE); + emmc_part_read(pkg2_part, 0x4000 / EMMC_BLOCKSIZE, 1, tmp); u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; free(tmp); // Read in package2. - u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); + u32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE); pkg2 = malloc(pkg2_size_aligned); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, - pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); -#if 0 - emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &storage); - if (sd_save_to_file(pkg2, pkg2_size_aligned, path)) - goto out; - gfx_puts("\npkg2 dumped to pkg2_encr.bin\n"); -#endif + emmc_part_read(pkg2_part, 0x4000 / EMMC_BLOCKSIZE, + pkg2_size_aligned / EMMC_BLOCKSIZE, pkg2); + + // Dump encrypted package2. + emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &emmc_storage); + res = sd_save_to_file(pkg2, pkg2_size, path); // Decrypt package2 and parse KIP1 blobs in INI1 section. pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2, kb); if (!pkg2_hdr) { - s_printf(txt_buf + strlen(txt_buf), "#FFDD00 Pkg2 decryption failed!#"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "#FFDD00 Pkg2 decryption failed!#"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); + if (!res) + { + strcat(txt_buf, "\npkg2 encrypted dumped to pkg2_encr.bin\n"); + lv_label_set_text(lb_desc, txt_buf); + manual_system_maintenance(true); + } + + // Clear EKS slot, in case something went wrong with tsec keygen. + hos_eks_clear(kb); + goto out; } @@ -519,41 +1340,48 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) "#C7EA46 INI1 size: #0x%05X\n\n", pkg2_hdr->sec_size[PKG2_SEC_KERNEL], pkg2_hdr->sec_size[PKG2_SEC_INI1]); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump pkg2.1. - emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage); + emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &emmc_storage); if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path)) goto out; - s_printf(txt_buf + strlen(txt_buf), "pkg2 dumped to pkg2_decr.bin\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "pkg2 dumped to pkg2_decr.bin\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump kernel. - emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage); + emmcsn_path_impl(path, "/pkg2", "kernel.bin", &emmc_storage); if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path)) goto out; - s_printf(txt_buf + strlen(txt_buf), "Kernel dumped to kernel.bin\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "Kernel dumped to kernel.bin\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); // Dump INI1. - u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; + u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1]; if (!ini1_size) { pkg2_get_newkern_info(pkg2_hdr->data); - ini1_off = pkg2_newkern_ini1_start; + ini1_off = pkg2_newkern_ini1_start; ini1_size = pkg2_newkern_ini1_end - pkg2_newkern_ini1_start; } + + if (!ini1_off) + { + strcat(txt_buf, "#FFDD00 Failed to dump INI1 and kips!#\n"); + goto out; + } + pkg2_ini1_t *ini1 = (pkg2_ini1_t *)(pkg2_hdr->data + ini1_off); - emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage); + emmcsn_path_impl(path, "/pkg2", "ini1.bin", &emmc_storage); if (sd_save_to_file(ini1, ini1_size, path)) goto out; - s_printf(txt_buf + strlen(txt_buf), "INI1 dumped to ini1.bin\n\n"); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + strcat(txt_buf, "INI1 dumped to ini1.bin\n\n"); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); char filename[32]; @@ -561,7 +1389,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) ptr += sizeof(pkg2_ini1_t); // Dump all kips. - u8 *kip_buffer = (u8 *)malloc(0x400000); + u8 *kip_buffer = (u8 *)malloc(SZ_4M); for (u32 i = 0; i < ini1->num_procs; i++) { @@ -575,7 +1403,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) kip1 = (pkg2_kip1_t *)kip_buffer; } - emmcsn_path_impl(path, "/pkg2/ini1", filename, &storage); + emmcsn_path_impl(path, "/pkg2/ini1", filename, &emmc_storage); if (sd_save_to_file(kip1, kip1_size, path)) { free(kip_buffer); @@ -583,7 +1411,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) } s_printf(txt_buf + strlen(txt_buf), "%s kip dumped to %s.kip1\n", kip1->name, kip1->name); - lv_label_set_array_text(lb_desc, txt_buf, 0x1000); + lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); ptr += kip1_size; @@ -591,7 +1419,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) free(kip_buffer); out: - nx_emmc_gpt_free(&gpt); + emmc_gpt_free(&gpt); out_free: free(pkg1); free(secmon); @@ -599,11 +1427,10 @@ out_free: free(loader); free(pkg2); free(txt_buf); - free(txt_buf2); - sdmmc_storage_end(&storage); - sd_unmount(false); + emmc_end(); + sd_unmount(); - if (kb >= KB_FIRMWARE_VERSION_620) + if (kb >= HOS_KB_VERSION_620) se_aes_key_clear(8); out_end: // Enable buttons. @@ -612,29 +1439,6 @@ out_end: return LV_RES_OK; } -void sept_run_dump() -{ - _create_window_dump_pk12_tool(NULL); -} - -static lv_obj_t *_create_container(lv_obj_t *parent) -{ - static lv_style_t h_style; - lv_style_copy(&h_style, &lv_style_transp); - h_style.body.padding.inner = 0; - h_style.body.padding.hor = LV_DPI - (LV_DPI / 4); - h_style.body.padding.ver = LV_DPI / 6; - - lv_obj_t *h1 = lv_cont_create(parent, NULL); - lv_cont_set_style(h1, &h_style); - lv_cont_set_fit(h1, false, true); - lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4); - lv_obj_set_click(h1, false); - lv_cont_set_layout(h1, LV_LAYOUT_OFF); - - return h1; -} - static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent) { lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY); @@ -672,9 +1476,10 @@ static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent) lv_obj_t *label_txt2 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt2, true); lv_label_set_static_text(label_txt2, - "Allows you to backup your eMMC partitions individually or as\n" - "a whole raw image to your SD card.\n" - "#FF8000 Supports SD cards from 4GB and up. FAT32 and exFAT.#"); + "Allows you to backup the eMMC partitions individually or as\n" + "a whole raw image to the SD card.\n" + "#C7EA46 Supports SD cards from# #FF8000 4GB# #C7EA46 and up. #" + "#FF8000 FAT32# #C7EA46 and ##FF8000 exFAT##C7EA46 .#"); lv_obj_set_style(label_txt2, &hint_small_style); lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); @@ -688,9 +1493,10 @@ static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent) label_txt2 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt2, true); lv_label_set_static_text(label_txt2, - "Allows you to restore your eMMC/emuMMC partitions individually\n" - "or as a whole raw image from your SD card.\n" - "#FF8000 Supports SD cards from 4GB and up. FAT32 and exFAT. #"); + "Allows you to restore the eMMC/emuMMC partitions individually\n" + "or as a whole raw image from the SD card.\n" + "#C7EA46 Supports SD cards from# #FF8000 4GB# #C7EA46 and up. #" + "#FF8000 FAT32# #C7EA46 and ##FF8000 exFAT##C7EA46 .#"); lv_obj_set_style(label_txt2, &hint_small_style); lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); @@ -702,14 +1508,14 @@ static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent) lv_label_set_static_text(label_sep, ""); lv_obj_t *label_txt3 = lv_label_create(h2, NULL); - lv_label_set_static_text(label_txt3, "Misc"); + lv_label_set_static_text(label_txt3, "SD Partitions & USB"); lv_obj_set_style(label_txt3, th->label.prim); lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10); line_sep = lv_line_create(h2, line_sep); lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8); - // Create Dump Package1/2 button. + // Create Partition SD Card button. lv_obj_t *btn3 = lv_btn_create(h2, NULL); if (hekate_bg) { @@ -718,21 +1524,37 @@ static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent) } label_btn = lv_label_create(btn3, NULL); lv_btn_set_fit(btn3, true, true); - lv_label_set_static_text(label_btn, SYMBOL_MODULES" Dump Package1/2"); + lv_label_set_static_text(label_btn, SYMBOL_SD" Partition SD Card"); lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); - lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_dump_pk12_tool); + lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, create_window_partition_manager); lv_obj_t *label_txt4 = lv_label_create(h2, NULL); lv_label_set_recolor(label_txt4, true); lv_label_set_static_text(label_txt4, - "Allows you to dump and decrypt pkg1 and pkg2 and further\n" - "split it up into their individual parts. It also dumps the kip1.\n\n"); + "Allows you to partition the SD Card for using it with #C7EA46 emuMMC#,\n" + "#C7EA46 Android# and #C7EA46 Linux#. You can also flash Linux and Android.\n"); lv_obj_set_style(label_txt4, &hint_small_style); lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); label_sep = lv_label_create(h2, NULL); lv_label_set_static_text(label_sep, ""); lv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7); + + // Create USB Tools button. + lv_obj_t *btn4 = lv_btn_create(h2, btn3); + label_btn = lv_label_create(btn4, NULL); + lv_label_set_static_text(label_btn, SYMBOL_USB" USB Tools"); + lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_window_usb_tools); + + label_txt4 = lv_label_create(h2, NULL); + lv_label_set_recolor(label_txt4, true); + lv_label_set_static_text(label_txt4, + "#C7EA46 USB mass storage#, #C7EA46 gamepad# and other USB tools.\n" + "Mass storage can mount SD, eMMC and emuMMC. The\n" + "gamepad transforms the Switch into an input device.#"); + lv_obj_set_style(label_txt4, &hint_small_style); + lv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); } static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) @@ -756,7 +1578,7 @@ static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) lv_line_set_style(line_sep, th->line.decor); lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8); - // Create Unset archive bit button. + // Create fix archive bit button. lv_obj_t *btn = lv_btn_create(h1, NULL); if (hekate_bg) { @@ -765,32 +1587,32 @@ static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) } lv_obj_t *label_btn = lv_label_create(btn, NULL); lv_btn_set_fit(btn, true, true); - lv_label_set_static_text(label_btn, SYMBOL_COPY" Unset archive bit"); + lv_label_set_static_text(label_btn, SYMBOL_DIRECTORY" Fix Archive Bit"); lv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_unset_abit_tool); lv_obj_t *label_txt2 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt2, true); lv_label_set_static_text(label_txt2, - "Allows you to unset the archive bit for all folders except the\n" - "root and emuMMC \'Nintendo\' folders.\n" - "#FF8000 If you want the Nintendo folders, use the below option.#"); + "Allows you to fix the archive bit for all folders including\n" + "the root and emuMMC \'Nintendo\' folders.\n" + "#C7EA46 It sets the archive bit to folders named with ##FF8000 .[ext]#\n" + "#FF8000 Use that option when you have corruption messages.#"); lv_obj_set_style(label_txt2, &hint_small_style); lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); - // Create Fix archive bit - Nintendo button. + // Create Fix touch calibration button. lv_obj_t *btn2 = lv_btn_create(h1, btn); label_btn = lv_label_create(btn2, NULL); - lv_label_set_static_text(label_btn, SYMBOL_DIRECTORY" Fix archive bit - Nintendo"); + lv_label_set_static_text(label_btn, SYMBOL_KEYBOARD" Calibrate Touchscreen"); lv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); - lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_window_unset_abit_tool); + lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_mbox_fix_touchscreen); label_txt2 = lv_label_create(h1, NULL); lv_label_set_recolor(label_txt2, true); lv_label_set_static_text(label_txt2, - "Allows you to fix your \'Nintendo\' folder's archive bits.\n" - "This will also fix the \'Nintendo\' folders found in emuMMC.\n" - "#FF8000 Use that option when you have corruption messages.#"); + "Allows you to calibrate the touchscreen module.\n" + "#FF8000 This fixes any issues with touchscreen in Nyx and HOS.#"); lv_obj_set_style(label_txt2, &hint_small_style); lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); @@ -821,12 +1643,12 @@ static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) label_btn = lv_label_create(btn3, NULL); lv_btn_set_fit(btn3, true, true); lv_label_set_recolor(label_btn, true); - lv_label_set_static_text(label_btn, SYMBOL_REFRESH" AutoRCM #00FFC9 ON #"); + lv_label_set_text(label_btn, SYMBOL_REFRESH" AutoRCM #00FFC9 ON #"); lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4); lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_mbox_autorcm_status); // Set default state for AutoRCM and lock it out if patched unit. - if (get_autorcm_status(false)) + if (get_set_autorcm_status(false)) lv_btn_set_state(btn3, LV_BTN_STATE_TGL_REL); else lv_btn_set_state(btn3, LV_BTN_STATE_REL); @@ -839,20 +1661,20 @@ static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) } autorcm_btn = btn3; - char *txt_buf = (char *)malloc(0x1000); + char *txt_buf = (char *)malloc(SZ_4K); s_printf(txt_buf, - "Allows you to enter RCM without using #C7EA46 VOL-# + #C7EA46 HOME# (jig).\n" + "Allows you to enter RCM without using #C7EA46 VOL+# & #C7EA46 HOME# (jig).\n" "#FF8000 It can restore all versions of AutoRCM whenever requested.#\n" - "#FF3C28 This corrupts your BCT and you can't boot without a custom#\n" + "#FF3C28 This corrupts the BCT and you can't boot without a custom#\n" "#FF3C28 bootloader.#"); if (h_cfg.rcm_patched) - s_printf(txt_buf + strlen(txt_buf), " #FF8000 This is disabled because this unit is patched!#"); + strcat(txt_buf, " #FF8000 This is disabled because this unit is patched!#"); lv_obj_t *label_txt4 = lv_label_create(h2, NULL); lv_label_set_recolor(label_txt4, true); - lv_label_set_array_text(label_txt4, txt_buf, 0x1000); + lv_label_set_text(label_txt4, txt_buf); free(txt_buf); lv_obj_set_style(label_txt4, &hint_small_style); @@ -861,6 +1683,21 @@ static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) label_sep = lv_label_create(h2, NULL); lv_label_set_static_text(label_sep, ""); lv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7); + + // Create Dump Package1/2 button. + lv_obj_t *btn4 = lv_btn_create(h2, btn); + label_btn = lv_label_create(btn4, NULL); + lv_label_set_static_text(label_btn, SYMBOL_MODULES" Dump Package1/2"); + lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_window_dump_pk12_tool); + + label_txt2 = lv_label_create(h2, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Allows you to dump and decrypt pkg1 and pkg2 and further\n" + "split it up into their individual parts. It also dumps the kip1."); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); } void create_tab_tools(lv_theme_t *th, lv_obj_t *parent) @@ -883,8 +1720,14 @@ void create_tab_tools(lv_theme_t *th, lv_obj_t *parent) lv_tabview_set_sliding(tv, false); lv_tabview_set_btns_pos(tv, LV_TABVIEW_BTNS_POS_BOTTOM); - lv_obj_t *tab1= lv_tabview_add_tab(tv, "eMMC "SYMBOL_DOT" Package1/2"); - lv_obj_t *tab2 = lv_tabview_add_tab(tv, "Archive bit "SYMBOL_DOT" AutoRCM"); + lv_obj_t *tab1= lv_tabview_add_tab(tv, "eMMC "SYMBOL_DOT" SD Partitions "SYMBOL_DOT" USB"); + lv_obj_t *tab2 = lv_tabview_add_tab(tv, "Arch bit "SYMBOL_DOT" RCM "SYMBOL_DOT" Touch "SYMBOL_DOT" Pkg1/2"); + + lv_obj_t *line_sep = lv_line_create(tv, NULL); + static const lv_point_t line_pp[] = { {0, 0}, { 0, LV_DPI / 4} }; + lv_line_set_points(line_sep, line_pp, 2); + lv_line_set_style(line_sep, lv_theme_get_current()->line.decor); + lv_obj_align(line_sep, tv, LV_ALIGN_IN_BOTTOM_MID, -1, -LV_DPI * 2 / 12); _create_tab_tools_emmc_pkg12(th, tab1); _create_tab_tools_arc_autorcm(th, tab2); diff --git a/nyx/nyx_gui/frontend/gui_tools.h b/nyx/nyx_gui/frontend/gui_tools.h index b58aef8..ae4bbf1 100644 --- a/nyx/nyx_gui/frontend/gui_tools.h +++ b/nyx/nyx_gui/frontend/gui_tools.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,10 +17,13 @@ #ifndef _GUI_TOOLS_H_ #define _GUI_TOOLS_H_ -#include "../libs/lvgl/lvgl.h" +#include + +extern lv_obj_t *ums_mbox; void create_tab_tools(lv_theme_t *th, lv_obj_t *parent); -void sept_run_dump(); -bool get_autorcm_status(bool change); +void nyx_run_ums(void *param); +bool get_set_autorcm_status(bool change); +lv_res_t action_ums_sd(lv_obj_t *btn); #endif diff --git a/nyx/nyx_gui/frontend/gui_tools_partition_manager.c b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c new file mode 100644 index 0000000..3ea91cb --- /dev/null +++ b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c @@ -0,0 +1,2799 @@ +/* + * Copyright (c) 2019-2024 CTCaer + * + * 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 + +#include "gui.h" +#include "gui_tools.h" +#include "gui_tools_partition_manager.h" +#include +#include + +#define AU_ALIGN_SECTORS 0x8000 // 16MB. +#define AU_ALIGN_BYTES (AU_ALIGN_SECTORS * SD_BLOCKSIZE) + +#define SECTORS_PER_GB 0x200000 + +#define HOS_MIN_SIZE_MB 2048 +#define ANDROID_SYSTEM_SIZE_MB 6144 // 6 GB. Fits both Legacy (4912MB) and Dynamic (6144MB) partition schemes. + +extern volatile boot_cfg_t *b_cfg; +extern volatile nyx_storage_t *nyx_str; + +typedef struct _partition_ctxt_t +{ + u32 total_sct; + u32 alignment; + int backup_possible; + + s32 hos_size; + u32 emu_size; + u32 l4t_size; + u32 and_size; + + bool emu_double; + bool emmc_is_64gb; + + bool and_dynamic; + + mbr_t mbr_old; + + lv_obj_t *bar_hos; + lv_obj_t *bar_emu; + lv_obj_t *bar_l4t; + lv_obj_t *bar_and; + + lv_obj_t *sep_emu; + lv_obj_t *sep_l4t; + lv_obj_t *sep_and; + + lv_obj_t *slider_bar_hos; + lv_obj_t *slider_emu; + lv_obj_t *slider_l4t; + lv_obj_t *slider_and; + + lv_obj_t *lbl_hos; + lv_obj_t *lbl_emu; + lv_obj_t *lbl_l4t; + lv_obj_t *lbl_and; +} partition_ctxt_t; + +typedef struct _l4t_flasher_ctxt_t +{ + u32 offset_sct; + u32 image_size_sct; +} l4t_flasher_ctxt_t; + +partition_ctxt_t part_info; +l4t_flasher_ctxt_t l4t_flash_ctxt; + +lv_obj_t *btn_flash_l4t; +lv_obj_t *btn_flash_android; + +int _copy_file(const char *src, const char *dst, const char *path) +{ + FIL fp_src; + FIL fp_dst; + int res; + + // Open file for reading. + f_chdrive(src); + res = f_open(&fp_src, path, FA_READ); + if (res != FR_OK) + return res; + + u32 file_bytes_left = f_size(&fp_src); + + // Open file for writing. + f_chdrive(dst); + f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE); + f_lseek(&fp_dst, f_size(&fp_src)); + f_lseek(&fp_dst, 0); + + while (file_bytes_left) + { + u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks. + file_bytes_left -= chunk_size; + + // Copy file to buffer. + f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL); + + // Write file to disk. + f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL); + } + + f_close(&fp_dst); + f_chdrive(src); + f_close(&fp_src); + + return FR_OK; +} + +static int _stat_and_copy_files(const char *src, const char *dst, char *path, u32 *total_files, u32 *total_size, lv_obj_t **labels) +{ + FRESULT res; + FIL fp_src; + FIL fp_dst; + DIR dir; + u32 dirLength = 0; + static FILINFO fno; + + f_chdrive(src); + + // Open directory. + res = f_opendir(&dir, path); + if (res != FR_OK) + return res; + + if (labels) + lv_label_set_text(labels[0], path); + + dirLength = strlen(path); + + // Hard limit path to 1024 characters. Do not result to error. + if (dirLength > 1024) + goto out; + + for (;;) + { + // Clear file path. + path[dirLength] = 0; + + // Read a directory item. + res = f_readdir(&dir, &fno); + + // Break on error or end of dir. + if (res != FR_OK || fno.fname[0] == 0) + break; + + // Set new directory or file. + memcpy(&path[dirLength], "/", 1); + strcpy(&path[dirLength + 1], fno.fname); + + if (labels) + { + lv_label_set_text(labels[1], fno.fname); + manual_system_maintenance(true); + } + + // Copy file to destination disk. + if (!(fno.fattrib & AM_DIR)) + { + u32 file_size = fno.fsize > RAMDISK_CLUSTER_SZ ? fno.fsize : RAMDISK_CLUSTER_SZ; // Ramdisk cluster size. + + // Check for overflow. + if ((file_size + *total_size) < *total_size) + { + // Set size to > 1GB, skip next folders and return. + *total_size = SZ_2G; + res = -1; + break; + } + + *total_size += file_size; + *total_files += 1; + + if (dst) + { + u32 file_bytes_left = fno.fsize; + + // Open file for writing. + f_chdrive(dst); + f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE); + f_lseek(&fp_dst, fno.fsize); + f_lseek(&fp_dst, 0); + + // Open file for reading. + f_chdrive(src); + f_open(&fp_src, path, FA_READ); + + while (file_bytes_left) + { + u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks. + file_bytes_left -= chunk_size; + + // Copy file to buffer. + f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL); + manual_system_maintenance(true); + + // Write file to disk. + f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL); + } + + // Finalize copied file. + f_close(&fp_dst); + f_chdrive(dst); + f_chmod(path, fno.fattrib, 0xFF); + + f_chdrive(src); + f_close(&fp_src); + } + + // If total is > 1GB exit. + if (*total_size > (RAM_DISK_SZ - SZ_16M)) // 0x2400000. + { + // Skip next folders and return. + res = -1; + break; + } + } + else // It's a directory. + { + if (!memcmp("System Volume Information", fno.fname, 25)) + continue; + + // Create folder to destination. + if (dst) + { + f_chdrive(dst); + f_mkdir(path); + f_chmod(path, fno.fattrib, 0xFF); + } + + // Enter the directory. + res = _stat_and_copy_files(src, dst, path, total_files, total_size, labels); + if (res != FR_OK) + break; + + if (labels) + { + // Clear folder path. + path[dirLength] = 0; + lv_label_set_text(labels[0], path); + } + } + } + +out: + f_closedir(&dir); + + return res; +} + +static void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, const char *name, int name_size) +{ + static const u8 linux_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 }; + u8 random_number[16]; + + // Create GPT partition. + memcpy(gpt->entries[*gpt_idx].type_guid, linux_part_guid, 16); + + // Set randomly created GUID + se_gen_prng128(random_number); + memcpy(gpt->entries[*gpt_idx].part_guid, random_number, 16); + + // Set partition start and end. + gpt->entries[*gpt_idx].lba_start = *curr_part_lba; + gpt->entries[*gpt_idx].lba_end = *curr_part_lba + size_lba - 1; + + // Set name. + memcpy(gpt->entries[*gpt_idx].name, name, name_size); + + // Wipe the first 1MB to sanitize it as raw-empty partition. + sdmmc_storage_write(&sd_storage, *curr_part_lba, 0x800, (void *)SDMMC_UPPER_BUFFER); + + // Prepare for next. + (*curr_part_lba) += size_lba; + (*gpt_idx)++; +} + +static void _prepare_and_flash_mbr_gpt() +{ + mbr_t mbr; + u8 random_number[16]; + + // Read current MBR. + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + // Copy over metadata if they exist. + if (*(u32 *)&part_info.mbr_old.bootstrap[0x80]) + memcpy(&mbr.bootstrap[0x80], &part_info.mbr_old.bootstrap[0x80], 304); + + // Clear the first 16MB. + memset((void *)SDMMC_UPPER_BUFFER, 0, AU_ALIGN_BYTES); + sdmmc_storage_write(&sd_storage, 0, AU_ALIGN_SECTORS, (void *)SDMMC_UPPER_BUFFER); + + u8 mbr_idx = 1; + se_gen_prng128(random_number); + memcpy(&mbr.signature, random_number, 4); + + // Apply L4T Linux second to MBR if no Android. + if (part_info.l4t_size && !part_info.and_size) + { + mbr.partitions[mbr_idx].type = 0x83; // Linux system partition. + mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11); + mbr.partitions[mbr_idx].size_sct = part_info.l4t_size << 11; + sdmmc_storage_write(&sd_storage, mbr.partitions[mbr_idx].start_sct, 0x800, (void *)SDMMC_UPPER_BUFFER); // Clear the first 1MB. + mbr_idx++; + } + + // emuMMC goes second or third. Next to L4T if no Android. + if (part_info.emu_size) + { + mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition. + mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11); + + if (!part_info.emu_double) + mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 11) - 0x800; // Reserve 1MB. + else + { + mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10; + mbr_idx++; + + // 2nd emuMMC. + mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition. + mbr.partitions[mbr_idx].start_sct = mbr.partitions[mbr_idx - 1].start_sct + (part_info.emu_size << 10); + mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 10) - 0x800; // Reserve 1MB. + } + mbr_idx++; + } + + if (part_info.and_size) + { + gpt_t *gpt = zalloc(sizeof(gpt_t)); + gpt_header_t gpt_hdr_backup = { 0 }; + + // Set GPT protective partition in MBR. + mbr.partitions[mbr_idx].type = 0xEE; + mbr.partitions[mbr_idx].start_sct = 1; + mbr.partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1; + mbr_idx++; + + // Set GPT header. + memcpy(&gpt->header.signature, "EFI PART", 8); + gpt->header.revision = 0x10000; + gpt->header.size = 92; + gpt->header.my_lba = 1; + gpt->header.alt_lba = sd_storage.sec_cnt - 1; + gpt->header.first_use_lba = (sizeof(mbr_t) + sizeof(gpt_t)) >> 9; + gpt->header.last_use_lba = sd_storage.sec_cnt - 0x800 - 1; // sd_storage.sec_cnt - 33 is start of backup gpt partition entries. + se_gen_prng128(random_number); + memcpy(gpt->header.disk_guid, random_number, 10); + memcpy(gpt->header.disk_guid + 10, "NYXGPT", 6); + gpt->header.part_ent_lba = 2; + gpt->header.part_ent_size = 128; + + // Set FAT GPT partition manually. + const u8 basic_part_guid[] = { 0xA2, 0xA0, 0xD0, 0xEB, 0xE5, 0xB9, 0x33, 0x44, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }; + memcpy(gpt->entries[0].type_guid, basic_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt->entries[0].part_guid, random_number, 16); + + // Clear non-standard Windows MBR attributes. bit4: Read only, bit5: Shadow copy, bit6: Hidden, bit7: No drive letter. + gpt->entries[0].part_guid[7] = 0; + + gpt->entries[0].lba_start = mbr.partitions[0].start_sct; + gpt->entries[0].lba_end = mbr.partitions[0].start_sct + mbr.partitions[0].size_sct - 1; + memcpy(gpt->entries[0].name, (char[]) { 'h', 0, 'o', 0, 's', 0, '_', 0, 'd', 0, 'a', 0, 't', 0, 'a', 0 }, 16); + + // Set the rest of GPT partitions. + u8 gpt_idx = 1; + u32 curr_part_lba = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11); + + // L4T partition. + if (part_info.l4t_size) + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, part_info.l4t_size << 11, (char[]) { 'l', 0, '4', 0, 't', 0 }, 6); + + if (part_info.and_dynamic) + { + // Android Linux Kernel partition. 64MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8); + + // Android Recovery partition. 64MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, (char[]) { 'r', 0, 'e', 0, 'c', 0, 'o', 0, 'v', 0, 'e', 0, 'r', 0, 'y', 0 }, 16); + + // Android Device Tree Reference partition. 1MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, (char[]) { 'd', 0, 't', 0, 'b', 0 }, 6); + + // Android Misc partition. 3MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, (char[]) { 'm', 0, 'i', 0, 's', 0, 'c', 0 }, 8); + + // Android Cache partition. 60MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, (char[]) { 'c', 0, 'a', 0, 'c', 0, 'h', 0, 'e', 0 }, 10); + + // Android Super dynamic partition. 5922MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xB91000, (char[]) { 's', 0, 'u', 0, 'p', 0, 'e', 0, 'r', 0 }, 10); + + // Android Userdata partition. + u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB). + if (!part_info.emu_size) + uda_size -= 0x800; // Reserve 1MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, (char[]) { 'u', 0, 's', 0, 'e', 0, 'r', 0, 'd', 0, 'a', 0, 't', 0, 'a', 0 }, 16); + } + else + { + // Android Vendor partition. 1GB + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, (char[]) { 'v', 0, 'e', 0, 'n', 0, 'd', 0, 'o', 0, 'r', 0 }, 12); + + // Android System partition. 3GB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, (char[]) { 'A', 0, 'P', 0, 'P', 0 }, 6); + + // Android Linux Kernel partition. 32MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6); + + // Android Recovery partition. 64MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6); + + // Android Device Tree Reference partition. 1MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6); + + // Android Encryption partition. 16MB. + // Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one. + sdmmc_storage_write(&sd_storage, curr_part_lba, 0x8000, (void *)SDMMC_UPPER_BUFFER); // Clear the whole of it. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, (char[]) { 'M', 0, 'D', 0, 'A', 0 }, 6); + + // Android Cache partition. 700MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, (char[]) { 'C', 0, 'A', 0, 'C', 0 }, 6); + + // Android Misc partition. 3MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, (char[]) { 'M', 0, 'S', 0, 'C', 0 }, 6); + + // Android Userdata partition. + u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB). + if (!part_info.emu_size) + uda_size -= 0x800; // Reserve 1MB. + _create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, (char[]) { 'U', 0, 'D', 0, 'A', 0 }, 6); + } + + // Handle emuMMC partitions manually. + if (part_info.emu_size) + { + // Set 1st emuMMC. + u8 emu_part_guid[] = { 0x00, 0x7E, 0xCA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'e', 'm', 'u', 'M', 'M', 'C' }; + memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt->entries[gpt_idx].part_guid, random_number, 16); + gpt->entries[gpt_idx].lba_start = curr_part_lba; + if (!part_info.emu_double) + gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 11) - 0x800 - 1; // Reserve 1MB. + else + gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 1; + memcpy(gpt->entries[gpt_idx].name, (char[]) { 'e', 0, 'm', 0, 'u', 0, 'm', 0, 'm', 0, 'c', 0 }, 12); + gpt_idx++; + + // Set 2nd emuMMC. + if (part_info.emu_double) + { + curr_part_lba += (part_info.emu_size << 10); + memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt->entries[gpt_idx].part_guid, random_number, 16); + gpt->entries[gpt_idx].lba_start = curr_part_lba; + gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 0x800 - 1; // Reserve 1MB. + memcpy(gpt->entries[gpt_idx].name, (char[]) { 'e', 0, 'm', 0, 'u', 0, 'm', 0, 'm', 0, 'c', 0, '2', 0 }, 14); + gpt_idx++; + } + } + + // Set final GPT header parameters. + gpt->header.num_part_ents = gpt_idx; + gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents); + gpt->header.crc32 = 0; // Set to 0 for calculation. + gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size); + + // Set final backup GPT header parameters. + memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t)); + gpt_hdr_backup.my_lba = sd_storage.sec_cnt - 1; + gpt_hdr_backup.alt_lba = 1; + gpt_hdr_backup.part_ent_lba = sd_storage.sec_cnt - 33; + gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation. + gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size); + + // Write main GPT. + sdmmc_storage_write(&sd_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt); + + // Write backup GPT partition table. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries); + + // Write backup GPT header. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup); + + free(gpt); + } + + // Write MBR. + sdmmc_storage_write(&sd_storage, 0, 1, &mbr); +} + +static lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn) +{ + action_ums_sd(btn); + + // Close and reopen partition manager. + lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK); + close_btn_action(close_btn); + lv_obj_del(ums_mbox); + create_window_partition_manager(NULL); + + return LV_RES_INV; +} + +static lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt) +{ + + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + // Flash Linux. + if (!btn_idx) + { + char path[128]; + + sd_mount(); + + strcpy(path, "switchroot/install/l4t."); + + // Delete all l4t.xx files. + u32 idx = 0; + while (true) + { + if (idx < 10) + { + path[23] = '0'; + itoa(idx, &path[23 + 1], 10); + } + else + itoa(idx, &path[23], 10); + + if (!f_stat(path, NULL)) + { + f_unlink(path); + } + else + break; + + idx++; + } + + sd_unmount(); + } + + return LV_RES_INV; +} + +static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + bool succeeded = false; + + if (btn_idx) + return LV_RES_INV; + + // Flash Linux. + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5); + + lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux..."); + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_fit(h1, true, true); + lv_cont_set_style(h1, &lv_style_transp_tight); + + lv_obj_t *bar = lv_bar_create(h1, NULL); + lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5); + lv_bar_set_range(bar, 0, 100); + lv_bar_set_value(bar, 0); + + lv_obj_t *label_pct = lv_label_create(h1, NULL); + lv_label_set_recolor(label_pct, true); + lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%"); + lv_label_set_style(label_pct, lv_theme_get_current()->label.prim); + lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + sd_mount(); + + int res = 0; + char *path = malloc(1024); + char *txt_buf = malloc(SZ_4K); + strcpy(path, "switchroot/install/l4t.00"); + u32 path_len = strlen(path) - 2; + + FIL fp; + + res = f_open(&fp, path, FA_READ); + if (res) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!"); + + goto exit; + } + + u64 fileSize = (u64)f_size(&fp); + + u32 num = 0; + u32 pct = 0; + u32 lba_curr = 0; + u32 bytesWritten = 0; + u32 currPartIdx = 0; + u32 prevPct = 200; + int retryCount = 0; + u32 total_size_sct = l4t_flash_ctxt.image_size_sct; + + u8 *buf = (u8 *)MIXD_BUF_ALIGNED; + DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0); + + // Start flashing L4T. + while (total_size_sct > 0) + { + // If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that. + if (bytesWritten >= fileSize) + { + // If we have more bytes written then close the file pointer and increase the part index we are using + f_close(&fp); + free(clmt); + memset(&fp, 0, sizeof(fp)); + currPartIdx++; + + if (currPartIdx < 10) + { + path[path_len] = '0'; + itoa(currPartIdx, &path[path_len + 1], 10); + } + else + itoa(currPartIdx, &path[path_len], 10); + + // Try to open the next file part + res = f_open(&fp, path, FA_READ); + if (res) + { + s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx); + lv_label_set_text(lbl_status, txt_buf); + manual_system_maintenance(true); + + goto exit; + } + fileSize = (u64)f_size(&fp); + bytesWritten = 0; + clmt = f_expand_cltbl(&fp, SZ_4M, 0); + } + + retryCount = 0; + num = MIN(total_size_sct, 8192); + + // Read next data block from SD. + res = f_read_fast(&fp, buf, num << 9); + manual_system_maintenance(false); + + if (res) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!"); + manual_system_maintenance(true); + + f_close(&fp); + free(clmt); + goto exit; + } + + // Write data block to L4T partition. + res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf); + + manual_system_maintenance(false); + + // If failed, retry 3 more times. + while (res) + { + msleep(150); + manual_system_maintenance(true); + + if (retryCount >= 3) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!"); + manual_system_maintenance(true); + + f_close(&fp); + free(clmt); + goto exit; + } + + res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf); + manual_system_maintenance(false); + } + + // Update completion percentage. + pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct; + if (pct != prevPct) + { + lv_bar_set_value(bar, pct); + s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct); + lv_label_set_text(label_pct, txt_buf); + manual_system_maintenance(true); + prevPct = pct; + } + + lba_curr += num; + total_size_sct -= num; + bytesWritten += num * EMMC_BLOCKSIZE; + } + lv_bar_set_value(bar, 100); + lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%"); + manual_system_maintenance(true); + + // Restore operation ended successfully. + f_close(&fp); + free(clmt); + + succeeded = true; + +exit: + free(path); + free(txt_buf); + + if (!succeeded) + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + else + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + sd_unmount(); + + return LV_RES_INV; +} + +static u32 _get_available_l4t_partition() +{ + mbr_t mbr = { 0 }; + gpt_t *gpt = zalloc(sizeof(gpt_t)); + + memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t)); + + // Read MBR. + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + // Read main GPT. + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt); + + // Search for a suitable partition. + u32 size_sct = 0; + if (!memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128) + { + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (!memcmp(gpt->entries[i].name, (char[]) { 'l', 0, '4', 0, 't', 0 }, 6)) + { + l4t_flash_ctxt.offset_sct = gpt->entries[i].lba_start; + size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + } + else + { + for (u32 i = 1; i < 4; i++) + { + if (mbr.partitions[i].type == 0x83) + { + l4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct; + size_sct = mbr.partitions[i].size_sct; + break; + } + } + } + + free(gpt); + + return size_sct; +} + +static int _get_available_android_partition() +{ + gpt_t *gpt = zalloc(sizeof(gpt_t)); + + // Read main GPT. + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt); + + // Check if GPT. + if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128) + goto out; + + // Find kernel partition. + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (gpt->entries[i].lba_start) + { + int found = !memcmp(gpt->entries[i].name, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8) ? 2 : 0; + found |= !memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6) ? 1 : 0; + + if (found) + { + free(gpt); + + return found; + } + } + + if (i > 126) + break; + } + +out: + free(gpt); + + return false; +} + +static lv_res_t _action_check_flash_linux(lv_obj_t *btn) +{ + FILINFO fno; + char path[128]; + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions..."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + manual_system_maintenance(true); + + sd_mount(); + + // Check if L4T image exists. + strcpy(path, "switchroot/install/l4t.00"); + if (f_stat(path, NULL)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Installation files not found!"); + goto error; + } + + // Find an applicable partition for L4T. + u32 size_sct = _get_available_l4t_partition(); + if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!"); + goto error; + } + + u32 idx = 0; + path[23] = 0; + + // Validate L4T images and consolidate their info. + while (true) + { + if (idx < 10) + { + path[23] = '0'; + itoa(idx, &path[23 + 1], 10); + } + else + itoa(idx, &path[23], 10); + + // Check for alignment. + if (f_stat(path, &fno)) + break; + + // Check if current part is unaligned. + if ((u64)fno.fsize % SZ_4M) + { + // Get next part filename. + idx++; + if (idx < 10) + { + path[23] = '0'; + itoa(idx, &path[23 + 1], 10); + } + else + itoa(idx, &path[23], 10); + + // If it exists, unaligned size for current part is not permitted. + if (!f_stat(path, NULL)) // NULL: Don't override current part fs info. + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!"); + goto error; + } + + // Last part. Align size to LBA (SD_BLOCKSIZE). + fno.fsize = ALIGN((u64)fno.fsize, SD_BLOCKSIZE); + idx--; + } + l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9; + + idx++; + } + + // Check if image size is bigger than the partition available. + if (l4t_flash_ctxt.image_size_sct > size_sct) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is bigger than the partition!"); + goto error; + } + + char *txt_buf = malloc(SZ_4K); + s_printf(txt_buf, + "#C7EA46 Status:# Found installation files and partition.\n" + "#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\n" + "\nDo you want to continue?", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11); + lv_label_set_text(lbl_status, txt_buf); + free(txt_buf); + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data); + goto exit; + +error: + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + +exit: + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + sd_unmount(); + + return LV_RES_OK; +} + +static lv_res_t _action_reboot_recovery(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + if (!btn_idx) + { + // Set custom reboot type to Android Recovery. + PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY; + + // Enable hekate boot configuration. + b_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN; + + // Set id to Android. + strcpy((char *)b_cfg->id, "SWANDR"); + + void (*main_ptr)() = (void *)nyx_str->hekate; + + // Deinit hardware. + sd_end(); + hw_deinit(false, 0); + + // Chainload to hekate main. + (*main_ptr)(); + } + + return LV_RES_INV; +} + +static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + bool boot_recovery = false; + + // Delete parent mbox. + mbox_action(btns, txt); + + if (btn_idx) + return LV_RES_INV; + + // Flash Android components. + char path[128]; + gpt_t *gpt = zalloc(sizeof(gpt_t)); + char *txt_buf = malloc(SZ_4K); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Android Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions..."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + manual_system_maintenance(true); + + sd_mount(); + + // Read main GPT. + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt); + + // Validate GPT header. + if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!"); + goto error; + } + + u32 offset_sct = 0; + u32 size_sct = 0; + + // Check if Kernel image should be flashed. + strcpy(path, "switchroot/install/boot.img"); + if (f_stat(path, NULL)) + { + s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n"); + goto boot_img_not_found; + } + + // Find Kernel partition. + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (!memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8)) + { + offset_sct = gpt->entries[i].lba_start; + size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + + // Flash Kernel. + if (offset_sct && size_sct) + { + u32 file_size = 0; + u8 *buf = sd_file_read(path, &file_size); + + if (file_size % 0x200) + { + file_size = ALIGN(file_size, 0x200); + u8 *buf_tmp = zalloc(file_size); + memcpy(buf_tmp, buf, file_size); + free(buf); + buf = buf_tmp; + } + + if ((file_size >> 9) > size_sct) + s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n"); + else + { + sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf); + + s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n"); + f_unlink(path); + } + + free(buf); + } + else + s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n"); + +boot_img_not_found: + lv_label_set_text(lbl_status, txt_buf); + manual_system_maintenance(true); + + // Check if Recovery should be flashed. + strcpy(path, "switchroot/install/recovery.img"); + if (f_stat(path, NULL)) + { + // Not found, try twrp.img instead. + strcpy(path, "switchroot/install/twrp.img"); + if (f_stat(path, NULL)) + { + strcat(txt_buf, "#FF8000 Warning:# Recovery image not found!\n"); + goto recovery_not_found; + } + } + + offset_sct = 0; + size_sct = 0; + + // Find Recovery partition. + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'r', 0, 'e', 0, 'c', 0, 'o', 0, 'v', 0, 'e', 0, 'r', 0, 'y', 0 }, 16)) + { + offset_sct = gpt->entries[i].lba_start; + size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + + // Flash Recovery. + if (offset_sct && size_sct) + { + u32 file_size = 0; + u8 *buf = sd_file_read(path, &file_size); + + if (file_size % 0x200) + { + file_size = ALIGN(file_size, 0x200); + u8 *buf_tmp = zalloc(file_size); + memcpy(buf_tmp, buf, file_size); + free(buf); + buf = buf_tmp; + } + + if ((file_size >> 9) > size_sct) + strcat(txt_buf, "#FF8000 Warning:# Recovery image too big!\n"); + else + { + sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf); + strcat(txt_buf, "#C7EA46 Success:# Recovery image flashed!\n"); + f_unlink(path); + } + + free(buf); + } + else + strcat(txt_buf, "#FF8000 Warning:# Recovery partition not found!\n"); + +recovery_not_found: + lv_label_set_text(lbl_status, txt_buf); + manual_system_maintenance(true); + + // Check if Device Tree should be flashed. + strcpy(path, "switchroot/install/nx-plat.dtimg"); + if (f_stat(path, NULL)) + { + strcpy(path, "switchroot/install/tegra210-icosa.dtb"); + if (f_stat(path, NULL)) + { + strcat(txt_buf, "#FF8000 Warning:# DTB image not found!"); + goto dtb_not_found; + } + } + + offset_sct = 0; + size_sct = 0; + + // Find Device Tree partition. + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (!memcmp(gpt->entries[i].name, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'd', 0, 't', 0, 'b', 0 }, 6)) + { + offset_sct = gpt->entries[i].lba_start; + size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + + // Flash Device Tree. + if (offset_sct && size_sct) + { + u32 file_size = 0; + u8 *buf = sd_file_read(path, &file_size); + + if (file_size % 0x200) + { + file_size = ALIGN(file_size, 0x200); + u8 *buf_tmp = zalloc(file_size); + memcpy(buf_tmp, buf, file_size); + free(buf); + buf = buf_tmp; + } + + if ((file_size >> 9) > size_sct) + strcat(txt_buf, "#FF8000 Warning:# DTB image too big!"); + else + { + sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf); + strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!"); + f_unlink(path); + } + + free(buf); + } + else + strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!"); + +dtb_not_found: + lv_label_set_text(lbl_status, txt_buf); + + // Check if Recovery is flashed unconditionally. + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'r', 0, 'e', 0, 'c', 0, 'o', 0, 'v', 0, 'e', 0, 'r', 0, 'y', 0 }, 16)) + { + u8 *buf = malloc(SD_BLOCKSIZE); + sdmmc_storage_read(&sd_storage, gpt->entries[i].lba_start, 1, buf); + if (!memcmp(buf, "ANDROID", 7)) + boot_recovery = true; + free(buf); + break; + } + + if (i > 126) + break; + } + +error: + if (boot_recovery) + { + // If a Recovery partition was found, ask user if rebooting into it is wanted. + strcat(txt_buf,"\n\nDo you want to reboot into Recovery\nto finish Android installation?"); + lv_label_set_text(lbl_status, txt_buf); + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_recovery); + } + else + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + free(txt_buf); + free(gpt); + + sd_unmount(); + + return LV_RES_INV; +} + +static lv_res_t _action_flash_android(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Android Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, + "This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 Recovery# if found.\n" + "These will be deleted after a successful flash.\n" + "Do you want to continue?"); + + lv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +static lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + lv_obj_del(ums_mbox); + break; + case 1: + _action_check_flash_linux(btns); + break; + case 2: + _action_flash_android(btns); + break; + case 3: + mbox_action(btns, txt); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + lv_obj_del(ums_mbox); + break; + case 1: + mbox_action(btns, txt); + _action_check_flash_linux(NULL); + return LV_RES_INV; + case 2: + mbox_action(btns, txt); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + lv_obj_del(ums_mbox); + break; + case 1: + mbox_action(btns, txt); + _action_flash_android(NULL); + return LV_RES_INV; + case 2: + mbox_action(btns, txt); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static int _backup_and_restore_files(bool backup, lv_obj_t **labels) +{ + const char *src_drv = backup ? "sd:" : "ram:"; + const char *dst_drv = backup ? "ram:" : "sd:"; + + int res = 0; + u32 total_size = 0; + u32 total_files = 0; + char *path = malloc(0x1000); + path[0] = 0; // Set default as root folder. + + // Check if Mariko Warmboot Storage exists in source drive. + f_chdrive(src_drv); + bool backup_mws = !part_info.backup_possible && !f_stat("warmboot_mariko", NULL); + bool backup_pld = !part_info.backup_possible && !f_stat("payload.bin", NULL); + + if (!part_info.backup_possible) + { + // Change path to hekate/Nyx. + strcpy(path, "bootloader"); + + // Create hekate/Nyx/MWS folders in destination drive. + f_chdrive(dst_drv); + f_mkdir("bootloader"); + if (backup_mws) + f_mkdir("warmboot_mariko"); + } + + // Copy all or hekate/Nyx files. + res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels); + + // If incomplete backup mode, copy MWS and payload.bin also. + if (!res) + { + if (backup_mws) + { + strcpy(path, "warmboot_mariko"); + res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels); + } + + if (!res && backup_pld) + { + strcpy(path, "payload.bin"); + res = _copy_file(src_drv, dst_drv, path); + } + } + + free(path); + + return res; +} + +static lv_res_t _create_mbox_start_partitioning(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + static const char *mbox_btn_map1[] = { "\222SD UMS", "\222Flash Linux", "\222Flash Android", "\221OK", "" }; + static const char *mbox_btn_map2[] = { "\222SD UMS", "\222Flash Linux", "\221OK", "" }; + static const char *mbox_btn_map3[] = { "\222SD UMS", "\222Flash Android", "\221OK", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Partition Manager#"); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + bool buttons_set = false; + + // Use safety wait if backup is not possible. + char *txt_buf = malloc(SZ_4K); + strcpy(txt_buf, "#FF8000 Partition Manager#\n\nSafety wait ends in "); + lv_mbox_set_text(mbox, txt_buf); + + u32 seconds = 5; + u32 text_idx = strlen(txt_buf); + while (seconds) + { + s_printf(txt_buf + text_idx, "%d seconds...", seconds); + lv_mbox_set_text(mbox, txt_buf); + manual_system_maintenance(true); + msleep(1000); + seconds--; + } + + lv_mbox_set_text(mbox, + "#FF8000 Partition Manager#\n\n" + "#FFDD00 Warning: Do you really want to continue?!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort."); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + free(txt_buf); + + if (!(btn_wait() & BTN_POWER)) + goto exit; + + // Start partitioning. + lv_mbox_set_text(mbox, "#FF8000 Partition Manager#"); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + lv_obj_t *lbl_paths[2]; + + // Create backup/restore paths labels. + lbl_paths[0] = lv_label_create(mbox, NULL); + lv_label_set_text(lbl_paths[0], "/"); + lv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT); + lv_cont_set_fit(lbl_paths[0], false, true); + lv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2); + lv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER); + lbl_paths[1] = lv_label_create(mbox, NULL); + lv_label_set_text(lbl_paths[1], " "); + lv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT); + lv_cont_set_fit(lbl_paths[1], false, true); + lv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2); + lv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER); + + sd_mount(); + + FATFS ram_fs; + + // Read current MBR. + sdmmc_storage_read(&sd_storage, 0, 1, &part_info.mbr_old); + + lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing Ramdisk..."); + lv_label_set_text(lbl_paths[0], "Please wait..."); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + // Initialize RAM disk. + if (ram_disk_init(&ram_fs, RAM_DISK_SZ)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to initialize Ramdisk!"); + goto error; + } + + lv_label_set_text(lbl_status, "#00DDFF Status:# Backing up files..."); + manual_system_maintenance(true); + + // Do full or hekate/Nyx backup. + if (_backup_and_restore_files(true, lbl_paths)) + { + if (part_info.backup_possible) + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!"); + else + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!\nBootloader folder exceeds 1GB or corrupt!"); + + goto error; + } + + f_mount(NULL, "sd:", 1); // Unmount SD card. + + lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting FAT32 partition..."); + lv_label_set_text(lbl_paths[0], "Please wait..."); + lv_label_set_text(lbl_paths[1], " "); + manual_system_maintenance(true); + + // Set reserved size. + u32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11); + part_rsvd_size += part_rsvd_size ? part_info.alignment : 0; // Do not reserve alignment space if no extra partitions. + disk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size); + u8 *buf = malloc(SZ_4M); + + // Set cluster size to 64KB and try to format. + u32 cluster_size = 65536; + u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M); + + if (!mkfs_error) + goto mkfs_no_error; + + // Retry formatting by halving cluster size, until one succeeds. + while (cluster_size > 4096) + { + cluster_size /= 2; + mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M); + + if (!mkfs_error) + break; + } + + if (mkfs_error) + { + // Failed to format. + s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n" + "Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error); + + lv_label_set_text(lbl_status, (char *)buf); + lv_label_set_text(lbl_paths[0], " "); + manual_system_maintenance(true); + + sd_end(); + + while (!(btn_wait() & BTN_POWER)); + + sd_mount(); + + lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files..."); + manual_system_maintenance(true); + + // Restore backed up files back to SD. + if (_backup_and_restore_files(false, lbl_paths)) + { + // Failed to restore files. Try again once more. + if (_backup_and_restore_files(false, lbl_paths)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!"); + free(buf); + goto error; + } + } + + lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!"); + f_mount(NULL, "ram:", 1); // Unmount ramdisk. + free(buf); + goto error; + } + +mkfs_no_error: + free(buf); + + // Remount sd card as it was unmounted from formatting it. + f_mount(&sd_fs, "sd:", 1); // Mount SD card. + + lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files..."); + manual_system_maintenance(true); + + // Restore backed up files back to SD. + if (_backup_and_restore_files(false, lbl_paths)) + { + // Failed to restore files. Try again once more. + if (_backup_and_restore_files(false, lbl_paths)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!"); + goto error; + } + } + + f_mount(NULL, "ram:", 1); // Unmount ramdisk. + f_chdrive("sd:"); + + // Set Volume label. + f_setlabel("0:SWITCH SD"); + + lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table..."); + lv_label_set_text(lbl_paths[0], "Please wait..."); + lv_label_set_text(lbl_paths[1], " "); + manual_system_maintenance(true); + + // Prepare MBR and GPT header and partition entries and flash them. + _prepare_and_flash_mbr_gpt(); + + // Enable/Disable buttons depending on partition layout. + if (part_info.l4t_size) + { + lv_obj_set_click(btn_flash_l4t, true); + lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL); + } + else + { + lv_obj_set_click(btn_flash_l4t, false); + lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA); + } + + // Enable/Disable buttons depending on partition layout. + if (part_info.and_size) + { + lv_obj_set_click(btn_flash_android, true); + lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL); + } + else + { + lv_obj_set_click(btn_flash_android, false); + lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA); + } + + sd_unmount(); + lv_label_set_text(lbl_status, "#00DDFF Status:# Done!"); + manual_system_maintenance(true); + + // Set buttons depending on what user chose to create. + if (part_info.l4t_size && part_info.and_size) + lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0); + else if (part_info.l4t_size) + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1); + else if (part_info.and_size) + lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2); + + if (part_info.l4t_size || part_info.and_size) + buttons_set = true; + + goto out; + +error: + f_chdrive("sd:"); + +out: + lv_obj_del(lbl_paths[0]); + lv_obj_del(lbl_paths[1]); +exit: + if (!buttons_set) + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + // Disable partitioning button. + if (btn) + lv_btn_set_state(btn, LV_BTN_STATE_INA); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + return LV_RES_OK; + case 1: + mbox_action(btns, txt); + _create_mbox_start_partitioning(NULL); + break; + case 2: + mbox_action(btns, txt); + break; + } + + return LV_RES_INV; +} + +static lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + mbox_action(btns, txt); + + if (!btn_idx) + { + mbox_action(btns, txt); + _create_mbox_start_partitioning(NULL); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_partitioning_warn(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\222SD UMS", "\222Start", "\222Cancel", "" }; + static const char *mbox_btn_map2[] = { "\222Start", "\222Cancel", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + char *txt_buf = malloc(SZ_4K); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + lv_mbox_set_text(mbox, "#FF8000 Partition Manager#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + s_printf(txt_buf, "#FFDD00 Warning: This will partition the SD Card!#\n\n"); + + if (part_info.backup_possible) + { + strcat(txt_buf, "#C7EA46 Your files will be backed up and restored!#\n" + "#FFDD00 Any other partition will be wiped!#"); + } + else + { + strcat(txt_buf, "#FFDD00 Your files will be wiped!#\n" + "#FFDD00 Any other partition will be also wiped!#\n" + "#FFDD00 Use USB UMS to copy them over!#"); + } + + lv_label_set_text(lbl_status, txt_buf); + + if (part_info.backup_possible) + lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1); + else + lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + free(txt_buf); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_partitioning_android(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + mbox_action(btns, txt); + + part_info.and_dynamic = !btn_idx; + _create_mbox_partitioning_warn(NULL); + + return LV_RES_INV; +} + +static lv_res_t _create_mbox_partitioning_andr_part(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\222Dynamic", "\222Legacy", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5); + lv_mbox_set_text(mbox, "#FF8000 Android Partitioning#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + lv_label_set_text(lbl_status, + "Please select a partition scheme:\n\n" + "#C7EA46 Dynamic:# Android 13+\n" + "#C7EA46 Legacy:# Android 10-11\n"); + + lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_android); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) { + if (part_info.and_size) + return _create_mbox_partitioning_andr_part(NULL); + else + return _create_mbox_partitioning_warn(NULL); +} + +static void _update_partition_bar() +{ + lv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos); + + // Set widths based on max bar width. + u32 total_size = (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB; + u32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size; + u32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size; + u32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size; + u32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size; + + // Update bar widths. + lv_obj_set_size(part_info.bar_hos, bar_hos_size, LV_DPI / 2); + lv_obj_set_size(part_info.bar_emu, bar_emu_size, LV_DPI / 2); + lv_obj_set_size(part_info.bar_l4t, bar_l4t_size, LV_DPI / 2); + lv_obj_set_size(part_info.bar_and, bar_and_size, LV_DPI / 2); + + // Re-align bars. + lv_obj_align(part_info.bar_emu, part_info.bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + lv_obj_align(part_info.bar_l4t, part_info.bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + lv_obj_align(part_info.bar_and, part_info.bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + // Set emuMMC blending separator sizes and realign. + lv_obj_set_size(part_info.sep_emu, bar_emu_size ? 8 : 0, LV_DPI / 2); + lv_obj_align(part_info.sep_emu, part_info.bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + // Set L4T blending separator sizes and realign. + lv_obj_set_size(part_info.sep_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 2); + lv_obj_align(part_info.sep_l4t, part_info.bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + // Set Android blending separator sizes and realign. + lv_obj_set_size(part_info.sep_and, bar_and_size ? 8 : 0, LV_DPI / 2); + lv_obj_align(part_info.sep_and, part_info.bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0); +} + +static lv_res_t _action_slider_emu(lv_obj_t *slider) +{ + #define EMUMMC_32GB_FULL 29856 + #define EMUMMC_64GB_FULL (59664 + 1) // 1MB extra for backup GPT. + + static const u32 rsvd_mb = 4 + 4 + 16 + 8; // BOOT0 + BOOT1 + 16MB offset + 8MB alignment. + u32 size; + char lbl_text[64]; + bool prev_emu_double = part_info.emu_double; + int slide_val = lv_slider_get_value(slider); + u32 max_emmc_size = !part_info.emmc_is_64gb ? EMUMMC_32GB_FULL : EMUMMC_64GB_FULL; + + part_info.emu_double = false; + + size = (slide_val > 10 ? (slide_val - 10) : slide_val) + 3; // Min 4GB. + size *= 1024; // Convert to GB. + size += rsvd_mb; // Add reserved size. + + if (!slide_val) + size = 0; // Reset if 0. + else if (slide_val >= 11) + { + size *= 2; + part_info.emu_double = true; + } + + // Handle special cases. 2nd value is for 64GB Aula. + if (slide_val == 10) + size = max_emmc_size; + else if (slide_val == 20) + size = 2 * max_emmc_size; + + // Sanitize sizes based on new HOS size. + s32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size; + if (hos_size > HOS_MIN_SIZE_MB) + { + part_info.emu_size = size; + part_info.hos_size = hos_size; + + s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10); + lv_label_set_text(part_info.lbl_hos, lbl_text); + lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10); + + if (!part_info.emu_double) + { + if (slide_val != 10) + s_printf(lbl_text, "#FF3C28 %d GiB#", size >> 10); + else + s_printf(lbl_text, "#FF3C28 %d FULL#", size >> 10); + } + else + s_printf(lbl_text, "#FFDD00 2x##FF3C28 %d#", size >> 11); + lv_label_set_text(part_info.lbl_emu, lbl_text); + } + else + { + u32 emu_size = part_info.emu_size; + + if (emu_size == max_emmc_size) + emu_size = 10; + else if (emu_size == 2 * max_emmc_size) + emu_size = 20; + else if (emu_size) + { + if (prev_emu_double) + emu_size /= 2; + emu_size -= rsvd_mb; + emu_size /= 1024; + emu_size -= 3; + + if (prev_emu_double) + emu_size += 11; + } + + int new_slider_val = emu_size; + part_info.emu_double = prev_emu_double ? true : false; + + lv_slider_set_value(slider, new_slider_val); + } + + _update_partition_bar(); + + return LV_RES_OK; +} + +static lv_res_t _action_slider_l4t(lv_obj_t *slider) +{ + char lbl_text[64]; + + u32 size = (u32)lv_slider_get_value(slider) << 10; + if (size < 4096) + size = 0; + else if (size < 8192) + size = 8192; + + s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size; + + // Sanitize sizes based on new HOS size. + if (hos_size > HOS_MIN_SIZE_MB) + { + if (size <= 8192) + lv_slider_set_value(slider, size >> 10); + } + else + { + size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048; + hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size; + if (hos_size < HOS_MIN_SIZE_MB || size < 8192) + { + lv_slider_set_value(slider, part_info.l4t_size >> 10); + goto out; + } + lv_slider_set_value(slider, size >> 10); + } + + part_info.l4t_size = size; + part_info.hos_size = hos_size; + + s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10); + lv_label_set_text(part_info.lbl_hos, lbl_text); + lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10); + s_printf(lbl_text, "#00DDFF %d GiB#", size >> 10); + lv_label_set_text(part_info.lbl_l4t, lbl_text); + + _update_partition_bar(); + +out: + return LV_RES_OK; +} + +static lv_res_t _action_slider_and(lv_obj_t *slider) +{ + char lbl_text[64]; + + u32 user_size = (u32)lv_slider_get_value(slider) << 10; + if (user_size < 2048) + user_size = 0; + else if (user_size < 4096) + user_size = 4096; + + u32 and_size = user_size ? (user_size + ANDROID_SYSTEM_SIZE_MB) : 0; + s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size; + + // Sanitize sizes based on new HOS size. + if (hos_size > HOS_MIN_SIZE_MB) + { + if (user_size <= 4096) + lv_slider_set_value(slider, user_size >> 10); + } + else + { + and_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048; + hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size; + if (hos_size < HOS_MIN_SIZE_MB || and_size < 8192) + { + lv_slider_set_value(slider, part_info.and_size >> 10); + goto out; + } + user_size = and_size - ANDROID_SYSTEM_SIZE_MB; + lv_slider_set_value(slider, user_size >> 10); + } + + part_info.and_size = and_size; + part_info.hos_size = hos_size; + + s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10); + lv_label_set_text(part_info.lbl_hos, lbl_text); + lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10); + s_printf(lbl_text, "#FF8000 %d GiB#", user_size >> 10); + lv_label_set_text(part_info.lbl_and, lbl_text); + + _update_partition_bar(); + +out: + return LV_RES_OK; +} + +static lv_res_t _mbox_check_files_total_size_option(lv_obj_t *btns, const char *txt) +{ + // If "don't backup" button was pressed, disable backup/restore of files. + if (!lv_btnm_get_pressed(btns)) + part_info.backup_possible = false; + + mbox_action(btns, txt); + + return LV_RES_INV; +} + +static void _create_mbox_check_files_total_size() +{ + static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind; + static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg; + + // Set HOS bar style. + lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic); + bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00); + bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color; + + // Set emuMMC bar style. + lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic); + bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28); + bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color; + + // Set L4T bar style. + lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic); + bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF); + bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color; + + // Set GPT bar style. + lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic); + bar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF); + bar_and_ind.body.grad_color = bar_and_ind.body.main_color; + + // Set separator styles. + lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont); + sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28); + sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color; + sep_emu_bg.body.radius = 0; + lv_style_copy(&sep_l4t_bg, &sep_emu_bg); + sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF); + sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color; + lv_style_copy(&sep_and_bg, &sep_emu_bg); + sep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF); + sep_and_bg.body.grad_color = sep_and_bg.body.main_color; + + char *txt_buf = malloc(SZ_8K); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + static const char *mbox_btn_map2[] = { "\222Don't Backup", "\222OK", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "Analyzing SD card usage. This might take a while..."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + manual_system_maintenance(true); + + char *path = malloc(0x1000); + u32 total_files = 0; + u32 total_size = 0; + path[0] = 0; + + // Check total size of files. + int res = _stat_and_copy_files("sd:", NULL, path, &total_files, &total_size, NULL); + + // Not more than 1.0GB. + part_info.backup_possible = !res && !(total_size > (RAM_DISK_SZ - SZ_16M)); + + if (part_info.backup_possible) + { + s_printf(txt_buf, + "#96FF00 The SD Card files will be backed up automatically!#\n" + "#FFDD00 Any other partition will be wiped!#\n" + "#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB", total_files, total_size >> 20); + lv_mbox_set_text(mbox, txt_buf); + } + else + { + lv_mbox_set_text(mbox, + "#FFDD00 The SD Card cannot be backed up automatically!#\n" + "#FFDD00 Any other partition will be also wiped!#\n\n" + "You will be asked to back up your files later via UMS."); + } + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_fit(h1, false, true); + lv_cont_set_style(h1, &lv_style_transp_tight); + lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3); + + lv_obj_t *lbl_part = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_part, true); + lv_label_set_text(lbl_part, "#00DDFF Current MBR partition layout:#"); + + // Read current MBR. + mbr_t mbr = { 0 }; + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + // Calculate MBR partitions size. + total_size = (sd_storage.sec_cnt - AU_ALIGN_SECTORS) / SECTORS_PER_GB; + u32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / SECTORS_PER_GB) / total_size; + u32 bar_emu_size = 0; + for (u32 i = 1; i < 4; i++) + if (mbr.partitions[i].type == 0xE0) + bar_emu_size += mbr.partitions[i].size_sct; + bar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / SECTORS_PER_GB) / total_size; + + u32 bar_l4t_size = 0; + for (u32 i = 1; i < 4; i++) + if (mbr.partitions[i].type == 0x83) + bar_l4t_size += mbr.partitions[i].size_sct; + bar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / SECTORS_PER_GB) / total_size; + + u32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size; + + // Create HOS bar. + lv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL); + lv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3); + lv_bar_set_range(bar_mbr_hos, 0, 1); + lv_bar_set_value(bar_mbr_hos, 1); + lv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind); + lv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6); + + // Create emuMMC bar. + lv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos); + lv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3); + lv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind); + lv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + // Create L4T bar. + lv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos); + lv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3); + lv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind); + lv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + // Create GPT bar. + lv_obj_t *bar_mbr_gpt = lv_bar_create(h1, bar_mbr_hos); + lv_obj_set_size(bar_mbr_gpt, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3); + lv_bar_set_style(bar_mbr_gpt, LV_BAR_STYLE_INDIC, &bar_and_ind); + lv_obj_align(bar_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + // Create emuMMC separator. + lv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL); + lv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3); + lv_obj_set_style(sep_mbr_emu, &sep_emu_bg); + lv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + // Create L4T separator. + lv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu); + lv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3); + lv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg); + lv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + // Create GPT separator. + lv_obj_t *sep_mbr_gpt = lv_cont_create(h1, sep_mbr_emu); + lv_obj_set_size(sep_mbr_gpt, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3); + lv_obj_set_style(sep_mbr_gpt, &sep_and_bg); + lv_obj_align(sep_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + // Print partition table info. + s_printf(txt_buf, + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x", + mbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct, + mbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct, + mbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct, + mbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct); + + lv_obj_t *lbl_table = lv_label_create(h1, NULL); + lv_label_set_style(lbl_table, &monospace_text); + lv_label_set_text(lbl_table, txt_buf); + lv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI); + + if (!part_info.backup_possible) + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + else + lv_mbox_add_btns(mbox, mbox_btn_map2, _mbox_check_files_total_size_option); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + free(txt_buf); + free(path); +} + +static lv_res_t _action_fix_mbr(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + lv_mbox_set_text(mbox, "#FF8000 Fix Hybrid MBR#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + mbr_t mbr[2] = { 0 }; + gpt_t *gpt = zalloc(sizeof(gpt_t)); + gpt_header_t gpt_hdr_backup = { 0 }; + + bool has_mbr_attributes = false; + bool hybrid_mbr_changed = false; + bool gpt_partition_exists = false; + + // Try to init sd card. No need for valid MBR. + if (!sd_mount() && !sd_get_card_initialized()) + { + lv_label_set_text(lbl_status, "#FFDD00 Failed to init SD!#"); + goto out; + } + + sdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]); + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt); + + memcpy(&mbr[1], &mbr[0], sizeof(mbr_t)); + + sd_unmount(); + + // Check for secret MBR attributes. + if (gpt->entries[0].part_guid[7]) + has_mbr_attributes = true; + + // Check if there's a GPT Protective partition. + for (u32 i = 0; i < 4; i++) + { + if (mbr[0].partitions[i].type == 0xEE) + gpt_partition_exists = true; + } + + // Check if GPT is valid. + if (!gpt_partition_exists || memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128) + { + lv_label_set_text(lbl_status, "#FFDD00 Warning:# No valid GPT was found!"); + + gpt_partition_exists = false; + + if (has_mbr_attributes) + goto check_changes; + else + goto out; + } + + sdmmc_storage_read(&sd_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup); + + // Parse GPT. + LIST_INIT(gpt_parsed); + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t)); + + if (gpt->entries[i].lba_start < gpt->header.first_use_lba) + continue; + + part->index = i; + part->lba_start = gpt->entries[i].lba_start; + part->lba_end = gpt->entries[i].lba_end; + + // ASCII conversion. Copy only the LSByte of the UTF-16LE name. + for (u32 j = 0; j < 36; j++) + part->name[j] = gpt->entries[i].name[j]; + part->name[35] = 0; + + list_append(&gpt_parsed, &part->link); + } + + // Set FAT and emuMMC partitions. + u32 mbr_idx = 1; + bool found_hos_data = false; + LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link) + { + // FatFS simple GPT found a fat partition, set it. + if (sd_fs.part_type && !part->index) + { + mbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC; + mbr[1].partitions[0].start_sct = part->lba_start; + mbr[1].partitions[0].size_sct = (part->lba_end - part->lba_start + 1); + } + + // FatFS simple GPT didn't find a fat partition as the first one. + if (!sd_fs.part_type && !found_hos_data && !strcmp(part->name, "hos_data")) + { + mbr[1].partitions[0].type = 0xC; + mbr[1].partitions[0].start_sct = part->lba_start; + mbr[1].partitions[0].size_sct = (part->lba_end - part->lba_start + 1); + found_hos_data = true; + } + + // Set up to max 2 emuMMC partitions. + if (!strcmp(part->name, "emummc") || !strcmp(part->name, "emummc2")) + { + mbr[1].partitions[mbr_idx].type = 0xE0; + mbr[1].partitions[mbr_idx].start_sct = part->lba_start; + mbr[1].partitions[mbr_idx].size_sct = (part->lba_end - part->lba_start + 1); + mbr_idx++; + } + + // Total reached last slot. + if (mbr_idx >= 3) + break; + } + + emmc_gpt_free(&gpt_parsed); + + // Set GPT protective partition. + mbr[1].partitions[mbr_idx].type = 0xEE; + mbr[1].partitions[mbr_idx].start_sct = 1; + mbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1; + + // Check for differences. + for (u32 i = 1; i < 4; i++) + { + if ((mbr[0].partitions[i].type != mbr[1].partitions[i].type) || + (mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) || + (mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct)) + { + hybrid_mbr_changed = true; + break; + } + } + +check_changes: + if (!hybrid_mbr_changed && !has_mbr_attributes) + { + lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#"); + goto out; + } + + char *txt_buf = malloc(SZ_16K); + + // Current MBR info. + s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n"); + s_printf(txt_buf + strlen(txt_buf), + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n", + mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct, + mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct, + mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct, + mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct); + + // New MBR info. + s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n"); + s_printf(txt_buf + strlen(txt_buf), + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x", + mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct, + mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct, + mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct, + mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct); + + lv_label_set_text(lbl_status, txt_buf); + lv_label_set_style(lbl_status, &monospace_text); + + free(txt_buf); + + lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER); + + lv_label_set_text(lbl_status, + "#FF8000 Warning: Do you really want to continue?!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + manual_system_maintenance(true); + + if (btn_wait() & BTN_POWER) + { + sd_mount(); + + // Write MBR. + if (hybrid_mbr_changed) + sdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]); + + // Fix MBR secret attributes. + if (has_mbr_attributes) + { + // Clear secret attributes. + gpt->entries[0].part_guid[7] = 0; + + if (gpt_partition_exists) + { + // Fix CRC32s. + u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents; + gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size); + gpt->header.crc32 = 0; // Set to 0 for calculation. + gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size); + + gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32; + gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation. + gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size); + + // Write main GPT. + u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE); + sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt); + + // Write backup GPT partition table. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries); + + // Write backup GPT header. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup); + } + else + { + // Only write the relevant sector if the only change is MBR attributes. + sdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]); + } + } + + sd_unmount(); + + lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#"); + } + else + lv_label_set_text(lbl_status, "#FFDD00 Warning: The Hybrid MBR Fix was canceled!#"); + +out: + free(gpt); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +lv_res_t create_window_partition_manager(lv_obj_t *btn) +{ + lv_obj_t *win = nyx_create_standard_window(SYMBOL_SD" Partition Manager"); + + lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR", _action_fix_mbr); + + static lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg; + static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind; + static lv_style_t bar_hos_btn, bar_emu_btn, bar_l4t_btn, bar_and_btn; + static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg; + + // Set HOS bar styles. + lv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg); + bar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000); + bar_hos_bg.body.grad_color = bar_hos_bg.body.main_color; + lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic); + bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00); + bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color; + lv_style_copy(&bar_hos_btn, lv_theme_get_current()->slider.knob); + bar_hos_btn.body.main_color = LV_COLOR_HEX(0x77CC00); + bar_hos_btn.body.grad_color = bar_hos_btn.body.main_color; + + // Set eMUMMC bar styles. + lv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg); + bar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00); + bar_emu_bg.body.grad_color = bar_emu_bg.body.main_color; + lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic); + bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28); + bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color; + lv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob); + bar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200); + bar_emu_btn.body.grad_color = bar_emu_btn.body.main_color; + lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont); + sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28); + sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color; + sep_emu_bg.body.radius = 0; + + // Set L4T bar styles. + lv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg); + bar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80); + bar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color; + lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic); + bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF); + bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color; + lv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob); + bar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC); + bar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color; + lv_style_copy(&sep_l4t_bg, &sep_emu_bg); + sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF); + sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color; + + // Set Android bar styles. + lv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg); + bar_and_bg.body.main_color = LV_COLOR_HEX(0x804000); + bar_and_bg.body.grad_color = bar_and_bg.body.main_color; + lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic); + bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000); + bar_and_ind.body.grad_color = bar_and_ind.body.main_color; + lv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob); + bar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600); + bar_and_btn.body.grad_color = bar_and_btn.body.main_color; + lv_style_copy(&sep_and_bg, &sep_emu_bg); + sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000); + sep_and_bg.body.grad_color = sep_and_bg.body.main_color; + + lv_obj_t *sep = lv_label_create(win, NULL); + lv_label_set_static_text(sep, ""); + lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(win, NULL); + lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI); + + if (!sd_mount()) + { + lv_obj_t *lbl = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl, true); + lv_label_set_text(lbl, "#FFDD00 Failed to init SD!#"); + return LV_RES_OK; + } + + memset(&part_info, 0, sizeof(partition_ctxt_t)); + _create_mbox_check_files_total_size(); + + char *txt_buf = malloc(SZ_8K); + + part_info.total_sct = sd_storage.sec_cnt; + + // Align down total size to ensure alignment of all partitions after HOS one. + part_info.alignment = part_info.total_sct - ALIGN_DOWN(part_info.total_sct, AU_ALIGN_SECTORS); + part_info.total_sct -= part_info.alignment; + + u32 extra_sct = AU_ALIGN_SECTORS + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB. + + // Set initial HOS partition size, so the correct cluster size can be selected. + part_info.hos_size = (part_info.total_sct >> 11) - 16; // Important if there's no slider change. + + // Check if eMMC should be 64GB (Aula). + part_info.emmc_is_64gb = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA; + + // Read current MBR. + mbr_t mbr = { 0 }; + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + u32 bar_hos_size = lv_obj_get_width(h1); + u32 bar_emu_size = 0; + u32 bar_l4t_size = 0; + u32 bar_and_size = 0; + + lv_obj_t *lbl = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl, true); + lv_label_set_text(lbl, "Choose #FFDD00 new# partition layout:"); + + // Create disk layout blocks. + // HOS partition block. + lv_obj_t *bar_hos = lv_bar_create(h1, NULL); + lv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2); + lv_bar_set_range(bar_hos, 0, 1); + lv_bar_set_value(bar_hos, 1); + lv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind); + lv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6); + part_info.bar_hos = bar_hos; + + // emuMMC partition block. + lv_obj_t *bar_emu = lv_bar_create(h1, bar_hos); + lv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2); + lv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind); + lv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + part_info.bar_emu = bar_emu; + + // L4T partition block. + lv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos); + lv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2); + lv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind); + lv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + part_info.bar_l4t = bar_l4t; + + // Android partition block. + lv_obj_t *bar_and = lv_bar_create(h1, bar_hos); + lv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2); + lv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind); + lv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + part_info.bar_and = bar_and; + + // HOS partition block. + lv_obj_t *sep_emu = lv_cont_create(h1, NULL); + lv_cont_set_fit(sep_emu, false, false); + lv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8. + lv_obj_set_style(sep_emu, &sep_emu_bg); + lv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + part_info.sep_emu = sep_emu; + + // Create disk layout blending separators. + lv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu); + lv_obj_set_style(sep_l4t, &sep_l4t_bg); + lv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + part_info.sep_l4t = sep_l4t; + + lv_obj_t *sep_and = lv_cont_create(h1, sep_emu); + lv_obj_set_style(sep_and, &sep_and_bg); + lv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + part_info.sep_and = sep_and; + + // Create slider type labels. + lv_obj_t *lbl_hos = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_hos, true); + lv_label_set_static_text(lbl_hos, "#96FF00 "SYMBOL_DOT" HOS (FAT32):#"); + lv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + + lv_obj_t *lbl_emu = lv_label_create(h1, lbl_hos); + lv_label_set_static_text(lbl_emu, "#FF3C28 "SYMBOL_DOT" emuMMC (RAW):#"); + lv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + lv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos); + lv_label_set_static_text(lbl_l4t, "#00DDFF "SYMBOL_DOT" Linux (EXT4):#"); + lv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + lv_obj_t *lbl_and = lv_label_create(h1, lbl_hos); + lv_label_set_static_text(lbl_and, "#FF8000 "SYMBOL_DOT" Android (USER):#"); + lv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + // Create HOS size slider. Non-interactive. + lv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL); + lv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17); + lv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB); + lv_bar_set_value(slider_bar_hos, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB); + lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg); + lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind); + lv_obj_align(slider_bar_hos, lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 6 / 4, 0); + part_info.slider_bar_hos = slider_bar_hos; + + // Create emuMMC size slider. + lv_obj_t *slider_emu = lv_slider_create(h1, NULL); + lv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3); + lv_slider_set_range(slider_emu, 0, 20); + lv_slider_set_value(slider_emu, 0); + lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg); + lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind); + lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn); + lv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5); + lv_slider_set_action(slider_emu, _action_slider_emu); + part_info.slider_emu = slider_bar_hos; + + // Create L4T size slider. + lv_obj_t *slider_l4t = lv_slider_create(h1, NULL); + lv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3); + lv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB); + lv_slider_set_value(slider_l4t, 0); + lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg); + lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind); + lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn); + lv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3); + lv_slider_set_action(slider_l4t, _action_slider_l4t); + part_info.slider_l4t = slider_l4t; + + // Create Android size slider. + lv_obj_t *slider_and = lv_slider_create(h1, NULL); + lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3); + lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (ANDROID_SYSTEM_SIZE_MB / 1024)); // Subtract android reserved size. + lv_slider_set_value(slider_and, 0); + lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg); + lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind); + lv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn); + lv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3); + lv_slider_set_action(slider_and, _action_slider_and); + part_info.slider_and = slider_and; + + // Create HOS size label. + lv_obj_t *lbl_sl_hos = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_sl_hos, true); + s_printf(txt_buf, "#96FF00 %d GiB#", (part_info.total_sct - AU_ALIGN_SECTORS) >> 11 >> 10); + lv_label_set_text(lbl_sl_hos, txt_buf); + lv_obj_align(lbl_sl_hos, slider_bar_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 4 / 7, 0); + part_info.lbl_hos = lbl_sl_hos; + + // Create emuMMC size label. + lv_obj_t *lbl_sl_emu = lv_label_create(h1, lbl_sl_hos); + lv_label_set_text(lbl_sl_emu, "#FF3C28 0 GiB#"); + lv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + part_info.lbl_emu = lbl_sl_emu; + + // Create L4T size label. + lv_obj_t *lbl_sl_l4t = lv_label_create(h1, lbl_sl_hos); + lv_label_set_text(lbl_sl_l4t, "#00DDFF 0 GiB#"); + lv_obj_align(lbl_sl_l4t, lbl_sl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + part_info.lbl_l4t = lbl_sl_l4t; + + // Create Android size label. + lv_obj_t *lbl_sl_and = lv_label_create(h1, lbl_sl_hos); + lv_label_set_text(lbl_sl_and, "#FF8000 0 GiB#"); + lv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + part_info.lbl_and = lbl_sl_and; + + // Set partition manager notes. + lv_obj_t *lbl_notes = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_notes, true); + lv_label_set_static_text(lbl_notes, + "Note 1: Only up to #C7EA46 1GB# can be backed up. If more, you will be asked to back them manually at the next step.\n" + "Note 2: Resized emuMMC formats the USER partition. A save data manager can be used to move them over.\n" + "Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n"); + lv_label_set_style(lbl_notes, &hint_small_style); + lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5); + + // Create UMS button. + lv_obj_t *btn1 = lv_btn_create(h1, NULL); + lv_obj_t *label_btn = lv_label_create(btn1, NULL); + lv_btn_set_fit(btn1, true, true); + lv_label_set_static_text(label_btn, SYMBOL_USB" SD UMS"); + lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5); + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd); + + // Create Flash Linux button. + btn_flash_l4t = lv_btn_create(h1, NULL); + lv_obj_t *label_btn2 = lv_label_create(btn_flash_l4t, NULL); + lv_btn_set_fit(btn_flash_l4t, true, true); + lv_label_set_static_text(label_btn2, SYMBOL_DOWNLOAD" Flash Linux"); + lv_obj_align(btn_flash_l4t, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0); + lv_btn_set_action(btn_flash_l4t, LV_BTN_ACTION_CLICK, _action_check_flash_linux); + + // Disable Flash Linux button if partition not found. + u32 size_sct = _get_available_l4t_partition(); + if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000) + { + lv_obj_set_click(btn_flash_l4t, false); + lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA); + } + + int part_type_and = _get_available_android_partition(); + + // Create Flash Android button. + btn_flash_android = lv_btn_create(h1, NULL); + label_btn = lv_label_create(btn_flash_android, NULL); + lv_btn_set_fit(btn_flash_android, true, true); + switch (part_type_and) + { + case 0: // Disable Flash Android button if partition not found. + lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android"); + lv_obj_set_click(btn_flash_android, false); + lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA); + break; + case 1: // Android 10/11. + lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 10/11"); + break; + case 2: // Android 13+ + lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 13+"); + break; + } + lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0); + lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android); + + // Create next step button. + btn1 = lv_btn_create(h1, NULL); + label_btn = lv_label_create(btn1, NULL); + lv_btn_set_fit(btn1, true, true); + lv_label_set_static_text(label_btn, SYMBOL_SD" Next Step"); + lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5); + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next); + + free(txt_buf); + + sd_unmount(); + + return LV_RES_OK; +} diff --git a/nyx/nyx_gui/soc/hw_init.h b/nyx/nyx_gui/frontend/gui_tools_partition_manager.h similarity index 79% rename from nyx/nyx_gui/soc/hw_init.h rename to nyx/nyx_gui/frontend/gui_tools_partition_manager.h index fe4defa..005016a 100644 --- a/nyx/nyx_gui/soc/hw_init.h +++ b/nyx/nyx_gui/frontend/gui_tools_partition_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 CTCaer + * Copyright (c) 2019-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,11 +14,9 @@ * along with this program. If not, see . */ -#ifndef _HW_INIT_H_ -#define _HW_INIT_H_ +#ifndef _GUI_TOOLS_PART_MANAGER_H_ +#define _GUI_TOOLS_PART_MANAGER_H_ -#include "../utils/types.h" - -void reconfig_hw_workaround(bool extra_reconfig, u32 magic); +lv_res_t create_window_partition_manager(lv_obj_t *btn); #endif diff --git a/nyx/nyx_gui/gfx/di.c b/nyx/nyx_gui/gfx/di.c deleted file mode 100644 index f7ccc4d..0000000 --- a/nyx/nyx_gui/gfx/di.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "di.h" -#include "../gfx/gfx.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../soc/clock.h" -#include "../soc/gpio.h" -#include "../soc/i2c.h" -#include "../soc/pinmux.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -#include "di.inl" - -static u32 _display_ver = 0; - -static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) -{ - u32 end = get_tmr_us() + timeout; - while (get_tmr_us() < end && DSI(off) & mask) - ; - usleep(5); -} - -void display_init() -{ - // Power on. - max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); - - // Enable Display Interface specific clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL. - - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X. - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). - - // Disable deap power down. - PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; - PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; - - // Config LCD and Backlight pins. - PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; - - // Set Backlight +-5V pins mode and direction - gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); - - // Enable Backlight power. - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable. - usleep(10000); - - // Configure Backlight pins (PWM, EN, RST). - gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. - - // Power up supply regulator for display interface. - MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0; - - // Set DISP1 clock source and parrent clock. - exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4); - - // Setup display communication interfaces. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94); - exec_cfg((u32 *)DSI_BASE, _display_config_3, 61); - usleep(10000); - - // Enable Backlight Reset. - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); - usleep(60000); - - // Setups DSI packet configuration and request display id. - DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; - DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; - _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); - - usleep(5000); - - _display_ver = DSI(_DSIREG(DSI_RD_DATA)); - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_4, 43); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(180000); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(20000); - - // Configure PLLD for DISP1. - exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3); - - // Finalize DSI configuration. - exec_cfg((u32 *)DSI_BASE, _display_config_5, 21); - DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; - exec_cfg((u32 *)DSI_BASE, _display_config_7, 10); - usleep(10000); - - // Calibrate display communication pads. - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6); - exec_cfg((u32 *)DSI_BASE, _display_config_9, 4); - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16); - usleep(10000); - - // Enable video display controller. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113); -} - -void display_backlight_pwm_init() -{ - clock_enable_pwm(); - - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. - - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source. - gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. -} - -void display_backlight(bool enable) -{ - gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); // Backlight PWM GPIO. -} - -void display_backlight_brightness(u32 brightness, u32 step_delay) -{ - u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF; - if (brightness == old_value) - return; - - if (brightness > 255) - brightness = 255; - - if (old_value < brightness) - { - for (u32 i = old_value; i < brightness + 1; i++) - { - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. - usleep(step_delay); - } - } - else - { - for (u32 i = old_value; i > brightness; i--) - { - PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. - usleep(step_delay); - } - } - if (!brightness) - PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; -} - -void display_end() -{ - display_backlight_brightness(0, 1000); - - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1; - DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF - - DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. - - // De-initialize video controller. - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17); - exec_cfg((u32 *)DSI_BASE, _display_config_13, 16); - usleep(10000); - - // De-initialize display panel. - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_14, 22); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - usleep(50000); - - // Disable display and backlight pins. - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. - usleep(10000); - - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. - usleep(10000); - - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. - usleep(10000); - - // Disable Display Interface specific clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X. - - // Power down pads. - DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); - DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; - - // Switch to automatic function mode. - gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. - - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1; -} - -void display_color_screen(u32 color) -{ - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8); - - // Configure display to show single color. - DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; - DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; - - usleep(35000); - - display_backlight(true); -} - -u32 *display_init_framebuffer() -{ - // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); - - usleep(35000); - - return (u32 *)NYX_FB_ADDRESS; -} - -u32 *display_init_framebuffer2() -{ - // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer2, 32); - - usleep(35000); - - return (u32 *)NYX_FB_ADDRESS; -} - diff --git a/nyx/nyx_gui/gfx/di.h b/nyx/nyx_gui/gfx/di.h deleted file mode 100644 index 10c1e85..0000000 --- a/nyx/nyx_gui/gfx/di.h +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 _DI_H_ -#define _DI_H_ - -#include "../../../common/memory_map.h" -#include "../utils/types.h" - -/*! Display registers. */ -#define _DIREG(reg) ((reg) * 4) - -#define DC_CMD_GENERAL_INCR_SYNCPT 0x00 - -#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 -#define SYNCPT_CNTRL_NO_STALL (1 << 8) -#define SYNCPT_CNTRL_SOFT_RESET (1 << 0) - -#define DC_CMD_CONT_SYNCPT_VSYNC 0x28 -#define SYNCPT_VSYNC_ENABLE (1 << 8) - -#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 - -#define DC_CMD_DISPLAY_COMMAND 0x32 -#define DISP_CTRL_MODE_STOP (0 << 5) -#define DISP_CTRL_MODE_C_DISPLAY (1 << 5) -#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) -#define DISP_CTRL_MODE_MASK (3 << 5) - -#define DC_CMD_DISPLAY_POWER_CONTROL 0x36 -#define PW0_ENABLE (1 << 0) -#define PW1_ENABLE (1 << 2) -#define PW2_ENABLE (1 << 4) -#define PW3_ENABLE (1 << 6) -#define PW4_ENABLE (1 << 8) -#define PM0_ENABLE (1 << 16) -#define PM1_ENABLE (1 << 18) - -#define DC_CMD_INT_MASK 0x38 -#define DC_CMD_INT_ENABLE 0x39 - -#define DC_CMD_STATE_ACCESS 0x40 -#define READ_MUX (1 << 0) -#define WRITE_MUX (1 << 2) - -#define DC_CMD_STATE_CONTROL 0x41 -#define GENERAL_ACT_REQ (1 << 0) -#define WIN_A_ACT_REQ (1 << 1) -#define WIN_B_ACT_REQ (1 << 2) -#define WIN_C_ACT_REQ (1 << 3) -#define CURSOR_ACT_REQ (1 << 7) -#define GENERAL_UPDATE (1 << 8) -#define WIN_A_UPDATE (1 << 9) -#define WIN_B_UPDATE (1 << 10) -#define WIN_C_UPDATE (1 << 11) -#define CURSOR_UPDATE (1 << 15) -#define NC_HOST_TRIG (1 << 24) - -#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 -#define WINDOW_A_SELECT (1 << 4) -#define WINDOW_B_SELECT (1 << 5) -#define WINDOW_C_SELECT (1 << 6) - -#define DC_CMD_REG_ACT_CONTROL 0x043 - -#define DC_COM_CRC_CONTROL 0x300 -#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) -#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) - -#define DC_COM_DSC_TOP_CTL 0x33E - -#define DC_DISP_DISP_WIN_OPTIONS 0x402 -#define HDMI_ENABLE (1 << 30) -#define DSI_ENABLE (1 << 29) -#define SOR1_TIMING_CYA (1 << 27) -#define SOR1_ENABLE (1 << 26) -#define SOR_ENABLE (1 << 25) -#define CURSOR_ENABLE (1 << 16) - -#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 -#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 -#define DC_DISP_DISP_TIMING_OPTIONS 0x405 -#define DC_DISP_REF_TO_SYNC 0x406 -#define DC_DISP_SYNC_WIDTH 0x407 -#define DC_DISP_BACK_PORCH 0x408 -#define DC_DISP_ACTIVE 0x409 -#define DC_DISP_FRONT_PORCH 0x40A - -#define DC_DISP_DISP_CLOCK_CONTROL 0x42E -#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) -#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) -#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) -#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) -#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) -#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) -#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) -#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) -#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) -#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) -#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) -#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) -#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) -#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) - -#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F -#define DISP_DATA_FORMAT_DF1P1C (0 << 0) -#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) -#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) -#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) -#define DISP_DATA_FORMAT_DF2S (4 << 0) -#define DISP_DATA_FORMAT_DF3S (5 << 0) -#define DISP_DATA_FORMAT_DFSPI (6 << 0) -#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) -#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) -#define DISP_ALIGNMENT_MSB (0 << 8) -#define DISP_ALIGNMENT_LSB (1 << 8) -#define DISP_ORDER_RED_BLUE (0 << 9) -#define DISP_ORDER_BLUE_RED (1 << 9) - -#define DC_DISP_DISP_COLOR_CONTROL 0x430 -#define DITHER_CONTROL_MASK (3 << 8) -#define DITHER_CONTROL_DISABLE (0 << 8) -#define DITHER_CONTROL_ORDERED (2 << 8) -#define DITHER_CONTROL_ERRDIFF (3 << 8) -#define BASE_COLOR_SIZE_MASK (0xf << 0) -#define BASE_COLOR_SIZE_666 (0 << 0) -#define BASE_COLOR_SIZE_111 (1 << 0) -#define BASE_COLOR_SIZE_222 (2 << 0) -#define BASE_COLOR_SIZE_333 (3 << 0) -#define BASE_COLOR_SIZE_444 (4 << 0) -#define BASE_COLOR_SIZE_555 (5 << 0) -#define BASE_COLOR_SIZE_565 (6 << 0) -#define BASE_COLOR_SIZE_332 (7 << 0) -#define BASE_COLOR_SIZE_888 (8 << 0) - -#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 -#define SC1_H_QUALIFIER_NONE (1 << 16) -#define SC0_H_QUALIFIER_NONE (1 << 0) - -#define DC_DISP_DATA_ENABLE_OPTIONS 0x432 -#define DE_SELECT_ACTIVE_BLANK (0 << 0) -#define DE_SELECT_ACTIVE (1 << 0) -#define DE_SELECT_ACTIVE_IS (2 << 0) -#define DE_CONTROL_ONECLK (0 << 2) -#define DE_CONTROL_NORMAL (1 << 2) -#define DE_CONTROL_EARLY_EXT (2 << 2) -#define DE_CONTROL_EARLY (3 << 2) -#define DE_CONTROL_ACTIVE_BLANK (4 << 2) - -#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 -#define DC_DISP_SD_BL_PARAMETERS 0x4D7 -#define DC_DISP_SD_BL_CONTROL 0x4DC -#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 - -#define DC_WIN_CSC_YOF 0x611 -#define DC_WIN_CSC_KYRGB 0x612 -#define DC_WIN_CSC_KUR 0x613 -#define DC_WIN_CSC_KVR 0x614 -#define DC_WIN_CSC_KUG 0x615 -#define DC_WIN_CSC_KVG 0x616 -#define DC_WIN_CSC_KUB 0x617 -#define DC_WIN_CSC_KVB 0x618 -#define DC_WIN_AD_WIN_OPTIONS 0xB80 -#define DC_WIN_BD_WIN_OPTIONS 0xD80 -#define DC_WIN_CD_WIN_OPTIONS 0xF80 - -// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). -#define DC_WIN_WIN_OPTIONS 0x700 -#define H_DIRECTION (1 << 0) -#define V_DIRECTION (1 << 2) -#define SCAN_COLUMN (1 << 4) -#define COLOR_EXPAND (1 << 6) -#define CSC_ENABLE (1 << 18) -#define WIN_ENABLE (1 << 30) - -#define DC_WIN_COLOR_DEPTH 0x703 -#define WIN_COLOR_DEPTH_P1 0x0 -#define WIN_COLOR_DEPTH_P2 0x1 -#define WIN_COLOR_DEPTH_P4 0x2 -#define WIN_COLOR_DEPTH_P8 0x3 -#define WIN_COLOR_DEPTH_B4G4R4A4 0x4 -#define WIN_COLOR_DEPTH_B5G5R5A 0x5 -#define WIN_COLOR_DEPTH_B5G6R5 0x6 -#define WIN_COLOR_DEPTH_AB5G5R5 0x7 -#define WIN_COLOR_DEPTH_B8G8R8A8 0xC -#define WIN_COLOR_DEPTH_R8G8B8A8 0xD -#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE -#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF -#define WIN_COLOR_DEPTH_YCbCr422 0x10 -#define WIN_COLOR_DEPTH_YUV422 0x11 -#define WIN_COLOR_DEPTH_YCbCr420P 0x12 -#define WIN_COLOR_DEPTH_YUV420P 0x13 -#define WIN_COLOR_DEPTH_YCbCr422P 0x14 -#define WIN_COLOR_DEPTH_YUV422P 0x15 -#define WIN_COLOR_DEPTH_YCbCr422R 0x16 -#define WIN_COLOR_DEPTH_YUV422R 0x17 -#define WIN_COLOR_DEPTH_YCbCr422RA 0x18 -#define WIN_COLOR_DEPTH_YUV422RA 0x19 - -#define DC_WIN_BUFFER_CONTROL 0x702 -#define DC_WIN_POSITION 0x704 - -#define DC_WIN_SIZE 0x705 -#define H_SIZE(x) (((x) & 0x1fff) << 0) -#define V_SIZE(x) (((x) & 0x1fff) << 16) - -#define DC_WIN_PRESCALED_SIZE 0x706 -#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) -#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) - -#define DC_WIN_H_INITIAL_DDA 0x707 -#define DC_WIN_V_INITIAL_DDA 0x708 - -#define DC_WIN_DDA_INC 0x709 -#define H_DDA_INC(x) (((x) & 0xffff) << 0) -#define V_DDA_INC(x) (((x) & 0xffff) << 16) - -#define DC_WIN_LINE_STRIDE 0x70A -#define LINE_STRIDE(x) (x) -#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) -#define DC_WIN_DV_CONTROL 0x70E - -/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ -#define DC_WINBUF_START_ADDR 0x800 -#define DC_WINBUF_ADDR_H_OFFSET 0x806 -#define DC_WINBUF_ADDR_V_OFFSET 0x808 -#define DC_WINBUF_SURFACE_KIND 0x80B -#define PITCH (0 << 0) -#define TILED (1 << 0) -#define BLOCK (2 << 0) -#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) - -/*! Display serial interface registers. */ -#define _DSIREG(reg) ((reg) * 4) - -#define DSI_RD_DATA 0x9 -#define DSI_WR_DATA 0xA - -#define DSI_POWER_CONTROL 0xB -#define DSI_POWER_CONTROL_ENABLE 1 - -#define DSI_INT_ENABLE 0xC -#define DSI_INT_STATUS 0xD -#define DSI_INT_MASK 0xE - -#define DSI_HOST_CONTROL 0xF -#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) -#define DSI_HOST_CONTROL_CRC_RESET (1 << 20) -#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) -#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) -#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) -#define DSI_HOST_CONTROL_RAW (1 << 6) -#define DSI_HOST_CONTROL_HS (1 << 5) -#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) -#define DSI_HOST_CONTROL_IMM_BTA (1 << 3) -#define DSI_HOST_CONTROL_PKT_BTA (1 << 2) -#define DSI_HOST_CONTROL_CS (1 << 1) -#define DSI_HOST_CONTROL_ECC (1 << 0) - -#define DSI_CONTROL 0x10 -#define DSI_CONTROL_HS_CLK_CTRL (1 << 20) -#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) -#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) -#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) -#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) -#define DSI_CONTROL_DCS_ENABLE (1 << 3) -#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) -#define DSI_CONTROL_VIDEO_ENABLE (1 << 1) -#define DSI_CONTROL_HOST_ENABLE (1 << 0) - -#define DSI_SOL_DELAY 0x11 -#define DSI_MAX_THRESHOLD 0x12 - -#define DSI_TRIGGER 0x13 -#define DSI_TRIGGER_HOST (1 << 1) -#define DSI_TRIGGER_VIDEO (1 << 0) - -#define DSI_TX_CRC 0x14 -#define DSI_STATUS 0x15 -#define DSI_INIT_SEQ_CONTROL 0x1A -#define DSI_INIT_SEQ_DATA_0 0x1B -#define DSI_INIT_SEQ_DATA_1 0x1C -#define DSI_INIT_SEQ_DATA_2 0x1D -#define DSI_INIT_SEQ_DATA_3 0x1E -#define DSI_PKT_SEQ_0_LO 0x23 -#define DSI_PKT_SEQ_0_HI 0x24 -#define DSI_PKT_SEQ_1_LO 0x25 -#define DSI_PKT_SEQ_1_HI 0x26 -#define DSI_PKT_SEQ_2_LO 0x27 -#define DSI_PKT_SEQ_2_HI 0x28 -#define DSI_PKT_SEQ_3_LO 0x29 -#define DSI_PKT_SEQ_3_HI 0x2A -#define DSI_PKT_SEQ_4_LO 0x2B -#define DSI_PKT_SEQ_4_HI 0x2C -#define DSI_PKT_SEQ_5_LO 0x2D -#define DSI_PKT_SEQ_5_HI 0x2E -#define DSI_DCS_CMDS 0x33 -#define DSI_PKT_LEN_0_1 0x34 -#define DSI_PKT_LEN_2_3 0x35 -#define DSI_PKT_LEN_4_5 0x36 -#define DSI_PKT_LEN_6_7 0x37 -#define DSI_PHY_TIMING_0 0x3C -#define DSI_PHY_TIMING_1 0x3D -#define DSI_PHY_TIMING_2 0x3E -#define DSI_BTA_TIMING 0x3F - -#define DSI_TIMEOUT_0 0x44 -#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) -#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) - -#define DSI_TIMEOUT_1 0x45 -#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) -#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) - -#define DSI_TO_TALLY 0x46 - -#define DSI_PAD_CONTROL_0 0x4B -#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) -#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) -#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) -#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) - -#define DSI_PAD_CONTROL_CD 0x4C -#define DSI_VIDEO_MODE_CONTROL 0x4E - -#define DSI_PAD_CONTROL_1 0x4F -#define DSI_PAD_CONTROL_2 0x50 - -#define DSI_PAD_CONTROL_3 0x51 -#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) -#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) -#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) -#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) - -#define DSI_PAD_CONTROL_4 0x52 -#define DSI_INIT_SEQ_DATA_15 0x5F - -#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60 - -void display_init(); -void display_backlight_pwm_init(); -void display_end(); - -/*! Show one single color on the display. */ -void display_color_screen(u32 color); - -/*! Switches screen backlight ON/OFF. */ -void display_backlight(bool enable); -void display_backlight_brightness(u32 brightness, u32 step_delay); - -/*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */ -u32 *display_init_framebuffer(); -u32 *display_init_framebuffer2(); - -#endif diff --git a/nyx/nyx_gui/gfx/di.inl b/nyx/nyx_gui/gfx/di.inl deleted file mode 100644 index 7ec0115..0000000 --- a/nyx/nyx_gui/gfx/di.inl +++ /dev/null @@ -1,599 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer -* -* 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 . -*/ - -//Clock config. -static const cfg_op_t _display_config_1[4] = { - {0x4E, 0x40000000}, //CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 - {0x34, 0x4830A001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2D0AAA} //CLK_RST_CONTROLLER_PLLD_MISC -}; - -//Display A config. -static const cfg_op_t _display_config_2[94] = { - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_REG_ACT_CONTROL, 0x54}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_DISP_DC_MCCIF_FIFOCTRL, 0}, - {DC_DISP_DISP_MEM_HIGH_PRIORITY, 0}, - {DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0}, - {DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE}, - {DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL}, - {DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, - {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, - {DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, - {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, - {0x4E4, 0}, - {DC_COM_CRC_CONTROL, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} -}; - -//DSI Init config. -static const cfg_op_t _display_config_3[61] = { - {DSI_WR_DATA, 0}, - {DSI_INT_ENABLE, 0}, - {DSI_INT_STATUS, 0}, - {DSI_INT_MASK, 0}, - {DSI_INIT_SEQ_DATA_0, 0}, - {DSI_INIT_SEQ_DATA_1, 0}, - {DSI_INIT_SEQ_DATA_2, 0}, - {DSI_INIT_SEQ_DATA_3, 0}, - {DSI_INIT_SEQ_DATA_15, 0}, - {DSI_DCS_CMDS, 0}, - {DSI_PKT_SEQ_0_LO, 0}, - {DSI_PKT_SEQ_1_LO, 0}, - {DSI_PKT_SEQ_2_LO, 0}, - {DSI_PKT_SEQ_3_LO, 0}, - {DSI_PKT_SEQ_4_LO, 0}, - {DSI_PKT_SEQ_5_LO, 0}, - {DSI_PKT_SEQ_0_HI, 0}, - {DSI_PKT_SEQ_1_HI, 0}, - {DSI_PKT_SEQ_2_HI, 0}, - {DSI_PKT_SEQ_3_HI, 0}, - {DSI_PKT_SEQ_4_HI, 0}, - {DSI_PKT_SEQ_5_HI, 0}, - {DSI_CONTROL, 0}, - {DSI_PAD_CONTROL_CD, 0}, - {DSI_SOL_DELAY, 0x18}, - {DSI_MAX_THRESHOLD, 0x1E0}, - {DSI_TRIGGER, 0}, - {DSI_INIT_SEQ_CONTROL, 0}, - {DSI_PKT_LEN_0_1, 0}, - {DSI_PKT_LEN_2_3, 0}, - {DSI_PKT_LEN_4_5, 0}, - {DSI_PKT_LEN_6_7, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30109}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_POWER_CONTROL, 0}, - {DSI_POWER_CONTROL, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30118}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_MAX_THRESHOLD, 0x40}, - {DSI_TRIGGER, 0}, - {DSI_TX_CRC, 0}, - {DSI_INIT_SEQ_CONTROL, 0} -}; - -//DSI config (if ver == 0x10). -static const cfg_op_t _display_config_4[43] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1939}, - {DSI_WR_DATA, 0xAAAAAAD8}, - {DSI_WR_DATA, 0xAAAAAAEB}, - {DSI_WR_DATA, 0xAAEBAAAA}, - {DSI_WR_DATA, 0xAAAAAAAA}, - {DSI_WR_DATA, 0xAAAAAAEB}, - {DSI_WR_DATA, 0xAAEBAAAA}, - {DSI_WR_DATA, 0xAA}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1BD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2739}, - {DSI_WR_DATA, 0xFFFFFFD8}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFF}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2BD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xF39}, - {DSI_WR_DATA, 0xFFFFFFD8}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFFFF}, - {DSI_WR_DATA, 0xFFFFFF}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x6D915}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST} -}; - -//DSI config. -static const cfg_op_t _display_config_5[21] = { - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30172}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)}, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_PKT_SEQ_0_LO, 0x40000208}, - {DSI_PKT_SEQ_2_LO, 0x40000308}, - {DSI_PKT_SEQ_4_LO, 0x40000308}, - {DSI_PKT_SEQ_1_LO, 0x40000308}, - {DSI_PKT_SEQ_3_LO, 0x3F3B2B08}, - {DSI_PKT_SEQ_3_HI, 0x2CC}, - {DSI_PKT_SEQ_5_LO, 0x3F3B2B08}, - {DSI_PKT_SEQ_5_HI, 0x2CC}, - {DSI_PKT_LEN_0_1, 0xCE0000}, - {DSI_PKT_LEN_2_3, 0x87001A2}, - {DSI_PKT_LEN_4_5, 0x190}, - {DSI_PKT_LEN_6_7, 0x190}, - {DSI_HOST_CONTROL, 0}, -}; - -//Clock config. -static const cfg_op_t _display_config_6[3] = { - {0x34, 0x4810C001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2DFC00} //CLK_RST_CONTROLLER_PLLD_MISC -}; - -//DSI config. -static const cfg_op_t _display_config_7[10] = { - {DSI_TRIGGER, 0}, - {DSI_CONTROL, 0}, - {DSI_SOL_DELAY, 6}, - {DSI_MAX_THRESHOLD, 0x1E0}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL| DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC} -}; - -//MIPI CAL config. -static const cfg_op_t _display_config_8[6] = { - {0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS - {0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0 - {0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2 - {0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1 -}; - -//DSI config. -static const cfg_op_t _display_config_9[4] = { - {DSI_PAD_CONTROL_1, 0}, - {DSI_PAD_CONTROL_2, 0}, - {DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, - {DSI_PAD_CONTROL_4, 0} -}; - -//MIPI CAL config. -static const cfg_op_t _display_config_10[16] = { - {0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG - {0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG - {0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 - {0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 - {0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG - {0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG - {0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG - {0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG - {0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG - {0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG - {0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG - {0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG - {0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 - {0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 - {0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 - {0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG -}; - -//Display A config. -static const cfg_op_t _display_config_11[113] = { - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_DV_CONTROL, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - /* Setup default YUV colorspace conversion coefficients */ - {DC_WIN_CSC_YOF, 0xF0}, - {DC_WIN_CSC_KYRGB, 0x12A}, - {DC_WIN_CSC_KUR, 0}, - {DC_WIN_CSC_KVR, 0x198}, - {DC_WIN_CSC_KUG, 0x39B}, - {DC_WIN_CSC_KVG, 0x32F}, - {DC_WIN_CSC_KUB, 0x204}, - {DC_WIN_CSC_KVB, 0}, - /* End of color coefficients */ - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, - {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, - {DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, - {DC_COM_PIN_OUTPUT_POLARITY(3), 0}, - {0x4E4, 0}, - {DC_COM_CRC_CONTROL, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {0x716, 0x10000FF}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, - {DC_CMD_STATE_ACCESS, 0}, - /* Set Display timings */ - {DC_DISP_DISP_TIMING_OPTIONS, 0}, - {DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1. - {DC_DISP_SYNC_WIDTH, 0x10048}, - {DC_DISP_BACK_PORCH, 0x90048}, - {DC_DISP_ACTIVE, 0x50002D0}, - {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. - /* End of Display timings */ - {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, - {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, - {DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, - {DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, - {DC_DISP_DISP_CLOCK_CONTROL, 0}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX}, - {DC_DISP_FRONT_PORCH, 0xA0088}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, - {DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, - {DC_CMD_DISPLAY_COMMAND_OPTION0, 0} -}; - -////Display A config. -static const cfg_op_t _display_config_12[17] = { - {DC_DISP_FRONT_PORCH, 0xA0088}, - {DC_CMD_INT_MASK, 0}, - {DC_CMD_STATE_ACCESS, 0}, - {DC_CMD_INT_ENABLE, 0}, - {DC_CMD_CONT_SYNCPT_VSYNC, 0}, - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, - {DC_CMD_DISPLAY_POWER_CONTROL, 0}, - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, -}; - -//DSI config. -static const cfg_op_t _display_config_13[16] = { - {DSI_POWER_CONTROL, 0}, - {DSI_PAD_CONTROL_1, 0}, - {DSI_PHY_TIMING_0, 0x6070601}, - {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30118}, - {DSI_BTA_TIMING, 0x190A14}, - {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) }, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, - {DSI_TO_TALLY, 0}, - {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, - {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, - {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, - {DSI_MAX_THRESHOLD, 0x40}, - {DSI_TRIGGER, 0}, - {DSI_TX_CRC, 0}, - {DSI_INIT_SEQ_CONTROL, 0} -}; - -//DSI config (if ver == 0x10). -static const cfg_op_t _display_config_14[22] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2139}, - {DSI_WR_DATA, 0x191919D5}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19191919}, - {DSI_WR_DATA, 0x19}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xB39}, - {DSI_WR_DATA, 0x4F0F41B1}, - {DSI_WR_DATA, 0xF179A433}, - {DSI_WR_DATA, 0x2D81}, - {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, - {DSI_TRIGGER, DSI_TRIGGER_HOST} -}; - -//Display A config. -static const cfg_op_t cfg_display_one_color[8] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} //DISPLAY_CTRL_MODE: continuous display. -}; - -//Display A config. -static const cfg_op_t cfg_display_framebuffer[32] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 - {DC_WIN_WIN_OPTIONS, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_WIN_POSITION, 0}, //(0,0) - {DC_WIN_H_INITIAL_DDA, 0}, - {DC_WIN_V_INITIAL_DDA, 0}, - {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. - {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, - {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. - {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. - {DC_WIN_BUFFER_CONTROL, 0}, - {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. - {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. - {DC_WINBUF_ADDR_H_OFFSET, 0}, //Linear: 0x383FFC, Block: 0x3813FC - {DC_WINBUF_ADDR_V_OFFSET, 1279}, //Linear: 1279, Block: 0 - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD. - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. -}; - -static const cfg_op_t cfg_display_framebuffer2[32] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 - {DC_WIN_WIN_OPTIONS, 0}, - {DC_WIN_WIN_OPTIONS, 0}, - {DC_WIN_POSITION, 0}, //(0,0) - {DC_WIN_H_INITIAL_DDA, 0}, - {DC_WIN_V_INITIAL_DDA, 0}, - {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. - {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, - {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. - {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(1280 * 2) | LINE_STRIDE(1280 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. - {DC_WIN_BUFFER_CONTROL, 0}, - {DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK}, //Regular surface. - {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. - {DC_WINBUF_ADDR_H_OFFSET, 0x3813FC}, //Linear: 0x383FFC, Block: 0x3813FC - {DC_WINBUF_ADDR_V_OFFSET, 0}, //Linear: 1279, Block: 0 - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, //Enable window AD. | SCAN_COLUMN | H_DIRECTION - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. -}; diff --git a/nyx/nyx_gui/gfx/gfx.c b/nyx/nyx_gui/gfx/gfx.c index 4a74d43..548986e 100644 --- a/nyx/nyx_gui/gfx/gfx.c +++ b/nyx/nyx_gui/gfx/gfx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +19,14 @@ #include #include "gfx.h" +#define COLUMN2_X 640 + +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + +static bool gfx_con_init_done = false; + static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) @@ -117,14 +125,6 @@ static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) }; -void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) -{ - gfx_ctxt.fb = fb; - gfx_ctxt.width = width; - gfx_ctxt.height = height; - gfx_ctxt.stride = stride; -} - void gfx_clear_grey(u8 color) { memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); @@ -136,9 +136,14 @@ void gfx_clear_color(u32 color) gfx_ctxt.fb[i] = color; } -void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) { - memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; + + gfx_clear_grey(0); } void gfx_con_init() @@ -147,12 +152,15 @@ void gfx_con_init() gfx_con.fntsz = 16; gfx_con.x = 0; gfx_con.y = 0; + gfx_con.col = 0; gfx_con.savedx = 0; gfx_con.savedy = 0; - gfx_con.fgcol = 0xFFCCCCCC; + gfx_con.fgcol = TXT_CLR_DEFAULT; gfx_con.fillbg = 1; - gfx_con.bgcol = 0xFF1B1B1B; + gfx_con.bgcol = TXT_CLR_BG; gfx_con.mute = 0; + + gfx_con_init_done = true; } void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) @@ -162,16 +170,32 @@ void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) gfx_con.bgcol = bgcol; } -void gfx_con_getpos(u32 *x, u32 *y) +void gfx_con_getpos(u32 *x, u32 *y, u32 *c) { *x = gfx_con.x; *y = gfx_con.y; + *c = gfx_con.col; } -void gfx_con_setpos(u32 x, u32 y) +void gfx_con_setpos(u32 x, u32 y, u32 c) { gfx_con.x = x; gfx_con.y = y; + + switch (c) + { + case GFX_COL_KEEP: + break; + case GFX_COL_AUTO: + if (x < COLUMN2_X) + gfx_con.col = 0; + else + gfx_con.col = COLUMN2_X; + break; + default: + gfx_con.col = c; + break; + } } void gfx_putc(char c) @@ -183,45 +207,58 @@ void gfx_putc(char c) if (c >= 32 && c <= 126) { u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; - u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; - for (u32 i = 0; i < 16; i += 2) { u8 v = *cbuf; for (u32 k = 0; k < 2; k++) { - for (u32 j = 0; j < 8; j++) + u32 fb_off = gfx_con.y + i + k + (gfx_ctxt.width - gfx_con.x) * gfx_ctxt.stride; + for (u32 j = 0; j < 16; j += 2) { - if (v & 1) + for (u32 l = 0; l < 2; l++) { - *fb = gfx_con.fgcol; - fb++; - *fb = gfx_con.fgcol; + if (v & 1) + gfx_ctxt.fb[fb_off - (j + l) * gfx_ctxt.stride] = gfx_con.fgcol; + else if (gfx_con.fillbg) + gfx_ctxt.fb[fb_off - (j + l) * gfx_ctxt.stride] = gfx_con.bgcol; } - else if (gfx_con.fillbg) - { - *fb = gfx_con.bgcol; - fb++; - *fb = gfx_con.bgcol; - } - else - fb++; v >>= 1; - fb++; } - fb += gfx_ctxt.stride - 16; v = *cbuf; } cbuf++; } gfx_con.x += 16; + if (gfx_con.x > gfx_ctxt.width - 16) + { + gfx_con.x = gfx_con.col; + gfx_con.y += 16; + if (gfx_con.y > gfx_ctxt.height - 33) + { + gfx_con.y = 0; + + if (!gfx_con.col) + gfx_con.col = COLUMN2_X; + else + gfx_con.col = 0; + gfx_con.x = gfx_con.col; + } + } } else if (c == '\n') { - gfx_con.x = 0; - gfx_con.y +=16; - if (gfx_con.y > gfx_ctxt.height - 16) + gfx_con.x = gfx_con.col; + gfx_con.y += 16; + if (gfx_con.y > gfx_ctxt.height - 33) + { gfx_con.y = 0; + + if (!gfx_con.col) + gfx_con.col = COLUMN2_X; + else + gfx_con.col = 0; + gfx_con.x = gfx_con.col; + } } break; case 8: @@ -229,29 +266,50 @@ void gfx_putc(char c) if (c >= 32 && c <= 126) { u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; - u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; for (u32 i = 0; i < 8; i++) { u8 v = *cbuf++; + u32 fb_off = gfx_con.y + i + (gfx_ctxt.width - gfx_con.x) * gfx_ctxt.stride; for (u32 j = 0; j < 8; j++) { if (v & 1) - *fb = gfx_con.fgcol; + gfx_ctxt.fb[fb_off - (j * gfx_ctxt.stride)] = gfx_con.fgcol; else if (gfx_con.fillbg) - *fb = gfx_con.bgcol; + gfx_ctxt.fb[fb_off - (j * gfx_ctxt.stride)] = gfx_con.bgcol; v >>= 1; - fb++; } - fb += gfx_ctxt.stride - 8; } gfx_con.x += 8; + if (gfx_con.x > gfx_ctxt.width / 2 + gfx_con.col - 8) + { + gfx_con.x = gfx_con.col; + gfx_con.y += 8; + if (gfx_con.y > gfx_ctxt.height - 33) + { + gfx_con.y = 0; + + if (!gfx_con.col) + gfx_con.col = COLUMN2_X; + else + gfx_con.col = 0; + gfx_con.x = gfx_con.col; + } + } } else if (c == '\n') { - gfx_con.x = 0; + gfx_con.x = gfx_con.col; gfx_con.y += 8; - if (gfx_con.y > gfx_ctxt.height - 8) + if (gfx_con.y > gfx_ctxt.height - 33) + { gfx_con.y = 0; + + if (!gfx_con.col) + gfx_con.col = COLUMN2_X; + else + gfx_con.col = 0; + gfx_con.x = gfx_con.col; + } } break; } @@ -259,7 +317,7 @@ void gfx_putc(char c) void gfx_puts(const char *s) { - if (!s || gfx_con.mute) + if (!s || !gfx_con_init_done || gfx_con.mute) return; for (; *s; s++) @@ -268,14 +326,24 @@ void gfx_puts(const char *s) static void _gfx_putn(u32 v, int base, char fill, int fcnt) { - char buf[65]; - static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; - char *p; - int c = fcnt; + static const char digits[] = "0123456789ABCDEF"; - if (base > 36) + char *p; + char buf[65]; + int c = fcnt; + bool negative = false; + + if (base != 10 && base != 16) return; + // Account for negative numbers. + if (base == 10 && v & 0x80000000) + { + negative = true; + v = (int)v * -1; + c--; + } + p = buf + 64; *p = 0; do @@ -285,9 +353,12 @@ static void _gfx_putn(u32 v, int base, char fill, int fcnt) v /= base; } while (v); + if (negative) + *--p = '-'; + if (fill != 0) { - while (c > 0) + while (c > 0 && p > buf) { *--p = fill; c--; @@ -297,34 +368,18 @@ static void _gfx_putn(u32 v, int base, char fill, int fcnt) gfx_puts(p); } -void gfx_put_small_sep() -{ - u8 prevFontSize = gfx_con.fntsz; - gfx_con.fntsz = 8; - gfx_putc('\n'); - gfx_con.fntsz = prevFontSize; -} - -void gfx_put_big_sep() -{ - u8 prevFontSize = gfx_con.fntsz; - gfx_con.fntsz = 16; - gfx_putc('\n'); - gfx_con.fntsz = prevFontSize; -} - void gfx_printf(const char *fmt, ...) { - if (gfx_con.mute) + if (!gfx_con_init_done || gfx_con.mute) return; va_list ap; int fill, fcnt; va_start(ap, fmt); - while(*fmt) + while (*fmt) { - if(*fmt == '%') + if (*fmt == '%') { fmt++; fill = 0; @@ -389,24 +444,37 @@ void gfx_printf(const char *fmt, ...) va_end(ap); } -void gfx_hexdump(u32 base, const u8 *buf, u32 len) +static void _gfx_cputs(u32 color, const char *s) { - if (gfx_con.mute) + gfx_con.fgcol = color; + gfx_puts(s); + gfx_putc('\n'); + gfx_con.fgcol = TXT_CLR_DEFAULT; +} + +void gfx_wputs(const char *s) { _gfx_cputs(TXT_CLR_WARNING, s); } +void gfx_eputs(const char *s) { _gfx_cputs(TXT_CLR_ERROR, s); } + +void gfx_hexdump(u32 base, const void *buf, u32 len) +{ + if (!gfx_con_init_done || gfx_con.mute) return; + u8 *buff = (u8 *)buf; + u8 prevFontSize = gfx_con.fntsz; gfx_con.fntsz = 8; - for(u32 i = 0; i < len; i++) + for (u32 i = 0; i < len; i++) { - if(i % 0x10 == 0) + if (i % 0x10 == 0) { - if(i != 0) + if (i != 0) { gfx_puts("| "); - for(u32 j = 0; j < 0x10; j++) + for (u32 j = 0; j < 0x10; j++) { - u8 c = buf[i - 0x10 + j]; - if(c >= 32 && c <= 126) + u8 c = buff[i - 0x10 + j]; + if (c >= 32 && c <= 126) gfx_putc(c); else gfx_putc('.'); @@ -415,7 +483,7 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) } gfx_printf("%08x: ", base + i); } - gfx_printf("%02x ", buf[i]); + gfx_printf("%02x ", buff[i]); if (i == len - 1) { int ln = len % 0x10 != 0; @@ -427,10 +495,10 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_puts(" "); } gfx_puts("| "); - for(u32 j = 0; j < (ln ? k : k + 1); j++) + for (u32 j = 0; j < (ln ? k : k + 1); j++) { - u8 c = buf[i - k + j]; - if(c >= 32 && c <= 126) + u8 c = buff[i - k + j]; + if (c >= 32 && c <= 126) gfx_putc(c); else gfx_putc('.'); @@ -442,108 +510,24 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len) gfx_con.fntsz = prevFontSize; } -static int abs(int x) -{ - if (x < 0) - return -x; - return x; -} - void gfx_set_pixel(u32 x, u32 y, u32 color) { - gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; + gfx_ctxt.fb[y + (gfx_ctxt.width - x) * gfx_ctxt.stride] = color; } -void gfx_line(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(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; - } - } -} - -void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) -{ - u32 pos = 0; - for (u32 y = pos_y; y < (pos_y + size_y); y++) - { - for (u32 x = pos_x; x < (pos_x + size_x); x++) - { - memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4); - pos++; - } - } -} - - -void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) -{ - u32 pos = 0; - for (u32 y = pos_y; y < (pos_y + size_y); y++) - { - for (u32 x = pos_x; x < (pos_x + size_x); x++) - { - gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); - pos+=3; - } - } -} - -void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +void gfx_set_rect_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) { u32 *ptr = (u32 *)buf; - for (u32 y = pos_y; y < (pos_y + size_y); y++) - for (u32 x = pos_x; x < (pos_x + size_x); x++) - gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++; -} - -void gfx_set_rect_argb_land(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) -{ - u32 pos = 0; - for (u32 y = pos_y; y < (pos_y + size_y); y++) + u32 line_size = pos_x2 - pos_x + 1; + //ptr = gfx_debug_rect(buf, pos_x, pos_y, pos_x2, pos_y2); + for (u32 y = pos_y; y <= pos_y2; y++) { - for (u32 x = pos_x; x < (pos_x + size_x); x++) - { - gfx_ctxt.fb[y + (gfx_ctxt.width - x) * gfx_ctxt.stride] = buf[pos]; - pos+=1; - } + memcpy(&fb[pos_x + y * stride], ptr, line_size * sizeof(u32)); + ptr += line_size; } } -void gfx_fill_rect_argb(const u32 color, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) -{ - for (u32 y = pos_y; y < (pos_y + size_y); y++) - for (u32 x = pos_x; x < (pos_x + size_x); x++) - gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; -} - -void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) -{ - for (u32 y = pos_y; y < (pos_y + size_y); y++) - { - for (u32 x = pos_x; x < (pos_x + size_x); x++) - gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x]; - } -} - -__attribute__((target("arm"))) void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) +void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) { u32 *ptr = (u32 *)buf; @@ -551,30 +535,30 @@ __attribute__((target("arm"))) void gfx_set_rect_land_pitch(u32 *fb, const u32 * if (!(pixels_w % 8)) { - for (u32 y = pos_y; y < (pos_y2 + 1); y++) - for (u32 x = pos_x; x < (pos_x2 + 1); x+=8) + for (u32 y = pos_y; y <= pos_y2; y++) + for (u32 x = pos_x; x <= pos_x2; x += 8) { - u32 *fbx = &fb[x * gfx_ctxt.stride + y]; + u32 *fbx = &fb[x * stride + y]; - fbx[0] = *ptr++; - fbx[gfx_ctxt.stride] = *ptr++; - fbx[gfx_ctxt.stride * 2] = *ptr++; - fbx[gfx_ctxt.stride * 3] = *ptr++; - fbx[gfx_ctxt.stride * 4] = *ptr++; - fbx[gfx_ctxt.stride * 5] = *ptr++; - fbx[gfx_ctxt.stride * 6] = *ptr++; - fbx[gfx_ctxt.stride * 7] = *ptr++; + fbx[0] = *ptr++; + fbx[stride] = *ptr++; + fbx[stride * 2] = *ptr++; + fbx[stride * 3] = *ptr++; + fbx[stride * 4] = *ptr++; + fbx[stride * 5] = *ptr++; + fbx[stride * 6] = *ptr++; + fbx[stride * 7] = *ptr++; } } else { for (u32 y = pos_y; y < (pos_y2 + 1); y++) for (u32 x = pos_x; x < (pos_x2 + 1); x++) - fb[x * gfx_ctxt.stride + y] = *ptr++; + fb[x * stride + y] = *ptr++; } } -__attribute__((target("arm"))) void gfx_set_rect_land_block(const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) +void gfx_set_rect_land_block(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) { u32 *ptr = (u32 *)buf; u32 GOB_address = 0; @@ -583,9 +567,9 @@ __attribute__((target("arm"))) void gfx_set_rect_land_block(const u32 *buf, u32 // Optimized u32 image_width_in_gobs = 655360; //1280 - for (u32 y = pos_y; y < (pos_y2 + 1); y++) + for (u32 y = pos_y; y <= pos_y2; y++) { - for (u32 x = pos_x; x < (pos_x2 + 1); x++) + for (u32 x = pos_x; x <= pos_x2; x++) { GOB_address = (y >> 7) * image_width_in_gobs + ((x >> 4) << 13) + (((y % 128) >> 3) << 9); @@ -596,7 +580,7 @@ __attribute__((target("arm"))) void gfx_set_rect_land_block(const u32 *buf, u32 + (((x2 % 32) >> 4) << 5) + ((y % 2) << 4) + (x2 % 16); - *(u32 *)(gfx_ctxt.fb + (addr >> 2)) = *ptr++; + *(u32 *)(fb + (addr >> 2)) = *ptr++; } } diff --git a/nyx/nyx_gui/gfx/gfx.h b/nyx/nyx_gui/gfx/gfx.h index 0d09576..e8686e0 100644 --- a/nyx/nyx_gui/gfx/gfx.h +++ b/nyx/nyx_gui/gfx/gfx.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it @@ -19,43 +19,77 @@ #ifndef _GFX_H_ #define _GFX_H_ -#include "../../../common/common_gfx.h" +#include -#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) -#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) -#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) -#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) +#define GFX_COL_KEEP 0xFFFE +#define GFX_COL_AUTO 0xFFFF + +#define TXT_CLR_BG 0xFF000000 // Black. +#define TXT_CLR_DEFAULT 0xFFFFFFFF // White. +#define TXT_CLR_WARNING 0xFFFFDD00 // Yellow. +#define TXT_CLR_ERROR 0xFFFF0000 // Red. +#define TXT_CLR_CYAN_L 0xFF00CCFF // Light Cyan. 0xFF0099EE 0xFF00DDFF FF0AB9E6 +#define TXT_CLR_TURQUOISE 0xFF00FFCC // Turquoise. +#define TXT_CLR_ORANGE 0xFFFFBA00 // Orange. +#define TXT_CLR_GREENISH 0xFF96FF00 // Toxic Green. 0xFFAEFD14 0xFFC7EA46 +#define TXT_CLR_GREEN_D 0xFF008800 // Dark Green. +#define TXT_CLR_RED_D 0xFF880000 // Dark Red. 0xFF800000 +#define TXT_CLR_GREY_D 0xFF303030 // Darkest Grey. +#define TXT_CLR_GREY_DM 0xFF444444 // Darker Grey. +#define TXT_CLR_GREY_M 0xFF555555 // Dark Grey. +#define TXT_CLR_GREY 0xFF888888 // Grey. + +#define EPRINTF(text) gfx_eputs(text) +#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", TXT_CLR_ERROR, args, TXT_CLR_DEFAULT) +#define WPRINTF(text) gfx_wputs(text) +#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", TXT_CLR_WARNING, args, TXT_CLR_DEFAULT) + +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 fntsz; + u32 x; + u32 y; + u32 col; + u32 savedx; + u32 savedy; + u32 savedcol; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); void gfx_clear_grey(u8 color); -void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height); void gfx_clear_color(u32 color); void gfx_con_init(); void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol); -void gfx_con_getpos(u32 *x, u32 *y); -void gfx_con_setpos(u32 x, u32 y); +void gfx_con_getpos(u32 *x, u32 *y, u32 *c); +void gfx_con_setpos(u32 x, u32 y, u32 c); void gfx_putc(char c); void gfx_puts(const char *s); -void gfx_printf(const char *fmt, ...); -void gfx_hexdump(u32 base, const u8 *buf, u32 len); +void gfx_wputs(const char *s); +void gfx_eputs(const char *s); +void gfx_printf(const char *fmt, ...) /* __attribute__((format(printf, 1, 2))) */; +void gfx_hexdump(u32 base, const void *buf, u32 len); void gfx_set_pixel(u32 x, u32 y, u32 color); -void gfx_line(int x0, int y0, int x1, int y1, u32 color); -void gfx_put_small_sep(); -void gfx_put_big_sep(); -void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_set_rect_argb_land(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_fill_rect_argb(const u32 color, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); -void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); - -void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); -void gfx_set_rect_land_block(const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); - -// Global gfx console and context. -gfx_ctxt_t gfx_ctxt; -gfx_con_t gfx_con; +void gfx_set_rect_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); +void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); +void gfx_set_rect_land_block(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); #endif diff --git a/nyx/nyx_gui/gfx/logos-gui.h b/nyx/nyx_gui/gfx/logos-gui.h index d75f04e..de65974 100644 --- a/nyx/nyx_gui/gfx/logos-gui.h +++ b/nyx/nyx_gui/gfx/logos-gui.h @@ -1,17 +1,407 @@ +/* + * Copyright (c) 2018-2024 CTCaer + * + * 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 _LOGOS_GUI_H_ #define _LOGOS_GUI_H_ -#include "../../../common/memory_map.h" +#include -#include "../libs/lv_conf.h" -#include "../libs/lvgl/lv_draw/lv_draw_img.h" -#include "../utils/types.h" +#include +#include #define HEKATE_LOGO +const u8 touch_cursor_map[] = { + 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, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, + 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, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x04, 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, 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, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 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, + 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, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x38, + 0x07, 0x07, 0x07, 0x44, 0x0d, 0x0d, 0x0d, 0x4c, 0x16, 0x16, 0x16, 0x53, + 0x1e, 0x1e, 0x1e, 0x54, 0x21, 0x21, 0x21, 0x57, 0x21, 0x21, 0x21, 0x57, + 0x18, 0x18, 0x18, 0x54, 0x10, 0x10, 0x10, 0x50, 0x07, 0x07, 0x07, 0x4c, + 0x04, 0x04, 0x04, 0x44, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x38, 0x0a, 0x0a, 0x0a, 0x4b, 0x1d, 0x1d, 0x1d, 0x58, + 0x38, 0x38, 0x38, 0x64, 0x59, 0x59, 0x59, 0x6c, 0x73, 0x73, 0x73, 0x70, + 0x84, 0x84, 0x84, 0x74, 0x8b, 0x8b, 0x8b, 0x74, 0x86, 0x86, 0x86, 0x74, + 0x76, 0x76, 0x76, 0x73, 0x5c, 0x5c, 0x5c, 0x6f, 0x3a, 0x3a, 0x3a, 0x6b, + 0x1d, 0x1d, 0x1d, 0x60, 0x09, 0x09, 0x09, 0x53, 0x04, 0x04, 0x04, 0x44, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x13, + 0x00, 0x00, 0x00, 0x08, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x30, 0x04, 0x04, 0x04, 0x44, + 0x15, 0x15, 0x15, 0x54, 0x41, 0x41, 0x41, 0x67, 0x7b, 0x7b, 0x7b, 0x74, + 0xb2, 0xb2, 0xb2, 0x7b, 0xe1, 0xe1, 0xe1, 0x7f, 0xf7, 0xf7, 0xf7, 0x7f, + 0xfd, 0xfd, 0xfd, 0x80, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, + 0xf9, 0xf9, 0xf9, 0x7f, 0xe5, 0xe5, 0xe5, 0x7f, 0xb9, 0xb9, 0xb9, 0x7c, + 0x80, 0x80, 0x80, 0x78, 0x46, 0x46, 0x46, 0x6f, 0x1b, 0x1b, 0x1b, 0x5f, + 0x03, 0x03, 0x03, 0x48, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 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, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x30, 0x04, 0x04, 0x04, 0x47, 0x21, 0x21, 0x21, 0x5f, + 0x63, 0x63, 0x63, 0x70, 0xb9, 0xb9, 0xb9, 0x7b, 0xf5, 0xf5, 0xf5, 0x7f, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xf9, 0xf9, 0xf9, 0x80, 0xc2, 0xc2, 0xc2, 0x7c, 0x6d, 0x6d, 0x6d, 0x74, + 0x27, 0x27, 0x27, 0x63, 0x07, 0x07, 0x07, 0x4b, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2b, + 0x04, 0x04, 0x04, 0x43, 0x23, 0x23, 0x23, 0x5f, 0x7a, 0x7a, 0x7a, 0x74, + 0xdb, 0xdb, 0xdb, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xe3, 0xe3, 0xe3, 0x7f, + 0x87, 0x87, 0x87, 0x77, 0x2e, 0x2e, 0x2e, 0x63, 0x07, 0x07, 0x07, 0x4b, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, + 0x1d, 0x1d, 0x1d, 0x57, 0x79, 0x79, 0x79, 0x73, 0xe5, 0xe5, 0xe5, 0x7f, + 0xfd, 0xfd, 0xfd, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xef, 0xef, 0xef, 0x7f, 0x86, 0x86, 0x86, 0x77, 0x26, 0x26, 0x26, 0x5f, + 0x04, 0x04, 0x04, 0x44, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x0e, 0x0e, 0x0e, 0x4b, + 0x5d, 0x5d, 0x5d, 0x6b, 0xda, 0xda, 0xda, 0x7c, 0xfd, 0xfd, 0xfd, 0x7f, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xe5, 0xe5, 0xe5, 0x7f, 0x69, 0x69, 0x69, 0x70, + 0x15, 0x15, 0x15, 0x57, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3b, 0x30, 0x30, 0x30, 0x5b, + 0xb5, 0xb5, 0xb5, 0x78, 0xf9, 0xf9, 0xf9, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xc1, 0xc1, 0xc1, 0x7c, + 0x3c, 0x3c, 0x3c, 0x67, 0x07, 0x07, 0x07, 0x48, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x2c, 0x0a, 0x0a, 0x0a, 0x48, 0x6a, 0x6a, 0x6a, 0x6c, + 0xef, 0xef, 0xef, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xf9, 0xf9, 0xf9, 0x80, + 0x77, 0x77, 0x77, 0x74, 0x15, 0x15, 0x15, 0x57, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x38, 0x1d, 0x1d, 0x1d, 0x58, 0xa7, 0xa7, 0xa7, 0x77, + 0xf9, 0xf9, 0xf9, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xb4, 0xb4, 0xb4, 0x7b, 0x2a, 0x2a, 0x2a, 0x60, 0x04, 0x04, 0x04, 0x44, + 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x27, + 0x04, 0x04, 0x04, 0x44, 0x36, 0x36, 0x36, 0x64, 0xd6, 0xd6, 0xd6, 0x7c, + 0xfd, 0xfd, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xe5, 0xe5, 0xe5, 0x7f, 0x46, 0x46, 0x46, 0x6b, 0x07, 0x07, 0x07, 0x4c, + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2c, + 0x03, 0x03, 0x03, 0x4b, 0x4e, 0x4e, 0x4e, 0x6c, 0xeb, 0xeb, 0xeb, 0x7f, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xf9, 0xf9, 0xf9, 0x7f, 0x60, 0x60, 0x60, 0x6f, 0x0a, 0x0a, 0x0a, 0x50, + 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, + 0x06, 0x06, 0x06, 0x4f, 0x5e, 0x5e, 0x5e, 0x6f, 0xf1, 0xf1, 0xf1, 0x80, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0x71, 0x71, 0x71, 0x70, 0x0f, 0x0f, 0x0f, 0x53, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, + 0x06, 0x06, 0x06, 0x4f, 0x63, 0x63, 0x63, 0x6f, 0xf3, 0xf3, 0xf3, 0x7f, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x7f, 0x74, 0x74, 0x74, 0x73, 0x0f, 0x0f, 0x0f, 0x53, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, + 0x03, 0x03, 0x03, 0x4b, 0x5a, 0x5a, 0x5a, 0x6c, 0xf1, 0xf1, 0xf1, 0x7f, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xfd, 0xfd, 0xfd, 0x7f, 0x6b, 0x6b, 0x6b, 0x70, 0x10, 0x10, 0x10, 0x50, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x28, + 0x04, 0x04, 0x04, 0x47, 0x45, 0x45, 0x45, 0x67, 0xe5, 0xe5, 0xe5, 0x7f, + 0xfd, 0xfd, 0xfd, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xf3, 0xf3, 0xf3, 0x7f, 0x57, 0x57, 0x57, 0x6c, 0x0a, 0x0a, 0x0a, 0x4c, + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x3c, 0x2e, 0x2e, 0x2e, 0x5f, 0xc7, 0xc7, 0xc7, 0x7b, + 0xfb, 0xfb, 0xfb, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xd4, 0xd4, 0xd4, 0x7c, 0x3d, 0x3d, 0x3d, 0x64, 0x04, 0x04, 0x04, 0x44, + 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x00, 0x00, 0x33, 0x16, 0x16, 0x16, 0x53, 0x8f, 0x8f, 0x8f, 0x74, + 0xf5, 0xf5, 0xf5, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xfd, 0xfd, 0xfd, 0x80, + 0x9f, 0x9f, 0x9f, 0x77, 0x23, 0x23, 0x23, 0x58, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x28, 0x07, 0x07, 0x07, 0x47, 0x4e, 0x4e, 0x4e, 0x68, + 0xdf, 0xdf, 0xdf, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xeb, 0xeb, 0xeb, 0x7f, + 0x5f, 0x5f, 0x5f, 0x6b, 0x0e, 0x0e, 0x0e, 0x4b, 0x00, 0x00, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x38, 0x1e, 0x1e, 0x1e, 0x57, + 0x93, 0x93, 0x93, 0x74, 0xf1, 0xf1, 0xf1, 0x7f, 0xff, 0xff, 0xff, 0x7f, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xf7, 0xf7, 0xf7, 0x80, 0xa4, 0xa4, 0xa4, 0x77, + 0x2b, 0x2b, 0x2b, 0x58, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2b, 0x04, 0x04, 0x04, 0x44, + 0x3c, 0x3c, 0x3c, 0x63, 0xbc, 0xbc, 0xbc, 0x7b, 0xf5, 0xf5, 0xf5, 0x80, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xfb, 0xfb, 0xfb, 0x7f, 0xc9, 0xc9, 0xc9, 0x7b, 0x4d, 0x4d, 0x4d, 0x64, + 0x0f, 0x0f, 0x0f, 0x47, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x33, + 0x0e, 0x0e, 0x0e, 0x4b, 0x54, 0x54, 0x54, 0x67, 0xc5, 0xc5, 0xc5, 0x7c, + 0xf3, 0xf3, 0xf3, 0x80, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xf7, 0xf7, 0xf7, 0x80, + 0xd2, 0xd2, 0xd2, 0x7c, 0x63, 0x63, 0x63, 0x6b, 0x14, 0x14, 0x14, 0x4c, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x34, 0x11, 0x11, 0x11, 0x4c, 0x54, 0x54, 0x54, 0x67, + 0xb8, 0xb8, 0xb8, 0x7b, 0xe9, 0xe9, 0xe9, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, + 0xfd, 0xfd, 0xfd, 0x80, 0xef, 0xef, 0xef, 0x7f, 0xc3, 0xc3, 0xc3, 0x7b, + 0x61, 0x61, 0x61, 0x68, 0x17, 0x17, 0x17, 0x4f, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, + 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, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x34, 0x0e, 0x0e, 0x0e, 0x4b, + 0x3c, 0x3c, 0x3c, 0x63, 0x90, 0x90, 0x90, 0x74, 0xd2, 0xd2, 0xd2, 0x7c, + 0xe9, 0xe9, 0xe9, 0x7f, 0xf7, 0xf7, 0xf7, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, + 0xfd, 0xfd, 0xfd, 0x80, 0xf7, 0xf7, 0xf7, 0x80, 0xeb, 0xeb, 0xeb, 0x7f, + 0xd9, 0xd9, 0xd9, 0x7f, 0x9b, 0x9b, 0x9b, 0x74, 0x46, 0x46, 0x46, 0x63, + 0x11, 0x11, 0x11, 0x4b, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x23, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x33, + 0x04, 0x04, 0x04, 0x44, 0x1b, 0x1b, 0x1b, 0x54, 0x4a, 0x4a, 0x4a, 0x67, + 0x87, 0x87, 0x87, 0x73, 0xb8, 0xb8, 0xb8, 0x7b, 0xd2, 0xd2, 0xd2, 0x7c, + 0xdd, 0xdd, 0xdd, 0x7f, 0xdf, 0xdf, 0xdf, 0x7f, 0xdd, 0xdd, 0xdd, 0x7f, + 0xd5, 0xd5, 0xd5, 0x7f, 0xbf, 0xbf, 0xbf, 0x7b, 0x90, 0x90, 0x90, 0x73, + 0x53, 0x53, 0x53, 0x68, 0x23, 0x23, 0x23, 0x58, 0x07, 0x07, 0x07, 0x44, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x13, + 0x00, 0x00, 0x00, 0x08, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x38, 0x07, 0x07, 0x07, 0x47, + 0x16, 0x16, 0x16, 0x53, 0x29, 0x29, 0x29, 0x5c, 0x3f, 0x3f, 0x3f, 0x67, + 0x4f, 0x4f, 0x4f, 0x6b, 0x57, 0x57, 0x57, 0x6c, 0x53, 0x53, 0x53, 0x6c, + 0x43, 0x43, 0x43, 0x67, 0x2e, 0x2e, 0x2e, 0x5f, 0x16, 0x16, 0x16, 0x53, + 0x07, 0x07, 0x07, 0x47, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, + 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, 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, 0x07, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x47, + 0x03, 0x03, 0x03, 0x4b, 0x07, 0x07, 0x07, 0x4f, 0x07, 0x07, 0x07, 0x4c, + 0x04, 0x04, 0x04, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x33, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 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, + 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, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x04, 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, 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, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x13, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 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, + 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, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const lv_img_dsc_t touch_cursor = { + .header.always_zero = 0, + .header.w = 33, + .header.h = 33, + .data_size = 1089 * LV_IMG_PX_SIZE_ALPHA_BYTE, + .header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA, + .data = touch_cursor_map, +}; + #ifdef HEKATE_LOGO -lv_img_dsc_t hekate_logo = { +const lv_img_dsc_t hekate_logo = { .header.always_zero = 0, .header.w = 193, .header.h = 76, @@ -20,7 +410,7 @@ lv_img_dsc_t hekate_logo = { .data = (const uint8_t *)(NYX_RES_ADDR + 0x1D900), }; -lv_img_dsc_t ctcaer_logo = { +const lv_img_dsc_t ctcaer_logo = { .header.always_zero = 0, .header.w = 147, .header.h = 76, @@ -31,4 +421,4 @@ lv_img_dsc_t ctcaer_logo = { #endif -#endif \ No newline at end of file +#endif diff --git a/nyx/nyx_gui/hos/hos.c b/nyx/nyx_gui/hos/hos.c index d173625..cef7bbe 100644 --- a/nyx/nyx_gui/hos/hos.c +++ b/nyx/nyx_gui/hos/hos.c @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk * Copyright (c) 2018 Ced2911 - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -20,184 +20,513 @@ #include +#include + #include "hos.h" -#include "sept.h" -#include "../config/config.h" -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../sec/tsec.h" -#include "../soc/bpmp.h" -#include "../soc/cluster.h" -#include "../soc/fuse.h" -#include "../soc/pmc.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/util.h" +#include "../config.h" extern hekate_config h_cfg; -extern void sd_unmount(bool deinit); +u8 *cal0_buf = NULL; +static u8 *bis_keys = NULL; -//#define DPRINTF(...) gfx_printf(__VA_ARGS__) -#define DPRINTF(...) - -#define PKG2_LOAD_ADDR 0xA9800000 - - // Secmon mailbox. -#define SECMON_MB_ADDR 0x40002EF8 -#define SECMON7_MB_ADDR 0x400000F8 -typedef struct _secmon_mailbox_t +typedef struct _tsec_keys_t { - // < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot. - // >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot. - u32 in; - // Non-zero: Secmon ready. - u32 out; -} secmon_mailbox_t; + u8 tsec[SE_KEY_128_SIZE]; + u8 tsec_root[SE_KEY_128_SIZE]; + u8 tmp[SE_KEY_128_SIZE]; +} tsec_keys_t; -static const u8 keyblob_keyseeds[][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 - { 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } //6.0.0 +typedef struct _kb_keys_t +{ + u8 master_kekseed[SE_KEY_128_SIZE]; + u8 random_data[0x70]; + u8 package1_key[SE_KEY_128_SIZE]; +} kb_keys_t; + +typedef struct _kb_t +{ + u8 cmac[SE_KEY_128_SIZE]; + u8 ctr[SE_AES_IV_SIZE]; + kb_keys_t keys; + u8 padding[0x150]; +} kb_t; + +static const u8 keyblob_keyseeds[HOS_KB_VERSION_600 - HOS_KB_VERSION_100 + 1][SE_KEY_128_SIZE] = { + { 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. + { 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } // 6.0.0. }; -static const u8 cmac_keyseed[0x10] = +static const u8 cmac_keyseed[SE_KEY_128_SIZE] = { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 }; -static const u8 master_keyseed_retail[0x10] = +static const u8 master_keyseed_retail[SE_KEY_128_SIZE] = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C }; -static const u8 console_keyseed[0x10] = - { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; +// Unused in this context. +//static const u8 master_keyseed_4xx[SE_KEY_128_SIZE] = +// { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; -const u8 package2_keyseed[] = - { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; - -static const u8 master_keyseed_4xx_5xx_610[0x10] = - { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; - -static const u8 master_keyseed_620[0x10] = +static const u8 master_kekseed_620[SE_KEY_128_SIZE] = { 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A }; -static const u8 console_keyseed_4xx_5xx[0x10] = +//!TODO: Update on mkey changes. +static const u8 master_kekseed_t210_max[SE_KEY_128_SIZE] = + { 0xA1, 0x7D, 0x34, 0xDB, 0x2D, 0x9D, 0xDA, 0xE5, 0xF8, 0x15, 0x63, 0x4C, 0x8F, 0xE7, 0x6C, 0xD8 }; // 20.0.0. + +//!TODO: Update on mkey changes. +static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 + 1][SE_KEY_128_SIZE] = { + { 0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56 }, // 6.0.0. + { 0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE }, // 6.2.0. + { 0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A }, // 7.0.0. + { 0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23 }, // 8.1.0. + { 0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13 }, // 9.0.0. + { 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82 }, // 9.1.0. + { 0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1 }, // 12.1.0. + { 0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6 }, // 13.0.0. + { 0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A }, // 14.0.0. + { 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D }, // 15.0.0. + { 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9 }, // 16.0.0. + { 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80 }, // 17.0.0. + { 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 }, // 18.0.0. + { 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }, // 19.0.0. + { 0x1A, 0x31, 0x62, 0x87, 0xA8, 0x09, 0xCA, 0xF8, 0x69, 0x15, 0x45, 0xC2, 0x6B, 0xAA, 0x5A, 0x8A }, // 20.0.0. +}; + +static const u8 console_keyseed[SE_KEY_128_SIZE] = + { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; + +static const u8 console_keyseed_4xx[SE_KEY_128_SIZE] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) +const u8 package2_keyseed[SE_KEY_128_SIZE] = + { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; + +//!TODO: Update on mkey changes. +static const u8 mkey_vectors[HOS_KB_VERSION_MAX + 1][SE_KEY_128_SIZE] = { + { 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D }, // Zeroes encrypted with mkey 00. + { 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD }, // Mkey 00 encrypted with mkey 01. + { 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 }, // Mkey 01 encrypted with mkey 02. + { 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 }, // Mkey 02 encrypted with mkey 03. + { 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 }, // Mkey 03 encrypted with mkey 04. + { 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE }, // Mkey 04 encrypted with mkey 05. + { 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 }, // Mkey 05 encrypted with mkey 06. + { 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F }, // Mkey 06 encrypted with mkey 07. + { 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }, // Mkey 07 encrypted with mkey 08. + { 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, // Mkey 08 encrypted with mkey 09. + { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }, // Mkey 09 encrypted with mkey 10. + { 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 }, // Mkey 10 encrypted with mkey 11. + { 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, // Mkey 11 encrypted with mkey 12. + { 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, // Mkey 12 encrypted with mkey 13. + { 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, // Mkey 13 encrypted with mkey 14. + { 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, // Mkey 14 encrypted with mkey 15. + { 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, // Mkey 15 encrypted with mkey 16. + { 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, // Mkey 16 encrypted with mkey 17. + { 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, // Mkey 17 encrypted with mkey 18. + { 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, // Mkey 18 encrypted with mkey 19. +}; + +//!TODO: Update on mkey changes. +static const u8 new_console_keyseed[HOS_KB_VERSION_MAX - HOS_KB_VERSION_400 + 1][SE_KEY_128_SIZE] = { + { 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D }, // 4.x New Device Key Source. + { 0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C }, // 5.x New Device Key Source. + { 0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4 }, // 6.x New Device Key Source. + { 0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17 }, // 6.2.0 New Device Key Source. + { 0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D }, // 7.0.0 New Device Key Source. + { 0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE }, // 8.1.0 New Device Key Source. + { 0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49 }, // 9.0.0 New Device Key Source. + { 0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94 }, // 9.1.0 New Device Key Source. + { 0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6 }, // 12.1.0 New Device Key Source. + { 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, // 13.0.0 New Device Key Source. + { 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, // 14.0.0 New Device Key Source. + { 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, // 15.0.0 New Device Key Source. + { 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, // 16.0.0 New Device Key Source. + { 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, // 17.0.0 New Device Key Source. + { 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, // 18.0.0 New Device Key Source. + { 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, // 19.0.0 New Device Key Source. + { 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, // 20.0.0 New Device Key Source. +}; + +//!TODO: Update on mkey changes. +static const u8 new_console_kekseed[HOS_KB_VERSION_MAX - HOS_KB_VERSION_400 + 1][SE_KEY_128_SIZE] = { + { 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D }, // 4.x New Device Keygen Source. + { 0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E }, // 5.x New Device Keygen Source. + { 0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF }, // 6.x New Device Keygen Source. + { 0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB }, // 6.2.0 New Device Keygen Source. + { 0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E }, // 7.0.0 New Device Keygen Source. + { 0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D }, // 8.1.0 New Device Keygen Source. + { 0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED }, // 9.0.0 New Device Keygen Source. + { 0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36 }, // 9.1.0 New Device Keygen Source. + { 0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3 }, // 12.1.0 New Device Keygen Source. + { 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, // 13.0.0 New Device Keygen Source. + { 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, // 14.0.0 New Device Keygen Source. + { 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, // 15.0.0 New Device Keygen Source. + { 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, // 16.0.0 New Device Keygen Source. + { 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, // 17.0.0 New Device Keygen Source. + { 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, // 18.0.0 New Device Keygen Source. + { 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, // 19.0.0 New Device Keygen Source. + { 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, // 20.0.0 New Device Keygen Source. +}; + +static const u8 gen_keyseed[SE_KEY_128_SIZE] = + { 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8 }; + +static const u8 gen_kekseed[SE_KEY_128_SIZE] = + { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 }; + +static const u8 gen_keyseed_retail[SE_KEY_128_SIZE] = + { 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95 }; + +static const u8 bis_kekseed[SE_KEY_128_SIZE] = + { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F }; + +static const u8 bis_keyseed[][SE_KEY_128_SIZE] = { + { 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48 }, // BIS 0 Crypt seed. + { 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06 }, // BIS 0 Tweak seed. + { 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F }, // BIS 1 Crypt seed. + { 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4 }, // BIS 1 Tweak seed. + { 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C }, // BIS 2/3 Crypt seed. + { 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4 } // BIS 2/3 Tweak seed. +}; + +bool hos_eks_rw_try(u8 *buf, bool write) { - u8 tmp[0x20]; - u32 retries = 0; - - if (kb > KB_FIRMWARE_VERSION_MAX) - return 0; - - if (kb <= KB_FIRMWARE_VERSION_600) - tsec_ctxt->size = 0xF00; - else if (kb == KB_FIRMWARE_VERSION_620) - tsec_ctxt->size = 0x2900; - else if (kb == KB_FIRMWARE_VERSION_700) - tsec_ctxt->size = 0x3000; - else - tsec_ctxt->size = 0x3300; - - // Prepare smmu tsec page for 6.2.0. - if (kb == KB_FIRMWARE_VERSION_620) + for (u32 i = 0; i < 3; i++) { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size); - tsec_ctxt->fw = tsec_paged; - } - - // Get TSEC key. - if (kb <= KB_FIRMWARE_VERSION_620) - { - while (tsec_query(tmp, kb, tsec_ctxt) < 0) + if (!write) { - memset(tmp, 0x00, 0x20); - retries++; - - // We rely on racing conditions, make sure we cover even the unluckiest cases. - if (retries > 15) - { - EPRINTF("\nFailed to get TSEC keys. Please try again.\n"); - return 0; - } + if (sdmmc_storage_read(&sd_storage, 0, 1, buf)) + return true; + } + else + { + if (sdmmc_storage_write(&sd_storage, 0, 1, buf)) + return true; } } - if (kb >= KB_FIRMWARE_VERSION_700) - se_aes_unwrap_key(8, 12, package2_keyseed); - else if (kb == KB_FIRMWARE_VERSION_620) + return false; +} + +static void _hos_eks_get() +{ + // Check if Erista based unit. + if (h_cfg.t210b01) + return; + + // Check if EKS already found and parsed. + if (!h_cfg.eks) { - // Set TSEC key. - se_aes_key_set(12, tmp, 0x10); - // Set TSEC root key. - se_aes_key_set(13, tmp + 0x10, 0x10); + // Read EKS blob. + u8 *mbr = zalloc(SD_BLOCKSIZE); + if (!hos_eks_rw_try(mbr, false)) + goto out; + + // Decrypt EKS blob. + hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x80); + se_aes_crypt_ecb(14, DECRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Check if valid and for this unit. + if (eks->magic == HOS_EKS_MAGIC && eks->lot0 == FUSE(FUSE_OPT_LOT_CODE_0)) + { + h_cfg.eks = eks; + return; + } + +out: + free(mbr); + } +} + +static void _hos_eks_save() +{ + // Check if Erista based unit. + if (h_cfg.t210b01) + return; + + // EKS save. Only for 7.0.0 and up. + bool new_eks = false; + if (!h_cfg.eks) + { + h_cfg.eks = zalloc(SD_BLOCKSIZE); + new_eks = true; + } + + // If matching blob doesn't exist, create it. + if (h_cfg.eks->enabled != HOS_EKS_TSEC_VER) + { + // Read EKS blob. + u8 *mbr = zalloc(SD_BLOCKSIZE); + if (!hos_eks_rw_try(mbr, false)) + { + if (new_eks) + { + free(h_cfg.eks); + h_cfg.eks = NULL; + } + + goto out; + } + + // Get keys. + u8 *keys = (u8 *)zalloc(SZ_8K); + se_get_aes_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE); + + // Set magic and personalized info. + h_cfg.eks->magic = HOS_EKS_MAGIC; + h_cfg.eks->enabled = HOS_EKS_TSEC_VER; + h_cfg.eks->lot0 = FUSE(FUSE_OPT_LOT_CODE_0); + + // Copy new keys. + memcpy(h_cfg.eks->tsec, keys + 12 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(h_cfg.eks->troot, keys + 13 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + memcpy(h_cfg.eks->troot_dev, keys + 11 * SE_KEY_128_SIZE, SE_KEY_128_SIZE); + + // Encrypt EKS blob. + u8 *eks = zalloc(SD_BLOCKSIZE); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, ENCRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + hos_eks_rw_try(mbr, true); + + free(eks); + free(keys); +out: + free(mbr); + } +} + +void hos_eks_clear(u32 kb) +{ + // Check if Erista based unit. + if (h_cfg.t210b01) + return; + + if (h_cfg.eks && kb >= HOS_KB_VERSION_700) + { + // Check if current Master key is enabled. + if (h_cfg.eks->enabled) + { + // Read EKS blob. + u8 *mbr = zalloc(SD_BLOCKSIZE); + if (!hos_eks_rw_try(mbr, false)) + goto out; + + // Disable current Master key version. + h_cfg.eks->enabled = 0; + + // Encrypt EKS blob. + u8 *eks = zalloc(SD_BLOCKSIZE); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, ENCRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + hos_eks_rw_try(mbr, true); + + free(eks); +out: + free(mbr); + } + } +} + +int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) +{ + u32 retries = 0; + bool use_tsec = false; + tsec_keys_t tsec_keys; + kb_t *kb_data = (kb_t *)keyblob; + + if (kb > HOS_KB_VERSION_MAX) + return 0; + + // Do Mariko keygen. + if (h_cfg.t210b01) + { + // Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units. + se_aes_unwrap_key(10, 14, console_keyseed_4xx); + + // Derive master key. + se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]); + se_aes_unwrap_key(7, 7, master_keyseed_retail); + + // Derive latest pkg2 key. + se_aes_unwrap_key(8, 7, package2_keyseed); + + return 1; + } + + // Do Erista keygen. + + // Use HOS EKS if it exists. + _hos_eks_get(); + + // Use tsec keygen for old firmware or if EKS keys does not exist for newer. + if (kb <= HOS_KB_VERSION_620 || !h_cfg.eks || (h_cfg.eks->enabled != HOS_EKS_TSEC_VER)) + use_tsec = true; + + if (kb <= HOS_KB_VERSION_600) + { + tsec_ctxt->size = 0xF00; + tsec_ctxt->type = TSEC_FW_TYPE_OLD; + } + else if (kb == HOS_KB_VERSION_620) + { + tsec_ctxt->size = 0x2900; + tsec_ctxt->type = TSEC_FW_TYPE_EMU; + + // Prepare smmu tsec page for 6.2.0. + u8 *tsec_paged = (u8 *)smmu_page_zalloc(3); + memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size); + tsec_ctxt->fw = tsec_paged; + } + else if (use_tsec) // 7.0.0+ + { + /* + * 7.0.0/8.1.0 tsec fw are 0x3000/0x3300. + * Unused here because of THK. + */ + + // Use custom TSEC Hovi Keygen firmware. + tsec_ctxt->fw = sd_file_read("bootloader/sys/thk.bin", NULL); + if (!tsec_ctxt->fw) + { + EPRINTF("\nFailed to load thk.bin"); + return 0; + } + + tsec_ctxt->size = 0x1F00; + tsec_ctxt->type = TSEC_FW_TYPE_NEW; + } + else if (h_cfg.eks) + { + // EKS found. Set TSEC keys. + se_aes_key_set(12, h_cfg.eks->tsec, SE_KEY_128_SIZE); + se_aes_key_set(13, h_cfg.eks->troot, SE_KEY_128_SIZE); + se_aes_key_set(11, h_cfg.eks->troot_dev, SE_KEY_128_SIZE); + } + + // Get TSEC key. + while (use_tsec && tsec_query(&tsec_keys, tsec_ctxt) < 0) + { + memset(&tsec_keys, 0x00, 0x20); + retries++; + + // We rely on racing conditions, make sure we cover even the unluckiest cases. + if (retries > 15) + { + EPRINTF("\nFailed to get TSEC keys. Please try again."); + return 0; + } + } + + if (kb >= HOS_KB_VERSION_700) + { + // For 7.0.0 and up, save EKS slot if it doesn't exist. + if (use_tsec) + { + _hos_eks_save(); + free(tsec_ctxt->fw); + } + + // Decrypt keyblob and set keyslots. + se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tmp, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tsec_keys.tmp); + + // Derive device keys. + se_aes_unwrap_key(10, 15, console_keyseed_4xx); + se_aes_unwrap_key(15, 15, console_keyseed); + + // Derive master kek. + se_aes_unwrap_key(7, 13, master_kekseed_t210_max); + + // Derive master key. + se_aes_unwrap_key(7, 7, master_keyseed_retail); // Package2 key. - se_aes_key_set(8, tmp + 0x10, 0x10); - se_aes_unwrap_key(8, 8, master_keyseed_620); - se_aes_unwrap_key(8, 8, master_keyseed_retail); - se_aes_unwrap_key(8, 8, package2_keyseed); + se_aes_unwrap_key(8, 7, package2_keyseed); + } + else if (kb == HOS_KB_VERSION_620) + { + // Set TSEC key. + se_aes_key_set(12, tsec_keys.tsec, SE_KEY_128_SIZE); + // Set TSEC root key. + se_aes_key_set(13, tsec_keys.tsec_root, SE_KEY_128_SIZE); + + // Decrypt keyblob and set keyslots. + se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tmp, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tsec_keys.tmp); + + // Derive device keys. + se_aes_unwrap_key(10, 15, console_keyseed_4xx); + se_aes_unwrap_key(15, 15, console_keyseed); + + // Derive master kek. + se_aes_unwrap_key(7, 13, master_kekseed_620); + + // Derive master key. + se_aes_unwrap_key(7, 7, master_keyseed_retail); + + // Package2 key. + se_aes_unwrap_key(8, 7, package2_keyseed); } else { // Set TSEC key. - se_aes_key_set(13, tmp, 0x10); + se_aes_key_set(13, tsec_keys.tsec, SE_KEY_128_SIZE); // Derive keyblob keys from TSEC+SBK. - se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]); - se_aes_unwrap_key(15, 14, tmp); - se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]); - se_aes_unwrap_key(13, 14, tmp); + se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tsec_keys.tsec); + se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, keyblob_keyseeds[kb]); + se_aes_unwrap_key(13, 14, tsec_keys.tsec); - // Clear SBK. - se_aes_key_clear(14); +/* + // Verify keyblob CMAC. + u8 cmac[SE_KEY_128_SIZE]; + se_aes_unwrap_key(11, 13, cmac_keyseed); + se_aes_cmac(cmac, SE_KEY_128_SIZE, 11, (void *)kb_data->ctr, sizeof(kb_data->ctr) + sizeof(kb_data->keys)); + if (!memcmp(kb_data->cmac, cmac, SE_KEY_128_SIZE)) + return 0; +*/ - //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; - - se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed); + se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, cmac_keyseed); se_aes_unwrap_key(11, 13, cmac_keyseed); // 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); // Package1 key. - se_aes_key_set(12, keyblob + 0x20, 0x10); - se_aes_key_set(13, keyblob + 0x20, 0x10); + se_aes_crypt_ctr(13, &kb_data->keys, sizeof(kb_keys_t), &kb_data->keys, sizeof(kb_keys_t), kb_data->ctr); + se_aes_key_set(11, kb_data->keys.package1_key, SE_KEY_128_SIZE); + se_aes_key_set(12, kb_data->keys.master_kekseed, SE_KEY_128_SIZE); + se_aes_key_set(13, kb_data->keys.master_kekseed, SE_KEY_128_SIZE); - se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail); + se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tsec, master_keyseed_retail); switch (kb) { - case KB_FIRMWARE_VERSION_100_200: - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: + case HOS_KB_VERSION_100: + case HOS_KB_VERSION_300: + case HOS_KB_VERSION_301: se_aes_unwrap_key(13, 15, console_keyseed); se_aes_unwrap_key(12, 12, master_keyseed_retail); break; - case KB_FIRMWARE_VERSION_400: - se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx); + case HOS_KB_VERSION_400: + se_aes_unwrap_key(13, 15, console_keyseed_4xx); se_aes_unwrap_key(15, 15, console_keyseed); - se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610); + //se_aes_unwrap_key(14, 12, master_keyseed_4xx); // In this context it's useless. So don't kill SBK. se_aes_unwrap_key(12, 12, master_keyseed_retail); break; - case KB_FIRMWARE_VERSION_500: - case KB_FIRMWARE_VERSION_600: - se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx); + case HOS_KB_VERSION_500: + case HOS_KB_VERSION_600: + se_aes_unwrap_key(10, 15, console_keyseed_4xx); se_aes_unwrap_key(15, 15, console_keyseed); - se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610); + //se_aes_unwrap_key(14, 12, master_keyseed_4xx); // In this context it's useless. So don't kill SBK. se_aes_unwrap_key(12, 12, master_keyseed_retail); break; } @@ -208,3 +537,198 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) return 1; } + +static void _hos_validate_mkey() +{ + u8 tmp_mkey[SE_KEY_128_SIZE]; + u32 mkey_idx = sizeof(mkey_vectors) / SE_KEY_128_SIZE; + do + { + mkey_idx--; + se_aes_crypt_ecb(7, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, mkey_vectors[mkey_idx], SE_KEY_128_SIZE); + for (u32 idx = 0; idx < mkey_idx; idx++) + { + se_aes_key_clear(2); + se_aes_key_set(2, tmp_mkey, SE_KEY_128_SIZE); + se_aes_crypt_ecb(2, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, mkey_vectors[mkey_idx - 1 - idx], SE_KEY_128_SIZE); + } + + if (!memcmp(tmp_mkey, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) + { + se_aes_key_clear(2); + return; + } + } while (mkey_idx - 1); + + se_aes_key_clear(2); + hos_eks_clear(HOS_KB_VERSION_MAX); +} + +static void _hos_bis_print_key(u32 idx, u8 *key) +{ + gfx_printf("BIS %d Crypt: ", idx); + for (int i = 0; i < SE_KEY_128_SIZE; i++) + gfx_printf("%02X", key[((idx * 2 + 0) * SE_KEY_128_SIZE) + i]); + gfx_puts("\n"); + + gfx_printf("BIS %d Tweak: ", idx); + for (int i = 0; i < SE_KEY_128_SIZE; i++) + gfx_printf("%02X", key[((idx * 2 + 1) * SE_KEY_128_SIZE) + i]); + gfx_puts("\n"); +} + +int hos_bis_keygen() +{ + u32 keygen_rev = 0; + u32 console_key_slot = 15; // HOS_KB_VERSION_MAX. Only for Erista. + tsec_ctxt_t tsec_ctxt = {0}; + + if (!bis_keys) + bis_keys = malloc(SE_KEY_128_SIZE * 6); + + // Run initial keygen. + hos_keygen(NULL, HOS_KB_VERSION_MAX, &tsec_ctxt); + + // All Mariko use new device keygen. New keygen was introduced in 4.0.0. + // We check unconditionally in order to support downgrades. + keygen_rev = fuse_read_odm_keygen_rev(); + + gfx_printf("Keygen rev: %d\n", keygen_rev); + + if (keygen_rev) + { + u8 tmp_mkey[SE_KEY_128_SIZE]; + u32 mkey_idx = sizeof(mkey_vectors) / SE_KEY_128_SIZE; + + // Keygen revision uses bootloader version, which starts from 1. + keygen_rev -= (HOS_KB_VERSION_400 + 1); + + // Derive mkey 0. + do + { + mkey_idx--; + se_aes_crypt_ecb(7, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, mkey_vectors[mkey_idx], SE_KEY_128_SIZE); + for (u32 idx = 0; idx < mkey_idx; idx++) + { + se_aes_key_clear(2); + se_aes_key_set(2, tmp_mkey, SE_KEY_128_SIZE); + se_aes_crypt_ecb(2, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, mkey_vectors[mkey_idx - 1 - idx], SE_KEY_128_SIZE); + } + } while (memcmp(tmp_mkey, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0 && (mkey_idx - 1)); + + // Derive new device key. + se_aes_key_clear(1); + se_aes_unwrap_key(1, 10, new_console_keyseed[keygen_rev]); // Uses Device key 4x. + se_aes_crypt_ecb(10, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, new_console_keyseed[keygen_rev], SE_KEY_128_SIZE); // Uses Device key 4x. + se_aes_unwrap_key(1, 2, new_console_kekseed[keygen_rev]); // Uses Master Key 0. + se_aes_unwrap_key(1, 1, tmp_mkey); + + console_key_slot = 1; + } + + // Generate generic key. + se_aes_key_clear(2); + se_aes_unwrap_key(2, console_key_slot, gen_keyseed_retail); + + // Clear bis keys storage. + memset(bis_keys, 0, SE_KEY_128_SIZE * 6); + + // Generate BIS 0 Keys. + se_aes_crypt_block_ecb(2, DECRYPT, bis_keys + (0 * SE_KEY_128_SIZE), bis_keyseed[0]); + se_aes_crypt_block_ecb(2, DECRYPT, bis_keys + (1 * SE_KEY_128_SIZE), bis_keyseed[1]); + + // Generate generic kek. + se_aes_key_clear(2); + se_aes_unwrap_key(2, console_key_slot, gen_kekseed); + se_aes_unwrap_key(2, 2, bis_kekseed); + se_aes_unwrap_key(2, 2, gen_keyseed); + + // Generate BIS 1 Keys. + se_aes_crypt_block_ecb(2, DECRYPT, bis_keys + (2 * SE_KEY_128_SIZE), bis_keyseed[2]); + se_aes_crypt_block_ecb(2, DECRYPT, bis_keys + (3 * SE_KEY_128_SIZE), bis_keyseed[3]); + + // Generate BIS 2/3 Keys. + se_aes_crypt_block_ecb(2, DECRYPT, bis_keys + (4 * SE_KEY_128_SIZE), bis_keyseed[4]); + se_aes_crypt_block_ecb(2, DECRYPT, bis_keys + (5 * SE_KEY_128_SIZE), bis_keyseed[5]); + + // Validate key because HOS_KB_VERSION_MAX. + if (!h_cfg.t210b01) + _hos_validate_mkey(); + + // Print keys to console. + _hos_bis_print_key(0, bis_keys); + _hos_bis_print_key(1, bis_keys); + _hos_bis_print_key(2, bis_keys); + + // Clear all AES tmp and bis keyslots. + for (u32 i = 0; i < 6; i++) + se_aes_key_clear(i); + + // Set BIS keys. + se_aes_key_set(0, bis_keys + (0 * SE_KEY_128_SIZE), SE_KEY_128_SIZE); + se_aes_key_set(1, bis_keys + (1 * SE_KEY_128_SIZE), SE_KEY_128_SIZE); + + se_aes_key_set(2, bis_keys + (2 * SE_KEY_128_SIZE), SE_KEY_128_SIZE); + se_aes_key_set(3, bis_keys + (3 * SE_KEY_128_SIZE), SE_KEY_128_SIZE); + + se_aes_key_set(4, bis_keys + (4 * SE_KEY_128_SIZE), SE_KEY_128_SIZE); + se_aes_key_set(5, bis_keys + (5 * SE_KEY_128_SIZE), SE_KEY_128_SIZE); + + return 1; +} + +void hos_bis_keys_clear() +{ + // Clear all aes bis keyslots. + for (u32 i = 0; i < 6; i++) + se_aes_key_clear(i); +} + +int hos_dump_cal0() +{ + // Init eMMC. + if (!emmc_initialize(false)) + return 1; + + // Generate BIS keys + hos_bis_keygen(); + + if (!cal0_buf) + cal0_buf = malloc(SZ_64K); + + // Read and decrypt CAL0. + emmc_set_partition(EMMC_GPP); + LIST_INIT(gpt); + emmc_gpt_parse(&gpt); + emmc_part_t *cal0_part = emmc_part_find(&gpt, "PRODINFO"); // check if null + nx_emmc_bis_init(cal0_part, false, 0); + nx_emmc_bis_read(0, 0x40, cal0_buf); + nx_emmc_bis_end(); + emmc_gpt_free(&gpt); + + emmc_end(); + + // Clear BIS keys slots. + hos_bis_keys_clear(); + + nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf; + + // Check keys validity. + if (memcmp(&cal0->magic, "CAL0", 4)) + { + free(cal0_buf); + cal0_buf = NULL; + + // Clear EKS keys. + hos_eks_clear(HOS_KB_VERSION_MAX); + + return 2; + } + + u32 hash[8]; + se_calc_sha256_oneshot(hash, (u8 *)cal0 + 0x40, cal0->body_size); + if (memcmp(hash, cal0->body_sha256, 0x20)) + return 3; + + return 0; +} diff --git a/nyx/nyx_gui/hos/hos.h b/nyx/nyx_gui/hos/hos.h index 13ed6e9..bdc82b9 100644 --- a/nyx/nyx_gui/hos/hos.h +++ b/nyx/nyx_gui/hos/hos.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,26 +18,56 @@ #ifndef _HOS_H_ #define _HOS_H_ +#include + #include "pkg1.h" #include "pkg2.h" -#include "../utils/types.h" -#include "../config/ini.h" -#include "../sec/tsec.h" -#define KB_FIRMWARE_VERSION_100_200 0 -#define KB_FIRMWARE_VERSION_300 1 -#define KB_FIRMWARE_VERSION_301 2 -#define KB_FIRMWARE_VERSION_400 3 -#define KB_FIRMWARE_VERSION_500 4 -#define KB_FIRMWARE_VERSION_600 5 -#define KB_FIRMWARE_VERSION_620 6 -#define KB_FIRMWARE_VERSION_700 7 -#define KB_FIRMWARE_VERSION_810 8 -#define KB_FIRMWARE_VERSION_900 9 -#define KB_FIRMWARE_VERSION_910 10 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 +#include -#define HOS_PKG11_MAGIC 0x31314B50 +//!TODO: Update on mkey changes. +enum { + HOS_KB_VERSION_100 = 0, + HOS_KB_VERSION_300 = 1, + HOS_KB_VERSION_301 = 2, + HOS_KB_VERSION_400 = 3, + HOS_KB_VERSION_500 = 4, + HOS_KB_VERSION_600 = 5, + HOS_KB_VERSION_620 = 6, + HOS_KB_VERSION_700 = 7, + HOS_KB_VERSION_810 = 8, + HOS_KB_VERSION_900 = 9, + HOS_KB_VERSION_910 = 10, + HOS_KB_VERSION_1210 = 11, + HOS_KB_VERSION_1300 = 12, + HOS_KB_VERSION_1400 = 13, + HOS_KB_VERSION_1500 = 14, + HOS_KB_VERSION_1600 = 15, + HOS_KB_VERSION_1700 = 16, + HOS_KB_VERSION_1800 = 17, + HOS_KB_VERSION_1900 = 18, + HOS_KB_VERSION_2000 = 19, + HOS_KB_VERSION_MAX = HOS_KB_VERSION_2000 +}; + +#define HOS_TSEC_VERSION 4 //! TODO: Update on TSEC Root Key changes. + +#define HOS_PKG11_MAGIC 0x31314B50 +#define HOS_EKS_MAGIC 0x31534B45 // EKS1. +#define HOS_EKS_TSEC_VER (HOS_KB_VERSION_700 + HOS_TSEC_VERSION) + +typedef struct _hos_eks_mbr_t +{ + u32 magic; + u32 enabled; + u32 lot0; + u32 rsvd; + u8 tsec[SE_KEY_128_SIZE]; + u8 troot[SE_KEY_128_SIZE]; + u8 troot_dev[SE_KEY_128_SIZE]; +} hos_eks_mbr_t; + +static_assert(sizeof(hos_eks_mbr_t) == 64, "HOS EKS size is wrong!"); typedef struct _launch_ctxt_t { @@ -52,23 +83,22 @@ typedef struct _launch_ctxt_t void *pkg2; u32 pkg2_size; + bool new_pkg2; - bool new_pkg2; void *kernel; u32 kernel_size; link_t kip1_list; char* kip1_patches; - bool svcperm; - bool debugmode; - bool stock; - bool atmosphere; - bool exo_no_user_exceptions; - bool emuMMC; - ini_sec_t *cfg; } launch_ctxt_t; -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt); +extern u8 *cal0_buf; + +void hos_eks_clear(u32 kb); +int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt); +int hos_bis_keygen(); +void hos_bis_keys_clear(); +int hos_dump_cal0(); #endif diff --git a/nyx/nyx_gui/hos/pkg1.c b/nyx/nyx_gui/hos/pkg1.c index 68b583b..f0a4d53 100644 --- a/nyx/nyx_gui/hos/pkg1.c +++ b/nyx/nyx_gui/hos/pkg1.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * Copyright (c) 2018 balika011 * * This program is free software; you can redistribute it and/or modify it @@ -19,82 +19,139 @@ #include +#include + +#include "hos.h" #include "pkg1.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../utils/aarch64_util.h" +#include "../config.h" + +extern hekate_config h_cfg; /* * 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 } - * 6.0: {ldr, sm, wb} { 1, 2, 0 } - * 6.2: {ldr, sm, wb} { 1, 2, 0 } - * 7.0: {ldr, sm, wb} { 1, 2, 0 } + * 1.0: {sm, ldr, wb} { 2, 1, 0 } + * 2.0+: {wb, ldr, sm} { 0, 1, 2 } + * 4.0+: {ldr, sm, wb} { 1, 2, 0 } */ +static const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTION_WB }; +static const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM }; +static const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB }; + + // Timestamp KB TSEC PK11 SECMON Warmboot static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, 0x40014020, 0x8000D000 }, //1.0.0 - { "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000 }, //2.0.0 - 2.3.0 - { "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000 }, //3.0.0 - { "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000 }, //3.0.1 - 3.0.2 - { "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000 }, //4.0.0 - 4.1.0 - { "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000 }, //5.0.0 - 5.1.0 - { "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800 }, //6.0.0 - 6.1.0 - { "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800 }, //6.2.0 - { "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //7.0.0 - { "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //7.0.1 - { "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //8.0.0 - 8.0.1 - { "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //8.1.0 - { "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //9.0.0 - { "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //9.1.0 - { NULL } //End. + { "20161121", 0, 0x1900, 0x3FE0, 0x40014020, 0x8000D000 }, // 1.0.0. + { "20170210", 0, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000 }, // 2.0.0 - 2.3.0. + { "20170519", 1, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000 }, // 3.0.0. + { "20170710", 2, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000 }, // 3.0.1 - 3.0.2. + { "20170921", 3, 0x1800, 0x3FE0, 0x4002B000, 0x4003B000 }, // 4.0.0 - 4.1.0. + { "20180220", 4, 0x1900, 0x3FE0, 0x4002B000, 0x4003B000 }, // 5.0.0 - 5.1.0. + { "20180802", 5, 0x1900, 0x3FE0, 0x4002B000, 0x4003D800 }, // 6.0.0 - 6.1.0. + { "20181107", 6, 0x0E00, 0x6FE0, 0x4002B000, 0x4003D800 }, // 6.2.0. + { "20181218", 7, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000 }, // 7.0.0. + { "20190208", 7, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000 }, // 7.0.1. + { "20190314", 7, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 8.0.0 - 8.0.1. + { "20190531", 8, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 8.1.0 - 8.1.1. + { "20190809", 9, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 9.0.0 - 9.0.1. + { "20191021", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 9.1.0 - 9.2.0. + { "20200303", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 10.0.0 - 10.2.0. + { "20201030", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 11.0.0 - 11.0.1. + { "20210129", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 12.0.0 - 12.0.1. + { "20210422", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 12.0.2 - 12.0.3. + { "20210607", 11, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 12.1.0. + { "20210805", 12, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 13.0.0 - 13.2.0 + { "20220105", 12, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 13.2.1. + { "20220209", 13, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 14.0.0 - 14.1.2. + { "20220801", 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 15.0.0 - 15.0.1. + { "20230111", 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 16.0.0 - 16.1.0. + { "20230906", 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 17.0.0 - 17.0.1. + { "20240207", 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 18.0.0 - 18.1.0. + { "20240808", 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 19.0.0 - 19.0.1. + { "20250206", 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 20.0.0+ }; const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date) { + pk1_hdr_t *hdr = (pk1_hdr_t *)pkg1; if (build_date) { - memcpy(build_date, (char *)(pkg1 + 0x10), 14); + memcpy(build_date, hdr->timestamp, 14); build_date[14] = 0; } - for (u32 i = 0; _pkg1_ids[i].id; i++) - if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) + for (u32 i = 0; i < ARRAY_SIZE(_pkg1_ids); i++) + if (!memcmp(hdr->timestamp, _pkg1_ids[i].id, 8)) return &_pkg1_ids[i]; + return NULL; } -void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1) +int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1) { + pk11_hdr_t *hdr; + // 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); + if (!h_cfg.t210b01) + { + u8 *pkg11 = pkg1 + id->pkg11_off; + u32 pkg11_size = *(u32 *)pkg11; + hdr = (pk11_hdr_t *)(pkg11 + 0x20); + se_aes_crypt_ctr(11, hdr, pkg11_size, hdr, pkg11_size, pkg11 + 0x10); + } + else + { + bl_hdr_t210b01_t *oem_hdr = (bl_hdr_t210b01_t *)pkg1; + pkg1 += sizeof(bl_hdr_t210b01_t); + hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20); + + // Use BEK for T210B01. + // Additionally, skip 0x20 bytes from decryption to maintain the header. + se_aes_iv_clear(13); + se_aes_crypt_cbc(13, DECRYPT, pkg1 + 0x20, oem_hdr->size - 0x20, pkg1 + 0x20, oem_hdr->size - 0x20); + } + + // Return if header is valid. + return (hdr->magic == PKG1_MAGIC); } -void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1) +const u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1) { - pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20); + const u8 *sec_map; + const 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 }; + // Get correct header mapping. + if (id->kb == HOS_KB_VERSION_100 && !memcmp(id->id, "20161121", 8)) + sec_map = sec_map_100; + else if (id->kb <= HOS_KB_VERSION_301) + sec_map = sec_map_2xx; + else + sec_map = sec_map_4xx; + + // Copy secmon, warmboot and nx bootloader payloads. 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] == 1 && ldr_dst) - memcpy(ldr_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]]; + u32 ssize = sec_size[sec_map[i]]; + switch (sec_map[i]) + { + case PK11_SECTION_WB: + if (wm_dst) + memcpy(wm_dst, pdata, ssize); + break; + case PK11_SECTION_LD: + if (ldr_dst) + memcpy(ldr_dst, pdata, ssize); + break; + case PK11_SECTION_SM: + if (sm_dst) + memcpy(sm_dst, pdata, ssize); + break; + } + pdata += ssize; } + + return sec_map; } diff --git a/nyx/nyx_gui/hos/pkg1.h b/nyx/nyx_gui/hos/pkg1.h index d22b672..6d30b58 100644 --- a/nyx/nyx_gui/hos/pkg1.h +++ b/nyx/nyx_gui/hos/pkg1.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2022-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,7 +18,37 @@ #ifndef _PKG1_H_ #define _PKG1_H_ -#include "../utils/types.h" +#include + +#define PKG1_MAGIC 0x31314B50 + +#define PK11_SECTION_WB 0 +#define PK11_SECTION_LD 1 +#define PK11_SECTION_SM 2 + +typedef struct _bl_hdr_t210b01_t +{ +/* 0x000 */ u8 aes_mac[0x10]; +/* 0x010 */ u8 rsa_sig[0x100]; +/* 0x110 */ u8 salt[0x20]; +/* 0x130 */ u8 sha256[0x20]; +/* 0x150 */ u32 version; +/* 0x154 */ u32 size; +/* 0x158 */ u32 load_addr; +/* 0x15C */ u32 entrypoint; +/* 0x160 */ u8 rsvd[0x10]; +} bl_hdr_t210b01_t; + +typedef struct _pk1_hdr_t +{ +/* 0x00 */ u32 si_sha256; // Secure Init. +/* 0x04 */ u32 sm_sha256; // Secure Monitor. +/* 0x08 */ u32 sl_sha256; // Secure Loader. +/* 0x0C */ u32 unk; // what's this? It's not warmboot. +/* 0x10 */ char timestamp[14]; +/* 0x1E */ u8 keygen; +/* 0x1F */ u8 version; +} pk1_hdr_t; typedef struct _pkg1_id_t { @@ -25,7 +56,6 @@ typedef struct _pkg1_id_t u32 kb; u32 tsec_off; u32 pkg11_off; - u32 sec_map[3]; u32 secmon_base; u32 warmboot_base; } pkg1_id_t; @@ -43,7 +73,7 @@ typedef struct _pk11_hdr_t } pk11_hdr_t; const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date); -void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); -void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1); +int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); +const u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1); #endif diff --git a/nyx/nyx_gui/hos/pkg2.c b/nyx/nyx_gui/hos/pkg2.c index 8462d1c..7b6d6cb 100644 --- a/nyx/nyx_gui/hos/pkg2.c +++ b/nyx/nyx_gui/hos/pkg2.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2024 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,21 +17,22 @@ #include +#include + #include "pkg2.h" #include "hos.h" -#include "../libs/fatfs/ff.h" -#include "../utils/aarch64_util.h" -#include "../mem/heap.h" -#include "../sec/se.h" -#include "../libs/compr/blz.h" - -#include "../gfx/gfx.h" +#include "../config.h" +#include +#include +extern hekate_config h_cfg; extern const u8 package2_keyseed[]; -/*#include "util.h" -#define DPRINTF(...) gfx_printf(__VA_ARGS__) +u32 pkg2_newkern_ini1_start; +u32 pkg2_newkern_ini1_end; + +/*#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DEBUG_PRINTING*/ #define DPRINTF(...) @@ -45,58 +46,85 @@ u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1) void pkg2_get_newkern_info(u8 *kern_data) { - u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1); - pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC. + u32 crt_start = 0; + u32 pkg2_newkern_ini1_info = 0; + pkg2_newkern_ini1_start = 0; - pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val); - pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); -} + u32 first_op = *(u32 *)kern_data; + if ((first_op & 0xFE000000) == 0x14000000) + crt_start = (first_op & 0x1FFFFFF) << 2; -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) -{ - u8 *ptr; - // Check for new pkg2 type. - if (!pkg2->sec_size[PKG2_SEC_INI1]) + // Find static OP offset that is close to INI1 offset. + u32 counter_ops = 0x100; + while (counter_ops) { - pkg2_get_newkern_info(pkg2->data); + if (*(u32 *)(kern_data + crt_start + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC) + { + // OP found. Add 12 for the INI1 info offset. + pkg2_newkern_ini1_info = crt_start + 0x100 - counter_ops + 12; - ptr = pkg2->data + pkg2_newkern_ini1_start; - *new_pkg2 = true; + // On v2 kernel with dynamic crt there's a NOP after heuristic. Offset one op. + if (crt_start) + pkg2_newkern_ini1_info += 4; + break; + } + + counter_ops -= 4; } - else - ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL]; - pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr; - ptr += sizeof(pkg2_ini1_t); + // Offset not found? + if (!counter_ops) + return; - for (u32 i = 0; i < ini1->num_procs; i++) + u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_info); + pkg2_newkern_ini1_info += ((info_op & 0xFFFF) >> 3); // Parse ADR and PC. + + pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_info); + pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_info + 0x8); + + // On v2 kernel with dynamic crt, values are relative to value address. + if (crt_start) { - 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); + pkg2_newkern_ini1_start += pkg2_newkern_ini1_info; + pkg2_newkern_ini1_end += pkg2_newkern_ini1_info + 0x8; } } -static const u8 mkey_keyseed_8xx[][0x10] = +//!TODO: Update on mkey changes. +static const u8 mkey_vector_7xx[HOS_KB_VERSION_MAX - HOS_KB_VERSION_810 + 1][SE_KEY_128_SIZE] = { - // Master key 8 encrypted with 9. (8.1.0 with 9.0.0) + // Master key 7 encrypted with 8. (7.0.0 with 8.1.0) + { 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }, + // Master key 8 encrypted with 9. (8.1.0 with 9.0.0) { 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, - // Master key 9 encrypted with 10. (9.0.0 with 9.1.0) - { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A } + // Master key 9 encrypted with 10. (9.0.0 with 9.1.0) + { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }, + // Master key 10 encrypted with 11. (9.1.0 with 12.1.0) + { 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 }, + // Master key 11 encrypted with 12. (12.1.0 with 13.0.0) + { 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, + // Master key 12 encrypted with 13. (13.0.0 with 14.0.0) + { 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, + // Master key 13 encrypted with 14. (14.0.0 with 15.0.0) + { 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, + // Master key 14 encrypted with 15. (15.0.0 with 16.0.0) + { 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, + // Master key 15 encrypted with 16. (16.0.0 with 17.0.0) + { 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, + // Master key 16 encrypted with 17. (17.0.0 with 18.0.0) + { 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, + // Master key 17 encrypted with 18. (18.0.0 with 19.0.0) + { 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, + // Master key 18 encrypted with 19. (19.0.0 with 20.0.0) + { 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, }; static bool _pkg2_key_unwrap_validate(pkg2_hdr_t *tmp_test, pkg2_hdr_t *hdr, u8 src_slot, u8 *mkey, const u8 *key_seed) { - // Decrypt older encrypted mkey. - se_aes_crypt_ecb(src_slot, 0, mkey, 0x10, key_seed, 0x10); + se_aes_crypt_ecb(src_slot, DECRYPT, mkey, SE_KEY_128_SIZE, key_seed, SE_KEY_128_SIZE); // Set and unwrap pkg2 key. - se_aes_key_clear(9); - se_aes_key_set(9, mkey, 0x10); + se_aes_key_set(9, mkey, SE_KEY_128_SIZE); se_aes_unwrap_key(9, 9, package2_keyseed); // Decrypt header. @@ -110,7 +138,7 @@ pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb) { pkg2_hdr_t mkey_test; u8 *pdata = (u8 *)data; - u8 keyslot = 8; + u8 pkg2_keyslot = 8; // Skip signature. pdata += 0x100; @@ -120,60 +148,55 @@ pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb) // Skip header. pdata += sizeof(pkg2_hdr_t); - //! Check if we need to decrypt with newer mkeys. Valid for sept for 8.1.0 and up. + // Check if we need to decrypt with newer mkeys. Valid for THK for 7.0.0 and up. se_aes_crypt_ctr(8, &mkey_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); if (mkey_test.magic == PKG2_MAGIC) goto key_found; - // Decrypt older pkg2 via new mkeys. - if ((kb >= KB_FIRMWARE_VERSION_810) && (kb < KB_FIRMWARE_VERSION_MAX)) + // Decrypt older pkg2 via new mkeys. + if ((kb >= HOS_KB_VERSION_700) && (kb < HOS_KB_VERSION_MAX)) { - u8 tmp_mkey[0x10]; - u8 decr_slot = 12; // Sept mkey. - u8 mkey_seeds_cnt = sizeof(mkey_keyseed_8xx) / 0x10; + u8 tmp_mkey[SE_KEY_128_SIZE]; + u8 decr_slot = 7; // THK mkey or T210B01 mkey. + u8 mkey_seeds_cnt = sizeof(mkey_vector_7xx) / SE_KEY_128_SIZE; u8 mkey_seeds_idx = mkey_seeds_cnt; // Real index + 1. - u8 mkey_seeds_min_idx = mkey_seeds_cnt - (KB_FIRMWARE_VERSION_MAX - kb); + u8 mkey_seeds_min_idx = mkey_seeds_cnt - (HOS_KB_VERSION_MAX - kb); while (mkey_seeds_cnt) { // Decrypt and validate mkey. int res = _pkg2_key_unwrap_validate(&mkey_test, hdr, decr_slot, - tmp_mkey, mkey_keyseed_8xx[mkey_seeds_idx - 1]); + tmp_mkey, mkey_vector_7xx[mkey_seeds_idx - 1]); if (res) { - keyslot = 9; + pkg2_keyslot = 9; goto key_found; } else { // Set current mkey in order to decrypt a lower mkey. mkey_seeds_idx--; - se_aes_key_clear(9); - se_aes_key_set(9, tmp_mkey, 0x10); - + se_aes_key_set(9, tmp_mkey, SE_KEY_128_SIZE); + decr_slot = 9; // Temp key. // Check if we tried last key for that pkg2 version. - // And start with a lower mkey in case sept is older. + // And start with a lower mkey in case mkey is older. if (mkey_seeds_idx == mkey_seeds_min_idx) { mkey_seeds_cnt--; mkey_seeds_idx = mkey_seeds_cnt; - decr_slot = 12; // Sept mkey. + decr_slot = 7; // THK mkey or T210B01 mkey. } - - // Out of keys. pkg2 is latest or process failed. - if (!mkey_seeds_cnt) - se_aes_key_clear(9); } } } key_found: // Decrypt header. - se_aes_crypt_ctr(keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + se_aes_crypt_ctr(pkg2_keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); //gfx_hexdump((u32)hdr, hdr, 0x100); if (hdr->magic != PKG2_MAGIC) @@ -185,14 +208,11 @@ DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]); if (!hdr->sec_size[i]) continue; - se_aes_crypt_ctr(keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]); + se_aes_crypt_ctr(pkg2_keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * SE_AES_IV_SIZE]); //gfx_hexdump((u32)pdata, pdata, 0x100); pdata += hdr->sec_size[i]; } - if (keyslot != 8) - se_aes_key_clear(9); - return hdr; } diff --git a/nyx/nyx_gui/hos/pkg2.h b/nyx/nyx_gui/hos/pkg2.h index db6c03c..df24639 100644 --- a/nyx/nyx_gui/hos/pkg2.h +++ b/nyx/nyx_gui/hos/pkg2.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,21 +18,23 @@ #ifndef _PKG2_H_ #define _PKG2_H_ -#include "../utils/types.h" -#include "../utils/list.h" +#include -#define PKG2_MAGIC 0x31324B50 -#define PKG2_SEC_BASE 0x80000000 +#define PKG2_MAGIC 0x31324B50 +#define PKG2_SEC_BASE 0x80000000 #define PKG2_SEC_KERNEL 0 -#define PKG2_SEC_INI1 1 +#define PKG2_SEC_INI1 1 +#define PKG2_SEC_UNUSED 2 #define INI1_MAGIC 0x31494E49 -#define PKG2_NEWKERN_GET_INI1 0x44 + +//! TODO: Update on kernel change if needed. +// Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16. +#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0. #define PKG2_NEWKERN_START 0x800 -u32 pkg2_newkern_ini1_val; -u32 pkg2_newkern_ini1_start; -u32 pkg2_newkern_ini1_end; +extern u32 pkg2_newkern_ini1_start; +extern u32 pkg2_newkern_ini1_end; typedef struct _pkg2_hdr_t { @@ -41,7 +43,8 @@ typedef struct _pkg2_hdr_t u32 magic; u32 base; u32 pad0; - u16 version; + u8 pkg2_ver; + u8 bl_ver; u16 pad1; u32 sec_size[4]; u32 sec_off[4]; @@ -90,8 +93,7 @@ typedef struct _pkg2_kip1_info_t } pkg2_kip1_info_t; void pkg2_get_newkern_info(u8 *kern_data); -u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1); -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); +u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1); pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb); diff --git a/nyx/nyx_gui/hos/sept.c b/nyx/nyx_gui/hos/sept.c deleted file mode 100644 index 907ea8f..0000000 --- a/nyx/nyx_gui/hos/sept.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 "sept.h" -#include "../config/config.h" -#include "../gfx/di.h" -#include "../ianos/ianos.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../soc/hw_init.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/types.h" -#include "../utils/util.h" - -#include "../gfx/gfx.h" - -#define RELOC_META_OFF 0x7C -#define PATCHED_RELOC_SZ 0x94 - -#define WB_RST_ADDR 0x40010ED0 -#define WB_RST_SIZE 0x30 - -u8 warmboot_reboot[] = { - 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 - 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 - 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0xFE, 0xFF, 0xFF, 0xEA, // LOOP - 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 - 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 -}; - -#define SEPT_PRI_ADDR 0x4003F000 - -#define SEPT_PK1T_ADDR 0xC0400000 -#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) -#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) -#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) -#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) - -extern volatile boot_cfg_t *b_cfg; -extern hekate_config h_cfg; -extern volatile nyx_storage_t *nyx_str; - -extern void *sd_file_read(char *path); -extern void sd_mount(); -extern void sd_unmount(bool deinit); -extern bool is_ipl_updated(void *buf); -extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); - -void check_sept() -{ - // Check if non-hekate payload is used for sept and restore it. - if (h_cfg.sept_run) - { - if (!f_stat("sept/payload.bak", NULL)) - { - f_unlink("sept/payload.bin"); - f_rename("sept/payload.bak", "sept/payload.bin"); - } - - return; - } - - u8 *pkg1 = (u8 *)calloc(1, 0x40000); - - sdmmc_storage_t storage; - sdmmc_t sdmmc; - if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - EPRINTF("Failed to init eMMC."); - goto out_free; - } - sdmmc_storage_set_mmc_partition(&storage, 1); - - // Read package1. - char *build_date = malloc(32); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1, build_date); - free(build_date); - if (!pkg1_id) - { - gfx_con.fntsz = 16; - EPRINTF("Unknown pkg1 version."); - goto out_free; - } - - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) - { - sdmmc_storage_end(&storage); - reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb); - } - -out_free: - free(pkg1); - sdmmc_storage_end(&storage); -} - -int reboot_to_sept(const u8 *tsec_fw, u32 kb) -{ - FIL fp; - - // Copy warmboot reboot code and TSEC fw. - u32 tsec_fw_size = 0x3000; - if (kb > KB_FIRMWARE_VERSION_700) - tsec_fw_size = 0x3300; - memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); - memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size); - *(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size; - - // Copy sept-primary. - if (f_open(&fp, "sept/sept-primary.bin", FA_READ)) - goto error; - - if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - // Copy sept-secondary. - if (kb < KB_FIRMWARE_VERSION_810) - { - if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ)) - if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. - goto error; - } - else - { - if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ)) - goto error; - } - - if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - b_cfg->boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN); - b_cfg->extra_cfg = EXTRA_CFG_NYX_DUMP; - - bool update_sept_payload = true; - if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE)) - { - ipl_ver_meta_t tmp_ver; - ipl_ver_meta_t heka_ver; - f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t)); - f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL); - memcpy(&heka_ver, (u8 *)nyx_str->hekate + 0x118, sizeof(ipl_ver_meta_t)); - - if (tmp_ver.magic == heka_ver.magic) - { - if (tmp_ver.version == heka_ver.version) - { - // Save auto boot config to sept payload, if any. - boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); - memcpy(tmp_cfg, (boot_cfg_t *)b_cfg, sizeof(boot_cfg_t)); - f_lseek(&fp, PATCHED_RELOC_SZ); - f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); - f_close(&fp); - update_sept_payload = false; - } - } - else - f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload. - - f_close(&fp); - } - - if (update_sept_payload) - { - volatile reloc_meta_t *reloc = (reloc_meta_t *)(nyx_str->hekate + RELOC_META_OFF); - f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS); - f_write(&fp, (u8 *)nyx_str->hekate, reloc->end - reloc->start, NULL); - f_close(&fp); - } - - sd_unmount(true); - - u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); - - void (*sept)() = (void *)pk1t_sept; - - reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); - - // Patch SDRAM init to perform an SVC immediately after second write. - PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; - PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; - // Set SVC handler to jump to sept-primary in IRAM. - PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; - PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - - reconfig_hw_workaround(false, 0); - - (*sept)(); - -error: - return 0; -} \ No newline at end of file diff --git a/nyx/nyx_gui/ianos/ianos.c b/nyx/nyx_gui/ianos/ianos.c deleted file mode 100644 index eec79b6..0000000 --- a/nyx/nyx_gui/ianos/ianos.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2018 M4xw - * Copyright (c) 2018-2019 CTCaer - * - * 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 "ianos.h" -#include "../utils/types.h" -#include "../libs/elfload/elfload.h" -#include "../../../common/common_module.h" -#include "../mem/heap.h" -#include "../gfx/gfx.h" - -#define IRAM_LIB_ADDR 0x4002B000 -#define DRAM_LIB_ADDR 0xE0000000 - -extern heap_t _heap; - -extern void *sd_file_read(const char *path, u32 *fsize); -extern bool sd_mount(); -extern void sd_unmount(bool deinit); - -void *elfBuf = NULL; -void *fileBuf = NULL; - -static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig) -{ - bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t)); - bdkParameters->gfxCon = &gfx_con; - bdkParameters->gfxCtx = &gfx_ctxt; - bdkParameters->memcpy = (memcpy_t)&memcpy; - bdkParameters->memset = (memset_t)&memset; - bdkParameters->sharedHeap = &_heap; - - entrypoint(moduleConfig, bdkParameters); -} - -static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size) -{ - (void)ctx; - (void)phys; - (void)size; - return (void *)virt; -} - -static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset) -{ - (void)ctx; - - memcpy(dest, fileBuf + offset, numberBytes); - - return true; -} - -//TODO: Support shared libraries. -uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig) -{ - uintptr_t epaddr = 0; - - if (sdmount) - { - if (!sd_mount()) - goto elfLoadFinalOut; - } - - fileBuf = sd_file_read(path, NULL); - - if (sdmount) - sd_unmount(true); - - if (!fileBuf) - goto elfLoadFinalOut; - - - el_ctx ctx; - ctx.pread = _ianos_read_cb; - - if (el_init(&ctx)) - goto elfLoadFinalOut; - - // Set our relocated library's buffer. - switch (type & 0xFFFF) - { - case EXEC_ELF: - case AR64_ELF: - elfBuf = (void *)DRAM_LIB_ADDR; - sd_unmount(true); - break; - default: - elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default. - } - - if (!elfBuf) - goto elfLoadFinalOut; - - // Load and relocate library. - ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf; - if (el_load(&ctx, _ianos_alloc_cb)) - goto elfFreeOut; - - if (el_relocate(&ctx)) - goto elfFreeOut; - - // Launch. - epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf; - moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr; - - _ianos_call_ep(ep, moduleConfig); - -elfFreeOut: - free(fileBuf); - elfBuf = NULL; - fileBuf = NULL; - -elfLoadFinalOut: - - return epaddr; -} \ No newline at end of file diff --git a/nyx/nyx_gui/input/als.c b/nyx/nyx_gui/input/als.c deleted file mode 100644 index ef9a4c8..0000000 --- a/nyx/nyx_gui/input/als.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Ambient light sensor driver for Nintendo Switch's Rohm BH1730 - * - * Copyright (c) 2018 CTCaer - * - * 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 "als.h" -#include "../power/max77620.h" -#include "../soc/clock.h" -#include "../soc/i2c.h" -#include "../soc/pinmux.h" -#include "../utils/util.h" - -#define HOS_GAIN BH1730_GAIN_64X -#define HOS_ITIME 38 - -void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime) -{ - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - itime)); - - als_val->gain = gain; - als_val->itime = itime; -} - -void get_als_lux(als_table_t *als_val) -{ - u32 data[2]; - float pre_gain_lux; - float visible_light; - float ir_light; - float light_ratio; - - u8 adc_ready = 0; - u8 retries = 100; - - const float als_gain_idx_tbl[4] = { 1.0, 2.0, 64.0, 128.0 }; - const float als_norm_res = 100.0; - const float als_multiplier = 3.6; - const float als_tint = 2.7; - - // Wait for ADC to prepare new data. - while (!(adc_ready & BH1730_CTL_ADC_VALID) && retries) - { - retries--; - adc_ready = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG)); - } - - // Get visible and ir light raw data. - data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) + - (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8); - data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) + - (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8); - - als_val->over_limit = data[0] > 65534 || data[1] > 65534; - als_val->vi_light = data[0]; - als_val->ir_light = data[1]; - - if (!data[0] || !retries) - { - als_val->lux = 0.0; - - return; - } - - visible_light = (float)data[0]; - ir_light = (float)data[1]; - light_ratio = (float)data[1] / (float)data[0]; - - // The following are specific to the light filter Switch uses. - if (light_ratio < 0.5) - pre_gain_lux = visible_light * 5.002 - ir_light * 7.502; - else if (light_ratio < 0.754) - pre_gain_lux = visible_light * 2.250 - ir_light * 2.000; - else if (light_ratio < 1.029) - pre_gain_lux = visible_light * 1.999 - ir_light * 1.667; - else if (light_ratio < 1.373) - pre_gain_lux = visible_light * 0.884 - ir_light * 0.583; - else if (light_ratio < 1.879) - pre_gain_lux = visible_light * 0.309 - ir_light * 0.165; - else pre_gain_lux = 0.0; - - als_val->lux = (pre_gain_lux / als_gain_idx_tbl[als_val->gain]) * (als_norm_res / ((float)als_val->itime * als_tint)) * als_multiplier; -} - -u8 als_init(als_table_t *als_val) -{ - pinmux_config_i2c(I2C_2); - clock_enable_i2c(I2C_2); - i2c_init(I2C_2); - - max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xD8 | MAX77620_LDO_CFG2_ADE_MASK); - - u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - HOS_ITIME)); - i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN); - - als_val->gain = HOS_GAIN; - als_val->itime = HOS_ITIME; - - return id; -} diff --git a/nyx/nyx_gui/input/touch.c b/nyx/nyx_gui/input/touch.c deleted file mode 100644 index 1adf071..0000000 --- a/nyx/nyx_gui/input/touch.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Touch driver for Nintendo Switch's STMicroelectronics FingerTip touch controller - * - * Copyright (c) 2018 langerhans - * Copyright (c) 2018 CTCaer - * - * 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 "../soc/clock.h" -#include "../soc/i2c.h" -#include "../soc/pinmux.h" -#include "../power/max7762x.h" -#include "../power/max77620.h" -#include "../soc/gpio.h" -#include "../soc/t210.h" -#include "../utils/util.h" -#include "touch.h" - - -#include "../gfx/gfx.h" -#define DPRINTF(...) gfx_printf(__VA_ARGS__) - -static int touch_command(u8 cmd) -{ - int err = i2c_send_byte(I2C_3, STMFTS_I2C_ADDR, cmd, 0); - if (!err) - return 1; - - // TODO: Check for completion in event loop - msleep(1); - return 0; -} - -#define X_REAL_MAX 1264 -#define Y_REAL_MAX 704 -#define EDGE_OFFSET 15 - -static void _touch_compensate_limits(touch_event *event, bool touching) -{ - event->x = MAX(event->x, EDGE_OFFSET); - event->x = MIN(event->x, X_REAL_MAX); - event->x -= EDGE_OFFSET; - u32 x_adj = (1280 * 1000) / (X_REAL_MAX - EDGE_OFFSET); - event->x = ((u32)event->x * x_adj) / 1000; - - if (touching) - { - event->y = MAX(event->y, EDGE_OFFSET); - event->y = MIN(event->y, Y_REAL_MAX); - event->y -= EDGE_OFFSET; - u32 y_adj = (720 * 1000) / (Y_REAL_MAX - EDGE_OFFSET); - event->y = ((u32)event->y * y_adj) / 1000; - } -} - -static void _touch_process_contact_event(touch_event *event, bool touching) -{ - event->x = (event->raw[2] << 4) | ((event->raw[4] & STMFTS_MASK_Y_LSB) >> 4); - - // Normally, GUI elements have bigger horizontal estate. - // Avoid parsing y axis when finger is removed to minimize touch noise. - if (touching) - { - event->y = (event->raw[3] << 4) | (event->raw[4] & STMFTS_MASK_X_MSB); - event->z = event->raw[5]; - event->fingers = ((event->raw[1] & STMFTS_MASK_TOUCH_ID) >> 4) + 1; - } - else - event->fingers = 0; - - _touch_compensate_limits(event, touching); -} - -static void _touch_parse_event(touch_event *event) -{ - event->type = event->raw[1] & STMFTS_MASK_EVENT_ID; - - switch (event->type) - { - case STMFTS_EV_MULTI_TOUCH_ENTER: - case STMFTS_EV_MULTI_TOUCH_MOTION: - _touch_process_contact_event(event, true); - if (event->z > 52) // Discard noisy hover touch. - event->touch = true; - else - { - event->touch = false; - event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; - } - break; - case STMFTS_EV_MULTI_TOUCH_LEAVE: - event->touch = false; - _touch_process_contact_event(event, false); - break; - case STMFTS_EV_NO_EVENT: - if (event->touch) - event->type = STMFTS_EV_MULTI_TOUCH_MOTION; - break; - default: - if (event->touch && event->raw[0] == STMFTS_EV_MULTI_TOUCH_MOTION) - event->type = STMFTS_EV_MULTI_TOUCH_MOTION; - else - event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; - } - - // gfx_con_setpos(&gfx_con, 0, 300); - // DPRINTF("x = %d \ny = %d \nz = %d \n", event->x, event->y, event->z); - // DPRINTF("0 = %02X\n1 = %02x\n2 = %02x\n3 = %02x\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]); - // DPRINTF("4 = %02X\n5 = %02x\n6 = %02x\n7 = %02x\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]); -} - -void touch_poll(touch_event *event) -{ - i2c_recv_buf_small(event->raw, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_LATEST_EVENT); - - _touch_parse_event(event); -} - -touch_event touch_poll_wait() -{ - touch_event event; - do - { - touch_poll(&event); - } while (event.type != STMFTS_EV_MULTI_TOUCH_LEAVE); - - return event; -} - -touch_info touch_get_info() -{ - touch_info info; - u8 buf[8]; - memset(&buf, 0, 8); - i2c_recv_buf_small(buf, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_INFO); - - info.chip_id = buf[0] << 8 | buf[1]; - info.fw_ver = buf[2] << 8 | buf[3]; - info.config_id = buf[4]; - info.config_ver = buf[5]; - - //DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02x, Cfg Ver: %d\n", - // info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver); - - return info; -} - -int touch_power_on() -{ - // Configure touchscreen GPIO. - PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1; - gpio_config(GPIO_PORT_J, GPIO_PIN_7, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_J, GPIO_PIN_7, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH); - - // IRQ and more. - // PINMUX_AUX(PINMUX_AUX_TOUCH_INT) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 3; - // gpio_config(GPIO_PORT_X, GPIO_PIN_1, GPIO_MODE_GPIO); - // gpio_write(GPIO_PORT_X, GPIO_PIN_1, GPIO_LOW); - - // Configure Touscreen and GCAsic shared GPIO. - PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2; - PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; - gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); - - // Initialize I2C3. - pinmux_config_i2c(I2C_3); - clock_enable_i2c(I2C_3); - i2c_init(I2C_3); - - // Enables LDO6 for touchscreen VDD/AVDD supply - max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, - MAX77620_LDO_CFG2_ADE_ENABLE | (3 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); - - msleep(20); - - // Initialize touchscreen module. - if (touch_command(STMFTS_SYSTEM_RESET)) - return 0; - - if (touch_command(STMFTS_SLEEP_OUT)) - return 0; - - if (touch_command(STMFTS_MS_CX_TUNING)) - return 0; - - if (touch_command(STMFTS_SS_CX_TUNING)) - return 0; - - if (touch_command(STMFTS_FULL_FORCE_CALIBRATION)) - return 0; - - if (touch_command(STMFTS_MS_MT_SENSE_ON)) - return 0; - - if (touch_command(STMFTS_SS_HOVER_SENSE_OFF)) - return 0; - - if (touch_command(STMFTS_MS_KEY_SENSE_OFF)) - return 0; - - return 1; -} - -void touch_power_off() -{ - touch_command(STMFTS_SLEEP_IN); - - // Disable touchscreen power. - gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW); - - // Disables LDO6 for touchscreen VDD, AVDD supply - max77620_regulator_enable(REGULATOR_LDO6, 0); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, - MAX77620_LDO_CFG2_ADE_ENABLE | (2 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); - - clock_disable_i2c(I2C_3); -} \ No newline at end of file diff --git a/nyx/nyx_gui/libs/compr/blz.c b/nyx/nyx_gui/libs/compr/blz.c deleted file mode 100644 index e0a0e7b..0000000 --- a/nyx/nyx_gui/libs/compr/blz.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2018 rajkosto - * Copyright (c) 2018 SciresM - * - * 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 - -#include "blz.h" - -const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter) -{ - if (compDataLen < sizeof(blz_footer)) - return NULL; - - const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)]; - if (outFooter != NULL) - memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4. - - return srcFooter; -} - -// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM! -int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) -{ - u32 addl_size = footer->addl_size; - u32 header_size = footer->header_size; - u32 cmp_and_hdr_size = footer->cmp_and_hdr_size; - - unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size; - u32 cmp_ofs = cmp_and_hdr_size - header_size; - u32 out_ofs = cmp_and_hdr_size + addl_size; - - while (out_ofs) - { - unsigned char control = cmp_start[--cmp_ofs]; - for (unsigned int i=0; i<8; i++) - { - if (control & 0x80) - { - if (cmp_ofs < 2) - return 0; // Out of bounds. - - cmp_ofs -= 2; - u16 seg_val = ((unsigned int)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs]; - u32 seg_size = ((seg_val >> 12) & 0xF) + 3; - u32 seg_ofs = (seg_val & 0x0FFF) + 3; - if (out_ofs < seg_size) // Kernel restricts segment copy to stay in bounds. - seg_size = out_ofs; - - out_ofs -= seg_size; - - for (unsigned int j = 0; j < seg_size; j++) - cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; - } - else - { - // Copy directly. - if (cmp_ofs < 1) - return 0; //out of bounds - - cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; - } - control <<= 1; - if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done. - return 1; - } - } - - return 1; -} - -int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize) -{ - blz_footer footer; - const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer); - if (compFooterPtr == NULL) - return 0; - - // Decompression must be done in-place, so need to copy the relevant compressed data first. - unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData; - memcpy(dstData, compData, numCompBytes); - memset(&dstData[numCompBytes], 0, dstSize - numCompBytes); - - return blz_uncompress_inplace(dstData, compDataLen, &footer); -} \ No newline at end of file diff --git a/nyx/nyx_gui/libs/compr/blz.h b/nyx/nyx_gui/libs/compr/blz.h deleted file mode 100644 index 3c17f8d..0000000 --- a/nyx/nyx_gui/libs/compr/blz.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018 rajkosto - * - * 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 _BLZ_H_ -#define _BLZ_H_ - -#include "../../utils/types.h" - -typedef struct _blz_footer -{ - u32 cmp_and_hdr_size; - u32 header_size; - u32 addl_size; -} blz_footer; - -// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL. -const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter); -// Returns 0 on failure. -int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer); -// Returns 0 on failure. -int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize); - -#endif \ No newline at end of file diff --git a/nyx/nyx_gui/libs/compr/lz.c b/nyx/nyx_gui/libs/compr/lz.c deleted file mode 100644 index a17c6e4..0000000 --- a/nyx/nyx_gui/libs/compr/lz.c +++ /dev/null @@ -1,179 +0,0 @@ -/************************************************************************* -* 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/nyx/nyx_gui/libs/compr/lz.h b/nyx/nyx_gui/libs/compr/lz.h deleted file mode 100644 index 6f31b4a..0000000 --- a/nyx/nyx_gui/libs/compr/lz.h +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************************************* -* 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/nyx/nyx_gui/libs/elfload/elfarch.h b/nyx/nyx_gui/libs/elfload/elfarch.h deleted file mode 100644 index f1cc388..0000000 --- a/nyx/nyx_gui/libs/elfload/elfarch.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2014, Owen Shepherd - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef ELFARCH_H -#define ELFARCH_H - -#if defined(__i386__) -#define EM_THIS EM_386 -#define EL_ARCH_USES_REL -#elif defined(__amd64__) -#define EM_THIS EM_AMD64 -#define EL_ARCH_USES_RELA -#elif defined(__arm__) -#define EM_THIS EM_ARM -#define EL_ARCH_USES_REL -#elif defined(__aarch64__) -#define EM_THIS EM_AARCH64 -#define EL_ARCH_USES_RELA -#define EL_ARCH_USES_REL -#else -#error specify your ELF architecture -#endif - -#if defined(__LP64__) || defined(__LLP64__) -#define ELFSIZE 64 -#else -#define ELFSIZE 32 -#endif - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define ELFDATATHIS ELFDATA2LSB -#else -#define ELFDATATHIS ELFDATA2MSB -#endif - -#endif diff --git a/nyx/nyx_gui/libs/elfload/elfload.c b/nyx/nyx_gui/libs/elfload/elfload.c deleted file mode 100644 index 16f8200..0000000 --- a/nyx/nyx_gui/libs/elfload/elfload.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright © 2018, M4xw - * Copyright © 2014, Owen Shepherd - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include "elfload.h" - -el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset) -{ - return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO; -} - -#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize)) -el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i) -{ - el_status rv = EL_OK; - for (; *i < ctx->ehdr.e_phnum; (*i)++) - { - if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i)))) - return rv; - - if (phdr->p_type == type) - { - return rv; - } - } - - *i = -1; - return rv; -} - -#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize)) -el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i) -{ - el_status rv = EL_OK; - - for (; *i < ctx->ehdr.e_shnum; (*i)++) - { - if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i)))) - - return rv; - - if (shdr->sh_type == type) - { - return rv; - } - } - - *i = -1; - - return rv; -} - -el_status el_init(el_ctx *ctx) -{ - el_status rv = EL_OK; - if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0))) - return rv; - - /* validate header */ - - if (!IS_ELF(ctx->ehdr)) - return EL_NOTELF; - - if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS) - return EL_WRONGBITS; - - if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS) - return EL_WRONGENDIAN; - - if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT) - return EL_NOTELF; - - if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN) - return EL_NOTEXEC; - - if (ctx->ehdr.e_machine != EM_THIS) - return EL_WRONGARCH; - - if (ctx->ehdr.e_version != EV_CURRENT) - return EL_NOTELF; - - /* load phdrs */ - Elf_Phdr ph; - - /* iterate through, calculate extents */ - ctx->base_load_paddr = ctx->base_load_vaddr = 0; - ctx->align = 1; - ctx->memsz = 0; - - unsigned i = 0; - for (;;) - { - if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) - return rv; - - if (i == (unsigned)-1) - break; - - Elf_Addr phend = ph.p_vaddr + ph.p_memsz; - if (phend > ctx->memsz) - ctx->memsz = phend; - - if (ph.p_align > ctx->align) - ctx->align = ph.p_align; - - i++; - } - - // Program Header - if (ctx->ehdr.e_type == ET_DYN) - { - i = 0; - - if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i))) - return rv; - - if (i == (unsigned)-1) - return EL_NODYN; - - ctx->dynoff = ph.p_offset; - ctx->dynsize = ph.p_filesz; - } - else - { - ctx->dynoff = 0; - ctx->dynsize = 0; - } - - // Section String Table - if (ctx->ehdr.e_type == ET_DYN) - { - i = ctx->ehdr.e_shstrndx - 1; - - if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i))) - return rv; - - // Reset - i = 0; - - if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i))) - return rv; - - if (i == (unsigned)-1) - return EL_NODYN; - } - - return rv; -} - -/* -typedef void* (*el_alloc_cb)( - el_ctx *ctx, - Elf_Addr phys, - Elf_Addr virt, - Elf_Addr size); -*/ - -el_status el_load(el_ctx *ctx, el_alloc_cb alloc) -{ - el_status rv = EL_OK; - - /* address deltas */ - Elf_Addr pdelta = ctx->base_load_paddr; - Elf_Addr vdelta = ctx->base_load_vaddr; - - /* iterate paddrs */ - Elf_Phdr ph; - unsigned i = 0; - for (;;) - { - if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) - return rv; - - if (i == (unsigned)-1) - break; - - Elf_Addr pload = ph.p_paddr + pdelta; - Elf_Addr vload = ph.p_vaddr + vdelta; - - /* allocate mem */ - char *dest = alloc(ctx, pload, vload, ph.p_memsz); - if (!dest) - return EL_ENOMEM; - - EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n", - ph.p_offset, ph.p_vaddr, dest); - - /* read loaded portion */ - if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset))) - return rv; - - /* zero mem-only portion */ - memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz); - - i++; - } - - return rv; -} - -el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag) -{ - el_status rv = EL_OK; - size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn); - - for (unsigned i = 0; i < ndyn; i++) - { - if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn))) - return rv; - - if (dyn->d_tag == tag) - return EL_OK; - } - - dyn->d_tag = DT_NULL; - return EL_OK; -} - -el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type) -{ - el_status rv = EL_OK; - - Elf_Dyn rel, relsz, relent; - - if ((rv = el_finddyn(ctx, &rel, type))) - return rv; - - if ((rv = el_finddyn(ctx, &relsz, type + 1))) - return rv; - - if ((rv = el_finddyn(ctx, &relent, type + 2))) - return rv; - - if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL) - { - ri->entrysize = 0; - ri->tablesize = 0; - ri->tableoff = 0; - } - else - { - ri->tableoff = rel.d_un.d_ptr; - ri->tablesize = relsz.d_un.d_val; - ri->entrysize = relent.d_un.d_val; - } - - return rv; -} - -extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel); -extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela); - -el_status el_relocate(el_ctx *ctx) -{ - el_status rv = EL_OK; - - // not dynamic - if (ctx->ehdr.e_type != ET_DYN) - return EL_OK; - - char *base = (char *)ctx->base_load_paddr; - - el_relocinfo ri; -#ifdef EL_ARCH_USES_REL - if ((rv = el_findrelocs(ctx, &ri, DT_REL))) - return rv; - - if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize) - { - EL_DEBUG("Relocation size %u doesn't match expected %u\n", - ri.entrysize, sizeof(Elf_Rel)); - return EL_BADREL; - } - - size_t relcnt = ri.tablesize / sizeof(Elf_Rel); - Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff); - for (size_t i = 0; i < relcnt; i++) - { - if ((rv = el_applyrel(ctx, &reltab[i]))) - return rv; - } -#endif - -#ifdef EL_ARCH_USES_RELA - if ((rv = el_findrelocs(ctx, &ri, DT_RELA))) - return rv; - - if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize) - { - EL_DEBUG("Relocation size %u doesn't match expected %u\n", - ri.entrysize, sizeof(Elf_RelA)); - return EL_BADREL; - } - - size_t relacnt = ri.tablesize / sizeof(Elf_RelA); - Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff); - for (size_t i = 0; i < relacnt; i++) - { - if ((rv = el_applyrela(ctx, &relatab[i]))) - return rv; - } -#endif - -#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA) -#error No relocation type defined! -#endif - - return rv; -} diff --git a/nyx/nyx_gui/libs/fatfs/diskio.c b/nyx/nyx_gui/libs/fatfs/diskio.c index cdeebf9..c877800 100644 --- a/nyx/nyx_gui/libs/fatfs/diskio.c +++ b/nyx/nyx_gui/libs/fatfs/diskio.c @@ -1,5 +1,7 @@ /*-----------------------------------------------------------------------*/ -/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ +/* Low level disk I/O module skeleton for FatFs */ +/* (C) ChaN, 2016 */ +/* (C) CTCaer, 2018-2020 */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ @@ -8,11 +10,14 @@ /*-----------------------------------------------------------------------*/ #include -#include "diskio.h" /* FatFs lower layer API */ -#include "../../../../common/memory_map.h" -#include "../../storage/sdmmc.h" -extern sdmmc_storage_t sd_storage; +#include + +#include /* FatFs lower layer API */ + +static u32 sd_rsvd_sectors = 0; +static u32 ramdisk_sectors = 0; +static u32 emummc_sectors = 0; /*-----------------------------------------------------------------------*/ /* Get Drive Status */ @@ -44,15 +49,19 @@ DRESULT disk_read ( UINT count /* Number of sectors to read */ ) { - // Ensure that buffer resides in DRAM and it's DMA aligned. - if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) - return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - if (sdmmc_storage_read(&sd_storage, sector, count, buf)) + switch (pdrv) { - memcpy(buff, buf, 512 * count); - return RES_OK; + case DRIVE_SD: + return sdmmc_storage_read(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + case DRIVE_RAM: + return ram_disk_read(sector, count, (void *)buff); + case DRIVE_EMMC: + return sdmmc_storage_read(&emmc_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + case DRIVE_BIS: + case DRIVE_EMU: + return nx_emmc_bis_read(sector, count, (void *)buff) ? RES_OK : RES_ERROR; } + return RES_ERROR; } @@ -66,13 +75,19 @@ DRESULT disk_write ( UINT count /* Number of sectors to write */ ) { - // Ensure that buffer resides in DRAM and it's DMA aligned. - if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) + switch (pdrv) + { + case DRIVE_SD: return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - memcpy(buf, buff, 512 * count); - if (sdmmc_storage_write(&sd_storage, sector, count, buf)) - return RES_OK; + case DRIVE_RAM: + return ram_disk_write(sector, count, (void *)buff); + case DRIVE_EMMC: + case DRIVE_BIS: + return RES_WRPRT; + case DRIVE_EMU: + return nx_emmc_bis_write(sector, count, (void *)buff) ? RES_OK : RES_ERROR; + } + return RES_ERROR; } @@ -85,5 +100,83 @@ DRESULT disk_ioctl ( void *buff /* Buffer to send/receive control data */ ) { + DWORD *buf = (DWORD *)buff; + + if (pdrv == DRIVE_SD) + { + switch (cmd) + { + case GET_SECTOR_COUNT: + *buf = sd_storage.sec_cnt - sd_rsvd_sectors; + break; + case GET_BLOCK_SIZE: + *buf = 32768; // Align to 16MB. + break; + } + } + else if (pdrv == DRIVE_RAM) + { + switch (cmd) + { + case GET_SECTOR_COUNT: + *buf = ramdisk_sectors; + break; + case GET_BLOCK_SIZE: + *buf = 2048; // Align to 1MB. + break; + } + } + else if (pdrv == DRIVE_EMU) + { + switch (cmd) + { + case GET_SECTOR_COUNT: + *buf = emummc_sectors; + break; + case GET_BLOCK_SIZE: + *buf = 32768; // Align to 16MB. + break; + } + } + else // Catch all for unknown devices. + { + switch (cmd) + { + case CTRL_SYNC: + break; + case GET_SECTOR_COUNT: + case GET_BLOCK_SIZE: + *buf = 0; // Zero value to force default or abort. + break; + } + } + + return RES_OK; +} + +DRESULT disk_set_info ( + BYTE pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + DWORD *buf = (DWORD *)buff; + + if (cmd == SET_SECTOR_COUNT) + { + switch (pdrv) + { + case DRIVE_SD: + sd_rsvd_sectors = *buf; + break; + case DRIVE_RAM: + ramdisk_sectors = *buf; + break; + case DRIVE_EMU: + emummc_sectors = *buf; + break; + } + } + return RES_OK; } diff --git a/nyx/nyx_gui/libs/fatfs/ffconf.h b/nyx/nyx_gui/libs/fatfs/ffconf.h index e54f7fd..d0c6f70 100644 --- a/nyx/nyx_gui/libs/fatfs/ffconf.h +++ b/nyx/nyx_gui/libs/fatfs/ffconf.h @@ -38,18 +38,29 @@ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ -#define FF_USE_MKFS 0 +#define FF_USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ -#define FF_FASTFS 1 - -#ifdef FF_FASTFS -#define FF_USE_FASTSEEK 1 -#else -#define FF_USE_FASTSEEK 0 +#if FF_USE_MKFS +#define FF_MKFS_LABEL "SWITCH SD " #endif +/* This sets FAT/FAT32 label. Exactly 11 characters, all caps. */ + + +#define FF_USE_FASTSEEK 0 /* This option switches fast seek function. (0:Disable or 1:Enable) */ +#define FF_FASTFS 1 +#if FF_FASTFS +#undef FF_USE_FASTSEEK +#define FF_USE_FASTSEEK 1 +#endif +/* This option switches fast access to chained clusters. (0:Disable or 1:Enable) */ + + +#define FF_SIMPLE_GPT 1 +/* This option switches support for the first GPT partition. (0:Disable or 1:Enable) */ + #define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ @@ -60,7 +71,7 @@ / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ -#define FF_USE_LABEL 0 +#define FF_USE_LABEL 1 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ @@ -155,7 +166,7 @@ */ -#define FF_FS_RPATH 0 +#define FF_FS_RPATH 1 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. @@ -168,12 +179,13 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 1 +#define FF_VOLUMES 5 /* Number of volumes (logical drives) to be used. (1-10) */ -#define FF_STR_VOLUME_ID 0 -#define FF_VOLUME_STRS "sd" +#define FF_STR_VOLUME_ID 1 +// Order is important. Any change to order, must also be reflected to diskio drive enum. +#define FF_VOLUME_STRS "sd","ram","emmc","bis","emu" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each @@ -183,6 +195,7 @@ / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +/ Order is important. Any change to order, must also be reflected to diskio drive enum. */ @@ -241,10 +254,10 @@ / Note that enabling exFAT discards ANSI C (C89) compatibility. */ -#define FF_FS_NORTC 1 +#define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2019 +#define FF_NORTC_YEAR 2024 /* The option FF_FS_NORTC switches timestamp function. 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. Every object modified by FatFs will have a fixed timestamp diff --git a/nyx/nyx_gui/libs/fatfs/ffunicode.c b/nyx/nyx_gui/libs/fatfs/ffunicode.c deleted file mode 100644 index 9f03963..0000000 --- a/nyx/nyx_gui/libs/fatfs/ffunicode.c +++ /dev/null @@ -1,625 +0,0 @@ -/*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13c */ -/*------------------------------------------------------------------------*/ -/* 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) 2018, 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 will be blanked at non-LFN configuration */ - -#if FF_DEFINED != 86604 /* 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 in BMP and valid code page? */ - 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 = 0, n, li, hi; - - - if (uni < 0x80) { /* ASCII? */ - c = (WCHAR)uni; - - } else { /* Non-ASCII */ - if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ - 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 = 0, n, li, hi; - - - if (oem < 0x80) { /* ASCII? */ - c = oem; - - } else { /* Extended char */ - if (cp == FF_CODE_PAGE) { /* Is it 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 conversion table */ - p = cp_table[i]; - if (p) { /* Is it valid code page ? */ - for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ - c = (c + 0x80) & 0xFF; - } - } else { /* DBCS */ - switch (cp) { /* Get conversion table */ - 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 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 */ -) -{ - const WORD *p; - WORD uc, bc, nc, cmd; - static const WORD cvt1[] = { /* Compressed up conversion table for 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 /* EOT */ - }; - static const WORD cvt2[] = { /* Compressed up conversion table for 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 /* EOT */ - }; - - - if (uni < 0x10000) { /* Is it in BMP? */ - uc = (WORD)uni; - p = uc < 0x1000 ? cvt1 : cvt2; - for (;;) { - bc = *p++; /* Get the block base */ - if (bc == 0 || uc < bc) break; /* Not matched? */ - 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 == 0) p += nc; /* Skip table if needed */ - } - uni = uc; - } - - return uni; -} - -#endif /* #if FF_USE_LFN */ diff --git a/nyx/nyx_gui/link.ld b/nyx/nyx_gui/link.ld index f0f01a0..9d8c015 100644 --- a/nyx/nyx_gui/link.ld +++ b/nyx/nyx_gui/link.ld @@ -5,7 +5,8 @@ SECTIONS { . = __ipl_start; .text : { *(.text._start); - *(._ipl_version); + KEEP(*(._ipl_version)); + *(.text._irq_setup); *(.text*); } .data : { diff --git a/nyx/nyx_gui/mem/heap.c b/nyx/nyx_gui/mem/heap.c deleted file mode 100644 index ca79c9d..0000000 --- a/nyx/nyx_gui/mem/heap.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 M4xw - * - * 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" -#include "../gfx/gfx.h" -#include "../../../common/common_heap.h" - -static void _heap_create(heap_t *heap, u32 start) -{ - heap->start = start; - heap->first = NULL; -} - -// Node info is before node address. -static u32 _heap_alloc(heap_t *heap, u32 size) -{ - hnode_t *node, *new_node; - - // Align to cache line size. - size = ALIGN(size, sizeof(hnode_t)); - - 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 (true) - { - // Check if there's available unused node. - if (!node->used && (size <= node->size)) - { - // Size and offset of the new unused node. - u32 new_size = node->size - size; - new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size); - - // If there's aligned unused space from the old node, - // create a new one and set the leftover size. - if (new_size >= (sizeof(hnode_t) << 2)) - { - new_node->size = new_size - sizeof(hnode_t); - new_node->used = 0; - new_node->next = node->next; - - // Check that we are not on first node. - if (new_node->next) - new_node->next->prev = new_node; - - new_node->prev = node; - node->next = new_node; - } - else // Unused node size is just enough. - size += new_size; - - node->size = size; - node->used = 1; - - return (u32)node + sizeof(hnode_t); - } - - // No unused node found, try the next one. - if (node->next) - node = node->next; - else - break; - } - - // No unused node found, create a new one. - new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); - new_node->used = 1; - new_node->size = size; - new_node->prev = node; - new_node->next = NULL; - node->next = new_node; - - return (u32)new_node + 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; - } -} - -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) -{ - if ((u32)buf >= _heap.start) - _heap_free(&_heap, (u32)buf); -} - -void heap_monitor(heap_monitor_t *mon, bool print_node_stats) -{ - u32 count = 0; - memset(mon, 0, sizeof(heap_monitor_t)); - - hnode_t *node = _heap.first; - while (true) - { - if (node->used) - mon->used += node->size + sizeof(hnode_t); - else - mon->total += node->size + sizeof(hnode_t); - - if (print_node_stats) - gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n", - count, node->used, (u32)node + sizeof(hnode_t), node->size); - - count++; - - if (node->next) - node = node->next; - else - break; - } - mon->total += mon->used; -} diff --git a/nyx/nyx_gui/mem/heap.h b/nyx/nyx_gui/mem/heap.h deleted file mode 100644 index 02d40be..0000000 --- a/nyx/nyx_gui/mem/heap.h +++ /dev/null @@ -1,29 +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 . - */ - -#ifndef _HEAP_H_ -#define _HEAP_H_ - -#include "../utils/types.h" -#include "../../../common/common_heap.h" - -void heap_init(u32 base); -void *malloc(u32 size); -void *calloc(u32 num, u32 size); -void free(void *buf); -void heap_monitor(heap_monitor_t *mon, bool print_node_stats); - -#endif diff --git a/nyx/nyx_gui/mem/mc.c b/nyx/nyx_gui/mem/mc.c deleted file mode 100644 index dd508e2..0000000 --- a/nyx/nyx_gui/mem/mc.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "../mem/mc.h" -#include "../soc/t210.h" -#include "../soc/clock.h" -#include "../utils/util.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool 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, false); - mc_config_tsec_carveout(0, 0, true); - - 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) = 0x3100000; - 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() -{ - // Enable ARC_CLK_OVR_ON. - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 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; - // Disable ARC_CLK_OVR_ON. - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF; -} - -void mc_enable() -{ - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; - // Enable EMC 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_CLR) = 0x2000001; //Clear EMC and MC reset. - usleep(5); - - //#ifdef CONFIG_ENABLE_AHB_REDIRECT - mc_disable_ahb_redirect(); - //mc_enable_ahb_redirect(); - //#endif -} diff --git a/nyx/nyx_gui/mem/mc.h b/nyx/nyx_gui/mem/mc.h deleted file mode 100644 index 6a28bde..0000000 --- a/nyx/nyx_gui/mem/mc.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _MC_H_ -#define _MC_H_ - -#include "../utils/types.h" -#include "../mem/mc_t210.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); -void mc_config_carveout(); -void mc_config_carveout_finalize(); -void mc_enable_ahb_redirect(); -void mc_disable_ahb_redirect(); -void mc_enable(); - -#endif diff --git a/nyx/nyx_gui/mem/mc_t210.h b/nyx/nyx_gui/mem/mc_t210.h deleted file mode 100644 index 602915f..0000000 --- a/nyx/nyx_gui/mem/mc_t210.h +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (c) 2014, NVIDIA Corporation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MC_T210_H_ -#define _MC_T210_H_ - -#define MC_INTSTATUS 0x0 -#define MC_INTMASK 0x4 -#define MC_ERR_STATUS 0x8 -#define MC_ERR_ADR 0xc -#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0 -#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4 -#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8 -#define MC_PCFIFO_CLIENT_CONFIG3 0xddc -#define MC_PCFIFO_CLIENT_CONFIG4 0xde0 -#define MC_EMEM_CFG 0x50 -#define MC_EMEM_ADR_CFG 0x54 -#define MC_EMEM_ADR_CFG_DEV0 0x58 -#define MC_EMEM_ADR_CFG_DEV1 0x5c -#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60 -#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64 -#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68 -#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c -#define MC_SECURITY_CFG0 0x70 -#define MC_SECURITY_CFG1 0x74 -#define MC_SECURITY_CFG3 0x9bc -#define MC_SECURITY_RSV 0x7c -#define MC_EMEM_ARB_CFG 0x90 -#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 -#define MC_EMEM_ARB_TIMING_RCD 0x98 -#define MC_EMEM_ARB_TIMING_RP 0x9c -#define MC_EMEM_ARB_TIMING_RC 0xa0 -#define MC_EMEM_ARB_TIMING_RAS 0xa4 -#define MC_EMEM_ARB_TIMING_FAW 0xa8 -#define MC_EMEM_ARB_TIMING_RRD 0xac -#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0 -#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4 -#define MC_EMEM_ARB_TIMING_R2R 0xb8 -#define MC_EMEM_ARB_TIMING_W2W 0xbc -#define MC_EMEM_ARB_TIMING_R2W 0xc0 -#define MC_EMEM_ARB_TIMING_W2R 0xc4 -#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0 -#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4 -#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0 -#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4 -#define MC_EMEM_ARB_DA_TURNS 0xd0 -#define MC_EMEM_ARB_DA_COVERS 0xd4 -#define MC_EMEM_ARB_MISC0 0xd8 -#define MC_EMEM_ARB_MISC1 0xdc -#define MC_EMEM_ARB_MISC2 0xc8 -#define MC_EMEM_ARB_RING1_THROTTLE 0xe0 -#define MC_EMEM_ARB_RING3_THROTTLE 0xe4 -#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0 -#define MC_EMEM_ARB_OVERRIDE 0xe8 -#define MC_EMEM_ARB_RSV 0xec -#define MC_CLKEN_OVERRIDE 0xf4 -#define MC_TIMING_CONTROL_DBG 0xf8 -#define MC_TIMING_CONTROL 0xfc -#define MC_STAT_CONTROL 0x100 -#define MC_STAT_STATUS 0x104 -#define MC_STAT_EMC_CLOCK_LIMIT 0x108 -#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c -#define MC_STAT_EMC_CLOCKS 0x110 -#define MC_STAT_EMC_CLOCKS_MSBS 0x114 -#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118 -#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158 -#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c -#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c -#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20 -#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24 -#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198 -#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8 -#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c -#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac -#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28 -#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c -#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0 -#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0 -#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120 -#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160 -#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128 -#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168 -#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c -#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c -#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130 -#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170 -#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134 -#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88 -#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174 -#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c -#define MC_STAT_EMC_SET0_COUNT 0x138 -#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c -#define MC_STAT_EMC_SET1_COUNT 0x178 -#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c -#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140 -#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144 -#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180 -#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184 -#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148 -#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c -#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188 -#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c -#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150 -#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190 -#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8 -#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc -#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8 -#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc -#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0 -#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0 -#define MC_CLIENT_HOTRESET_CTRL 0x200 -#define MC_CLIENT_HOTRESET_CTRL_1 0x970 -#define MC_CLIENT_HOTRESET_STATUS 0x204 -#define MC_CLIENT_HOTRESET_STATUS_1 0x974 -#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208 -#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c -#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210 -#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214 -#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94 -#define MC_EMEM_ARB_HYSTERESIS_0 0x218 -#define MC_EMEM_ARB_HYSTERESIS_1 0x21c -#define MC_EMEM_ARB_HYSTERESIS_2 0x220 -#define MC_EMEM_ARB_HYSTERESIS_3 0x224 -#define MC_EMEM_ARB_HYSTERESIS_4 0xb84 -#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0 -#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4 -#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8 -#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc -#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0 -#define MC_EMEM_ARB_DHYST_CTRL 0xbcc -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec -#define MC_RESERVED_RSV 0x3fc -#define MC_DISB_EXTRA_SNAP_LEVELS 0x408 -#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4 -#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0 -#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18 -#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08 -#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10 -#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c -#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40 -#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414 -#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc -#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c -#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14 -#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0 -#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac -#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c -#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48 -#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8 -#define MC_USBX_EXTRA_SNAP_LEVELS 0x404 -#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8 -#define MC_SD_EXTRA_SNAP_LEVELS 0xa04 -#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c -#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8 -#define MC_GK_EXTRA_SNAP_LEVELS 0xa00 -#define MC_VE2_EXTRA_SNAP_LEVELS 0x410 -#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44 -#define MC_VIDEO_PROTECT_BOM 0x648 -#define MC_VIDEO_PROTECT_SIZE_MB 0x64c -#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978 -#define MC_VIDEO_PROTECT_REG_CTRL 0x650 -#define MC_ERR_VPR_STATUS 0x654 -#define MC_ERR_VPR_ADR 0x658 -#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418 -#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590 -#define MC_IRAM_BOM 0x65c -#define MC_IRAM_TOM 0x660 -#define MC_IRAM_ADR_HI 0x980 -#define MC_IRAM_REG_CTRL 0x964 -#define MC_EMEM_CFG_ACCESS_CTRL 0x664 -#define MC_TZ_SECURITY_CTRL 0x668 -#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c -#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4 -#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc -#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8 -#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80 -#define MC_SEC_CARVEOUT_BOM 0x670 -#define MC_SEC_CARVEOUT_SIZE_MB 0x674 -#define MC_SEC_CARVEOUT_ADR_HI 0x9d4 -#define MC_SEC_CARVEOUT_REG_CTRL 0x678 -#define MC_ERR_SEC_STATUS 0x67c -#define MC_ERR_SEC_ADR 0x680 -#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684 -#define MC_STUTTER_CONTROL 0x688 -#define MC_RESERVED_RSV_1 0x958 -#define MC_DVFS_PIPE_SELECT 0x95c -#define MC_AHB_PTSA_MIN 0x4e0 -#define MC_AUD_PTSA_MIN 0x54c -#define MC_MLL_MPCORER_PTSA_RATE 0x44c -#define MC_RING2_PTSA_RATE 0x440 -#define MC_USBD_PTSA_RATE 0x530 -#define MC_USBX_PTSA_MIN 0x528 -#define MC_USBD_PTSA_MIN 0x534 -#define MC_APB_PTSA_MAX 0x4f0 -#define MC_JPG_PTSA_RATE 0x584 -#define MC_DIS_PTSA_MIN 0x420 -#define MC_AVP_PTSA_MAX 0x4fc -#define MC_AVP_PTSA_RATE 0x4f4 -#define MC_RING1_PTSA_MIN 0x480 -#define MC_DIS_PTSA_MAX 0x424 -#define MC_SD_PTSA_MAX 0x4d8 -#define MC_MSE_PTSA_RATE 0x4c4 -#define MC_VICPC_PTSA_MIN 0x558 -#define MC_PCX_PTSA_MAX 0x4b4 -#define MC_ISP_PTSA_RATE 0x4a0 -#define MC_A9AVPPC_PTSA_MIN 0x48c -#define MC_RING2_PTSA_MAX 0x448 -#define MC_AUD_PTSA_RATE 0x548 -#define MC_HOST_PTSA_MIN 0x51c -#define MC_MLL_MPCORER_PTSA_MAX 0x454 -#define MC_SD_PTSA_MIN 0x4d4 -#define MC_RING1_PTSA_RATE 0x47c -#define MC_JPG_PTSA_MIN 0x588 -#define MC_HDAPC_PTSA_MIN 0x62c -#define MC_AVP_PTSA_MIN 0x4f8 -#define MC_JPG_PTSA_MAX 0x58c -#define MC_VE_PTSA_MAX 0x43c -#define MC_DFD_PTSA_MAX 0x63c -#define MC_VICPC_PTSA_RATE 0x554 -#define MC_GK_PTSA_MAX 0x544 -#define MC_VICPC_PTSA_MAX 0x55c -#define MC_SDM_PTSA_MAX 0x624 -#define MC_SAX_PTSA_RATE 0x4b8 -#define MC_PCX_PTSA_MIN 0x4b0 -#define MC_APB_PTSA_MIN 0x4ec -#define MC_GK2_PTSA_MIN 0x614 -#define MC_PCX_PTSA_RATE 0x4ac -#define MC_RING1_PTSA_MAX 0x484 -#define MC_HDAPC_PTSA_RATE 0x628 -#define MC_MLL_MPCORER_PTSA_MIN 0x450 -#define MC_GK2_PTSA_MAX 0x618 -#define MC_AUD_PTSA_MAX 0x550 -#define MC_GK2_PTSA_RATE 0x610 -#define MC_ISP_PTSA_MAX 0x4a8 -#define MC_DISB_PTSA_RATE 0x428 -#define MC_VE2_PTSA_MAX 0x49c -#define MC_DFD_PTSA_MIN 0x638 -#define MC_FTOP_PTSA_RATE 0x50c -#define MC_A9AVPPC_PTSA_RATE 0x488 -#define MC_VE2_PTSA_MIN 0x498 -#define MC_USBX_PTSA_MAX 0x52c -#define MC_DIS_PTSA_RATE 0x41c -#define MC_USBD_PTSA_MAX 0x538 -#define MC_A9AVPPC_PTSA_MAX 0x490 -#define MC_USBX_PTSA_RATE 0x524 -#define MC_FTOP_PTSA_MAX 0x514 -#define MC_HDAPC_PTSA_MAX 0x630 -#define MC_SD_PTSA_RATE 0x4d0 -#define MC_DFD_PTSA_RATE 0x634 -#define MC_FTOP_PTSA_MIN 0x510 -#define MC_SDM_PTSA_RATE 0x61c -#define MC_AHB_PTSA_RATE 0x4dc -#define MC_SMMU_SMMU_PTSA_MAX 0x460 -#define MC_RING2_PTSA_MIN 0x444 -#define MC_SDM_PTSA_MIN 0x620 -#define MC_APB_PTSA_RATE 0x4e8 -#define MC_MSE_PTSA_MIN 0x4c8 -#define MC_HOST_PTSA_RATE 0x518 -#define MC_VE_PTSA_RATE 0x434 -#define MC_AHB_PTSA_MAX 0x4e4 -#define MC_SAX_PTSA_MIN 0x4bc -#define MC_SMMU_SMMU_PTSA_MIN 0x45c -#define MC_ISP_PTSA_MIN 0x4a4 -#define MC_HOST_PTSA_MAX 0x520 -#define MC_SAX_PTSA_MAX 0x4c0 -#define MC_VE_PTSA_MIN 0x438 -#define MC_GK_PTSA_MIN 0x540 -#define MC_MSE_PTSA_MAX 0x4cc -#define MC_DISB_PTSA_MAX 0x430 -#define MC_DISB_PTSA_MIN 0x42c -#define MC_SMMU_SMMU_PTSA_RATE 0x458 -#define MC_VE2_PTSA_RATE 0x494 -#define MC_GK_PTSA_RATE 0x53c -#define MC_PTSA_GRANT_DECREMENT 0x960 -#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4 -#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0 -#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380 -#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384 -#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc -#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8 -#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370 -#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0 -#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374 -#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8 -#define MC_LATENCY_ALLOWANCE_VIC_0 0x394 -#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8 -#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8 -#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc -#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390 -#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0 -#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694 -#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348 -#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c -#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344 -#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0 -#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0 -#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698 -#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec -#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc -#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0 -#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4 -#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8 -#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4 -#define MC_LATENCY_ALLOWANCE_HC_1 0x314 -#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0 -#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4 -#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c -#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec -#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320 -#define MC_LATENCY_ALLOWANCE_VI2_0 0x398 -#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c -#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4 -#define MC_LATENCY_ALLOWANCE_SATA_0 0x350 -#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690 -#define MC_LATENCY_ALLOWANCE_HC_0 0x310 -#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8 -#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac -#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4 -#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388 -#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328 -#define MC_LATENCY_ALLOWANCE_HDA_0 0x318 -#define MC_MIN_LENGTH_APE_0 0xb34 -#define MC_MIN_LENGTH_DCB_2 0x8a8 -#define MC_MIN_LENGTH_A9AVP_0 0x950 -#define MC_MIN_LENGTH_TSEC_0 0x93c -#define MC_MIN_LENGTH_DC_1 0x898 -#define MC_MIN_LENGTH_AXIAP_0 0x94c -#define MC_MIN_LENGTH_ISP2B_0 0x930 -#define MC_MIN_LENGTH_VI2_0 0x944 -#define MC_MIN_LENGTH_DCB_0 0x8a0 -#define MC_MIN_LENGTH_DCB_1 0x8a4 -#define MC_MIN_LENGTH_PPCS_1 0x8f4 -#define MC_MIN_LENGTH_NVJPG_0 0xb3c -#define MC_MIN_LENGTH_HDA_0 0x8c4 -#define MC_MIN_LENGTH_NVENC_0 0x8d4 -#define MC_MIN_LENGTH_SDMMC_0 0xb18 -#define MC_MIN_LENGTH_ISP2B_1 0x934 -#define MC_MIN_LENGTH_HC_1 0x8c0 -#define MC_MIN_LENGTH_DC_3 0xb20 -#define MC_MIN_LENGTH_AVPC_0 0x890 -#define MC_MIN_LENGTH_VIC_0 0x940 -#define MC_MIN_LENGTH_ISP2_0 0x91c -#define MC_MIN_LENGTH_HC_0 0x8bc -#define MC_MIN_LENGTH_SE_0 0xb38 -#define MC_MIN_LENGTH_NVDEC_0 0xb30 -#define MC_MIN_LENGTH_SATA_0 0x8fc -#define MC_MIN_LENGTH_DC_0 0x894 -#define MC_MIN_LENGTH_XUSB_1 0x92c -#define MC_MIN_LENGTH_DC_2 0x89c -#define MC_MIN_LENGTH_SDMMCAA_0 0xb14 -#define MC_MIN_LENGTH_GPU_0 0xb04 -#define MC_MIN_LENGTH_ETR_0 0xb44 -#define MC_MIN_LENGTH_AFI_0 0x88c -#define MC_MIN_LENGTH_PPCS_0 0x8f0 -#define MC_MIN_LENGTH_ISP2_1 0x920 -#define MC_MIN_LENGTH_XUSB_0 0x928 -#define MC_MIN_LENGTH_MPCORE_0 0x8cc -#define MC_MIN_LENGTH_TSECB_0 0xb48 -#define MC_MIN_LENGTH_SDMMCA_0 0xb10 -#define MC_MIN_LENGTH_GPU2_0 0xb40 -#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c -#define MC_MIN_LENGTH_PTC_0 0x8f8 -#define MC_EMEM_ARB_OVERRIDE_1 0x968 -#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984 -#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988 -#define MC_EMEM_ARB_STATS_0 0x990 -#define MC_EMEM_ARB_STATS_1 0x994 -#define MC_MTS_CARVEOUT_BOM 0x9a0 -#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4 -#define MC_MTS_CARVEOUT_ADR_HI 0x9a8 -#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac -#define MC_ERR_MTS_STATUS 0x9b0 -#define MC_ERR_MTS_ADR 0x9b4 -#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00 -#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04 -#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74 -#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8 -#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10 -#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04 -#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28 -#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30 -#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c -#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c -#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70 -#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c -#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c -#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4 -#define MC_SECURITY_CARVEOUT2_CFG0 0xc58 -#define MC_SECURITY_CARVEOUT1_CFG0 0xc08 -#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84 -#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68 -#define MC_SECURITY_CARVEOUT3_BOM 0xcac -#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70 -#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78 -#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c -#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18 -#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc -#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38 -#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34 -#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0 -#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60 -#define MC_SECURITY_CARVEOUT3_CFG0 0xca8 -#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8 -#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88 -#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64 -#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50 -#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14 -#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14 -#define MC_SECURITY_CARVEOUT1_BOM 0xc0c -#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c -#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68 -#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8 -#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58 -#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24 -#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4 -#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78 -#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c -#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18 -#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28 -#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c -#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0 -#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8 -#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60 -#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00 -#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64 -#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc -#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80 -#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54 -#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20 -#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4 -#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c -#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74 -#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc -#define MC_SECURITY_CARVEOUT4_BOM 0xcfc -#define MC_SECURITY_CARVEOUT5_CFG0 0xd48 -#define MC_SECURITY_CARVEOUT2_BOM 0xc5c -#define MC_SECURITY_CARVEOUT5_BOM 0xd4c -#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24 -#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c -#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0 -#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10 -#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20 -#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c -#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c -#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08 -#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 -#define MC_DA_CONFIG0 0x9dc - -#endif diff --git a/nyx/nyx_gui/mem/minerva.c b/nyx/nyx_gui/mem/minerva.c deleted file mode 100644 index 143c89e..0000000 --- a/nyx/nyx_gui/mem/minerva.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 - -#include "minerva.h" -#include "../soc/fuse.h" -#include "../utils/util.h" - -#include "../soc/clock.h" -#include "../ianos/ianos.h" -#include "../soc/fuse.h" -#include "../soc/t210.h" - -extern volatile nyx_storage_t *nyx_str; - -u32 minerva_init() -{ - u32 curr_ram_idx = 0; - - minerva_cfg = NULL; - mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - - // Set table to nyx storage. - mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; - - // Check if Minerva is already initialized. - if (mtc_cfg->init_done == MTC_INIT_MAGIC) - { - mtc_cfg->train_mode = OP_PERIODIC_TRAIN; // Retrain if needed. - u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); - minerva_cfg = (void *)ep_addr; - - return 0; - } - else - { - mtc_config_t mtc_tmp; - - mtc_tmp.mtc_table = mtc_cfg->mtc_table; - mtc_tmp.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; - mtc_tmp.init_done = MTC_NEW_MAGIC; - - u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_tmp); - - // Ensure that Minerva is new. - if (mtc_tmp.init_done == MTC_INIT_MAGIC) - minerva_cfg = (void *)ep_addr; - - // Copy Minerva context to Nyx storage. - if (minerva_cfg) - memcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t)); - } - - if (!minerva_cfg) - return 1; - - // Get current frequency - for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++) - { - if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc) - break; - } - - mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz; - mtc_cfg->rate_to = 204000; - mtc_cfg->train_mode = OP_TRAIN; - minerva_cfg(mtc_cfg, NULL); - mtc_cfg->rate_to = 800000; - minerva_cfg(mtc_cfg, NULL); - mtc_cfg->rate_to = 1600000; - minerva_cfg(mtc_cfg, NULL); - - // FSP WAR. - mtc_cfg->train_mode = OP_SWITCH; - mtc_cfg->rate_to = 800000; - minerva_cfg(mtc_cfg, NULL); - - // Switch to max. - mtc_cfg->rate_to = 1600000; - minerva_cfg(mtc_cfg, NULL); - - return 0; -} - -void minerva_change_freq(minerva_freq_t freq) -{ - if (!minerva_cfg) - return; - - mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - if (mtc_cfg->rate_from != freq) - { - mtc_cfg->rate_to = freq; - mtc_cfg->train_mode = OP_SWITCH; - minerva_cfg(mtc_cfg, NULL); - } -} - -void minerva_periodic_training() -{ - if (!minerva_cfg) - return; - - mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; - if (mtc_cfg->rate_from == FREQ_1600) - { - mtc_cfg->train_mode = OP_PERIODIC_TRAIN; - minerva_cfg(mtc_cfg, NULL); - } -} \ No newline at end of file diff --git a/nyx/nyx_gui/mem/minerva.h b/nyx/nyx_gui/mem/minerva.h deleted file mode 100644 index 00228f4..0000000 --- a/nyx/nyx_gui/mem/minerva.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 _FE_MINERVA_H_ -#define _FE_MINERVA_H_ - -#include "mtc_table.h" -#include "../utils/types.h" - -#define MTC_INIT_MAGIC 0x3043544D -#define MTC_NEW_MAGIC 0x5243544D - -#define EMC_PERIODIC_TRAIN_MS 250 - -typedef struct -{ - s32 rate_to; - s32 rate_from; - emc_table_t *mtc_table; - u32 table_entries; - emc_table_t *current_emc_table; - u32 train_mode; - u32 sdram_id; - u32 prev_temp; - bool emc_2X_clk_src_is_pllmb; - bool fsp_for_src_freq; - bool train_ram_patterns; - bool init_done; -} mtc_config_t; - -enum train_mode_t -{ - OP_SWITCH = 0, - OP_TRAIN = 1, - OP_TRAIN_SWITCH = 2, - OP_PERIODIC_TRAIN = 3, - OP_TEMP_COMP = 4 -}; - -typedef enum -{ - FREQ_204 = 204000, - FREQ_800 = 800000, - FREQ_1600 = 1600000 -} minerva_freq_t; - -void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); -u32 minerva_init(); -void minerva_change_freq(minerva_freq_t freq); -void minerva_periodic_training(); - -#endif diff --git a/nyx/nyx_gui/mem/sdram.c b/nyx/nyx_gui/mem/sdram.c deleted file mode 100644 index f0cd286..0000000 --- a/nyx/nyx_gui/mem/sdram.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 balika011 - * Copyright (c) 2019 CTCaer - * - * 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 "mc.h" -#include "emc.h" -#include "sdram_param_t210.h" -#include "../../../common/memory_map.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" -#include "../soc/clock.h" -#include "../soc/fuse.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -#define CONFIG_SDRAM_COMPRESS_CFG - -#ifdef CONFIG_SDRAM_COMPRESS_CFG -#include "../libs/compr/lz.h" -#include "sdram_config_lz.inl" -#else -#include "sdram_config.inl" -#endif - -static u32 _get_sdram_id() -{ - return (fuse_read_odm(4) & 0x38) >> 3; -} - -static void _sdram_config(const sdram_params_t *params) -{ - // Program DPD3/DPD4 regs (coldboot path). - // Enable sel_dpd on unused pins. - u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000; - PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; - usleep(params->pmc_io_dpd3_req_wait); - - // Disable e_dpd_vttgen. - dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000; - PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; - usleep(params->pmc_io_dpd4_req_wait); - - // Disable e_dpd_bg. - PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; - usleep(params->pmc_io_dpd4_req_wait); - - PMC(APBDEV_PMC_WEAK_BIAS) = 0; - usleep(1); - - // Start clocks. - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; - - // u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); - // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp; - // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000; - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); - - u32 wait_end = get_tmr_us() + 300; - while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000)) - { - if (get_tmr_us() >= wait_end) - goto break_nosleep; - } - usleep(10); - -break_nosleep: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF); - if (params->emc_clock_source_dll) - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; - if (params->clear_clock2_mc1) - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets. - - // Set pad macros. - 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; // Trigger timing update so above writes take place. - usleep(10); // Ensure the regulators settle. - - // Select EMC write mux. - EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; - - // Patch 2 using BCT spare variables. - if (params->emc_bct_spare2) - *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; - - // Program CMD mapping. Required before brick mapping, else - // we can't guarantee CK will be differential at all times. - 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; - - // Program brick mapping. - 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; - - // This is required to do any reads from the pad macros. - EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; - - EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; - - // Set swizzle for Rank 0. - 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; - // Set swizzle for Rank 1. - 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; - - // Patch 4 using BCT spare variables. - if (params->emc_bct_spare6) - *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; - - // Set pad controls. - 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; - - // Program Autocal controls with shadowed register fields. - 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; - - // Common pad macro (cpm). - EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; - - // Patch 3 using BCT spare variables. - if (params->emc_bct_spare4) - *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; - - EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. - - // Initialize MC VPR settings. - 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; - - // Program SDRAM geometry parameters. - 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; - - // Program bank swizzling. - 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; - - // Program external memory aperture (base and size). - MC(MC_EMEM_CFG) = params->mc_emem_cfg; - - // Program SEC carveout (base and size). - 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; - - // Program MTS carveout (base and size). - 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; - - // Program the memory arbiter. - 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; // Trigger MC timing update. - - // Program second-level clock enable overrides. - MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; - - // Program statistics gathering. - MC(MC_STAT_CONTROL) = params->mc_stat_control; - - // Program SDRAM geometry parameters. - EMC(EMC_ADR_CFG) = params->emc_adr_cfg; - - // Program second-level clock enable overrides. - EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; - - // Program EMC pad auto calibration. - 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; - usleep(params->emc_auto_cal_wait); - - // Patch 5 using BCT spare variables. - if (params->emc_bct_spare8) - *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; - - // Program EMC timing configuration. - 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) = 1; - 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; - - // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. - 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; - - // Set pipe bypass enable bits before sending any DRAM commands. - EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; - - // Patch BootROM. - if (params->boot_rom_patch_control & (1 << 31)) - { - *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; - MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. - } - - // Release SEL_DPD_CMD. - PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; - usleep(params->pmc_io_dpd3_req_wait); - - // Set autocal interval if not configured. - 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; - - // ZQ CAL setup (not actually issuing ZQ CAL now). - if (params->emc_zcal_warm_cold_boot_enables & 1) - { - if (params->memory_type == 2) - EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; - 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; // Trigger timing update so above writes take place. - usleep(params->emc_timing_control_wait); - - // Deassert HOLD_CKE_LOW. - PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F; - usleep(params->pmc_ddr_ctrl_wait); - - // Set clock enable signal. - u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); - if (params->memory_type == 2 || params->memory_type == 3) - { - EMC(EMC_PIN) = pin_gpio_cfg; - (void)EMC(EMC_PIN); - usleep(params->emc_pin_extra_wait + 200); - EMC(EMC_PIN) = pin_gpio_cfg | 0x100; - (void)EMC(EMC_PIN); - } - - if (params->memory_type == 3) - usleep(params->emc_pin_extra_wait + 2000); - else if (params->memory_type == 2) - usleep(params->emc_pin_extra_wait + 500); - - // Enable clock enable signal. - EMC(EMC_PIN) = pin_gpio_cfg | 0x101; - (void)EMC(EMC_PIN); - usleep(params->emc_pin_program_wait); - - // Send NOP (trigger just needs to be non-zero). - if (params->memory_type != 3) - EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; - - // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. - if (params->memory_type == 1) - usleep(params->emc_pin_extra_wait + 200); - - // Init zq calibration, - if (params->memory_type == 3) - { - // Patch 6 using BCT spare variables. - if (params->emc_bct_spare10) - *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; - - // Write mode registers. - 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) - { - // Issue ZQCAL start, device 0. - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; - usleep(params->emc_zcal_init_wait); - - // Issue ZQCAL latch. - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; - // Same for device 1. - if (!(params->emc_dev_select & 2)) - { - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; - usleep(params->emc_zcal_init_wait); - EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; - } - } - } - - // Set package and DPD pad control. - PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; - - // Start periodic ZQ calibration (LPDDRx only). - 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; - } - - // Patch 7 using BCT spare variables. - if (params->emc_bct_spare12) - *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; - - EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. - - if (params->emc_extra_refresh_num) - EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; - - // Enable refresh. - 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; - - // Write addr swizzle lock bit. - EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; - - EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions. - - // Enable EMC pipe clock gating. - EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; - - // Depending on freqency, enable CMD/CLK fdpd. - EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; - - // Enable arbiter. - SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); - - // Lock carveouts per BCT cfg. - 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; - - //Disable write access to a bunch of EMC registers. - MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; -} - -sdram_params_t *sdram_get_params() -{ -#ifdef CONFIG_SDRAM_COMPRESS_CFG - u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; - LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); - return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()]; -#else - return _dram_cfgs[_get_sdram_id()]; -#endif -} - -/* - * Function: sdram_get_params_patched - * - * This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again. - * If the boot_rom_patch_control's MSB is set, it uses it as an index to - * APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data. - * (The MSB falls out when it gets multiplied by sizeof(u32)). - * Because the bootrom does not do any boundary checks, it lets us write anywhere and anything. - * Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time. - * The first patch is not needed any more when the exploit is triggered, so we overwrite that. - * 0x10459E is the address where it returns an error when the signature is not valid. - * We change that to MOV R0, #0, so we pass the check. - * - * Note: The modulus in the header must match and validated. - */ - -sdram_params_t *sdram_get_params_patched() -{ - #define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff)) - sdram_params_t *sdram_params = sdram_get_params(); - - // Disable Warmboot signature check. - sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); - sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); -/* - // Disable SBK lock. - sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4); - sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000); - - // Disable bootrom read lock. - sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4); - sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000); - sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); - sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); -*/ - return sdram_params; -} - -void sdram_init() -{ - const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); - - // Set DRAM voltage. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); - - // VDDP Select. - PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; - usleep(params->pmc_vddp_sel_wait); - - // Set DDR pad voltage. - PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); - - // Turn on MEM IO Power. - 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; - - // Patch 1 using BCT spare variables - if (params->emc_bct_spare0) - *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; - - _sdram_config(params); -} diff --git a/nyx/nyx_gui/mem/sdram.h b/nyx/nyx_gui/mem/sdram.h deleted file mode 100644 index badc703..0000000 --- a/nyx/nyx_gui/mem/sdram.h +++ /dev/null @@ -1,27 +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 . - */ - -#ifndef _SDRAM_H_ -#define _SDRAM_H_ - -#include "sdram_param_t210.h" - -void sdram_init(); -sdram_params_t *sdram_get_params(); -sdram_params_t *sdram_get_params_patched(); -void sdram_lp0_save_params(const void *params); - -#endif diff --git a/nyx/nyx_gui/mem/sdram_config.inl b/nyx/nyx_gui/mem/sdram_config.inl deleted file mode 100644 index d23f4da..0000000 --- a/nyx/nyx_gui/mem/sdram_config.inl +++ /dev/null @@ -1,1152 +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 . - */ - -static const u8 _dram_cfg_0[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, 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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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, 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_1[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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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_2[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, 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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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, 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_3[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, 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, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 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_4[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, 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, - 0x14, 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, 0x04, 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, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 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, 0x14, 0x00, 0x14, 0x00, - 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, - 0x14, 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, 0x1B, 0x00, 0x00, 0x00, 0x1B, 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, 0x0C, 0x00, - 0x02, 0x03, 0x0C, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x18, 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, 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_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_5, - (const u32 *)_dram_cfg_6 -}; diff --git a/nyx/nyx_gui/mem/sdram_config_lz.inl b/nyx/nyx_gui/mem/sdram_config_lz.inl deleted file mode 100644 index 832b5b4..0000000 --- a/nyx/nyx_gui/mem/sdram_config_lz.inl +++ /dev/null @@ -1,124 +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 . - */ - -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/nyx/nyx_gui/mem/sdram_lp0.c b/nyx/nyx_gui/mem/sdram_lp0.c deleted file mode 100644 index 869e85a..0000000 --- a/nyx/nyx_gui/mem/sdram_lp0.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * Copyright 2014 Google Inc. - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../soc/t210.h" -#include "../soc/pmc_lp0_t210.h" -#include "sdram_lp0_param_t210.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) -{ - struct sdram_params *sdram = (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 - - //TODO: pkg1.1 (1.X - 3.X) reads them from MC. - // Patch carveout parameters. - /*sdram->McGeneralizedCarveout1Bom = 0; - sdram->McGeneralizedCarveout1BomHi = 0; - sdram->McGeneralizedCarveout1Size128kb = 0; - sdram->McGeneralizedCarveout1Access0 = 0; - sdram->McGeneralizedCarveout1Access1 = 0; - sdram->McGeneralizedCarveout1Access2 = 0; - sdram->McGeneralizedCarveout1Access3 = 0; - sdram->McGeneralizedCarveout1Access4 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout1ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout1Cfg0 = 0; - sdram->McGeneralizedCarveout2Bom = 0x80020000; - sdram->McGeneralizedCarveout2BomHi = 0; - sdram->McGeneralizedCarveout2Size128kb = 2; - sdram->McGeneralizedCarveout2Access0 = 0; - sdram->McGeneralizedCarveout2Access1 = 0; - sdram->McGeneralizedCarveout2Access2 = 0x3000000; - sdram->McGeneralizedCarveout2Access3 = 0; - sdram->McGeneralizedCarveout2Access4 = 0x300; - sdram->McGeneralizedCarveout2ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout2ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout2Cfg0 = 0x440167E; - sdram->McGeneralizedCarveout3Bom = 0; - sdram->McGeneralizedCarveout3BomHi = 0; - sdram->McGeneralizedCarveout3Size128kb = 0; - sdram->McGeneralizedCarveout3Access0 = 0; - sdram->McGeneralizedCarveout3Access1 = 0; - sdram->McGeneralizedCarveout3Access2 = 0x3000000; - sdram->McGeneralizedCarveout3Access3 = 0; - sdram->McGeneralizedCarveout3Access4 = 0x300; - sdram->McGeneralizedCarveout3ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout3ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout3Cfg0 = 0x4401E7E; - sdram->McGeneralizedCarveout4Bom = 0; - sdram->McGeneralizedCarveout4BomHi = 0; - sdram->McGeneralizedCarveout4Size128kb = 0; - sdram->McGeneralizedCarveout4Access0 = 0; - sdram->McGeneralizedCarveout4Access1 = 0; - sdram->McGeneralizedCarveout4Access2 = 0; - sdram->McGeneralizedCarveout4Access3 = 0; - sdram->McGeneralizedCarveout4Access4 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout4ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout4Cfg0 = 0x8F; - sdram->McGeneralizedCarveout5Bom = 0; - sdram->McGeneralizedCarveout5BomHi = 0; - sdram->McGeneralizedCarveout5Size128kb = 0; - sdram->McGeneralizedCarveout5Access0 = 0; - sdram->McGeneralizedCarveout5Access1 = 0; - sdram->McGeneralizedCarveout5Access2 = 0; - sdram->McGeneralizedCarveout5Access3 = 0; - sdram->McGeneralizedCarveout5Access4 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess0 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess1 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess2 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess3 = 0; - sdram->McGeneralizedCarveout5ForceInternalAccess4 = 0; - sdram->McGeneralizedCarveout5Cfg0 = 0x8F;*/ - - //TODO: this is 4.X+ behaviour which seems to work fine for < 4.X. - // Patch carveout parameters. - sdram->McGeneralizedCarveout1Cfg0 = 0; - sdram->McGeneralizedCarveout2Cfg0 = 0; - sdram->McGeneralizedCarveout3Cfg0 = 0; - sdram->McGeneralizedCarveout4Cfg0 = 0; - sdram->McGeneralizedCarveout5Cfg0 = 0; - - // Patch SDRAM parameters. - u32 t0 = sdram->EmcSwizzleRank0Byte0 << 5 >> 29 > sdram->EmcSwizzleRank0Byte0 << 1 >> 29; - u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->EmcSwizzleRank1Byte0 << 5 >> 29 > sdram->EmcSwizzleRank1Byte0 << 1 >> 29) << 4); - u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->EmcSwizzleRank0Byte1 << 5 >> 29 > sdram->EmcSwizzleRank0Byte1 << 1 >> 29) << 1); - u32 t3 = (t2 & 0xFFFFFFDF) | ((sdram->EmcSwizzleRank1Byte1 << 5 >> 29 > sdram->EmcSwizzleRank1Byte1 << 1 >> 29) << 5); - u32 t4 = (t3 & 0xFFFFFFFB) | ((sdram->EmcSwizzleRank0Byte2 << 5 >> 29 > sdram->EmcSwizzleRank0Byte2 << 1 >> 29) << 2); - u32 t5 = (t4 & 0xFFFFFFBF) | ((sdram->EmcSwizzleRank1Byte2 << 5 >> 29 > sdram->EmcSwizzleRank1Byte2 << 1 >> 29) << 6); - u32 t6 = (t5 & 0xFFFFFFF7) | ((sdram->EmcSwizzleRank0Byte3 << 5 >> 29 > sdram->EmcSwizzleRank0Byte3 << 1 >> 29) << 3); - u32 t7 = (t6 & 0xFFFFFF7F) | ((sdram->EmcSwizzleRank1Byte3 << 5 >> 29 > sdram->EmcSwizzleRank1Byte3 << 1 >> 29) << 7); - sdram->SwizzleRankByteEncode = t7; - sdram->EmcBctSpare2 = 0x40000DD8; - sdram->EmcBctSpare3 = t7; - - 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(EmcBctSpare3, 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); - - 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/nyx/nyx_gui/mem/sdram_lp0_param_t210.h b/nyx/nyx_gui/mem/sdram_lp0_param_t210.h deleted file mode 100644 index 9028990..0000000 --- a/nyx/nyx_gui/mem/sdram_lp0_param_t210.h +++ /dev/null @@ -1,964 +0,0 @@ -/* - * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. - * Copyright 2014 Google Inc. - * Copyright (c) 2018 CTCaer - * - * 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 "../utils/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/nyx/nyx_gui/nyx.c b/nyx/nyx_gui/nyx.c index 4812228..05275a2 100644 --- a/nyx/nyx_gui/nyx.c +++ b/nyx/nyx_gui/nyx.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2023 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,52 +19,23 @@ #include #include -#include "../../common/memory_map.h" +#include -#include "config/config.h" -#include "gfx/di.h" -#include "gfx/gfx.h" +#include "config.h" #include "hos/hos.h" -#include "ianos/ianos.h" -#include "libs/compr/blz.h" -#include "libs/fatfs/ff.h" -#include "mem/heap.h" -#include "mem/minerva.h" -#include "mem/sdram.h" -#include "power/max77620.h" -#include "soc/bpmp.h" -#include "soc/fuse.h" -#include "soc/gpio.h" -#include "soc/hw_init.h" -#include "soc/i2c.h" -#include "soc/pmc.h" -#include "soc/t210.h" -#include "soc/uart.h" -#include "storage/sdmmc.h" -#include "utils/btn.h" -#include "utils/dirlist.h" -#include "utils/list.h" -#include "utils/util.h" +#include +#include +#include #include "frontend/fe_emmc_tools.h" #include "frontend/gui.h" -//TODO: ugly. -sdmmc_t sd_sdmmc; -sdmmc_storage_t sd_storage; -FATFS sd_fs; -static bool sd_mounted = false; -static bool sd_init_done = false; - -#ifdef MENU_LOGO_ENABLE -u8 *Kc_MENU_LOGO; -#endif //MENU_LOGO_ENABLE - +nyx_config n_cfg; hekate_config h_cfg; const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = { .magic = NYX_MAGIC, - .version = (NYX_VER_MJ + '0') | ((NYX_VER_MN + '0') << 8) | ((NYX_VER_HF + '0') << 16), + .version = (NYX_VER_MJ + '0') | ((NYX_VER_MN + '0') << 8) | ((NYX_VER_HF + '0') << 16) | ((NYX_VER_RL) << 24), .rsvd0 = 0, .rsvd1 = 0 }; @@ -72,142 +43,52 @@ const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; volatile boot_cfg_t *b_cfg; -bool get_sd_card_removed() +char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage) { - if (sd_init_done && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) - return true; + static char emmc_sn[9] = {0}; - return false; -} - -bool sd_mount() -{ - if (sd_mounted) - return true; - - int res = 0; - - if (!sd_init_done) - { - res = !sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11); - if (!res) - sd_init_done = true; - } - - if (res) - { - EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); - } - else - { - int res = f_mount(&sd_fs, "", 1); - if (res == FR_OK) - { - sd_mounted = true; - return true; - } - else - { - EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); - } - } - - return false; -} - -void sd_unmount(bool deinit) -{ - if (sd_init_done && sd_mounted) - { - f_mount(NULL, "", 1); - sd_mounted = false; - } - if (sd_init_done && deinit) - { - sdmmc_storage_end(&sd_storage); - sd_init_done = false; - } -} - -void *sd_file_read(const char *path, u32 *fsize) -{ - FIL fp; - if (f_open(&fp, path, FA_READ) != FR_OK) - return NULL; - - u32 size = f_size(&fp); - if (fsize) - *fsize = size; - - void *buf = malloc(size); - - if (f_read(&fp, buf, size, NULL) != FR_OK) - { - free(buf); - f_close(&fp); - - return NULL; - } - - f_close(&fp); - - return buf; -} - -int sd_save_to_file(void *buf, u32 size, const char *filename) -{ - FIL fp; - u32 res = 0; - res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE); - if (res) - { - EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); - return res; - } - - f_write(&fp, buf, size, NULL); - f_close(&fp); - - return 0; -} - -void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage) -{ - sdmmc_storage_t storage2; - sdmmc_t sdmmc; - char emmcSN[9]; - bool init_done = false; - - memcpy(path, "backup", 7); - f_mkdir(path); + // Check if eMMC S/N storage has valid data and skip parsing in that case. + if (emmc_sn[0] && strcmp(emmc_sn, "00000000")) + goto create_dir; + // Get actual eMMC S/N. if (!storage) { - if (!sdmmc_storage_init_mmc(&storage2, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - memcpy(emmcSN, "00000000", 9); + if (!emmc_initialize(false)) + strcpy(emmc_sn, "00000000"); else { - init_done = true; - itoa(storage2.cid.serial, emmcSN, 16); + itoa(emmc_storage.cid.serial, emmc_sn, 16); + emmc_end(); } } else - itoa(storage->cid.serial, emmcSN, 16); + itoa(storage->cid.serial, emmc_sn, 16); - u32 sub_dir_len = strlen(sub_dir); // Can be a null-terminator. - u32 filename_len = strlen(filename); // Can be a null-terminator. +create_dir: + // Check if only eMMC S/N was requested. + if (!path) + return emmc_sn; - memcpy(path + strlen(path), "/", 2); - memcpy(path + strlen(path), emmcSN, 9); + // Create main folder. + strcpy(path, "backup"); f_mkdir(path); - memcpy(path + strlen(path), sub_dir, sub_dir_len + 1); - if (sub_dir_len) - f_mkdir(path); - memcpy(path + strlen(path), "/", 2); - memcpy(path + strlen(path), filename, filename_len + 1); - if (init_done) - sdmmc_storage_end(&storage2); + // Create eMMC S/N folder. + strcat(path, "/"); + strcat(path, emmc_sn); + f_mkdir(path); + + // Create sub folder if defined. Dir slash must be included. + strcat(path, sub_dir); // Can be a null-terminator. + if (strlen(sub_dir)) + f_mkdir(path); + + // Add filename. + strcat(path, "/"); + strcat(path, filename); // Can be a null-terminator. + + return emmc_sn; } // This is a safe and unused DRAM region for our payloads. @@ -217,13 +98,15 @@ void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t #define PATCHED_RELOC_ENTRY 0x40010000 #define EXT_PAYLOAD_ADDR 0xC0000000 #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -#define COREBOOT_ADDR (0xD0000000 - 0x100000) -#define CBFS_DRAM_EN_ADDR 0x4003e000 +#define COREBOOT_END_ADDR 0xD0000000 +#define CBFS_DRAM_EN_ADDR 0x4003E000 #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" +static void *coreboot_addr; + void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { - memcpy((u8 *)payload_src, (u8 *)NYX_LOAD_ADDR, PATCHED_RELOC_SZ); + memcpy((u8 *)payload_src, (u8 *)nyx_str->hekate, PATCHED_RELOC_SZ); volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); @@ -234,7 +117,7 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) if (payload_size == 0x7000) { - memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); // Bootblock. *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; } } @@ -251,184 +134,398 @@ lv_res_t launch_payload(lv_obj_t *list) strcpy(path,"bootloader/payloads/"); strcat(path, filename); - if (sd_mount()) + if (!sd_mount()) + goto out; + + FIL fp; + if (f_open(&fp, path, FA_READ)) { - FIL fp; - if (f_open(&fp, path, FA_READ)) - { - EPRINTFARGS("Payload file is missing!\n(%s)", path); - sd_unmount(false); + EPRINTFARGS("Payload file is missing!\n(%s)", path); - goto out; - } - - // Read and copy the payload to our chosen address - void *buf; - u32 size = f_size(&fp); - - if (size < 0x30000) - buf = (void *)RCM_PAYLOAD_ADDR; - else - buf = (void *)COREBOOT_ADDR; - - if (f_read(&fp, buf, size, NULL)) - { - f_close(&fp); - sd_unmount(false); - - goto out; - } - - f_close(&fp); - - sd_unmount(true); - - if (size < 0x30000) - { - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); - reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); - } - else - { - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); - reconfig_hw_workaround(true, 0); - } - - void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; - - // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. - sdmmc_storage_init_wait_sd(); - - // Launch our payload. - (*ext_payload_ptr)(); + goto out; } + // Read and copy the payload to our chosen address + void *buf; + u32 size = f_size(&fp); + + if (size < 0x30000) + buf = (void *)RCM_PAYLOAD_ADDR; + else + { + coreboot_addr = (void *)(COREBOOT_END_ADDR - size); + buf = coreboot_addr; + if (h_cfg.t210b01) + { + f_close(&fp); + + EPRINTF("Coreboot not allowed on Mariko!"); + + goto out; + } + } + + if (f_read(&fp, buf, size, NULL)) + { + f_close(&fp); + + goto out; + } + + f_close(&fp); + + sd_end(); + + if (size < 0x30000) + { + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); + hw_deinit(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); + } + else + { + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); + hw_deinit(true, 0); + } + + void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; + + // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. + sdmmc_storage_init_wait_sd(); + + // Launch our payload. + (*ext_payload_ptr)(); + out: + sd_unmount(); + return LV_RES_OK; } -void load_saved_configuration() +static void _load_saved_configuration() { LIST_INIT(ini_sections); + LIST_INIT(ini_nyx_sections); - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) { - // Load configuration. - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Skip other ini entries. - if (ini_sec->type == INI_CHOICE) - { - if (!strcmp(ini_sec->name, "config")) - { - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - if (!strcmp("autoboot", kv->key)) - h_cfg.autoboot = atoi(kv->val); - else if (!strcmp("autoboot_list", kv->key)) - h_cfg.autoboot_list = atoi(kv->val); - else if (!strcmp("bootwait", kv->key)) - h_cfg.bootwait = atoi(kv->val); - else if (!strcmp("verification", kv->key)) - h_cfg.verification = atoi(kv->val); - else if (!strcmp("backlight", kv->key)) - { - h_cfg.backlight = atoi(kv->val); - if (h_cfg.backlight <= 20) - h_cfg.backlight = 30; - } - else if (!strcmp("autohosoff", kv->key)) - h_cfg.autohosoff = atoi(kv->val); - else if (!strcmp("autonogc", kv->key)) - h_cfg.autonogc = atoi(kv->val); - else if (!strcmp("updater2p", kv->key)) - h_cfg.updater2p = atoi(kv->val); - else if (!strcmp("brand", kv->key)) - { - h_cfg.brand = malloc(strlen(kv->val) + 1); - strcpy(h_cfg.brand, kv->val); - } - else if (!strcmp("tagline", kv->key)) - { - h_cfg.tagline = malloc(strlen(kv->val) + 1); - strcpy(h_cfg.tagline, kv->val); - } - } + create_config_entry(); + goto skip_main_cfg_parse; + } - continue; + // Load hekate configuration. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Only parse config section. + if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config")) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("autoboot", kv->key)) + h_cfg.autoboot = atoi(kv->val); + else if (!strcmp("autoboot_list", kv->key)) + h_cfg.autoboot_list = atoi(kv->val); + else if (!strcmp("bootwait", kv->key)) + h_cfg.bootwait = atoi(kv->val); + else if (!strcmp("backlight", kv->key)) + { + h_cfg.backlight = atoi(kv->val); + if (h_cfg.backlight <= 20) + h_cfg.backlight = 30; } + else if (!strcmp("noticker", kv->key)) + h_cfg.noticker = atoi(kv->val); + else if (!strcmp("autohosoff", kv->key)) + h_cfg.autohosoff = atoi(kv->val); + else if (!strcmp("autonogc", kv->key)) + h_cfg.autonogc = atoi(kv->val); + else if (!strcmp("updater2p", kv->key)) + h_cfg.updater2p = atoi(kv->val); + else if (!strcmp("bootprotect", kv->key)) + h_cfg.bootprotect = atoi(kv->val); } + + break; } } + + ini_free(&ini_sections); + +skip_main_cfg_parse: + if (!ini_parse(&ini_nyx_sections, "bootloader/nyx.ini", false)) + return; + + // Load Nyx configuration. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_nyx_sections, link) + { + // Only parse config section. + if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config")) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("themebg", kv->key)) + n_cfg.theme_bg = strtol(kv->val, NULL, 16); + else if (!strcmp("themecolor", kv->key)) + n_cfg.theme_color = atoi(kv->val); + else if (!strcmp("entries5col", kv->key)) + n_cfg.entries_5_col = atoi(kv->val) == 1; + else if (!strcmp("timeoff", kv->key)) + { + n_cfg.timeoff = strtol(kv->val, NULL, 16); + if (n_cfg.timeoff != 1) + max77620_rtc_set_epoch_offset((int)n_cfg.timeoff); + } + else if (!strcmp("homescreen", kv->key)) + n_cfg.home_screen = atoi(kv->val); + else if (!strcmp("verification", kv->key)) + n_cfg.verification = atoi(kv->val); + else if (!strcmp("umsemmcrw", kv->key)) + n_cfg.ums_emmc_rw = atoi(kv->val) == 1; + else if (!strcmp("jcdisable", kv->key)) + n_cfg.jc_disable = atoi(kv->val) == 1; + else if (!strcmp("jcforceright", kv->key)) + n_cfg.jc_force_right = atoi(kv->val) == 1; + else if (!strcmp("bpmpclock", kv->key)) + n_cfg.bpmp_clock = atoi(kv->val); + } + + break; + } + } + + ini_free(&ini_nyx_sections); +} + +static int nyx_load_resources() +{ + FIL fp; + int res; + + res = f_open(&fp, "bootloader/sys/res.pak", FA_READ); + if (res) + return res; + + res = f_read(&fp, (void *)NYX_RES_ADDR, f_size(&fp), NULL); + f_close(&fp); + + return res; +} + +static void nyx_load_bg_icons() +{ + // If no custom switch icon exists, load normal. + if (!f_stat("bootloader/res/icon_switch_custom.bmp", NULL)) + icon_switch = bmp_to_lvimg_obj("bootloader/res/icon_switch_custom.bmp"); + else + icon_switch = bmp_to_lvimg_obj("bootloader/res/icon_switch.bmp"); + + // If no custom payload icon exists, load normal. + if (!f_stat("bootloader/res/icon_payload_custom.bmp", NULL)) + icon_payload = bmp_to_lvimg_obj("bootloader/res/icon_payload_custom.bmp"); + else + icon_payload = bmp_to_lvimg_obj("bootloader/res/icon_payload.bmp"); + + // Load background resource if any. + hekate_bg = bmp_to_lvimg_obj("bootloader/res/background.bmp"); +} + +#define EXCP_EN_ADDR 0x4003FFFC +#define EXCP_MAGIC 0x30505645 // EVP0 +#define EXCP_TYPE_ADDR 0x4003FFF8 +#define EXCP_TYPE_RESET 0x545352 // RST +#define EXCP_TYPE_UNDEF 0x464455 // UDF +#define EXCP_TYPE_PABRT 0x54424150 // PABT +#define EXCP_TYPE_DABRT 0x54424144 // DABT +#define EXCP_LR_ADDR 0x4003FFF4 + +enum { + SD_NO_ERROR = 0, + SD_MOUNT_ERROR = 1, + SD_FILE_ERROR = 2 +}; + +static void _show_errors(int sd_error) +{ + u32 *excp_enabled = (u32 *)EXCP_EN_ADDR; + u32 *excp_type = (u32 *)EXCP_TYPE_ADDR; + u32 *excp_lr = (u32 *)EXCP_LR_ADDR; + + if (*excp_enabled == EXCP_MAGIC || sd_error) + { + gfx_clear_grey(0); + gfx_con_setpos(0, 0, 0); + display_backlight_brightness(150, 1000); + display_init_window_d_console(); + display_window_d_console_enable(); + } + + switch (sd_error) + { + case SD_MOUNT_ERROR: + WPRINTF("Failed to init or mount SD!\n"); + goto error_occured; + case SD_FILE_ERROR: + WPRINTF("Failed to load GUI resources!\nres.pak not found or corrupted.\n"); + goto error_occured; + case SD_NO_ERROR: + default: + break; + } + + if (*excp_enabled == EXCP_MAGIC) + { + WPRINTFARGS("Nyx exception occurred (LR %08X):\n", *excp_lr); + switch (*excp_type) + { + case EXCP_TYPE_RESET: + WPRINTF("RESET"); + break; + case EXCP_TYPE_UNDEF: + WPRINTF("UNDEF"); + break; + case EXCP_TYPE_PABRT: + WPRINTF("PABRT"); + break; + case EXCP_TYPE_DABRT: + WPRINTF("DABRT"); + break; + } + gfx_puts("\n"); + + // Clear the exception. + *excp_lr = 0; + *excp_type = 0; + *excp_enabled = 0; + +error_occured: + WPRINTF("Press any key to reload Nyx..."); + + msleep(1000); + btn_wait(); + + reload_nyx(NULL, true); + } } void nyx_init_load_res() { bpmp_mmu_enable(); - bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + bpmp_clk_rate_get(); + + // Set a modest clock for init. It will be restored later if possible. + bpmp_clk_rate_set(BPMP_CLK_LOWER_BOOST); // Set bootloader's default configuration. set_default_configuration(); + set_nyx_default_configuration(); - gfx_init_ctxt((u32 *)NYX_FB_ADDRESS, 720, 1280, 720); + // Reset new info if magic not correct. + if (nyx_str->info.magic != NYX_NEW_INFO) + { + nyx_str->info.sd_init = 0; + for (u32 i = 0; i < 3; i++) + nyx_str->info.sd_errors[i] = 0; + } + + // Clear info magic. + nyx_str->info.magic = 0; + + // Set display id from previous initialization. + display_set_decoded_panel_id(nyx_str->info.disp_id); + + // Initialize gfx console. + gfx_init_ctxt((u32 *)LOG_FB_ADDRESS, 1280, 656, 656); gfx_con_init(); - sd_mount(); + // Show exception errors if any. + _show_errors(SD_NO_ERROR); + + // Try 2 times to mount SD card. + if (!sd_mount()) + { + // Restore speed to SDR104. + sd_end(); + + // Retry. + if (!sd_mount()) + _show_errors(SD_MOUNT_ERROR); // Fatal. + } // Train DRAM and switch to max frequency. minerva_init(); - load_saved_configuration(); + // Load hekate/Nyx configuration. + _load_saved_configuration(); - FIL fp; - f_open(&fp, "bootloader/sys/res.pak", FA_READ); - f_read(&fp, (void *)NYX_RES_ADDR, f_size(&fp), NULL); - f_close(&fp); + // Load Nyx resources. + if (nyx_load_resources()) + { + // Try again. + if (nyx_load_resources()) + _show_errors(SD_FILE_ERROR); // Fatal since resources are mandatory. + } - icon_switch = bmp_to_lvimg_obj("bootloader/res/icon_switch.bmp"); - icon_payload = bmp_to_lvimg_obj("bootloader/res/icon_payload.bmp"); - icon_lakka = bmp_to_lvimg_obj("bootloader/res/icon_lakka.bmp"); - hekate_bg = bmp_to_lvimg_obj("bootloader/res/background.bmp"); + // Initialize nyx cfg to lower clock on first boot. + // In case of lower binned SoC, this can help with hangs. + if (!n_cfg.bpmp_clock) + { + // Set lower clock and save it. + n_cfg.bpmp_clock = 2; + create_nyx_config_entry(false); - sd_unmount(false); + // Start at max clock and test it. + n_cfg.bpmp_clock = 0; + } - h_cfg.rcm_patched = fuse_check_patched_rcm(); + // Set selected clock. + switch (n_cfg.bpmp_clock) + { + case 0: + case 1: + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + break; + case 2: + bpmp_clk_rate_set(BPMP_CLK_LOWER_BOOST); + break; + case 3: + default: + bpmp_clk_rate_set(BPMP_CLK_LOWEST_BOOST); + break; + } + + // Load default launch icons and background if it exists. + nyx_load_bg_icons(); + + // Unmount FAT partition. + sd_unmount(); } -extern void pivot_stack(u32 stack_top); - -#if (LV_LOG_PRINTF == 1) - #include "soc/clock.h" - #include "soc/gpio.h" - #include "soc/pinmux.h" -#endif - void ipl_main() { - //Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. - heap_init(IPL_HEAP_START); - - + // Set heap address. + heap_init((void *)IPL_HEAP_START); b_cfg = (boot_cfg_t *)(nyx_str->hekate + 0x94); - // Important: Preserve version header! - __asm__ ("" : : "" (ipl_ver)); +#ifdef DEBUG_UART_PORT + // Enable the selected uart debug port. + #if (DEBUG_UART_PORT == UART_B) + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + #elif (DEBUG_UART_PORT == UART_C) + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + #endif + pinmux_config_uart(DEBUG_UART_PORT); + clock_enable_uart(DEBUG_UART_PORT); + uart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX); + uart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD); -#if (LV_LOG_PRINTF == 1) - gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); - pinmux_config_uart(UART_B); - clock_enable_uart(UART_B); - uart_init(UART_B, 115200); - - uart_send(UART_B, (u8 *)"Hekate-NYX: Hello!\r\n", 20); - uart_wait_idle(UART_B, UART_TX_IDLE); + uart_send(DEBUG_UART_PORT, (u8 *)"hekate-NYX: Hello!\r\n", 20); + uart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE); #endif - // Initialize the rest of hw and load nyx's resources. + // Initialize the rest of hw and load Nyx resources. nyx_init_load_res(); + // Initialize Nyx GUI and show it. nyx_load_and_run(); // Halt BPMP if we managed to get out of execution. diff --git a/nyx/nyx_gui/power/bq24193.c b/nyx/nyx_gui/power/bq24193.c deleted file mode 100644 index 6aa5dcb..0000000 --- a/nyx/nyx_gui/power/bq24193.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Battery charger driver for Nintendo Switch's TI BQ24193 - * - * Copyright (c) 2018 CTCaer - * - * 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 "bq24193.h" -#include "../soc/i2c.h" -#include "../utils/util.h" - -int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) -{ - u8 data; - - switch (prop) { - case BQ24193_InputVoltageLimit: // Input voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource); - data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; - *value += ((data >> 0) & 1) ? 80 : 0; - *value += ((data >> 1) & 1) ? 160 : 0; - *value += ((data >> 2) & 1) ? 320 : 0; - *value += ((data >> 3) & 1) ? 640 : 0; - *value += 3880; - break; - case BQ24193_InputCurrentLimit: // Input current limit (mA). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource); - data &= BQ24193_INCONFIG_INLIMIT_MASK; - switch (data) - { - case 0: - *value = 100; - break; - case 1: - *value = 150; - break; - case 2: - *value = 500; - break; - case 3: - *value = 900; - break; - case 4: - *value = 1200; - break; - case 5: - *value = 1500; - break; - case 6: - *value = 2000; - break; - case 7: - *value = 3000; - break; - } - break; - case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig); - *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; - *value *= 100; - *value += 3000; - break; - case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr); - data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2; - *value += ((data >> 0) & 1) ? 64 : 0; - *value += ((data >> 1) & 1) ? 128 : 0; - *value += ((data >> 2) & 1) ? 256 : 0; - *value += ((data >> 3) & 1) ? 512 : 0; - *value += ((data >> 4) & 1) ? 1024 : 0; - *value += ((data >> 5) & 1) ? 2048 : 0; - *value += 512; - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr); - data &= BQ24193_CHRGCURR_20PCT_MASK; - if (data) - *value = *value * 20 / 100; // Fast charge current limit is 20%. - break; - case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt); - data = (data & BQ24193_CHRGVOLT_VREG) >> 2; - *value += ((data >> 0) & 1) ? 16 : 0; - *value += ((data >> 1) & 1) ? 32 : 0; - *value += ((data >> 2) & 1) ? 64 : 0; - *value += ((data >> 3) & 1) ? 128 : 0; - *value += ((data >> 4) & 1) ? 256 : 0; - *value += ((data >> 5) & 1) ? 512 : 0; - *value += 3504; - break; - case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt); - data &= BQ24193_IRTHERMAL_THERM_MASK; - if (data) - *value = 300; - else - *value = 100; - break; - case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_IRCompThermal); - data &= BQ24193_IRTHERMAL_THERM_MASK; - switch (data) - { - case 0: - *value = 60; - break; - case 1: - *value = 80; - break; - case 2: - *value = 100; - break; - case 3: - *value = 120; - break; - } - break; - case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Status); - *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; - break; - case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_FaultReg); - *value = data & BQ24193_FAULT_THERM_MASK; - break; - case BQ24193_DevID: // Dev ID. - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart); - *value = data & BQ24193_VENDORPART_DEV_MASK; - break; - case BQ24193_ProductNumber: // Product number. - data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart); - *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; - break; - default: - return -1; - } - return 0; -} - -void bq24193_fake_battery_removal() -{ - u8 value; - - // Disable watchdog to keep BATFET disabled. - value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer); - value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK; - i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value); - - // Force BATFET to disabled state. This disconnects the battery from the system. - value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc); - value |= BQ24193_MISC_BATFET_DI_MASK; - i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value); -} diff --git a/nyx/nyx_gui/power/bq24193.h b/nyx/nyx_gui/power/bq24193.h deleted file mode 100644 index 34e9fbf..0000000 --- a/nyx/nyx_gui/power/bq24193.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Battery charger driver for Nintendo Switch's TI BQ24193 - * - * Copyright (c) 2018 CTCaer - * - * 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 __BQ24193_H_ -#define __BQ24193_H_ - -#define BQ24193_I2C_ADDR 0x6B - -// REG 0 masks. -#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0) -#define BQ24193_INCONFIG_VINDPM_MASK 0x78 -#define BQ24193_INCONFIG_HIZ_EN_MASK (1<<7) - -// REG 1 masks. -#define BQ24193_PORCONFIG_BOOST_MASK (1<<0) -#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1) -#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4) -#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6) -#define BQ24193_PORCONFIG_RESET_MASK (1<<7) - -// REG 2 masks. -#define BQ24193_CHRGCURR_20PCT_MASK (1<<0) -#define BQ24193_CHRGCURR_ICHG_MASK 0xFC - -// REG 3 masks. -#define BQ24193_PRECHRG_ITERM 0x0F -#define BQ24193_PRECHRG_IPRECHG 0xF0 - -// REG 4 masks. -#define BQ24193_CHRGVOLT_VTHRES (1<<0) -#define BQ24193_CHRGVOLT_BATTLOW (1<<1) -#define BQ24193_CHRGVOLT_VREG 0xFC - -// REG 5 masks. -#define BQ24193_CHRGTERM_ISET_MASK (1<<0) -#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1) -#define BQ24193_CHRGTERM_ENTIMER_MASK (1<<3) -#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4) -#define BQ24193_CHRGTERM_TERM_ST_MASK (1<<6) -#define BQ24193_CHRGTERM_TERM_EN_MASK (1<<7) - -// REG 6 masks. -#define BQ24193_IRTHERMAL_THERM_MASK (3<<0) -#define BQ24193_IRTHERMAL_VCLAMP_MASK (7<<2) -#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5) - -// REG 7 masks. -#define BQ24193_MISC_INT_MASK (3<<0) -#define BQ24193_MISC_VSET_MASK (1<<4) -#define BQ24193_MISC_BATFET_DI_MASK (1<<5) -#define BQ24193_MISC_TMR2X_EN_MASK (1<<6) -#define BQ24193_MISC_DPDM_EN_MASK (1<<7) - -// REG 8 masks. -#define BQ24193_STATUS_VSYS_MASK (1<<0) -#define BQ24193_STATUS_THERM_MASK (1<<1) -#define BQ24193_STATUS_PG_MASK (1<<2) -#define BQ24193_STATUS_DPM_MASK (1<<3) -#define BQ24193_STATUS_CHRG_MASK (3<<4) -#define BQ24193_STATUS_VBUS_MASK (3<<6) - -// REG 9 masks. -#define BQ24193_FAULT_THERM_MASK (7<<0) -#define BQ24193_FAULT_BATT_OVP_MASK (1<<3) -#define BQ24193_FAULT_CHARGE_MASK (3<<4) -#define BQ24193_FAULT_BOOST_MASK (1<<6) -#define BQ24193_FAULT_WATCHDOG_MASK (1<<7) - -// REG A masks. -#define BQ24193_VENDORPART_DEV_MASK (3<<0) -#define BQ24193_VENDORPART_PN_MASK (7<<3) - -enum BQ24193_reg { - BQ24193_InputSource = 0x00, - BQ24193_PORConfig = 0x01, - BQ24193_ChrgCurr = 0x02, - BQ24193_PreChrgTerm = 0x03, - BQ24193_ChrgVolt = 0x04, - BQ24193_ChrgTermTimer = 0x05, - BQ24193_IRCompThermal = 0x06, - BQ24193_Misc = 0x07, - BQ24193_Status = 0x08, - BQ24193_FaultReg = 0x09, - BQ24193_VendorPart = 0x0A, -}; - -enum BQ24193_reg_prop { - BQ24193_InputVoltageLimit, // REG 0. - BQ24193_InputCurrentLimit, // REG 0. - BQ24193_SystemMinimumVoltage, // REG 1. - BQ24193_FastChargeCurrentLimit, // REG 2. - BQ24193_ChargeVoltageLimit, // REG 4. - BQ24193_RechargeThreshold, // REG 4. - BQ24193_ThermalRegulation, // REG 6. - BQ24193_ChargeStatus, // REG 8. - BQ24193_TempStatus, // REG 9. - BQ24193_DevID, // REG A. - BQ24193_ProductNumber, // REG A. -}; - -int bq24193_get_property(enum BQ24193_reg_prop prop, int *value); -void bq24193_fake_battery_removal(); - -#endif /* __BQ24193_H_ */ diff --git a/nyx/nyx_gui/power/max17050.c b/nyx/nyx_gui/power/max17050.c deleted file mode 100644 index b3a8b21..0000000 --- a/nyx/nyx_gui/power/max17050.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Fuel gauge driver for Nintendo Switch's Maxim 17050 - * - * Copyright (c) 2011 Samsung Electronics - * MyungJoo Ham - * Copyright (c) 2018 CTCaer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This driver is based on max17040_battery.c - */ - -#include "max17050.h" -#include "../soc/i2c.h" -#include "../utils/util.h" - -/* Status register bits */ -#define STATUS_POR_BIT (1 << 1) -#define STATUS_BST_BIT (1 << 3) -#define STATUS_VMN_BIT (1 << 8) -#define STATUS_TMN_BIT (1 << 9) -#define STATUS_SMN_BIT (1 << 10) -#define STATUS_BI_BIT (1 << 11) -#define STATUS_VMX_BIT (1 << 12) -#define STATUS_TMX_BIT (1 << 13) -#define STATUS_SMX_BIT (1 << 14) -#define STATUS_BR_BIT (1 << 15) - -#define VFSOC0_LOCK 0x0000 -#define VFSOC0_UNLOCK 0x0080 - -#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ - -int max17050_get_property(enum MAX17050_reg reg, int *value) -{ - u16 data; - - switch (reg) - { - case MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap). - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Age); - *value = data >> 8; /* Show MSB. 1% increments */ - break; - case MAX17050_Cycles: // Cycle count. - i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Cycles); - break; - case MAX17050_MinVolt: // Voltage max/min - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt); - *value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */ - break; - case MAX17050_MaxVolt: // Voltage max/min - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MinMaxVolt); - *value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */ - break; - case MAX17050_V_empty: // Voltage min design. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_V_empty); - *value = (data >> 7) * 10; /* Units of LSB = 10mV */ - break; - case MAX17050_VCELL: // Voltage now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL); - *value = data * 625 / 8 / 1000; - break; - case MAX17050_AvgVCELL: // Voltage avg. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL); - *value = data * 625 / 8 / 1000; - break; - case MAX17050_OCVInternal: // Voltage ocv. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_OCVInternal); - *value = data * 625 / 8 / 1000; - break; - case MAX17050_RepSOC: // Capacity %. - i2c_recv_buf_small((u8 *)value, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC); - break; - case MAX17050_DesignCap: // Charge full design. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap); - data = data * 5 / 10; - *value = data; - break; - case MAX17050_FullCAP: // Charge full. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullCAP); - data = data * 5 / 10; - *value = data; - break; - case MAX17050_RepCap: // Charge now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepCap); - data = data * 5 / 10; - *value = data; - break; - case MAX17050_TEMP: // Temp. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_TEMP); - *value = (s16)data; - *value = *value * 10 / 256; - break; - case MAX17050_Current: // Current now. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_Current); - *value = (s16)data; - *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; - break; - case MAX17050_AvgCurrent: // Current avg. - i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgCurrent); - *value = (s16)data; - *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; - break; - default: - return -1; - } - return 0; -} - -static int _max17050_write_verify_reg(u8 reg, u16 value) -{ - int retries = 8; - int ret; - u16 read_value; - - do - { - ret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2); - i2c_recv_buf_small((u8 *)&read_value, 2, I2C_1, MAXIM17050_I2C_ADDR, reg); - if (read_value != value) - { - ret = -1; - retries--; - } - } while (retries && read_value != value); - - return ret; -} - -static void _max17050_override_por(u8 reg, u16 value) -{ - if (value) - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2); -} - -static void _max17050_load_new_capacity_params() -{ - u16 fullcap, repSoc, dq_acc, dp_acc; - - fullcap = 0x2476; // 4667mAh design capacity. - dq_acc = 0x10bc; // From a healthy fuel gauge. - dp_acc = 0x5e09; // =||= - repSoc = 0x6400; // 100%. - - _max17050_write_verify_reg(MAX17050_RemCap, fullcap); - _max17050_write_verify_reg(MAX17050_RepCap, fullcap); - - _max17050_write_verify_reg(MAX17050_dQacc, dq_acc); - _max17050_write_verify_reg(MAX17050_dPacc, dp_acc); - - _max17050_write_verify_reg(MAX17050_FullCAP, fullcap); - //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, (u8 *)&fullcap, 2); - _max17050_write_verify_reg(MAX17050_FullCAPNom, fullcap); - /* Update SOC register with new SOC */ - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC, (u8 *)&repSoc, 2); -} - -static void _max17050_reset_vfsoc0_reg() -{ - u16 lockVal = 0; - u16 vfSoc = 0x6440; // >100% for fully charged battery - - lockVal = VFSOC0_UNLOCK; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2); - - _max17050_write_verify_reg(MAX17050_VFSOC0, vfSoc); - - lockVal = VFSOC0_LOCK; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2); -} - -static void _max17050_update_capacity_regs() -{ - u16 value = 0x2476; // Set to 4667mAh design capacity. - _max17050_write_verify_reg(MAX17050_FullCAP, value); - _max17050_write_verify_reg(MAX17050_FullCAPNom, value); - //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, config->design_cap, 2); -} - -static void _max17050_write_config_regs() -{ - u16 value = 0; - - value = 0x7254; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_CONFIG, (u8 *)&value, 2); - value = 0x2473; - i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_LearnCFG, (u8 *)&value, 2); - //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FilterCFG, (u8 *)&value, 2) - //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RelaxCFG, (u8 *)&value, 2) - //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullSOCThr, (u8 *)&value, 2) -} - -/* - * Block write all the override values coming from platform data. - * This function MUST be called before the POR initialization proceedure - * specified by maxim. - */ -static void _max17050_override_por_values() -{ - u16 dq_acc = 0x10bc; // From a healthy fuel gauge. - u16 dp_acc = 0x5e09; // =||= - - _max17050_override_por(MAX17050_dQacc, dq_acc); - _max17050_override_por(MAX17050_dPacc, dp_acc); - - //_max17050_override_por(MAX17050_RCOMP0, config->rcomp0); //0x58 - //_max17050_override_por(MAX17050_TempCo, config->tcompc0); //0x1b22 - - //u16 k_empty0 = 0x439; - //_max17050_override_por(map, MAX17050_K_empty0, k_empty0); // Unknown cell data -} - -static void _max17050_set_por_bit(u16 value) -{ - _max17050_write_verify_reg(MAX17050_STATUS, value); -} - -int max17050_fix_configuration() -{ - /* Init phase, set the POR bit */ - _max17050_set_por_bit(STATUS_POR_BIT); - - /* Override POR values */ - _max17050_override_por_values(); - /* After Power up, the MAX17050 requires 500ms in order - * to perform signal debouncing and initial SOC reporting - */ - msleep(500); - - /* Initialize configaration */ - _max17050_write_config_regs(); - - /* update capacity params */ - _max17050_update_capacity_regs(); - - /* delay must be atleast 350mS to allow VFSOC - * to be calculated from the new configuration - */ - msleep(350); - - /* reset vfsoc0 reg */ - _max17050_reset_vfsoc0_reg(); - - /* load new capacity params */ - _max17050_load_new_capacity_params(); - - /* Init complete, Clear the POR bit */ - //_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR? - - // Sets POR, BI, BR. - _max17050_set_por_bit(0x8801); - - return 0; -} diff --git a/nyx/nyx_gui/power/max77620.h b/nyx/nyx_gui/power/max77620.h deleted file mode 100644 index 26ea855..0000000 --- a/nyx/nyx_gui/power/max77620.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Defining registers address and its bit definitions of MAX77620 and MAX20024 - * - * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2019 CTCaer - * - * 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_ - -#define MAX77620_I2C_ADDR 0x3C - -/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ -#define MAX77620_REG_CNFGGLBL1 0x00 -#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) -#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) -#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) -#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) -#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) -#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E -#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) -#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) -#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) - -#define MAX77620_REG_CNFGGLBL2 0x01 -#define MAX77620_REG_CNFGGLBL3 0x02 -#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_REG_CNFG1_32K 0x03 -#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) - -#define MAX77620_REG_CNFGBBC 0x04 -#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_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) -#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT) -#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT) -#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) - -#define MAX77620_REG_IRQTOP 0x05 -#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_REG_INTLBT 0x06 -#define MAX77620_REG_IRQTOPM 0x0D -#define MAX77620_IRQ_LBM_MASK (1 << 3) -#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) -#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) - -#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_INTENLBT 0x0E -#define MAX77620_GLBLM_MASK (1 << 0) - -#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_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_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_LDO_POWER_MODE_MASK 0xC0 -#define MAX77620_LDO_POWER_MODE_SHIFT 6 -#define MAX77620_POWER_MODE_NORMAL 3 -#define MAX77620_POWER_MODE_LPM 2 -#define MAX77620_POWER_MODE_GLPM 1 -#define MAX77620_POWER_MODE_DISABLE 0 -#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) -#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) -#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) -#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_REG_LDO_CFG3 0x35 -#define MAX77620_TRACK4_MASK (1 << 5) -#define MAX77620_TRACK4_SHIFT 5 - -#define MAX77620_LDO_SLEW_RATE_MASK 0x1 - -#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_CNFG_GPIO_DRV_MASK (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) -#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) -#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 << 3) -#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_REG_ONOFFCNFG1 0x41 -#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_REG_ONOFFCNFG2 0x42 -#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) - -/* 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 - -/* Minimum and maximum FPS period time (in microseconds) are - * different for MAX77620 and Max20024. - */ -#define MAX77620_FPS_COUNT 3 - -#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_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 - -#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) - -#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) - -/* 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/nyx/nyx_gui/power/max7762x.c b/nyx/nyx_gui/power/max7762x.c deleted file mode 100644 index 0e7a6b5..0000000 --- a/nyx/nyx_gui/power/max7762x.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer - * - * 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 "../soc/i2c.h" -#include "../utils/util.h" - -#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, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 }, - { REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 }, - { REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 }, - { REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 }, - { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 }, - { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 }, - { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 }, - { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 }, - { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 }, - { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 }, - { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 }, - { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 }, - { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } -}; - -static void _max77620_try_set_reg(u8 reg, u8 val) -{ - u8 tmp; - do - { - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val); - tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg); - } while (val != tmp); -} - -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, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1; - return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, 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]; - - _max77620_try_set_reg(reg->fps_addr, - (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (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_min || 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, MAX77620_I2C_ADDR, reg->volt_addr); - val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_try_set_reg(reg->volt_addr, val); - usleep(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, MAX77620_I2C_ADDR, addr); - if (enable) - val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); - else - val &= ~reg->enable_mask; - _max77620_try_set_reg(addr, val); - usleep(1000); - - return 1; -} - -int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) -{ - if (id > REGULATOR_MAX) - return 0; - - const max77620_regulator_t *reg = &_pmic_regulators[id]; - - if (mv < reg->mv_min || mv > reg->mv_max) - return 0; - - u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; - u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); - _max77620_try_set_reg(reg->volt_addr, val); - usleep(1000); - - return 1; -} - -void max77620_config_default() -{ - for (u32 i = 1; i <= REGULATOR_MAX; i++) - { - i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, 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); - } - _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); -} - -void max77620_low_battery_monitor_config() -{ - _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | - MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); -} diff --git a/nyx/nyx_gui/power/max7762x.h b/nyx/nyx_gui/power/max7762x.h deleted file mode 100644 index 3a0afe3..0000000 --- a/nyx/nyx_gui/power/max7762x.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2019 CTCaer - * - * 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 "../utils/types.h" - -/* -* Switch Power domains (max77620): -* Name | Usage | uV step | uV min | uV default | uV max | Init -*-------+---------------+---------+--------+------------+---------+------------------ -* sd0 | SoC | 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, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) -* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | -* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) -* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) -* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V -* 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 - -#define MAX77621_CPU_I2C_ADDR 0x1B -#define MAX77621_GPU_I2C_ADDR 0x1C - -#define MAX77621_VOUT_REG 0 -#define MAX77621_VOUT_DVC_REG 1 -#define MAX77621_CONTROL1_REG 2 -#define MAX77621_CONTROL2_REG 3 - -/* MAX77621_VOUT */ -#define MAX77621_VOUT_ENABLE (1 << 7) -#define MAX77621_VOUT_MASK 0x7F -#define MAX77621_VOUT_0_95V 0x37 -#define MAX77621_VOUT_1_09V 0x4F - -/* MAX77621_VOUT_DVC_DVS */ -#define MAX77621_DVS_VOUT_MASK 0x7F - -/* MAX77621_CONTROL1 */ -#define MAX77621_SNS_ENABLE (1 << 7) -#define MAX77621_FPWM_EN_M (1 << 6) -#define MAX77621_NFSR_ENABLE (1 << 5) -#define MAX77621_AD_ENABLE (1 << 4) -#define MAX77621_BIAS_ENABLE (1 << 3) -#define MAX77621_FREQSHIFT_9PER (1 << 2) - -#define MAX77621_RAMP_12mV_PER_US 0x0 -#define MAX77621_RAMP_25mV_PER_US 0x1 -#define MAX77621_RAMP_50mV_PER_US 0x2 -#define MAX77621_RAMP_200mV_PER_US 0x3 -#define MAX77621_RAMP_MASK 0x3 - -/* MAX77621_CONTROL2 */ -#define MAX77621_WDTMR_ENABLE (1 << 6) -#define MAX77621_DISCH_ENBABLE (1 << 5) -#define MAX77621_FT_ENABLE (1 << 4) -#define MAX77621_T_JUNCTION_120 (1 << 7) - -#define MAX77621_CKKADV_TRIP_DISABLE 0xC -#define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 -#define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4 -#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 - -#define MAX77621_INDUCTOR_MIN_30_PER 0x0 -#define MAX77621_INDUCTOR_NOMINAL 0x1 -#define MAX77621_INDUCTOR_PLUS_30_PER 0x2 -#define MAX77621_INDUCTOR_PLUS_60_PER 0x3 - -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); -int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); -void max77620_config_default(); -void max77620_low_battery_monitor_config(); - -#endif diff --git a/nyx/nyx_gui/power/regulator_5v.c b/nyx/nyx_gui/power/regulator_5v.c deleted file mode 100644 index a65615a..0000000 --- a/nyx/nyx_gui/power/regulator_5v.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 "../soc/gpio.h" -#include "../soc/pinmux.h" -#include "../soc/t210.h" -#include "../utils/types.h" - -static u8 reg_5v_dev = 0; - -void regulator_enable_5v(u8 dev) -{ - // The power supply selection from battery or USB is automatic. - if (!reg_5v_dev) - { - // Fan and Rail power from internal 5V regulator (battery). - PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1; - gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH); - - // Fan and Rail power from USB 5V VDD. - PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1; - gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH); - } - reg_5v_dev |= dev; -} - -void regulator_disable_5v(u8 dev) -{ - reg_5v_dev &= ~dev; - - if (!reg_5v_dev) - { - // Rail power from internal 5V regulator (battery). - gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW); - gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_DISABLE); - gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_SPIO); - PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = PINMUX_PARKED | PINMUX_INPUT_ENABLE; - - // Rail power from USB 5V VDD. - gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); - gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); - gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_SPIO); - PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_PARKED | PINMUX_INPUT_ENABLE; - } -} - -bool regulator_get_5v_dev_enabled(u8 dev) -{ - return (reg_5v_dev & dev); -} diff --git a/nyx/nyx_gui/rtc/max77620-rtc.h b/nyx/nyx_gui/rtc/max77620-rtc.h deleted file mode 100644 index 99199d2..0000000 --- a/nyx/nyx_gui/rtc/max77620-rtc.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC - * - * Copyright (c) 2018 CTCaer - * - * 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 _MFD_MAX77620_RTC_H_ -#define _MFD_MAX77620_RTC_H_ - -#include "../utils/types.h" - -#define MAX77620_RTC_I2C_ADDR 0x68 - -#define MAX77620_RTC_NR_TIME_REGS 7 - -#define MAX77620_RTC_CONTROLM_REG 0x02 -#define MAX77620_RTC_CONTROL_REG 0x03 -#define MAX77620_RTC_BIN_FORMAT (1 << 0) -#define MAX77620_RTC_24H (1 << 1) - -#define MAX77620_RTC_UPDATE0_REG 0x04 -#define MAX77620_RTC_WRITE_UPDATE (1 << 0) -#define MAX77620_RTC_READ_UPDATE (1 << 4) - -#define MAX77620_RTC_SEC_REG 0x07 -#define MAX77620_RTC_MIN_REG 0x08 -#define MAX77620_RTC_HOUR_REG 0x09 -#define MAX77620_RTC_HOUR_PM_MASK (1 << 6) -#define MAX77620_RTC_WEEKDAY_REG 0x0A -#define MAX77620_RTC_MONTH_REG 0x0B -#define MAX77620_RTC_YEAR_REG 0x0C -#define MAX77620_RTC_DATE_REG 0x0D - -#define MAX77620_ALARM1_SEC_REG 0x0E -#define MAX77620_ALARM1_MIN_REG 0x0F -#define MAX77620_ALARM1_HOUR_REG 0x10 -#define MAX77620_ALARM1_WEEKDAY_REG 0x11 -#define MAX77620_ALARM1_MONTH_REG 0x12 -#define MAX77620_ALARM1_YEAR_REG 0x13 -#define MAX77620_ALARM1_DATE_REG 0x14 -#define MAX77620_ALARM2_SEC_REG 0x15 -#define MAX77620_ALARM2_MIN_REG 0x16 -#define MAX77620_ALARM2_HOUR_REG 0x17 -#define MAX77620_ALARM2_WEEKDAY_REG 0x18 -#define MAX77620_ALARM2_MONTH_REG 0x19 -#define MAX77620_ALARM2_YEAR_REG 0x1A -#define MAX77620_ALARM2_DATE_REG 0x1B -#define MAX77620_RTC_ALARM_EN_MASK (1 << 7) - -typedef struct _rtc_time_t { - u8 weekday; - u8 sec; - u8 min; - u8 hour; - u8 day; - u8 month; - u16 year; -} rtc_time_t; - -void max77620_rtc_get_time(rtc_time_t *time); -void max77620_rtc_stop_alarm(); -void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time); -u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding); - -#endif /* _MFD_MAX77620_RTC_H_ */ diff --git a/nyx/nyx_gui/sec/se.c b/nyx/nyx_gui/sec/se.c deleted file mode 100644 index 36cc35f..0000000 --- a/nyx/nyx_gui/sec/se.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../sec/se.h" -#include "../mem/heap.h" -#include "../soc/bpmp.h" -#include "../soc/t210.h" -#include "../sec/se_t210.h" -#include "../utils/util.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 (int 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) & SE_STATUS_0_STATE_WAIT_IN || - SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR) - return 0; - return 1; -} - -se_ll_t *ll_dst, *ll_src; -static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot) -{ - 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); - - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - - SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); - - int res = 1; - if (is_oneshot) - { - res = _se_wait(); - - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - - if (src) - free(ll_src); - if (dst) - free(ll_dst); - } - - return res; -} - -static int _se_execute_finalize() -{ - int res = _se_wait(); - - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - - if (ll_src) - { - free(ll_src); - ll_src = NULL; - } - if (ll_dst) - { - free(ll_dst); - ll_dst = NULL; - } - - return res; -} - -static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) -{ - if (!src || !dst) - return 0; - - 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, true); - 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 & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = - ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | - ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); - if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) - SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); -} - -void se_key_acc_ctrl(u32 ks, u32 flags) -{ - if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; - if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) - 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, const 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_BLOCK_COUNT_REG_OFFSET) = 0; - SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); - - return _se_execute(OP_START, NULL, 0, input, 0x10, true); -} - -int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) -{ - 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) = (src_size >> 4) - 1; - return _se_execute(OP_START, dst, dst_size, src, src_size, true); -} - -int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) -{ - return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); -} - -int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const 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, true)) - 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; -} - -int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot) -{ - int res; - u32 *hash32 = (u32 *)hash; - - if (src_size > 0xFFFFFF || (u32)hash % 4 || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer. - return 0; - - // Setup config for SHA256. - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = sha_cfg; - - // Set total size to current buffer size if empty. - if (!total_size) - total_size = src_size; - - // Set total size: BITS(src_size), up to 2 EB. - SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(total_size << 3); - SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = (u32)(total_size >> 29); - SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; - - // Set size left to hash. - SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(total_size << 3); - SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = (u32)(total_size >> 29); - SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; - SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; - - // If we hash in chunks, copy over the intermediate. - if (sha_cfg == SHA_CONTINUE) - { - if (!msg_left) - return 0; - - // Restore message left to process. - SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = msg_left[0]; - SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = msg_left[1]; - - // Restore hash reg. - for (u32 i = 0; i < 8; i++) - SE(SE_HASH_RESULT_REG_OFFSET + (i << 2)) = byte_swap_32(hash32[i]); - } - - // Trigger the operation. - res = _se_execute(OP_START, NULL, 0, src, src_size, is_oneshot); - - if (is_oneshot) - { - // Backup message left. - if (msg_left) - { - msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); - msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); - } - - // Copy output hash. - for (u32 i = 0; i < 8; i++) - hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); - } - - return res; -} - -int se_calc_sha256_finalize(void *hash, u32 *msg_left) -{ - u32 *hash32 = (u32 *)hash; - int res = _se_execute_finalize(); - - // Backup message left. - if (msg_left) - { - msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); - msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); - } - - // Copy output hash. - for (u32 i = 0; i < 8; i++) - hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); - - return res; -} diff --git a/nyx/nyx_gui/sec/se.h b/nyx/nyx_gui/sec/se.h deleted file mode 100644 index 8ff74c1..0000000 --- a/nyx/nyx_gui/sec/se.h +++ /dev/null @@ -1,33 +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 . -*/ - -#ifndef _SE_H_ -#define _SE_H_ - -#include "../utils/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, const void *input); -int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); -int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); -int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); -int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot); -int se_calc_sha256_finalize(void *hash, u32 *msg_left); - -#endif diff --git a/nyx/nyx_gui/sec/se_t210.h b/nyx/nyx_gui/sec/se_t210.h deleted file mode 100644 index 3b610bc..0000000 --- a/nyx/nyx_gui/sec/se_t210.h +++ /dev/null @@ -1,389 +0,0 @@ -/* -* 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 "../utils/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_TZRAM_SECURITY_0 0x004 - -#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_STATUS_0_STATE_WAIT_IN 3 - -#define SE_ERR_STATUS_0 0x804 -#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0 - -#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_CONTINUE 0 -#define SHA_INIT_HASH 1 - -#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204 -#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208 -#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C -#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210 -#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214 -#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218 -#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C -#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220 - -#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_TBL_DIS_KEY_LOCK_FLAG 0x80 - -#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 -#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) -#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) -#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2) -#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3) -#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4) -#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5) -#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6) -#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F - -#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_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 - -#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 -#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) -#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) -#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2) -#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2) -#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 -#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F - -#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/nyx/nyx_gui/sec/tsec.h b/nyx/nyx_gui/sec/tsec.h deleted file mode 100644 index 45d994c..0000000 --- a/nyx/nyx_gui/sec/tsec.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer -* -* 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 _TSEC_H_ -#define _TSEC_H_ - -#include "../utils/types.h" - -typedef struct _tsec_ctxt_t -{ - void *fw; - u32 size; - void *pkg1; - u32 pkg11_off; - u32 secmon_base; -} tsec_ctxt_t; - -int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); - -#endif diff --git a/nyx/nyx_gui/sec/tsec_t210.h b/nyx/nyx_gui/sec/tsec_t210.h deleted file mode 100644 index befe269..0000000 --- a/nyx/nyx_gui/sec/tsec_t210.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2018 CTCaer -* -* 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 _TSEC_T210_H_ -#define _TSEC_T210_H_ - -#define TSEC_BOOTKEYVER 0x1040 -#define TSEC_STATUS 0x1044 -#define TSEC_ITFEN 0x1048 -#define TSEC_ITFEN_CTXEN (1 << 0) -#define TSEC_ITFEN_MTHDEN (1 << 1) -#define TSEC_IRQMSET 0x1010 -#define TSEC_IRQMSET_WDTMR (1 << 1) -#define TSEC_IRQMSET_HALT (1 << 4) -#define TSEC_IRQMSET_EXTERR (1 << 5) -#define TSEC_IRQMSET_SWGEN0 (1 << 6) -#define TSEC_IRQMSET_SWGEN1 (1 << 7) -#define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8) -#define TSEC_IRQDEST 0x101C -#define TSEC_IRQDEST_HALT (1 << 4) -#define TSEC_IRQDEST_EXTERR (1 << 5) -#define TSEC_IRQDEST_SWGEN0 (1 << 6) -#define TSEC_IRQDEST_SWGEN1 (1 << 7) -#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) -#define TSEC_CPUCTL 0x1100 -#define TSEC_CPUCTL_STARTCPU (1 << 1) -#define TSEC_BOOTVEC 0x1104 -#define TSEC_DMACTL 0x110C -#define TSEC_DMATRFBASE 0x1110 -#define TSEC_DMATRFMOFFS 0x1114 -#define TSEC_DMATRFCMD 0x1118 -#define TSEC_DMATRFCMD_IDLE (1 << 1) -#define TSEC_DMATRFCMD_IMEM (1 << 4) -#define TSEC_DMATRFCMD_SIZE_256B (6 << 8) -#define TSEC_DMATRFFBOFFS 0x111C - -#endif diff --git a/nyx/nyx_gui/soc/clock.c b/nyx/nyx_gui/soc/clock.c deleted file mode 100644 index ebbe572..0000000 --- a/nyx/nyx_gui/soc/clock.c +++ /dev/null @@ -1,590 +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 "../soc/clock.h" -#include "../soc/t210.h" -#include "../utils/util.h" -#include "../storage/sdmmc.h" - -/* - * CLOCK Peripherals: - * L 0 - 31 - * H 32 - 63 - * U 64 - 95 - * V 96 - 127 - * W 128 - 159 - * X 160 - 191 - * Y 192 - 223 - */ - -/* clock_t: reset, enable, source, index, clk_src, clk_div */ - -static const clock_t _clock_uart[] = { -/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 }, -/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 }, -/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 }, -/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 }, -/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 } -}; - -//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26. -static const clock_t _clock_i2c[] = { -/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz -/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz -/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz -/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz -/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz -/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz -}; - -static clock_t _clock_se = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 -}; - -static clock_t _clock_tzram = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0 -}; - -static clock_t _clock_host1x = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 -}; -static clock_t _clock_tsec = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 -}; -static clock_t _clock_sor_safe = { - CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0 -}; -static clock_t _clock_sor0 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0 -}; -static clock_t _clock_sor1 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 -}; -static clock_t _clock_kfuse = { - CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 -}; - -static clock_t _clock_cl_dvfs = { - CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0 -}; -static clock_t _clock_coresight = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 -}; - -static clock_t _clock_pwm = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. -}; - -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); - usleep(2); - - // 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(bool enable) -{ - CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28); -} - -void clock_enable_uart(u32 idx) -{ - clock_enable(&_clock_uart[idx]); -} - -void clock_enable_i2c(u32 idx) -{ - clock_enable(&_clock_i2c[idx]); -} - -void clock_disable_i2c(u32 idx) -{ - clock_disable(&_clock_i2c[idx]); -} - -void clock_enable_se() -{ - clock_enable(&_clock_se); -} - -void clock_enable_tzram() -{ - clock_enable(&_clock_tzram); -} - -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(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100; - usleep(10); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF; - usleep(20); -} - -void clock_disable_kfuse() -{ - clock_disable(&_clock_kfuse); -} - -void clock_enable_cl_dvfs() -{ - clock_enable(&_clock_cl_dvfs); -} - -void clock_disable_cl_dvfs() -{ - clock_disable(&_clock_cl_dvfs); -} - -void clock_enable_coresight() -{ - clock_enable(&_clock_coresight); -} - -void clock_disable_coresight() -{ - clock_disable(&_clock_coresight); -} - -void clock_enable_pwm() -{ - clock_enable(&_clock_pwm); -} - -void clock_disable_pwm() -{ - clock_disable(&_clock_pwm); -} - -void clock_enable_pllc(u32 divn) -{ - u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; - - // Check if already enabled and configured. - if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn)) - return; - - // Take PLLC out of reset and set basic misc parameters. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = - ((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM. - - // Disable PLL and IDDQ in case they are on. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; - usleep(10); - - // Set PLLC4 dividers. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. - - // Enable PLLC4 and wait for Phase and Frequency lock. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; - while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) - ; - - // Disable PLLC_OUT1, enable reset and set div to 1.5. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8); - - // Enable PLLC_OUT1 and bring it out of reset. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); - msleep(1); // Wait a bit for PLL to stabilize. -} - -void clock_disable_pllc() -{ - // Disable PLLC and PLLC_OUT1. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS; - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ; - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET; - usleep(10); -} - -#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; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; - break; - } -} - -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; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; - break; - } -} - -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 void _clock_sdmmc_set_enable(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; - break; - } -} - -static void _clock_sdmmc_clear_enable(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; - break; - } -} - -static u32 _clock_sdmmc_table[8] = { 0 }; - -#define PLLP_OUT0 0x0 -static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) -{ - u32 divisor = 0; - u32 source = PLLP_OUT0; - - // Get IO clock divisor. - switch (val) - { - case 25000: - *pout = 24728; - divisor = 31; // 16.5 div. - break; - case 26000: - *pout = 25500; - divisor = 30; // 16 div. - break; - case 40800: - *pout = 40800; - divisor = 18; // 10 div. - break; - case 50000: - *pout = 48000; - divisor = 15; // 8.5 div. - break; - case 52000: - *pout = 51000; - divisor = 14; // 8 div. - break; - case 100000: - *pout = 90667; - divisor = 7; // 4.5 div. - break; - case 200000: - *pout = 163200; - divisor = 3; // 2.5 div. - break; - case 208000: - *pout = 204000; - divisor = 2; // 2 div. - break; - default: - *pout = 24728; - divisor = 31; // 16.5 div. - } - - _clock_sdmmc_table[2 * id] = val; - _clock_sdmmc_table[2 * id + 1] = *pout; - - // Set SDMMC clock. - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | 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_host(pout, id, val); - if (is_enabled) - _clock_sdmmc_set_enable(id); - _clock_sdmmc_is_reset(id); - } -} - -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) -{ - // Get Card clock divisor. - 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; - break; - case 6: - case 8: - *pout = 25000; - *pdivisor = 1; - break; - case 7: - *pout = 50000; - *pdivisor = 1; - break; - case 10: - *pout = 100000; - *pdivisor = 1; - break; - 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_host(&div, id, val); - _clock_sdmmc_set_enable(id); - _clock_sdmmc_is_reset(id); - usleep((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/nyx/nyx_gui/soc/clock.h b/nyx/nyx_gui/soc/clock.h deleted file mode 100644 index 3679b46..0000000 --- a/nyx/nyx_gui/soc/clock.h +++ /dev/null @@ -1,201 +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 . - */ - -#ifndef _CLOCK_H_ -#define _CLOCK_H_ - -#include "../utils/types.h" - -/*! Clock registers. */ -#define CLK_RST_CONTROLLER_RST_SOURCE 0x0 -#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 -#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 -#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_PLLC_BASE 0x80 -#define CLK_RST_CONTROLLER_PLLC_OUT 0x84 -#define CLK_RST_CONTROLLER_PLLC_MISC 0x88 -#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C -#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 -#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 -#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C -#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 -#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 -#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 -#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC -#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 -#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 -#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 -#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC -#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 -#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 -#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_UARTA 0x178 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C -#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 -#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 -#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 -#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C -#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290 -#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 -#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C -#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0 -#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4 -#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8 -#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC -#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_H_CLR 0x30C -#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_H_CLR 0x32C -#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_RST_DEVICES_W 0x35C -#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_LVL2_CLK_GATE_OVRC 0x3A0 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C -#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 -#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 -#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 -#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 -#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C -#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 -#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 -#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 -#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C -#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 -#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 -#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C -#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 -#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 -#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 -#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 -#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 -#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 -#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 - -#define CLK_NO_SOURCE 0x0 - -/*! PLL control and status bits */ -#define PLLCX_BASE_ENABLE (1 << 30) -#define PLLCX_BASE_REF_DIS (1 << 29) -#define PLLCX_BASE_LOCK (1 << 27) - -#define PLLC_MISC_RESET (1 << 30) -#define PLLC_MISC1_IDDQ (1 << 27) -#define PLLC_OUT1_CLKEN (1 << 1) -#define PLLC_OUT1_RSTN_CLR (1 << 0) - -#define PLLC4_MISC_EN_LCKDET (1 << 30) -#define PLLC4_BASE_IDDQ (1 << 18) -#define PLLC4_OUT3_CLKEN (1 << 1) -#define PLLC4_OUT3_RSTN_CLR (1 << 0) - -/*! Generic clock descriptor. */ -typedef struct _clock_t -{ - u32 reset; - u32 enable; - u32 source; - u8 index; - u8 clk_src; - 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(bool enable); -void clock_enable_uart(u32 idx); -void clock_enable_i2c(u32 idx); -void clock_disable_i2c(u32 idx); -void clock_enable_se(); -void clock_enable_tzram(); -void clock_enable_host1x(); -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_disable_cl_dvfs(); -void clock_enable_coresight(); -void clock_disable_coresight(); -void clock_enable_pwm(); -void clock_disable_pwm(); -void clock_enable_pllc(u32 divn); -void clock_disable_pllc(); -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_card_clock_div(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/nyx/nyx_gui/soc/cluster.c b/nyx/nyx_gui/soc/cluster.c deleted file mode 100644 index 79538ed..0000000 --- a/nyx/nyx_gui/soc/cluster.c +++ /dev/null @@ -1,140 +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 "../soc/cluster.h" -#include "../soc/i2c.h" -#include "../soc/clock.h" -#include "../utils/util.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../power/max77620.h" -#include "../power/max7762x.h" - -void _cluster_enable_power() -{ - u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); - - // Enable cores power. - // 1-3.x: MAX77621_NFSR_ENABLE. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, - MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); - // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); -} - -int _cluster_pmc_enable_partition(u32 part, int enable) -{ - u32 part_mask = 1 << part; - u32 desired_state = enable << part; - - // Check if the partition has the state we want. - if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) - return 1; - - u32 i = 5001; - while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) - { - usleep(1); - i--; - if (i < 1) - return 0; - } - - // Toggle power gating. - PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; - - i = 5001; - while (i > 0) - { - if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) - break; - usleep(1); - i--; - } - - return 1; -} - -void cluster_boot_cpu0(u32 entry) -{ - // Set ACTIVE_CLUSER to FAST. - FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE; - - _cluster_enable_power(); - - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. - { - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. - usleep(2); - 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(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000)) - ; - - // 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(); - - // CAR2PMC_CPU_ACK_WIDTH should be set to 0. - CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; - - // Enable CPU rail. - _cluster_pmc_enable_partition(0, 1); - // Enable cluster 0 non-CPU. - _cluster_pmc_enable_partition(15, 1); - // Enable CE0. - _cluster_pmc_enable_partition(14, 1); - - // Request and wait for RAM repair. - FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; - while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2)) - ; - - EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; - - // Set reset vector. - SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; - SB(SB_AA64_RESET_HIGH) = 0; - // Non-secure reset vector write disable. - SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; - (void)SB(SB_CSR); - - // Tighten up the security aperture. - // MC(MC_TZ_SECURITY_CTRL) = 1; - - // Clear MSELECT reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; - // Clear NONCPU reset. - CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; - // Clear CPU0 reset. - // < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. - CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001; -} diff --git a/nyx/nyx_gui/soc/fuse.h b/nyx/nyx_gui/soc/fuse.h deleted file mode 100644 index 9240b04..0000000 --- a/nyx/nyx_gui/soc/fuse.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 shuffle2 - * Copyright (c) 2018 balika011 - * - * 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 "../utils/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 -#define FUSE_SKU_INFO 0x110 -#define FUSE_CPU_SPEEDO_0_CALIB 0x114 -#define FUSE_CPU_IDDQ_CALIB 0x118 -#define FUSE_OPT_FT_REV 0x128 -#define FUSE_CPU_SPEEDO_1_CALIB 0x12C -#define FUSE_CPU_SPEEDO_2_CALIB 0x130 -#define FUSE_SOC_SPEEDO_0_CALIB 0x134 -#define FUSE_SOC_SPEEDO_1_CALIB 0x138 -#define FUSE_SOC_SPEEDO_2_CALIB 0x13C -#define FUSE_SOC_IDDQ_CALIB 0x140 -#define FUSE_OPT_CP_REV 0x190 -#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c -#define FUSE_PRIVATE_KEY0 0x1A4 -#define FUSE_PRIVATE_KEY1 0x1A8 -#define FUSE_PRIVATE_KEY2 0x1AC -#define FUSE_PRIVATE_KEY3 0x1B0 -#define FUSE_PRIVATE_KEY4 0x1B4 -#define FUSE_RESERVED_SW 0x1C0 -#define FUSE_SKU_DIRECT_CONFIG 0x1F4 -#define FUSE_OPT_VENDOR_CODE 0x200 -#define FUSE_OPT_FAB_CODE 0x204 -#define FUSE_OPT_LOT_CODE_0 0x208 -#define FUSE_OPT_LOT_CODE_1 0x20C -#define FUSE_OPT_WAFER_ID 0x210 -#define FUSE_OPT_X_COORDINATE 0x214 -#define FUSE_OPT_Y_COORDINATE 0x218 -#define FUSE_GPU_IDDQ_CALIB 0x228 - -/*! Fuse commands. */ -#define FUSE_READ 0x1 -#define FUSE_WRITE 0x2 -#define FUSE_SENSE 0x3 -#define FUSE_CMD_MASK 0x3 - -/*! Fuse cache registers. */ -#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) - -void fuse_disable_program(); -u32 fuse_read_odm(u32 idx); -void fuse_wait_idle(); -int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); -int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); -void fuse_read_array(u32 *words); -bool fuse_check_patched_rcm(); - -#endif diff --git a/nyx/nyx_gui/soc/gpio.c b/nyx/nyx_gui/soc/gpio.c deleted file mode 100644 index 053c43a..0000000 --- a/nyx/nyx_gui/soc/gpio.c +++ /dev/null @@ -1,94 +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 "../soc/gpio.h" -#include "../soc/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/nyx/nyx_gui/soc/gpio.h b/nyx/nyx_gui/soc/gpio.h deleted file mode 100644 index 83170b0..0000000 --- a/nyx/nyx_gui/soc/gpio.h +++ /dev/null @@ -1,77 +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 . - */ - -#ifndef _GPIO_H_ -#define _GPIO_H_ - -#include "../utils/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/nyx/nyx_gui/soc/hw_init.c b/nyx/nyx_gui/soc/hw_init.c deleted file mode 100644 index d8e5491..0000000 --- a/nyx/nyx_gui/soc/hw_init.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018-2019 CTCaer - * - * 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 "hw_init.h" -#include "bpmp.h" -#include "clock.h" -#include "gpio.h" -#include "pmc.h" -#include "t210.h" -#include "../mem/minerva.h" -#include "../gfx/di.h" -#include "../input/touch.h" -#include "../power/regulator_5v.h" -#include "../storage/sdmmc.h" -#include "../thermal/fan.h" -#include "../utils/util.h" - -extern sdmmc_t sd_sdmmc; -extern volatile nyx_storage_t *nyx_str; - -void reconfig_hw_workaround(bool extra_reconfig, u32 magic) -{ - // Disable BPMP max clock. - bpmp_clk_rate_set(BPMP_CLK_NORMAL); - - // Deinit touchscreen and 5V regulators. - touch_power_off(); - set_fan_duty(0); - regulator_disable_5v(REGULATOR_5V_ALL); - - // Flush/disable MMU cache and set DRAM clock to 204MHz. - bpmp_mmu_disable(); - minerva_change_freq(FREQ_204); - nyx_str->mtc_cfg.init_done = 0; - - // Re-enable clocks to Audio Processing Engine as a workaround to hanging. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. - - if (extra_reconfig) - { - msleep(10); - PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; - - clock_disable_cl_dvfs(); - - // Disable Joy-con GPIOs. - gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO); - gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO); - } - - // Power off display. - display_end(); - - // Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits. - if (magic == 0xBAADF00D) - { - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); - sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0); - clock_disable_cl_dvfs(); - - msleep(200); - } -} \ No newline at end of file diff --git a/nyx/nyx_gui/soc/i2c.c b/nyx/nyx_gui/soc/i2c.c deleted file mode 100644 index d06d64a..0000000 --- a/nyx/nyx_gui/soc/i2c.c +++ /dev/null @@ -1,143 +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 - -#include "i2c.h" -#include "../utils/util.h" - -static u32 i2c_addrs[] = { - 0x7000C000, 0x7000C400, 0x7000C500, - 0x7000C700, 0x7000D000, 0x7000D100 -}; - -static void _i2c_wait(vu32 *base) -{ - base[I2C_CONFIG_LOAD] = 0x25; - for (u32 i = 0; i < 20; i++) - { - usleep(1); - if (!(base[I2C_CONFIG_LOAD] & 1)) - break; - } -} - -static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) -{ - if (size > 4) - return 0; - - u32 tmp = 0; - memcpy(&tmp, buf, size); - - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). - base[I2C_CMD_DATA1] = tmp; //Set value. - base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. - _i2c_wait(base); //Kick transaction. - - base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; - while (base[I2C_STATUS] & 0x100) - ; - - if (base[I2C_STATUS] << 28) - return 0; - - return 1; -} - -static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) -{ - if (size > 8) - return 0; - - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). - base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode. - _i2c_wait(base); // Kick transaction. - - base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; - while (base[I2C_STATUS] & 0x100) - ; - - if (base[I2C_STATUS] << 28) - return 0; - - u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. - if (size > 4) - { - memcpy(buf, &tmp, 4); - tmp = base[I2C_CMD_DATA2]; // Get MS value. - memcpy(buf + 4, &tmp, size - 4); - } - else - memcpy(buf, &tmp, size); - - return 1; -} - -void i2c_init(u32 idx) -{ - vu32 *base = (vu32 *)i2c_addrs[idx]; - - base[I2C_CLK_DIVISOR_REGISTER] = 0x50001; - base[I2C_BUS_CLEAR_CONFIG] = 0x90003; - _i2c_wait(base); - - for (u32 i = 0; i < 10; i++) - { - usleep(20000); - if (base[INTERRUPT_STATUS_REGISTER] & 0x800) - break; - } - - (vu32)base[I2C_BUS_CLEAR_STATUS]; - base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER]; -} - -int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) -{ - u8 tmp[4]; - - if (size > 3) - return 0; - - tmp[0] = y; - memcpy(tmp + 1, buf, size); - - return _i2c_send_pkt(idx, x, tmp, size + 1); -} - -int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y) -{ - int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); - if (res) - res = _i2c_recv_pkt(idx, buf, size, x); - return res; -} - -int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b) -{ - return i2c_send_buf_small(idx, x, y, &b, 1); -} - -u8 i2c_recv_byte(u32 idx, u32 x, u32 y) -{ - u8 tmp = 0; - i2c_recv_buf_small(&tmp, 1, idx, x, y); - return tmp; -} - diff --git a/nyx/nyx_gui/soc/i2c.h b/nyx/nyx_gui/soc/i2c.h deleted file mode 100644 index e2b2af5..0000000 --- a/nyx/nyx_gui/soc/i2c.h +++ /dev/null @@ -1,46 +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 . - */ - -#ifndef _I2C_H_ -#define _I2C_H_ - -#include "../utils/types.h" - -#define I2C_1 0 -#define I2C_2 1 -#define I2C_3 2 -#define I2C_4 3 -#define I2C_5 4 -#define I2C_6 5 - -#define I2C_CNFG 0x00 -#define I2C_CMD_ADDR0 0x01 -#define I2C_CMD_DATA1 0x03 -#define I2C_CMD_DATA2 0x04 -#define I2C_STATUS 0x07 -#define INTERRUPT_STATUS_REGISTER 0x1A -#define I2C_CLK_DIVISOR_REGISTER 0x1B -#define I2C_BUS_CLEAR_CONFIG 0x21 -#define I2C_BUS_CLEAR_STATUS 0x22 -#define I2C_CONFIG_LOAD 0x23 - -void i2c_init(u32 idx); -int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size); -int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y); -int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b); -u8 i2c_recv_byte(u32 idx, u32 x, u32 y); - -#endif diff --git a/nyx/nyx_gui/soc/kfuse.h b/nyx/nyx_gui/soc/kfuse.h deleted file mode 100644 index a535803..0000000 --- a/nyx/nyx_gui/soc/kfuse.h +++ /dev/null @@ -1,42 +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 . - */ - -#ifndef _KFUSE_H_ -#define _KFUSE_H_ - -#include "../utils/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_wait_ready(); -int kfuse_read(u32 *buf); - -#endif diff --git a/nyx/nyx_gui/soc/pinmux.c b/nyx/nyx_gui/soc/pinmux.c deleted file mode 100644 index 582ab29..0000000 --- a/nyx/nyx_gui/soc/pinmux.c +++ /dev/null @@ -1,32 +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 "../soc/pinmux.h" -#include "../soc/t210.h" - -void pinmux_config_uart(u32 idx) -{ - PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0; - PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0; - PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN; -} - -void pinmux_config_i2c(u32 idx) -{ - PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE; - PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE; -} diff --git a/nyx/nyx_gui/soc/pinmux.h b/nyx/nyx_gui/soc/pinmux.h deleted file mode 100644 index bb4ecb1..0000000 --- a/nyx/nyx_gui/soc/pinmux.h +++ /dev/null @@ -1,108 +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 . - */ - -#ifndef _PINMUX_H_ -#define _PINMUX_H_ - -#include "../utils/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_SATA_LED_ACTIVE 0x4C -#define PINMUX_AUX_DMIC3_CLK 0xB4 -#define PINMUX_AUX_DMIC3_DAT 0xB8 -#define PINMUX_AUX_CAM_I2C_SCL 0xD4 -#define PINMUX_AUX_CAM_I2C_SDA 0xD8 -#define PINMUX_AUX_UART2_TX 0xF4 -#define PINMUX_AUX_UART3_TX 0x104 -#define PINMUX_AUX_DAP4_DIN 0x148 -#define PINMUX_AUX_DAP4_SCLK 0x150 -#define PINMUX_AUX_GPIO_X1_AUD 0x18C -#define PINMUX_AUX_GPIO_X3_AUD 0x190 -#define PINMUX_AUX_SPDIF_IN 0x1A4 -#define PINMUX_AUX_USB_VBUS_EN0 0x1A8 -#define PINMUX_AUX_USB_VBUS_EN1 0x1AC -#define PINMUX_AUX_WIFI_EN 0x1B4 -#define PINMUX_AUX_WIFI_RST 0x1B8 -#define PINMUX_AUX_AP_WAKE_NFC 0x1CC -#define PINMUX_AUX_NFC_EN 0x1D0 -#define PINMUX_AUX_NFC_INT 0x1D4 -#define PINMUX_AUX_CAM1_PWDN 0x1EC -#define PINMUX_AUX_CAM2_PWDN 0x1F0 -#define PINMUX_AUX_LCD_BL_PWM 0x1FC -#define PINMUX_AUX_LCD_BL_EN 0x200 -#define PINMUX_AUX_LCD_RST 0x204 -#define PINMUX_AUX_LCD_GPIO2 0x20C -#define PINMUX_AUX_TOUCH_INT 0x220 -#define PINMUX_AUX_MOTION_INT 0x224 -#define PINMUX_AUX_BUTTON_HOME 0x240 -#define PINMUX_AUX_GPIO_PE6 0x248 -#define PINMUX_AUX_GPIO_PH6 0x250 -#define PINMUX_AUX_GPIO_PK3 0x260 -#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)) -#define PINMUX_AUX_UARTX_RTS(x) (0xEC + 0x10 * (x)) -#define PINMUX_AUX_UARTX_CTS(x) (0xF0 + 0x10 * (x)) -/*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */ -#define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x)) -#define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x)) - -#define PINMUX_FUNC_MASK (3 << 0) - -#define PINMUX_PULL_MASK (3 << 2) -#define PINMUX_PULL_NONE (0 << 2) -#define PINMUX_PULL_DOWN (1 << 2) -#define PINMUX_PULL_UP (2 << 2) - -#define PINMUX_TRISTATE (1 << 4) -#define PINMUX_PARKED (1 << 5) -#define PINMUX_INPUT_ENABLE (1 << 6) -#define PINMUX_LOCK (1 << 7) -#define PINMUX_LPDR (1 << 8) -#define PINMUX_HSM (1 << 9) - -#define PINMUX_IO_HV (1 << 10) -#define PINMUX_OPEN_DRAIN (1 << 11) -#define PINMUX_SCHMT (1 << 12) - -#define PINMUX_DRIVE_1X (0 << 13) -#define PINMUX_DRIVE_2X (1 << 13) -#define PINMUX_DRIVE_3X (2 << 13) -#define PINMUX_DRIVE_4X (3 << 13) - -void pinmux_config_uart(u32 idx); -void pinmux_config_i2c(u32 idx); - -#endif diff --git a/nyx/nyx_gui/soc/pmc.h b/nyx/nyx_gui/soc/pmc.h deleted file mode 100644 index 8cd9161..0000000 --- a/nyx/nyx_gui/soc/pmc.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 st4rk - * - * 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 _PMC_H_ -#define _PMC_H_ - -/*! PMC registers. */ -#define APBDEV_PMC_CNTRL 0x0 -#define PMC_CNTRL_MAIN_RST (1 << 4) -#define APBDEV_PMC_SEC_DISABLE 0x4 -#define APBDEV_PMC_PWRGATE_TOGGLE 0x30 -#define APBDEV_PMC_PWRGATE_STATUS 0x38 -#define APBDEV_PMC_NO_IOPOWER 0x44 -#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) -#define APBDEV_PMC_SCRATCH0 0x50 -#define APBDEV_PMC_SCRATCH1 0x54 -#define APBDEV_PMC_SCRATCH20 0xA0 -#define APBDEV_PMC_PWR_DET_VAL 0xE4 -#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12) -#define APBDEV_PMC_DDR_PWR 0xE8 -#define APBDEV_PMC_CRYPTO_OP 0xF4 -#define PMC_CRYPTO_OP_SE_ENABLE 0 -#define PMC_CRYPTO_OP_SE_DISABLE 1 -#define APBDEV_PMC_SCRATCH33 0x120 -#define APBDEV_PMC_SCRATCH40 0x13C -#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 -#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 -#define APBDEV_PMC_RST_STATUS 0x1B4 -#define APBDEV_PMC_IO_DPD_REQ 0x1B8 -#define APBDEV_PMC_IO_DPD2_REQ 0x1C0 -#define APBDEV_PMC_VDDP_SEL 0x1CC -#define APBDEV_PMC_DDR_CFG 0x1D0 -#define APBDEV_PMC_SCRATCH45 0x234 -#define APBDEV_PMC_SCRATCH46 0x238 -#define APBDEV_PMC_SCRATCH49 0x244 -#define APBDEV_PMC_TSC_MULT 0x2B4 -#define APBDEV_PMC_SEC_DISABLE2 0x2C4 -#define APBDEV_PMC_WEAK_BIAS 0x2C8 -#define APBDEV_PMC_REG_SHORT 0x2CC -#define APBDEV_PMC_SEC_DISABLE3 0x2D8 -#define APBDEV_PMC_SECURE_SCRATCH21 0x334 -#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10 -#define APBDEV_PMC_SECURE_SCRATCH32 0x360 -#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 -#define APBDEV_PMC_CNTRL2 0x440 -#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000 -#define APBDEV_PMC_IO_DPD3_REQ 0x45C -#define APBDEV_PMC_IO_DPD4_REQ 0x464 -#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 -#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC -#define APBDEV_PMC_DDR_CNTRL 0x4E4 -#define APBDEV_PMC_SEC_DISABLE4 0x5B0 -#define APBDEV_PMC_SEC_DISABLE5 0x5B4 -#define APBDEV_PMC_SEC_DISABLE6 0x5B8 -#define APBDEV_PMC_SEC_DISABLE7 0x5BC -#define APBDEV_PMC_SEC_DISABLE8 0x5C0 -#define APBDEV_PMC_SCRATCH188 0x810 -#define APBDEV_PMC_SCRATCH190 0x818 -#define APBDEV_PMC_SCRATCH200 0x840 - -#endif diff --git a/nyx/nyx_gui/soc/pmc_lp0_t210.h b/nyx/nyx_gui/soc/pmc_lp0_t210.h deleted file mode 100644 index 641d9f7..0000000 --- a/nyx/nyx_gui/soc/pmc_lp0_t210.h +++ /dev/null @@ -1,564 +0,0 @@ -/* - * 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 "../utils/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/nyx/nyx_gui/soc/smmu.c b/nyx/nyx_gui/soc/smmu.c deleted file mode 100644 index fb096d4..0000000 --- a/nyx/nyx_gui/soc/smmu.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 balika011 - * - * 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 "smmu.h" -#include "../soc/cluster.h" -#include "../soc/t210.h" -#include "../mem/mc_t210.h" -#include "../utils/util.h" -#include "../utils/aarch64_util.h" - -bool smmu_used = false; -u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR; - -//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1; -u8 smmu_payload[] __attribute__((aligned(16))) = { - 0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010 - 0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1 - 0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1] - 0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS - 0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH - 0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop - 0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0 - 0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1] - 0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000 - 0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0 - 0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG - 0x00, 0x00, 0x00, 0x00, // 0x2C: - 0x00, 0x00, 0x00, 0x00, // 0x30: secmon address - 0x00, 0x00, 0x00, 0x00 // 0x34: -}; - -void *page_alloc(u32 num) -{ - u8 *res = _pageheap; - _pageheap += 0x1000 * num; - memset(res, 0, 0x1000 * num); - return res; -} - -u32 *smmu_alloc_pdir() -{ - u32 *pdir = (u32 *)page_alloc(1); - for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) - pdir[pdn] = _PDE_VACANT(pdn); - return pdir; -} - -void smmu_flush_regs() -{ - (void)MC(MC_SMMU_PTB_DATA); -} - -void smmu_flush_all() -{ - MC(MC_SMMU_PTC_FLUSH) = 0; - smmu_flush_regs(); - MC(MC_SMMU_TLB_FLUSH) = 0; - smmu_flush_regs(); -} - -void smmu_init(u32 secmon_base) -{ - MC(MC_SMMU_PTB_ASID) = 0; - MC(MC_SMMU_PTB_DATA) = 0; - MC(MC_SMMU_TLB_CONFIG) = 0x30000030; - MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F; - MC(MC_SMMU_PTC_FLUSH) = 0; - MC(MC_SMMU_TLB_FLUSH) = 0; - - // Set the secmon address - *(u32 *)(smmu_payload + 0x30) = secmon_base; -} - -void smmu_enable() -{ - if (smmu_used) - return; - - cluster_boot_cpu0((u32)smmu_payload); - smmu_used = true; - msleep(150); - - smmu_flush_all(); -} - -bool smmu_is_used() -{ - return smmu_used; -} - -void smmu_exit() -{ - *(u32 *)(smmu_payload + 0x14) = _NOP(); -} - -u32 *smmu_init_domain4(u32 dev_base, u32 asid) -{ - u32 *pdir = smmu_alloc_pdir(); - - MC(MC_SMMU_PTB_ASID) = asid; - MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR); - smmu_flush_regs(); - - MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid); - smmu_flush_regs(); - - return pdir; -} - -u32 *smmu_get_pte(u32 *pdir, u32 iova) -{ - u32 ptn = SMMU_ADDR_TO_PFN(iova); - u32 pdn = SMMU_ADDR_TO_PDN(iova); - u32 *ptbl; - - if (pdir[pdn] != _PDE_VACANT(pdn)) - ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT); - else - { - ptbl = (u32 *)page_alloc(1); - u32 addr = SMMU_PDN_TO_ADDR(pdn); - for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE) - ptbl[pn] = _PTE_VACANT(addr); - pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT); - smmu_flush_all(); - } - - return &ptbl[ptn % SMMU_PTBL_COUNT]; -} - -void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr) -{ - for (int i = 0; i < cnt; i++) - { - u32 *pte = smmu_get_pte(pdir, addr); - *pte = SMMU_ADDR_TO_PFN(page) | attr; - addr += 0x1000; - page += 0x1000; - } - smmu_flush_all(); -} - -u32 *smmu_init_for_tsec() -{ - return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1); -} - -void smmu_deinit_for_tsec() -{ - MC(MC_SMMU_PTB_ASID) = 1; - MC(MC_SMMU_PTB_DATA) = 0; - MC(MC_SMMU_TSEC_ASID) = 0; - smmu_flush_regs(); -} - diff --git a/nyx/nyx_gui/soc/smmu.h b/nyx/nyx_gui/soc/smmu.h deleted file mode 100644 index 827d58b..0000000 --- a/nyx/nyx_gui/soc/smmu.h +++ /dev/null @@ -1,82 +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 "../utils/types.h" - -#define SMMU_HEAP_ADDR 0xA0000000 - -#define MC_INTSTATUS 0x0 -#define MC_INTMASK 0x4 -#define MC_ERR_STATUS 0x8 -#define MC_ERR_ADR 0xc -#define MC_SMMU_CONFIG 0x10 -#define MC_SMMU_TLB_CONFIG 0x14 -#define MC_SMMU_PTC_CONFIG 0x18 -#define MC_SMMU_PTB_ASID 0x1c -#define MC_SMMU_PTB_DATA 0x20 -#define MC_SMMU_TLB_FLUSH 0x30 -#define MC_SMMU_PTC_FLUSH 0x34 -#define MC_SMMU_ASID_SECURITY 0x38 -#define MC_SMMU_TSEC_ASID 0x294 -#define MC_SMMU_TRANSLATION_ENABLE_0 0x228 -#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c -#define MC_SMMU_TRANSLATION_ENABLE_2 0x230 -#define MC_SMMU_TRANSLATION_ENABLE_3 0x234 -#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98 - -#define SMMU_PDE_NEXT_SHIFT 28 -#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29 -#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30 -#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31 -#define SMMU_PAGE_SHIFT 12 -#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT) -#define SMMU_PDIR_COUNT 1024 -#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT) -#define SMMU_PTBL_COUNT 1024 -#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT) -#define SMMU_PDIR_SHIFT 12 -#define SMMU_PDE_SHIFT 12 -#define SMMU_PTE_SHIFT 12 -#define SMMU_PFN_MASK 0x000FFFFF -#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) -#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) -#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22) -#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT) -#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT) -#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT) -#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT) -#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR) -#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE) -#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR) -#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr)) -#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr)) - -void *page_alloc(u32 num); -u32 *smmu_alloc_pdir(); -void smmu_flush_regs(); -void smmu_flush_all(); -void smmu_init(u32 secmon_base); -void smmu_enable(); -bool smmu_is_used(); -void smmu_exit(); -u32 *smmu_init_domain4(u32 dev_base, u32 asid); -u32 *smmu_get_pte(u32 *pdir, u32 iova); -void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr); -u32 *smmu_init_for_tsec(); -void smmu_deinit_for_tsec(); diff --git a/nyx/nyx_gui/soc/t210.h b/nyx/nyx_gui/soc/t210.h deleted file mode 100644 index 85e42f4..0000000 --- a/nyx/nyx_gui/soc/t210.h +++ /dev/null @@ -1,231 +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 . -*/ - -#ifndef _T210_H_ -#define _T210_H_ - -#include "../utils/types.h" - -#define BOOTROM_BASE 0x100000 -#define IRAM_BASE 0x40000000 -#define HOST1X_BASE 0x50000000 -#define BPMP_CACHE_BASE 0x50040000 -#define DISPLAY_A_BASE 0x54200000 -#define DSI_BASE 0x54300000 -#define VIC_BASE 0x54340000 -#define TSEC_BASE 0x54500000 -#define SOR1_BASE 0x54580000 -#define TMR_BASE 0x60005000 -#define CLOCK_BASE 0x60006000 -#define FLOW_CTLR_BASE 0x60007000 -#define SYSREG_BASE 0x6000C000 -#define SB_BASE (SYSREG_BASE + 0x200) -#define GPIO_BASE 0x6000D000 -#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 IPATCH_BASE 0x6001DC00 -#define APB_MISC_BASE 0x70000000 -#define PINMUX_AUX_BASE 0x70003000 -#define UART_BASE 0x70006000 -#define PWM_BASE 0x7000A000 -#define RTC_BASE 0x7000E000 -#define PMC_BASE 0x7000E400 -#define SYSCTR0_BASE 0x700F0000 -#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 -#define CL_DVFS_BASE 0x70110000 -#define I2S_BASE 0x702D1000 -#define TZRAM_BASE 0x7C010000 - -#define _REG(base, off) *(vu32 *)((base) + (off)) - -#define HOST1X(off) _REG(HOST1X_BASE, off) -#define BPMP_CACHE_CTRL(off) _REG(BPMP_CACHE_BASE, off) -#define DISPLAY_A(off) _REG(DISPLAY_A_BASE, off) -#define DSI(off) _REG(DSI_BASE, off) -#define VIC(off) _REG(VIC_BASE, off) -#define TSEC(off) _REG(TSEC_BASE, off) -#define SOR1(off) _REG(SOR1_BASE, off) -#define TMR(off) _REG(TMR_BASE, off) -#define CLOCK(off) _REG(CLOCK_BASE, off) -#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 PWM(off) _REG(PWM_BASE, off) -#define RTC(off) _REG(RTC_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) -#define I2S(off) _REG(I2S_BASE, off) -#define CL_DVFS(off) _REG(CL_DVFS_BASE, off) -#define TEST_REG(off) _REG(0x0, off) - -/* HOST1X registers. */ -#define HOST1X_CH0_SYNC_BASE 0x2100 -#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4) -#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200) - -/*! EVP registers. */ -#define EVP_CPU_RESET_VECTOR 0x100 -#define EVP_COP_RESET_VECTOR 0x200 -#define EVP_COP_UNDEF_VECTOR 0x204 -#define EVP_COP_SWI_VECTOR 0x208 -#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C -#define EVP_COP_DATA_ABORT_VECTOR 0x210 -#define EVP_COP_RSVD_VECTOR 0x214 -#define EVP_COP_IRQ_VECTOR 0x218 -#define EVP_COP_FIQ_VECTOR 0x21C - -/*! Misc registers. */ -#define APB_MISC_PP_STRAPPING_OPT_A 0x08 -#define APB_MISC_PP_PINMUX_GLOBAL 0x40 -#define APB_MISC_GP_HIDREV 0x804 -#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 -#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 -#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 -#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC -#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 -#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 - -/*! System registers. */ -#define AHB_ARBITRATION_XBAR_CTRL 0xE0 -#define AHB_AHB_SPARE_REG 0x110 - -/*! Secure boot registers. */ -#define SB_CSR 0x0 -#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) -#define SB_CSR_PIROM_DISABLE (1 << 4) -#define SB_AA64_RESET_LOW 0x30 -#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0) -#define SB_AA64_RESET_HIGH 0x34 - -/*! SOR registers. */ -#define SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB 0x1E8 -#define SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB 0x21C -#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB 0x208 -#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB 0x20C - -/*! RTC registers. */ -#define APBDEV_RTC_SECONDS 0x8 -#define APBDEV_RTC_SHADOW_SECONDS 0xC -#define APBDEV_RTC_MILLI_SECONDS 0x10 - -/*! SYSCTR0 registers. */ -#define SYSCTR0_CNTFID0 0x20 -#define SYSCTR0_CNTCR 0x00 -#define SYSCTR0_COUNTERID0 0xFE0 -#define SYSCTR0_COUNTERID1 0xFE4 -#define SYSCTR0_COUNTERID2 0xFE8 -#define SYSCTR0_COUNTERID3 0xFEC -#define SYSCTR0_COUNTERID4 0xFD0 -#define SYSCTR0_COUNTERID5 0xFD4 -#define SYSCTR0_COUNTERID6 0xFD8 -#define SYSCTR0_COUNTERID7 0xFDC -#define SYSCTR0_COUNTERID8 0xFF0 -#define SYSCTR0_COUNTERID9 0xFF4 -#define SYSCTR0_COUNTERID10 0xFF8 -#define SYSCTR0_COUNTERID11 0xFFC - -/*! TMR registers. */ -#define TIMERUS_CNTR_1US (0x10 + 0x0) -#define TIMERUS_USEC_CFG (0x10 + 0x4) -#define TIMER_TMR9_TMR_PTV 0x80 -#define TIMER_EN (1 << 31) -#define TIMER_PER_EN (1 << 30) -#define TIMER_WDT4_CONFIG (0x100 + 0x80) -#define TIMER_SRC(TMR) (TMR & 0xF) -#define TIMER_PER(PER) ((PER & 0xFF) << 4) -#define TIMER_SYSRESET_EN (1 << 14) -#define TIMER_PMCRESET_EN (1 << 15) -#define TIMER_WDT4_COMMAND (0x108 + 0x80) -#define TIMER_START_CNT (1 << 0) -#define TIMER_CNT_DISABLE (1 << 1) -#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80) -#define TIMER_MAGIC_PTRN 0xC45A - -/*! I2S registers. */ -#define I2S1_CG 0x88 -#define I2S1_CTRL 0xA0 -#define I2S2_CG 0x188 -#define I2S2_CTRL 0x1A0 -#define I2S3_CG 0x288 -#define I2S3_CTRL 0x2A0 -#define I2S4_CG 0x388 -#define I2S4_CTRL 0x3A0 -#define I2S5_CG 0x488 -#define I2S5_CTRL 0x4A0 -#define I2S_CG_SLCG_ENABLE (1 << 0) -#define I2S_CTRL_MASTER_EN (1 << 10) - -/*! PWM registers. */ -#define PWM_CONTROLLER_PWM_CSR_0 0x00 -#define PWM_CONTROLLER_PWM_CSR_1 0x10 -#define PWM_CSR_EN (1 << 31) - -/*! Special registers. */ -#define EMC_SCRATCH0 0x324 -#define EMC_HEKA_UPD (1 << 30) -#define EMC_SEPT_RUN (1 << 31) - -/*! Flow controller registers. */ -#define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define HALT_COP_SEC (1 << 23) -#define HALT_COP_MSEC (1 << 24) -#define HALT_COP_USEC (1 << 25) -#define HALT_COP_JTAG (1 << 28) -#define HALT_COP_WAIT_EVENT (1 << 30) -#define HALT_COP_WAIT_IRQ (1 << 31) -#define HALT_COP_MAX_CNT 0xFF -#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 -#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 -#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C -#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 -#define FLOW_CTLR_CPU0_CSR 0x8 -#define FLOW_CTLR_CPU1_CSR 0x18 -#define FLOW_CTLR_CPU2_CSR 0x20 -#define FLOW_CTLR_CPU3_CSR 0x28 -#define FLOW_CTLR_RAM_REPAIR 0x40 -#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 - -#endif diff --git a/nyx/nyx_gui/soc/uart.c b/nyx/nyx_gui/soc/uart.c deleted file mode 100644 index 57694c4..0000000 --- a/nyx/nyx_gui/soc/uart.c +++ /dev/null @@ -1,167 +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 "../soc/uart.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -/* UART A, B, C, D and E. */ -static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 }; - -void uart_init(u32 idx, u32 baud) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - // Make sure no data is being sent. - uart_wait_idle(idx, UART_TX_IDLE); - - // Misc settings. - u32 rate = (8 * baud + 408000000) / (16 * baud); - uart->UART_IER_DLAB = 0; // Disable interrupts. - uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode. - uart->UART_THR_DLAB = (u8)rate; // Divisor latch LSB. - uart->UART_IER_DLAB = (u8)(rate >> 8); // Divisor latch MSB. - uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB. - (void)uart->UART_SPR; - - // Setup and flush fifo. - uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO; - (void)uart->UART_SPR; - usleep(20); - uart->UART_MCR = 0; // Disable hardware flow control. - usleep(96); - uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; - - // Wait 3 symbols for baudrate change. - usleep(3 * ((baud + 999999) / baud)); - uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE); -} - -void uart_wait_idle(u32 idx, u32 which) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - if (UART_TX_IDLE & which) - { - while (!(uart->UART_LSR & UART_LSR_TMTY)) - ; - } - if (UART_RX_IDLE & which) - { - while (uart->UART_LSR & UART_LSR_RDR) - ; - } -} - -void uart_send(u32 idx, const u8 *buf, u32 len) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - for (u32 i = 0; i != len; i++) - { - while (!(uart->UART_LSR & UART_LSR_THRE)) - ; - uart->UART_THR_DLAB = buf[i]; - }; -} - -u32 uart_recv(u32 idx, u8 *buf, u32 len) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - u32 timeout = get_tmr_us() + 1000; - u32 i; - - for (i = 0; ; i++) - { - while (!(uart->UART_LSR & UART_LSR_RDR)) - { - if (!len) - { - if (timeout < get_tmr_us()) - break; - } - else if (len < i) - break; - } - if (timeout < get_tmr_us()) - break; - - buf[i] = uart->UART_THR_DLAB; - timeout = get_tmr_us() + 1000; - }; - - return i ? (len ? (i - 1) : i) : 0; -} - -void uart_invert(u32 idx, bool enable, u32 invert_mask) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - if (enable) - uart->UART_IRDA_CSR |= invert_mask; - else - uart->UART_IRDA_CSR &= ~invert_mask; - (void)uart->UART_SPR; -} - -u32 uart_get_IIR(u32 idx) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - return uart->UART_IIR_FCR; -} - -void uart_set_IIR(u32 idx) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD; - (void)uart->UART_SPR; - uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD; - (void)uart->UART_SPR; -} - -void uart_empty_fifo(u32 idx, u32 which) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - uart->UART_MCR = 0; - (void)uart->UART_SPR; - usleep(96); - - uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; - (void)uart->UART_SPR; - usleep(18); - u32 tries = 0; - - if (UART_IIR_FCR_TX_CLR & which) - { - while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY) - { - tries++; - usleep(100); - } - tries = 0; - } - - if (UART_IIR_FCR_RX_CLR & which) - { - while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR) - { - tries++; - usleep(100); - } - } -} diff --git a/nyx/nyx_gui/soc/uart.h b/nyx/nyx_gui/soc/uart.h deleted file mode 100644 index 23dde13..0000000 --- a/nyx/nyx_gui/soc/uart.h +++ /dev/null @@ -1,86 +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 . -*/ - -#ifndef _UART_H_ -#define _UART_H_ - -#include "../utils/types.h" - -#define UART_A 0 -#define UART_B 1 -#define UART_C 2 -#define UART_D 3 -#define UART_E 4 - -#define BAUD_115200 115200 - -#define UART_TX_IDLE 0x1 -#define UART_RX_IDLE 0x2 - -#define UART_TX_FIFO_FULL 0x100 -#define UART_RX_FIFO_EMPTY 0x200 - -#define UART_INVERT_RXD 0x01 -#define UART_INVERT_TXD 0x02 -#define UART_INVERT_CTS 0x04 -#define UART_INVERT_RTS 0x08 - -#define UART_IER_DLAB_IE_EORD 0x20 - -#define UART_LCR_DLAB 0x80 -#define UART_LCR_STOP 0x4 -#define UART_LCR_WORD_LENGTH_8 0x3 - -#define UART_LSR_RDR 0x1 -#define UART_LSR_THRE 0x20 -#define UART_LSR_TMTY 0x40 -#define UART_LSR_FIFOE 0x80 - -#define UART_IIR_FCR_TX_CLR 0x4 -#define UART_IIR_FCR_RX_CLR 0x2 -#define UART_IIR_FCR_EN_FIFO 0x1 - -#define UART_MCR_RTS 0x2 -#define UART_MCR_DTR 0x1 - -typedef struct _uart_t -{ - /* 0x00 */ vu32 UART_THR_DLAB; - /* 0x04 */ vu32 UART_IER_DLAB; - /* 0x08 */ vu32 UART_IIR_FCR; - /* 0x0C */ vu32 UART_LCR; - /* 0x10 */ vu32 UART_MCR; - /* 0x14 */ vu32 UART_LSR; - /* 0x18 */ vu32 UART_MSR; - /* 0x1C */ vu32 UART_SPR; - /* 0x20 */ vu32 UART_IRDA_CSR; - /* 0x24 */ vu32 UART_RX_FIFO_CFG; - /* 0x28 */ vu32 UART_MIE; - /* 0x2C */ vu32 UART_VENDOR_STATUS; - /* 0x30 */ u8 _pad_30[0xC]; - /* 0x3C */ vu32 UART_ASR; -} uart_t; - -void uart_init(u32 idx, u32 baud); -void uart_wait_idle(u32 idx, u32 which); -void uart_send(u32 idx, const u8 *buf, u32 len); -u32 uart_recv(u32 idx, u8 *buf, u32 len); -void uart_invert(u32 idx, bool enable, u32 invert_mask); -u32 uart_get_IIR(u32 idx); -void uart_set_IIR(u32 idx); -void uart_empty_fifo(u32 idx, u32 which); - -#endif diff --git a/nyx/nyx_gui/start.S b/nyx/nyx_gui/start.S index c520ef1..c2333f7 100644 --- a/nyx/nyx_gui/start.S +++ b/nyx/nyx_gui/start.S @@ -23,8 +23,8 @@ .extern memset .type memset, %function -.extern ipl_main -.type ipl_main, %function +.extern _irq_setup +.type _irq_setup, %function .globl _start .type _start, %function @@ -36,7 +36,7 @@ _start: /* If we are not in the right location already, copy a relocator to upper IRAM. */ ADR R2, _reloc_ipl - LDR R3, =0x4003FFE0 + LDR R3, =0x4003FF00 MOV R4, #(_real_start - _reloc_ipl) _copy_loop: LDMIA R2!, {R5} @@ -48,7 +48,7 @@ _copy_loop: LDR R2, =__ipl_end SUB R2, R2, R1 LDR R3, =_real_start - LDR R4, =0x4003FFE0 + LDR R4, =0x4003FF00 BX R4 _reloc_ipl: @@ -60,14 +60,14 @@ _reloc_ipl: BX R3 _real_start: - /* Initially, we place our stack in IRAM but will move it to SDRAM later. */ - LDR SP, =0x90010000 + /* We place our stack in SDRAM. */ + LDR SP, =0x4003F000 LDR R0, =__bss_start EOR R1, R1, R1 LDR R2, =__bss_end SUB R2, R2, R0 BL memset - BL ipl_main + BL _irq_setup B . .globl pivot_stack diff --git a/nyx/nyx_gui/storage/nx_emmc.c b/nyx/nyx_gui/storage/nx_emmc.c deleted file mode 100644 index 01bb694..0000000 --- a/nyx/nyx_gui/storage/nx_emmc.c +++ /dev/null @@ -1,77 +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 - -#include "nx_emmc.h" -#include "../mem/heap.h" -#include "../utils/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; - - // ASCII conversion. Copy only the LSByte of the UTF-16LE name. - for (u32 i = 0; i < 36; i++) - part->name[i] = ent->name[i]; - part->name[36] = 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/nyx/nyx_gui/storage/nx_emmc.h b/nyx/nyx_gui/storage/nx_emmc.h deleted file mode 100644 index 753d5aa..0000000 --- a/nyx/nyx_gui/storage/nx_emmc.h +++ /dev/null @@ -1,72 +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 . - */ - -#ifndef _NX_EMMC_H_ -#define _NX_EMMC_H_ - -#include "../utils/types.h" -#include "../utils/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; - char 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/nyx/nyx_gui/storage/sd.h b/nyx/nyx_gui/storage/sd.h deleted file mode 100644 index fafd322..0000000 --- a/nyx/nyx_gui/storage/sd.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * include/linux/mmc/sd.h - * - * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. - * Copyright (c) 2018 CTCaer - * - * 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 */ -#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ -#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ -#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ - -/* -* 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 */ -#define SD_SCR_BUS_WIDTH_1 (1<<0) -#define SD_SCR_BUS_WIDTH_4 (1<<2) - -/* -* SD bus widths -*/ -#define SD_BUS_WIDTH_1 0 -#define SD_BUS_WIDTH_4 2 - -/* -* SD bus speeds -*/ -#define UHS_SDR12_BUS_SPEED 0 -#define HIGH_SPEED_BUS_SPEED 1 -#define UHS_SDR25_BUS_SPEED 1 -#define UHS_SDR50_BUS_SPEED 2 -#define UHS_SDR104_BUS_SPEED 3 -#define UHS_DDR50_BUS_SPEED 4 -#define HS400_BUS_SPEED 5 - -#define SD_MODE_HIGH_SPEED (1 << HIGH_SPEED_BUS_SPEED) -#define SD_MODE_UHS_SDR12 (1 << UHS_SDR12_BUS_SPEED) -#define SD_MODE_UHS_SDR25 (1 << UHS_SDR25_BUS_SPEED) -#define SD_MODE_UHS_SDR50 (1 << UHS_SDR50_BUS_SPEED) -#define SD_MODE_UHS_SDR104 (1 << UHS_SDR104_BUS_SPEED) -#define SD_MODE_UHS_DDR50 (1 << UHS_DDR50_BUS_SPEED) - -#define SD_DRIVER_TYPE_B 0x01 -#define SD_DRIVER_TYPE_A 0x02 - -#define SD_SET_CURRENT_LIMIT_200 0 -#define SD_SET_CURRENT_LIMIT_400 1 -#define SD_SET_CURRENT_LIMIT_600 2 -#define SD_SET_CURRENT_LIMIT_800 3 - -/* -* 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/nyx/nyx_gui/storage/sdmmc.c b/nyx/nyx_gui/storage/sdmmc.c deleted file mode 100644 index e823a05..0000000 --- a/nyx/nyx_gui/storage/sdmmc.c +++ /dev/null @@ -1,1238 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer - * - * 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 "../../../common/memory_map.h" -#include "../gfx/gfx.h" -#include "../mem/heap.h" -#include "../utils/util.h" - -//#define DPRINTF(...) gfx_printf(__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 9 times on error. - u32 retries = 10; - do - { - if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) - goto out; - else - retries--; - - msleep(100); - } while (retries); - - return 0; - -out:; -DPRINTF("readwrite: %08X\n", blkcnt); - sector += blkcnt; - num_sectors -= blkcnt; - bbuf += 512 * blkcnt; - } - - return 1; -} - -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 = SD_OCR_CCS | SD_OCR_VDD_18; - break; - case SDMMC_POWER_3_3: - arg = SD_OCR_CCS | SD_OCR_VDD_27_34; - 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_ms() + 1500; - - while (1) - { - u32 cond = 0; - if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) - break; - - if (cond & MMC_CARD_BUSY) - { - if (cond & SD_OCR_CCS) - storage->has_sector_access = 1; - - return 1; - } - if (get_tmr_ms() > timeout) - break; - - usleep(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 void _mmc_storage_parse_cid(sdmmc_storage_t *storage) -{ - u32 *raw_cid = (u32 *)&(storage->raw_cid); - - switch (storage->csd.mmca_vsn) - { - case 0: /* MMC v1.0 - v1.2 */ - case 1: /* MMC v1.4 */ - storage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8); - storage->cid.manfid = unstuff_bits(raw_cid, 104, 24); - storage->cid.hwrev = unstuff_bits(raw_cid, 44, 4); - storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4); - storage->cid.serial = unstuff_bits(raw_cid, 16, 24); - break; - case 2: /* MMC v2.0 - v2.2 */ - case 3: /* MMC v3.1 - v3.3 */ - case 4: /* MMC v4 */ - storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); - storage->cid.card_bga = unstuff_bits(raw_cid, 112, 2); - storage->cid.oemid = unstuff_bits(raw_cid, 104, 8); - storage->cid.prv = unstuff_bits(raw_cid, 48, 8); - storage->cid.serial = unstuff_bits(raw_cid, 16, 32); - break; - default: - break; - } - - storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); - storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); - storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); - storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); - storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); - storage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8); - - storage->cid.month = unstuff_bits(raw_cid, 12, 4); - storage->cid.year = unstuff_bits(raw_cid, 8, 4) + 1997; - if (storage->ext_csd.rev >= 5) - { - if (storage->cid.year < 2010) - storage->cid.year += 16; - } -} - -static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) -{ - u32 *raw_csd = (u32 *)&(storage->raw_csd); - - storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); - storage->csd.structure = unstuff_bits(raw_csd, 126, 2); - storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); - storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); - storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); -} - -static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) -{ - storage->ext_csd.rev = buf[EXT_CSD_REV]; - storage->ext_csd.ext_struct = buf[EXT_CSD_STRUCTURE]; - storage->ext_csd.card_type = buf[EXT_CSD_CARD_TYPE]; - storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION]; - storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT]; - storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT]; - storage->ext_csd.sectors = *(u32 *)&buf[EXT_CSD_SEC_CNT]; - storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; - storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; - storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; - - storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; -} - -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); - _mmc_storage_parse_ext_csd(storage, buf); - - 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"); - storage->csd.busspeed = 52; - - 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"); - storage->csd.busspeed = 200; - - 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"); - storage->csd.busspeed = 400; - - 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"); - - usleep(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->raw_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->raw_csd)) - return 0; -DPRINTF("[MMC] got csd\n"); - _mmc_storage_parse_csd(storage); - - 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->raw_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; - } - free(ext_csd); -DPRINTF("[MMC] got ext_csd\n"); - _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd - //gfx_hexdump(0, ext_csd, 512); - - /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. - Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). - Additionally this works only when we put the device in idle mode which we don't after enabling it. */ - if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) - { - _mmc_storage_enable_bkops(storage); -DPRINTF("[MMC] BKOPS enabled\n"); - } - else - { -DPRINTF("[MMC] BKOPS disabled\n"); - } - - if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) - return 0; -DPRINTF("[MMC] succesfully switched to HS mode\n"); - - sdmmc_sd_clock_ctrl(storage->sdmmc, 1); - - 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 1; // The SD Card is version 1.X - - u32 resp = 0; - if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5)) - return 2; - - return (resp & 0xFF) == 0xAA ? 0 : 2; -} - -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; - // Support for Current > 150mA - u32 arg = (~is_version_1 & 1) ? SD_OCR_XPC : 0; - // Support for handling block-addressed SDHC cards - arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0; - // Support for 1.8V - arg |= (supports_low_voltage & ~is_version_1 & 1) ? SD_OCR_S18R : 0; - // This is needed for most cards. Do not set bit7 even if 1.8V is supported. - arg |= SD_OCR_VDD_32_33; - 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_ms() + 1500; - - while (1) - { - u32 cond = 0; - if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage)) - break; - if (cond & MMC_CARD_BUSY) - { - if (cond & SD_OCR_CCS) - storage->has_sector_access = 1; - - if (cond & SD_ROCR_S18A && 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_ms() > timeout) - break; - msleep(10); // Needs to be at least 10ms for some SD Cards - } - - 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_ms() + 1500; - - 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_ms() > timeout) - break; - usleep(1000); - } - - return 0; -} - -static void _sd_storage_parse_scr(sdmmc_storage_t *storage) -{ - // unstuff_bits can parse only 4 u32 - u32 resp[4]; - - resp[3] = *(u32 *)&storage->raw_scr[4]; - resp[2] = *(u32 *)&storage->raw_scr[0]; - - storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); - storage->scr.bus_widths = unstuff_bits(resp, 48, 4); - if (storage->scr.sda_vsn == SCR_SPEC_VER_2) - /* Check if Physical Layer Spec v3.0 is supported */ - storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); - if (storage->scr.sda_spec3) - storage->scr.cmds = unstuff_bits(resp, 32, 2); -} - -int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *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); - //Prepare buffer for unstuff_bits - for (int i = 0; i < 8; i+=4) - { - storage->raw_scr[i + 3] = buf[i]; - storage->raw_scr[i + 2] = buf[i + 1]; - storage->raw_scr[i + 1] = buf[i + 2]; - storage->raw_scr[i] = buf[i + 3]; - } - _sd_storage_parse_scr(storage); - //gfx_hexdump(0, storage->raw_scr, 8); - - 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 mode, int group, u32 arg) -{ - sdmmc_cmd_t cmdbuf; - u32 switchcmd = mode << 31 | 0x00FFFFFF; - switchcmd &= ~(0xF << (group * 4)); - switchcmd |= arg << (group * 4); - sdmmc_init_cmd(&cmdbuf, SD_SWITCH, switchcmd, 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); -} - -void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) -{ - u32 pwr = SD_SET_CURRENT_LIMIT_800; - _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - - while (pwr > 0) - { - pwr--; - _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - if (((buf[15] >> 4) & 0x0F) == pwr) - break; - } - - switch (pwr) - { - case SD_SET_CURRENT_LIMIT_800: -DPRINTF("[SD] power limit raised to 800mA\n"); - break; - case SD_SET_CURRENT_LIMIT_600: -DPRINTF("[SD] power limit raised to 600mA\n"); - break; - case SD_SET_CURRENT_LIMIT_400: -DPRINTF("[SD] power limit raised to 800mA\n"); - break; - default: - case SD_SET_CURRENT_LIMIT_200: -DPRINTF("[SD] power limit defaulted to 200mA\n"); - break; - } -} - -int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) -{ - if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) - return 0; -DPRINTF("[SD] SD supports switch to (U)HS check\n"); - - u32 type_out = buf[16] & 0xF; - if (type_out != hs_type) - return 0; -DPRINTF("[SD] SD supports selected (U)HS mode\n"); - - if ((((u16)buf[0] << 8) | buf[1]) < 0x320) - { - if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type)) - return 0; - - if (type_out != (buf[16] & 0xF)) - return 0; - } - - return 1; -} - -int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) -{ - // Try to raise the current limit to let the card perform better. - _sd_storage_set_current_limit(storage, buf); - - if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) - return 0; - - if (!_sd_storage_switch_get(storage, buf)) - return 0; - //gfx_hexdump(0, (u8 *)buf, 64); - - u32 hs_type = 0; - switch (type) - { - case 11: // SDR104. - // Fall through if not supported. - if (buf[13] & SD_MODE_UHS_SDR104) - { - type = 11; - hs_type = UHS_SDR104_BUS_SPEED; -DPRINTF("[SD] bus speed set to SDR104\n"); - storage->csd.busspeed = 104; - break; - } - case 10: // SDR50. - if (buf[13] & SD_MODE_UHS_SDR50) - { - type = 10; - hs_type = UHS_SDR50_BUS_SPEED; -DPRINTF("[SD] bus speed set to SDR50\n"); - storage->csd.busspeed = 50; - break; - } - case 8: // SDR12. - if (!(buf[13] & SD_MODE_UHS_SDR12)) - return 0; - type = 8; - hs_type = UHS_SDR12_BUS_SPEED; -DPRINTF("[SD] bus speed set to SDR12\n"); - storage->csd.busspeed = 12; - break; - default: - return 0; - break; - } - - if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) - return 0; -DPRINTF("[SD] SD card accepted UHS\n"); - if (!sdmmc_setup_clock(storage->sdmmc, type)) - return 0; -DPRINTF("[SD] setup clock\n"); - if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) - return 0; -DPRINTF("[SD] config tuning\n"); - return _sdmmc_storage_check_status(storage); -} - -int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) -{ - if (!_sd_storage_switch_get(storage, buf)) - return 0; - //gfx_hexdump(0, (u8 *)buf, 64); - if (!(buf[13] & SD_MODE_HIGH_SPEED)) - 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); -} - -static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) -{ - // unstuff_bits supports only 4 u32 so break into 2 x 16byte groups - u32 raw_ssr1[4]; - u32 raw_ssr2[4]; - - raw_ssr1[3] = *(u32 *)&storage->raw_ssr[12]; - raw_ssr1[2] = *(u32 *)&storage->raw_ssr[8]; - raw_ssr1[1] = *(u32 *)&storage->raw_ssr[4]; - raw_ssr1[0] = *(u32 *)&storage->raw_ssr[0]; - - raw_ssr2[3] = *(u32 *)&storage->raw_ssr[28]; - raw_ssr2[2] = *(u32 *)&storage->raw_ssr[24]; - raw_ssr2[1] = *(u32 *)&storage->raw_ssr[20]; - raw_ssr2[0] = *(u32 *)&storage->raw_ssr[16]; - - storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1; - switch(unstuff_bits(raw_ssr1, 440 - 384, 8)) - { - case 0: - storage->ssr.speed_class = 0; - break; - case 1: - storage->ssr.speed_class = 2; - break; - case 2: - storage->ssr.speed_class = 4; - break; - case 3: - storage->ssr.speed_class = 6; - break; - case 4: - storage->ssr.speed_class = 10; - break; - default: - storage->ssr.speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8); - break; - } - storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4); - storage->ssr.video_class = unstuff_bits(raw_ssr1, 384 - 384, 8); - - storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4); -} - -static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) -{ - sdmmc_cmd_t cmdbuf; - sdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, 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 (!(storage->csd.cmdclass & CCC_APP_SPEC)) - { -DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); - return 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); - //Prepare buffer for unstuff_bits - for (int i = 0; i < 64; i+=4) - { - storage->raw_ssr[i + 3] = buf[i]; - storage->raw_ssr[i + 2] = buf[i + 1]; - storage->raw_ssr[i + 1] = buf[i + 2]; - storage->raw_ssr[i] = buf[i + 3]; - } - _sd_storage_parse_ssr(storage); - //gfx_hexdump(0, storage->raw_ssr, 64); - - return _sdmmc_storage_check_result(tmp); -} - -static void _sd_storage_parse_cid(sdmmc_storage_t *storage) -{ - u32 *raw_cid = (u32 *)&(storage->raw_cid); - - storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); - storage->cid.oemid = unstuff_bits(raw_cid, 104, 16); - storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); - storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); - storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); - storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); - storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); - storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4); - storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4); - storage->cid.serial = unstuff_bits(raw_cid, 24, 32); - storage->cid.month = unstuff_bits(raw_cid, 8, 4); - storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000; -} - -static void _sd_storage_parse_csd(sdmmc_storage_t *storage) -{ - u32 *raw_csd = (u32 *)&(storage->raw_csd); - - storage->csd.structure = unstuff_bits(raw_csd, 126, 2); - storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); - storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); - storage->csd.write_protect = unstuff_bits(raw_csd, 12, 2); - switch(storage->csd.structure) - { - case 0: - storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); - break; - case 1: - storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22)); - storage->csd.capacity = storage->csd.c_size << 10; - storage->csd.read_blkbits = 9; - break; - } -} - -void sdmmc_storage_init_wait_sd() -{ - u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; - if (sd_poweroff_time < 100) - msleep(100 - sd_poweroff_time); -} - -int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) -{ - int is_version_1 = 0; - u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - - // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. - sdmmc_storage_init_wait_sd(); - - 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"); - - usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); - - if (!_sdmmc_storage_go_idle_state(storage)) - return 0; -DPRINTF("[SD] went to idle state\n"); - - is_version_1 = _sd_storage_send_if_cond(storage); - if (is_version_1 == 2) - return 0; -DPRINTF("[SD] after send if cond\n"); - - if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11)) - return 0; -DPRINTF("[SD] got op cond\n"); - - if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) - return 0; -DPRINTF("[SD] got cid\n"); - _sd_storage_parse_cid(storage); - - if (!_sd_storage_get_rca(storage)) - return 0; -DPRINTF("[SD] got rca (= %04X)\n", storage->rca); - - if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) - return 0; -DPRINTF("[SD] got csd\n"); - - //Parse CSD. - _sd_storage_parse_csd(storage); - switch (storage->csd.structure) - { - case 0: - storage->sec_cnt = storage->csd.capacity; - break; - case 1: - storage->sec_cnt = storage->csd.c_size << 10; - break; - default: -DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); - 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"); - - if (!_sd_storage_get_scr(storage, buf)) - return 0; - - //gfx_hexdump(0, storage->raw_scr, 8); -DPRINTF("[SD] got scr\n"); - - // Check if card supports a wider bus and if it's not SD Version 1.X - if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) - { - if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) - 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_uhs_low_volt(storage, type, buf)) - return 0; -DPRINTF("[SD] enabled UHS\n"); - } - else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) - { - if (!_sd_storage_enable_hs_high_volt(storage, buf)) - return 0; - -DPRINTF("[SD] enabled HS\n"); - storage->csd.busspeed = 25; - } - - sdmmc_sd_clock_ctrl(sdmmc, 1); - - // Parse additional card info from sd status. - if (_sd_storage_get_ssr(storage, buf)) - { -DPRINTF("[SD] got sd status\n"); - } - - 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 = 64; - 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"); - - usleep(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/nyx/nyx_gui/storage/sdmmc.h b/nyx/nyx_gui/storage/sdmmc.h deleted file mode 100644 index c8b8f96..0000000 --- a/nyx/nyx_gui/storage/sdmmc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "../utils/types.h" -#include "sdmmc_driver.h" - -u32 sd_power_cycle_time_start; - -typedef struct _mmc_cid -{ - u32 manfid; - u8 prod_name[8]; - u8 card_bga; - u8 prv; - u32 serial; - u16 oemid; - u16 year; - u8 hwrev; - u8 fwrev; - u8 month; -} mmc_cid_t; - -typedef struct _mmc_csd -{ - u8 structure; - u8 mmca_vsn; - u16 cmdclass; - u32 c_size; - u32 r2w_factor; - u32 max_dtr; - u32 erase_size; /* In sectors */ - u32 read_blkbits; - u32 write_blkbits; - u32 capacity; - u8 write_protect; - u16 busspeed; -} mmc_csd_t; - -typedef struct _mmc_ext_csd -{ - u8 rev; - u32 sectors; - int bkops; /* background support bit */ - int bkops_en; /* manual bkops enable bit */ - u8 ext_struct; /* 194 */ - u8 card_type; /* 196 */ - u8 bkops_status; /* 246 */ - u16 dev_version; - u8 boot_mult; - u8 rpmb_mult; -} mmc_ext_csd_t; - -typedef struct _sd_scr -{ - u8 sda_vsn; - u8 sda_spec3; - u8 bus_widths; - u8 cmds; -} sd_scr_t; - -typedef struct _sd_ssr -{ - u8 bus_width; - u8 speed_class; - u8 uhs_grade; - u8 video_class; - u8 app_class; -} sd_ssr_t; - -/*! 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 raw_cid[0x10]; - u8 raw_csd[0x10]; - u8 raw_scr[8]; - u8 raw_ssr[0x40]; - mmc_cid_t cid; - mmc_csd_t csd; - mmc_ext_csd_t ext_csd; - sd_scr_t scr; - sd_ssr_t ssr; -} 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); -void sdmmc_storage_init_wait_sd(); -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/nyx/nyx_gui/storage/sdmmc_driver.c b/nyx/nyx_gui/storage/sdmmc_driver.c deleted file mode 100644 index 57d20f9..0000000 --- a/nyx/nyx_gui/storage/sdmmc_driver.c +++ /dev/null @@ -1,1148 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer - * - * 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 "mmc.h" -#include "sdmmc.h" -#include "../gfx/gfx.h" -#include "../power/max7762x.h" -#include "../soc/bpmp.h" -#include "../soc/clock.h" -#include "../soc/gpio.h" -#include "../soc/pinmux.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -//#define DPRINTF(...) gfx_printf(__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) -{ - u8 pwr = 0; - - switch (power) - { - case SDMMC_POWER_OFF: - sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER; - break; - case SDMMC_POWER_1_8: - sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; - pwr = 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; - pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; - break; - default: - return 0; - } - - if (power != SDMMC_POWER_OFF) - { - pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; - sdmmc->regs->pwrcon = pwr; - } - - 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->ventunctl0 &= 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); - switch (sdmmc->id) - { - case SDMMC_1: - if (power == SDMMC_POWER_OFF) - break; - if (power == SDMMC_POWER_1_8) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x304; // Up: 3, Dn: 4. - else if (power == SDMMC_POWER_3_3) - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x808; // Up: 8, Dn: 8. - break; - case SDMMC_4: - APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0x3FFC) | 0x1040; - break; - } - //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->vendllcal |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 5; - while (sdmmc->regs->vendllcal & 0x80000000) - { - if (get_tmr_ms() > timeout) - { - res = 0; - goto out; - } - } - - timeout = get_tmr_ms() + 10; - while (sdmmc->regs->dllcfgstatus & 0x80000000) - { - if (get_tmr_ms() > 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. - bool should_enable_sd_clock = false; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = true; - 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; // Should this be 0xFFFB (~4) ? - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; - break; - case 2: - case 7: - sdmmc->regs->hostctl |= 4; - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; - break; - case 3: - case 11: - case 13: - case 14: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 4: - // Non standard. - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 8: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 10: - // T210 Errata for SDR50, the host must be set to SDR104. - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - } - - _sdmmc_get_clkcon(sdmmc); - - u32 tmp; - u16 divisor; - clock_sdmmc_get_card_clock_div(&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; - // CRC is stripped, so shifting is needed. - u32 tempreg; - for (int i = 0; i < 4; i++) - { - switch(i) - { - case 0: - tempreg = sdmmc->regs->rspreg3; - break; - case 1: - tempreg = sdmmc->regs->rspreg2; - break; - case 2: - tempreg = sdmmc->regs->rspreg1; - break; - case 3: - tempreg = sdmmc->regs->rspreg0; - break; - } - rsp[i] = tempreg << 8; - - if (i != 0) - rsp[i - 1] |= (tempreg >> 24) & 0xFF; - } - 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_ms() + 2000; - while (sdmmc->regs->swrst << 29 >> 30 && get_tmr_ms() < timeout) - ; -} - -static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) -{ - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 2000; - while(sdmmc->regs->prnsts & 1) // CMD inhibit. - if (get_tmr_ms() > timeout) - { - _sdmmc_reset(sdmmc); - return 0; - } - - if (wait_dat) - { - timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->prnsts & 2) // DAT inhibit. - if (get_tmr_ms() > 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_ms() + 2000; - while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level. - if (get_tmr_ms() > 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, bool 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, true); -} - -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); - usleep(1); - - _sdmmc_reset(sdmmc); - - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_us() + 5000; - while (get_tmr_us() < timeout) - { - if (sdmmc->regs->norintsts & 0x20) - { - sdmmc->regs->norintsts = 0x20; - sdmmc->regs->norintstsen &= 0xFFDF; - _sdmmc_get_clkcon(sdmmc); - usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); - return 1; - } - } - - _sdmmc_reset(sdmmc); - - sdmmc->regs->norintstsen &= 0xFFDF; - _sdmmc_get_clkcon(sdmmc); - usleep((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->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier. - sdmmc->regs->ventunctl0 |= 0x20000; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; - - for (u32 i = 0; i < max; i++) - { - _sdmmc_config_tuning_once(sdmmc, cmd); - if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) - break; - } - - if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) - 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_ms() + 2000; - while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) - { - if (get_tmr_ms() > timeout) - return 0; - } - - sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT; - sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; - - if (!(sdmmc->regs->capareg & 0x10000000)) - return 0; - - sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; - 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) -{ - bool should_enable_sd_clock = false; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = true; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - - if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000)) - { - sdmmc->regs->sdmemcmppadctl |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - } - - sdmmc->regs->autocalcfg |= 0xA0000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - - u32 timeout = get_tmr_ms() + 10; - while (sdmmc->regs->autocalcfg & 0x80000000) - { - if (get_tmr_ms() > 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_ms() + 2000; - 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_ms() > 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, false); - - 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; - - bool should_disable_sd_clock = false; - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - { - should_disable_sd_clock = true; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - } - - int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); - usleep((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; - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - 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_ms() + 1500; - 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) - { - bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); - 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_ms() < 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; - bool is_data_present = false; - if (req) - { - _sdmmc_config_dma(sdmmc, &blkcnt, req); - _sdmmc_enable_interrupts(sdmmc); - is_data_present = true; - } - else - { - _sdmmc_enable_interrupts(sdmmc); - is_data_present = false; - } - - _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) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //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); - usleep(100); - - // Check if SD card is inserted. - 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; // Enable deep loopback for SDMMC1 CLK pad. - PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED; - PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - - // 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) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //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); - - usleep(1000); - - // Enable SD card power. - max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); - max77620_regulator_enable(REGULATOR_LDO2, 1); - - usleep(1000); - - // For good measure. - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; - - usleep(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_card_clock_div(&clock, &divisor, type); - clock_sdmmc_enable(id, clock); - - sdmmc->clock_stopped = 0; - - //TODO: make this skip-able. - sdmmc->regs->iospare |= 0x80000; - sdmmc->regs->veniotrimctl &= 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); - // Disable SDMMC power. - _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); - - // Disable SD card power. - if (sdmmc->id == SDMMC_1) - { - gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); - max77620_regulator_enable(REGULATOR_LDO2, 0); - sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. - usleep(1000); // To power cycle, min 1ms without power is needed. - } - - _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); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - } - - int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); - usleep((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); - - // Enable schmitt trigger for better duty cycle and low jitter clock. - PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; - PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; - - 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); - msleep(5); - - if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) - { - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep(1000); - if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) - return 1; - } - - return 0; -} diff --git a/nyx/nyx_gui/storage/sdmmc_driver.h b/nyx/nyx_gui/storage/sdmmc_driver.h deleted file mode 100644 index cf9b9e1..0000000 --- a/nyx/nyx_gui/storage/sdmmc_driver.h +++ /dev/null @@ -1,126 +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 . - */ - -#ifndef _SDMMC_DRIVER_H_ -#define _SDMMC_DRIVER_H_ - -#include "../utils/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 - -/*! SDMMC host control 2 */ -#define SDHCI_CTRL_UHS_MASK 0xFFF8 -#define SDHCI_CTRL_VDD_330 0xFFF7 -#define SDHCI_CTRL_VDD_180 8 -#define SDHCI_CTRL_EXEC_TUNING 0x40 -#define SDHCI_CTRL_TUNED_CLK 0x80 -#define SDHCI_HOST_VERSION_4_EN 0x1000 -#define SDHCI_ADDRESSING_64BIT_EN 0x2000 -#define SDHCI_CTRL_PRESET_VAL_EN 0x8000 - -/*! SD bus speeds. */ -#define UHS_SDR12_BUS_SPEED 0 -#define HIGH_SPEED_BUS_SPEED 1 -#define UHS_SDR25_BUS_SPEED 1 -#define UHS_SDR50_BUS_SPEED 2 -#define UHS_SDR104_BUS_SPEED 3 -#define UHS_DDR50_BUS_SPEED 4 -#define HS400_BUS_SPEED 5 - -/*! 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/nyx/nyx_gui/storage/sdmmc_t210.h b/nyx/nyx_gui/storage/sdmmc_t210.h deleted file mode 100644 index e11c3ff..0000000 --- a/nyx/nyx_gui/storage/sdmmc_t210.h +++ /dev/null @@ -1,132 +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 . - */ - -#ifndef _SDMMC_T210_H_ -#define _SDMMC_T210_H_ - -#include "../utils/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 veniotrimctl; - vu32 vendllcal; - vu8 res7[8]; - vu32 dllcfgstatus; - vu32 ventunctl0; - vu32 field_1C4; - vu8 field_1C8[24]; - vu32 sdmemcmppadctl; - vu32 autocalcfg; - vu32 autocalintval; - vu32 autocalsts; - vu32 iospare; -} t210_sdmmc_t; - -#endif diff --git a/nyx/nyx_gui/thermal/fan.c b/nyx/nyx_gui/thermal/fan.c deleted file mode 100644 index f142638..0000000 --- a/nyx/nyx_gui/thermal/fan.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Fan driver for Nintendo Switch - * - * Copyright (c) 2018 CTCaer - * - * 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 "fan.h" -#include "../power/regulator_5v.h" -#include "../soc/gpio.h" -#include "../soc/pinmux.h" -#include "../soc/t210.h" -#include "../utils/util.h" - -void set_fan_duty(u32 duty) -{ - static bool fan_init = false; - static u16 curr_duty = -1; - - if (curr_duty == duty) - return; - - if (!fan_init) - { - // Fan tachometer. - PINMUX_AUX(PINMUX_AUX_CAM1_PWDN) = PINMUX_TRISTATE | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; - gpio_config(GPIO_PORT_S, GPIO_PIN_7, GPIO_MODE_GPIO); - gpio_output_enable(GPIO_PORT_S, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); - gpio_write(GPIO_PORT_S, GPIO_PIN_7, GPIO_LOW); - - PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Max PWM to disable fan. - - PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. - gpio_config(GPIO_PORT_V, GPIO_PIN_4, GPIO_MODE_SPIO); // Fan power mode. - - fan_init = true; - } - - if (duty > 236) - duty = 236; - - // Inverted polarity. - u32 inv_duty = 236 - duty; - - // If disabled send a 0 duty. - if (inv_duty == 236) - { - PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Bit 24 is absolute 0%. - regulator_disable_5v(REGULATOR_5V_FAN); - } - else // Set PWM duty. - { - // Fan power supply. - regulator_enable_5v(REGULATOR_5V_FAN); - PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (inv_duty << 16); - } - - curr_duty = duty; -} - -void get_fan_speed(u32 *duty, u32 *rpm) -{ - if (rpm) - { - u32 irq_count = 1; - bool should_read = true; - bool irq_val = 0; - - // Poll irqs for 2 seconds. - int timer = get_tmr_us() + 1000000; - while (timer - get_tmr_us()) - { - irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7); - if (irq_val && should_read) - { - irq_count++; - should_read = false; - } - else if (!irq_val) - should_read = true; - } - - // Calculate rpm based on triggered interrupts. - *rpm = 60000000 / ((1000000 * 2) / irq_count); - } - - if (duty) - *duty = 236 - ((PWM(PWM_CONTROLLER_PWM_CSR_1) >> 16) & 0xFF); -} diff --git a/nyx/nyx_gui/utils/btn.c b/nyx/nyx_gui/utils/btn.c deleted file mode 100644 index 63a983a..0000000 --- a/nyx/nyx_gui/utils/btn.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 "btn.h" -#include "../soc/i2c.h" -#include "../soc/gpio.h" -#include "../soc/t210.h" -#include "util.h" -#include "../power/max77620.h" - -u8 btn_read() -{ - u8 res = 0; - if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) - res |= BTN_VOL_DOWN; - if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) - res |= BTN_VOL_UP; - if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4) - res |= BTN_POWER; - return res; -} - -u8 btn_wait() -{ - u8 res = 0, btn = btn_read(); - bool pwr = false; - - //Power button down, raise a filter. - if (btn & BTN_POWER) - { - pwr = true; - btn &= ~BTN_POWER; - } - - do - { - res = btn_read(); - //Power button up, remove filter. - if (!(res & BTN_POWER) && pwr) - pwr = false; - else if (pwr) //Power button still down. - res &= ~BTN_POWER; - } while (btn == res); - - return res; -} - -u8 btn_wait_timeout(u32 time_ms, u8 mask) -{ - u32 timeout = get_tmr_ms() + time_ms; - u8 res = btn_read() & mask; - - while (get_tmr_ms() < timeout) - { - if (res == mask) - break; - else - res = btn_read() & mask; - }; - - return res; -} diff --git a/nyx/nyx_gui/utils/dirlist.h b/nyx/nyx_gui/utils/dirlist.h deleted file mode 100644 index 9ad3c38..0000000 --- a/nyx/nyx_gui/utils/dirlist.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2018 CTCaer - * - * 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 "../utils/types.h" - -char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs); diff --git a/nyx/nyx_gui/utils/sprintf.c b/nyx/nyx_gui/utils/sprintf.c deleted file mode 100644 index 1b969d2..0000000 --- a/nyx/nyx_gui/utils/sprintf.c +++ /dev/null @@ -1,149 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2019 CTCaer -* -* 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 - -#include "types.h" - -char **sout_buf; - -static void _s_putc(char c) -{ - **sout_buf = c; - *sout_buf += 1; -} - -static void _s_puts(char *s) -{ - for (; *s; s++) - _s_putc(*s); -} - -static void _s_putn(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--; - } - } - - _s_puts(p); -} - -static void _s_putp(u32 *v, int base, char fill, int fcnt) -{ - _s_putn(*v, base, fill, fcnt); -} - -void s_printf(char *out_buf, const char *fmt, ...) -{ - va_list ap; - int fill, fcnt; - - sout_buf = &out_buf; - - 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': - _s_putc(va_arg(ap, u32)); - break; - case 's': - _s_puts(va_arg(ap, char *)); - break; - case 'd': - _s_putn(va_arg(ap, u32), 10, fill, fcnt); - break; - case 'p': - case 'P': - _s_putp(va_arg(ap, u32*), 16, fill, fcnt); - break; - case 'x': - case 'X': - _s_putn(va_arg(ap, u32), 16, fill, fcnt); - break; - case 'k': - //gfx_con.fgcol = va_arg(ap, u32); - break; - case 'K': - //gfx_con.bgcol = va_arg(ap, u32); - //gfx_con.fillbg = 1; - break; - case '%': - _s_putc('%'); - break; - case '\0': - goto out; - default: - _s_putc('%'); - _s_putc(*fmt); - break; - } - } - else - _s_putc(*fmt); - fmt++; - } - -out: - **sout_buf = '\0'; - va_end(ap); -} \ No newline at end of file diff --git a/nyx/nyx_gui/utils/types.h b/nyx/nyx_gui/utils/types.h deleted file mode 100644 index e0c43fe..0000000 --- a/nyx/nyx_gui/utils/types.h +++ /dev/null @@ -1,99 +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 . -*/ - -#ifndef _TYPES_H_ -#define _TYPES_H_ - -#define NULL ((void *)0) - -#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ALIGN_DOWN(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 signed char s8; -typedef short s16; -typedef short SHORT; -typedef int s32; -typedef int INT; -typedef long LONG; -typedef long long int s64; -typedef unsigned char u8; -typedef unsigned char BYTE; -typedef unsigned short u16; -typedef unsigned short WORD; -typedef unsigned short WCHAR; -typedef unsigned int u32; -typedef unsigned int UINT; -typedef unsigned long DWORD; -typedef unsigned long long QWORD; -typedef unsigned long long int u64; -typedef volatile unsigned char vu8; -typedef volatile unsigned short vu16; -typedef volatile unsigned int vu32; - -typedef int bool; -#define true 1 -#define false 0 - -#define BOOT_CFG_AUTOBOOT_EN (1 << 0) -#define BOOT_CFG_FROM_LAUNCH (1 << 1) -#define BOOT_CFG_FROM_ID (1 << 2) -#define BOOT_CFG_SEPT_RUN (1 << 7) - -#define EXTRA_CFG_KEYS (1 << 0) -#define EXTRA_CFG_PAYLOAD (1 << 1) -#define EXTRA_CFG_MODULE (1 << 2) - -#define EXTRA_CFG_NYX_RELOAD (1 << 6) -#define EXTRA_CFG_NYX_DUMP (1 << 7) - -typedef struct __attribute__((__packed__)) _boot_cfg_t -{ - u8 boot_cfg; - u8 autoboot; - u8 autoboot_list; - u8 extra_cfg; - union - { - struct - { - char id[8]; - }; - u8 xt_str[0x80]; - }; -} boot_cfg_t; - -typedef struct __attribute__((__packed__)) _ipl_ver_meta_t -{ - u32 magic; - u32 version; - u16 rsvd0; - u16 rsvd1; -} ipl_ver_meta_t; - -typedef struct __attribute__((__packed__)) _reloc_meta_t -{ - u32 start; - u32 stack; - u32 end; - u32 ep; -} reloc_meta_t; - -#endif diff --git a/nyx/nyx_gui/utils/util.c b/nyx/nyx_gui/utils/util.c deleted file mode 100644 index ba0b753..0000000 --- a/nyx/nyx_gui/utils/util.c +++ /dev/null @@ -1,139 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2018 CTCaer -* -* 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 "util.h" -#include "../gfx/di.h" -#include "../mem/minerva.h" -#include "../power/max77620.h" -#include "../rtc/max77620-rtc.h" -#include "../soc/bpmp.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" -#include "../soc/t210.h" - -#define USE_RTC_TIMER - -extern volatile nyx_storage_t *nyx_str; - -extern void sd_unmount(bool deinit); - -u32 get_tmr_s() -{ - return RTC(APBDEV_RTC_SECONDS); -} - -u32 get_tmr_ms() -{ - // The registers must be read with the following order: - // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) - return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); -} - -u32 get_tmr_us() -{ - return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US -} - -void msleep(u32 ms) -{ -#ifdef USE_RTC_TIMER - u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); - // Casting to u32 is important! - while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) - ; -#else - bpmp_msleep(ms); -#endif -} - -void usleep(u32 us) -{ -#ifdef USE_RTC_TIMER - u32 start = TMR(TIMERUS_CNTR_1US); - - // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately. - if ((start + us) < start) - bpmp_usleep(us); - else - while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important! - ; -#else - bpmp_usleep(us); -#endif -} - -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) -{ - for(u32 i = 0; i < num_ops; i++) - base[ops[i].off] = ops[i].val; -} - -void panic(u32 val) -{ - // Set panic code. - PMC(APBDEV_PMC_SCRATCH200) = val; - //PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE; - TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN; - TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN; - TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN; - TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; - - while (true) - usleep(1); -} - -void reboot_normal() -{ - bpmp_mmu_disable(); - - sd_unmount(true); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; - - panic(0x21); // Bypass fuse programming in package1. -} - -void reboot_rcm() -{ - bpmp_mmu_disable(); - - sd_unmount(true); - display_end(); - - nyx_str->mtc_cfg.init_done = 0; - - PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm. - PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; - - while (true) - bpmp_halt(); -} - -void power_off() -{ - sd_unmount(true); - display_end(); - - // Stop the alarm, in case we injected and powered off too fast. - max77620_rtc_stop_alarm(); - - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); - - while (true) - bpmp_halt(); -} diff --git a/nyx/nyx_gui/utils/util.h b/nyx/nyx_gui/utils/util.h deleted file mode 100644 index cdddc85..0000000 --- a/nyx/nyx_gui/utils/util.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer - * - * 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 _UTIL_H_ -#define _UTIL_H_ - -#include "types.h" -#include "../mem/minerva.h" - -typedef enum -{ - NYX_CFG_DUMP = (1 << 7), -} nyx_cfg_t; - -typedef enum -{ - ERR_LIBSYS_LP0 = (1 << 0), - ERR_SYSOLD_NYX = (1 << 1), - ERR_SYSOLD_MTC = (1 << 2), -} hekate_errors_t; - -#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ - ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) - -typedef struct _cfg_op_t -{ - u32 off; - u32 val; -} cfg_op_t; - -typedef struct _nyx_info_t -{ - u32 rsvd; - u32 errors; -} nyx_info_t; - -typedef struct _nyx_storage_t -{ - u32 version; - u32 cfg; - u8 irama[0x8000]; - u8 hekate[0x30000]; - u8 rsvd[0x800000 - sizeof(nyx_info_t)]; - nyx_info_t info; - mtc_config_t mtc_cfg; - emc_table_t mtc_table; -} nyx_storage_t; - -u32 get_tmr_us(); -u32 get_tmr_ms(); -u32 get_tmr_s(); -void usleep(u32 us); -void msleep(u32 ms); -void panic(u32 val); -void reboot_normal(); -void reboot_rcm(); -void power_off(); -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); - -#endif diff --git a/nyx/resources/icon_lakka.bmp b/nyx/resources/icon_lakka.bmp index 5127015..5cff98c 100644 Binary files a/nyx/resources/icon_lakka.bmp and b/nyx/resources/icon_lakka.bmp differ diff --git a/nyx/resources/icon_lakka_hue.bmp b/nyx/resources/icon_lakka_hue.bmp new file mode 100644 index 0000000..6ac6020 Binary files /dev/null and b/nyx/resources/icon_lakka_hue.bmp differ diff --git a/nyx/resources/icon_payload.bmp b/nyx/resources/icon_payload.bmp index cdb0ed4..f60e75d 100644 Binary files a/nyx/resources/icon_payload.bmp and b/nyx/resources/icon_payload.bmp differ diff --git a/nyx/resources/icon_switch.bmp b/nyx/resources/icon_switch.bmp index 743cc84..358c495 100644 Binary files a/nyx/resources/icon_switch.bmp and b/nyx/resources/icon_switch.bmp differ diff --git a/res/hekate_ipl_template.ini b/res/hekate_ipl_template.ini index 86375fe..fcb886a 100644 --- a/res/hekate_ipl_template.ini +++ b/res/hekate_ipl_template.ini @@ -1,56 +1,102 @@ [config] -autoboot=4 +autoboot=0 autoboot_list=0 bootwait=3 -verification=1 +noticker=0 backlight=100 -autohosoff=0 +autohosoff=1 autonogc=1 +updater2p=1 +bootprotect=0 + +# Only include above what you want to change from defaults. +# config.c in bootloader and Nyx have all the defaults. + {-------- Stock -------} -[Stock 6.2.0 and lower] +[Stock] +pkg3=atmosphere/package3 stock=1 emummc_force_disable=1 -[Stock All FW] -fss0=atmosphere/fusee-secondary.bin -stock=1 -emummc_force_disable=1 -# Both above disable kernel patching -# Stock All FW, includes exosphere and warmboot, ONLY when >= 7.0.0. +# This disables kernel patching and CFW kips. +# Includes exosphere and warmboot, ONLY when >= 7.0.0 and Erista. +# Includes exosphere on Mariko. +# Exosphere/warmboot are not identifiable as it is now. +# This is the closest to OFW, especially when AutoRCM is needed. + -[Stock emuMMC All FW] -fss0=atmosphere/fusee-secondary.bin -stock=1 -{ } {-- Custom Firmwares --} -[Atmo FSS0 Vanilla] -fss0=atmosphere/fusee-secondary.bin -logopath=bootloader/res/bootlogo_atmo.bmp -icon=bootloader/res/icon_atmo.bmp +[Atmo Vanilla] +pkg3=atmosphere/package3 +kip1=atmosphere/kips/* + +# Note: +# The above adheres to emummc.ini. It will launch emuMMC if enabled, otherwise sysMMC. +# The kip1 line can be omitted if wanted. It's in example in order to mimic fusee behavior. + + + +[Atmo EMU] +pkg3=atmosphere/package3 +emummcforce=1 + +[Atmo SYS] +pkg3=atmosphere/package3 +emummc_force_disable=1 # Note: # You can have 2 entries of everything where one can boot with emuMMC and one without, -# via the emummc_force_disable=1 key. -# logopath= key is for bootlogo. icon= key is for Nyx icon. -# All entries can have these stylistic keys. +# via the emummc_force_disable=1 and emummcforce=1 keys. Like the examples above. +# These 2 entries allow user to easily boot enforceable SYS or EMU CFW +# emummcforce=1 makes sure that emuMMC is enabled otherwise it will error out +# in order to protect user from booting SYS without knowing. +# emummc_force_disable=1 disables emuMMC and allows user to boot SYS CFW +# even if emuMMC is enabled. -[CFW FSS0 extra kips & patches] -fss0=atmosphere/fusee-secondary.bin + +[Atmo EMU2] +pkg3=atmosphere/package3 +emupath=emuMMC/SD02 +emummcforce=1 + +# Note: +# The above allows you to swap emuMMC on the fly while booting. +# The path defined is the main path of emuMMC folder, for example +# emuMMC/RAW1, emuMMC/RAW2, emuMMC/SD00, emuMMC/TEST, etc. +# Only works with emuMMC created/migrated via hekate. + + + +[Atmo with extra kips] +pkg3=atmosphere/package3 +kip1=cfw/mods/mods_extra/* +kip1=cfw/mods/mods_extra/single/extra.kip + +# Note: +# The above can be used with any pkg3 entry. Like the ones above. +# You can even override atmosphere (pkg3) kips with this. +# The wildcard '*' like above can be used to load all kips from a selected directory. + + +{-- Custom Firmwares Old methods --} +[CFW PKG3 extra kips & patches] +pkg3=atmosphere/package3 kip1patch=name_of_patch kip1=cfw/mods/mods_extra/* kip1=cfw/mods/mods_extra/single/extra.kip # Note: # Both options for kip1 can be used. Wildcard and single. -# You can override kips loaded from FSS0 if you define them after that entry. +# You can override kips loaded from PKG3/FSS0 if you define them after the pkg3 key. # If kip1 patch resides in patches.ini and that file OR the patch for # current HOS version does not exist, it will error out. -[Atmo Vanilla] + +[CFW KIPs method] secmon=cfw/mods/exosphere.bin warmboot=cfw/mods/lp0fw.bin kip1=cfw/mods/loader.kip @@ -63,35 +109,48 @@ atmosphere=1 # Note: # All kips defined method. This can be changed to what is below also. -# atmosphere=1 key is IMPORTANT when no FFS0 is defined. +# atmosphere=1 key is IMPORTANT when no PKG3/FSS0 is defined. -[CFW Extra kips] + +[CFW KIPs method with wildcard] secmon=cfw/mods/exosphere.bin warmboot=cfw/mods/lp0fw.bin kip1=cfw/mods/* kip1=cfw/mods/extra/extra.kip atmosphere=1 -{ } # Note: # All kips parsed from a directory, plus extra added. + {------- Tools -------} -[memloader] -payload=bootloader/payloads/memloader.bin +[Lockpick RCM] +payload=bootloader/payloads/Lockpick_RCM.bin -# hekate - CTCaer mod v5.0.0 .ini template +# hekate - CTCaer mod v5.8.0 .ini template +# +# All entries in this template can have these stylistic keys: +# like logopath= key which is for bootlogo and icon= key for Nyx icon. +# Other than these, there many other keys to choose from, like the exosphere configuration keys. +# All of them are descibed in the main README. +# +# Atmosphere 1.0.0 changes: +# Entries that use Atmosphere are updated to use package3 instead of fusee-secondary.bin for +# Atmosphere 1.0.0 and up. If 0.20.1 and older is used, replace package3 with fusee-secondary.bin. +# +# # NOT TO BE USED AS IS! # Pick [config] and then only the needed [sections]. # or { } lines can be ommited. # If [config] is not copied, hekate will create one with defaults. - +# If wanted, only the changed defaults can be edited. The rest will be created automatically. +# # Note: The keys in a section are parsed sequentially. # This is important for override order of keys (if any double or matching functionality). # Disclaimer: There are many combos, that allow hekate to basically boot everything NATIVELY. # hekate will ALWAYS do what YOU tell it to do. If you get an error, -# that means that hekate_ipl.ini was wrongly made or files are missing! +# that means that hekate_ipl.ini was wrongly made or files are missing/corrupt/etc! diff --git a/res/patches_template.ini b/res/patches_template.ini index 0ebe8bd..786fcc8 100644 --- a/res/patches_template.ini +++ b/res/patches_template.ini @@ -21,132 +21,3 @@ .nosigchk=0:0x194A0:0x4:BA090094,E0031F2A .nosigchk=0:0x3A79C:0x4:E0060036,1F2003D5 -#FS Patches for 2.0.0 -[FS:cd7bbe18d6130b28] -.nosigchk=0:0x15DF4:0x4:BC0A0094,E0031F2A -.nosigchk=0:0x3F720:0x4:00060036,1F2003D5 - -#FS Patches for 2.0.0 exfat -[FS:e76692dfaa0420e9] -.nosigchk=0:0x15DF4:0x4:BC0A0094,E0031F2A -.nosigchk=0:0x3F720:0x4:00060036,1F2003D5 - -#FS Patches for 2.1.0 -[FS:0d7005627b07767c] -.nosigchk=0:0x15F64:0x4:DF0A0094,E0031F2A -.nosigchk=0:0x3FAF8:0x4:00060036,1F2003D5 - -#FS Patches for 2.1.0 exfat -[FS:dbd85fcacc193da8] -.nosigchk=0:0x15F64:0x4:DF0A0094,E0031F2A -.nosigchk=0:0x3FAF8:0x4:00060036,1F2003D5 - -#FS Patches for 3.0.0 -[FS:a86da5e87ef1097b] -.nosigchk=0:0x18E24:0x4:520C0094,E0031F2A -.nosigchk=0:0x49EC8:0x4:40040036,1F2003D5 - -#FS Patches for 3.0.0 exfat -[FS:981c57e7f02f70f7] -.nosigchk=0:0x18E24:0x4:520C0094,E0031F2A -.nosigchk=0:0x49EC8:0x4:40040036,1F2003D5 - -#FS Patches for 3.0.1 -[FS:57397c063f10b631] -.nosigchk=0:0x18E90:0x4:520C0094,E0031F2A -.nosigchk=0:0x49F34:0x4:E0030036,1F2003D5 - -#FS Patches for 3.0.1 exfat -[FS:073099d7c6ad7d89] -.nosigchk=0:0x18E90:0x4:520C0094,E0031F2A -.nosigchk=0:0x49F34:0x4:E0030036,1F2003D5 - -#FS Patches for 4.0.0 -[FS:06e90719595a010c] -.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A -.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 - -#FS Patches for 4.0.0 exfat -[FS:549b0f8d6f72c4e9] -.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A -.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 - -#FS Patches for 4.1.0 -[FS:8096af7c6a35aa82] -.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A -.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 - -#FS Patches for 4.1.0 exfat -[FS:02d5abaafd20c8b0] -.nosigchk=0:0x1C4FC:0x4:3C2F0094,E0031F2A -.nosigchk=0:0x57934:0x4:E0020036,1F2003D5 - -#FS Patches for 5.0.0 -[FS:a6f27ad9ac7c73ad] -.nosigchk=0:0x22DDC:0x4:7D3E0094,E0031F2A -.nosigchk=0:0x7D490:0x4:40030036,1F2003D5 - -#FS Patches for 5.0.0 exfat -[FS:ce3ecba2f2f062f5] -.nosigchk=0:0x22DDC:0x4:7D3E0094,E0031F2A -.nosigchk=0:0x7D490:0x4:40030036,1F2003D5 - -#FS Patches for 5.1.0 -[FS:76f87402c9387c0f] -.nosigchk=0:0x22E0C:0x4:853E0094,E0031F2A -.nosigchk=0:0x7D860:0x4:40030036,1F2003D5 - -#FS Patches for 5.1.0 exfat -[FS:10b2d81605488599] -.nosigchk=0:0x22E0C:0x4:853E0094,E0031F2A -.nosigchk=0:0x7D860:0x4:40030036,1F2003D5 - -#FS Patches for 6.0.0 - 4 -[FS:1b82cb221867cb52] -.nosigchk=0:0x712A8:0x4:8E3E0094,E0031F2A -.nosigchk=0:0xEB08C:0x4:C0030036,1F2003D5 - -#FS Patches for 6.0.0 - 4 exfat -[FS:966add3d20b62713] -.nosigchk=0:0x7C9A8:0x4:8E3E0094,E0031F2A -.nosigchk=0:0xF678C:0x4:C0030036,1F2003D5 - -#FS Patches for 6.0.0 - 5 -[FS:3a574d436186191d] -.nosigchk=0:0x712A8:0x4:8E3E0094,E0031F2A -.nosigchk=0:0xEB08C:0x4:C0030036,1F2003D5 - -#FS Patches for 6.0.0 - 5 exfat -[FS:330553f6b5fb55c4] -.nosigchk=0:0x7C9A8:0x4:8E3E0094,E0031F2A -.nosigchk=0:0xF678C:0x4:C0030036,1F2003D5 - -#FS Patches for 7.0.0 -[FS:2ADBE97E9B5F4177] -.nosigchk=0:0x74A2C:0x4:31430094,E0031F2A -.nosigchk=0:0xF25E4:0x4:C0030036,1F2003D5 - -#FS Patches for 7.0.0 exfat -[FS:2CCE659CEC536A8E] -.nosigchk=0:0x7FFDC:0x4:31430094,E0031F2A -.nosigchk=0:0xFDB94:0x4:C0030036,1F2003D5 - -#FS Patches for 8.0.0 -[FS:B2F5176B3548364D] -.nosigchk=0:0x7630C:0x4:51440094,E0031F2A -.nosigchk=0:0xF49A4:0x4:C0030036,1F2003D5 - -#FS Patches for 8.0.0 exfat -[FS:DBD941C0C53C52CC] -.nosigchk=0:0x818BC:0x4:51440094,E0031F2A -.nosigchk=0:0xFFF54:0x4:C0030036,1F2003D5 - -#FS Patches for 8.1.0 -[FS:6B09B67B29C02024] -.nosigchk=0:0x7630C:0x4:51440094,E0031F2A -.nosigchk=0:0xF49A4:0x4:C0030036,1F2003D5 - -#FS Patches for 8.1.0 exfat -[FS:B4CAE1F24965D92E] -.nosigchk=0:0x818BC:0x4:51440094,E0031F2A -.nosigchk=0:0xFFF54:0x4:C0030036,1F2003D5 diff --git a/tools/bin2c/Makefile b/tools/bin2c/Makefile new file mode 100644 index 0000000..e870ac8 --- /dev/null +++ b/tools/bin2c/Makefile @@ -0,0 +1,16 @@ +NATIVE_CC ?= gcc + +ifeq (, $(shell which $(NATIVE_CC) 2>/dev/null)) +$(error "Native GCC is missing. Please install it first. If it's path is custom, set it with export NATIVE_CC=") +endif + +.PHONY: all clean + +all: bin2c + @echo > /dev/null + +clean: + @rm -f bin2c + +bin2c: bin2c.c + @$(NATIVE_CC) -o $@ bin2c.c diff --git a/tools/bin2c/bin2c.c b/tools/bin2c/bin2c.c new file mode 100644 index 0000000..0d820fc --- /dev/null +++ b/tools/bin2c/bin2c.c @@ -0,0 +1,83 @@ +/* + * This is bin2c program, which allows you to convert binary file to + * C language array, for use as embedded resource, for instance you can + * embed graphics or audio file directly into your program. + * This is public domain software, use it on your own risk. + * Contact Serge Fukanchik at fuxx@mail.ru if you have any questions. + */ + +#include +#include +#include +#include +#include + +/* Replace . with _ */ +char* +make_ident ( char* name ) +{ + char* ret; + char* p; + + ret = strdup ( name ); + + for ( p = ret; p[0]; p++ ) + { + if ( !isalnum ( p[0] ) ) p[0] = '_'; + } + return ret; +} + +int +main ( int argc, char* argv[] ) +{ + unsigned char buf[BUFSIZ]; + char* ident; + FILE *fd; + size_t size, i, total, blksize = BUFSIZ; + int need_comma = 0; + + if ( argc != 2 ) + { + fprintf ( stderr, "Usage: %s binary_file > output_file\n", argv[0] ); + return -1; + } + + fd = fopen ( argv[1], "rb" ); + if ( fd == NULL ) + { + fprintf ( stderr, "%s: can't open %s for reading\n", argv[0], argv[1] ); + return -1; + } + + fseek(fd, 0, SEEK_END); + size = ftell(fd); + rewind(fd); + + ident = make_ident ( argv[1] ); + + printf ( "static const unsigned char __attribute__((section (\"._%s\"))) %s[] = {", ident, ident ); + for ( total = 0; total < size; ) + { + if ( size - total < blksize ) blksize = size - total; + if ( fread ( buf, 1, blksize, fd ) != blksize ) + { + fprintf ( stderr, "%s: file read error\n", argv[0] ); + return -1; + } + for ( i = 0; i < blksize; i++ ) + { + if ( need_comma ) printf ( ", " ); + else need_comma = 1; + if ( ( total % 11 ) == 0 ) printf ( "\n\t" ); + printf ( "0x%.2x", buf[i] ); + total++; + } + } + printf ( "\n};\n" ); + + fclose ( fd ); + free ( ident ); + + return 0; +} diff --git a/tools/lz/Makefile b/tools/lz/Makefile new file mode 100644 index 0000000..3d6fec8 --- /dev/null +++ b/tools/lz/Makefile @@ -0,0 +1,16 @@ +NATIVE_CC ?= gcc + +ifeq (, $(shell which $(NATIVE_CC) 2>/dev/null)) +$(error "Native GCC is missing. Please install it first. If it's path is custom, set it with export NATIVE_CC=") +endif + +.PHONY: all clean + +all: lz77 + @echo > /dev/null + +clean: + @rm -f lz77 + +lz77: lz.c lz77.c + @$(NATIVE_CC) -o $@ lz.c lz77.c diff --git a/tools/lz/lz.c b/tools/lz/lz.c new file mode 100644 index 0000000..01a3e69 --- /dev/null +++ b/tools/lz/lz.c @@ -0,0 +1,546 @@ +// +// Name: lz.c +// Author: Marcus Geelnard +// Description: LZ77 coder/decoder implementation. +// Reentrant: Yes +// $ATH_LICENSE_NULL$ +// +// 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 +// + +// +// This file has been altered from the original version. +// + +/************************************************************************* +* Constants used for LZ77 coding +*************************************************************************/ + +/* Maximum offset (can be any size < 2^31). Lower values give faster + compression, while higher values gives better compression. The default + value of 100000 is quite high. Experiment to see what works best for + you. */ +#define LZ_MAX_OFFSET 100000 + + + +/************************************************************************* +* INTERNAL FUNCTIONS * +*************************************************************************/ + + +/************************************************************************* +* _LZ_StringCompare() - Return maximum length string match. +*************************************************************************/ + +static unsigned int _LZ_StringCompare( unsigned char * str1, + unsigned char * str2, unsigned int minlen, unsigned int maxlen ) +{ + unsigned int len; + + for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len ); + + return len; +} + + +/************************************************************************* +* _LZ_WriteVarSize() - Write unsigned integer with variable number of +* bytes depending on value. +*************************************************************************/ + +static int _LZ_WriteVarSize( unsigned int x, unsigned char * buf ) +{ + unsigned int y; + int num_bytes, i, b; + + /* Determine number of bytes needed to store the number x */ + y = x >> 3; + for( num_bytes = 5; num_bytes >= 2; -- num_bytes ) + { + if( y & 0xfe000000 ) break; + y <<= 7; + } + + /* Write all bytes, seven bits in each, with 8:th bit set for all */ + /* but the last byte. */ + for( i = num_bytes-1; i >= 0; -- i ) + { + b = (x >> (i*7)) & 0x0000007f; + if( i > 0 ) + { + b |= 0x00000080; + } + *buf ++ = (unsigned char) b; + } + + /* Return number of bytes written */ + return num_bytes; +} + + +/************************************************************************* +* _LZ_ReadVarSize() - Read unsigned integer with variable number of +* bytes depending on value. +*************************************************************************/ + +static int _LZ_ReadVarSize( unsigned int * x, 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_Compress() - Compress a block of data using an LZ77 coder. +* in - Input (uncompressed) buffer. +* out - Output (compressed) buffer. This buffer must be 0.4% larger +* than the input buffer, plus one byte. +* insize - Number of input bytes. +* The function returns the size of the compressed data. +*************************************************************************/ + +int LZ_Compress( unsigned char *in, unsigned char *out, + unsigned int insize ) +{ + unsigned char marker, symbol; + unsigned int inpos, outpos, bytesleft, i; + unsigned int maxoffset, offset, bestoffset; + unsigned int maxlength, length, bestlength; + unsigned int histogram[ 256 ]; + unsigned char *ptr1, *ptr2; + + /* Do we have anything to compress? */ + if( insize < 1 ) + { + return 0; + } + + /* Create histogram */ + for( i = 0; i < 256; ++ i ) + { + histogram[ i ] = 0; + } + for( i = 0; i < insize; ++ i ) + { + ++ histogram[ in[ i ] ]; + } + + /* Find the least common byte, and use it as the marker symbol */ + marker = 0; + for( i = 1; i < 256; ++ i ) + { + if( histogram[ i ] < histogram[ marker ] ) + { + marker = i; + } + } + + /* Remember the marker symbol for the decoder */ + out[ 0 ] = marker; + + /* Start of compression */ + inpos = 0; + outpos = 1; + + /* Main compression loop */ + bytesleft = insize; + do + { + /* Determine most distant position */ + if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET; + else maxoffset = inpos; + + /* Get pointer to current position */ + ptr1 = &in[ inpos ]; + + /* Search history window for maximum length string match */ + bestlength = 3; + bestoffset = 0; + for( offset = 3; offset <= maxoffset; ++ offset ) + { + /* Get pointer to candidate string */ + ptr2 = &ptr1[ -(int)offset ]; + + /* Quickly determine if this is a candidate (for speed) */ + if( (ptr1[ 0 ] == ptr2[ 0 ]) && + (ptr1[ bestlength ] == ptr2[ bestlength ]) ) + { + /* Determine maximum length for this offset */ + maxlength = (bytesleft < offset ? bytesleft : offset); + + /* Count maximum length match at this offset */ + length = _LZ_StringCompare( ptr1, ptr2, 0, maxlength ); + + /* Better match than any previous match? */ + if( length > bestlength ) + { + bestlength = length; + bestoffset = offset; + } + } + } + + /* Was there a good enough match? */ + if( (bestlength >= 8) || + ((bestlength == 4) && (bestoffset <= 0x0000007f)) || + ((bestlength == 5) && (bestoffset <= 0x00003fff)) || + ((bestlength == 6) && (bestoffset <= 0x001fffff)) || + ((bestlength == 7) && (bestoffset <= 0x0fffffff)) ) + { + out[ outpos ++ ] = (unsigned char) marker; + outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] ); + outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] ); + inpos += bestlength; + bytesleft -= bestlength; + } + else + { + /* Output single byte (or two bytes if marker byte) */ + symbol = in[ inpos ++ ]; + out[ outpos ++ ] = symbol; + if( symbol == marker ) + { + out[ outpos ++ ] = 0; + } + -- bytesleft; + } + } + while( bytesleft > 3 ); + + /* Dump remaining bytes, if any */ + while( inpos < insize ) + { + if( in[ inpos ] == marker ) + { + out[ outpos ++ ] = marker; + out[ outpos ++ ] = 0; + } + else + { + out[ outpos ++ ] = in[ inpos ]; + } + ++ inpos; + } + + return outpos; +} + + +/************************************************************************* +* LZ_CompressFast() - Compress a block of data using an LZ77 coder. +* in - Input (uncompressed) buffer. +* out - Output (compressed) buffer. This buffer must be 0.4% larger +* than the input buffer, plus one byte. +* insize - Number of input bytes. +* work - Pointer to a temporary buffer (internal working buffer), which +* must be able to hold (insize+65536) unsigned integers. +* The function returns the size of the compressed data. +*************************************************************************/ + +int LZ_CompressFast( unsigned char *in, unsigned char *out, + unsigned int insize, unsigned int *work ) +{ + unsigned char marker, symbol; + unsigned int inpos, outpos, bytesleft, i, index, symbols; + unsigned int offset, bestoffset; + unsigned int maxlength, length, bestlength; + unsigned int histogram[ 256 ], *lastindex, *jumptable; + unsigned char *ptr1, *ptr2; + + /* Do we have anything to compress? */ + if( insize < 1 ) + { + return 0; + } + + /* Assign arrays to the working area */ + lastindex = work; + jumptable = &work[ 65536 ]; + + /* Build a "jump table". Here is how the jump table works: + jumptable[i] points to the nearest previous occurrence of the same + symbol pair as in[i]:in[i+1], so in[i] == in[jumptable[i]] and + in[i+1] == in[jumptable[i]+1], and so on... Following the jump table + gives a dramatic boost for the string search'n'match loop compared + to doing a brute force search. The jump table is built in O(n) time, + so it is a cheap operation in terms of time, but it is expensice in + terms of memory consumption. */ + for( i = 0; i < 65536; ++ i ) + { + lastindex[ i ] = 0xffffffff; + } + for( i = 0; i < insize-1; ++ i ) + { + symbols = (((unsigned int)in[i]) << 8) | ((unsigned int)in[i+1]); + index = lastindex[ symbols ]; + lastindex[ symbols ] = i; + jumptable[ i ] = index; + } + jumptable[ insize-1 ] = 0xffffffff; + + /* Create histogram */ + for( i = 0; i < 256; ++ i ) + { + histogram[ i ] = 0; + } + for( i = 0; i < insize; ++ i ) + { + ++ histogram[ in[ i ] ]; + } + + /* Find the least common byte, and use it as the marker symbol */ + marker = 0; + for( i = 1; i < 256; ++ i ) + { + if( histogram[ i ] < histogram[ marker ] ) + { + marker = i; + } + } + + /* Remember the marker symbol for the decoder */ + out[ 0 ] = marker; + + /* Start of compression */ + inpos = 0; + outpos = 1; + + /* Main compression loop */ + bytesleft = insize; + do + { + /* Get pointer to current position */ + ptr1 = &in[ inpos ]; + + /* Search history window for maximum length string match */ + bestlength = 3; + bestoffset = 0; + index = jumptable[ inpos ]; + while( (index != 0xffffffff) && ((inpos - index) < LZ_MAX_OFFSET) ) + { + /* Get pointer to candidate string */ + ptr2 = &in[ index ]; + + /* Quickly determine if this is a candidate (for speed) */ + if( ptr2[ bestlength ] == ptr1[ bestlength ] ) + { + /* Determine maximum length for this offset */ + offset = inpos - index; + maxlength = (bytesleft < offset ? bytesleft : offset); + + /* Count maximum length match at this offset */ + length = _LZ_StringCompare( ptr1, ptr2, 2, maxlength ); + + /* Better match than any previous match? */ + if( length > bestlength ) + { + bestlength = length; + bestoffset = offset; + } + } + + /* Get next possible index from jump table */ + index = jumptable[ index ]; + } + + /* Was there a good enough match? */ + if( (bestlength >= 8) || + ((bestlength == 4) && (bestoffset <= 0x0000007f)) || + ((bestlength == 5) && (bestoffset <= 0x00003fff)) || + ((bestlength == 6) && (bestoffset <= 0x001fffff)) || + ((bestlength == 7) && (bestoffset <= 0x0fffffff)) ) + { + out[ outpos ++ ] = (unsigned char) marker; + outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] ); + outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] ); + inpos += bestlength; + bytesleft -= bestlength; + } + else + { + /* Output single byte (or two bytes if marker byte) */ + symbol = in[ inpos ++ ]; + out[ outpos ++ ] = symbol; + if( symbol == marker ) + { + out[ outpos ++ ] = 0; + } + -- bytesleft; + } + } + while( bytesleft > 3 ); + + /* Dump remaining bytes, if any */ + while( inpos < insize ) + { + if( in[ inpos ] == marker ) + { + out[ outpos ++ ] = marker; + out[ outpos ++ ] = 0; + } + else + { + out[ outpos ++ ] = in[ inpos ]; + } + ++ inpos; + } + + return outpos; +} + + +/************************************************************************* +* 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. +*************************************************************************/ + +int LZ_Uncompress( 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 0; + } + + /* 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 ); + + return outpos; +} diff --git a/tools/lz/lz.h b/tools/lz/lz.h new file mode 100644 index 0000000..7f7b22a --- /dev/null +++ b/tools/lz/lz.h @@ -0,0 +1,61 @@ +// +// Name: lz.h +// Author: Marcus Geelnard +// Description: LZ77 coder/decoder interface. +// Reentrant: Yes +// ------------------------------------------------------------------------ +// $ATH_LICENSE_NULL$ +// 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 +// + +// +// This file has been altered from the original version. +// + +#ifndef _lz_h_ +#define _lz_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* +* Function prototypes +*************************************************************************/ + +int LZ_Compress( unsigned char *in, unsigned char *out, + unsigned int insize ); +int LZ_CompressFast( unsigned char *in, unsigned char *out, + unsigned int insize, unsigned int *work ); +int LZ_Uncompress( unsigned char *in, unsigned char *out, + unsigned int insize ); + + +#ifdef __cplusplus +} +#endif + +#endif /* _lz_h_ */ diff --git a/tools/lz/lz77.c b/tools/lz/lz77.c new file mode 100644 index 0000000..75b90a6 --- /dev/null +++ b/tools/lz/lz77.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 CTCaer + * + * 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 +#include +#include +#include +#include "lz.h" + +char filename[1024]; + +int main(int argc, char *argv[]) +{ + int nbytes; + int filename_len; + struct stat statbuf; + FILE *in_file, *out_file; + + if(stat(argv[1], &statbuf)) + goto error; + + if((in_file=fopen(argv[1], "rb")) == NULL) + goto error; + + strcpy(filename, argv[1]); + filename_len = strlen(filename); + + uint32_t in_size = statbuf.st_size; + uint8_t *in_buf = (uint8_t *)malloc(in_size); + + uint32_t out_size = statbuf.st_size + 257; + uint8_t *out_buf = (uint8_t *)malloc(out_size); + + if(!(in_buf && out_buf)) + goto error; + + if(fread(in_buf, 1, in_size, in_file) != in_size) + goto error; + + fclose(in_file); + + uint32_t *work = (uint32_t*)malloc(sizeof(uint32_t) * (in_size + 65536)); + for (int i = 0; i < 2; i++) + { + uint32_t in_size_tmp; + if (!i) + { + in_size_tmp = in_size / 2; + strcpy(filename + filename_len, ".00.lz"); + } + else + { + in_size_tmp = in_size - (in_size / 2); + strcpy(filename + filename_len, ".01.lz"); + } + + if (work) + nbytes = LZ_CompressFast(in_buf + (in_size / 2) * i, out_buf, in_size_tmp, work); + else + goto error; + + if (nbytes > out_size) + goto error; + + if((out_file = fopen(filename,"wb")) == NULL) + goto error; + + if (fwrite(out_buf, 1, nbytes, out_file) != nbytes) + goto error; + + fclose(out_file); + } + + return 0; + +error: + fprintf(stderr, "Failed to compress: %s\n", argv[1]); + exit(1); +}