mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 12:34:47 +00:00
Almost finished
This commit is contained in:
commit
653cbde739
361 changed files with 40347 additions and 4135 deletions
5
Makefile
5
Makefile
|
@ -133,6 +133,7 @@ dist: dist-no-debug
|
|||
cp exosphere/loader_stub/loader_stub.elf atmosphere-$(AMSVER)-debug/exosphere-loader-stub.elf
|
||||
cp exosphere/program/program.elf atmosphere-$(AMSVER)-debug/exosphere-program.elf
|
||||
cp exosphere/warmboot/warmboot.elf atmosphere-$(AMSVER)-debug/exosphere-warmboot.elf
|
||||
cp exosphere/mariko_fatal/mariko_fatal.elf atmosphere-$(AMSVER)-debug/exosphere-mariko-fatal.elf
|
||||
cp exosphere/program/sc7fw/sc7fw.elf atmosphere-$(AMSVER)-debug/exosphere-sc7fw.elf
|
||||
cp exosphere/program/rebootstub/rebootstub.elf atmosphere-$(AMSVER)-debug/exosphere-rebootstub.elf
|
||||
cp mesosphere/kernel_ldr/kernel_ldr.elf atmosphere-$(AMSVER)-debug/kernel_ldr.elf
|
||||
|
@ -142,8 +143,12 @@ dist: dist-no-debug
|
|||
cp stratosphere/creport/creport.elf atmosphere-$(AMSVER)-debug/creport.elf
|
||||
cp stratosphere/dmnt/dmnt.elf atmosphere-$(AMSVER)-debug/dmnt.elf
|
||||
cp stratosphere/eclct.stub/eclct.stub.elf atmosphere-$(AMSVER)-debug/eclct.stub.elf
|
||||
cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf
|
||||
cp stratosphere/fatal/fatal.elf atmosphere-$(AMSVER)-debug/fatal.elf
|
||||
cp stratosphere/jpegdec/jpegdec.elf atmosphere-$(AMSVER)-debug/jpegdec.elf
|
||||
cp stratosphere/loader/loader.elf atmosphere-$(AMSVER)-debug/loader.elf
|
||||
cp stratosphere/ncm/ncm.elf atmosphere-$(AMSVER)-debug/ncm.elf
|
||||
cp stratosphere/pgl/pgl.elf atmosphere-$(AMSVER)-debug/pgl.elf
|
||||
cp stratosphere/pm/pm.elf atmosphere-$(AMSVER)-debug/pm.elf
|
||||
cp stratosphere/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf
|
||||
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,9 +1,10 @@
|
|||
[hbl_config]
|
||||
; Program Specific Config
|
||||
; Up to 8 program-specific configurations can be set.
|
||||
; These use `program_id_#` and `override_key_#`
|
||||
; These use `program_id_#`, `override_address_space_#`, and `override_key_#`
|
||||
; where # is in range [0,7].
|
||||
; program_id_0=010000000000100D
|
||||
; override_address_space=39_bit
|
||||
; override_key_0=!R
|
||||
|
||||
; Any Application Config
|
||||
|
@ -12,6 +13,7 @@
|
|||
; by a program specific config.
|
||||
; override_any_app=true
|
||||
; override_any_app_key=R
|
||||
; override_any_app_address_space=39_bit
|
||||
; path=atmosphere/hbl.nsp
|
||||
|
||||
[default_config]
|
||||
|
|
|
@ -12,6 +12,7 @@ Building Atmosphère is a very straightforward process that relies almost exclus
|
|||
|
||||
2. Install the following packages via (dkp-)pacman:
|
||||
+ `switch-dev`
|
||||
+ `switch-glm`
|
||||
+ `switch-libjpeg-turbo`
|
||||
+ `devkitARM`
|
||||
+ `devkitarm-rules`
|
||||
|
|
|
@ -1,4 +1,38 @@
|
|||
# Changelog
|
||||
## 0.16.0
|
||||
+ Support was added for 11.0.0.
|
||||
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
|
||||
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||
+ `loader`, `sm`, `boot`, `pgl` were updated to reflect the latest official behaviors.
|
||||
+ **Please Note**: 11.0.0 implements an opt-in version of the atmosphère `sm` extension that allows for closing session without unregistering services.
|
||||
+ Correspondingly, the extension will be deprecated in favor of the new official opt-in command. In 0.17.0, it will be removed entirely.
|
||||
+ If your custom system module relies on this extension (however unlikely that seems to me), please update it accordingly.
|
||||
+ `erpt` was partially updated to provide compatibility with 11.0.0.
|
||||
+ The latest firmware attaches additional fields and context information to logs.
|
||||
+ A future atmosphère update will implement this logic, so that users who are interested can also get the new information when examining their logs.
|
||||
+ **Please Note**: 11.0.0 introduced breaking changes to the `usb` system module's `usb:ds` API.
|
||||
+ Homebrew which uses the `usb:ds` service should rebuild with the latest libnx version to support running on 11.0.0.
|
||||
+ The `boot` system module was rewritten to reflect the huge driver changes introduced in 8.0.0.
|
||||
+ This includes a number of improvements to both logo display and battery management logic.
|
||||
+ Support was added for configuring the address space width for `hbl`.
|
||||
+ The `hbl_config!override_address_space_(#)` and `hbl_config!override_any_app_address_space` can now be set to `39_bit`, `36_bit`, or `32_bit` to control the address space for hbl on a per-override basis.
|
||||
+ If a configuration has not been set, hbl will now default to 39-bit address space.
|
||||
+ Previously, a legacy 36-bit address space was always used to maintain compatibility with 1.0.0.
|
||||
+ A new loader extension was added to support 39-bit whenever possible (including mesosphere-on-1.0.0), with fallback to 36-bit when unavailable.
|
||||
+ Support was added to a number of components for running on Mariko hardware.
|
||||
+ The `boot` system module can now safely be run on mariko hardware, performing correct hardware initialization.
|
||||
+ Daybreak (and generally, system update logic) were updated to be usable on Mariko.
|
||||
+ Boot0 protection/management logic was updated to perform correct actions on Mariko.
|
||||
+ Reboot to payload does not and cannot work on Mariko. Correspondingly, A "fatal error" handler was written, to display and save fatal errors from within TrustZone.
|
||||
+ **Please Note:** Atmosphere is still not properly usable on Mariko hardware.
|
||||
+ In particular, wake-from-sleep will not properly function (the magic numbers aren't set correctly), among a few other minor issues.
|
||||
+ `exosphère` received support for building under debug configuration.
|
||||
+ A small (otherwise unused) portion of IRAM is now reserved for debug-only exosphere code (this region is unused/untouched under release config).
|
||||
+ This enables logging (including printf) to uart from the secure monitor, for those interested.
|
||||
+ A number of bugs were fixed, including:
|
||||
+ Minor issues in a number of filesystem related code were fixed.
|
||||
+ An issue was fixed that could cause NCM to abort on consoles which came with 3.0.x and were never updated.
|
||||
+ Several issues were fixed, and usability and stability were improved.
|
||||
## 0.15.0
|
||||
+ fusee-primary's panic display was updated to automatically identify and give suggestions to resolve many of the most common errors users encounter.
|
||||
+ Having been tested as well as I can alone, `mesosphere` (atmosphère's reimplementation of the Nintendo Switch kernel) is now available for users interested in trying it.
|
||||
|
|
103
docs/components/detail/exosphere_memory_layout.txt
Normal file
103
docs/components/detail/exosphere_memory_layout.txt
Normal file
|
@ -0,0 +1,103 @@
|
|||
exosphere, storage requirements:
|
||||
|
||||
Nonvolatile memory:
|
||||
0xE000
|
||||
|
||||
Volatile memory: 0x2000
|
||||
|
||||
Physical Address Space:
|
||||
-0x7C010000-0x7C012000 - boot code/volatile memory
|
||||
-0x7C012000-0x7C01E000 - program region
|
||||
-0x7C01E000-0x7C01F000 - global data/context
|
||||
-0x7C01F000-0x7C020000 - L2/L3 page table
|
||||
|
||||
-0x7C020000-0x7C040000 - Mariko-only program region
|
||||
-0x7C040000-0x7C048000 - Mariko-only program stack
|
||||
-0x7C048000-0x7C050000 - Reserved Mariko TZRAM (SE context carveouts, etc)
|
||||
|
||||
Virtual Address Space:
|
||||
|
||||
L1: 0x40 bytes.
|
||||
|
||||
L1 Entries:
|
||||
-0 (0x000000000-0x040000000): Empty
|
||||
-1 (0x040000000-0x080000000): Identity Mapping/Empty
|
||||
-2 (0x080000000-0x0C0000000): DRAM Mapping/Empty
|
||||
-3 (0x0C0000000-0x100000000): DRAM Mapping/Empty
|
||||
-4 (0x100000000-0x140000000): Empty
|
||||
-5 (0x140000000-0x180000000): Empty
|
||||
-6 (0x180000000-0x1C0000000): Empty
|
||||
-7 (0x1C0000000-0x200000000): Virtual Region
|
||||
|
||||
L2 Page and L3 page are both0x7C01F000
|
||||
|
||||
L2 Entries:
|
||||
-0x040000000 (Identity IRAM Table)
|
||||
- Entry Used: 0x000
|
||||
-0x07C000000 (Identity TZRAM Table)
|
||||
- Entry Used: 0x1E0
|
||||
-0x1F0000000 (Virtual Region Table)
|
||||
- Entry Used: 0x180
|
||||
|
||||
L3 Entries:
|
||||
- Identity TZRAM mapping (0x7C010000-0x7C020000)
|
||||
- Entry Used: 0x010-0x01F
|
||||
- Identity IRAM mapping (0x40020000-0x40040000)
|
||||
- Entry Used: 0x020-0x03F
|
||||
- Virtual Device region (0x1F0040000-0x1F0080000)
|
||||
- Entry Used: 0x040-0x07F
|
||||
- Read Only TZRAM Alias (0x1F00A0000-0x1F00B0000)
|
||||
- Entry Used: 0x0A0-0x0AF
|
||||
- Program region (0x1F00C0000-0x1F00CC000)
|
||||
- Entry Used: 0x0C0-0x0CB
|
||||
- Mariko Program region (0x1F00D0000-0x1F00F0000)
|
||||
- Entry Used: 0x0D0-0x0EF
|
||||
- Mariko Program stack (0x1F00F4000-0x1F00FC000)
|
||||
- Entry Used: 0x0F4-0x0FB
|
||||
- Secure DRAM Storage (0x1F0100000-0x1F0110000)
|
||||
- Entry Used: 0x100-0x10F
|
||||
- Debug DRAM Storage (0x1F0110000-0x1F0114000)
|
||||
- Entry Used: 0x110-0x113
|
||||
- SC7 IRAM Work Space (0x1F0120000-0x1F0130000)
|
||||
- Entry Used: 0x120-0x12F
|
||||
- SC7 IRAM Firmware (0x1F0140000-0x1F0141000)
|
||||
- Entry Used: 0x140-0x140
|
||||
- Debug Code (0x1F0150000-0x1F0154000)
|
||||
- Entry Used: 0x150-0x153
|
||||
- Reserved For Debug (0x1F0160000-0x1F0170000)
|
||||
- Entry Used: 0x160-0x16F
|
||||
- Boot Code (0x1F01C0000-0x1F01C2000)
|
||||
- Entry Used: 0x1C0-0x1C1
|
||||
- AMS IRAM Page (0x1F01F2000-0x1F01F2000)
|
||||
- Entry Used: 0x1F2-0x1F2
|
||||
- AMS User Page (0x1F01F4000-0x1F01F4000)
|
||||
- Entry Used: 0x1F4-0x1F4
|
||||
- SMC User Page (0x1F01F6000-0x1F01F6000)
|
||||
- Entry Used: 0x1F6-0x1F6
|
||||
- Volatile (Data) (0x1F01F8000-0x1F01F9000)
|
||||
- Entry Used: 0x1F8-0x1F8
|
||||
- Volatile (Stacks) (0x1F01FA000-0x1F01FB000)
|
||||
- Entry Used: 0x1FA-0x1FA
|
||||
- Global Data (0x1F01FC000-0x1F01FD000)
|
||||
|
||||
|
||||
NV Global Data needs:
|
||||
Exosphere + Emummc Config (<=0x200)
|
||||
Boot Config[0x400]
|
||||
RSA Context(0x100)
|
||||
Old Device Keys[0x20][0x10];
|
||||
Old Master Keys[0x20][0x10];
|
||||
Imported Rsa Keys[4][0x200];
|
||||
CPU Ctx[4][0x100];
|
||||
|
||||
Total: 0x1700
|
||||
|
||||
Global Data Page (accessible via X18):
|
||||
0x000-0x200: Exosphere Config
|
||||
0x200-0x400: Emummc Config
|
||||
0x400-0x800: Sealed AES Keys
|
||||
0x800-0xC00: Boot Config
|
||||
0xC00-0xFFF: CPU contexts. Can be replaced, but this fits exactly so minimizes program space waste.
|
||||
|
||||
Volatile Global Data needs:
|
||||
Random Cache 0x400 bytes
|
|
@ -5,8 +5,8 @@
|
|||
;
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emuMMC
|
||||
branch = exo2
|
||||
commit = 6a814ebbe72cf5245b863b9edea9cd3801437a12
|
||||
parent = f551ca4461a79908c37307db10cd8cacf8b98f17
|
||||
branch = develop
|
||||
commit = 6fd752dad13c02d482a5d89c24f4e8ce8b9d8f56
|
||||
parent = 4f1a4e74992aa84b8ab84bccacc720e2d5823791
|
||||
method = rebase
|
||||
cmdver = 0.4.1
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
#include "offsets/1000_exfat.h"
|
||||
#include "offsets/1020.h"
|
||||
#include "offsets/1020_exfat.h"
|
||||
#include "offsets/1100.h"
|
||||
#include "offsets/1100_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
|
@ -108,6 +110,8 @@ DEFINE_OFFSET_STRUCT(_1000);
|
|||
DEFINE_OFFSET_STRUCT(_1000_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1020);
|
||||
DEFINE_OFFSET_STRUCT(_1020_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1100);
|
||||
DEFINE_OFFSET_STRUCT(_1100_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
|
@ -177,6 +181,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
|||
return &(GET_OFFSET_STRUCT_NAME(_1020));
|
||||
case FS_VER_10_2_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1020_EXFAT));
|
||||
case FS_VER_11_0_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1100));
|
||||
case FS_VER_11_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1100_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@ enum FS_VER
|
|||
FS_VER_10_2_0,
|
||||
FS_VER_10_2_0_EXFAT,
|
||||
|
||||
FS_VER_11_0_0,
|
||||
FS_VER_11_0_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
|
58
emummc/source/FS/offsets/1100.h
Normal file
58
emummc/source/FS/offsets/1100.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1100_H__
|
||||
#define __FS_1100_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1100_SDMMC_ACCESSOR_GC 0x156D90
|
||||
#define FS_OFFSET_1100_SDMMC_ACCESSOR_SD 0x154F40
|
||||
#define FS_OFFSET_1100_SDMMC_ACCESSOR_NAND 0x1500F0
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1100_SDMMC_WRAPPER_READ 0x14B990
|
||||
#define FS_OFFSET_1100_SDMMC_WRAPPER_WRITE 0x14BA70
|
||||
#define FS_OFFSET_1100_RTLD 0x688
|
||||
#define FS_OFFSET_1100_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1100_CLKRST_SET_MIN_V_CLK_RATE 0x14AC40
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1100_LOCK_MUTEX 0x28FF0
|
||||
#define FS_OFFSET_1100_UNLOCK_MUTEX 0x29040
|
||||
|
||||
#define FS_OFFSET_1100_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x14B8F0
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1100_SD_MUTEX 0xE323E8
|
||||
#define FS_OFFSET_1100_NAND_MUTEX 0xE2D338
|
||||
#define FS_OFFSET_1100_ACTIVE_PARTITION 0xE2D378
|
||||
#define FS_OFFSET_1100_SDMMC_DAS_HANDLE 0xE15D40
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1100_SD_DAS_INIT 0x273B4
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1100_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006D944, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007A3C0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00080708, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00092198, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1100_H__
|
58
emummc/source/FS/offsets/1100_exfat.h
Normal file
58
emummc/source/FS/offsets/1100_exfat.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1100_EXFAT_H__
|
||||
#define __FS_1100_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_ACCESSOR_GC 0x156D90
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_ACCESSOR_SD 0x154F40
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_ACCESSOR_NAND 0x1500F0
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_READ 0x14B990
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_WRITE 0x14BA70
|
||||
#define FS_OFFSET_1100_EXFAT_RTLD 0x688
|
||||
#define FS_OFFSET_1100_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1100_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14AC40
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1100_EXFAT_LOCK_MUTEX 0x28FF0
|
||||
#define FS_OFFSET_1100_EXFAT_UNLOCK_MUTEX 0x29040
|
||||
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x14B8F0
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1100_EXFAT_SD_MUTEX 0xE403E8
|
||||
#define FS_OFFSET_1100_EXFAT_NAND_MUTEX 0xE3B338
|
||||
#define FS_OFFSET_1100_EXFAT_ACTIVE_PARTITION 0xE3B378
|
||||
#define FS_OFFSET_1100_EXFAT_SDMMC_DAS_HANDLE 0xE23D40
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1100_EXFAT_SD_DAS_INIT 0x273B4
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1100_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006D944, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007A3C0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00080708, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00092198, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1100_EXFAT_H__
|
|
@ -136,8 +136,8 @@ 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 */
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* include/linux/mmc/sd.h
|
||||
*
|
||||
* Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved.
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
|
@ -10,8 +8,8 @@
|
|||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_MMC_SD_H
|
||||
#define LINUX_MMC_SD_H
|
||||
#ifndef MMC_SD_H
|
||||
#define MMC_SD_H
|
||||
|
||||
/* SD commands type argument response */
|
||||
/* class 0 */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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,
|
||||
|
@ -156,7 +156,7 @@ int sdmmc_calculate_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sdmmc_memcpy_buf = true;
|
||||
return dma_buf_idx;
|
||||
}
|
||||
|
@ -164,15 +164,18 @@ int sdmmc_calculate_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_
|
|||
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;
|
||||
//TODO: R1_SWITCH_ERROR can be skipped for certain card types.
|
||||
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)
|
||||
|
@ -285,14 +288,23 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
|||
|
||||
sdmmc_end(storage->sdmmc);
|
||||
|
||||
storage->initialized = 0;
|
||||
|
||||
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;
|
||||
bool first_reinit = false;
|
||||
while (num_sectors)
|
||||
u32 sct_off = sector;
|
||||
u32 sct_total = num_sectors;
|
||||
bool first_reinit = true;
|
||||
|
||||
// Exit if not initialized.
|
||||
if (!storage->initialized)
|
||||
return 0;
|
||||
|
||||
while (sct_total)
|
||||
{
|
||||
u32 blkcnt = 0;
|
||||
// Retry 5 times if failed.
|
||||
|
@ -300,7 +312,7 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
|
|||
do
|
||||
{
|
||||
reinit_try:
|
||||
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write))
|
||||
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sct_off, MIN(sct_total, 0xFFFF), bbuf, is_write))
|
||||
goto out;
|
||||
else
|
||||
retries--;
|
||||
|
@ -313,24 +325,33 @@ reinit_try:
|
|||
{
|
||||
int res;
|
||||
|
||||
if (!first_reinit)
|
||||
if (first_reinit)
|
||||
res = nx_sd_initialize(true);
|
||||
else
|
||||
res = nx_sd_init_retry(true);
|
||||
|
||||
// Reset values for a retry.
|
||||
blkcnt = 0;
|
||||
retries = 3;
|
||||
first_reinit = true;
|
||||
first_reinit = false;
|
||||
|
||||
// If succesful reinit, restart xfer.
|
||||
if (res)
|
||||
{
|
||||
bbuf = (u8 *)buf;
|
||||
sct_off = sector;
|
||||
sct_total = num_sectors;
|
||||
|
||||
goto reinit_try;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed.
|
||||
return 0;
|
||||
|
||||
out:
|
||||
DPRINTF("readwrite: %08X\n", blkcnt);
|
||||
sector += blkcnt;
|
||||
num_sectors -= blkcnt;
|
||||
sct_off += blkcnt;
|
||||
sct_total -= blkcnt;
|
||||
bbuf += 512 * blkcnt;
|
||||
}
|
||||
|
||||
|
@ -459,9 +480,11 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
|
|||
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;
|
||||
}
|
||||
|
@ -518,6 +541,7 @@ static void _mmc_storage_parse_cid(sdmmc_storage_t *storage)
|
|||
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 */
|
||||
|
@ -527,6 +551,7 @@ static void _mmc_storage_parse_cid(sdmmc_storage_t *storage)
|
|||
storage->cid.prv = unstuff_bits(raw_cid, 48, 8);
|
||||
storage->cid.serial = unstuff_bits(raw_cid, 16, 32);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -571,6 +596,10 @@ static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf)
|
|||
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->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT];
|
||||
}
|
||||
|
||||
|
@ -613,6 +642,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 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;
|
||||
|
@ -671,7 +701,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||
if (!_mmc_storage_enable_HS200(storage))
|
||||
return 0;
|
||||
|
||||
sdmmc_set_tap_value(storage->sdmmc);
|
||||
sdmmc_save_tap_value(storage->sdmmc);
|
||||
|
||||
if (!_mmc_storage_enable_HS(storage, 0))
|
||||
return 0;
|
||||
|
@ -727,7 +757,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_wid
|
|||
storage->sdmmc = sdmmc;
|
||||
storage->rca = 2; //TODO: this could be a config item.
|
||||
|
||||
if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_POWER_SAVE_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after init\n");
|
||||
|
||||
|
@ -798,7 +828,9 @@ DPRINTF("[MMC] BKOPS enabled\n");
|
|||
return 0;
|
||||
DPRINTF("[MMC] succesfully switched to HS mode\n");
|
||||
|
||||
sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
sdmmc_card_clock_powersave(storage->sdmmc, SDMMC_POWER_SAVE_ENABLE);
|
||||
|
||||
storage->initialized = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -812,6 +844,7 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
|||
return 0;
|
||||
|
||||
storage->partition = partition;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -850,7 +883,7 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage)
|
|||
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)
|
||||
static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int bus_low_voltage_support)
|
||||
{
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
// Support for Current > 150mA
|
||||
|
@ -858,7 +891,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int
|
|||
// 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;
|
||||
arg |= (bus_low_voltage_support & ~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);
|
||||
|
@ -868,22 +901,24 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int
|
|||
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)
|
||||
static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int bus_low_voltage_support)
|
||||
{
|
||||
u64 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))
|
||||
if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, bus_low_voltage_support))
|
||||
break;
|
||||
if (cond & MMC_CARD_BUSY)
|
||||
{
|
||||
DPRINTF("[SD] cond: %08X, lv: %d\n", cond, bus_low_voltage_support);
|
||||
|
||||
if (cond & SD_OCR_CCS)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
// Check if card supports 1.8V signaling.
|
||||
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
||||
if (cond & SD_ROCR_S18A && bus_low_voltage_support)
|
||||
{
|
||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||
if (storage->sdmmc->id == SDMMC_1 &&
|
||||
|
@ -896,6 +931,10 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
|||
DPRINTF("-> switched to low voltage\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF("[SD] no low voltage support\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1050,12 +1089,15 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit,
|
|||
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 400mA\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
case SD_SET_CURRENT_LIMIT_200:
|
||||
DPRINTF("[SD] power limit defaulted to 200mA\n");
|
||||
|
@ -1068,7 +1110,7 @@ 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] supports switch to (U)HS mode\n");
|
||||
DPRINTF("[SD] supports (U)HS mode: %d\n", buf[16] & 0xF);
|
||||
|
||||
u32 type_out = buf[16] & 0xF;
|
||||
if (type_out != hs_type)
|
||||
|
@ -1104,6 +1146,7 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
|
|||
|
||||
u8 access_mode = buf[13];
|
||||
u16 current_limit = buf[7] | buf[6] << 8;
|
||||
DPRINTF("[SD] access: %02X, current: %02X\n", access_mode, current_limit);
|
||||
|
||||
// Try to raise the current limit to let the card perform better.
|
||||
_sd_storage_set_current_limit(storage, current_limit, buf);
|
||||
|
@ -1142,7 +1185,7 @@ DPRINTF("[SD] bus speed set to SDR50\n");
|
|||
if (access_mode & SD_MODE_UHS_SDR25)
|
||||
{
|
||||
type = SDHCI_TIMING_UHS_SDR25;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
hs_type = UHS_SDR25_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR25\n");
|
||||
storage->csd.busspeed = 25;
|
||||
break;
|
||||
|
@ -1155,6 +1198,7 @@ DPRINTF("[SD] bus speed set to SDR25\n");
|
|||
DPRINTF("[SD] bus speed set to SDR12\n");
|
||||
storage->csd.busspeed = 12;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -1165,10 +1209,10 @@ DPRINTF("[SD] bus speed set to SDR12\n");
|
|||
DPRINTF("[SD] card accepted UHS\n");
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||
return 0;
|
||||
DPRINTF("[SD] setup clock\n");
|
||||
DPRINTF("[SD] after setup clock\n");
|
||||
if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
||||
return 0;
|
||||
DPRINTF("[SD] config tuning\n");
|
||||
DPRINTF("[SD] after tuning\n");
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
|
@ -1227,6 +1271,7 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
|
|||
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;
|
||||
|
@ -1235,7 +1280,7 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
|
|||
}
|
||||
}
|
||||
|
||||
static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type)
|
||||
static bool _sdmmc_storage_get_low_voltage_support(u32 bus_width, u32 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -1261,7 +1306,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_widt
|
|||
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, SDMMC_AUTO_CAL_DISABLE))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_POWER_SAVE_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[SD] after init\n");
|
||||
|
||||
|
@ -1276,9 +1321,9 @@ DPRINTF("[SD] went to idle state\n");
|
|||
return 0;
|
||||
DPRINTF("[SD] after send if cond\n");
|
||||
|
||||
bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type);
|
||||
bool bus_low_voltage_support = _sdmmc_storage_get_low_voltage_support(bus_width, type);
|
||||
|
||||
if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage))
|
||||
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_low_voltage_support))
|
||||
return 0;
|
||||
DPRINTF("[SD] got op cond\n");
|
||||
|
||||
|
@ -1356,7 +1401,7 @@ DPRINTF("[SD] SD does not support wide bus width\n");
|
|||
return 0;
|
||||
DPRINTF("[SD] enabled UHS\n");
|
||||
|
||||
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE);
|
||||
}
|
||||
else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
{
|
||||
|
@ -1369,12 +1414,15 @@ DPRINTF("[SD] enabled HS\n");
|
|||
case SDMMC_BUS_WIDTH_4:
|
||||
storage->csd.busspeed = 25;
|
||||
break;
|
||||
|
||||
case SDMMC_BUS_WIDTH_1:
|
||||
storage->csd.busspeed = 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
storage->initialized = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1414,17 +1462,19 @@ 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_DDR52, SDMMC_AUTO_CAL_DISABLE))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS102, SDMMC_POWER_SAVE_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[gc] after init\n");
|
||||
|
||||
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS102, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
DPRINTF("[gc] after tuning\n");
|
||||
|
||||
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE);
|
||||
|
||||
storage->initialized = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -54,16 +54,19 @@ typedef struct _mmc_csd
|
|||
|
||||
typedef struct _mmc_ext_csd
|
||||
{
|
||||
u8 rev;
|
||||
u32 sectors;
|
||||
int bkops; /* background support bit */
|
||||
int bkops_en; /* manual bkops enable bit */
|
||||
u8 rev;
|
||||
u8 ext_struct; /* 194 */
|
||||
u8 card_type; /* 196 */
|
||||
u8 bkops_status; /* 246 */
|
||||
u16 dev_version;
|
||||
u8 pre_eol_info;
|
||||
u8 dev_life_est_a;
|
||||
u8 dev_life_est_b;
|
||||
u8 boot_mult;
|
||||
u8 rpmb_mult;
|
||||
u16 dev_version;
|
||||
} mmc_ext_csd_t;
|
||||
|
||||
typedef struct _sd_scr
|
||||
|
@ -81,6 +84,7 @@ typedef struct _sd_ssr
|
|||
u8 uhs_grade;
|
||||
u8 video_class;
|
||||
u8 app_class;
|
||||
u32 protected_size;
|
||||
} sd_ssr_t;
|
||||
|
||||
/*! SDMMC storage context. */
|
||||
|
@ -99,6 +103,7 @@ typedef struct _sdmmc_storage_t
|
|||
mmc_csd_t csd;
|
||||
mmc_ext_csd_t ext_csd;
|
||||
sd_scr_t scr;
|
||||
int initialized;
|
||||
} sdmmc_storage_t;
|
||||
|
||||
extern sdmmc_accessor_t *_current_accessor;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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,
|
||||
|
@ -58,12 +58,15 @@ static int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 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;
|
||||
}
|
||||
|
@ -96,7 +99,7 @@ void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width)
|
|||
sdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS;
|
||||
}
|
||||
|
||||
void sdmmc_set_tap_value(sdmmc_t *sdmmc)
|
||||
void sdmmc_save_tap_value(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16;
|
||||
sdmmc->venclkctl_set = 1;
|
||||
|
@ -105,7 +108,7 @@ void sdmmc_set_tap_value(sdmmc_t *sdmmc)
|
|||
static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type)
|
||||
{
|
||||
const u32 dqs_trim_val = 0x28;
|
||||
const u32 tap_values[] = { 4, 0, 3, 0 };
|
||||
const u32 tap_values_t210[] = { 4, 0, 3, 0 };
|
||||
|
||||
u32 tap_val = 0;
|
||||
|
||||
|
@ -122,36 +125,49 @@ static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type)
|
|||
tap_val = sdmmc->venclkctl_tap;
|
||||
}
|
||||
else
|
||||
{
|
||||
tap_val = tap_values[sdmmc->id];
|
||||
}
|
||||
tap_val = sdmmc->t210b01 ? 11 : tap_values_t210[sdmmc->id];
|
||||
|
||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _sdmmc_get_clkcon(sdmmc_t *sdmmc)
|
||||
static int _sdmmc_commit_changes(sdmmc_t *sdmmc)
|
||||
{
|
||||
return sdmmc->regs->clkcon;
|
||||
}
|
||||
|
||||
static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_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 (power == SDMMC_POWER_1_8)
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm.
|
||||
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)
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm.
|
||||
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:
|
||||
case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16.
|
||||
APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -169,13 +185,13 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
|||
if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD))
|
||||
{
|
||||
sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
// Enable auto calibration and start auto configuration.
|
||||
sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep(2);
|
||||
|
||||
u64 timeout = get_tmr_ms() + 10;
|
||||
|
@ -187,24 +203,18 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
|||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Check if PU results are inside limits.
|
||||
// SDMMC1: CZ pads - 7-bit PU. SDMMC2/4: LV_CZ pads - 5-bit PU.
|
||||
u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x7F;
|
||||
switch (sdmmc->id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
if (!autocal_pu_status || autocal_pu_status == 0x7F)
|
||||
timeout = 0;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
case SDMMC_4:
|
||||
autocal_pu_status &= 0x1F;
|
||||
if (!autocal_pu_status || autocal_pu_status == 0x1F)
|
||||
timeout = 0;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
#if 0
|
||||
// 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.
|
||||
u8 code_mask = (sdmmc->t210b01 || sdmmc->id != SDMMC_1) ? 0x1F : 0x7F;
|
||||
u8 autocal_pu_status = sdmmc->regs->autocalsts & code_mask;
|
||||
if (!autocal_pu_status)
|
||||
EPRINTF("SDMMC: Comp Pad short to gnd!");
|
||||
else if (autocal_pu_status == code_mask)
|
||||
EPRINTF("SDMMC: Comp Pad open!");
|
||||
#endif
|
||||
|
||||
// In case auto calibration fails, we load suggested standard values.
|
||||
if (!timeout)
|
||||
{
|
||||
|
@ -230,7 +240,7 @@ static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc)
|
|||
}
|
||||
|
||||
sdmmc->regs->vendllcalcfg |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
u64 timeout = get_tmr_ms() + 5;
|
||||
while (sdmmc->regs->vendllcalcfg & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE)
|
||||
|
@ -261,12 +271,21 @@ out:;
|
|||
static void _sdmmc_reset(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
u64 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)
|
||||
;
|
||||
}
|
||||
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
{
|
||||
// Disable the SD clock if it was enabled, and reenable it later.
|
||||
|
@ -290,36 +309,41 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
|||
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 for SDR50, the host must be set to SDR104.
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
case SDHCI_TIMING_MMC_DDR52:
|
||||
case SDHCI_TIMING_MMC_HS102:
|
||||
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;
|
||||
}
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
u32 clock;
|
||||
u16 divisor;
|
||||
|
@ -349,10 +373,10 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
|||
static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc)
|
||||
{
|
||||
// Recalibrate conditionally.
|
||||
if ((sdmmc->id == SDMMC_1) && !sdmmc->auto_cal_enabled)
|
||||
if (sdmmc->manual_cal && !sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
if (!sdmmc->auto_cal_enabled)
|
||||
if (!sdmmc->powersave_enabled)
|
||||
{
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
|
@ -366,18 +390,17 @@ static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc)
|
|||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable)
|
||||
void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable)
|
||||
{
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if ((sdmmc->id == SDMMC_1) && !auto_cal_enable && sdmmc->card_clock_enabled)
|
||||
if (sdmmc->manual_cal && !powersave_enable && sdmmc->card_clock_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
sdmmc->auto_cal_enabled = auto_cal_enable;
|
||||
if (auto_cal_enable)
|
||||
sdmmc->powersave_enabled = powersave_enable;
|
||||
if (powersave_enable)
|
||||
{
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
return;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -398,6 +421,7 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
return 0;
|
||||
rsp[0] = sdmmc->regs->rspreg0;
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 0x10)
|
||||
return 0;
|
||||
|
@ -426,9 +450,9 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
rsp[i - 1] |= (tempreg >> 24) & 0xFF;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -449,6 +473,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
return 0;
|
||||
rsp[0] = sdmmc->rsp[0];
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 0x10)
|
||||
return 0;
|
||||
|
@ -457,9 +482,9 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
rsp[2] = sdmmc->rsp[2];
|
||||
rsp[3] = sdmmc->rsp[3];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -467,7 +492,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
|
||||
static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
u64 timeout = get_tmr_ms() + 2000;
|
||||
while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT)
|
||||
|
@ -493,7 +518,7 @@ static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat)
|
|||
|
||||
static int _sdmmc_wait_card_busy(sdmmc_t *sdmmc)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
u64 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK))
|
||||
|
@ -512,16 +537,19 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
|
|||
{
|
||||
case SDMMC_BUS_WIDTH_1:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -533,6 +561,7 @@ static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_presen
|
|||
{
|
||||
case SDMMC_RSP_TYPE_0:
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_1:
|
||||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
|
@ -541,15 +570,17 @@ static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_presen
|
|||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_data_present)
|
||||
|
@ -572,7 +603,7 @@ static void _sdmmc_send_tuning_cmd(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd)
|
||||
{
|
||||
if (sdmmc->auto_cal_enabled)
|
||||
if (sdmmc->powersave_enabled)
|
||||
return 0;
|
||||
if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, true))
|
||||
return 0;
|
||||
|
@ -584,13 +615,13 @@ static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
_sdmmc_send_tuning_cmd(sdmmc, cmd);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
u64 timeout = get_tmr_us() + 5000;
|
||||
while (get_tmr_us() < timeout)
|
||||
|
@ -599,7 +630,7 @@ static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
{
|
||||
sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL;
|
||||
sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
return 1;
|
||||
}
|
||||
|
@ -608,7 +639,7 @@ static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
return 0;
|
||||
|
@ -627,15 +658,18 @@ int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
max = 128;
|
||||
flag = (2 << 13); // 128 iterations.
|
||||
break;
|
||||
|
||||
case SDHCI_TIMING_UHS_SDR50:
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
case SDHCI_TIMING_MMC_DDR52:
|
||||
case SDHCI_TIMING_MMC_HS102:
|
||||
max = 256;
|
||||
flag = (4 << 13); // 256 iterations.
|
||||
break;
|
||||
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -664,7 +698,7 @@ 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_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
u64 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE))
|
||||
{
|
||||
|
@ -700,17 +734,28 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power)
|
|||
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;
|
||||
if (!sdmmc->t210b01)
|
||||
{
|
||||
off_pd = 123;
|
||||
off_pu = 123;
|
||||
}
|
||||
else
|
||||
{
|
||||
off_pd = 6;
|
||||
off_pu = 6;
|
||||
}
|
||||
}
|
||||
else if (power == SDMMC_POWER_3_3)
|
||||
{
|
||||
off_pd = 125;
|
||||
off_pu = 0;
|
||||
if (!sdmmc->t210b01)
|
||||
{
|
||||
off_pd = 125;
|
||||
off_pu = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
@ -740,7 +785,7 @@ 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);
|
||||
DPRINTF("norintsts %08X, errintsts %08X\n", norintsts, errintsts);
|
||||
|
||||
if (pout)
|
||||
*pout = norintsts;
|
||||
|
@ -762,7 +807,7 @@ DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts);
|
|||
|
||||
static int _sdmmc_wait_response(sdmmc_t *sdmmc)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
u64 timeout = get_tmr_ms() + 2000;
|
||||
while (true)
|
||||
|
@ -813,7 +858,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
return 0;
|
||||
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if ((sdmmc->id == SDMMC_1) && sdmmc->auto_cal_enabled)
|
||||
if (sdmmc->manual_cal && sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
bool should_disable_sd_clock = false;
|
||||
|
@ -821,7 +866,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
{
|
||||
should_disable_sd_clock = true;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
}
|
||||
|
||||
|
@ -842,7 +887,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
u32 blkcnt = req->num_sectors;
|
||||
if (blkcnt >= 0xFFFF)
|
||||
blkcnt = 0xFFFF;
|
||||
|
||||
|
||||
u64 admaaddr = (u64)sdmmc_calculate_dma_addr(_current_accessor, req->buf, blkcnt);
|
||||
if (!admaaddr)
|
||||
{
|
||||
|
@ -861,7 +906,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
|
||||
sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFFFFFFFFFF80000;
|
||||
|
||||
sdmmc->regs->blksize = req->blksize | 0x7000;
|
||||
sdmmc->regs->blksize = req->blksize | 0x7000; // DMA 512KB (Detects A18 carry out).
|
||||
sdmmc->regs->blkcnt = blkcnt;
|
||||
|
||||
if (blkcnt_out)
|
||||
|
@ -953,8 +998,6 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
|||
|
||||
is_data_present = true;
|
||||
}
|
||||
else
|
||||
is_data_present = false;
|
||||
|
||||
_sdmmc_enable_interrupts(sdmmc);
|
||||
|
||||
|
@ -962,7 +1005,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
|||
return 0;
|
||||
|
||||
int result = _sdmmc_wait_response(sdmmc);
|
||||
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result,
|
||||
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result,
|
||||
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
|
||||
if (result)
|
||||
{
|
||||
|
@ -970,12 +1013,6 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
|||
{
|
||||
sdmmc->expected_rsp_type = cmd->rsp_type;
|
||||
result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type);
|
||||
|
||||
/*if(sdmmc->rsp[0] & 0xFDF9A080)
|
||||
{
|
||||
res = 0;
|
||||
sdmmc->rsp[0] = 0; // Reset error
|
||||
}*/
|
||||
}
|
||||
|
||||
if (req && result)
|
||||
|
@ -1029,7 +1066,56 @@ bool sdmmc_get_sd_inserted()
|
|||
return (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1));
|
||||
}
|
||||
|
||||
static int _sdmmc_config_sdmmc1()
|
||||
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 dicharging.
|
||||
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.
|
||||
|
@ -1044,76 +1130,102 @@ static int _sdmmc_config_sdmmc1()
|
|||
|
||||
/*
|
||||
* Pinmux config:
|
||||
* DRV_TYPE = DRIVE_2X
|
||||
* DRV_TYPE = DRIVE_2X (for 33 Ohm driver)
|
||||
* 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;
|
||||
// Enable deep loopback for SDMMC1 CLK pad.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
|
||||
|
||||
// Configure SDMMC1 CLK pinmux, based on state and SoC type.
|
||||
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 the reset 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.
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, PMC_NO_IOPOWER_SDMMC1_IO_EN, PMC_NO_IOPOWER_SDMMC1_IO_EN);
|
||||
usleep(1000);
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, ~PMC_NO_IOPOWER_SDMMC1_IO_EN, PMC_NO_IOPOWER_SDMMC1_IO_EN);
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, 0, 0); // Commit write.
|
||||
|
||||
// Inform IO pads that voltage is gonna be 3.3V.
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN);
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, 0, 0); // Commit write.
|
||||
|
||||
// Set enable SD card power.
|
||||
//PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; // Pull down.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; // GPIO control, pull down.
|
||||
//PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; // Proper pinmuxing. Breaks on HOS, takes over 1 minute to recover.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; // Wrong but working pinmuxing. Instant take over by FS.
|
||||
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);
|
||||
usleep(10000);
|
||||
|
||||
// Enable SD card power.
|
||||
// Enable SD card IO power.
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 1);
|
||||
usleep(1000);
|
||||
|
||||
// Set pad slew codes to get good quality clock.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000;
|
||||
usleep(1000);
|
||||
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)
|
||||
static void _sdmmc_config_emmc(u32 id, bool t210b01)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SDMMC_2:
|
||||
// Unset park for pads.
|
||||
APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF;
|
||||
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.
|
||||
APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040;
|
||||
|
||||
// Enabled schmitt trigger.
|
||||
APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; // Enable Schmitt trigger.
|
||||
if (t210b01)
|
||||
APB_MISC(APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL) &= 0xFFBFFFF9; // Unset CMD/CLK/DQS powedown.
|
||||
// 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, int auto_cal_enable)
|
||||
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int powersave_enable)
|
||||
{
|
||||
const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||
u32 clock;
|
||||
u16 divisor;
|
||||
u8 vref_sel = 7;
|
||||
|
||||
if (id > SDMMC_4)
|
||||
const u32 trim_values_t210[] = { 2, 8, 3, 8 };
|
||||
const u32 trim_values_t210b01[] = { 14, 13, 15, 13 };
|
||||
const u32 *trim_values = sdmmc->t210b01 ? trim_values_t210b01 : trim_values_t210;
|
||||
|
||||
if (id > SDMMC_4 || id == SDMMC_3)
|
||||
return 0;
|
||||
|
||||
memset(sdmmc, 0, sizeof(sdmmc_t));
|
||||
|
@ -1121,45 +1233,57 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a
|
|||
sdmmc->regs = (t210_sdmmc_t *)QueryIoMapping(_sdmmc_bases[id], 0x200);
|
||||
sdmmc->id = id;
|
||||
sdmmc->clock_stopped = 1;
|
||||
sdmmc->t210b01 = splGetSocType() == SplSocType_Mariko;
|
||||
|
||||
// Do specific SDMMC HW configuration.
|
||||
switch (id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
if (!_sdmmc_config_sdmmc1())
|
||||
if (!_sdmmc_config_sdmmc1(sdmmc->t210b01))
|
||||
return 0;
|
||||
if (sdmmc->t210b01)
|
||||
vref_sel = 0;
|
||||
else
|
||||
sdmmc->manual_cal = 1;
|
||||
break;
|
||||
|
||||
case SDMMC_2:
|
||||
case SDMMC_4:
|
||||
_sdmmc_config_emmc(id);
|
||||
_sdmmc_config_emmc(id, sdmmc->t210b01);
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable clock if enabled.
|
||||
if (clock_sdmmc_is_not_reset_and_enabled(id))
|
||||
{
|
||||
_sdmmc_sd_clock_disable(sdmmc);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
}
|
||||
|
||||
u32 clock;
|
||||
u16 divisor;
|
||||
// Configure and enable selected clock.
|
||||
clock_sdmmc_get_card_clock_div(&clock, &divisor, type);
|
||||
clock_sdmmc_enable(id, clock);
|
||||
|
||||
// Make sure all sdmmc registers are reset.
|
||||
_sdmmc_reset_all(sdmmc);
|
||||
|
||||
sdmmc->clock_stopped = 0;
|
||||
|
||||
//TODO: make this skip-able.
|
||||
// Set default pad IO trimming configuration.
|
||||
sdmmc->regs->iospare |= 0x80000; // Enable muxing.
|
||||
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB; // Set Band Gap VREG to supply DLL.
|
||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | (trim_values[sdmmc->id] << 24);
|
||||
sdmmc->regs->sdmemcmppadctl =
|
||||
(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | 7;
|
||||
(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | vref_sel;
|
||||
|
||||
// Configure auto calibration values.
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
// 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);
|
||||
|
@ -1167,18 +1291,50 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a
|
|||
|
||||
if (sdmmc_setup_clock(sdmmc, type))
|
||||
{
|
||||
sdmmc_card_clock_ctrl(sdmmc, auto_cal_enable);
|
||||
sdmmc_card_clock_powersave(sdmmc, powersave_enable);
|
||||
_sdmmc_card_clock_enable(sdmmc);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdmmc1_disable_power()
|
||||
{
|
||||
// Clear pull down from CLK pad.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_PULL_MASK;
|
||||
|
||||
// Set pads to discharge state.
|
||||
_sdmmc_config_sdmmc1_pads(true);
|
||||
|
||||
// Disable SD card IO power regulator.
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
usleep(4000);
|
||||
|
||||
// Disable SD card IO power pin.
|
||||
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW);
|
||||
|
||||
// T210/T210B01 WAR: Set start timer for IO and Controller power discharge.
|
||||
msleep(239);
|
||||
|
||||
// Disable SDMMC1 controller power.
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, PMC_NO_IOPOWER_SDMMC1_IO_EN, PMC_NO_IOPOWER_SDMMC1_IO_EN);
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, 0, 0); // Commit write.
|
||||
|
||||
// Inform IO pads that next voltage might be 3.3V.
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN);
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, 0, 0); // Commit write.
|
||||
|
||||
// Set pads to reset state.
|
||||
_sdmmc_config_sdmmc1_pads(false);
|
||||
|
||||
// Set pull down to CLK pad.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_PULL_DOWN;
|
||||
}
|
||||
|
||||
void sdmmc_end(sdmmc_t *sdmmc)
|
||||
{
|
||||
if (!sdmmc->clock_stopped)
|
||||
|
@ -1189,17 +1345,9 @@ void sdmmc_end(sdmmc_t *sdmmc)
|
|||
|
||||
// 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);
|
||||
sdmmc1_disable_power();
|
||||
|
||||
// Inform IO pads that next voltage might be 3.3V.
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN);
|
||||
|
||||
msleep(100); // To power cycle min 1ms without power is needed.
|
||||
}
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
clock_sdmmc_disable(sdmmc->id);
|
||||
sdmmc->clock_stopped = 1;
|
||||
}
|
||||
|
@ -1219,7 +1367,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
return 0;
|
||||
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->id == SDMMC_1 && sdmmc->auto_cal_enabled)
|
||||
if (sdmmc->manual_cal && sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
int should_disable_sd_clock = 0;
|
||||
|
@ -1227,7 +1375,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
{
|
||||
should_disable_sd_clock = 1;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
}
|
||||
|
||||
|
@ -1248,36 +1396,32 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12))
|
||||
return 0;
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
// Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed.
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||
usleep(300);
|
||||
usleep(150);
|
||||
|
||||
// Inform IO pads that we switched to 1.8V.
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, ~PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN);
|
||||
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, 0, 0); // Commit write.
|
||||
|
||||
// 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;
|
||||
_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_get_clkcon(sdmmc);
|
||||
_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_get_clkcon(sdmmc);
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
usleep(1000);
|
||||
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
||||
if ((sdmmc->regs->prnsts & SDHCI_DATA_LVL_MASK) == SDHCI_DATA_LVL_MASK)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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,
|
||||
|
@ -195,13 +195,13 @@
|
|||
#define SDHCI_TIMING_UHS_SDR104 11
|
||||
#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock.
|
||||
#define SDHCI_TIMING_UHS_DDR50 13
|
||||
#define SDHCI_TIMING_MMC_DDR52 14
|
||||
#define SDHCI_TIMING_MMC_HS102 14
|
||||
|
||||
#define SDHCI_CAN_64BIT 0x10000000
|
||||
|
||||
/*! SDMMC Low power features. */
|
||||
#define SDMMC_AUTO_CAL_DISABLE 0
|
||||
#define SDMMC_AUTO_CAL_ENABLE 1
|
||||
#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))
|
||||
|
@ -213,7 +213,8 @@ typedef struct _sdmmc_t
|
|||
u32 id;
|
||||
u32 divisor;
|
||||
u32 clock_stopped;
|
||||
int auto_cal_enabled;
|
||||
int powersave_enabled;
|
||||
int manual_cal;
|
||||
int card_clock_enabled;
|
||||
int venclkctl_set;
|
||||
u32 venclkctl_tap;
|
||||
|
@ -222,6 +223,7 @@ typedef struct _sdmmc_t
|
|||
u64 dma_addr_next;
|
||||
u32 rsp[4];
|
||||
u32 rsp3;
|
||||
int t210b01;
|
||||
} sdmmc_t;
|
||||
|
||||
/*! SDMMC command. */
|
||||
|
@ -247,15 +249,15 @@ typedef struct _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_set_tap_value(sdmmc_t *sdmmc);
|
||||
void sdmmc_save_tap_value(sdmmc_t *sdmmc);
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
|
||||
void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable);
|
||||
void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable);
|
||||
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
|
||||
int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);
|
||||
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
|
||||
int sdmmc_get_sd_power_enabled();
|
||||
bool sdmmc_get_sd_inserted();
|
||||
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable);
|
||||
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int powersave_enable);
|
||||
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);
|
||||
|
|
|
@ -103,6 +103,7 @@ typedef struct _t210_sdmmc_t
|
|||
vu32 iospare;
|
||||
vu32 mcciffifoctl;
|
||||
vu32 timeoutwcoal;
|
||||
vu32 unk1;
|
||||
} t210_sdmmc_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -155,8 +155,8 @@ void __initheap(void)
|
|||
static void _receive_process_handle_thread(void *_session_handle) {
|
||||
Result rc;
|
||||
|
||||
// Convert the argument to a handle we can use.
|
||||
Handle session_handle = (Handle)(uintptr_t)_session_handle;
|
||||
// Convert the argument to a handle copy we can use.
|
||||
Handle session_handle = *(Handle*)_session_handle;
|
||||
|
||||
// Receive the request from the client thread.
|
||||
memset(armGetTls(), 0, 0x10);
|
||||
|
@ -194,7 +194,7 @@ static void _init_process_handle(void) {
|
|||
|
||||
// Create a new thread to receive our handle.
|
||||
Handle thread_handle;
|
||||
rc = svcCreateThread(&thread_handle, _receive_process_handle_thread, (void *)(uintptr_t)server_handle, temp_thread_stack + sizeof(temp_thread_stack), 0x20, 3);
|
||||
rc = svcCreateThread(&thread_handle, _receive_process_handle_thread, &server_handle, temp_thread_stack + sizeof(temp_thread_stack), 0x20, 3);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
|
|
|
@ -59,6 +59,47 @@ Result smcGetConfig(SplConfigItem config_item, u64 *out_config)
|
|||
return rc;
|
||||
}
|
||||
|
||||
SplHardwareType splGetHardwareType(void)
|
||||
{
|
||||
u64 value;
|
||||
Result rc = smcGetConfig(SplConfigItem_HardwareType, &value);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
return (SplHardwareType)value;
|
||||
}
|
||||
|
||||
SplSocType splGetSocType(void)
|
||||
{
|
||||
static SplSocType soc_type;
|
||||
static bool soc_type_set = false;
|
||||
|
||||
if (soc_type_set)
|
||||
return soc_type;
|
||||
|
||||
switch (splGetHardwareType())
|
||||
{
|
||||
case SplHardwareType_Icosa:
|
||||
case SplHardwareType_Copper:
|
||||
soc_type = SplSocType_Erista;
|
||||
break;
|
||||
case SplHardwareType_Hoag:
|
||||
case SplHardwareType_Iowa:
|
||||
case SplHardwareType_Calcio:
|
||||
case SplHardwareType_Five:
|
||||
soc_type = SplSocType_Mariko;
|
||||
break;
|
||||
default:
|
||||
fatal_abort(Fatal_InvalidEnum);
|
||||
}
|
||||
|
||||
soc_type_set = true;
|
||||
|
||||
return soc_type;
|
||||
}
|
||||
|
||||
|
||||
Result smcCopyToIram(uintptr_t iram_addr, const void *src_addr, u32 size)
|
||||
{
|
||||
SecmonArgs args;
|
||||
|
|
|
@ -37,6 +37,20 @@ typedef enum {
|
|||
SplConfigItem_HasRcmBugPatch = 65004,
|
||||
} SplConfigItem;
|
||||
|
||||
typedef enum {
|
||||
SplSocType_Erista = 0,
|
||||
SplSocType_Mariko = 1,
|
||||
} SplSocType;
|
||||
|
||||
typedef enum {
|
||||
SplHardwareType_Icosa = 0,
|
||||
SplHardwareType_Copper = 1,
|
||||
SplHardwareType_Hoag = 2,
|
||||
SplHardwareType_Iowa = 3,
|
||||
SplHardwareType_Calcio = 4,
|
||||
SplHardwareType_Five = 5,
|
||||
} SplHardwareType;
|
||||
|
||||
typedef enum {
|
||||
EXO_EMUMMC_TYPE_NONE = 0,
|
||||
EXO_EMUMMC_TYPE_PARTITION = 1,
|
||||
|
@ -69,6 +83,9 @@ typedef struct {
|
|||
|
||||
Result smcGetConfig(SplConfigItem config_item, u64 *out_config);
|
||||
|
||||
SplHardwareType splGetHardwareType(void);
|
||||
SplSocType splGetSocType(void);
|
||||
|
||||
void smcRebootToRcm(void);
|
||||
void smcRebootToIramPayload(void);
|
||||
void smcPerformShutdown(void);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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,
|
||||
|
@ -410,7 +411,7 @@ void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)
|
|||
*pclock = 40800;
|
||||
*pdivisor = 1;
|
||||
break;
|
||||
case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz.
|
||||
case SDHCI_TIMING_MMC_HS102: // Actual IO Freq: 99.84 MHz.
|
||||
*pclock = 200000;
|
||||
*pdivisor = 2;
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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,
|
||||
|
@ -17,78 +18,151 @@
|
|||
#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
|
||||
};
|
||||
#define GPIO_BANK_IDX(port) ((port) >> 2)
|
||||
|
||||
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
|
||||
};
|
||||
#define GPIO_CNF_OFFSET(port) (0x00 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_OE_OFFSET(port) (0x10 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_OUT_OFFSET(port) (0x20 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_IN_OFFSET(port) (0x30 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_STA_OFFSET(port) (0x40 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_ENB_OFFSET(port) (0x50 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_LVL_OFFSET(port) (0x60 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_CLR_OFFSET(port) (0x70 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
|
||||
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
|
||||
};
|
||||
#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_OE_MASKED_OFFSET(port) (0x90 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + (((port) >> 2) << 8) + (((port) % 4) << 2))
|
||||
|
||||
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
|
||||
#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)
|
||||
{
|
||||
u32 offset = GPIO_CNF_OFFSET(port);
|
||||
|
||||
if (mode)
|
||||
GPIO(_gpio_cnf[port]) |= pins;
|
||||
GPIO(offset) |= pins;
|
||||
else
|
||||
GPIO(_gpio_cnf[port]) &= ~pins;
|
||||
(void)GPIO(_gpio_cnf[port]);
|
||||
GPIO(offset) &= ~pins;
|
||||
|
||||
(void)GPIO(offset); // Commit the write.
|
||||
}
|
||||
|
||||
void gpio_output_enable(u32 port, u32 pins, int enable)
|
||||
{
|
||||
u32 port_offset = GPIO_OE_OFFSET(port);
|
||||
|
||||
if (enable)
|
||||
GPIO(_gpio_oe[port]) |= pins;
|
||||
GPIO(port_offset) |= pins;
|
||||
else
|
||||
GPIO(_gpio_oe[port]) &= ~pins;
|
||||
(void)GPIO(_gpio_oe[port]);
|
||||
GPIO(port_offset) &= ~pins;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
}
|
||||
|
||||
void gpio_write(u32 port, u32 pins, int high)
|
||||
{
|
||||
u32 port_offset = GPIO_OUT_OFFSET(port);
|
||||
|
||||
if (high)
|
||||
GPIO(_gpio_out[port]) |= pins;
|
||||
GPIO(port_offset) |= pins;
|
||||
else
|
||||
GPIO(_gpio_out[port]) &= ~pins;
|
||||
(void)GPIO(_gpio_out[port]);
|
||||
GPIO(port_offset) &= ~pins;
|
||||
|
||||
(void)GPIO(port_offset); // Commit the write.
|
||||
}
|
||||
|
||||
int gpio_read(u32 port, u32 pins)
|
||||
{
|
||||
return (GPIO(_gpio_in[port]) & pins) ? 1 : 0;
|
||||
u32 port_offset = GPIO_IN_OFFSET(port);
|
||||
|
||||
return (GPIO(port_offset) & pins) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void _gpio_interrupt_clear(u32 port, u32 pins)
|
||||
{
|
||||
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)
|
||||
{
|
||||
u32 port_offset = GPIO_INT_STA_OFFSET(port);
|
||||
u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins;
|
||||
|
||||
int status = ((GPIO(port_offset) & pins) && enabled) ? 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
u32 bank_idx = GPIO_BANK_IDX(port);
|
||||
|
||||
return gpio_bank_irq_ids[bank_idx];
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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,
|
||||
|
@ -21,10 +22,23 @@
|
|||
|
||||
#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)
|
||||
|
@ -72,6 +86,10 @@
|
|||
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);
|
||||
int gpio_read(u32 port, u32 pins);
|
||||
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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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,25 +21,88 @@
|
|||
#include "../utils/util.h"
|
||||
#include "t210.h"
|
||||
|
||||
// TODO: not hardcode I2C_5
|
||||
static u64 i2c_addrs[] = {
|
||||
0x7000C000, 0x7000C400, 0x7000C500,
|
||||
0x7000C700, 0x7000D000, 0x7000D100
|
||||
#define I2C_PACKET_PROT_I2C (1 << 4)
|
||||
#define I2C_HEADER_CONT_XFER (1 << 15)
|
||||
#define I2C_HEADER_REP_START (1 << 16)
|
||||
#define I2C_HEADER_IE_ENABLE (1 << 17)
|
||||
#define I2C_HEADER_READ (1 << 19)
|
||||
|
||||
#define I2C_CNFG (0x00 / 4)
|
||||
#define CMD1_WRITE (0 << 6)
|
||||
#define CMD1_READ (1 << 6)
|
||||
#define NORMAL_MODE_GO (1 << 9)
|
||||
#define PACKET_MODE_GO (1 << 10)
|
||||
#define NEW_MASTER_FSM (1 << 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 (1 << 8)
|
||||
|
||||
#define I2C_TX_FIFO (0x50 / 4)
|
||||
#define I2C_RX_FIFO (0x54 / 4)
|
||||
|
||||
#define I2C_FIFO_CONTROL (0x5C / 4)
|
||||
#define RX_FIFO_FLUSH (1 << 0)
|
||||
#define TX_FIFO_FLUSH (1 << 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 (1 << 0)
|
||||
#define TX_FIFO_DATA_REQ (1 << 1)
|
||||
#define ARB_LOST (1 << 2)
|
||||
#define NO_ACK (1 << 3)
|
||||
#define RX_FIFO_UNDER (1 << 4)
|
||||
#define TX_FIFO_OVER (1 << 5)
|
||||
#define ALL_PACKETS_COMPLETE (1 << 6)
|
||||
#define PACKET_COMPLETE (1 << 7)
|
||||
#define BUS_CLEAR_DONE (1 << 11)
|
||||
|
||||
#define I2C_CLK_DIVISOR (0x6C / 4)
|
||||
|
||||
#define I2C_BUS_CLEAR_CONFIG (0x84 / 4)
|
||||
#define BC_ENABLE (1 << 0)
|
||||
#define BC_TERMINATE (1 << 1)
|
||||
|
||||
#define I2C_BUS_CLEAR_STATUS (0x88 / 4)
|
||||
|
||||
#define I2C_CONFIG_LOAD (0x8C / 4)
|
||||
#define MSTR_CONFIG_LOAD (1 << 0)
|
||||
#define TIMEOUT_CONFIG_LOAD (1 << 2)
|
||||
|
||||
static const u64 i2c_addrs[] = {
|
||||
0x7000C000, // I2C_1.
|
||||
0x7000C400, // I2C_2.
|
||||
0x7000C500, // I2C_3.
|
||||
0x7000C700, // I2C_4.
|
||||
0x7000D000, // I2C_5.
|
||||
0x7000D100 // I2C_6.
|
||||
};
|
||||
|
||||
static void _i2c_wait(vu32 *base)
|
||||
static void _i2c_load_cfg_wait(vu32 *base)
|
||||
{
|
||||
base[I2C_CONFIG_LOAD] = 0x25;
|
||||
|
||||
base[I2C_CONFIG_LOAD] = (1 << 5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD;
|
||||
for (u32 i = 0; i < 20; i++)
|
||||
{
|
||||
usleep(1);
|
||||
if (!(base[I2C_CONFIG_LOAD] & 1))
|
||||
if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
||||
static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size)
|
||||
{
|
||||
if (size > 4)
|
||||
return 0;
|
||||
|
@ -47,46 +111,58 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
|||
memcpy(&tmp, buf, size);
|
||||
|
||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000);
|
||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||
|
||||
// Set device address and send mode.
|
||||
base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE;
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
// Set size and send mode.
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
// Load configuration.
|
||||
_i2c_load_cfg_wait(base);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 1500;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
// Initiate transaction on normal mode.
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO;
|
||||
|
||||
u64 timeout = get_tmr_ms() + 100;
|
||||
while (base[I2C_STATUS] & I2C_STATUS_BUSY)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (base[I2C_STATUS] << 28)
|
||||
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
||||
static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
|
||||
{
|
||||
if (size > 8)
|
||||
if (size > 4)
|
||||
return 0;
|
||||
|
||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000);
|
||||
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.
|
||||
// Set device address and recv mode.
|
||||
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
// Set size and recv mode.
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;
|
||||
|
||||
u32 timeout = get_tmr_ms() + 1500;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
// Load configuration.
|
||||
_i2c_load_cfg_wait(base);
|
||||
|
||||
// Initiate transaction on normal mode.
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO;
|
||||
|
||||
u64 timeout = get_tmr_ms() + 100;
|
||||
while (base[I2C_STATUS] & I2C_STATUS_BUSY)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (base[I2C_STATUS] << 28)
|
||||
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
|
||||
return 0;
|
||||
|
||||
u32 tmp = base[I2C_CMD_DATA1]; // Get LS value.
|
||||
|
@ -106,50 +182,52 @@ void i2c_init()
|
|||
{
|
||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000);
|
||||
|
||||
base[I2C_CLK_DIVISOR_REGISTER] = 0x50001;
|
||||
base[I2C_BUS_CLEAR_CONFIG] = 0x90003;
|
||||
_i2c_wait(base);
|
||||
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[INTERRUPT_STATUS_REGISTER] & 0x800)
|
||||
if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE)
|
||||
break;
|
||||
}
|
||||
|
||||
(vu32)base[I2C_BUS_CLEAR_STATUS];
|
||||
base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER];
|
||||
base[I2C_INT_STATUS] = base[I2C_INT_STATUS];
|
||||
}
|
||||
|
||||
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
||||
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size)
|
||||
{
|
||||
u8 tmp[4];
|
||||
|
||||
if (size > 3)
|
||||
return 0;
|
||||
|
||||
tmp[0] = y;
|
||||
tmp[0] = reg;
|
||||
memcpy(tmp + 1, buf, size);
|
||||
|
||||
return _i2c_send_pkt(idx, x, tmp, size + 1);
|
||||
return _i2c_send_single(i2c_idx, dev_addr, tmp, size + 1);
|
||||
}
|
||||
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
|
||||
{
|
||||
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
|
||||
int res = _i2c_send_single(i2c_idx, dev_addr, (u8 *)®, 1);
|
||||
if (res)
|
||||
res = _i2c_recv_pkt(idx, buf, size, x);
|
||||
res = _i2c_recv_single(i2c_idx, buf, size, dev_addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b)
|
||||
int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val)
|
||||
{
|
||||
return i2c_send_buf_small(idx, x, y, &b, 1);
|
||||
return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1);
|
||||
}
|
||||
|
||||
u8 i2c_recv_byte(u32 idx, u32 x, u32 y)
|
||||
u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg)
|
||||
{
|
||||
u8 tmp = 0;
|
||||
i2c_recv_buf_small(&tmp, 1, idx, x, y);
|
||||
i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -26,21 +27,10 @@
|
|||
#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();
|
||||
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);
|
||||
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, 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
|
||||
|
|
|
@ -51,6 +51,18 @@
|
|||
#define PINMUX_AUX_GPIO_PE6 0x248
|
||||
#define PINMUX_AUX_GPIO_PH6 0x250
|
||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||
/* 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,7 +90,8 @@
|
|||
#define PINMUX_OPEN_DRAIN (1 << 11)
|
||||
#define PINMUX_SCHMT (1 << 12)
|
||||
|
||||
#define PINMUX_DRIVE_1X (0 << 13)
|
||||
#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)
|
||||
|
|
|
@ -35,6 +35,7 @@ enum FatalReason
|
|||
Fatal_FatfsMount,
|
||||
Fatal_FatfsFileOpen,
|
||||
Fatal_FatfsMemExhaustion,
|
||||
Fatal_InvalidEnum,
|
||||
Fatal_Max
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ static inline uintptr_t _GetIoMapping(u64 io_addr, u64 io_size)
|
|||
u64 vaddr;
|
||||
u64 aligned_addr = (io_addr & ~0xFFFul);
|
||||
u64 aligned_size = io_size + (io_addr - aligned_addr);
|
||||
|
||||
if (emuMMC_ctx.fs_ver >= FS_VER_10_0_0) {
|
||||
u64 out_size;
|
||||
if (svcQueryIoMapping(&vaddr, &out_size, aligned_addr, aligned_size) != 0) {
|
||||
|
@ -48,6 +49,7 @@ static inline uintptr_t _GetIoMapping(u64 io_addr, u64 io_size)
|
|||
fatal_abort(Fatal_IoMappingLegacy);
|
||||
}
|
||||
}
|
||||
|
||||
return (uintptr_t)(vaddr + (io_addr - aligned_addr));
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,7 @@ for i in range(6):
|
|||
if i < len(section_names):
|
||||
section["Name"] = section_names[i]
|
||||
|
||||
section["OutOffset"], section["DecompressedSize"], section["CompressedSize"], section["Attribute"] = unpack(
|
||||
"IIII", section_bytes)
|
||||
section["OutOffset"], section["DecompressedSize"], section["CompressedSize"], section["Attribute"] = unpack("IIII", section_bytes)
|
||||
sections.append(section)
|
||||
print(section)
|
||||
|
||||
|
|
|
@ -5,22 +5,39 @@ define ATMOSPHERE_ADD_TARGET
|
|||
|
||||
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
|
||||
|
||||
$(strip $1): exosphere$(strip $2).bin warmboot/warmboot$(strip $2).bin
|
||||
@cp warmboot/warmboot$(strip $2).bin warmboot$(strip $2).bin
|
||||
$(strip $1): exosphere$(strip $2).bin warmboot$(strip $2).bin mariko_fatal$(strip $2).bin
|
||||
|
||||
exosphere$(strip $2).bin: loader_stub/loader_stub$(strip $2).bin
|
||||
@cp loader_stub/loader_stub$(strip $2).bin exosphere$(strip $2).bin
|
||||
@printf LENY >> exosphere$(strip $2).bin
|
||||
@echo "Built exosphere$(strip $2).bin..."
|
||||
|
||||
warmboot/warmboot$(strip $2).bin:
|
||||
warmboot$(strip $2).bin: warmboot/warmboot$(strip $2).bin
|
||||
@cp warmboot/warmboot$(strip $2).bin warmboot$(strip $2).bin
|
||||
@echo "Built warmboot$(strip $2).bin..."
|
||||
|
||||
mariko_fatal$(strip $2).bin: mariko_fatal/mariko_fatal$(strip $2).bin
|
||||
@cp mariko_fatal/mariko_fatal$(strip $2).bin mariko_fatal$(strip $2).bin
|
||||
@echo "Built mariko_fatal$(strip $2).bin..."
|
||||
|
||||
check_program_$(strip $1):
|
||||
@$$(MAKE) -C program $(strip $1)
|
||||
|
||||
check_warmboot_$(strip $1):
|
||||
@$$(MAKE) -C warmboot $(strip $1)
|
||||
|
||||
loader_stub/loader_stub$(strip $2).bin:
|
||||
check_mariko_fatal_$(strip $1):
|
||||
@$$(MAKE) -C mariko_fatal $(strip $1)
|
||||
|
||||
loader_stub/loader_stub$(strip $2).bin: check_program_$(strip $1)
|
||||
@$$(MAKE) -C loader_stub $(strip $1)
|
||||
|
||||
clean-$(strip $1): clean-program-$(strip $1) clean-loader_stub-$(strip $1) clean-warmboot-$(strip $1)
|
||||
@rm -rf exosphere$(strip $2).bin warmboot$(strip $2).bin
|
||||
warmboot/warmboot$(strip $2).bin: check_warmboot_$(strip $1)
|
||||
|
||||
mariko_fatal/mariko_fatal$(strip $2).bin: check_mariko_fatal_$(strip $1)
|
||||
|
||||
clean-$(strip $1): clean-program-$(strip $1) clean-loader_stub-$(strip $1) clean-warmboot-$(strip $1) clean-mariko_fatal-$(strip $1)
|
||||
@rm -rf exosphere$(strip $2).bin warmboot$(strip $2).bin mariko_fatal$(strip $2).bin
|
||||
|
||||
clean-program-$(strip $1):
|
||||
@$$(MAKE) -C program clean-$(strip $1)
|
||||
|
@ -31,6 +48,9 @@ clean-loader_stub-$(strip $1):
|
|||
clean-warmboot-$(strip $1):
|
||||
@$$(MAKE) -C warmboot clean-$(strip $1)
|
||||
|
||||
clean-mariko_fatal-$(strip $1):
|
||||
@$$(MAKE) -C mariko_fatal clean-$(strip $1)
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, release, ))
|
||||
|
@ -38,7 +58,7 @@ $(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug))
|
|||
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit))
|
||||
|
||||
clean: clean-program clean-loader_stub clean-warmboot
|
||||
@rm -rf exosphere*.bin warmboot*.bin
|
||||
@rm -rf exosphere*.bin warmboot*.bin mariko_fatal*.bin
|
||||
|
||||
clean-program:
|
||||
@$(MAKE) -C program clean
|
||||
|
@ -49,4 +69,7 @@ clean-loader_stub:
|
|||
clean-warmboot:
|
||||
@$(MAKE) -C warmboot clean
|
||||
|
||||
.PHONY: all clean clean-program clean-loader_stub clean-warmboot $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config) clean-program-$(config) clean-loader_stub-$(config) clean-warmboot-$(config))
|
||||
clean-mariko_fatal:
|
||||
@$(MAKE) -C mariko_fatal clean
|
||||
|
||||
.PHONY: all clean clean-program clean-loader_stub clean-warmboot $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),check_program_$(config) check_warmboot_$(strip $1) clean-$(config) clean-program-$(config) clean-loader_stub-$(config) clean-warmboot-$(config))
|
||||
|
|
|
@ -24,6 +24,7 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
|||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
BINFILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
|
@ -40,7 +41,7 @@ endif
|
|||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC) program.lz4.o boot_code.lz4.o
|
||||
export OFILES := $(OFILES_SRC) program.lz4.o boot_code.lz4.o
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace ams::secmon::loader {
|
|||
/* Uncompress the program image. */
|
||||
Uncompress(secmon::MemoryRegionPhysicalTzramFullProgramImage.GetPointer(), secmon::MemoryRegionPhysicalTzramFullProgramImage.GetSize(), program_lz4, program_lz4_size);
|
||||
|
||||
|
||||
/* Copy the boot image to the end of IRAM */
|
||||
u8 *relocated_boot_code = secmon::MemoryRegionPhysicalIramBootCodeImage.GetEndPointer<u8>() - boot_code_lz4_size;
|
||||
std::memcpy(relocated_boot_code, boot_code_lz4, boot_code_lz4_size);
|
||||
|
@ -32,7 +31,6 @@ namespace ams::secmon::loader {
|
|||
/* Uncompress the boot image. */
|
||||
Uncompress(secmon::MemoryRegionPhysicalIramBootCodeImage.GetPointer(), secmon::MemoryRegionPhysicalIramBootCodeImage.GetSize(), relocated_boot_code, boot_code_lz4_size);
|
||||
|
||||
|
||||
/* Jump to the boot image. */
|
||||
reinterpret_cast<void (*)()>(secmon::MemoryRegionPhysicalIramBootCodeImage.GetAddress())();
|
||||
|
||||
|
|
141
exosphere/mariko_fatal/Makefile
Normal file
141
exosphere/mariko_fatal/Makefile
Normal file
|
@ -0,0 +1,141 @@
|
|||
#---------------------------------------------------------------------------------
|
||||
# Define the atmosphere board and cpu
|
||||
#---------------------------------------------------------------------------------
|
||||
export ATMOSPHERE_BOARD := nx-hac-001
|
||||
export ATMOSPHERE_CPU := arm-cortex-a57
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# pull in common atmosphere configuration
|
||||
#---------------------------------------------------------------------------------
|
||||
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
|
||||
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(__RECURSIVE__),1)
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
BINFILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES))))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I.
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
|
||||
|
||||
export TOPDIR := $(CURRENT_DIRECTORY)
|
||||
|
||||
OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ATMOSPHERE_BUILD_CONFIGS :=
|
||||
all: release
|
||||
|
||||
define ATMOSPHERE_ADD_TARGET
|
||||
|
||||
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
|
||||
|
||||
$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1)
|
||||
@$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \
|
||||
DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
|
||||
LIBEXOSPHERE_NAME=exosphere$(strip $2) \
|
||||
--no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
|
||||
-f $$(THIS_MAKEFILE)
|
||||
|
||||
check_libexo_$(strip $1):
|
||||
@$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1)
|
||||
|
||||
clean-$(strip $1):
|
||||
@echo clean $(strip $1) ...
|
||||
@rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \
|
||||
ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \
|
||||
))
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \
|
||||
ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \
|
||||
))
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \
|
||||
ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \
|
||||
))
|
||||
|
||||
$(ATMOSPHERE_BUILD_DIR)/%:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config))
|
||||
|
||||
.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
$(OUTPUT).bin : $(OUTPUT).elf
|
||||
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a
|
||||
|
||||
%.elf:
|
||||
@echo linking $(notdir $@)
|
||||
$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
|
||||
diskio.o ff.o: CFLAGS += -Wno-error
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h: %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
227
exosphere/mariko_fatal/mariko_fatal.ld
Normal file
227
exosphere/mariko_fatal/mariko_fatal.ld
Normal file
|
@ -0,0 +1,227 @@
|
|||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
NULL : ORIGIN = 0, LENGTH = 4K
|
||||
mariko_tzram : ORIGIN = 0x1F00D0000, LENGTH = 128K
|
||||
}
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* =========== CODE section =========== */
|
||||
PROVIDE(__start__ = ORIGIN(mariko_tzram));
|
||||
. = __start__;
|
||||
__code_start = . ;
|
||||
|
||||
.crt0 :
|
||||
{
|
||||
KEEP (*(.crt0 .crt0.*))
|
||||
KEEP (fatal_crt0_cpp.o(.text*))
|
||||
*(.crt0.rodata*)
|
||||
fatal_crt0_cpp.o(.rodata*)
|
||||
*(.crt0.data*)
|
||||
fatal_crt0_cpp.o(.data*)
|
||||
. = ALIGN(8);
|
||||
} >mariko_tzram
|
||||
|
||||
.preinit_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
} >mariko_tzram
|
||||
|
||||
.init_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE (__init_array_end = .);
|
||||
} >mariko_tzram
|
||||
|
||||
.fini_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE (__fini_array_end = .);
|
||||
} >mariko_tzram
|
||||
|
||||
.ctors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} >mariko_tzram
|
||||
|
||||
.dtors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} >mariko_tzram
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
. = ALIGN(8);
|
||||
} >mariko_tzram
|
||||
|
||||
.init :
|
||||
{
|
||||
KEEP( *(.init) )
|
||||
. = ALIGN(8);
|
||||
} >mariko_tzram
|
||||
|
||||
.plt :
|
||||
{
|
||||
*(.plt)
|
||||
*(.iplt)
|
||||
. = ALIGN(8);
|
||||
} >mariko_tzram
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP( *(.fini) )
|
||||
. = ALIGN(8);
|
||||
} >mariko_tzram
|
||||
|
||||
|
||||
/* =========== RODATA section =========== */
|
||||
. = ALIGN(8);
|
||||
__rodata_start = . ;
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
. = ALIGN(8);
|
||||
} >mariko_tzram
|
||||
|
||||
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >mariko_tzram
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >mariko_tzram
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >mariko_tzram
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >mariko_tzram
|
||||
|
||||
.hash : { *(.hash) } >mariko_tzram
|
||||
|
||||
/* =========== DATA section =========== */
|
||||
. = ALIGN(8);
|
||||
__data_start = . ;
|
||||
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >mariko_tzram
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >mariko_tzram
|
||||
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >mariko_tzram
|
||||
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >mariko_tzram
|
||||
|
||||
.preinit_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
} >mariko_tzram
|
||||
|
||||
.init_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE (__init_array_end = .);
|
||||
} >mariko_tzram
|
||||
|
||||
.fini_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE (__fini_array_end = .);
|
||||
} >mariko_tzram
|
||||
|
||||
.ctors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} >mariko_tzram
|
||||
|
||||
.dtors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} >mariko_tzram
|
||||
|
||||
__got_start__ = .;
|
||||
|
||||
.got : { *(.got) *(.igot) } >mariko_tzram
|
||||
.got.plt : { *(.got.plt) *(.igot.plt) } >mariko_tzram
|
||||
|
||||
__got_end__ = .;
|
||||
|
||||
.data ALIGN(8) :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
} >mariko_tzram
|
||||
|
||||
__bss_start__ = .;
|
||||
.bss ALIGN(8) :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
} >mariko_tzram
|
||||
__bss_end__ = .;
|
||||
|
||||
__end__ = ABSOLUTE(.) ;
|
||||
|
||||
/* ==================
|
||||
==== Metadata ====
|
||||
================== */
|
||||
|
||||
/* Discard sections that difficult post-processing */
|
||||
/DISCARD/ : { *(.group .comment .note .interp) }
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
}
|
7
exosphere/mariko_fatal/mariko_fatal.specs
Normal file
7
exosphere/mariko_fatal/mariko_fatal.specs
Normal file
|
@ -0,0 +1,7 @@
|
|||
%rename link old_link
|
||||
|
||||
*link:
|
||||
%(old_link) -T %:getenv(TOPDIR /mariko_fatal.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
||||
|
||||
*startfile:
|
||||
crti%O%s crtbegin%O%s
|
31
exosphere/mariko_fatal/source/fatal_abort_impl.cpp
Normal file
31
exosphere/mariko_fatal/source/fatal_abort_impl.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
AMS_SECMON_LOG("AbortImpl was called\n");
|
||||
AMS_LOG_FLUSH();
|
||||
reg::Write(0x4, 0xAAAAAAAA);
|
||||
|
||||
/* TODO: Reboot */
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
#include <exosphere/diag/diag_detailed_assertion_impl.inc>
|
||||
|
||||
}
|
38
exosphere/mariko_fatal/source/fatal_crt0.s
Normal file
38
exosphere/mariko_fatal/source/fatal_crt0.s
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.section .crt0.text.start, "ax", %progbits
|
||||
.align 6
|
||||
.global _start
|
||||
_start:
|
||||
/* Set the stack pointer to a temporary location. */
|
||||
ldr x20, =0x1F00FC000
|
||||
mov sp, x20
|
||||
|
||||
/* Save any arguments we may have. */
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
/* Initialize all memory to expected state. */
|
||||
ldr x0, =__bss_start__
|
||||
ldr x1, =__bss_end__
|
||||
bl _ZN3ams6secmon5fatal10InitializeEmm
|
||||
|
||||
/* Restore any arguments we may have. */
|
||||
ldp x0, x1, [sp], #16
|
||||
|
||||
/* Jump to the fatal program. */
|
||||
ldr x16, =_ZN3ams6secmon5fatal4MainEv
|
||||
br x16
|
30
exosphere/mariko_fatal/source/fatal_crt0_cpp.cpp
Normal file
30
exosphere/mariko_fatal/source/fatal_crt0_cpp.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
extern "C" void __libc_init_array();
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void Initialize(uintptr_t bss_start, size_t bss_end) {
|
||||
/* Clear bss. */
|
||||
std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start);
|
||||
|
||||
/* Call init array. */
|
||||
__libc_init_array();
|
||||
}
|
||||
|
||||
}
|
352
exosphere/mariko_fatal/source/fatal_device_page_table.cpp
Normal file
352
exosphere/mariko_fatal/source/fatal_device_page_table.cpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Definitions. */
|
||||
constexpr size_t PageDirectorySize = mmu::PageSize;
|
||||
constexpr size_t PageTableSize = mmu::PageSize;
|
||||
static_assert(PageDirectorySize == mmu::PageSize);
|
||||
|
||||
using DeviceVirtualAddress = u64;
|
||||
|
||||
constexpr size_t AsidCount = 0x80;
|
||||
constexpr size_t PhysicalAddressBits = 34;
|
||||
constexpr size_t PhysicalAddressMask = (1ul << PhysicalAddressBits) - 1ul;
|
||||
constexpr size_t DeviceVirtualAddressBits = 34;
|
||||
constexpr size_t DeviceVirtualAddressMask = (1ul << DeviceVirtualAddressBits) - 1ul;
|
||||
|
||||
constexpr size_t DevicePageBits = 12;
|
||||
constexpr size_t DevicePageSize = (1ul << DevicePageBits);
|
||||
static_assert(DevicePageSize == mmu::PageSize);
|
||||
|
||||
constexpr size_t DeviceLargePageBits = 22;
|
||||
constexpr size_t DeviceLargePageSize = (1ul << DeviceLargePageBits);
|
||||
static_assert(DeviceLargePageSize % DevicePageSize == 0);
|
||||
|
||||
constexpr size_t DeviceRegionBits = 32;
|
||||
constexpr size_t DeviceRegionSize = (1ul << DeviceRegionBits);
|
||||
static_assert(DeviceRegionSize % DeviceLargePageSize == 0);
|
||||
|
||||
constexpr const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
|
||||
|
||||
constexpr size_t TableCount = (1ul << DeviceVirtualAddressBits) / DeviceRegionSize;
|
||||
|
||||
consteval u32 EncodeAsidRegisterValue(u8 asid) {
|
||||
u32 value = 0x80000000u;
|
||||
for (size_t t = 0; t < TableCount; t++) {
|
||||
value |= (asid << (BITSIZEOF(u8) * t));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr u8 SdmmcAsid = 1;
|
||||
constexpr u8 DcAsid = 2;
|
||||
|
||||
constexpr u32 SdmmcAsidRegisterValue = EncodeAsidRegisterValue(SdmmcAsid);
|
||||
constexpr u32 DcAsidRegisterValue = EncodeAsidRegisterValue(DcAsid);
|
||||
|
||||
constexpr dd::PhysicalAddress DcL0PageTablePhysical = MemoryRegionPhysicalDramDcL0DevicePageTable.GetAddress();
|
||||
constexpr dd::PhysicalAddress SdmmcL0PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L0DevicePageTable.GetAddress();
|
||||
constexpr dd::PhysicalAddress SdmmcL1PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L1DevicePageTable.GetAddress();
|
||||
|
||||
/* Types. */
|
||||
class EntryBase {
|
||||
protected:
|
||||
enum Bit : u32 {
|
||||
Bit_Table = 28,
|
||||
Bit_NonSecure = 29,
|
||||
Bit_Writeable = 30,
|
||||
Bit_Readable = 31,
|
||||
};
|
||||
private:
|
||||
u32 value;
|
||||
protected:
|
||||
constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const {
|
||||
return (this->value & (1u << n));
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
|
||||
return this->SelectBit(n) != 0;
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 EncodeBit(Bit n, bool en) {
|
||||
return en ? (1u << n) : 0;
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 EncodeValue(bool r, bool w, bool ns, dd::PhysicalAddress addr, bool t) {
|
||||
return EncodeBit(Bit_Readable, r) | EncodeBit(Bit_Writeable, w) | EncodeBit(Bit_NonSecure, ns) | EncodeBit(Bit_Table, t) | static_cast<u32>(addr >> DevicePageBits);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SetValue(u32 v) {
|
||||
/* Prevent re-ordering around entry modifications. */
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
this->value = v;
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
}
|
||||
public:
|
||||
static constexpr ALWAYS_INLINE u32 EncodePtbDataValue(dd::PhysicalAddress addr) {
|
||||
return EncodeValue(true, true, true, addr, false);
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); }
|
||||
constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); }
|
||||
constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); }
|
||||
constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); }
|
||||
|
||||
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); }
|
||||
|
||||
constexpr ALWAYS_INLINE dd::PhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(this->value) << DevicePageBits) & PhysicalAddressMask; }
|
||||
|
||||
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
|
||||
};
|
||||
|
||||
class PageDirectoryEntry : public EntryBase {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBit(Bit_Table); }
|
||||
|
||||
ALWAYS_INLINE void SetTable(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
|
||||
AMS_ASSERT(util::IsAligned(addr, DevicePageSize));
|
||||
this->SetValue(EncodeValue(r, w, ns, addr, true));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SetLargePage(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
|
||||
AMS_ASSERT(util::IsAligned(addr, DeviceLargePageSize));
|
||||
this->SetValue(EncodeValue(r, w, ns, addr, false));
|
||||
}
|
||||
};
|
||||
|
||||
class PageTableEntry : public EntryBase {
|
||||
public:
|
||||
ALWAYS_INLINE void SetPage(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
|
||||
AMS_ASSERT(util::IsAligned(addr, DevicePageSize));
|
||||
this->SetValue(EncodeValue(r, w, ns, addr, true));
|
||||
}
|
||||
};
|
||||
|
||||
/* Memory controller access functionality. */
|
||||
void WriteMcRegister(size_t offset, u32 value) {
|
||||
reg::Write(MC + offset, value);
|
||||
}
|
||||
|
||||
u32 ReadMcRegister(size_t offset) {
|
||||
return reg::Read(MC + offset);
|
||||
}
|
||||
|
||||
/* Memory controller utilities. */
|
||||
void SmmuSynchronizationBarrier() {
|
||||
ReadMcRegister(MC_SMMU_CONFIG);
|
||||
}
|
||||
|
||||
void InvalidatePtc() {
|
||||
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0);
|
||||
}
|
||||
|
||||
void InvalidatePtc(dd::PhysicalAddress address) {
|
||||
WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast<u64>(address) >> 32));
|
||||
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (address & 0xFFFFFFF0u) | 1u);
|
||||
}
|
||||
|
||||
enum TlbFlushVaMatch : u32 {
|
||||
TlbFlushVaMatch_All = 0,
|
||||
TlbFlushVaMatch_Section = 2,
|
||||
TlbFlushVaMatch_Group = 3,
|
||||
};
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 EncodeTlbFlushValue(bool match_asid, u8 asid, dd::PhysicalAddress address, TlbFlushVaMatch match) {
|
||||
return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match);
|
||||
}
|
||||
|
||||
void InvalidateTlb() {
|
||||
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All));
|
||||
}
|
||||
|
||||
void InvalidateTlb(u8 asid) {
|
||||
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All));
|
||||
}
|
||||
|
||||
void InvalidateTlbSection(u8 asid, dd::PhysicalAddress address) {
|
||||
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section));
|
||||
}
|
||||
|
||||
void SetTable(u8 asid, dd::PhysicalAddress address) {
|
||||
/* Write the table address. */
|
||||
{
|
||||
WriteMcRegister(MC_SMMU_PTB_ASID, asid);
|
||||
WriteMcRegister(MC_SMMU_PTB_DATA, EntryBase::EncodePtbDataValue(address));
|
||||
|
||||
SmmuSynchronizationBarrier();
|
||||
}
|
||||
|
||||
/* Ensure consistency. */
|
||||
InvalidatePtc();
|
||||
InvalidateTlb(asid);
|
||||
SmmuSynchronizationBarrier();
|
||||
}
|
||||
|
||||
void MapImpl(dd::PhysicalAddress phys_addr, size_t size, DeviceVirtualAddress address, u8 asid, void *l0_table, dd::PhysicalAddress l0_phys, void *l1_table, dd::PhysicalAddress l1_phys) {
|
||||
/* Validate L0. */
|
||||
AMS_ABORT_UNLESS(l0_table != nullptr);
|
||||
AMS_ABORT_UNLESS(l0_phys != 0);
|
||||
|
||||
/* Cache permissions. */
|
||||
const bool read = true;
|
||||
const bool write = true;
|
||||
|
||||
/* Walk the directory. */
|
||||
u64 remaining = size;
|
||||
while (remaining > 0) {
|
||||
const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize;
|
||||
const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize;
|
||||
|
||||
/* Get and validate l1. */
|
||||
PageDirectoryEntry *l1 = static_cast<PageDirectoryEntry *>(l0_table);
|
||||
AMS_ASSERT(l1 != nullptr);
|
||||
|
||||
/* Setup an l1 table/entry, if needed. */
|
||||
if (!l1[l1_index].IsTable()) {
|
||||
/* Check that an entry doesn't already exist. */
|
||||
AMS_ASSERT(!l1[l1_index].IsValid());
|
||||
|
||||
/* If we can make an l1 entry, do so. */
|
||||
if (l2_index == 0 && util::IsAligned(phys_addr, DeviceLargePageSize) && remaining >= DeviceLargePageSize) {
|
||||
/* Set the large page. */
|
||||
l1[l1_index].SetLargePage(read, write, true, phys_addr);
|
||||
hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
|
||||
|
||||
/* Synchronize. */
|
||||
InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry));
|
||||
InvalidateTlbSection(asid, address);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Advance. */
|
||||
phys_addr += DeviceLargePageSize;
|
||||
address += DeviceLargePageSize;
|
||||
remaining -= DeviceLargePageSize;
|
||||
continue;
|
||||
} else {
|
||||
/* Make an l1 table. */
|
||||
AMS_ABORT_UNLESS(l1_table != nullptr);
|
||||
AMS_ABORT_UNLESS(l1_phys != 0);
|
||||
|
||||
/* Clear the l1 table. */
|
||||
std::memset(l1_table, 0, mmu::PageSize);
|
||||
hw::FlushDataCache(l1_table, mmu::PageSize);
|
||||
|
||||
/* Set the l1 table. */
|
||||
l1[l1_index].SetTable(true, true, true, l1_phys);
|
||||
hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
|
||||
|
||||
/* Synchronize. */
|
||||
InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry));
|
||||
InvalidateTlbSection(asid, address);
|
||||
SmmuSynchronizationBarrier();
|
||||
}
|
||||
}
|
||||
|
||||
/* If we get to this point, l1 must be a table. */
|
||||
AMS_ASSERT(l1[l1_index].IsTable());
|
||||
AMS_ABORT_UNLESS(l1_table != nullptr);
|
||||
AMS_ABORT_UNLESS(l1_phys != 0);
|
||||
|
||||
/* Map l2 entries. */
|
||||
{
|
||||
PageTableEntry *l2 = static_cast<PageTableEntry *>(l1_table);
|
||||
|
||||
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
||||
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
||||
|
||||
/* Set the entries. */
|
||||
for (size_t i = 0; i < map_count; ++i) {
|
||||
AMS_ASSERT(!l2[l2_index + i].IsValid());
|
||||
l2[l2_index + i].SetPage(read, write, true, phys_addr + DevicePageSize * i);
|
||||
}
|
||||
hw::FlushDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
|
||||
|
||||
/* Invalidate the page table cache. */
|
||||
for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) {
|
||||
InvalidatePtc(l1_phys + i * sizeof(PageTableEntry));
|
||||
}
|
||||
|
||||
/* Synchronize. */
|
||||
InvalidateTlbSection(asid, address);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Advance. */
|
||||
phys_addr += map_count * DevicePageSize;
|
||||
address += map_count * DevicePageSize;
|
||||
remaining -= map_count * DevicePageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeDevicePageTableForSdmmc1() {
|
||||
/* Configure sdmmc to use our new page table. */
|
||||
WriteMcRegister(MC_SMMU_SDMMC1A_ASID, SdmmcAsidRegisterValue);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Ensure consistency. */
|
||||
InvalidatePtc();
|
||||
InvalidateTlb();
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Clear the L0 Page Table. */
|
||||
std::memset(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize);
|
||||
hw::FlushDataCache(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), mmu::PageSize);
|
||||
|
||||
/* Set the page table for the sdmmc asid. */
|
||||
SetTable(SdmmcAsid, SdmmcL0PageTablePhysical);
|
||||
|
||||
/* Map the appropriate region into the asid. */
|
||||
MapImpl(MemoryRegionPhysicalDramSdmmcMappedData.GetAddress(), MemoryRegionPhysicalDramSdmmcMappedData.GetSize(), MemoryRegionVirtualDramSdmmcMappedData.GetAddress(),
|
||||
SdmmcAsid,
|
||||
MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), SdmmcL0PageTablePhysical,
|
||||
MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer<void>(), SdmmcL1PageTablePhysical);
|
||||
}
|
||||
|
||||
void InitializeDevicePageTableForDc() {
|
||||
/* Configure dc to use our new page table. */
|
||||
WriteMcRegister(MC_SMMU_DC_ASID, DcAsidRegisterValue);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Ensure consistency. */
|
||||
InvalidatePtc();
|
||||
InvalidateTlb();
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Clear the L0 Page Table. */
|
||||
std::memset(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize);
|
||||
hw::FlushDataCache(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), mmu::PageSize);
|
||||
|
||||
/* Set the page table for the dc asid. */
|
||||
SetTable(DcAsid, DcL0PageTablePhysical);
|
||||
|
||||
/* Map the appropriate region into the asid. */
|
||||
static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetAddress(), DeviceLargePageSize));
|
||||
static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetSize(), DeviceLargePageSize));
|
||||
|
||||
MapImpl(MemoryRegionDramDcFramebuffer.GetAddress(), MemoryRegionDramDcFramebuffer.GetSize(), MemoryRegionDramDcFramebuffer.GetAddress(),
|
||||
DcAsid,
|
||||
MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), DcL0PageTablePhysical,
|
||||
nullptr, 0);
|
||||
}
|
||||
|
||||
}
|
24
exosphere/mariko_fatal/source/fatal_device_page_table.hpp
Normal file
24
exosphere/mariko_fatal/source/fatal_device_page_table.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void InitializeDevicePageTableForSdmmc1();
|
||||
void InitializeDevicePageTableForDc();
|
||||
|
||||
}
|
602
exosphere/mariko_fatal/source/fatal_display.cpp
Normal file
602
exosphere/mariko_fatal/source/fatal_display.cpp
Normal file
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_device_page_table.hpp"
|
||||
#include "fatal_registers_di.hpp"
|
||||
#include "fatal_display.hpp"
|
||||
#include "fatal_print.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
#include "fatal_display_config.inc"
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* Helpful defines. */
|
||||
constexpr int DsiWaitForCommandMilliSecondsMax = 250;
|
||||
constexpr int DsiWaitForCommandCompletionMilliSeconds = 5;
|
||||
constexpr int DsiWaitForHostControlMilliSecondsMax = 150;
|
||||
|
||||
constexpr inline int I2cAddressMax77620Pmic = 0x3C;
|
||||
|
||||
constexpr size_t GPIO_PORT3_CNF_0 = 0x200;
|
||||
constexpr size_t GPIO_PORT3_OE_0 = 0x210;
|
||||
constexpr size_t GPIO_PORT3_OUT_0 = 0x220;
|
||||
|
||||
constexpr size_t GPIO_PORT6_CNF_1 = 0x504;
|
||||
constexpr size_t GPIO_PORT6_OE_1 = 0x514;
|
||||
constexpr size_t GPIO_PORT6_OUT_1 = 0x524;
|
||||
|
||||
/* Globals. */
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionVirtualDevicePmc .GetAddress();
|
||||
constexpr inline const uintptr_t g_disp1_regs = secmon::MemoryRegionVirtualDeviceDisp1 .GetAddress();
|
||||
constexpr inline const uintptr_t g_dsi_regs = secmon::MemoryRegionVirtualDeviceDsi .GetAddress();
|
||||
constexpr inline const uintptr_t g_clk_rst_regs = secmon::MemoryRegionVirtualDeviceClkRst .GetAddress();
|
||||
constexpr inline const uintptr_t g_gpio_regs = secmon::MemoryRegionVirtualDeviceGpio .GetAddress();
|
||||
constexpr inline const uintptr_t g_apb_misc_regs = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress();
|
||||
constexpr inline const uintptr_t g_mipi_cal_regs = secmon::MemoryRegionVirtualDeviceMipiCal.GetAddress();
|
||||
|
||||
constinit u32 *g_frame_buffer = nullptr;
|
||||
|
||||
inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
reg::Write(base_address + reg_writes[i].offset, reg_writes[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) {
|
||||
switch (GetSocType()) {
|
||||
case fuse::SocType_Erista: DoRegisterWrites(base_address, reg_writes_erista, num_writes_erista); break;
|
||||
case fuse::SocType_Mariko: DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
inline void DoSleepOrRegisterWrites(uintptr_t base_address, const SleepOrRegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
switch (reg_writes[i].kind) {
|
||||
case SleepOrRegisterWriteKind_Write:
|
||||
reg::Write(base_address + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value);
|
||||
break;
|
||||
case SleepOrRegisterWriteKind_Sleep:
|
||||
util::WaitMicroSeconds(reg_writes[i].offset * UINT64_C(1000));
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaitDsiTrigger() {
|
||||
const u32 timeout = util::GetMicroSeconds() + (DsiWaitForCommandMilliSecondsMax * 1000u);
|
||||
|
||||
while (true) {
|
||||
if (util::GetMicroSeconds() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
util::WaitMicroSeconds(DsiWaitForCommandCompletionMilliSeconds * 1000u);
|
||||
}
|
||||
|
||||
void WaitDsiHostControl() {
|
||||
const u32 timeout = util::GetMicroSeconds() + (DsiWaitForHostControlMilliSecondsMax * 1000u);
|
||||
|
||||
while (true) {
|
||||
if (util::GetMicroSeconds() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EnableBacklightForVendor2050ForHardwareTypeFive(int brightness) {
|
||||
/* Enable FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 2);
|
||||
|
||||
/* Configure DSI_LINE_TYPE as FOUR */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 9);
|
||||
|
||||
/* Set and wait for FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ }
|
||||
|
||||
/* Configure display brightness. */
|
||||
const u32 brightness_val = ((0x7FF * brightness) / 100);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, (brightness_val & 0x700) | ((brightness_val & 0xFF) << 16) | 0x51);
|
||||
|
||||
/* Set and wait for FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ }
|
||||
|
||||
/* Set client sync point block reset. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 1);
|
||||
util::WaitMicroSeconds(300'000ul);
|
||||
|
||||
/* Clear client sync point block resest. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 0);
|
||||
util::WaitMicroSeconds(300'000ul);
|
||||
|
||||
/* Clear DSI_LINE_TYPE config. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0);
|
||||
|
||||
/* Disable FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 0);
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
}
|
||||
|
||||
void EnableBacklightForGeneric(int brightness) {
|
||||
AMS_UNUSED(brightness);
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
}
|
||||
|
||||
#define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes))
|
||||
#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko))
|
||||
#define DO_SLEEP_OR_REGISTER_WRITES(base_address, writes) DoSleepOrRegisterWrites(base_address, writes, util::size(writes))
|
||||
|
||||
void InitializeFrameBuffer() {
|
||||
if (g_frame_buffer != nullptr) {
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
} else {
|
||||
/* Clear the frame buffer. */
|
||||
g_frame_buffer = secmon::MemoryRegionDramDcFramebuffer.GetPointer<u32>();
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Attach the frame buffer to DC. */
|
||||
InitializeDevicePageTableForDc();
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] void FinalizeFrameBuffer() {
|
||||
/* We don't actually support finalizing the framebuffer, so do nothing here. */
|
||||
}
|
||||
|
||||
constexpr const char *GetErrorDescription(u32 error_desc) {
|
||||
switch (error_desc) {
|
||||
case 0x100:
|
||||
return "Instruction Abort";
|
||||
case 0x101:
|
||||
return "Data Abort";
|
||||
case 0x102:
|
||||
return "PC Misalignment";
|
||||
case 0x103:
|
||||
return "SP Misalignment";
|
||||
case 0x104:
|
||||
return "Trap";
|
||||
case 0x106:
|
||||
return "SError";
|
||||
case 0x301:
|
||||
return "Bad SVC";
|
||||
case 0xF00:
|
||||
return "Kernel Panic";
|
||||
case 0xFFD:
|
||||
return "Stack overflow";
|
||||
case 0xFFE:
|
||||
return "std::abort() called";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintSuggestedErrorFix(const ams::impl::FatalErrorContext *f_ctx) {
|
||||
/* Try to recognize certain errors automatically, and suggest fixes for them. */
|
||||
const char *suggestion = nullptr;
|
||||
|
||||
constexpr u64 ProgramIdAmsMitm = UINT64_C(0x010041544D530000);
|
||||
constexpr u64 ProgramIdBoot = UINT64_C(0x0100000000000005);
|
||||
if (f_ctx->error_desc == 0xFFE) {
|
||||
if (f_ctx->program_id == ProgramIdAmsMitm) {
|
||||
/* When a user has archive bits set improperly, attempting to create an automatic backup will fail */
|
||||
/* to create the file path with error 0x202 */
|
||||
if (f_ctx->gprs[0] == fs::ResultPathNotFound().GetValue()) {
|
||||
/* When the archive bit error is occurring, it manifests as failure to create automatic backup. */
|
||||
/* Thus, we can search the stack for the automatic backups path. */
|
||||
const char * const automatic_backups_prefix = "automatic_backups/X" /* ..... */;
|
||||
const int prefix_len = std::strlen(automatic_backups_prefix);
|
||||
|
||||
for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) {
|
||||
if (std::memcmp(&f_ctx->stack_dump[i], automatic_backups_prefix, prefix_len) == 0) {
|
||||
suggestion = "The atmosphere directory may improperly have archive bits set.\n"
|
||||
"Please try running an archive bit fixer tool (for example, the one in Hekate).\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (f_ctx->gprs[0] == fs::ResultExFatUnavailable().GetValue()) {
|
||||
/* When a user installs non-exFAT firm but has an exFAT formatted SD card, this error will */
|
||||
/* be returned on attempt to access the SD card. */
|
||||
suggestion = "Your console has non-exFAT firmware installed, but your SD card\n"
|
||||
"is formatted as exFAT. Format your SD card as FAT32, or manually\n"
|
||||
"flash exFAT firmware to package2.\n";
|
||||
}
|
||||
} else if (f_ctx->program_id == ProgramIdBoot) {
|
||||
/* 9.x -> 10.x updated the API for SvcQueryIoMapping. */
|
||||
/* This can cause the kernel to reject incorrect-ABI calls by boot when a partial update is applied */
|
||||
/* (older kernel in package2, for some reason). */
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
if (f_ctx->gprs[i] == svc::ResultNotFound().GetValue()) {
|
||||
suggestion = "A partial update may have been improperly performed.\n"
|
||||
"To fix, try manually flashing latest package2 to MMC.\n"
|
||||
"\n"
|
||||
"For help doing this, seek support in the ReSwitched or\n"
|
||||
"Nintendo Homebrew discord servers.\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (f_ctx->error_desc == 0xF00) { /* Kernel Panic */
|
||||
suggestion = "Please contact SciresM#0524 on Discord, or create an issue on the Atmosphere\n"
|
||||
"GitHub issue tracker. Thank you very much for helping to test mesosphere.\n";
|
||||
}
|
||||
|
||||
/* If we found a suggestion, print it. */
|
||||
if (suggestion != nullptr) {
|
||||
Print("%s", suggestion);
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeDisplay() {
|
||||
/* TODO: What other configuration is needed, if any? */
|
||||
|
||||
/* Configure LCD pinmux tristate + passthrough. */
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
|
||||
if (fuse::GetHardwareType() == fuse::HardwareType_Five) {
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4);
|
||||
} else {
|
||||
/* Configure LCD power, VDD. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
|
||||
}
|
||||
|
||||
/* Disable the LCD backlight. */
|
||||
if (GetLcdVendor() == 0x2050) {
|
||||
/* TODO: We're not sure display is alive. How to manage this? */
|
||||
/* This is probably incorrect backlight disable for hw-type 5. */
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
} else {
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
}
|
||||
|
||||
/* Disable backlight RST/Voltage. */
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
if (GetLcdVendor() == 0x2050) {
|
||||
util::WaitMicroSeconds(30'000ul);
|
||||
} else {
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
}
|
||||
|
||||
/* Cut clock to DSI. */
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_MIPI_CAL_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_DSI_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_MIPI_CAL, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_DSI, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_HOST1X_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_DISP1_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_HOST1X, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_DISP1, ENABLE));
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * 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)));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeDisplay() {
|
||||
/* Ensure that the display is finalized. */
|
||||
FinalizeDisplay();
|
||||
|
||||
/* Setup the framebuffer. */
|
||||
InitializeFrameBuffer();
|
||||
|
||||
/* Get the hardware type. */
|
||||
const auto hw_type = fuse::GetHardwareType();
|
||||
|
||||
/* Turn on DSI/voltage rail. */
|
||||
{
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A);
|
||||
}
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x23, 0xD0);
|
||||
}
|
||||
|
||||
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_MIPI_CAL_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_DSI_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_MIPI_CAL, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_DSI, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_HOST1X_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_DISP1_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_HOST1X, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_DISP1, ENABLE));
|
||||
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_SET_SET_CLK_ENB_UART_FST_MIPI_CAL, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_DIVISOR, 10),
|
||||
CLK_RST_REG_BITS_ENUM (CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_SRC, PLLP_OUT3));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DSIA_LP, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_DIVISOR, 10),
|
||||
CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_SRC, PLLP_OUT0));
|
||||
|
||||
/* Set IO_DPD_REQ to DPD_OFF. */
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD_REQ, PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_OFF));
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD2_REQ, PMC_REG_BITS_ENUM(IO_DPD2_REQ_CODE, DPD_OFF));
|
||||
|
||||
/* Configure LCD pinmux tristate + passthrough. */
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
|
||||
if (hw_type == fuse::HardwareType_Five) {
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4);
|
||||
} else {
|
||||
/* Configure LCD power, VDD. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
|
||||
}
|
||||
|
||||
/* Configure display interface and display. */
|
||||
reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0);
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0);
|
||||
reg::Write(g_apb_misc_regs + APB_MISC_GP_DSI_PAD_CONTROL, 0);
|
||||
}
|
||||
|
||||
/* Execute configs. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init03);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init04);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init05);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init06);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init07);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Enable backlight reset. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
util::WaitMicroSeconds(60'000ul);
|
||||
|
||||
if (hw_type == fuse::HardwareType_Five) {
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x40103);
|
||||
} else {
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204);
|
||||
}
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
|
||||
WaitDsiHostControl();
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
|
||||
/* Parse LCD vendor. */
|
||||
{
|
||||
u32 host_response[3];
|
||||
for (size_t i = 0; i < util::size(host_response); i++) {
|
||||
host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA);
|
||||
}
|
||||
|
||||
/* The last word from host response is:
|
||||
Bits 0-7: FAB
|
||||
Bits 8-15: REV
|
||||
Bits 16-23: Minor REV
|
||||
*/
|
||||
u32 lcd_vendor;
|
||||
if ((host_response[2] & 0xFF) == 0x10) {
|
||||
lcd_vendor = 0;
|
||||
} else {
|
||||
lcd_vendor = (host_response[2] >> 8) & 0xFF00;
|
||||
}
|
||||
lcd_vendor = (lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
|
||||
|
||||
AMS_ASSERT(lcd_vendor == GetLcdVendor());
|
||||
}
|
||||
|
||||
/* LCD vendor specific configuration. */
|
||||
switch (GetLcdVendor()) {
|
||||
case 0x10: /* Japan Display Inc screens. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificInit01);
|
||||
break;
|
||||
case 0xF20: /* Innolux first revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(180'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0xF30: /* AUO first revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(180'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0x2050: /* Unknown (hardware type 5) screen. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(180'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xA015);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x205315);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x51);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0x1020: /* Innolux second revision screen. */
|
||||
case 0x1030: /* AUO second revision screen. */
|
||||
case 0x1040: /* Unknown second revision screen. */
|
||||
default:
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(120'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
}
|
||||
util::WaitMicroSeconds(20'000ul);
|
||||
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init08);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09);
|
||||
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4));
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Configure MIPI CAL. */
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
/* On Mariko the above configurations are executed twice, for some reason. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
}
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Write DISP1, FrameBuffer config. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc02);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigFrameBuffer);
|
||||
if (GetLcdVendor() != 0x2050) {
|
||||
util::WaitMicroSeconds(35'000ul);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) {
|
||||
/* Initialize the console. */
|
||||
InitializeConsole(g_frame_buffer);
|
||||
{
|
||||
Print("%s\n", "A fatal error occurred when running Atmosph\xe8re.");
|
||||
Print("Program ID: %016" PRIx64 "\n", f_ctx->program_id);
|
||||
Print("Error Desc: %s (0x%x)\n", GetErrorDescription(f_ctx->error_desc), f_ctx->error_desc);
|
||||
Print("\n");
|
||||
|
||||
if (R_SUCCEEDED(save_result)) {
|
||||
Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin", f_ctx->report_identifier);
|
||||
} else {
|
||||
Print("Failed to save report to the SD card! (%08x)\n", save_result.GetValue());
|
||||
}
|
||||
|
||||
PrintSuggestedErrorFix(f_ctx);
|
||||
|
||||
Print("\nPress POWER to reboot.\n");
|
||||
}
|
||||
|
||||
/* Ensure the device will see consistent data. */
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Enable backlight. */
|
||||
constexpr auto DisplayBrightness = 100;
|
||||
if (GetLcdVendor() == 0x2050) {
|
||||
EnableBacklightForVendor2050ForHardwareTypeFive(DisplayBrightness);
|
||||
} else {
|
||||
EnableBacklightForGeneric(DisplayBrightness);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
28
exosphere/mariko_fatal/source/fatal_display.hpp
Normal file
28
exosphere/mariko_fatal/source/fatal_display.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
constexpr inline size_t FrameBufferHeight = 768;
|
||||
constexpr inline size_t FrameBufferWidth = 1280;
|
||||
constexpr inline size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
||||
|
||||
void InitializeDisplay();
|
||||
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result);
|
||||
|
||||
}
|
682
exosphere/mariko_fatal/source/fatal_display_config.inc
Normal file
682
exosphere/mariko_fatal/source/fatal_display_config.inc
Normal file
|
@ -0,0 +1,682 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct RegisterWrite {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum SleepOrRegisterWriteKind : u16 {
|
||||
SleepOrRegisterWriteKind_Write = 0,
|
||||
SleepOrRegisterWriteKind_Sleep = 1,
|
||||
};
|
||||
|
||||
struct SleepOrRegisterWrite {
|
||||
SleepOrRegisterWriteKind kind;
|
||||
u16 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld01Erista[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld01Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDc01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_REG_ACT_CONTROL, 0x54},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DC_MCCIF_FIFOCTRL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{SleepOrRegisterWriteKind_Write, 0x4E4, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init01[] = {
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x0},
|
||||
{sizeof(u32) * DSI_INT_ENABLE, 0x0},
|
||||
{sizeof(u32) * DSI_INT_STATUS, 0x0},
|
||||
{sizeof(u32) * DSI_INT_MASK, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_0, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_1, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_2, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init02Erista[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init02Mariko[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init03[] = {
|
||||
{sizeof(u32) * DSI_DCS_CMDS, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_HI, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init04Erista[] = {
|
||||
/* No register writes. */
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init04Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init05[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_CD, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 0x18},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_0_1, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_2_3, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_4_5, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_6_7, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init06[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init07[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsiPhyTimingErista[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsiPhyTimingMariko[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1939},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1BD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2739},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2BD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x6D915},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1105},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Sleep, 180, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2905},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld02Erista[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld02Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init08[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDsi01Init09[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_2, 0x30172},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_BTA_TIMING, 0x190A14},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TO_TALLY, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_0_LO, 0x40000208},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_2_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_4_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_1_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_LO, 0x3F3B2B08},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_HI, 0x2CC},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_LO, 0x3F3B2B08},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_HI, 0x2CC},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_0_1, 0xCE0000},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_2_3, 0x87001A2},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_4_5, 0x190},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_6_7, 0x190},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_HOST_CONTROL, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init10[] = {
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 6},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init11Erista[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * 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)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init11Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal01[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG0, 1},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal02Erista[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal02Mariko[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal03Erista[] = {
|
||||
{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},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal03Mariko[] = {
|
||||
{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},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal04[] = {
|
||||
{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},
|
||||
{MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDc02[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{SleepOrRegisterWriteKind_Write, 0x4E4, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
/* Set Display timings */
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_TIMING_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1.
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_SYNC_WIDTH, 0x10048},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_BACK_PORCH, 0x90048},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_ACTIVE, 0x50002D0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
|
||||
/* End of Display timings */
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_ENABLE(1), 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
|
||||
};
|
||||
|
||||
constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000;
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigFrameBuffer[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_POSITION, 0}, //(0,0)
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_H_INITIAL_DDA, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_V_INITIAL_DDA, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_BUFFER_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_START_ADDR, DisplayConfigFrameBufferAddress}, //Framebuffer address.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDc01Fini01[] = {
|
||||
{sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{sizeof(u32) * DC_CMD_INT_MASK, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_INT_ENABLE, 0},
|
||||
{sizeof(u32) * DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Fini01[] = {
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Fini02[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificFini01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2139},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x4F0F41B1},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF179A433},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2D81},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigAuoRev1SpecificFini01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D6},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x711148B1},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x71143209},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x114D31},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Sleep, 5, 0},
|
||||
};
|
4655
exosphere/mariko_fatal/source/fatal_font.inc
Normal file
4655
exosphere/mariko_fatal/source/fatal_font.inc
Normal file
File diff suppressed because it is too large
Load diff
97
exosphere/mariko_fatal/source/fatal_main.cpp
Normal file
97
exosphere/mariko_fatal/source/fatal_main.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_sdmmc.hpp"
|
||||
#include "fatal_save_context.hpp"
|
||||
#include "fatal_sound.hpp"
|
||||
#include "fatal_display.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int I2cAddressMax77620Pmic = 0x3C;
|
||||
|
||||
ALWAYS_INLINE const ams::impl::FatalErrorContext *GetFatalErrorContext() {
|
||||
return MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<ams::impl::FatalErrorContext>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Main() {
|
||||
/* Set library register addresses. */
|
||||
actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress());
|
||||
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
|
||||
flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress());
|
||||
fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress());
|
||||
gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress());
|
||||
i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress());
|
||||
i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress());
|
||||
pinmux::SetRegisterAddress(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress());
|
||||
pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress());
|
||||
se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress(), MemoryRegionVirtualDeviceSecurityEngine2.GetAddress());
|
||||
uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress());
|
||||
wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
|
||||
util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
|
||||
|
||||
/* Ensure that the log library is initialized. */
|
||||
log::Initialize();
|
||||
|
||||
AMS_SECMON_LOG("%s\n", "Fatal start.");
|
||||
|
||||
/* Save the fatal error context. */
|
||||
const auto *f_ctx = GetFatalErrorContext();
|
||||
Result result = SaveFatalErrorContext(f_ctx);
|
||||
if (R_SUCCEEDED(result)) {
|
||||
AMS_SECMON_LOG("Saved fatal error context to /atmosphere/fatal_reports/report_%016" PRIx64 ".bin!\n", f_ctx->report_identifier);
|
||||
} else {
|
||||
AMS_SECMON_LOG("Failed to save fatal error context: %08x\n", result.GetValue());
|
||||
}
|
||||
|
||||
/* Ensure that i2c-1/i2c-5 are usable for communicating with the audio device/pmic. */
|
||||
clkrst::EnableI2c1Clock();
|
||||
clkrst::EnableI2c5Clock();
|
||||
i2c::Initialize(i2c::Port_1);
|
||||
i2c::Initialize(i2c::Port_5);
|
||||
|
||||
/* Shut down audio. */
|
||||
{
|
||||
StopSound();
|
||||
}
|
||||
|
||||
/* Display the fatal error. */
|
||||
{
|
||||
AMS_SECMON_LOG("Showing Display, LCD Vendor = %04x\n", GetLcdVendor());
|
||||
InitializeDisplay();
|
||||
ShowDisplay(f_ctx, result);
|
||||
}
|
||||
|
||||
/* Ensure we have nothing waiting to be logged. */
|
||||
AMS_LOG_FLUSH();
|
||||
|
||||
/* Wait for power button to be pressed. */
|
||||
while (!pmic::IsPowerButtonPressed()) {
|
||||
util::WaitMicroSeconds(100);
|
||||
}
|
||||
|
||||
/* Reboot. */
|
||||
pmic::ShutdownSystem(true);
|
||||
|
||||
/* Wait for our reboot to complete. */
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
}
|
127
exosphere/mariko_fatal/source/fatal_print.cpp
Normal file
127
exosphere/mariko_fatal/source/fatal_print.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_display.hpp"
|
||||
#include "fatal_print.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
#include "fatal_font.inc"
|
||||
|
||||
constexpr inline const u32 TextColor = 0xFFA0A0A0;
|
||||
|
||||
constexpr inline const size_t ConsoleWidth = FrameBufferWidth / FontWidth;
|
||||
constexpr inline const size_t ConsoleHeight = FrameBufferHeight / FontHeight;
|
||||
|
||||
constinit u32 *g_frame_buffer = nullptr;
|
||||
constinit size_t g_col = 1;
|
||||
constinit size_t g_row = 0;
|
||||
|
||||
void SetPixel(size_t x, size_t y, u32 color) {
|
||||
g_frame_buffer[(FrameBufferWidth - x) * FrameBufferHeight + y] = color;
|
||||
}
|
||||
|
||||
void PutCarriageReturn() {
|
||||
g_col = 1;
|
||||
}
|
||||
|
||||
void PutNewLine() {
|
||||
g_col = 1;
|
||||
++g_row;
|
||||
|
||||
/* TODO: Support scrolling? */
|
||||
}
|
||||
|
||||
void PutCharImpl(const char c) {
|
||||
/* Get the character data for the font. */
|
||||
const u8 * cdata = FontData + c * (FontHeight * util::DivideUp(FontWidth, BITSIZEOF(u8)));
|
||||
|
||||
/* Determine where to start drawing. */
|
||||
const size_t x = g_col * FontWidth;
|
||||
const size_t y = g_row * FontHeight;
|
||||
|
||||
for (size_t cur_y = 0; cur_y < FontHeight; ++cur_y) {
|
||||
size_t cur_x = 0;
|
||||
int wbits = FontWidth;
|
||||
while (wbits > 0) {
|
||||
const auto bits = *(cdata++);
|
||||
|
||||
SetPixel(x + cur_x + 0, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][0] & TextColor);
|
||||
SetPixel(x + cur_x + 1, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][1] & TextColor);
|
||||
SetPixel(x + cur_x + 2, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][2] & TextColor);
|
||||
SetPixel(x + cur_x + 3, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][3] & TextColor);
|
||||
SetPixel(x + cur_x + 4, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][0] & TextColor);
|
||||
SetPixel(x + cur_x + 5, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][1] & TextColor);
|
||||
SetPixel(x + cur_x + 6, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][2] & TextColor);
|
||||
SetPixel(x + cur_x + 7, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][3] & TextColor);
|
||||
|
||||
cur_x += BITSIZEOF(u8);
|
||||
wbits -= BITSIZEOF(u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PutChar(const char c) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
PutCarriageReturn();
|
||||
break;
|
||||
case '\n':
|
||||
PutNewLine();
|
||||
break;
|
||||
default:
|
||||
PutCharImpl(c);
|
||||
if ((++g_col) >= ConsoleWidth) {
|
||||
PutNewLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeConsole(u32 *frame_buffer) {
|
||||
/* Setup the console variables. */
|
||||
g_frame_buffer = frame_buffer;
|
||||
g_col = 1;
|
||||
g_row = 0;
|
||||
|
||||
/* Clear the console. */
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
}
|
||||
|
||||
void Print(const char *fmt, ...) {
|
||||
/* Generate the string. */
|
||||
char log_str[1_KB];
|
||||
{
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
util::TVSNPrintf(log_str, sizeof(log_str), fmt, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
/* Print each character. */
|
||||
const size_t len = std::strlen(log_str);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
PutChar(log_str[i]);
|
||||
}
|
||||
|
||||
/* Flush the console. */
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
}
|
||||
|
||||
}
|
24
exosphere/mariko_fatal/source/fatal_print.hpp
Normal file
24
exosphere/mariko_fatal/source/fatal_print.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void InitializeConsole(u32 *frame_buffer);
|
||||
void Print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
}
|
352
exosphere/mariko_fatal/source/fatal_registers_di.hpp
Normal file
352
exosphere/mariko_fatal/source/fatal_registers_di.hpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
#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_STATUS 0x37
|
||||
#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_INCR_SYNCPT_CNTRL 0x1
|
||||
|
||||
#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_PAD_CONTROL_5_MARIKO 0x53
|
||||
#define DSI_PAD_CONTROL_6_MARIKO 0x54
|
||||
#define DSI_PAD_CONTROL_7_MARIKO 0x55
|
||||
#define DSI_INIT_SEQ_DATA_15 0x5F
|
||||
|
||||
#define DSI_INIT_SEQ_DATA_15_MARIKO 0x62
|
68
exosphere/mariko_fatal/source/fatal_save_context.cpp
Normal file
68
exosphere/mariko_fatal/source/fatal_save_context.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_save_context.hpp"
|
||||
#include "fatal_sdmmc.hpp"
|
||||
#include "fs/fatal_fs_api.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx) {
|
||||
/* Initialize the sdmmc driver. */
|
||||
R_TRY(InitializeSdCard());
|
||||
|
||||
/* Get the connection status. */
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
{
|
||||
sdmmc::SpeedMode speed_mode;
|
||||
sdmmc::BusWidth bus_width;
|
||||
R_TRY(CheckSdCardConnection(std::addressof(speed_mode), std::addressof(bus_width)));
|
||||
AMS_SECMON_LOG("Sd Card Connection:\n");
|
||||
AMS_SECMON_LOG(" Speed Mode: %u\n", static_cast<u32>(speed_mode));
|
||||
AMS_SECMON_LOG(" Bus Width: %u\n", static_cast<u32>(bus_width));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Mount the SD card. */
|
||||
R_UNLESS(fs::MountSdCard(), fs::ResultPartitionNotFound());
|
||||
|
||||
/* Unmount the SD card once we're done. */
|
||||
ON_SCOPE_EXIT { fs::UnmountSdCard(); };
|
||||
|
||||
/* Create and open the file. */
|
||||
fs::FileHandle file;
|
||||
{
|
||||
/* Generate the file path. */
|
||||
char path[0x40];
|
||||
util::TSNPrintf(path, sizeof(path), "/atmosphere/fatal_errors/report_%016" PRIx64 ".bin", ctx->report_identifier);
|
||||
|
||||
/* Create the file. */
|
||||
R_TRY(fs::CreateFile(path, sizeof(*ctx)));
|
||||
|
||||
/* Open the file. */
|
||||
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_ReadWrite));
|
||||
}
|
||||
|
||||
/* Ensure we close the file when done with it. */
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
/* Write the context to the file. */
|
||||
R_TRY(fs::WriteFile(file, 0, ctx, sizeof(*ctx), fs::WriteOption::Flush));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
23
exosphere/mariko_fatal/source/fatal_save_context.hpp
Normal file
23
exosphere/mariko_fatal/source/fatal_save_context.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx);
|
||||
|
||||
}
|
108
exosphere/mariko_fatal/source/fatal_sdmmc.cpp
Normal file
108
exosphere/mariko_fatal/source/fatal_sdmmc.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_device_page_table.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline auto Port = sdmmc::Port_SdCard0;
|
||||
|
||||
ALWAYS_INLINE u8 *GetSdCardWorkBuffer() {
|
||||
return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>() + MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetSdCardDmaBuffer() {
|
||||
return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>();
|
||||
}
|
||||
|
||||
constexpr inline size_t SdCardDmaBufferSize = MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize;
|
||||
constexpr inline size_t SdCardDmaBufferSectors = SdCardDmaBufferSize / sdmmc::SectorSize;
|
||||
static_assert(util::IsAligned(SdCardDmaBufferSize, sdmmc::SectorSize));
|
||||
|
||||
}
|
||||
|
||||
Result InitializeSdCard() {
|
||||
/* Map main memory for the sdmmc device. */
|
||||
InitializeDevicePageTableForSdmmc1();
|
||||
|
||||
/* Initialize sdmmc library. */
|
||||
sdmmc::Initialize(Port);
|
||||
|
||||
sdmmc::SetSdCardWorkBuffer(Port, GetSdCardWorkBuffer(), sdmmc::SdCardWorkBufferSize);
|
||||
|
||||
//sdmmc::Deactivate(Port);
|
||||
R_TRY(sdmmc::Activate(Port));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) {
|
||||
return sdmmc::CheckSdCardConnection(out_sm, out_bw, Port);
|
||||
}
|
||||
|
||||
Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||
/* Validate that our buffer is valid. */
|
||||
AMS_ASSERT(size >= sector_count * sdmmc::SectorSize);
|
||||
|
||||
/* Repeatedly read sectors. */
|
||||
u8 *dst_u8 = static_cast<u8 *>(dst);
|
||||
void * const dma_buffer = GetSdCardDmaBuffer();
|
||||
while (sector_count > 0) {
|
||||
/* Read sectors into the DMA buffer. */
|
||||
const size_t cur_sectors = std::min(sector_count, SdCardDmaBufferSectors);
|
||||
const size_t cur_size = cur_sectors * sdmmc::SectorSize;
|
||||
R_TRY(sdmmc::Read(dma_buffer, cur_size, Port, sector_index, cur_sectors));
|
||||
|
||||
/* Copy data from the DMA buffer to the output. */
|
||||
std::memcpy(dst_u8, dma_buffer, cur_size);
|
||||
|
||||
/* Advance. */
|
||||
dst_u8 += cur_size;
|
||||
sector_index += cur_sectors;
|
||||
sector_count -= cur_sectors;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
/* Validate that our buffer is valid. */
|
||||
AMS_ASSERT(size >= sector_count * sdmmc::SectorSize);
|
||||
|
||||
/* Repeatedly read sectors. */
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
void * const dma_buffer = GetSdCardDmaBuffer();
|
||||
while (sector_count > 0) {
|
||||
/* Copy sectors into the DMA buffer. */
|
||||
const size_t cur_sectors = std::min(sector_count, SdCardDmaBufferSectors);
|
||||
const size_t cur_size = cur_sectors * sdmmc::SectorSize;
|
||||
std::memcpy(dma_buffer, src_u8, cur_size);
|
||||
|
||||
/* Write sectors to the sd card. */
|
||||
R_TRY(sdmmc::Write(Port, sector_index, cur_sectors, dma_buffer, cur_size));
|
||||
|
||||
/* Advance. */
|
||||
src_u8 += cur_size;
|
||||
sector_index += cur_sectors;
|
||||
sector_count -= cur_sectors;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
26
exosphere/mariko_fatal/source/fatal_sdmmc.hpp
Normal file
26
exosphere/mariko_fatal/source/fatal_sdmmc.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
Result InitializeSdCard();
|
||||
Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw);
|
||||
Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count);
|
||||
Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size);
|
||||
|
||||
}
|
26
exosphere/mariko_fatal/source/fatal_sdmmc_c.cpp
Normal file
26
exosphere/mariko_fatal/source/fatal_sdmmc_c.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_sdmmc_c.h"
|
||||
#include "fatal_sdmmc.hpp"
|
||||
|
||||
bool sdmmc_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||
return R_SUCCEEDED(ams::secmon::fatal::ReadSdCard(dst, size, sector_index, sector_count));
|
||||
}
|
||||
|
||||
bool sdmmc_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
return R_SUCCEEDED(ams::secmon::fatal::WriteSdCard(sector_index, sector_count, src, size));
|
||||
}
|
28
exosphere/mariko_fatal/source/fatal_sdmmc_c.h
Normal file
28
exosphere/mariko_fatal/source/fatal_sdmmc_c.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool sdmmc_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count);
|
||||
bool sdmmc_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
62
exosphere/mariko_fatal/source/fatal_sound.cpp
Normal file
62
exosphere/mariko_fatal/source/fatal_sound.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_sound.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int I2cAddressMaxAlc5639 = 0x1C;
|
||||
|
||||
constexpr inline uintptr_t GPIO = secmon::MemoryRegionVirtualDeviceGpio.GetAddress();
|
||||
|
||||
constexpr size_t GPIO_PORT7_CNF_1 = 0x604;
|
||||
constexpr size_t GPIO_PORT7_OE_1 = 0x614;
|
||||
constexpr size_t GPIO_PORT7_OUT_1 = 0x624;
|
||||
|
||||
void WriteAlc5639Register(int r, u16 val) {
|
||||
i2c::Send(i2c::Port_1, I2cAddressMaxAlc5639, r, std::addressof(val), sizeof(val));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StopSound() {
|
||||
/* Mute output to the speaker, setting left/right volume to 0 DB. */
|
||||
WriteAlc5639Register(0x01, 0xC8C8);
|
||||
|
||||
/* Mute output to headphones, setting left/right volume to 0 DB. */
|
||||
WriteAlc5639Register(0x02, 0xC8C8);
|
||||
|
||||
/* Clear all Power Management Control registers by writing 0x0000 to them. */
|
||||
for (int r = 0x61; r <= 0x66; ++r) {
|
||||
WriteAlc5639Register(r, 0x0000);
|
||||
}
|
||||
|
||||
/* Configure CodecLdoEn as GPIO. */
|
||||
reg::SetBits(GPIO + GPIO_PORT7_CNF_1, (1u << 4));
|
||||
|
||||
/* Configure CodecLdoEn as Output. */
|
||||
reg::SetBits(GPIO + GPIO_PORT7_OE_1, (1u << 4));
|
||||
|
||||
/* Wait 200 milliseconds for config to take effect. */
|
||||
util::WaitMicroSeconds(200'000ul);
|
||||
|
||||
/* Pull CodecLdoEn low. */
|
||||
reg::ClearBits(GPIO + GPIO_PORT7_OUT_1, (1u << 4));
|
||||
}
|
||||
|
||||
}
|
23
exosphere/mariko_fatal/source/fatal_sound.hpp
Normal file
23
exosphere/mariko_fatal/source/fatal_sound.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void StopSound();
|
||||
|
||||
}
|
340
exosphere/mariko_fatal/source/fatfs/00history.txt
Normal file
340
exosphere/mariko_fatal/source/fatfs/00history.txt
Normal file
|
@ -0,0 +1,340 @@
|
|||
----------------------------------------------------------------------------
|
||||
Revision history of FatFs module
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
R0.00 (February 26, 2006)
|
||||
|
||||
Prototype.
|
||||
|
||||
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
|
||||
The first release.
|
||||
|
||||
|
||||
|
||||
R0.02 (June 01, 2006)
|
||||
|
||||
Added FAT12 support.
|
||||
Removed unbuffered mode.
|
||||
Fixed a problem on small (<32M) partition.
|
||||
|
||||
|
||||
|
||||
R0.02a (June 10, 2006)
|
||||
|
||||
Added a configuration option (_FS_MINIMUM).
|
||||
|
||||
|
||||
|
||||
R0.03 (September 22, 2006)
|
||||
|
||||
Added f_rename().
|
||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||
|
||||
|
||||
|
||||
R0.03a (December 11, 2006)
|
||||
|
||||
Improved cluster scan algorithm to write files fast.
|
||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||
|
||||
|
||||
|
||||
R0.04 (February 04, 2007)
|
||||
|
||||
Added f_mkfs().
|
||||
Supported multiple drive system.
|
||||
Changed some interfaces for multiple drive system.
|
||||
Changed f_mountdrv() to f_mount().
|
||||
|
||||
|
||||
|
||||
R0.04a (April 01, 2007)
|
||||
|
||||
Supported multiple partitions on a physical drive.
|
||||
Added a capability of extending file size to f_lseek().
|
||||
Added minimization level 3.
|
||||
Fixed an endian sensitive code in f_mkfs().
|
||||
|
||||
|
||||
|
||||
R0.04b (May 05, 2007)
|
||||
|
||||
Added a configuration option _USE_NTFLAG.
|
||||
Added FSINFO support.
|
||||
Fixed DBCS name can result FR_INVALID_NAME.
|
||||
Fixed short seek (<= csize) collapses the file object.
|
||||
|
||||
|
||||
|
||||
R0.05 (August 25, 2007)
|
||||
|
||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||
|
||||
|
||||
|
||||
R0.05a (February 03, 2008)
|
||||
|
||||
Added f_truncate() and f_utime().
|
||||
Fixed off by one error at FAT sub-type determination.
|
||||
Fixed btr in f_read() can be mistruncated.
|
||||
Fixed cached sector is not flushed when create and close without write.
|
||||
|
||||
|
||||
|
||||
R0.06 (April 01, 2008)
|
||||
|
||||
Added fputc(), fputs(), fprintf() and fgets().
|
||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||
|
||||
|
||||
|
||||
R0.07 (April 01, 2009)
|
||||
|
||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||
Added long file name feature. (_USE_LFN)
|
||||
Added multiple code page feature. (_CODE_PAGE)
|
||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||
Added auto cluster size selection to f_mkfs().
|
||||
Added rewind option to f_readdir().
|
||||
Changed result code of critical errors.
|
||||
Renamed string functions to avoid name collision.
|
||||
|
||||
|
||||
|
||||
R0.07a (April 14, 2009)
|
||||
|
||||
Septemberarated out OS dependent code on reentrant cfg.
|
||||
Added multiple sector size feature.
|
||||
|
||||
|
||||
|
||||
R0.07c (June 21, 2009)
|
||||
|
||||
Fixed f_unlink() can return FR_OK on error.
|
||||
Fixed wrong cache control in f_lseek().
|
||||
Added relative path feature.
|
||||
Added f_chdir() and f_chdrive().
|
||||
Added proper case conversion to extended character.
|
||||
|
||||
|
||||
|
||||
R0.07e (November 03, 2009)
|
||||
|
||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||
Fixed name matching error on the 13 character boundary.
|
||||
Added a configuration option, _LFN_UNICODE.
|
||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||
|
||||
|
||||
|
||||
R0.08 (May 15, 2010)
|
||||
|
||||
Added a memory configuration option. (_USE_LFN = 3)
|
||||
Added file lock feature. (_FS_SHARE)
|
||||
Added fast seek feature. (_USE_FASTSEEK)
|
||||
Changed some types on the API, XCHAR->TCHAR.
|
||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||
String functions support UTF-8 encoding files on Unicode cfg.
|
||||
|
||||
|
||||
|
||||
R0.08a (August 16, 2010)
|
||||
|
||||
Added f_getcwd(). (_FS_RPATH = 2)
|
||||
Added sector erase feature. (_USE_ERASE)
|
||||
Moved file lock semaphore table from fs object to the bss.
|
||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||
|
||||
|
||||
|
||||
R0.08b (January 15, 2011)
|
||||
|
||||
Fast seek feature is also applied to f_read() and f_write().
|
||||
f_lseek() reports required table size on creating CLMP.
|
||||
Extended format syntax of f_printf().
|
||||
Ignores duplicated directory separators in given path name.
|
||||
|
||||
|
||||
|
||||
R0.09 (September 06, 2011)
|
||||
|
||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||
Added f_fdisk().
|
||||
|
||||
|
||||
|
||||
R0.09a (August 27, 2012)
|
||||
|
||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||
Changed option name _FS_SHARE to _FS_LOCK.
|
||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||
|
||||
|
||||
|
||||
R0.09b (January 24, 2013)
|
||||
|
||||
Added f_setlabel() and f_getlabel().
|
||||
|
||||
|
||||
|
||||
R0.10 (October 02, 2013)
|
||||
|
||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||
Added f_closedir().
|
||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||
Added forced mount feature with changes of f_mount().
|
||||
Improved behavior of volume auto detection.
|
||||
Improved write throughput of f_puts() and f_printf().
|
||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
||||
|
||||
|
||||
|
||||
R0.10a (January 15, 2014)
|
||||
|
||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||
Fixed f_close() invalidates the file object without volume lock.
|
||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10c (November 09, 2014)
|
||||
|
||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||
Changed option name _USE_ERASE to _USE_TRIM.
|
||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||
Fixed a potential problem of FAT access that can appear on disk error.
|
||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||
|
||||
|
||||
|
||||
R0.11 (February 09, 2015)
|
||||
|
||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.11a (September 05, 2015)
|
||||
|
||||
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12 (April 12, 2016)
|
||||
|
||||
Added support for exFAT file system. (_FS_EXFAT)
|
||||
Added f_expand(). (_USE_EXPAND)
|
||||
Changed some members in FINFO structure and behavior of f_readdir().
|
||||
Added an option _USE_CHMOD.
|
||||
Removed an option _WORD_ACCESS.
|
||||
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12a (July 10, 2016)
|
||||
|
||||
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||
f_forward() is available regardless of _FS_TINY.
|
||||
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||
|
||||
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.13 (May 21, 2017)
|
||||
|
||||
Changed heading character of configuration keywords "_" to "FF_".
|
||||
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
|
||||
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
|
||||
Improved cluster allocation time on stretch a deep buried cluster chain.
|
||||
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
|
||||
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
|
||||
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
|
||||
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
|
||||
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
|
||||
|
||||
|
||||
|
||||
R0.13a (October 14, 2017)
|
||||
|
||||
Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2)
|
||||
Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF).
|
||||
Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk().
|
||||
Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09)
|
||||
Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c)
|
||||
Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.13b (April 07, 2018)
|
||||
|
||||
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
|
||||
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
|
||||
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
|
||||
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)
|
||||
|
||||
|
||||
|
||||
R0.13c (October 14, 2018)
|
||||
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
|
||||
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
|
||||
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
|
||||
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
|
||||
|
||||
|
||||
|
||||
R0.14 (October 14, 2019)
|
||||
Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1)
|
||||
Changed some API functions, f_mkfs() and f_fdisk().
|
||||
Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters.
|
||||
Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters.
|
||||
Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12)
|
||||
Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12)
|
||||
|
21
exosphere/mariko_fatal/source/fatfs/00readme.txt
Normal file
21
exosphere/mariko_fatal/source/fatfs/00readme.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
FatFs Module Source Files R0.14
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
ffunicode.c Optional Unicode utility functions.
|
||||
ffsystem.c An example of optional O/S related functions.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You need to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
102
exosphere/mariko_fatal/source/fatfs/diskio.c
Normal file
102
exosphere/mariko_fatal/source/fatfs/diskio.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*-----------------------------------------------------------------------*/
|
||||
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* If a working storage control module is available, it should be */
|
||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||
/* This is an example of glue functions to attach various exsisting */
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "ff.h" /* Obtains integer types */
|
||||
#include "diskio.h" /* Declarations of disk functions */
|
||||
#include "ffconf.h"
|
||||
|
||||
#include "../fatal_sdmmc_c.h"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case 0:
|
||||
return sdmmc_read_sd_card(buff, count * 512, sector, count) ? RES_OK : RES_ERROR;
|
||||
default:
|
||||
return RES_PARERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case 0:
|
||||
return sdmmc_write_sd_card(sector, count, buff, count * 512) ? RES_OK : RES_ERROR;
|
||||
default:
|
||||
return RES_PARERR;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
77
exosphere/mariko_fatal/source/fatfs/diskio.h
Normal file
77
exosphere/mariko_fatal/source/fatfs/diskio.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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, LBA_t sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t 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
|
6864
exosphere/mariko_fatal/source/fatfs/ff.c
Normal file
6864
exosphere/mariko_fatal/source/fatfs/ff.c
Normal file
File diff suppressed because it is too large
Load diff
426
exosphere/mariko_fatal/source/fatfs/ff.h
Normal file
426
exosphere/mariko_fatal/source/fatfs/ff.h
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.14 /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2019, 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 86606 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* Integer types used for FatFs API */
|
||||
|
||||
#if defined(_WIN32) /* Main development platform */
|
||||
#define FF_INTDEF 2
|
||||
#include <windows.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
|
||||
#define FF_INTDEF 2
|
||||
#include <stdint.h>
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef uint16_t WORD; /* 16-bit unsigned integer */
|
||||
typedef uint32_t DWORD; /* 32-bit unsigned integer */
|
||||
typedef uint64_t QWORD; /* 64-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#else /* Earlier than C99 */
|
||||
#define FF_INTDEF 1
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef unsigned short WORD; /* 16-bit unsigned integer */
|
||||
typedef unsigned long DWORD; /* 32-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#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 mapping 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 and LBA variables */
|
||||
|
||||
#if FF_FS_EXFAT
|
||||
#if FF_INTDEF != 2
|
||||
#error exFAT feature wants C99 or later
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#if FF_LBA64
|
||||
typedef QWORD LBA_t;
|
||||
#else
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
#else
|
||||
#if FF_LBA64
|
||||
#error exFAT needs to be enabled when enable 64-bit LBA
|
||||
#endif
|
||||
typedef DWORD FSIZE_t;
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
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] */
|
||||
LBA_t volbase; /* Volume base sector */
|
||||
LBA_t fatbase; /* FAT base sector */
|
||||
LBA_t dirbase; /* Root directory base sector/cluster */
|
||||
LBA_t database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
LBA_t bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
LBA_t winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3: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 {
|
||||
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) */
|
||||
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !FF_FS_READONLY
|
||||
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
LBA_t 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;
|
||||
|
||||
|
||||
|
||||
/* Format parameter structure (MKFS_PARM) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
|
||||
BYTE n_fat; /* Number of FATs */
|
||||
UINT align; /* Data area alignment (sector) */
|
||||
UINT n_root; /* Number of root directory entries */
|
||||
DWORD au_size; /* Cluster size (byte) */
|
||||
} MKFS_PARM;
|
||||
|
||||
|
||||
|
||||
/* 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, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], 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 */
|
298
exosphere/mariko_fatal/source/fatfs/ffconf.h
Normal file
298
exosphere/mariko_fatal/source/fatfs/ffconf.h
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs Functional Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FFCONF_DEF 86606 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define FF_FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: Basic functions are fully enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||
/ are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define FF_USE_STRFUNC 2
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
||||
#define FF_USE_MKFS 0
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FASTSEEK 0
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_EXPAND 1
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define FF_USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_CODE_PAGE 850
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect code page setting can cause a file open failure.
|
||||
/
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 771 - KBL
|
||||
/ 775 - Baltic
|
||||
/ 850 - Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 860 - Portuguese
|
||||
/ 861 - Icelandic
|
||||
/ 862 - Hebrew
|
||||
/ 863 - Canadian French
|
||||
/ 864 - Arabic
|
||||
/ 865 - Nordic
|
||||
/ 866 - Russian
|
||||
/ 869 - Greek 2
|
||||
/ 932 - Japanese (DBCS)
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
/ 0 - Include all code pages above and configured by f_setcp()
|
||||
*/
|
||||
|
||||
|
||||
#define FF_USE_LFN 1
|
||||
#define FF_MAX_LFN 255
|
||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||
/
|
||||
/ 0: Disable LFN. FF_MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
|
||||
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
|
||||
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
|
||||
/ be in range of 12 to 255. It is recommended to be set it 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() exemplified in ffsystem.c, need to be added to the project. */
|
||||
|
||||
|
||||
#define FF_LFN_UNICODE 2
|
||||
/* 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 3
|
||||
/* 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 "sdmc"
|
||||
/* 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",...
|
||||
*/
|
||||
|
||||
|
||||
#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_LBA64 0
|
||||
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
|
||||
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
|
||||
|
||||
|
||||
#define FF_MIN_GPT 0x100000000
|
||||
/* Minimum number of sectors to switch GPT format to create partition in f_mkfs and
|
||||
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
|
||||
|
||||
|
||||
#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. */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ 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 2019
|
||||
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||
/ the timestamp function. 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 in read-only configuration (FF_FS_READONLY = 1). */
|
||||
|
||||
|
||||
#define FF_FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
#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 <somertos.h> // 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 ---*/
|
170
exosphere/mariko_fatal/source/fatfs/ffsystem.c
Normal file
170
exosphere/mariko_fatal/source/fatfs/ffsystem.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*------------------------------------------------------------------------*/
|
||||
/* Sample Code of OS Dependent Functions for FatFs */
|
||||
/* (C)ChaN, 2018 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "ff.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
|
||||
|
||||
|
||||
|
||||
#if FF_FS_REENTRANT /* Mutal exclusion */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object for the volume, such as semaphore and mutex.
|
||||
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
|
||||
|
||||
|
||||
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
|
||||
BYTE vol, /* Corresponding volume (logical drive number) */
|
||||
FF_SYNC_t* sobj /* Pointer to return the created sync object */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
*sobj = CreateMutex(NULL, FALSE, NULL);
|
||||
return (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||
|
||||
/* uITRON */
|
||||
// T_CSEM csem = {TA_TPRI,1,1};
|
||||
// *sobj = acre_sem(&csem);
|
||||
// return (int)(*sobj > 0);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// *sobj = OSMutexCreate(0, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// *sobj = xSemaphoreCreateMutex();
|
||||
// return (int)(*sobj != NULL);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// *sobj = osMutexCreate(&Mutex[vol]);
|
||||
// return (int)(*sobj != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
|
||||
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)CloseHandle(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(del_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// vSemaphoreDelete(sobj);
|
||||
// return 1;
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexDelete(sobj) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
FF_SYNC_t sobj /* Sync object to wait */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(wai_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant (
|
||||
FF_SYNC_t sobj /* Sync object to be signaled */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
ReleaseMutex(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// sig_sem(sobj);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OSMutexPost(sobj);
|
||||
|
||||
/* FreeRTOS */
|
||||
// xSemaphoreGive(sobj);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// osMutexRelease(sobj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
15593
exosphere/mariko_fatal/source/fatfs/ffunicode.c
Normal file
15593
exosphere/mariko_fatal/source/fatfs/ffunicode.c
Normal file
File diff suppressed because it is too large
Load diff
259
exosphere/mariko_fatal/source/fs/fatal_fs_api.cpp
Normal file
259
exosphere/mariko_fatal/source/fs/fatal_fs_api.cpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "../fatfs/ff.h"
|
||||
#include "fatal_fs_api.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t MaxFiles = 8;
|
||||
|
||||
constinit bool g_is_sd_mounted = false;
|
||||
|
||||
FATFS g_sd_fs;
|
||||
|
||||
constinit FIL g_files[MaxFiles] = {};
|
||||
constinit bool g_files_opened[MaxFiles] = {};
|
||||
constinit int g_open_modes[MaxFiles] = {};
|
||||
|
||||
Result TranslateFatFsError(FRESULT res) {
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return ResultSuccess();
|
||||
case FR_DISK_ERR:
|
||||
return fs::ResultMmcAccessFailed();
|
||||
case FR_INT_ERR:
|
||||
return fs::ResultPreconditionViolation();
|
||||
case FR_NOT_READY:
|
||||
return fs::ResultMmcAccessFailed();
|
||||
case FR_NO_FILE:
|
||||
return fs::ResultPathNotFound();
|
||||
case FR_NO_PATH:
|
||||
return fs::ResultPathNotFound();
|
||||
case FR_INVALID_NAME:
|
||||
return fs::ResultInvalidPath();
|
||||
case FR_DENIED:
|
||||
return fs::ResultPermissionDenied();
|
||||
case FR_EXIST:
|
||||
return fs::ResultPathAlreadyExists();
|
||||
case FR_INVALID_OBJECT:
|
||||
return fs::ResultInvalidArgument();
|
||||
case FR_WRITE_PROTECTED:
|
||||
return fs::ResultWriteNotPermitted();
|
||||
case FR_INVALID_DRIVE:
|
||||
return fs::ResultInvalidMountName();
|
||||
case FR_NOT_ENABLED:
|
||||
return fs::ResultInvalidMountName(); /* BAD/TODO */
|
||||
case FR_NO_FILESYSTEM:
|
||||
return fs::ResultInvalidMountName(); /* BAD/TODO */
|
||||
case FR_TIMEOUT:
|
||||
return fs::ResultTargetLocked(); /* BAD/TODO */
|
||||
case FR_LOCKED:
|
||||
return fs::ResultTargetLocked();
|
||||
case FR_NOT_ENOUGH_CORE:
|
||||
return fs::ResultPreconditionViolation(); /* BAD/TODO */
|
||||
case FR_TOO_MANY_OPEN_FILES:
|
||||
return fs::ResultPreconditionViolation(); /* BAD/TODO */
|
||||
case FR_INVALID_PARAMETER:
|
||||
return fs::ResultInvalidArgument();
|
||||
default:
|
||||
return fs::ResultInternal();
|
||||
}
|
||||
}
|
||||
|
||||
int TranslateToFatFsMode(int mode) {
|
||||
int fmode = FA_OPEN_EXISTING;
|
||||
if ((mode & OpenMode_Read) != 0) {
|
||||
fmode |= FA_READ;
|
||||
}
|
||||
if ((mode & OpenMode_Write) != 0) {
|
||||
fmode |= FA_WRITE;
|
||||
}
|
||||
if ((mode & OpenMode_AllowAppend) != 0) {
|
||||
fmode |= FA_OPEN_APPEND;
|
||||
}
|
||||
return fmode;
|
||||
}
|
||||
|
||||
FIL *GetInternalFile(FileHandle handle) {
|
||||
return static_cast<FIL *>(handle._handle);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE size_t GetFileIndex(FIL *fp) {
|
||||
const size_t file_index = (fp - g_files);
|
||||
AMS_ASSERT(file_index < MaxFiles);
|
||||
return file_index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MountSdCard() {
|
||||
AMS_ASSERT(!g_is_sd_mounted);
|
||||
g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "", 1) == FR_OK;
|
||||
return g_is_sd_mounted;
|
||||
}
|
||||
|
||||
void UnmountSdCard() {
|
||||
AMS_ASSERT(g_is_sd_mounted);
|
||||
f_unmount("");
|
||||
g_is_sd_mounted = false;
|
||||
}
|
||||
|
||||
Result CreateFile(const char *path, s64 size) {
|
||||
/* Create the file. */
|
||||
FIL fp;
|
||||
R_TRY(TranslateFatFsError(f_open(std::addressof(fp), path, FA_CREATE_NEW | FA_READ | FA_WRITE)));
|
||||
|
||||
/* Ensure that we close the file when we're done with it. */
|
||||
ON_SCOPE_EXIT { f_close(std::addressof(fp)); };
|
||||
|
||||
/* Expand the file. */
|
||||
R_TRY(TranslateFatFsError(f_expand(std::addressof(fp), size, 1)));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CreateDirectory(const char *path) {
|
||||
return TranslateFatFsError(f_mkdir(path));
|
||||
}
|
||||
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode) {
|
||||
/* Find a free file. */
|
||||
for (size_t i = 0; i < MaxFiles; ++i) {
|
||||
if (!g_files_opened[i]) {
|
||||
/* Open the file. */
|
||||
FIL *fp = std::addressof(g_files[i]);
|
||||
R_TRY(TranslateFatFsError(f_open(fp, path, TranslateToFatFsMode(mode))));
|
||||
|
||||
/* Set the output. */
|
||||
out_file->_handle = fp;
|
||||
g_files_opened[i] = true;
|
||||
g_open_modes[i] = mode;
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return fs::ResultOpenCountLimit();
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
/* Option is unused. */
|
||||
AMS_UNUSED(option);
|
||||
|
||||
/* Seek to the offset we're reading at. */
|
||||
R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset)));
|
||||
|
||||
/* Read the data. */
|
||||
u32 br;
|
||||
R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br))));
|
||||
|
||||
/* Check that we read the correct amount. */
|
||||
R_UNLESS(br == size, fs::ResultOutOfRange());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
return ReadFile(handle, offset, buffer, size, fs::ReadOption::None);
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
/* Option is unused. */
|
||||
AMS_UNUSED(option);
|
||||
|
||||
/* Seek to the offset we're reading at. */
|
||||
R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset)));
|
||||
|
||||
/* Read the data. */
|
||||
u32 br;
|
||||
R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br))));
|
||||
|
||||
/* Set the output size. */
|
||||
*out = br;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
return ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None);
|
||||
}
|
||||
|
||||
Result GetFileSize(s64 *out, FileHandle handle) {
|
||||
FIL *fp = GetInternalFile(handle);
|
||||
*out = f_size(fp);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FlushFile(FileHandle handle) {
|
||||
return TranslateFatFsError(f_sync(GetInternalFile(handle)));
|
||||
}
|
||||
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
|
||||
/* Seek to the offset we're writing at. */
|
||||
R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset)));
|
||||
|
||||
/* Write the data. */
|
||||
u32 bw;
|
||||
R_TRY(TranslateFatFsError(f_write(GetInternalFile(handle), buffer, size, std::addressof(bw))));
|
||||
|
||||
/* Check that we wrote the correct amount. */
|
||||
R_UNLESS(bw == size, fs::ResultOutOfRange());
|
||||
|
||||
/* If we should, flush the file. */
|
||||
if (option.HasFlushFlag()) {
|
||||
R_TRY(FlushFile(handle));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetFileSize(FileHandle handle, s64 size) {
|
||||
FIL *fp = GetInternalFile(handle);
|
||||
|
||||
/* Check if we have nothing to do. */
|
||||
const size_t fsize = f_size(fp);
|
||||
R_SUCCEED_IF(static_cast<FSIZE_t>(size) == fsize);
|
||||
|
||||
/* NOTE/TODO: This may not preserve file data. Do this in a way that does? */
|
||||
|
||||
/* Truncate the file. */
|
||||
R_TRY(TranslateFatFsError(f_truncate(fp)));
|
||||
|
||||
/* Expand the file. */
|
||||
R_TRY(TranslateFatFsError(f_expand(fp, size, 1)));
|
||||
|
||||
/* Ensure the file is synchronized. */
|
||||
R_TRY(FlushFile(handle));
|
||||
|
||||
/* Check that our expansion succeeded. */
|
||||
AMS_ASSERT(f_size(fp) == static_cast<FSIZE_t>(size));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
int GetFileOpenMode(FileHandle handle) {
|
||||
return g_open_modes[GetFileIndex(GetInternalFile(handle))];
|
||||
}
|
||||
|
||||
void CloseFile(FileHandle handle) {
|
||||
const size_t index = GetFileIndex(GetInternalFile(handle));
|
||||
f_close(std::addressof(g_files[index]));
|
||||
g_open_modes[index] = 0;
|
||||
g_files_opened[index] = false;
|
||||
}
|
||||
|
||||
}
|
94
exosphere/mariko_fatal/source/fs/fatal_fs_api.hpp
Normal file
94
exosphere/mariko_fatal/source/fs/fatal_fs_api.hpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
enum OpenMode {
|
||||
OpenMode_Read = (1 << 0),
|
||||
OpenMode_Write = (1 << 1),
|
||||
OpenMode_AllowAppend = (1 << 2),
|
||||
|
||||
OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write),
|
||||
OpenMode_All = (OpenMode_ReadWrite | OpenMode_AllowAppend),
|
||||
};
|
||||
|
||||
struct ReadOption {
|
||||
u32 value;
|
||||
|
||||
static const ReadOption None;
|
||||
};
|
||||
|
||||
inline constexpr const ReadOption ReadOption::None = {0};
|
||||
|
||||
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
|
||||
|
||||
struct WriteOption {
|
||||
u32 value;
|
||||
|
||||
constexpr inline bool HasFlushFlag() const {
|
||||
return this->value & 1;
|
||||
}
|
||||
|
||||
static const WriteOption None;
|
||||
static const WriteOption Flush;
|
||||
};
|
||||
|
||||
inline constexpr const WriteOption WriteOption::None = {0};
|
||||
inline constexpr const WriteOption WriteOption::Flush = {1};
|
||||
|
||||
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
static_assert(util::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32));
|
||||
|
||||
struct FileHandle {
|
||||
void *_handle;
|
||||
};
|
||||
|
||||
bool MountSdCard();
|
||||
void UnmountSdCard();
|
||||
|
||||
Result CreateFile(const char *path, s64 size);
|
||||
Result CreateDirectory(const char *path);
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode);
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option);
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size);
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option);
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size);
|
||||
Result GetFileSize(s64 *out, FileHandle handle);
|
||||
Result FlushFile(FileHandle handle);
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option);
|
||||
Result SetFileSize(FileHandle handle, s64 size);
|
||||
int GetFileOpenMode(FileHandle handle);
|
||||
void CloseFile(FileHandle handle);
|
||||
|
||||
}
|
|
@ -40,7 +40,7 @@ endif
|
|||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC) rebootstub.bin.o sc7fw.bin.o
|
||||
export OFILES := $(OFILES_SRC) rebootstub.bin.o sc7fw.bin.o
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
|
|
|
@ -5,7 +5,8 @@ MEMORY
|
|||
{
|
||||
NULL : ORIGIN = 0, LENGTH = 4K
|
||||
unused_region : ORIGIN = 0x1000, LENGTH = 4K
|
||||
iram_boot_code : ORIGIN = 0x040032000, LENGTH = 48K
|
||||
iram_boot_code : ORIGIN = 0x040032000, LENGTH = 4K
|
||||
iram_boot_keys : ORIGIN = 0x040033000, LENGTH = 4K
|
||||
tzram : ORIGIN = 0x07C010000, LENGTH = 64K
|
||||
|
||||
/* Warmboot code follows the vectors in memory. */
|
||||
|
@ -13,9 +14,10 @@ MEMORY
|
|||
warmboot_text : ORIGIN = ORIGIN(tzram) + 10K, LENGTH = 2K
|
||||
|
||||
main : ORIGIN = 0x1F00C0000, LENGTH = 48K
|
||||
tzram_boot : ORIGIN = 0x1F01C0000, LENGTH = 8K
|
||||
debug_code : ORIGIN = 0x1F0150000, LENGTH = 16K
|
||||
tzram_boot : ORIGIN = 0x1F01C0800, LENGTH = 6K
|
||||
|
||||
glob : ORIGIN = 0x040032000, LENGTH = 64K
|
||||
glob : ORIGIN = 0x040032000, LENGTH = 128K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
@ -85,58 +87,80 @@ SECTIONS
|
|||
KEEP (*(.dtors))
|
||||
} >iram_boot_code AT>glob
|
||||
|
||||
__bootcode_end__ = ABSOLUTE(.);
|
||||
|
||||
__program_start__ = ABSOLUTE(.);
|
||||
|
||||
.tzram_boot_volatile_data : {
|
||||
KEEP (*(.volatile_keys .volatile_keys.*))
|
||||
} >tzram_boot AT>glob
|
||||
|
||||
.tzram_boot_volatile_data.fill : {
|
||||
.boot_code.fill : {
|
||||
FILL(0x00000000);
|
||||
. = ORIGIN(tzram_boot) + 0x7FF;
|
||||
. = ORIGIN(iram_boot_code) + 0xFFF;
|
||||
BYTE(0x00);
|
||||
} >tzram_boot AT>glob
|
||||
} >iram_boot_code AT>glob
|
||||
|
||||
.boot_code_volatile_keys : {
|
||||
KEEP (*(.volatile_keys .volatile_keys.*))
|
||||
} >iram_boot_keys AT>glob
|
||||
|
||||
.boot_keys.fill : {
|
||||
FILL(0x00000000);
|
||||
. = ORIGIN(iram_boot_keys) + 0xFFF;
|
||||
BYTE(0x00);
|
||||
} >iram_boot_keys AT>glob
|
||||
|
||||
.debug_code : {
|
||||
KEEP (*(.text._ZN3ams3log6PrintfEPKcz .text._ZN3ams3log7VPrintfEPKcSt9__va_list .text._ZN3ams3log4DumpEPKvm))
|
||||
KEEP (*(.text._ZN3ams4util10TVSNPrintfEPcmPKcSt9__va_list .text._ZN3ams4util12_GLOBAL__N_114TVSNPrintfImplEPcmPKcSt9__va_list .text._ZZN3ams4util12_GLOBAL__N_114TVSNPrintfImplEPcmPKcSt9__va_listENKUlbmE3_clEbm))
|
||||
KEEP(secmon_exception_handler.o(.text*))
|
||||
secmon_exception_handler.o(.rodata*)
|
||||
secmon_exception_handler.o(.data*)
|
||||
} >debug_code AT>glob
|
||||
|
||||
.debug_code.bss_fill :
|
||||
{
|
||||
FILL(0x00000000);
|
||||
secmon_exception_handler.o(.bss* COMMON)
|
||||
. = ORIGIN(debug_code) + LENGTH(debug_code) - 1;
|
||||
BYTE(0x00);
|
||||
} >debug_code AT>glob
|
||||
|
||||
__bootcode_end__ = ABSOLUTE(.) - ORIGIN(debug_code) + 0x40034000;
|
||||
|
||||
__program_start__ = __bootcode_end__;
|
||||
|
||||
.tzram_boot_code :
|
||||
{
|
||||
KEEP(secmon_main.o(.text*))
|
||||
KEEP(secmon_boot_functions.o(.text*))
|
||||
KEEP (secmon_boot_cache.o(.text*))
|
||||
KEEP(secmon_boot_cache.o(.text*))
|
||||
KEEP(secmon_boot_config.o(.text*))
|
||||
KEEP(secmon_boot_setup.o(.text*))
|
||||
KEEP(secmon_boot_rsa.o(.text*))
|
||||
KEEP(secmon_package2.o(.text*))
|
||||
secmon_main.o(.rodata*)
|
||||
secmon_boot_functions.o(.rodata*)
|
||||
secmon_boot_cache.o(.rodata*)
|
||||
secmon_boot_config.o(.rodata*)
|
||||
secmon_boot_setup.o(.rodata*)
|
||||
secmon_boot_rsa.o(.rodata*)
|
||||
secmon_package2.o(.rodata*)
|
||||
secmon_main.o(.data*)
|
||||
secmon_boot_functions.o(.data*)
|
||||
secmon_boot_cache.o(.data*)
|
||||
secmon_boot_config.o(.data*)
|
||||
secmon_boot_setup.o(.data*)
|
||||
secmon_boot_rsa.o(.data*)
|
||||
secmon_package2.o(.data*)
|
||||
. = ALIGN(8);
|
||||
} >tzram_boot AT>glob
|
||||
|
||||
.tzram_boot_code.bss :
|
||||
.tzram_boot_code.bss_fill :
|
||||
{
|
||||
FILL(0x00000000);
|
||||
__boot_bss_start__ = ABSOLUTE(.);
|
||||
secmon_main.o(.bss* COMMON)
|
||||
secmon_boot_functions.o(.bss* COMMON)
|
||||
secmon_boot_cache.o(.bss* COMMON)
|
||||
secmon_boot_config.o(.bss* COMMON)
|
||||
secmon_boot_setup.o(.bss* COMMON)
|
||||
secmon_boot_rsa.o(.bss* COMMON)
|
||||
secmon_package2.o(.bss* COMMON)
|
||||
__boot_bss_end__ = ABSOLUTE(.);
|
||||
} >tzram_boot AT>glob
|
||||
|
||||
.tzram_boot_code.fill :
|
||||
{
|
||||
FILL(0x00000000);
|
||||
. = ORIGIN(tzram_boot) + LENGTH(tzram_boot) - 1;
|
||||
BYTE(0x00);
|
||||
} > tzram_boot AT>glob
|
||||
|
@ -147,7 +171,6 @@ SECTIONS
|
|||
. = ALIGN(0x100);
|
||||
} >main AT>glob
|
||||
|
||||
|
||||
.warmboot :
|
||||
{
|
||||
KEEP (*(.warmboot.text.start)) /* Should be first */
|
||||
|
|
|
@ -24,6 +24,7 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
|||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
BINFILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
|
|
|
@ -24,6 +24,7 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
|||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
BINFILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace ams::secmon::boot {
|
|||
void MakePageTable();
|
||||
void UnmapPhysicalIdentityMapping();
|
||||
void UnmapDram();
|
||||
void LoadMarikoProgram();
|
||||
|
||||
void InitializeColdBoot();
|
||||
|
||||
|
|
|
@ -49,9 +49,19 @@ namespace ams::secmon::boot {
|
|||
}
|
||||
}
|
||||
|
||||
void ClearIram() {
|
||||
void ClearIramBootCode() {
|
||||
/* Clear the boot code image from where it was loaded in IRAM. */
|
||||
util::ClearMemory(MemoryRegionPhysicalIramBootCodeImage.GetPointer(), MemoryRegionPhysicalIramBootCodeImage.GetSize());
|
||||
util::ClearMemory(MemoryRegionPhysicalIramBootCodeCode.GetPointer(), MemoryRegionPhysicalIramBootCodeCode.GetSize());
|
||||
}
|
||||
|
||||
void ClearIramBootKeys() {
|
||||
/* Clear the boot keys from where they were loaded in IRAM. */
|
||||
util::ClearMemory(MemoryRegionPhysicalIramBootCodeKeys.GetPointer(), MemoryRegionPhysicalIramBootCodeKeys.GetSize());
|
||||
}
|
||||
|
||||
void ClearIramDebugCode() {
|
||||
/* Clear the boot code image from where it was loaded in IRAM. */
|
||||
util::ClearMemory(MemoryRegionPhysicalDebugCode.GetPointer(), MemoryRegionPhysicalDebugCode.GetSize());
|
||||
}
|
||||
|
||||
void WaitForNxBootloader(const pkg1::SecureMonitorParameters ¶ms, pkg1::BootloaderState state) {
|
||||
|
@ -147,7 +157,7 @@ namespace ams::secmon::boot {
|
|||
const u8 * const mod = secmon::boot::GetPackage2RsaModulus(pkg1::IsProductionForPublicKey());
|
||||
const size_t mod_size = se::RsaSize;
|
||||
if (verify) {
|
||||
CheckVerifyResult(secmon::boot::VerifyPackage2Signature(header, mod, mod_size), pkg1::ErrorInfo_InvalidPackage2Signature, "package2 header sign verification failed");
|
||||
CheckVerifyResult(secmon::boot::VerifyPackage2Signature(header, mod, mod_size), pkg1::ErrorInfo_InvalidPackage2Signature, "pkg2 sign FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,10 +177,10 @@ namespace ams::secmon::boot {
|
|||
|
||||
void VerifyPackage2Header(const pkg2::Package2Meta &meta) {
|
||||
/* Validate the metadata. */
|
||||
CheckVerifyResult(VerifyPackage2Meta(meta), pkg1::ErrorInfo_InvalidPackage2Meta, "package2 meta verification failed");
|
||||
CheckVerifyResult(VerifyPackage2Meta(meta), pkg1::ErrorInfo_InvalidPackage2Meta, "pkg2 meta FAIL");
|
||||
|
||||
/* Validate the version. */
|
||||
CheckVerifyResult(VerifyPackage2Version(meta), pkg1::ErrorInfo_InvalidPackage2Version, "package2 version verification failed");
|
||||
CheckVerifyResult(VerifyPackage2Version(meta), pkg1::ErrorInfo_InvalidPackage2Version, "pkg2 version FAIL");
|
||||
}
|
||||
|
||||
void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted) {
|
||||
|
@ -178,6 +188,8 @@ namespace ams::secmon::boot {
|
|||
const u8 key_generation = meta.GetKeyGeneration();
|
||||
/* Decrypt or load each payload in order. */
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
AMS_SECMON_LOG("pkg2 payload[%d]: %09lx -> %09lx size=%08x\n", i, src, dst + meta.payload_offsets[i], meta.payload_sizes[i]);
|
||||
|
||||
if (encrypted) {
|
||||
DecryptPayload(dst + meta.payload_offsets[i], src, meta.payload_sizes[i], meta.payload_ivs[i], sizeof(meta.payload_ivs[i]), key_generation);
|
||||
} else {
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
namespace ams::secmon::boot {
|
||||
|
||||
void ClearIram();
|
||||
void ClearIramBootCode();
|
||||
void ClearIramBootKeys();
|
||||
void ClearIramDebugCode();
|
||||
|
||||
void WaitForNxBootloader(const pkg1::SecureMonitorParameters ¶ms, pkg1::BootloaderState state);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
.section .volatile_keys._ZN3ams6secmon4boot15VolatileKeyDataE, "aw", %progbits
|
||||
.global _ZN3ams6secmon4boot15VolatileKeyDataE
|
||||
_ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
|
@ -75,3 +74,74 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||
|
||||
/* Package2 Aes Key Source. */
|
||||
.byte 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7
|
||||
|
||||
/* Master Key Source. */
|
||||
.byte 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
|
||||
|
||||
/* Device Master Key Source Kek Source. */
|
||||
.byte 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
|
||||
|
||||
/* NOTE: These are just latest-master-kek encrypted with KEK. */
|
||||
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
||||
/* TODO: Update on next change of keys. */
|
||||
/* Mariko Development Master Kek Source. */
|
||||
.byte 0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE
|
||||
|
||||
/* Mariko Production Master Kek Source. */
|
||||
.byte 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82
|
||||
|
||||
/* Development Master Key Vectors. */
|
||||
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
|
||||
.byte 0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23 /* Master key 00 encrypted with Master key 01. */
|
||||
.byte 0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D /* Master key 01 encrypted with Master key 02. */
|
||||
.byte 0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3 /* Master key 02 encrypted with Master key 03. */
|
||||
.byte 0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA /* Master key 03 encrypted with Master key 04. */
|
||||
.byte 0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC /* Master key 04 encrypted with Master key 05. */
|
||||
.byte 0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E /* Master key 05 encrypted with Master key 06. */
|
||||
.byte 0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19 /* Master key 06 encrypted with Master key 07. */
|
||||
.byte 0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04 /* Master key 07 encrypted with Master key 08. */
|
||||
.byte 0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE /* Master key 08 encrypted with Master key 09. */
|
||||
.byte 0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4 /* Master key 09 encrypted with Master key 0A. */
|
||||
|
||||
/* Production Master Key Vectors. */
|
||||
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
|
||||
.byte 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD /* Master key 00 encrypted with Master key 01. */
|
||||
.byte 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 /* Master key 01 encrypted with Master key 02. */
|
||||
.byte 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 /* Master key 02 encrypted with Master key 03. */
|
||||
.byte 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 /* Master key 03 encrypted with Master key 04. */
|
||||
.byte 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE /* Master key 04 encrypted with Master key 05. */
|
||||
.byte 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 /* Master key 05 encrypted with Master key 06. */
|
||||
.byte 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F /* Master key 06 encrypted with Master key 07. */
|
||||
.byte 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 /* Master key 07 encrypted with Master key 08. */
|
||||
.byte 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 /* Master key 08 encrypted with Master key 09. */
|
||||
.byte 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A /* Master key 09 encrypted with Master key 0A. */
|
||||
|
||||
/* Device Master Key Source Sources. */
|
||||
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
|
||||
.byte 0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C /* 5.0.0 Device Master Key Source Source. */
|
||||
.byte 0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4 /* 6.0.0 Device Master Key Source Source. */
|
||||
.byte 0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17 /* 6.2.0 Device Master Key Source Source. */
|
||||
.byte 0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D /* 7.0.0 Device Master Key Source Source. */
|
||||
.byte 0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE /* 8.1.0 Device Master Key Source Source. */
|
||||
.byte 0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49 /* 9.0.0 Device Master Key Source Source. */
|
||||
.byte 0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94 /* 9.1.0 Device Master Key Source Source. */
|
||||
|
||||
/* Development Device Master Kek Sources. */
|
||||
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
|
||||
.byte 0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8 /* 5.0.0 Device Master Kek Source. */
|
||||
.byte 0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5 /* 6.0.0 Device Master Kek Source. */
|
||||
.byte 0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38 /* 6.2.0 Device Master Kek Source. */
|
||||
.byte 0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE /* 7.0.0 Device Master Kek Source. */
|
||||
.byte 0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87 /* 8.1.0 Device Master Kek Source. */
|
||||
.byte 0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F /* 9.0.0 Device Master Kek Source. */
|
||||
.byte 0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B /* 9.1.0 Device Master Kek Source. */
|
||||
|
||||
/* Production Device Master Kek Sources. */
|
||||
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
|
||||
.byte 0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E /* 5.0.0 Device Master Kek Source. */
|
||||
.byte 0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF /* 6.0.0 Device Master Kek Source. */
|
||||
.byte 0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB /* 6.2.0 Device Master Kek Source. */
|
||||
.byte 0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E /* 7.0.0 Device Master Kek Source. */
|
||||
.byte 0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D /* 8.1.0 Device Master Kek Source. */
|
||||
.byte 0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED /* 9.0.0 Device Master Kek Source. */
|
||||
.byte 0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36 /* 9.1.0 Device Master Kek Source. */
|
||||
|
|
|
@ -74,10 +74,6 @@ namespace ams::secmon::boot {
|
|||
reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH32, 0x129);
|
||||
}
|
||||
|
||||
constinit const u8 DeviceMasterKeySourceKekSource[se::AesBlockSize] = {
|
||||
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
|
||||
};
|
||||
|
||||
/* This function derives the master kek and device keys using the tsec root key. */
|
||||
void DeriveMasterKekAndDeviceKeyErista(bool is_prod) {
|
||||
/* NOTE: Exosphere does not use this in practice, and expects the bootloader to set up keys already. */
|
||||
|
@ -89,21 +85,6 @@ namespace ams::secmon::boot {
|
|||
AMS_UNUSED(is_prod);
|
||||
}
|
||||
|
||||
/* NOTE: These are just latest-master-kek encrypted with BEK. */
|
||||
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
||||
/* TODO: Update on next change of keys. */
|
||||
constinit const u8 MarikoMasterKekSourceProd[se::AesBlockSize] = {
|
||||
0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82
|
||||
};
|
||||
|
||||
constinit const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
||||
0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE
|
||||
};
|
||||
|
||||
constinit const u8 MasterKeySource[se::AesBlockSize] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
|
||||
};
|
||||
|
||||
void DeriveMasterKekAndDeviceKeyMariko(bool is_prod) {
|
||||
/* Clear all keyslots other than KEK and SBK in SE1. */
|
||||
for (int i = 0; i < pkg1::AesKeySlot_Count; ++i) {
|
||||
|
@ -118,10 +99,10 @@ namespace ams::secmon::boot {
|
|||
}
|
||||
|
||||
/* Derive the master kek. */
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_MasterKek, pkg1::AesKeySlot_MarikoKek, is_prod ? MarikoMasterKekSourceProd : MarikoMasterKekSourceDev, se::AesBlockSize);
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_MasterKek, pkg1::AesKeySlot_MarikoKek, GetMarikoMasterKekSource(is_prod), se::AesBlockSize);
|
||||
|
||||
/* Derive the device master key source kek. */
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMasterKeySourceKekMariko, pkg1::AesKeySlot_SecureBoot, DeviceMasterKeySourceKekSource, se::AesBlockSize);
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMasterKeySourceKekMariko, pkg1::AesKeySlot_SecureBoot, GetDeviceMasterKeySourceKekSource(), se::AesBlockSize);
|
||||
|
||||
/* Clear the KEK, now that we're done using it. */
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_MarikoKek);
|
||||
|
@ -137,7 +118,7 @@ namespace ams::secmon::boot {
|
|||
|
||||
void DeriveMasterKey() {
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Master, pkg1::AesKeySlot_MasterKek, MasterKeySource, se::AesBlockSize);
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Master, pkg1::AesKeySlot_MasterKek, GetMasterKeySource(), se::AesBlockSize);
|
||||
} else /* if (GetSocType() == fuse::SocType_Erista) */ {
|
||||
/* Nothing to do here; erista bootloader will have derived master key already. */
|
||||
}
|
||||
|
@ -167,45 +148,17 @@ namespace ams::secmon::boot {
|
|||
se::LockAesKeySlot(slot, flags);
|
||||
}
|
||||
|
||||
constinit const u8 MasterKeyVectorsDev[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
|
||||
{0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */
|
||||
{0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */
|
||||
{0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D}, /* Master key 01 encrypted with Master key 02. */
|
||||
{0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */
|
||||
{0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */
|
||||
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04}, /* Master key 07 encrypted with Master key 08. */
|
||||
{0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */
|
||||
{0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */
|
||||
};
|
||||
|
||||
constinit const u8 MasterKeyVectorsProd[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
|
||||
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
|
||||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
||||
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
|
||||
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
|
||||
};
|
||||
|
||||
bool TestKeyGeneration(int generation, bool is_prod) {
|
||||
/* Decrypt the vector chain from generation to start. */
|
||||
int slot = pkg1::AesKeySlot_Master;
|
||||
for (int i = generation; i > 0; --i) {
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, slot, GetMasterKeyVector(is_prod, i), se::AesBlockSize);
|
||||
slot = pkg1::AesKeySlot_Temporary;
|
||||
}
|
||||
|
||||
/* Decrypt the final vector. */
|
||||
u8 test_vector[se::AesBlockSize];
|
||||
se::DecryptAes128(test_vector, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[0] : MasterKeyVectorsDev[0], se::AesBlockSize);
|
||||
se::DecryptAes128(test_vector, se::AesBlockSize, slot, GetMasterKeyVector(is_prod, 0), se::AesBlockSize);
|
||||
|
||||
constexpr u8 ZeroBlock[se::AesBlockSize] = {};
|
||||
return crypto::IsSameBytes(ZeroBlock, test_vector, se::AesBlockSize);
|
||||
|
@ -224,9 +177,9 @@ namespace ams::secmon::boot {
|
|||
}
|
||||
|
||||
void DeriveAllMasterKeys(bool is_prod, u8 * const work_block) {
|
||||
|
||||
/* Determine the generation. */
|
||||
const int generation = DetermineKeyGeneration(is_prod);
|
||||
AMS_SECMON_LOG("KeyGen: %02X\n", static_cast<unsigned int>(generation));
|
||||
|
||||
/* Set the global generation. */
|
||||
::ams::secmon::impl::SetKeyGeneration(generation);
|
||||
|
@ -235,7 +188,7 @@ namespace ams::secmon::boot {
|
|||
int slot = pkg1::AesKeySlot_Master;
|
||||
for (int i = generation; i > 0; --i) {
|
||||
/* Decrypt the old master key. */
|
||||
se::DecryptAes128(work_block, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
|
||||
se::DecryptAes128(work_block, se::AesBlockSize, slot, GetMasterKeyVector(is_prod, i), se::AesBlockSize);
|
||||
|
||||
/* Set the old master key. */
|
||||
SetMasterKey(i - 1, work_block, se::AesBlockSize);
|
||||
|
@ -248,39 +201,6 @@ namespace ams::secmon::boot {
|
|||
}
|
||||
}
|
||||
|
||||
constinit const u8 DeviceMasterKeySourceSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */
|
||||
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */
|
||||
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */
|
||||
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */
|
||||
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */
|
||||
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */
|
||||
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */
|
||||
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */
|
||||
};
|
||||
|
||||
constinit const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */
|
||||
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */
|
||||
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */
|
||||
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */
|
||||
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */
|
||||
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */
|
||||
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */
|
||||
{0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */
|
||||
};
|
||||
|
||||
constinit const u8 DeviceMasterKekSourcesProd[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */
|
||||
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */
|
||||
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */
|
||||
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */
|
||||
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */
|
||||
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */
|
||||
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */
|
||||
{0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */
|
||||
};
|
||||
|
||||
void DeriveAllDeviceMasterKeys(bool is_prod, u8 * const work_block) {
|
||||
/* Get the current key generation. */
|
||||
const int current_generation = secmon::GetKeyGeneration();
|
||||
|
@ -296,10 +216,10 @@ namespace ams::secmon::boot {
|
|||
LoadMasterKey(pkg1::AesKeySlot_Temporary, pkg1::KeyGeneration_1_0_0);
|
||||
|
||||
/* Decrypt the device master kek for the generation. */
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, is_prod ? DeviceMasterKekSourcesProd[i] : DeviceMasterKekSourcesDev[i], se::AesBlockSize);
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, GetDeviceMasterKekSource(is_prod, i), se::AesBlockSize);
|
||||
|
||||
/* Decrypt the device master key source into the work block. */
|
||||
se::DecryptAes128(work_block, se::AesBlockSize, kek_slot, DeviceMasterKeySourceSources[i], se::AesBlockSize);
|
||||
se::DecryptAes128(work_block, se::AesBlockSize, kek_slot, GetDeviceMasterKeySourceSource(i), se::AesBlockSize);
|
||||
|
||||
/* If we're decrypting the current device master key, decrypt into the keyslot. */
|
||||
if (generation == current_generation) {
|
||||
|
@ -412,6 +332,12 @@ namespace ams::secmon::boot {
|
|||
InvalidateL1Entries(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize());
|
||||
}
|
||||
|
||||
constexpr void UnmapMarikoProgramImpl(u64 *l1, u64 *l2, u64 *l3) {
|
||||
/* Unmap the L1 entry corresponding to to the Dram entries. */
|
||||
AMS_UNUSED(l1, l2);
|
||||
InvalidateL3Entries(l3, MemoryRegionVirtualTzramMarikoProgram.GetAddress(), MemoryRegionVirtualTzramMarikoProgram.GetSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeColdBoot() {
|
||||
|
@ -467,4 +393,30 @@ namespace ams::secmon::boot {
|
|||
secmon::boot::EnsureMappingConsistency();
|
||||
}
|
||||
|
||||
void LoadMarikoProgram() {
|
||||
void * const mariko_program_dst = MemoryRegionVirtualTzramMarikoProgram.GetPointer<void>();
|
||||
void * const mariko_program_src = MemoryRegionPhysicalMarikoProgramImage.GetPointer<void>();
|
||||
const size_t mariko_program_size = MemoryRegionVirtualTzramMarikoProgram.GetSize();
|
||||
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
/* On Mariko, we want to load the mariko program image into mariko tzram. */
|
||||
std::memcpy(mariko_program_dst, mariko_program_src, mariko_program_size);
|
||||
hw::FlushDataCache(mariko_program_dst, mariko_program_size);
|
||||
} else {
|
||||
/* On Erista, we don't have mariko-only-tzram, so unmap it. */
|
||||
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();
|
||||
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>();
|
||||
|
||||
UnmapMarikoProgramImpl(l1, l2_l3, l2_l3);
|
||||
}
|
||||
|
||||
/* Clear the Mariko program image from DRAM. */
|
||||
util::ClearMemory(mariko_program_src, mariko_program_size);
|
||||
hw::FlushDataCache(mariko_program_src, mariko_program_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Ensure the mappings are consistent. */
|
||||
secmon::boot::EnsureMappingConsistency();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace ams::secmon {
|
|||
/* This checks the security engine's validity, and configures common interrupts in the GIC. */
|
||||
/* This also initializes the global configuration context. */
|
||||
secmon::Setup1();
|
||||
AMS_SECMON_LOG("%s\n", "Boot begin.");
|
||||
|
||||
/* Save the boot info. */
|
||||
secmon::SaveBootInfo(secmon_params);
|
||||
|
@ -70,7 +71,12 @@ namespace ams::secmon {
|
|||
secmon::SetupCpuCoreContext();
|
||||
|
||||
/* Clear the crt0 code that was present in iram. */
|
||||
secmon::boot::ClearIram();
|
||||
secmon::boot::ClearIramBootCode();
|
||||
|
||||
/* Clear the debug code from iram, if we're not in debug config. */
|
||||
#if !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING)
|
||||
secmon::boot::ClearIramDebugCode();
|
||||
#endif
|
||||
|
||||
/* Alert the bootloader that we're initialized. */
|
||||
secmon_params.secmon_state = pkg1::SecureMonitorState_Initialized;
|
||||
|
@ -117,8 +123,8 @@ namespace ams::secmon {
|
|||
std::memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
/* Unmap the identity mapping. */
|
||||
secmon::boot::UnmapPhysicalIdentityMapping();
|
||||
/* Load the mariko program image. */
|
||||
secmon::boot::LoadMarikoProgram();
|
||||
|
||||
/* Setup the GPU carveout's magic numbers. */
|
||||
secmon::boot::WriteGpuCarveoutMagicNumbers();
|
||||
|
@ -160,7 +166,7 @@ namespace ams::secmon {
|
|||
}
|
||||
|
||||
/* Verify the package2 payloads. */
|
||||
secmon::boot::CheckVerifyResult(secmon::boot::VerifyPackage2Payloads(pkg2_meta, pkg2_payloads_start), pkg1::ErrorInfo_InvalidPackage2Payload, "package2 payload verification failed");
|
||||
secmon::boot::CheckVerifyResult(secmon::boot::VerifyPackage2Payloads(pkg2_meta, pkg2_payloads_start), pkg1::ErrorInfo_InvalidPackage2Payload, "pkg2 payload FAIL");
|
||||
|
||||
/* Decrypt/Move the package2 payloads to the right places. */
|
||||
secmon::boot::DecryptAndLoadPackage2Payloads(Package2LoadAddress, pkg2_meta, pkg2_payloads_start, !bc.signed_data.IsPackage2EncryptionDisabled());
|
||||
|
@ -172,6 +178,12 @@ namespace ams::secmon {
|
|||
/* Set the core's entrypoint and argument. */
|
||||
secmon::SetEntryContext(0, Package2LoadAddress + pkg2_meta.entrypoint, 0);
|
||||
|
||||
/* Clear the boot keys from iram. */
|
||||
secmon::boot::ClearIramBootKeys();
|
||||
|
||||
/* Unmap the identity mapping. */
|
||||
secmon::boot::UnmapPhysicalIdentityMapping();
|
||||
|
||||
/* Unmap DRAM. */
|
||||
secmon::boot::UnmapDram();
|
||||
|
||||
|
@ -184,6 +196,8 @@ namespace ams::secmon {
|
|||
|
||||
/* Configure the smc handler tables to reflect the current target firmware. */
|
||||
secmon::smc::ConfigureSmcHandlersForTargetFirmware();
|
||||
|
||||
AMS_SECMON_LOG("%s\n", "Boot end.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,6 +84,17 @@ namespace ams::secmon::boot {
|
|||
/* Identity-map IRAM boot code as rwx. */
|
||||
SetL3BlockEntry(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
{
|
||||
/* Map the debug code region as rwx. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualDebugCode.GetAddress(), MemoryRegionPhysicalDebugCode.GetAddress(), MemoryRegionPhysicalDebugCode.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||
|
||||
|
||||
/* Map the DRAM debug code store region as rw. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualDramDebugDataStore.GetAddress(), MemoryRegionPhysicalDramDebugDataStore.GetAddress(), MemoryRegionPhysicalDramDebugDataStore.GetSize(), MappingAttributesEl3NonSecureRwData);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Map all devices. */
|
||||
{
|
||||
#define MAP_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
|
||||
|
@ -114,6 +125,12 @@ namespace ams::secmon::boot {
|
|||
/* Map the program region as rwx. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualTzramProgram.GetAddress(), MemoryRegionPhysicalTzramProgram.GetAddress(), MemoryRegionVirtualTzramProgram.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||
|
||||
/* Map the mariko program region as rwx. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualTzramMarikoProgram.GetAddress(), MemoryRegionPhysicalTzramMarikoProgram.GetAddress(), MemoryRegionPhysicalTzramMarikoProgram.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||
|
||||
/* Map the mariko program region as rwx. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualTzramMarikoProgramStack.GetAddress(), MemoryRegionPhysicalTzramMarikoProgramStack.GetAddress(), MemoryRegionPhysicalTzramMarikoProgramStack.GetSize(), MappingAttributesEl3SecureRwData);
|
||||
|
||||
/* Map the boot code region. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualTzramBootCode.GetAddress(), MemoryRegionPhysicalTzramBootCode.GetAddress(), MemoryRegionVirtualTzramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||
|
||||
|
|
|
@ -21,17 +21,6 @@ namespace ams {
|
|||
namespace {
|
||||
|
||||
constexpr bool SaveSystemStateForDebug = false;
|
||||
constexpr bool LogSystemStateForDebug = false;
|
||||
|
||||
void LogU64(u64 value) {
|
||||
char buffer[2 * sizeof(value)];
|
||||
for (size_t i = 0; i < sizeof(value); ++i) {
|
||||
buffer[sizeof(buffer) - 1 - (2 * i) - 0] = "0123456789ABCDEF"[(value >> 0) & 0xF];
|
||||
buffer[sizeof(buffer) - 1 - (2 * i) - 1] = "0123456789ABCDEF"[(value >> 4) & 0xF];
|
||||
value >>= 8;
|
||||
}
|
||||
log::SendText(buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -114,57 +103,6 @@ namespace ams::secmon {
|
|||
util::WaitMicroSeconds(1000);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void LogSystemStateForDebugErrorReboot(u64 lr, u64 sp) {
|
||||
log::SendText("*** Error Reboot ***\n", 21);
|
||||
log::Flush();
|
||||
|
||||
u64 temp_reg;
|
||||
|
||||
__asm__ __volatile__("mrs %0, esr_el3" : "=r"(temp_reg) :: "memory");
|
||||
log::SendText("ESR_EL3: ", 9);
|
||||
LogU64(temp_reg);
|
||||
log::SendText("\n", 1);
|
||||
log::Flush();
|
||||
|
||||
__asm__ __volatile__("mrs %0, elr_el3" : "=r"(temp_reg) :: "memory");
|
||||
log::SendText("ELR_EL3: ", 9);
|
||||
LogU64(temp_reg);
|
||||
log::SendText("\n", 1);
|
||||
log::Flush();
|
||||
|
||||
__asm__ __volatile__("mrs %0, far_el3" : "=r"(temp_reg) :: "memory");
|
||||
log::SendText("FAR_EL3: ", 9);
|
||||
LogU64(temp_reg);
|
||||
log::SendText("\n", 1);
|
||||
log::Flush();
|
||||
|
||||
log::SendText("LR: ", 9);
|
||||
LogU64(lr);
|
||||
log::SendText("\n", 1);
|
||||
log::Flush();
|
||||
|
||||
log::SendText("SP: ", 9);
|
||||
LogU64(sp);
|
||||
log::SendText("\n", 1);
|
||||
log::Flush();
|
||||
|
||||
log::SendText("Stack:\n", 7);
|
||||
log::Flush();
|
||||
|
||||
char buf[2];
|
||||
for (int i = 0; i < 0x100; ++i) {
|
||||
const u8 byte = *(volatile u8 *)(sp + i);
|
||||
buf[0] = "0123456789ABCDEF"[(byte >> 4) & 0xF];
|
||||
buf[1] = "0123456789ABCDEF"[(byte >> 0) & 0xF];
|
||||
log::SendText(buf, 2);
|
||||
log::Flush();
|
||||
if (util::IsAligned(i + 1, 0x10)) {
|
||||
log::SendText("\n", 1);
|
||||
log::Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetError(pkg1::ErrorInfo info) {
|
||||
|
@ -181,14 +119,6 @@ namespace ams::secmon {
|
|||
SaveSystemStateForDebugErrorReboot();
|
||||
}
|
||||
|
||||
if constexpr (LogSystemStateForDebug) {
|
||||
u64 lr, sp;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
__asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory");
|
||||
|
||||
LogSystemStateForDebugErrorReboot(lr, sp);
|
||||
}
|
||||
|
||||
/* Lockout the security engine. */
|
||||
se::Lockout();
|
||||
|
||||
|
|
99
exosphere/program/source/secmon_exception_handler.cpp
Normal file
99
exosphere/program/source/secmon_exception_handler.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "secmon_error.hpp"
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
|
||||
|
||||
constinit std::atomic_bool g_is_locked = false;
|
||||
|
||||
}
|
||||
|
||||
void ExceptionHandlerImpl(uintptr_t lr, uintptr_t sp) {
|
||||
/* On release config, we won't actually use the passed parameters. */
|
||||
AMS_UNUSED(lr, sp);
|
||||
|
||||
/* Ensure that previous logs have been flushed. */
|
||||
AMS_LOG_FLUSH();
|
||||
|
||||
/* Get system registers. */
|
||||
uintptr_t far_el1, far_el3, elr_el3;
|
||||
util::BitPack32 esr_el3;
|
||||
|
||||
HW_CPU_GET_FAR_EL1(far_el1);
|
||||
HW_CPU_GET_FAR_EL3(far_el3);
|
||||
HW_CPU_GET_ELR_EL3(elr_el3);
|
||||
HW_CPU_GET_ESR_EL3(esr_el3);
|
||||
|
||||
/* Print some whitespace before the exception handler. */
|
||||
AMS_LOG("\n\n");
|
||||
AMS_SECMON_LOG("ExceptionHandler\n");
|
||||
AMS_SECMON_LOG("----------------\n");
|
||||
AMS_SECMON_LOG("esr: 0x%08X\n", esr_el3.value);
|
||||
AMS_SECMON_LOG(" Exception Class: 0x%02X\n", esr_el3.Get<hw::EsrEl3::Ec>());
|
||||
AMS_SECMON_LOG(" Instruction Length: %d\n", esr_el3.Get<hw::EsrEl3::Il>() ? 32 : 16);
|
||||
AMS_SECMON_LOG(" Instruction Specific Syndrome: 0x%07X\n", esr_el3.Get<hw::EsrEl3::Iss>());
|
||||
|
||||
AMS_SECMON_LOG("far_el1: 0x%016lX\n", far_el1);
|
||||
AMS_SECMON_LOG("far_el3: 0x%016lX\n", far_el3);
|
||||
AMS_SECMON_LOG("elr_el3: 0x%016lX\n", elr_el3);
|
||||
|
||||
AMS_SECMON_LOG("lr: 0x%016lX\n", lr);
|
||||
AMS_SECMON_LOG("sp: 0x%016lX\n", sp);
|
||||
|
||||
AMS_DUMP(reinterpret_cast<void *>(sp), util::AlignUp(sp, mmu::PageSize) - sp);
|
||||
|
||||
AMS_LOG_FLUSH();
|
||||
}
|
||||
|
||||
NORETURN void ExceptionHandler() {
|
||||
/* Get link register and stack pointer. */
|
||||
u64 lr, sp;
|
||||
{
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
__asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory");
|
||||
}
|
||||
|
||||
/* Acquire exclusive access to exception handling logic. */
|
||||
if (!g_is_locked.exchange(true)) {
|
||||
/* Invoke the exception handler impl. */
|
||||
ExceptionHandlerImpl(lr, sp);
|
||||
|
||||
/* Lockout the security engine. */
|
||||
se::Lockout();
|
||||
|
||||
/* Lockout fuses. */
|
||||
fuse::Lockout();
|
||||
|
||||
/* Disable crypto operations after reboot. */
|
||||
reg::Write(PMC + APBDEV_PMC_CRYPTO_OP, 0);
|
||||
|
||||
/* Perform an error reboot. */
|
||||
secmon::SetError(pkg1::ErrorInfo_UnknownAbort);
|
||||
secmon::ErrorReboot();
|
||||
} else {
|
||||
/* Wait forever while the first core prints the exception and reboots. */
|
||||
while (true) {
|
||||
util::WaitMicroSeconds(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -76,6 +76,11 @@ vector_entry synch_sp0
|
|||
.endfunc
|
||||
.cfi_endproc
|
||||
_ZN3ams6secmon26UnexpectedExceptionHandlerEv:
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
/* Jump to the debug exception handler. */
|
||||
ldr x16, =_ZN3ams6secmon16ExceptionHandlerEv
|
||||
br x16
|
||||
#else
|
||||
/* Load the ErrorInfo scratch. */
|
||||
ldr x0, =0x1F004AC40
|
||||
|
||||
|
@ -85,6 +90,7 @@ _ZN3ams6secmon26UnexpectedExceptionHandlerEv:
|
|||
|
||||
/* Perform an error reboot. */
|
||||
b _ZN3ams6secmon11ErrorRebootEv
|
||||
#endif
|
||||
|
||||
vector_entry irq_sp0
|
||||
/* An unexpected exception was taken. */
|
||||
|
@ -157,22 +163,22 @@ vector_entry irq_a64
|
|||
check_vector_size irq_a64
|
||||
|
||||
vector_entry fiq_a64
|
||||
/* Save X29, X30. */
|
||||
/* Save x18, x26-x30. */
|
||||
stp x29, x30, [sp, #-0x10]!
|
||||
|
||||
/* Get the current core ID, ensure it's core 3. */
|
||||
mrs x29, mpidr_el1
|
||||
and x29, x29, #3
|
||||
cmp x29, #3
|
||||
b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||
|
||||
/* Save x26-x28, x18. */
|
||||
stp x28, x18, [sp, #-0x10]!
|
||||
stp x26, x27, [sp, #-0x10]!
|
||||
|
||||
/* Set x18 to the global data region. */
|
||||
ldr x18, =0x1F01FA000
|
||||
|
||||
/* Get the current core. */
|
||||
mrs x29, mpidr_el1
|
||||
and x29, x29, #3
|
||||
|
||||
/* If we're not on core 3, take the core0-2 handler. */
|
||||
cmp x29, #3
|
||||
b.ne _ZN3ams6secmon25HandleFiqExceptionCore012Ev
|
||||
|
||||
/* Handle the fiq exception. */
|
||||
bl _ZN3ams6secmon18HandleFiqExceptionEv
|
||||
|
||||
|
@ -320,7 +326,41 @@ _ZN3ams6secmon18HandleFiqExceptionEv:
|
|||
vector_entry serror_a32
|
||||
/* An unexpected exception was taken. */
|
||||
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||
check_vector_size serror_a32
|
||||
.endfunc
|
||||
.cfi_endproc
|
||||
_ZN3ams6secmon25HandleFiqExceptionCore012Ev:
|
||||
/* Acquire exclusive access to the common smc stack. */
|
||||
stp x4, x5, [sp, #-0x10]!
|
||||
stp x2, x3, [sp, #-0x10]!
|
||||
stp x0, x1, [sp, #-0x10]!
|
||||
bl _ZN3ams6secmon25AcquireCommonSmcStackLockEv
|
||||
ldp x0, x1, [sp], #0x10
|
||||
ldp x2, x3, [sp], #0x10
|
||||
ldp x4, x5, [sp], #0x10
|
||||
|
||||
/* Pivot to use the common smc stack. */
|
||||
mov x30, sp
|
||||
ldr x29, =0x1F01F6E80
|
||||
mov sp, x29
|
||||
stp x29, x30, [sp, #-0x10]!
|
||||
|
||||
/* Handle the fiq exception. */
|
||||
bl _ZN3ams6secmon18HandleFiqExceptionEv
|
||||
|
||||
/* Restore our core-specific stack. */
|
||||
ldp x29, x30, [sp], #0x10
|
||||
mov sp, x30
|
||||
|
||||
/* Release our exclusive access to the common smc stack. */
|
||||
stp x0, x1, [sp, #-0x10]!
|
||||
bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
|
||||
ldp x0, x1, [sp], #0x10
|
||||
|
||||
/* Return. */
|
||||
ldp x26, x27, [sp], #0x10
|
||||
ldp x28, x18, [sp], #0x10
|
||||
ldp x29, x30, [sp], #0x10
|
||||
eret
|
||||
|
||||
/* Instantiate the literal pool for the exception vectors. */
|
||||
.ltorg
|
||||
|
|
|
@ -25,14 +25,16 @@ namespace ams::secmon {
|
|||
|
||||
constinit InterruptHandler g_handlers[InterruptHandlersMax] = {};
|
||||
constinit int g_interrupt_ids[InterruptHandlersMax] = {};
|
||||
constinit u8 g_interrupt_core_masks[InterruptHandlersMax] = {};
|
||||
|
||||
}
|
||||
|
||||
void SetInterruptHandler(int interrupt_id, InterruptHandler handler) {
|
||||
void SetInterruptHandler(int interrupt_id, u8 core_mask, InterruptHandler handler) {
|
||||
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
||||
if (g_interrupt_ids[i] == 0) {
|
||||
g_interrupt_ids[i] = interrupt_id;
|
||||
g_handlers[i] = handler;
|
||||
g_interrupt_ids[i] = interrupt_id;
|
||||
g_handlers[i] = handler;
|
||||
g_interrupt_core_masks[i] = core_mask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +53,9 @@ namespace ams::secmon {
|
|||
/* Check each handler. */
|
||||
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
||||
if (g_interrupt_ids[i] == interrupt_id) {
|
||||
/* Validate that we can invoke the handler. */
|
||||
AMS_ABORT_UNLESS((g_interrupt_core_masks[i] & (1u << hw::GetCurrentCoreId())) != 0);
|
||||
|
||||
/* Invoke the handler. */
|
||||
g_handlers[i]();
|
||||
gic::SetEndOfInterrupt(interrupt_id);
|
||||
|
|
|
@ -20,6 +20,6 @@ namespace ams::secmon {
|
|||
|
||||
using InterruptHandler = void (*)();
|
||||
|
||||
void SetInterruptHandler(int interrupt_id, InterruptHandler handler);
|
||||
void SetInterruptHandler(int interrupt_id, u8 core_mask, InterruptHandler handler);
|
||||
|
||||
}
|
||||
|
|
|
@ -86,6 +86,12 @@ namespace ams::secmon {
|
|||
InvalidateL3Entries(l3, MemoryRegionVirtualAtmosphereUserPage.GetAddress(), MemoryRegionVirtualAtmosphereUserPage.GetSize());
|
||||
}
|
||||
|
||||
constexpr void MapDramForMarikoProgramImpl(u64 *l1, u64 *l2, u64 *l3) {
|
||||
/* Map the L1 entry corresponding to the mariko program dram entry. */
|
||||
AMS_UNUSED(l2, l3);
|
||||
SetL1BlockEntry(l1, MemoryRegionDramForMarikoProgram.GetAddress(), MemoryRegionDramForMarikoProgram.GetAddress(), MemoryRegionDramForMarikoProgram.GetSize(), MappingAttributesEl3NonSecureRwData);
|
||||
}
|
||||
|
||||
void ClearLow(uintptr_t address, size_t size) {
|
||||
/* Clear the low part. */
|
||||
util::ClearMemory(reinterpret_cast<void *>(address), size / 2);
|
||||
|
@ -301,4 +307,16 @@ namespace ams::secmon {
|
|||
ReleaseSpinLock(g_ams_user_page_spin_lock);
|
||||
}
|
||||
|
||||
void MapDramForMarikoProgram() {
|
||||
/* Get the tables. */
|
||||
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();
|
||||
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>();
|
||||
|
||||
/* Map. */
|
||||
MapDramForMarikoProgramImpl(l1, l2_l3, l2_l3);
|
||||
|
||||
/* Ensure the mappings are consistent. */
|
||||
secmon::EnsureMappingConsistency();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,4 +32,6 @@ namespace ams::secmon {
|
|||
uintptr_t MapAtmosphereUserPage(uintptr_t address);
|
||||
void UnmapAtmosphereUserPage();
|
||||
|
||||
void MapDramForMarikoProgram();
|
||||
|
||||
}
|
89
exosphere/program/source/secmon_mariko_fatal_error.cpp
Normal file
89
exosphere/program/source/secmon_mariko_fatal_error.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "secmon_cpu_context.hpp"
|
||||
#include "secmon_map.hpp"
|
||||
#include "secmon_page_mapper.hpp"
|
||||
#include "secmon_mariko_fatal_error.hpp"
|
||||
#include "smc/secmon_smc_power_management.hpp"
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit u8 g_fatal_error_mask = 0;
|
||||
|
||||
}
|
||||
|
||||
void HandleMarikoFatalErrorInterrupt() {
|
||||
/* This interrupt handler doesn't return, so mark that we're at end of interrupt. */
|
||||
gic::SetEndOfInterrupt(MarikoFatalErrorInterruptId);
|
||||
|
||||
/* Get the current core id. */
|
||||
const auto core_id = hw::GetCurrentCoreId();
|
||||
|
||||
/* Set that we received the fatal on the current core. */
|
||||
g_fatal_error_mask |= (1u << core_id);
|
||||
hw::FlushDataCache(std::addressof(g_fatal_error_mask), sizeof(g_fatal_error_mask));
|
||||
hw::DataSynchronizationBarrier();
|
||||
|
||||
/* If not all cores have received the fatal, we need to trigger the interrupt on other cores. */
|
||||
if (g_fatal_error_mask != (1u << NumCores) - 1) {
|
||||
/* Configure and send the interrupt to the next core. */
|
||||
const auto next_core = __builtin_ctz(~g_fatal_error_mask);
|
||||
gic::SetSpiTargetCpu(MarikoFatalErrorInterruptId, (1u << next_core));
|
||||
gic::SetPending(MarikoFatalErrorInterruptId);
|
||||
}
|
||||
|
||||
/* If current core is not 3, kill ourselves. */
|
||||
if (core_id != NumCores - 1) {
|
||||
smc::PowerOffCpu();
|
||||
} else {
|
||||
/* Wait for all cores to kill themselves. */
|
||||
while (g_fatal_error_mask != (1u << NumCores) - 1) {
|
||||
util::WaitMicroSeconds(100);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the fatal error context to mariko tzram. */
|
||||
{
|
||||
/* Map the iram page. */
|
||||
constexpr uintptr_t FatalErrorPhysicalAddress = MemoryRegionPhysicalIramFatalErrorContext.GetAddress();
|
||||
AtmosphereIramPageMapper mapper(FatalErrorPhysicalAddress);
|
||||
if (mapper.Map()) {
|
||||
/* Copy the fatal error context. */
|
||||
void *dst = MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<void>();
|
||||
const void *src = mapper.GetPointerTo(FatalErrorPhysicalAddress, sizeof(ams::impl::FatalErrorContext));
|
||||
std::memcpy(dst, src, sizeof(ams::impl::FatalErrorContext));
|
||||
}
|
||||
}
|
||||
|
||||
/* Map Dram for the mariko program. */
|
||||
MapDramForMarikoProgram();
|
||||
|
||||
AMS_SECMON_LOG("%s\n", "Jumping to Mariko Fatal.");
|
||||
AMS_LOG_FLUSH();
|
||||
|
||||
/* Jump to the mariko fatal program. */
|
||||
reinterpret_cast<void (*)()>(secmon::MemoryRegionVirtualTzramMarikoProgram.GetAddress())();
|
||||
|
||||
/* The mariko fatal program never returns. */
|
||||
__builtin_unreachable();
|
||||
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
}
|
25
exosphere/program/source/secmon_mariko_fatal_error.hpp
Normal file
25
exosphere/program/source/secmon_mariko_fatal_error.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
constexpr inline int MarikoFatalErrorInterruptId = 198;
|
||||
|
||||
NORETURN void HandleMarikoFatalErrorInterrupt();
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
#include "secmon_error.hpp"
|
||||
#include "secmon_map.hpp"
|
||||
#include "secmon_cpu_context.hpp"
|
||||
#include "secmon_mariko_fatal_error.hpp"
|
||||
#include "secmon_interrupt_handler.hpp"
|
||||
#include "secmon_misc.hpp"
|
||||
#include "smc/secmon_random_cache.hpp"
|
||||
|
@ -814,6 +815,16 @@ namespace ams::secmon {
|
|||
reg::Read(MC + MC_IRAM_REG_CTRL);
|
||||
}
|
||||
|
||||
void DisableUntranslatedDeviceMemoryAccess() {
|
||||
/* If we can (mariko only), disable GMMU accesses that bypass the SMMU. */
|
||||
/* Additionally, force all untranslated acccesses to hit one of the carveouts. */
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
reg::Write(MC + MC_UNTRANSLATED_REGION_CHECK, MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_UNTRANSLATED_REGION_CHECK_ACCESS, DISABLED),
|
||||
MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_REQUIRE_UNTRANSLATED_CLIENTS_HIT_CARVEOUT, ENABLED),
|
||||
MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_REQUIRE_UNTRANSLATED_GPU_HIT_CARVEOUT, ENABLED));
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeCarveoutSecureScratchRegisters() {
|
||||
/* Define carveout scratch values. */
|
||||
constexpr uintptr_t WarmbootCarveoutAddress = MemoryRegionDram.GetAddress();
|
||||
|
@ -1072,25 +1083,36 @@ namespace ams::secmon {
|
|||
|
||||
/* Setup the security engine interrupt. */
|
||||
constexpr int SecurityEngineInterruptId = 90;
|
||||
gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority);
|
||||
gic::SetInterruptGroup(SecurityEngineInterruptId, 0);
|
||||
gic::SetEnable (SecurityEngineInterruptId, true);
|
||||
gic::SetSpiTargetCpu (SecurityEngineInterruptId, (1 << 3));
|
||||
gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level);
|
||||
constexpr u8 SecurityEngineInterruptCoreMask = (1 << 3);
|
||||
gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority);
|
||||
gic::SetInterruptGroup(SecurityEngineInterruptId, 0);
|
||||
gic::SetEnable (SecurityEngineInterruptId, true);
|
||||
gic::SetSpiTargetCpu (SecurityEngineInterruptId, SecurityEngineInterruptCoreMask);
|
||||
gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level);
|
||||
|
||||
/* Setup the activity monitor interrupt. */
|
||||
constexpr int ActivityMonitorInterruptId = 77;
|
||||
gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority);
|
||||
gic::SetInterruptGroup(ActivityMonitorInterruptId, 0);
|
||||
gic::SetEnable (ActivityMonitorInterruptId, true);
|
||||
gic::SetSpiTargetCpu (ActivityMonitorInterruptId, (1 << 3));
|
||||
gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level);
|
||||
constexpr u8 ActivityMonitorInterruptCoreMask = (1 << 3);
|
||||
gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority);
|
||||
gic::SetInterruptGroup(ActivityMonitorInterruptId, 0);
|
||||
gic::SetEnable (ActivityMonitorInterruptId, true);
|
||||
gic::SetSpiTargetCpu (ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask);
|
||||
gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level);
|
||||
|
||||
/* Setup the mariko fatal error interrupt. */
|
||||
constexpr u8 MarikoFatalInterruptCoreMask = 0b1111;
|
||||
gic::SetPriority (MarikoFatalErrorInterruptId, gic::HighestPriority);
|
||||
gic::SetInterruptGroup(MarikoFatalErrorInterruptId, 0);
|
||||
gic::SetEnable (MarikoFatalErrorInterruptId, true);
|
||||
gic::SetSpiTargetCpu (MarikoFatalErrorInterruptId, 0);
|
||||
gic::SetSpiMode (MarikoFatalErrorInterruptId, gic::InterruptMode_Level);
|
||||
|
||||
/* If we're coldboot, perform one-time setup. */
|
||||
if (g_is_cold_boot) {
|
||||
/* Register both interrupt handlers. */
|
||||
SetInterruptHandler(SecurityEngineInterruptId, se::HandleInterrupt);
|
||||
SetInterruptHandler(ActivityMonitorInterruptId, actmon::HandleInterrupt);
|
||||
/* Register all interrupt handlers. */
|
||||
SetInterruptHandler(SecurityEngineInterruptId, SecurityEngineInterruptCoreMask, se::HandleInterrupt);
|
||||
SetInterruptHandler(ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask, actmon::HandleInterrupt);
|
||||
SetInterruptHandler(MarikoFatalErrorInterruptId, MarikoFatalInterruptCoreMask, secmon::HandleMarikoFatalErrorInterrupt);
|
||||
|
||||
/* We're expecting the other cores to come out of reset. */
|
||||
for (int i = 1; i < NumCores; ++i) {
|
||||
|
@ -1145,6 +1167,9 @@ namespace ams::secmon {
|
|||
/* Disable the ARC. */
|
||||
DisableArc();
|
||||
|
||||
/* Disable untranslated memory accesses by devices. */
|
||||
DisableUntranslatedDeviceMemoryAccess();
|
||||
|
||||
/* Further protections aren't applied on <= 1.0.0. */
|
||||
if (GetTargetFirmware() <= TargetFirmware_1_0_0) {
|
||||
return;
|
||||
|
|
|
@ -201,6 +201,18 @@ namespace ams::secmon {
|
|||
if (!std::is_constant_evaluated()) { hw::InvalidateDataCacheLine(l1 + GetL1EntryIndex(start_address)); }
|
||||
}
|
||||
|
||||
void RestoreDebugCode() {
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
{
|
||||
const u64 *src = MemoryRegionPhysicalDramDebugDataStore.GetPointer<u64>();
|
||||
volatile u64 *dst = MemoryRegionPhysicalDebugCode.GetPointer<u64>();
|
||||
for (size_t i = 0; i < MemoryRegionPhysicalDramDebugDataStore.GetSize() / sizeof(u64); ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AddPhysicalTzramIdentityMapping() {
|
||||
/* Get page table extents. */
|
||||
u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer<u64>();
|
||||
|
@ -276,6 +288,7 @@ namespace ams::secmon {
|
|||
void SetupSocDmaControllersCpuMemoryControllersEnableMmuWarmboot() {
|
||||
/* If this is being called from lp0 exit, we want to setup the soc dma controllers. */
|
||||
if (IsExitLp0()) {
|
||||
RestoreDebugCode();
|
||||
SetupSocDmaControllers();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "secmon_cpu_context.hpp"
|
||||
#include "secmon_page_mapper.hpp"
|
||||
#include "secmon_mariko_fatal_error.hpp"
|
||||
#include "secmon_user_power_management.hpp"
|
||||
|
||||
#include "rebootstub_bin.h"
|
||||
|
@ -84,6 +86,19 @@ namespace ams::secmon {
|
|||
PerformPmcReboot();
|
||||
}
|
||||
|
||||
void PerformUserRebootToFatalError() {
|
||||
if (fuse::GetSocType() == fuse::SocType_Erista) {
|
||||
/* On Erista, we reboot to fatal error by jumping to fusee primary's handler. */
|
||||
return PerformUserRebootToPayload();
|
||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
||||
/* Call the fatal error handler. */
|
||||
HandleMarikoFatalErrorInterrupt();
|
||||
|
||||
/* We should never get to this point. */
|
||||
AMS_ABORT("Returned from Mariko Fatal handler?\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PerformUserShutDown() {
|
||||
/* Load our reboot stub to iram. */
|
||||
LoadRebootStub(RebootStubAction_ShutDown);
|
||||
|
|
|
@ -19,13 +19,15 @@
|
|||
namespace ams::secmon {
|
||||
|
||||
enum UserRebootType {
|
||||
UserRebootType_None = 0,
|
||||
UserRebootType_ToRcm = 1,
|
||||
UserRebootType_ToPayload = 2,
|
||||
UserRebootType_None = 0,
|
||||
UserRebootType_ToRcm = 1,
|
||||
UserRebootType_ToPayload = 2,
|
||||
UserRebootType_ToFatalError = 3,
|
||||
};
|
||||
|
||||
void PerformUserRebootToRcm();
|
||||
void PerformUserRebootToPayload();
|
||||
void PerformUserRebootToFatalError();
|
||||
void PerformUserShutDown();
|
||||
|
||||
}
|
||||
|
|
|
@ -304,11 +304,20 @@ namespace ams::secmon::smc {
|
|||
case UserRebootType_ToPayload:
|
||||
PerformUserRebootToPayload();
|
||||
break;
|
||||
case UserRebootType_ToFatalError:
|
||||
PerformUserRebootToFatalError();
|
||||
break;
|
||||
default:
|
||||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
} else /* if (soc_type == fuse::SocType_Mariko) */ {
|
||||
return SmcResult::NotImplemented;
|
||||
switch (static_cast<UserRebootType>(args.r[3])) {
|
||||
case UserRebootType_ToFatalError:
|
||||
PerformUserRebootToFatalError();
|
||||
break;
|
||||
default:
|
||||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ConfigItem::ExosphereNeedsShutdown:
|
||||
|
|
|
@ -133,7 +133,7 @@ namespace ams::secmon::smc {
|
|||
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
|
||||
}
|
||||
|
||||
void PowerOffCpu() {
|
||||
void PowerOffCpuImpl() {
|
||||
/* Get the current core id. */
|
||||
const auto core_id = hw::GetCurrentCoreId();
|
||||
|
||||
|
@ -333,12 +333,24 @@ namespace ams::secmon::smc {
|
|||
}
|
||||
|
||||
void SaveSecureContext() {
|
||||
/* Save the appropriate secure context. */
|
||||
const auto soc_type = GetSocType();
|
||||
if (soc_type == fuse::SocType_Erista) {
|
||||
SaveSecureContextForErista();
|
||||
} else /* if (soc_type == fuse::SocType_Mariko) */ {
|
||||
SaveSecureContextForMariko();
|
||||
}
|
||||
|
||||
/* Save the debug code. */
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
{
|
||||
const void * const debug_code_src = MemoryRegionVirtualDebugCode.GetPointer<void>();
|
||||
void * const debug_code_dst = MemoryRegionVirtualDramDebugDataStore.GetPointer<void>();
|
||||
std::memcpy(debug_code_dst, debug_code_src, MemoryRegionVirtualDebugCode.GetSize());
|
||||
hw::FlushDataCache(debug_code_dst, MemoryRegionVirtualDebugCode.GetSize());
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoadAndStartSc7BpmpFirmware() {
|
||||
|
@ -491,9 +503,7 @@ namespace ams::secmon::smc {
|
|||
|
||||
}
|
||||
|
||||
SmcResult SmcPowerOffCpu(SmcArguments &args) {
|
||||
AMS_UNUSED(args);
|
||||
|
||||
void PowerOffCpu() {
|
||||
/* Get the current core id. */
|
||||
const auto core_id = hw::GetCurrentCoreId();
|
||||
|
||||
|
@ -502,15 +512,21 @@ namespace ams::secmon::smc {
|
|||
|
||||
/* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */
|
||||
if (core_id == NumCores - 1) {
|
||||
PowerOffCpu();
|
||||
PowerOffCpuImpl();
|
||||
} else {
|
||||
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpu);
|
||||
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpuImpl);
|
||||
}
|
||||
|
||||
/* This code will never be reached. */
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
SmcResult SmcPowerOffCpu(SmcArguments &args) {
|
||||
AMS_UNUSED(args);
|
||||
|
||||
PowerOffCpu();
|
||||
}
|
||||
|
||||
SmcResult SmcPowerOnCpu(SmcArguments &args) {
|
||||
/* Get and validate the core to power on. */
|
||||
const int which_core = args.r[1];
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
namespace ams::secmon::smc {
|
||||
|
||||
NORETURN void PowerOffCpu();
|
||||
|
||||
SmcResult SmcPowerOffCpu(SmcArguments &args);
|
||||
SmcResult SmcPowerOnCpu(SmcArguments &args);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ def split_binary(data):
|
|||
assert D == 0xDDDDDDDDDDDDDDDD
|
||||
data = data[0x40:]
|
||||
|
||||
#print ('%X %X %X %X' % (START, BOOT_CODE_START, BOOT_CODE_END, PROGRAM_START))
|
||||
boot_code = data[BOOT_CODE_START - START:BOOT_CODE_END - BOOT_CODE_START]
|
||||
program = data[PROGRAM_START - START:]
|
||||
return [('boot_code%s.lz4', lz4_compress(boot_code)), ('program%s.lz4', lz4_compress(program))]
|
||||
|
|
|
@ -24,6 +24,7 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
|||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
BINFILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
|
|
|
@ -103,4 +103,6 @@ namespace ams::diag {
|
|||
warmboot::ExceptionHandler();
|
||||
}
|
||||
|
||||
#include <exosphere/diag/diag_detailed_assertion_impl.inc>
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue