Compare commits

...

57 Commits
0.9.2 ... 0.9.4

Author SHA1 Message Date
Michael Scire
c62c4846fc Bump version to 0.9.4. 2019-09-14 10:43:39 -07:00
Michael Scire
8db5b01507 hbl_html: enforce line ending = lf (fixes broken whitelist) 2019-09-14 10:43:39 -07:00
Michael Scire
a6e405c988 ldr: fix hbl_html redirection invocation 2019-09-14 10:43:39 -07:00
Michael Scire
6613fda4b1 ams_mitm: add temporary hid mitm on 9.x for compat 2019-09-14 10:43:39 -07:00
Michael Scire
a18a6e87df git subrepo pull emummc
subrepo:
  subdir:   "emummc"
  merged:   "5f5817e6"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "develop"
  commit:   "5f5817e6"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
2019-09-14 10:43:39 -07:00
Michael Scire
93d83c5bb9 ams: initial support for 9.0.0 2019-09-14 10:43:39 -07:00
Michael Scire
6ee8720028 boot: fix pinmux init off-by-one 2019-08-29 00:18:40 -07:00
Michael Scire
600d68bd1a ams_mitm: fix bis key generation for newer hardware 2019-08-29 00:14:23 -07:00
hexkyz
0c3a294cbe Minor information update regarding previously unknown mysteries 2019-08-22 20:52:40 +01:00
Michael Scire
25218795b4 Bump version to 0.9.3 2019-08-08 18:06:21 -07:00
Michael Scire
a65ec67128 git subrepo push stratosphere/libstratosphere
subrepo:
  subdir:   "stratosphere/libstratosphere"
  merged:   "2d081135"
upstream:
  origin:   "https://github.com/Atmosphere-NX/libstratosphere"
  branch:   "master"
  commit:   "2d081135"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
2019-08-08 17:50:09 -07:00
Michael Scire
5d753f2384 Add default system settings for hbl applet support 2019-08-08 17:45:31 -07:00
Michael Scire
1f2de35f94 fatal: use new vi enum value 2019-08-07 13:02:02 -07:00
Michael Scire
5c140b4f35 dist: include fusee-mtc in release zips. 2019-08-05 19:37:02 -07:00
Michael Scire
362ee3cdb0 autobackup: dump bis keys (closes #583). 2019-08-05 19:35:04 -07:00
Michael Scire
215f1bc8ee fatal: fix abort in viSetDisplayPowerState on < 3.0.0 2019-08-05 18:55:04 -07:00
hexkyz
4d72c2b37a fusee-primary: force displaying of fatal errors 2019-07-31 20:01:01 +01:00
hexkyz
dc4dbe29ae Move memory training code into it's own stage (fusee-mtc) 2019-07-26 20:38:15 +01:00
TuxSH
72dd25a99e Fix uart init 2019-07-24 00:52:02 +02:00
Michael Scire
39d041466d fatal: refactor into sts namespace 2019-07-23 14:01:16 -07:00
Michael Scire
442ebff829 util: fix copy/paste error in intrusive lists 2019-07-23 14:01:16 -07:00
hexkyz
7e169bc7df pm: work around HOS bug 2019-07-23 19:38:14 +01:00
hexkyz
00f4e5158f Add missing dummy reads in gpio code 2019-07-23 18:33:34 +01:00
hexkyz
0c688189f6 Fix uart pinmux configuration 2019-07-21 21:21:13 +01:00
hexkyz
7cee36544c Cleanup and re-write uart code 2019-07-21 19:18:15 +01:00
hexkyz
f9c1d5fc1b Fix GPIO/SFIO defines: cosmetic change, gpio code was working properly despite the mistake 2019-07-21 15:55:40 +01:00
Michael Scire
d95e20952c kvdb: fix iterator access issue 2019-07-18 20:34:15 -07:00
Michael Scire
32a90334bb spl: rsa service does not need a dispatch table 2019-07-17 20:58:46 -07:00
Michael Scire
f534d3498e git subrepo clone https://github.com/Atmosphere-NX/libstratosphere stratosphere/libstratosphere
subrepo:
  subdir:   "stratosphere/libstratosphere"
  merged:   "0c5dab80"
upstream:
  origin:   "https://github.com/Atmosphere-NX/libstratosphere"
  branch:   "master"
  commit:   "0c5dab80"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
2019-07-17 20:04:00 -07:00
Michael Scire
3ea9f444db Remove libstratosphere submodule 2019-07-17 20:03:48 -07:00
TuxSH
5672c935ed Update libstratosphere submodule 2019-07-16 01:26:07 +02:00
Michael Scire
4cc2b5c38a creport: address review commentary 2019-07-15 14:35:48 -07:00
Michael Scire
00e3d874e3 creport: fix dangling reference to user_result 2019-07-15 14:35:48 -07:00
Michael Scire
803e91a8c4 creport: pass user break result directly 2019-07-15 14:35:48 -07:00
Michael Scire
227a1d938d creport: refactor to use sts:: namespace. 2019-07-15 14:35:48 -07:00
Michael Scire
fc7f06dc78 pm/sm: add ability to forward declare mitm'd services (closes #557) 2019-07-11 22:24:59 -07:00
Michael Scire
6777dd9b38 pm: inform sm of title ids. remove inconsistent mitm association. 2019-07-11 22:24:59 -07:00
Michael Scire
4db212ea7b pm: actually use the flag detection code in libstratosphere 2019-07-11 22:24:59 -07:00
Michael Scire
8177a27db9 pm: fix boot2 launch logic error 2019-07-11 22:24:59 -07:00
Michael Scire
27ff119ba6 pm: fix minor resource manager bugs 2019-07-11 22:24:59 -07:00
Michael Scire
c20774ff5d pm: fix missing flag clears 2019-07-11 22:24:59 -07:00
Michael Scire
a9f5b7728b pm: address review comments. 2019-07-11 22:24:59 -07:00
Michael Scire
08ad48fbf3 pm: implement correct application thread boosting mechanism 2019-07-11 22:24:59 -07:00
Michael Scire
2d0c881ffe strat: go all in on ncm::TitleId 2019-07-11 22:24:59 -07:00
Michael Scire
c916a7db88 strat: remove sizeof() / sizeof([0]) 2019-07-11 22:24:59 -07:00
Michael Scire
a5da286351 fix dumb mistake 2019-07-11 22:24:59 -07:00
Michael Scire
20a48c3a26 pm: complete rewrite 2019-07-11 22:24:59 -07:00
hexkyz
5bba0f47ff Merge pull request #625 from suppai/master
Fix compilation with latest libnx master
2019-07-08 16:56:54 +01:00
suppai
bfc987abcd Fix for libnx commit 4f441a4/latest master at time of writing 2019-07-07 23:56:21 -04:00
hexkyz
85bf7c86e0 fusee: cleanup and optimize boot sequence 2019-07-06 20:58:01 +01:00
Michael Scire
2225b86eea Adjust version string based on ReSwitched vote. 2019-07-02 11:49:24 -07:00
hexkyz
d09be18359 Fix argument type for isalnum and toupper 2019-07-02 17:22:28 +01:00
hexkyz
09ab3efddd Fix argument type for isspace 2019-07-01 20:29:43 +01:00
hexkyz
382a0192f9 Fix spacing in diskio 2019-07-01 20:20:34 +01:00
hexkyz
e3b968fa80 Update FatFs to R0.13c 2019-07-01 20:12:30 +01:00
Connor
6f85b11fcc Fix for 4.X units (new strato rework broke a method in spl) (#616)
* Fix for 4.X units (new strato rework broke a method in spl)

* Fixed formatting in spl
2019-07-01 03:53:46 -07:00
hexkyz
e561919a52 Fix logic in ldr_ro_manager
Fix argument type for isdigit/isxdigit
2019-06-30 18:48:16 +01:00
460 changed files with 117909 additions and 76930 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
common/defaults/hbl_html/accessible-urls/accessible-urls.txt text eol=lf

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "common/include/boost"] [submodule "common/include/boost"]
path = common/include/boost path = common/include/boost
url = https://github.com/Atmosphere-NX/ext-boost.git url = https://github.com/Atmosphere-NX/ext-boost.git
[submodule "stratosphere/libstratosphere"]
path = stratosphere/libstratosphere
url = https://github.com/Atmosphere-NX/libstratosphere.git

View File

@@ -57,6 +57,7 @@ dist: all
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
cp fusee/fusee-mtc/fusee-mtc.bin atmosphere-$(AMSVER)/atmosphere/fusee-mtc.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin

View File

@@ -1,6 +1,7 @@
BCT0 BCT0
[stage1] [stage1]
stage2_path = atmosphere/fusee-secondary.bin stage2_path = atmosphere/fusee-secondary.bin
stage2_mtc_path = atmosphere/fusee-mtc.bin
stage2_addr = 0xF0000000 stage2_addr = 0xF0000000
stage2_entrypoint = 0xF0000000 stage2_entrypoint = 0xF0000000

View File

@@ -29,3 +29,12 @@ dmnt_always_save_cheat_toggles = u8!0x0
; NOTE: EXPERIMENTAL ; NOTE: EXPERIMENTAL
; If you do not know what you are doing, do not touch this yet. ; If you do not know what you are doing, do not touch this yet.
fsmitm_redirect_saves_to_sd = u8!0x0 fsmitm_redirect_saves_to_sd = u8!0x0
[hbloader]
; Controls the size of the homebrew heap when running as applet.
; If set to zero, all available applet memory is used as heap.
; The default is zero.
applet_heap_size = u64!0x0
; Controls the amount of memory to reserve when running as applet
; for usage by other applets. This setting has no effect if
; applet_heap_size is non-zero. The default is zero.
applet_heap_reservation_size = u64!0x8000000

View File

@@ -27,11 +27,12 @@
#define ATMOSPHERE_TARGET_FIRMWARE_700 8 #define ATMOSPHERE_TARGET_FIRMWARE_700 8
#define ATMOSPHERE_TARGET_FIRMWARE_800 9 #define ATMOSPHERE_TARGET_FIRMWARE_800 9
#define ATMOSPHERE_TARGET_FIRMWARE_810 10 #define ATMOSPHERE_TARGET_FIRMWARE_810 10
#define ATMOSPHERE_TARGET_FIRMWARE_900 11
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_810 #define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_900
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100 #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_810 #define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_900
/* TODO: What should this be, for release? */ /* TODO: What should this be, for release? */
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT #define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT

View File

@@ -19,10 +19,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0 #define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 9 #define ATMOSPHERE_RELEASE_VERSION_MINOR 9
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2 #define ATMOSPHERE_RELEASE_VERSION_MICRO 4
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 9
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
#endif #endif

View File

@@ -1,4 +1,46 @@
# Changelog # Changelog
## 0.9.4
+ Support was added for 9.0.0.
+ **Please note**: 9.0.0 made a number of changes that may cause some issues with homebrew. Details:
+ 9.0.0 changed HID in a way that causes libnx to be unable to detect button input.
+ Homebrew should be recompiled with newest libnx to fix this.
+ Atmosphere now provides a temporary hid-mitm that will cause homebrew to continue to work as expected.
+ This mitm will be removed in a future Atmosphere revision once homebrew has been updated, to allow users to use a custom hid mitm again if they desire.
+ 9.0.0 introduced an dependency in FS on the USB system module in order to launch the SD card.
+ This means the USB system module must now be launched before the SD card is initialized.
+ Correspondingly, the USB system module can no longer be IPS patched, and its settings cannot be reliably mitm'd.
+ We know this is frustrating, so we'll be looking into whether there is some way of addressing this in the future.
+ An off-by-one error was fixed in `boot` system module's pinmux initialization.
+ This could theoretically have caused issues with HdmiCec communication.
+ No users reported issues, so it's unclear if this was a problem in practice.
+ A bug was fixed that could cause webapplet launching homebrew to improperly set the accessible url whitelist.
+ BIS key generation has been fixed for newer hardware.
+ Newer hardware uses new, per-firmware device key to generate BIS keys instead of the first device key, so previously the wrong keys were generated as backup.
+ This only affects units manufactured after ~5.0.0.
+ General system stability improvements to enhance the user's experience.
## 0.9.3
+ Thanks to hexkyz, fusee's boot sequence has been greatly optimized.
+ Memory training is now managed by a separate binary (`fusee-mtc`, loaded by fusee-primary before fusee-secondary).
+ Unnecessarily long splash screen display times were reduced.
+ The end result is that Atmosphere now boots *significantly* faster. :)
+ **Note:** This means fusee-primary must be updated for Atmosphere to boot successfully.
+ The version string was adjusted, and now informs users whether or not they are using emummc.
+ Atmosphere now automatically backs up the user's BIS keys on boot.
+ This should prevent a user from corrupting nand without access to a copy of the keys needed to fix it.
+ This is especially relevant on ipatched units, where the RCM vulnerability is not an option for addressing bricks.
+ The `pm` system module was rewritten as part of Stratosphere's ongoing refactor.
+ Support was added for forward-declaring a mitm'd service before a custom user sysmodule is launched.
+ This should help resolve dependency issues with service registration times.
+ SM is now informed of every process's title id, including built-in system modules.
+ The `creport` system module was rewritten as part of Stratosphere's ongoing refactor.
+ creport now dumps up to 0x100 of stack from each thread in the target process.
+ A few bugs were fixed, including one that caused creport to incorrectly dump process dying messages.
+ Defaults were added to `system_settings.ini` for controlling hbloader's memory usage in applet mode.
+ These defaults reserve enough memory so that homebrew can launch swkbd while in applet mode.
+ The `fatal` system module was rewritten as part of Stratosphere's ongoing refactor.
+ Incorrect display output ("2000-0000") has been fixed. Fatal will now correctly show 2162-0002 when this occurs.
+ A longstanding bug in how fatal manages the displays has been fixed, and official display init behavior is now matched precisely.
+ General system stability improvements to enhance the user's experience.
## 0.9.2 ## 0.9.2
+ A number of emummc bugfixes were added (all thanks to @m4xw's hard work). The following is a summary of emummc changes: + A number of emummc bugfixes were added (all thanks to @m4xw's hard work). The following is a summary of emummc changes:
+ Support for file-based emummc instances was fixed. + Support for file-based emummc instances was fixed.

View File

@@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/m4xw/emuMMC remote = https://github.com/m4xw/emuMMC
branch = develop branch = develop
commit = 5f51fa3b81d2b14b348f6e8579454007019fc7a6 commit = 5f5817e646d4c800ae4bd6db4a57eee6bde62eed
parent = e871a754a87631c3036ca985ff1c223e00ef4dda parent = 68091a28a23836032c98396259f7ee4796b312f9
method = rebase method = rebase
cmdver = 0.4.0 cmdver = 0.4.0

View File

@@ -2,7 +2,7 @@
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw*** *A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
### Supported Horizon Versions ### Supported Horizon Versions
**1.0.0 - 8.1.0** **1.0.0 - 9.0.0**
## Features ## Features
* Arbitrary SDMMC backend selection * Arbitrary SDMMC backend selection

View File

@@ -41,6 +41,8 @@
#include "offsets/800_exfat.h" #include "offsets/800_exfat.h"
#include "offsets/810.h" #include "offsets/810.h"
#include "offsets/810_exfat.h" #include "offsets/810_exfat.h"
#include "offsets/900.h"
#include "offsets/900_exfat.h"
#include "../utils/fatal.h" #include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers #define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -92,6 +94,8 @@ DEFINE_OFFSET_STRUCT(_800);
DEFINE_OFFSET_STRUCT(_800_EXFAT); DEFINE_OFFSET_STRUCT(_800_EXFAT);
DEFINE_OFFSET_STRUCT(_810); DEFINE_OFFSET_STRUCT(_810);
DEFINE_OFFSET_STRUCT(_810_EXFAT); DEFINE_OFFSET_STRUCT(_810_EXFAT);
DEFINE_OFFSET_STRUCT(_900);
DEFINE_OFFSET_STRUCT(_900_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) { const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) { switch (version) {
@@ -145,6 +149,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_810)); return &(GET_OFFSET_STRUCT_NAME(_810));
case FS_VER_8_1_0_EXFAT: case FS_VER_8_1_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT)); return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT));
case FS_VER_9_0_0:
return &(GET_OFFSET_STRUCT_NAME(_900));
case FS_VER_9_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_900_EXFAT));
default: default:
fatal_abort(Fatal_UnknownVersion); fatal_abort(Fatal_UnknownVersion);
} }

View File

@@ -59,6 +59,9 @@ enum FS_VER
FS_VER_8_1_0, FS_VER_8_1_0,
FS_VER_8_1_0_EXFAT, FS_VER_8_1_0_EXFAT,
FS_VER_9_0_0,
FS_VER_9_0_0_EXFAT,
FS_VER_MAX, FS_VER_MAX,
}; };

View File

@@ -0,0 +1,59 @@
/*
* 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_900_H__
#define __FS_900_H__
// Accessor vtable getters
#define FS_OFFSET_900_SDMMC_ACCESSOR_GC 0x1430F0
#define FS_OFFSET_900_SDMMC_ACCESSOR_SD 0x141200
#define FS_OFFSET_900_SDMMC_ACCESSOR_NAND 0x13C080
// Hooks
#define FS_OFFSET_900_SDMMC_WRAPPER_READ 0x1377E0
#define FS_OFFSET_900_SDMMC_WRAPPER_WRITE 0x1378C0
#define FS_OFFSET_900_RTLD 0x454
#define FS_OFFSET_900_RTLD_DESTINATION 0x9C
#define FS_OFFSET_900_CLKRST_SET_MIN_V_CLK_RATE 0x136A00
// Misc funcs
#define FS_OFFSET_900_LOCK_MUTEX 0x25280
#define FS_OFFSET_900_UNLOCK_MUTEX 0x252D0
#define FS_OFFSET_900_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x137740
// Misc Data
#define FS_OFFSET_900_SD_MUTEX 0xE1D3E8
#define FS_OFFSET_900_NAND_MUTEX 0xE18258
#define FS_OFFSET_900_ACTIVE_PARTITION 0xE18298
#define FS_OFFSET_900_SDMMC_DAS_HANDLE 0xDFEFA0
// NOPs
#define FS_OFFSET_900_SD_DAS_INIT 0x1472BC
// Nintendo Paths
#define FS_OFFSET_900_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x00068A60, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00070A40, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00081CB4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00081EF4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008211C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_900_H__

View File

@@ -0,0 +1,59 @@
/*
* 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_900_EXFAT_H__
#define __FS_900_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_900_EXFAT_SDMMC_ACCESSOR_GC 0x1430F0
#define FS_OFFSET_900_EXFAT_SDMMC_ACCESSOR_SD 0x141200
#define FS_OFFSET_900_EXFAT_SDMMC_ACCESSOR_NAND 0x13C080
// Hooks
#define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_READ 0x1377E0
#define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_WRITE 0x1378C0
#define FS_OFFSET_900_EXFAT_RTLD 0x454
#define FS_OFFSET_900_EXFAT_RTLD_DESTINATION 0x9C
#define FS_OFFSET_900_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x136A00
// Misc funcs
#define FS_OFFSET_900_EXFAT_LOCK_MUTEX 0x25280
#define FS_OFFSET_900_EXFAT_UNLOCK_MUTEX 0x252D0
#define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x137740
// Misc Data
#define FS_OFFSET_900_EXFAT_SD_MUTEX 0xE2B3E8
#define FS_OFFSET_900_EXFAT_NAND_MUTEX 0xE26258
#define FS_OFFSET_900_EXFAT_ACTIVE_PARTITION 0xE26298
#define FS_OFFSET_900_EXFAT_SDMMC_DAS_HANDLE 0xE0CFA0
// NOPs
#define FS_OFFSET_900_EXFAT_SD_DAS_INIT 0x1472BC
// Nintendo Paths
#define FS_OFFSET_900_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x00068A60, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00070A40, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00081CB4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00081EF4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008211C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_900_EXFAT_H__

View File

@@ -15,13 +15,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "fatal.h" #include "fatal.h"
void __attribute__((noreturn)) fatal_abort(enum FatalReason abortReason) void __attribute__((noreturn)) fatal_abort(enum FatalReason abortReason)
{ {
atmosphere_fatal_error_ctx error_ctx;
memset(&error_ctx, 0, sizeof(atmosphere_fatal_error_ctx));
// Basic error storage for Atmosphere
// TODO: Maybe include a small reboot2payload stub?
error_ctx.magic = ATMOSPHERE_REBOOT_TO_FATAL_MAGIC;
error_ctx.title_id = 0x0100000000000000; // FS
error_ctx.error_desc = abortReason;
// Copy fatal context
smcCopyToIram(ATMOSPHERE_FATAL_ERROR_ADDR, &error_ctx, sizeof(atmosphere_fatal_error_ctx));
// Reboot to RCM // Reboot to RCM
smcRebootToRcm(); smcRebootToRcm();
while(true) while (true)
; // Should never be reached ; // Should never be reached
} }

View File

@@ -18,7 +18,8 @@
#pragma once #pragma once
#include "../nx/smc.h" #include "../nx/smc.h"
enum FatalReason { enum FatalReason
{
Fatal_InitMMC = 0, Fatal_InitMMC = 0,
Fatal_InitSD, Fatal_InitSD,
Fatal_InvalidAccessor, Fatal_InvalidAccessor,
@@ -32,4 +33,45 @@ enum FatalReason {
Fatal_Max Fatal_Max
}; };
#define AMS_FATAL_ERROR_MAX_STACKTRACE 0x20
#define AMS_FATAL_ERROR_MAX_STACKDUMP 0x100
/* Atmosphere reboot-to-fatal-error. */
typedef struct
{
uint32_t magic;
uint32_t error_desc;
uint64_t title_id;
union {
uint64_t gprs[32];
struct
{
uint64_t _gprs[29];
uint64_t fp;
uint64_t lr;
uint64_t sp;
};
};
uint64_t pc;
uint64_t module_base;
uint32_t pstate;
uint32_t afsr0;
uint32_t afsr1;
uint32_t esr;
uint64_t far;
uint64_t report_identifier; /* Normally just system tick. */
uint64_t stack_trace_size;
uint64_t stack_dump_size;
uint64_t stack_trace[AMS_FATAL_ERROR_MAX_STACKTRACE];
uint8_t stack_dump[AMS_FATAL_ERROR_MAX_STACKDUMP];
} atmosphere_fatal_error_ctx;
/* "AFE1" */
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC 0x31454641
/* "AFE0" */
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0 0x30454641
#define ATMOSPHERE_FATAL_ERROR_ADDR 0x4003E000
#define ATMOSPHERE_FATAL_ERROR_CONTEXT ((volatile atmosphere_fatal_error_ctx *)(ATMOSPHERE_FATAL_ERROR_ADDR))
void __attribute__((noreturn)) fatal_abort(enum FatalReason abortReason); void __attribute__((noreturn)) fatal_abort(enum FatalReason abortReason);

View File

@@ -79,7 +79,7 @@ typedef enum {
CARDEVICE_UARTC = ((1 << 5) | 0x17), CARDEVICE_UARTC = ((1 << 5) | 0x17),
CARDEVICE_I2C1 = ((0 << 5) | 0xC), CARDEVICE_I2C1 = ((0 << 5) | 0xC),
CARDEVICE_I2C5 = ((1 << 5) | 0xF), CARDEVICE_I2C5 = ((1 << 5) | 0xF),
CARDEVICE_UNK = ((3 << 5) | 0x1E), CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
CARDEVICE_SE = ((3 << 5) | 0x1F), CARDEVICE_SE = ((3 << 5) | 0x1F),
CARDEVICE_HOST1X = ((0 << 5) | 0x1C), CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
CARDEVICE_TSEC = ((2 << 5) | 0x13), CARDEVICE_TSEC = ((2 << 5) | 0x13),

View File

@@ -35,6 +35,14 @@
#define MC_SMMU_PTB_DATA 0x20 #define MC_SMMU_PTB_DATA 0x20
#define MC_SMMU_TLB_FLUSH 0x30 #define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34 #define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_ASID_SECURITY_1 0x3c
#define MC_SMMU_ASID_SECURITY_2 0x9e0
#define MC_SMMU_ASID_SECURITY_3 0x9e4
#define MC_SMMU_ASID_SECURITY_4 0x9e8
#define MC_SMMU_ASID_SECURITY_5 0x9ec
#define MC_SMMU_ASID_SECURITY_6 0x9f0
#define MC_SMMU_ASID_SECURITY_7 0x9f4
#define MC_SMMU_AFI_ASID 0x238 #define MC_SMMU_AFI_ASID 0x238
#define MC_SMMU_AVPC_ASID 0x23c #define MC_SMMU_AVPC_ASID 0x23c
#define MC_SMMU_PPCS1_ASID 0x298 #define MC_SMMU_PPCS1_ASID 0x298

View File

@@ -85,6 +85,9 @@ void bootup_misc_mmio(void) {
setup_dram_magic_numbers(); setup_dram_magic_numbers();
} }
/* On 9.0.0+, Nintendo writes random values to context save scratch here, and locks the SRK scratch. */
/* There's no real need for us to do this, so we won't. */
/* Mark TMR5, TMR6, TMR7, TMR8, WDT0, WDT1, WDT2 and WDT3 as secure. */ /* Mark TMR5, TMR6, TMR7, TMR8, WDT0, WDT1, WDT2 and WDT3 as secure. */
SHARED_TIMER_SECURE_CFG_0 = 0xF1E0; SHARED_TIMER_SECURE_CFG_0 = 0xF1E0;
@@ -140,28 +143,26 @@ void bootup_misc_mmio(void) {
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = sec_disable_2; APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = sec_disable_2;
} }
/* Reset Translation Enable Registers. */ /* Reset Translation Enable registers. */
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_0) = 0xFFFFFFFF; MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_0) = 0xFFFFFFFF;
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_1) = 0xFFFFFFFF; MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_1) = 0xFFFFFFFF;
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_2) = 0xFFFFFFFF; MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_2) = 0xFFFFFFFF;
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_3) = 0xFFFFFFFF; MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_3) = 0xFFFFFFFF;
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_4) = 0xFFFFFFFF; MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_4) = 0xFFFFFFFF;
/* TODO: What are these MC reg writes? */ /* Set SMMU ASID security registers. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
MAKE_MC_REG(0x038) = 0xE; MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0xE;
} else { } else {
MAKE_MC_REG(0x038) = 0x0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0x0;
} }
MAKE_MC_REG(0x03C) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_1) = 0;
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_2) = 0;
/* MISC registers. */ MAKE_MC_REG(MC_SMMU_ASID_SECURITY_3) = 0;
MAKE_MC_REG(0x9E0) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_4) = 0;
MAKE_MC_REG(0x9E4) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_5) = 0;
MAKE_MC_REG(0x9E8) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_6) = 0;
MAKE_MC_REG(0x9EC) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_7) = 0;
MAKE_MC_REG(0x9F0) = 0;
MAKE_MC_REG(0x9F4) = 0;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
MAKE_MC_REG(MC_SMMU_PTB_ASID) = 0; MAKE_MC_REG(MC_SMMU_PTB_ASID) = 0;
@@ -215,7 +216,7 @@ void bootup_misc_mmio(void) {
if (!g_has_booted_up) { if (!g_has_booted_up) {
/* N doesn't do this, but we should for compatibility. */ /* N doesn't do this, but we should for compatibility. */
uart_select(UART_A); uart_config(UART_A);
clkrst_reboot(CARDEVICE_UARTA); clkrst_reboot(CARDEVICE_UARTA);
uart_init(UART_A, 115200); uart_init(UART_A, 115200);

View File

@@ -14,25 +14,56 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "i2c.h" #include "i2c.h"
#include "utils.h" #include "utils.h"
#include "timers.h" #include "timers.h"
#include "pinmux.h"
/* Prototypes for internal commands. */ /* Prototypes for internal commands. */
volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id); volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id);
void i2c_load_config(volatile i2c_registers_t *regs); void i2c_load_config(volatile tegra_i2c_t *regs);
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size);
bool i2c_read(volatile i2c_registers_t *regs, uint8_t device, void *dst, size_t dst_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size);
/* Configure I2C pinmux. */
void i2c_config(I2CDevice id) {
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
switch (id) {
case I2C_1:
pinmux->gen1_i2c_scl = PINMUX_INPUT;
pinmux->gen1_i2c_sda = PINMUX_INPUT;
break;
case I2C_2:
pinmux->gen2_i2c_scl = PINMUX_INPUT;
pinmux->gen2_i2c_sda = PINMUX_INPUT;
break;
case I2C_3:
pinmux->gen3_i2c_scl = PINMUX_INPUT;
pinmux->gen3_i2c_sda = PINMUX_INPUT;
break;
case I2C_4:
pinmux->cam_i2c_scl = PINMUX_INPUT;
pinmux->cam_i2c_sda = PINMUX_INPUT;
break;
case I2C_5:
pinmux->pwr_i2c_scl = PINMUX_INPUT;
pinmux->pwr_i2c_sda = PINMUX_INPUT;
break;
case I2C_6:
/* Unused. */
break;
default: break;
}
}
/* Initialize I2C based on registers. */ /* Initialize I2C based on registers. */
void i2c_init(unsigned int id) { void i2c_init(I2CDevice id) {
volatile i2c_registers_t *regs = i2c_get_registers_from_id(id); volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
/* Setup divisor, and clear the bus. */ /* Setup divisor, and clear the bus. */
regs->I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001; regs->I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001;
@@ -43,7 +74,7 @@ void i2c_init(unsigned int id) {
/* Wait a while until BUS_CLEAR_DONE is set. */ /* Wait a while until BUS_CLEAR_DONE is set. */
for (unsigned int i = 0; i < 10; i++) { for (unsigned int i = 0; i < 10; i++) {
wait(20000); wait(25);
if (regs->I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) { if (regs->I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) {
break; break;
} }
@@ -61,16 +92,16 @@ void i2c_init(unsigned int id) {
void i2c_send_pmic_cpu_shutdown_cmd(void) { void i2c_send_pmic_cpu_shutdown_cmd(void) {
uint32_t val = 0; uint32_t val = 0;
/* PMIC == Device 4:3C. */ /* PMIC == Device 4:3C. */
i2c_query(4, 0x3C, 0x41, &val, 1); i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1);
val |= 4; val |= 4;
i2c_send(4, 0x3C, 0x41, &val, 1); i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1);
} }
/* Queries the value of TI charger bit over I2C. */ /* Queries the value of TI charger bit over I2C. */
bool i2c_query_ti_charger_bit_7(void) { bool i2c_query_ti_charger_bit_7(void) {
uint32_t val = 0; uint32_t val = 0;
/* TI Charger = Device 0:6B. */ /* TI Charger = Device 0:6B. */
i2c_query(0, 0x6B, 0, &val, 1); i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
return (val & 0x80) != 0; return (val & 0x80) != 0;
} }
@@ -78,34 +109,34 @@ bool i2c_query_ti_charger_bit_7(void) {
void i2c_clear_ti_charger_bit_7(void) { void i2c_clear_ti_charger_bit_7(void) {
uint32_t val = 0; uint32_t val = 0;
/* TI Charger = Device 0:6B. */ /* TI Charger = Device 0:6B. */
i2c_query(0, 0x6B, 0, &val, 1); i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
val &= 0x7F; val &= 0x7F;
i2c_send(0, 0x6B, 0, &val, 1); i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
} }
/* Sets TI charger bit over I2C. */ /* Sets TI charger bit over I2C. */
void i2c_set_ti_charger_bit_7(void) { void i2c_set_ti_charger_bit_7(void) {
uint32_t val = 0; uint32_t val = 0;
/* TI Charger = Device 0:6B. */ /* TI Charger = Device 0:6B. */
i2c_query(0, 0x6B, 0, &val, 1); i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
val |= 0x80; val |= 0x80;
i2c_send(0, 0x6B, 0, &val, 1); i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
} }
/* Get registers pointer based on I2C ID. */ /* Get registers pointer based on I2C ID. */
volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id) { volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) {
switch (id) { switch (id) {
case 0: case I2C_1:
return I2C1_REGS; return I2C1_REGS;
case 1: case I2C_2:
return I2C2_REGS; return I2C2_REGS;
case 2: case I2C_3:
return I2C3_REGS; return I2C3_REGS;
case 3: case I2C_4:
return I2C4_REGS; return I2C4_REGS;
case 4: case I2C_5:
return I2C5_REGS; return I2C5_REGS;
case 5: case I2C_6:
return I2C6_REGS; return I2C6_REGS;
default: default:
generic_panic(); generic_panic();
@@ -114,7 +145,7 @@ volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id) {
} }
/* Load hardware config for I2C4. */ /* Load hardware config for I2C4. */
void i2c_load_config(volatile i2c_registers_t *regs) { void i2c_load_config(volatile tegra_i2c_t *regs) {
/* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */ /* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */
regs->I2C_I2C_CONFIG_LOAD_0 = 0x25; regs->I2C_I2C_CONFIG_LOAD_0 = 0x25;
@@ -128,8 +159,8 @@ void i2c_load_config(volatile i2c_registers_t *regs) {
} }
/* Reads a register from a device over I2C, writes result to output. */ /* Reads a register from a device over I2C, writes result to output. */
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) {
volatile i2c_registers_t *regs = i2c_get_registers_from_id(id); volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
uint32_t val = r; uint32_t val = r;
/* Write single byte register ID to device. */ /* Write single byte register ID to device. */
@@ -145,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst
} }
/* Writes a value to a register over I2C. */ /* Writes a value to a register over I2C. */
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) {
uint32_t val = r; uint32_t val = r;
if (src_size == 0) { if (src_size == 0) {
return true; return true;
@@ -158,7 +189,7 @@ bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_
} }
/* Writes bytes to device over I2C. */ /* Writes bytes to device over I2C. */
bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t src_size) { bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size) {
if (src_size > 4) { if (src_size > 4) {
return false; return false;
} else if (src_size == 0) { } else if (src_size == 0) {
@@ -177,8 +208,7 @@ bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t
i2c_load_config(regs); i2c_load_config(regs);
/* Config |= SEND; */ /* Config |= SEND; */
regs->I2C_I2C_CNFG_0 |= 0x200; regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
while (regs->I2C_I2C_STATUS_0 & 0x100) { while (regs->I2C_I2C_STATUS_0 & 0x100) {
/* Wait until not busy. */ /* Wait until not busy. */
@@ -189,7 +219,7 @@ bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t
} }
/* Reads bytes from device over I2C. */ /* Reads bytes from device over I2C. */
bool i2c_read(volatile i2c_registers_t *regs, uint8_t device, void *dst, size_t dst_size) { bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size) {
if (dst_size > 4) { if (dst_size > 4) {
return false; return false;
} else if (dst_size == 0) { } else if (dst_size == 0) {
@@ -205,8 +235,7 @@ bool i2c_read(volatile i2c_registers_t *regs, uint8_t device, void *dst, size_t
i2c_load_config(regs); i2c_load_config(regs);
/* Config |= SEND; */ /* Config |= SEND; */
regs->I2C_I2C_CNFG_0 |= 0x200; regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
while (regs->I2C_I2C_STATUS_0 & 0x100) { while (regs->I2C_I2C_STATUS_0 & 0x100) {
/* Wait until not busy. */ /* Wait until not busy. */

View File

@@ -19,10 +19,27 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "memory_map.h" #include "memory_map.h"
/* Exosphere driver for the Tegra X1 I2C registers. */ /* Exosphere driver for the Tegra X1 I2C registers. */
#define MAX77621_CPU_I2C_ADDR 0x1B
#define MAX77621_GPU_I2C_ADDR 0x1C
#define MAX17050_I2C_ADDR 0x36
#define MAX77620_PWR_I2C_ADDR 0x3C
#define MAX77620_RTC_I2C_ADDR 0x68
#define BQ24193_I2C_ADDR 0x6B
typedef enum {
I2C_1 = 0,
I2C_2 = 1,
I2C_3 = 2,
I2C_4 = 3,
I2C_5 = 4,
I2C_6 = 5,
} I2CDevice;
typedef struct { typedef struct {
uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CNFG_0;
uint32_t I2C_I2C_CMD_ADDR0_0; uint32_t I2C_I2C_CMD_ADDR0_0;
@@ -65,7 +82,7 @@ typedef struct {
uint32_t I2C_I2C_INTERFACE_TIMING_1_0; uint32_t I2C_I2C_INTERFACE_TIMING_1_0;
uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0; uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0;
uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0; uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0;
} i2c_registers_t; } tegra_i2c_t;
static inline uintptr_t get_i2c_dtv_234_base(void) { static inline uintptr_t get_i2c_dtv_234_base(void) {
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DTV_I2C234); return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DTV_I2C234);
@@ -75,17 +92,20 @@ static inline uintptr_t get_i2c56_spi2b_base(void) {
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_I2C56_SPI2B); return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_I2C56_SPI2B);
} }
#define I2C1_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x000)) #define I2C1_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x000))
#define I2C2_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x400)) #define I2C2_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x400))
#define I2C3_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x500)) #define I2C3_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x500))
#define I2C4_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x700)) #define I2C4_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x700))
#define I2C5_REGS ((volatile i2c_registers_t *)(get_i2c56_spi2b_base() + 0x000)) #define I2C5_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x000))
#define I2C6_REGS ((volatile i2c_registers_t *)(get_i2c56_spi2b_base() + 0x100)) #define I2C6_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x100))
void i2c_init(unsigned int id); void i2c_config(I2CDevice id);
void i2c_init(I2CDevice id);
bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
void i2c_send_pmic_cpu_shutdown_cmd(void); void i2c_send_pmic_cpu_shutdown_cmd(void);
bool i2c_query_ti_charger_bit_7(void); bool i2c_query_ti_charger_bit_7(void);
void i2c_clear_ti_charger_bit_7(void); void i2c_clear_ti_charger_bit_7(void);
void i2c_set_ti_charger_bit_7(void); void i2c_set_ti_charger_bit_7(void);

View File

@@ -43,6 +43,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */ {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. */ {0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 08 encrypted with Master key 09. */
}; };
/* Retail unit keys. */ /* Retail unit keys. */
@@ -57,6 +58,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */ {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. */ {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. */ {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. */
}; };
bool check_mkey_revision(unsigned int revision, bool is_retail) { bool check_mkey_revision(unsigned int revision, bool is_retail) {

View File

@@ -19,8 +19,8 @@
/* This is glue code to enable master key support across versions. */ /* This is glue code to enable master key support across versions. */
/* TODO: Update to 0xA on release of new master key. */ /* TODO: Update to 0xB on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x9 #define MASTERKEY_REVISION_MAX 0xA
#define MASTERKEY_REVISION_100_230 0x00 #define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01 #define MASTERKEY_REVISION_300 0x01
@@ -29,8 +29,9 @@
#define MASTERKEY_REVISION_500_510 0x04 #define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_610 0x05 #define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620 0x06 #define MASTERKEY_REVISION_620 0x06
#define MASTERKEY_REVISION_700_800 0x07 #define MASTERKEY_REVISION_700_800 0x07
#define MASTERKEY_REVISION_810_CURRENT 0x08 #define MASTERKEY_REVISION_810 0x08
#define MASTERKEY_REVISION_900_CURRENT 0x09
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410) #define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)

View File

@@ -40,6 +40,14 @@ static inline uintptr_t get_mc_base(void) {
#define MC_SMMU_PTB_DATA 0x20 #define MC_SMMU_PTB_DATA 0x20
#define MC_SMMU_TLB_FLUSH 0x30 #define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34 #define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_ASID_SECURITY_1 0x3c
#define MC_SMMU_ASID_SECURITY_2 0x9e0
#define MC_SMMU_ASID_SECURITY_3 0x9e4
#define MC_SMMU_ASID_SECURITY_4 0x9e8
#define MC_SMMU_ASID_SECURITY_5 0x9ec
#define MC_SMMU_ASID_SECURITY_6 0x9f0
#define MC_SMMU_ASID_SECURITY_7 0x9f4
#define MC_SMMU_AFI_ASID 0x238 #define MC_SMMU_AFI_ASID 0x238
#define MC_SMMU_AVPC_ASID 0x23c #define MC_SMMU_AVPC_ASID 0x23c
#define MC_SMMU_PPCS1_ASID 0x298 #define MC_SMMU_PPCS1_ASID 0x298

View File

@@ -18,26 +18,15 @@
#define EXOSPHERE_MISC_H #define EXOSPHERE_MISC_H
#include <stdint.h> #include <stdint.h>
#include "memory_map.h" #include "memory_map.h"
/* Exosphere driver for the Tegra X1 MISC Registers. */ /* Exosphere driver for the Tegra X1 MISC Registers. */
#define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC)) #define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC))
#define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n) #define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n)
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00)
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04)
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08)
#define PINMUX_AUX_GEN1_I2C_SCL_0 MAKE_MISC_REG(0x30BC)
#define PINMUX_AUX_GEN1_I2C_SDA_0 MAKE_MISC_REG(0x30C0)
#define PINMUX_AUX_UARTn_TX_0(n) MAKE_MISC_REG(0x30E4 + 0x10 * (n))
#define PINMUX_AUX_UARTn_RX_0(n) MAKE_MISC_REG(0x30E8 + 0x10 * (n))
#define PINMUX_AUX_UARTn_RTS_0(n) MAKE_MISC_REG(0x30EC + 0x10 * (n))
#define PINMUX_AUX_UARTn_CTS_0(n) MAKE_MISC_REG(0x30F0 + 0x10 * (n))
#endif #endif

View File

@@ -43,7 +43,8 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10]
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
}; };
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@@ -52,7 +53,8 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ {0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */
}; };
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@@ -61,7 +63,8 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */ {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */ {0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */ {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ {0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */
}; };
static void derive_new_device_keys(unsigned int keygen_keyslot) { static void derive_new_device_keys(unsigned int keygen_keyslot) {
@@ -141,6 +144,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800: case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY); derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break; break;
} }
@@ -330,7 +334,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */ /* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */ /* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) { if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_900_CURRENT) {
return true; return true;
} }
@@ -456,6 +460,7 @@ static void copy_warmboot_bin_to_dram() {
case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800: case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
warmboot_src = (uint8_t *)0x4003E000; warmboot_src = (uint8_t *)0x4003E000;
break; break;
} }
@@ -532,6 +537,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
MAKE_REG32(PMC_BASE + 0x360) = 0x14A; MAKE_REG32(PMC_BASE + 0x360) = 0x14A;
break; break;
case ATMOSPHERE_TARGET_FIRMWARE_900:
MAKE_REG32(PMC_BASE + 0x360) = 0x16B;
break;
} }
} }

View File

@@ -71,7 +71,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MAXVER_600_610 0x8 #define PACKAGE2_MAXVER_600_610 0x8
#define PACKAGE2_MAXVER_620 0x9 #define PACKAGE2_MAXVER_620 0x9
#define PACKAGE2_MAXVER_700_800 0xA #define PACKAGE2_MAXVER_700_800 0xA
#define PACKAGE2_MAXVER_810_CURRENT 0xB #define PACKAGE2_MAXVER_810 0xB
#define PACKAGE2_MAXVER_900_CURRENT 0xC
#define PACKAGE2_MINVER_100 0x3 #define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4 #define PACKAGE2_MINVER_200 0x4
@@ -82,7 +83,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MINVER_600_610 0x9 #define PACKAGE2_MINVER_600_610 0x9
#define PACKAGE2_MINVER_620 0xA #define PACKAGE2_MINVER_620 0xA
#define PACKAGE2_MINVER_700_800 0xB #define PACKAGE2_MINVER_700_800 0xB
#define PACKAGE2_MINVER_810_CURRENT 0xC #define PACKAGE2_MINVER_810 0xC
#define PACKAGE2_MINVER_900_CURRENT 0xD
typedef struct { typedef struct {
union { union {

214
exosphere/src/pinmux.h Normal file
View File

@@ -0,0 +1,214 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef EXOSPHERE_PINMUX_H
#define EXOSPHERE_PINMUX_H
#include <stdint.h>
#include "memory_map.h"
#define PINMUX_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC) + 0x3000)
#define MAKE_PINMUX_REG(n) MAKE_REG32(PINMUX_BASE + n)
#define PINMUX_TRISTATE (1 << 4)
#define PINMUX_PARKED (1 << 5)
#define PINMUX_INPUT (1 << 6)
#define PINMUX_PULL_NONE (0 << 2)
#define PINMUX_PULL_DOWN (1 << 2)
#define PINMUX_PULL_UP (2 << 2)
#define PINMUX_SELECT_FUNCTION0 0
#define PINMUX_SELECT_FUNCTION1 1
#define PINMUX_SELECT_FUNCTION2 2
#define PINMUX_SELECT_FUNCTION3 3
#define PINMUX_DRIVE_1X (0 << 13)
#define PINMUX_DRIVE_2X (1 << 13)
#define PINMUX_DRIVE_3X (2 << 13)
#define PINMUX_DRIVE_4X (3 << 13)
typedef struct {
uint32_t sdmmc1_clk;
uint32_t sdmmc1_cmd;
uint32_t sdmmc1_dat3;
uint32_t sdmmc1_dat2;
uint32_t sdmmc1_dat1;
uint32_t sdmmc1_dat0;
uint32_t _r18;
uint32_t sdmmc3_clk;
uint32_t sdmmc3_cmd;
uint32_t sdmmc3_dat0;
uint32_t sdmmc3_dat1;
uint32_t sdmmc3_dat2;
uint32_t sdmmc3_dat3;
uint32_t _r34;
uint32_t pex_l0_rst_n;
uint32_t pex_l0_clkreq_n;
uint32_t pex_wake_n;
uint32_t pex_l1_rst_n;
uint32_t pex_l1_clkreq_n;
uint32_t sata_led_active;
uint32_t spi1_mosi;
uint32_t spi1_miso;
uint32_t spi1_sck;
uint32_t spi1_cs0;
uint32_t spi1_cs1;
uint32_t spi2_mosi;
uint32_t spi2_miso;
uint32_t spi2_sck;
uint32_t spi2_cs0;
uint32_t spi2_cs1;
uint32_t spi4_mosi;
uint32_t spi4_miso;
uint32_t spi4_sck;
uint32_t spi4_cs0;
uint32_t qspi_sck;
uint32_t qspi_cs_n;
uint32_t qspi_io0;
uint32_t qspi_io1;
uint32_t qspi_io2;
uint32_t qspi_io3;
uint32_t _ra0;
uint32_t dmic1_clk;
uint32_t dmic1_dat;
uint32_t dmic2_clk;
uint32_t dmic2_dat;
uint32_t dmic3_clk;
uint32_t dmic3_dat;
uint32_t gen1_i2c_scl;
uint32_t gen1_i2c_sda;
uint32_t gen2_i2c_scl;
uint32_t gen2_i2c_sda;
uint32_t gen3_i2c_scl;
uint32_t gen3_i2c_sda;
uint32_t cam_i2c_scl;
uint32_t cam_i2c_sda;
uint32_t pwr_i2c_scl;
uint32_t pwr_i2c_sda;
uint32_t uart1_tx;
uint32_t uart1_rx;
uint32_t uart1_rts;
uint32_t uart1_cts;
uint32_t uart2_tx;
uint32_t uart2_rx;
uint32_t uart2_rts;
uint32_t uart2_cts;
uint32_t uart3_tx;
uint32_t uart3_rx;
uint32_t uart3_rts;
uint32_t uart3_cts;
uint32_t uart4_tx;
uint32_t uart4_rx;
uint32_t uart4_rts;
uint32_t uart4_cts;
uint32_t dap1_fs;
uint32_t dap1_din;
uint32_t dap1_dout;
uint32_t dap1_sclk;
uint32_t dap2_fs;
uint32_t dap2_din;
uint32_t dap2_dout;
uint32_t dap2_sclk;
uint32_t dap4_fs;
uint32_t dap4_din;
uint32_t dap4_dout;
uint32_t dap4_sclk;
uint32_t cam1_mclk;
uint32_t cam2_mclk;
uint32_t jtag_rtck;
uint32_t clk_32k_in;
uint32_t clk_32k_out;
uint32_t batt_bcl;
uint32_t clk_req;
uint32_t cpu_pwr_req;
uint32_t pwr_int_n;
uint32_t shutdown;
uint32_t core_pwr_req;
uint32_t aud_mclk;
uint32_t dvfs_pwm;
uint32_t dvfs_clk;
uint32_t gpio_x1_aud;
uint32_t gpio_x3_aud;
uint32_t pcc7;
uint32_t hdmi_cec;
uint32_t hdmi_int_dp_hpd;
uint32_t spdif_out;
uint32_t spdif_in;
uint32_t usb_vbus_en0;
uint32_t usb_vbus_en1;
uint32_t dp_hpd0;
uint32_t wifi_en;
uint32_t wifi_rst;
uint32_t wifi_wake_ap;
uint32_t ap_wake_bt;
uint32_t bt_rst;
uint32_t bt_wake_ap;
uint32_t ap_wake_nfc;
uint32_t nfc_en;
uint32_t nfc_int;
uint32_t gps_en;
uint32_t gps_rst;
uint32_t cam_rst;
uint32_t cam_af_en;
uint32_t cam_flash_en;
uint32_t cam1_pwdn;
uint32_t cam2_pwdn;
uint32_t cam1_strobe;
uint32_t lcd_te;
uint32_t lcd_bl_pwm;
uint32_t lcd_bl_en;
uint32_t lcd_rst;
uint32_t lcd_gpio1;
uint32_t lcd_gpio2;
uint32_t ap_ready;
uint32_t touch_rst;
uint32_t touch_clk;
uint32_t modem_wake_ap;
uint32_t touch_int;
uint32_t motion_int;
uint32_t als_prox_int;
uint32_t temp_alert;
uint32_t button_power_on;
uint32_t button_vol_up;
uint32_t button_vol_down;
uint32_t button_slide_sw;
uint32_t button_home;
uint32_t pa6;
uint32_t pe6;
uint32_t pe7;
uint32_t ph6;
uint32_t pk0;
uint32_t pk1;
uint32_t pk2;
uint32_t pk3;
uint32_t pk4;
uint32_t pk5;
uint32_t pk6;
uint32_t pk7;
uint32_t pl0;
uint32_t pl1;
uint32_t pz0;
uint32_t pz1;
uint32_t pz2;
uint32_t pz3;
uint32_t pz4;
uint32_t pz5;
} tegra_pinmux_t;
static inline volatile tegra_pinmux_t *pinmux_get_regs(void)
{
return (volatile tegra_pinmux_t *)PINMUX_BASE;
}
#endif

View File

@@ -77,6 +77,7 @@ static void enable_lp0_wake_events(void) {
static void notify_pmic_shutdown(void) { static void notify_pmic_shutdown(void) {
clkrst_reboot(CARDEVICE_I2C5); clkrst_reboot(CARDEVICE_I2C5);
i2c_init(I2C_5);
if (fuse_get_bootrom_patch_version() >= 0x7F) { if (fuse_get_bootrom_patch_version() >= 0x7F) {
i2c_send_pmic_cpu_shutdown_cmd(); i2c_send_pmic_cpu_shutdown_cmd();
} }

View File

@@ -186,6 +186,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800: case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
/* No more LoadSecureExpModKey. */ /* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL; g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C; g_smc_user_table[0xC].id = 0xC300D60C;

View File

@@ -53,6 +53,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800: case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
default: default:
return keyslot <= 5; return keyslot <= 5;
} }

View File

@@ -15,66 +15,120 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "timers.h"
#include "uart.h" #include "uart.h"
#include "misc.h" #include "timers.h"
#include "pinmux.h"
void uart_select(UartDevice dev) { static inline void uart_wait_cycles(uint32_t baud, uint32_t num)
unsigned int id = (unsigned int)dev; {
PINMUX_AUX_UARTn_TX_0(id) = 0; /* UART */ wait((num * 1000000 + 16 * baud - 1) / (16 * baud));
PINMUX_AUX_UARTn_RX_0(id) = 0x48; /* UART, enable, pull up */ }
PINMUX_AUX_UARTn_RTS_0(id) = 0; /* UART */
PINMUX_AUX_UARTn_CTS_0(id) = 0x44; /* UART, enable, pull down */ static inline void uart_wait_syms(uint32_t baud, uint32_t num)
{
wait((num * 1000000 + baud - 1) / baud);
}
void uart_config(UartDevice dev) {
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
switch (dev) {
case UART_A:
pinmux->uart1_tx = 0;
pinmux->uart1_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart1_rts = 0;
pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_B:
pinmux->uart2_tx = 0;
pinmux->uart2_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart2_rts = 0;
pinmux->uart2_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_C:
pinmux->uart3_tx = 0;
pinmux->uart3_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart3_rts = 0;
pinmux->uart3_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_D:
pinmux->uart4_tx = 0;
pinmux->uart4_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart4_rts = 0;
pinmux->uart4_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_E:
/* Unused. */
break;
default: break;
}
} }
void uart_init(UartDevice dev, uint32_t baud) { void uart_init(UartDevice dev, uint32_t baud) {
volatile uart_t *uart = get_uart_device(dev); volatile tegra_uart_t *uart = uart_get_regs(dev);
/* Set baud rate. */ /* Wait for idle state. */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE);
/* Calculate baud rate, round to nearest. */
uint32_t rate = (8 * baud + 408000000) / (16 * baud); uint32_t rate = (8 * baud + 408000000) / (16 * baud);
uart->UART_LCR = UART_LCR_DLAB; /* Enable DLAB. */
uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
uart->UART_LCR = 0; /* Diable DLAB. */
/* Setup UART in fifo mode. */ /* Setup UART in FIFO mode. */
uart->UART_IER_DLAB = 0; uart->UART_IER_DLAB = 0;
uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Enable and clear TX and RX FIFOs. */
uart->UART_LSR;
wait(3 * ((baud + 999999) / baud));
uart->UART_LCR = UART_LCR_WD_LENGTH_8; /* Set word length 8. */
uart->UART_MCR = 0; uart->UART_MCR = 0;
uart->UART_MSR = 0; uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */
uart->UART_IRDA_CSR = 0; uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */ uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
uart->UART_MIE = 0; uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */
uart->UART_ASR = 0; uart->UART_SPR; /* Dummy read. */
uart_wait_syms(baud, 3); /* Wait for 3 symbols at the new baudrate. */
/* Enable FIFO with default settings. */
uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO;
uart->UART_SPR; /* Dummy read as mandated by TRM. */
uart_wait_cycles(baud, 3); /* Wait for 3 baud cycles, as mandated by TRM (erratum). */
/* Flush FIFO. */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); /* Make sure there's no data being written in TX FIFO (TRM). */
uart->UART_IIR_FCR |= UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Clear TX and RX FIFOs. */
uart_wait_cycles(baud, 32); /* Wait for 32 baud cycles (TRM, erratum). */
/* Wait for idle state (TRM). */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE);
} }
/* This function blocks until the UART device (dev) is in the desired state (status). Make sure the desired state can be reached! */ /* This function blocks until the UART device is in the desired state. */
void uart_wait_idle(UartDevice dev, UartVendorStatus status) { void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
while (!(get_uart_device(dev)->UART_VENDOR_STATUS & status)) { volatile tegra_uart_t *uart = uart_get_regs(dev);
/* Wait */
if (status & UART_VENDOR_STATE_TX_IDLE) {
while (!(uart->UART_LSR & UART_LSR_TMTY)) {
/* Wait */
}
}
if (status & UART_VENDOR_STATE_RX_IDLE) {
while (uart->UART_LSR & UART_LSR_RDR) {
/* Wait */
}
} }
} }
void uart_send(UartDevice dev, const void *buf, size_t len) { void uart_send(UartDevice dev, const void *buf, size_t len) {
volatile uart_t *uart = get_uart_device(dev); volatile tegra_uart_t *uart = uart_get_regs(dev);
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) { while (!(uart->UART_LSR & UART_LSR_THRE)) {
/* Wait until the TX FIFO isn't full */ /* Wait until it's possible to send data. */
} }
uart->UART_THR_DLAB = *((const uint8_t *)buf + i); uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
} }
} }
void uart_recv(UartDevice dev, void *buf, size_t len) { void uart_recv(UartDevice dev, void *buf, size_t len) {
volatile uart_t *uart = get_uart_device(dev); volatile tegra_uart_t *uart = uart_get_regs(dev);
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) { while (!(uart->UART_LSR & UART_LSR_RDR)) {
/* Wait until the RX FIFO isn't empty */ /* Wait until it's possible to receive data. */
} }
*((uint8_t *)buf + i) = uart->UART_THR_DLAB; *((uint8_t *)buf + i) = uart->UART_THR_DLAB;
} }

View File

@@ -31,7 +31,7 @@ static inline uintptr_t get_uart_base(void) {
#define BAUD_115200 115200 #define BAUD_115200 115200
/* Exosphère: add the clkreset values for UART C,D,E */ /* UART devices */
typedef enum { typedef enum {
UART_A = 0, UART_A = 0,
UART_B = 1, UART_B = 1,
@@ -148,31 +148,31 @@ typedef enum {
} UartInterruptIdentification; } UartInterruptIdentification;
typedef struct { typedef struct {
/* 0x00 */ uint32_t UART_THR_DLAB; uint32_t UART_THR_DLAB;
/* 0x04 */ uint32_t UART_IER_DLAB; uint32_t UART_IER_DLAB;
/* 0x08 */ uint32_t UART_IIR_FCR; uint32_t UART_IIR_FCR;
/* 0x0C */ uint32_t UART_LCR; uint32_t UART_LCR;
/* 0x10 */ uint32_t UART_MCR; uint32_t UART_MCR;
/* 0x14 */ uint32_t UART_LSR; uint32_t UART_LSR;
/* 0x18 */ uint32_t UART_MSR; uint32_t UART_MSR;
/* 0x1C */ uint32_t UART_SPR; uint32_t UART_SPR;
/* 0x20 */ uint32_t UART_IRDA_CSR; uint32_t UART_IRDA_CSR;
/* 0x24 */ uint32_t UART_RX_FIFO_CFG; uint32_t UART_RX_FIFO_CFG;
/* 0x28 */ uint32_t UART_MIE; uint32_t UART_MIE;
/* 0x2C */ uint32_t UART_VENDOR_STATUS; uint32_t UART_VENDOR_STATUS;
/* 0x30 */ uint8_t _pad_30[0x0C]; uint8_t _0x30[0x0C];
/* 0x3C */ uint32_t UART_ASR; uint32_t UART_ASR;
} uart_t; } tegra_uart_t;
void uart_select(UartDevice dev); void uart_config(UartDevice dev);
void uart_init(UartDevice dev, uint32_t baud); void uart_init(UartDevice dev, uint32_t baud);
void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_wait_idle(UartDevice dev, UartVendorStatus status);
void uart_send(UartDevice dev, const void *buf, size_t len); void uart_send(UartDevice dev, const void *buf, size_t len);
void uart_recv(UartDevice dev, void *buf, size_t len); void uart_recv(UartDevice dev, void *buf, size_t len);
static inline volatile uart_t *get_uart_device(UartDevice dev) { static inline volatile tegra_uart_t *uart_get_regs(UartDevice dev) {
static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400}; static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400};
return (volatile uart_t *)(UART_BASE + offsets[dev]); return (volatile tegra_uart_t *)(UART_BASE + offsets[dev]);
} }
#endif #endif

View File

@@ -24,7 +24,6 @@
#include "bootup.h" #include "bootup.h"
#include "smc_api.h" #include "smc_api.h"
#include "exocfg.h" #include "exocfg.h"
#include "se.h" #include "se.h"
#include "mc.h" #include "mc.h"
#include "car.h" #include "car.h"
@@ -32,7 +31,6 @@
#include "misc.h" #include "misc.h"
#include "uart.h" #include "uart.h"
#include "interrupt.h" #include "interrupt.h"
#include "pmc.h" #include "pmc.h"
uintptr_t get_warmboot_main_stack_address(void) { uintptr_t get_warmboot_main_stack_address(void) {
@@ -41,8 +39,7 @@ uintptr_t get_warmboot_main_stack_address(void) {
static void warmboot_configure_hiz_mode(void) { static void warmboot_configure_hiz_mode(void) {
/* Enable input to I2C1 */ /* Enable input to I2C1 */
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40; i2c_config(I2C_1);
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
clkrst_reboot(CARDEVICE_I2C1); clkrst_reboot(CARDEVICE_I2C1);
i2c_init(0); i2c_init(0);
@@ -69,7 +66,7 @@ void __attribute__((noreturn)) warmboot_main(void) {
if (VIRT_MC_SECURITY_CFG3 == 0) { if (VIRT_MC_SECURITY_CFG3 == 0) {
/* N only does this on dev units, but we will do it unconditionally. */ /* N only does this on dev units, but we will do it unconditionally. */
{ {
uart_select(UART_A); uart_config(UART_A);
clkrst_reboot(CARDEVICE_UARTA); clkrst_reboot(CARDEVICE_UARTA);
uart_init(UART_A, 115200); uart_init(UART_A, 115200);
} }

View File

@@ -1,4 +1,4 @@
SUBFOLDERS := fusee-primary fusee-secondary SUBFOLDERS := fusee-primary fusee-mtc fusee-secondary
TOPTARGETS := all clean TOPTARGETS := all clean

163
fusee/fusee-mtc/Makefile Normal file
View File

@@ -0,0 +1,163 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
TOPDIR ?= $(CURDIR)
AMS := $(TOPDIR)/../../
include $(DEVKITARM)/base_rules
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD)
ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
AMSREV := $(AMSREV)-dirty
endif
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := src src/lib src/display
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
DEFINES := -D__BPMP__ -DFUSEE_STAGE1_SRC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
CFLAGS := \
-g \
-O2 \
-fomit-frame-pointer \
-ffunction-sections \
-fdata-sections \
-std=gnu11 \
-Werror \
-Wall \
-fstrict-volatile-bitfields \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# 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 .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
%.elf: $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
@$(NM) -CSn $@ > $(notdir $*.lst)
$(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
#---------------------------------------------------------------------------------------

170
fusee/fusee-mtc/linker.ld Normal file
View File

@@ -0,0 +1,170 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
PHDRS
{
crt0 PT_LOAD;
main PT_LOAD;
}
/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */
MEMORY
{
NULL : ORIGIN = 0x00000000, LENGTH = 0x1000
main : ORIGIN = 0xF0000000, LENGTH = 0x10000000
}
SECTIONS
{
PROVIDE(__start__ = 0xF0000000);
PROVIDE(__stack_bottom__ = 0x90010000);
PROVIDE(__stack_top__ = 0x90020000);
PROVIDE(__heap_start__ = 0x90020000);
PROVIDE(__heap_end__ = 0xA0020000);
. = __start__;
.crt0 :
{
KEEP( *(.text.start) )
KEEP( *(.init) )
. = ALIGN(32);
} >main :crt0
.text :
{
. = ALIGN(32);
/* .text */
*(.text)
*(.text.*)
*(.glue_7)
*(.glue_7t)
*(.stub)
*(.gnu.warning)
*(.gnu.linkonce.t*)
/* .fini */
KEEP( *(.fini) )
. = ALIGN(8);
} >main :main
.rodata :
{
*(.rodata)
*(.roda)
*(.rodata.*)
*all.rodata*(*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(8);
} >main
.preinit_array :
{
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
} >main
.init_array ALIGN(4) :
{
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
} >main
.fini_array ALIGN(4) :
{
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE (__fini_array_end = .);
} >main
.ctors ALIGN(4) :
{
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >main
.dtors ALIGN(4) :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >main
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) __exidx_start = ABSOLUTE(.);} >main
ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = ABSOLUTE(.);} >main
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(32);
} >main
.bss (NOLOAD) :
{
. = ALIGN(32);
PROVIDE (__bss_start__ = ABSOLUTE(.));
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b*)
*(COMMON)
. = ALIGN(32);
PROVIDE (__bss_end__ = ABSOLUTE(.));
} >main :NONE
__end__ = ABSOLUTE(.) ;
/* ==================
==== Metadata ====
================== */
/* Discard sections that difficult post-processing */
/DISCARD/ : { *(.group .comment .note) }
/* 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) }
}

View File

@@ -0,0 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
*startfile:
crti%O%s crtbegin%O%s

139
fusee/fusee-mtc/src/car.c Normal file
View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2018-2019 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 "car.h"
#include "timers.h"
#include "utils.h"
static inline uint32_t get_clk_source_reg(CarDevice dev) {
switch (dev) {
case CARDEVICE_UARTA: return 0x178;
case CARDEVICE_UARTB: return 0x17C;
case CARDEVICE_UARTC: return 0x1A0;
case CARDEVICE_I2C1: return 0x124;
case CARDEVICE_I2C5: return 0x128;
case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0x42C;
case CARDEVICE_HOST1X: return 0x180;
case CARDEVICE_TSEC: return 0x1F4;
case CARDEVICE_SOR_SAFE: return 0;
case CARDEVICE_SOR0: return 0;
case CARDEVICE_SOR1: return 0x410;
case CARDEVICE_KFUSE: return 0;
case CARDEVICE_CL_DVFS: return 0;
case CARDEVICE_CORESIGHT: return 0x1D4;
case CARDEVICE_ACTMON: return 0x3E8;
case CARDEVICE_BPMP: return 0;
default: generic_panic();
}
}
static inline uint32_t get_clk_source_val(CarDevice dev) {
switch (dev) {
case CARDEVICE_UARTA: return 0;
case CARDEVICE_UARTB: return 0;
case CARDEVICE_UARTC: return 0;
case CARDEVICE_I2C1: return 6;
case CARDEVICE_I2C5: return 6;
case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0;
case CARDEVICE_HOST1X: return 4;
case CARDEVICE_TSEC: return 0;
case CARDEVICE_SOR_SAFE: return 0;
case CARDEVICE_SOR0: return 0;
case CARDEVICE_SOR1: return 0;
case CARDEVICE_KFUSE: return 0;
case CARDEVICE_CL_DVFS: return 0;
case CARDEVICE_CORESIGHT: return 0;
case CARDEVICE_ACTMON: return 6;
case CARDEVICE_BPMP: return 0;
default: generic_panic();
}
}
static inline uint32_t get_clk_source_div(CarDevice dev) {
switch (dev) {
case CARDEVICE_UARTA: return 0;
case CARDEVICE_UARTB: return 0;
case CARDEVICE_UARTC: return 0;
case CARDEVICE_I2C1: return 0;
case CARDEVICE_I2C5: return 0;
case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0;
case CARDEVICE_HOST1X: return 3;
case CARDEVICE_TSEC: return 2;
case CARDEVICE_SOR_SAFE: return 0;
case CARDEVICE_SOR0: return 0;
case CARDEVICE_SOR1: return 2;
case CARDEVICE_KFUSE: return 0;
case CARDEVICE_CL_DVFS: return 0;
case CARDEVICE_CORESIGHT: return 4;
case CARDEVICE_ACTMON: return 0;
case CARDEVICE_BPMP: return 0;
default: generic_panic();
}
}
static uint32_t g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298};
static uint32_t g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4};
void clk_enable(CarDevice dev) {
uint32_t clk_source_reg;
if ((clk_source_reg = get_clk_source_reg(dev))) {
MAKE_CAR_REG(clk_source_reg) = (get_clk_source_val(dev) << 29) | get_clk_source_div(dev);
}
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
}
void clk_disable(CarDevice dev) {
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
}
void rst_enable(CarDevice dev) {
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
}
void rst_disable(CarDevice dev) {
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
}
void clkrst_enable(CarDevice dev) {
clk_enable(dev);
rst_disable(dev);
}
void clkrst_disable(CarDevice dev) {
rst_enable(dev);
clk_disable(dev);
}
void clkrst_reboot(CarDevice dev) {
clkrst_disable(dev);
if (dev == CARDEVICE_KFUSE) {
/* Workaround for KFUSE clock. */
clk_enable(dev);
udelay(100);
rst_disable(dev);
udelay(200);
} else {
clkrst_enable(dev);
}
}
void clkrst_enable_fuse_regs(bool enable) {
volatile tegra_car_t *car = car_get_regs();
car->misc_clk_enb = ((car->misc_clk_enb & 0xEFFFFFFF) | ((enable & 1) << 28));
}

505
fusee/fusee-mtc/src/car.h Normal file
View File

@@ -0,0 +1,505 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_CAR_H
#define FUSEE_CAR_H
#include <stdint.h>
#include <stdbool.h>
#define CAR_BASE 0x60006000
#define MAKE_CAR_REG(n) MAKE_REG32(CAR_BASE + n)
#define CLK_L_SDMMC1 (1 << 14)
#define CLK_L_SDMMC2 (1 << 9)
#define CLK_U_SDMMC3 (1 << 5)
#define CLK_L_SDMMC4 (1 << 15)
#define CLK_SOURCE_MASK (0b111 << 29)
#define CLK_SOURCE_FIRST (0b000 << 29)
#define CLK_DIVIDER_MASK (0xff << 0)
#define CLK_DIVIDER_UNITY (0x00 << 0)
#define NUM_CAR_BANKS 7
/* Clock and reset devices. */
typedef enum {
CARDEVICE_UARTA = ((0 << 5) | 0x6),
CARDEVICE_UARTB = ((0 << 5) | 0x7),
CARDEVICE_UARTC = ((1 << 5) | 0x17),
CARDEVICE_I2C1 = ((0 << 5) | 0xC),
CARDEVICE_I2C5 = ((1 << 5) | 0xF),
CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
CARDEVICE_SE = ((3 << 5) | 0x1F),
CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
CARDEVICE_TSEC = ((2 << 5) | 0x13),
CARDEVICE_SOR_SAFE = ((6 << 5) | 0x1E),
CARDEVICE_SOR0 = ((5 << 5) | 0x16),
CARDEVICE_SOR1 = ((5 << 5) | 0x17),
CARDEVICE_KFUSE = ((1 << 5) | 0x8),
CARDEVICE_CL_DVFS = ((4 << 5) | 0x1B),
CARDEVICE_CORESIGHT = ((2 << 5) | 0x9),
CARDEVICE_ACTMON = ((3 << 5) | 0x17),
CARDEVICE_BPMP = ((0 << 5) | 0x1)
} CarDevice;
/* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */
typedef struct {
uint32_t rst_src; /* _RST_SOURCE_0, 0x00 */
/* _RST_DEVICES_L/H/U_0 0x4-0xc */
uint32_t rst_dev_l;
uint32_t rst_dev_h;
uint32_t rst_dev_u;
/* _CLK_OUT_ENB_L/H/U_0 0x10-0x18 */
uint32_t clk_out_enb_l;
uint32_t clk_out_enb_h;
uint32_t clk_out_enb_u;
uint32_t _0x1C;
uint32_t cclk_brst_pol; /* _CCLK_BURST_POLICY_0, 0x20 */
uint32_t super_cclk_div; /* _SUPER_CCLK_DIVIDER_0, 0x24 */
uint32_t sclk_brst_pol; /* _SCLK_BURST_POLICY_0, 0x28 */
uint32_t super_sclk_div; /* _SUPER_SCLK_DIVIDER_0, 0x2c */
uint32_t clk_sys_rate; /* _CLK_SYSTEM_RATE_0, 0x30 */
uint32_t prog_dly_clk; /* _PROG_DLY_CLK_0, 0x34 */
uint32_t aud_sync_clk_rate; /* _AUDIO_SYNC_CLK_RATE_0, 0x38 */
uint32_t _0x3C;
uint32_t cop_clk_skip_plcy; /* _COP_CLK_SKIP_POLICY_0, 0x40 */
uint32_t clk_mask_arm; /* _CLK_MASK_ARM_0, 0x44 */
uint32_t misc_clk_enb; /* _MISC_CLK_ENB_0, 0x48 */
uint32_t clk_cpu_cmplx; /* _CLK_CPU_CMPLX_0, 0x4c */
uint32_t osc_ctrl; /* _OSC_CTRL_0, 0x50 */
uint32_t pll_lfsr; /* _PLL_LFSR_0, 0x54 */
uint32_t osc_freq_det; /* _OSC_FREQ_DET_0, 0x58 */
uint32_t osc_freq_det_stat; /* _OSC_FREQ_DET_STATUS_0, 0x5c */
uint32_t _0x60[2];
uint32_t plle_ss_cntl; /* _PLLE_SS_CNTL_0, 0x68 */
uint32_t plle_misc1; /* _PLLE_MISC1_0, 0x6c */
uint32_t _0x70[4];
/* PLLC 0x80-0x8c */
uint32_t pllc_base;
uint32_t pllc_out;
uint32_t pllc_misc0;
uint32_t pllc_misc1;
/* PLLM 0x90-0x9c */
uint32_t pllm_base;
uint32_t pllm_out;
uint32_t pllm_misc1;
uint32_t pllm_misc2;
/* PLLP 0xa0-0xac */
uint32_t pllp_base;
uint32_t pllp_outa;
uint32_t pllp_outb;
uint32_t pllp_misc;
/* PLLA 0xb0-0xbc */
uint32_t plla_base;
uint32_t plla_out;
uint32_t plla_misc0;
uint32_t plla_misc1;
/* PLLU 0xc0-0xcc */
uint32_t pllu_base;
uint32_t pllu_out;
uint32_t pllu_misc1;
uint32_t pllu_misc2;
/* PLLD 0xd0-0xdc */
uint32_t plld_base;
uint32_t plld_out;
uint32_t plld_misc1;
uint32_t plld_misc2;
/* PLLX 0xe0-0xe4 */
uint32_t pllx_base;
uint32_t pllx_misc;
/* PLLE 0xe8-0xf4 */
uint32_t plle_base;
uint32_t plle_misc;
uint32_t plle_ss_cntl1;
uint32_t plle_ss_cntl2;
uint32_t lvl2_clk_gate_ovra; /* _LVL2_CLK_GATE_OVRA_0, 0xf8 */
uint32_t lvl2_clk_gate_ovrb; /* _LVL2_CLK_GATE_OVRB_0, 0xfc */
uint32_t clk_source_i2s2; /* _CLK_SOURCE_I2S2_0, 0x100 */
uint32_t clk_source_i2s3; /* _CLK_SOURCE_I2S3_0, 0x104 */
uint32_t clk_source_spdif_out; /* _CLK_SOURCE_SPDIF_OUT_0, 0x108 */
uint32_t clk_source_spdif_in; /* _CLK_SOURCE_SPDIF_IN_0, 0x10c */
uint32_t clk_source_pwm; /* _CLK_SOURCE_PWM_0, 0x110 */
uint32_t _0x114;
uint32_t clk_source_spi2; /* _CLK_SOURCE_SPI2_0, 0x118 */
uint32_t clk_source_spi3; /* _CLK_SOURCE_SPI3_0, 0x11c */
uint32_t _0x120;
uint32_t clk_source_i2c1; /* _CLK_SOURCE_I2C1_0, 0x124 */
uint32_t clk_source_i2c5; /* _CLK_SOURCE_I2C5_0, 0x128 */
uint32_t _0x12c[2];
uint32_t clk_source_spi1; /* _CLK_SOURCE_SPI1_0, 0x134 */
uint32_t clk_source_disp1; /* _CLK_SOURCE_DISP1_0, 0x138 */
uint32_t clk_source_disp2; /* _CLK_SOURCE_DISP2_0, 0x13c */
uint32_t _0x140;
uint32_t clk_source_isp; /* _CLK_SOURCE_ISP_0, 0x144 */
uint32_t clk_source_vi; /* _CLK_SOURCE_VI_0, 0x148 */
uint32_t _0x14c;
uint32_t clk_source_sdmmc1; /* _CLK_SOURCE_SDMMC1_0, 0x150 */
uint32_t clk_source_sdmmc2; /* _CLK_SOURCE_SDMMC2_0, 0x154 */
uint32_t _0x158[3];
uint32_t clk_source_sdmmc4; /* _CLK_SOURCE_SDMMC4_0, 0x164 */
uint32_t _0x168[4];
uint32_t clk_source_uarta; /* _CLK_SOURCE_UARTA_0, 0x178 */
uint32_t clk_source_uartb; /* _CLK_SOURCE_UARTB_0, 0x17c */
uint32_t clk_source_host1x; /* _CLK_SOURCE_HOST1X_0, 0x180 */
uint32_t _0x184[5];
uint32_t clk_source_i2c2; /* _CLK_SOURCE_I2C2_0, 0x198 */
uint32_t clk_source_emc; /* _CLK_SOURCE_EMC_0, 0x19c */
uint32_t clk_source_uartc; /* _CLK_SOURCE_UARTC_0, 0x1a0 */
uint32_t _0x1a4;
uint32_t clk_source_vi_sensor; /* _CLK_SOURCE_VI_SENSOR_0, 0x1a8 */
uint32_t _0x1ac[2];
uint32_t clk_source_spi4; /* _CLK_SOURCE_SPI4_0, 0x1b4 */
uint32_t clk_source_i2c3; /* _CLK_SOURCE_I2C3_0, 0x1b8 */
uint32_t clk_source_sdmmc3; /* _CLK_SOURCE_SDMMC3_0, 0x1bc */
uint32_t clk_source_uartd; /* _CLK_SOURCE_UARTD_0, 0x1c0 */
uint32_t _0x1c4[2];
uint32_t clk_source_owr; /* _CLK_SOURCE_OWR_0, 0x1cc */
uint32_t _0x1d0;
uint32_t clk_source_csite; /* _CLK_SOURCE_CSITE_0, 0x1d4 */
uint32_t clk_source_i2s1; /* _CLK_SOURCE_I2S1_0, 0x1d8 */
uint32_t clk_source_dtv; /* _CLK_SOURCE_DTV_0, 0x1dc */
uint32_t _0x1e0[5];
uint32_t clk_source_tsec; /* _CLK_SOURCE_TSEC_0, 0x1f4 */
uint32_t _0x1f8;
uint32_t clk_spare2; /* _CLK_SPARE2_0, 0x1fc */
uint32_t _0x200[32];
uint32_t clk_out_enb_x; /* _CLK_OUT_ENB_X_0, 0x280 */
uint32_t clk_enb_x_set; /* _CLK_ENB_X_SET_0, 0x284 */
uint32_t clk_enb_x_clr; /* _CLK_ENB_X_CLR_0, 0x288 */
uint32_t rst_devices_x; /* _RST_DEVICES_X_0, 0x28c */
uint32_t rst_dev_x_set; /* _RST_DEV_X_SET_0, 0x290 */
uint32_t rst_dev_x_clr; /* _RST_DEV_X_CLR_0, 0x294 */
uint32_t clk_out_enb_y; /* _CLK_OUT_ENB_Y_0, 0x298 */
uint32_t clk_enb_y_set; /* _CLK_ENB_Y_SET_0, 0x29c */
uint32_t clk_enb_y_clr; /* _CLK_ENB_Y_CLR_0, 0x2a0 */
uint32_t rst_devices_y; /* _RST_DEVICES_Y_0, 0x2a4 */
uint32_t rst_dev_y_set; /* _RST_DEV_Y_SET_0, 0x2a8 */
uint32_t rst_dev_y_clr; /* _RST_DEV_Y_CLR_0, 0x2ac */
uint32_t _0x2b0[17];
uint32_t dfll_base; /* _DFLL_BASE_0, 0x2f4 */
uint32_t _0x2f8[2];
/* _RST_DEV_L/H/U_SET_0 0x300-0x314 */
uint32_t rst_dev_l_set;
uint32_t rst_dev_l_clr;
uint32_t rst_dev_h_set;
uint32_t rst_dev_h_clr;
uint32_t rst_dev_u_set;
uint32_t rst_dev_u_clr;
uint32_t _0x318[2];
/* _CLK_ENB_L/H/U_CLR_0 0x320-0x334 */
uint32_t clk_enb_l_set;
uint32_t clk_enb_l_clr;
uint32_t clk_enb_h_set;
uint32_t clk_enb_h_clr;
uint32_t clk_enb_u_set;
uint32_t clk_enb_u_clr;
uint32_t _0x338;
uint32_t ccplex_pg_sm_ovrd; /* _CCPLEX_PG_SM_OVRD_0, 0x33c */
uint32_t rst_cpu_cmplx_set; /* _RST_CPU_CMPLX_SET_0, 0x340 */
uint32_t rst_cpu_cmplx_clr; /* _RST_CPU_CMPLX_CLR_0, 0x344 */
/* Additional (T30) registers */
uint32_t clk_cpu_cmplx_set; /* _CLK_CPU_CMPLX_SET_0, 0x348 */
uint32_t clk_cpu_cmplx_clr; /* _CLK_CPU_CMPLX_SET_0, 0x34c */
uint32_t _0x350[2];
uint32_t rst_dev_v; /* _RST_DEVICES_V_0, 0x358 */
uint32_t rst_dev_w; /* _RST_DEVICES_W_0, 0x35c */
uint32_t clk_out_enb_v; /* _CLK_OUT_ENB_V_0, 0x360 */
uint32_t clk_out_enb_w; /* _CLK_OUT_ENB_W_0, 0x364 */
uint32_t cclkg_brst_pol; /* _CCLKG_BURST_POLICY_0, 0x368 */
uint32_t super_cclkg_div; /* _SUPER_CCLKG_DIVIDER_0, 0x36c */
uint32_t cclklp_brst_pol; /* _CCLKLP_BURST_POLICY_0, 0x370 */
uint32_t super_cclkp_div; /* _SUPER_CCLKLP_DIVIDER_0, 0x374 */
uint32_t clk_cpug_cmplx; /* _CLK_CPUG_CMPLX_0, 0x378 */
uint32_t clk_cpulp_cmplx; /* _CLK_CPULP_CMPLX_0, 0x37c */
uint32_t cpu_softrst_ctrl; /* _CPU_SOFTRST_CTRL_0, 0x380 */
uint32_t cpu_softrst_ctrl1; /* _CPU_SOFTRST_CTRL1_0, 0x384 */
uint32_t cpu_softrst_ctrl2; /* _CPU_SOFTRST_CTRL2_0, 0x388 */
uint32_t _0x38c[5];
uint32_t lvl2_clk_gate_ovrc; /* _LVL2_CLK_GATE_OVRC, 0x3a0 */
uint32_t lvl2_clk_gate_ovrd; /* _LVL2_CLK_GATE_OVRD, 0x3a4 */
uint32_t _0x3a8[2];
uint32_t _0x3b0;
uint32_t clk_source_mselect; /* _CLK_SOURCE_MSELECT_0, 0x3b4 */
uint32_t clk_source_tsensor; /* _CLK_SOURCE_TSENSOR_0, 0x3b8 */
uint32_t clk_source_i2s4; /* _CLK_SOURCE_I2S4_0, 0x3bc */
uint32_t clk_source_i2s5; /* _CLK_SOURCE_I2S5_0, 0x3c0 */
uint32_t clk_source_i2c4; /* _CLK_SOURCE_I2C4_0, 0x3c4 */
uint32_t _0x3c8[2];
uint32_t clk_source_ahub; /* _CLK_SOURCE_AHUB_0, 0x3d0 */
uint32_t _0x3d4[4];
uint32_t clk_source_hda2codec_2x; /* _CLK_SOURCE_HDA2CODEC_2X_0, 0x3e4 */
uint32_t clk_source_actmon; /* _CLK_SOURCE_ACTMON_0, 0x3e8 */
uint32_t clk_source_extperiph1; /* _CLK_SOURCE_EXTPERIPH1_0, 0x3ec */
uint32_t clk_source_extperiph2; /* _CLK_SOURCE_EXTPERIPH2_0, 0x3f0 */
uint32_t clk_source_extperiph3; /* _CLK_SOURCE_EXTPERIPH3_0, 0x3f4 */
uint32_t _0x3f8;
uint32_t clk_source_i2c_slow; /* _CLK_SOURCE_I2C_SLOW_0, 0x3fc */
uint32_t clk_source_sys; /* _CLK_SOURCE_SYS_0, 0x400 */
uint32_t clk_source_ispb; /* _CLK_SOURCE_ISPB_0, 0x404 */
uint32_t _0x408[2];
uint32_t clk_source_sor1; /* _CLK_SOURCE_SOR1_0, 0x410 */
uint32_t clk_source_sor0; /* _CLK_SOURCE_SOR0_0, 0x414 */
uint32_t _0x418[2];
uint32_t clk_source_sata_oob; /* _CLK_SOURCE_SATA_OOB_0, 0x420 */
uint32_t clk_source_sata; /* _CLK_SOURCE_SATA_0, 0x424 */
uint32_t clk_source_hda; /* _CLK_SOURCE_HDA_0, 0x428 */
uint32_t _0x42c;
/* _RST_DEV_V/W_SET_0 0x430-0x43c */
uint32_t rst_dev_v_set;
uint32_t rst_dev_v_clr;
uint32_t rst_dev_w_set;
uint32_t rst_dev_w_clr;
/* _CLK_ENB_V/W_CLR_0 0x440-0x44c */
uint32_t clk_enb_v_set;
uint32_t clk_enb_v_clr;
uint32_t clk_enb_w_set;
uint32_t clk_enb_w_clr;
/* Additional (T114+) registers */
uint32_t rst_cpug_cmplx_set; /* _RST_CPUG_CMPLX_SET_0, 0x450 */
uint32_t rst_cpug_cmplx_clr; /* _RST_CPUG_CMPLX_CLR_0, 0x454 */
uint32_t rst_cpulp_cmplx_set; /* _RST_CPULP_CMPLX_SET_0, 0x458 */
uint32_t rst_cpulp_cmplx_clr; /* _RST_CPULP_CMPLX_CLR_0, 0x45c */
uint32_t clk_cpug_cmplx_set; /* _CLK_CPUG_CMPLX_SET_0, 0x460 */
uint32_t clk_cpug_cmplx_clr; /* _CLK_CPUG_CMPLX_CLR_0, 0x464 */
uint32_t clk_cpulp_cmplx_set; /* _CLK_CPULP_CMPLX_SET_0, 0x468 */
uint32_t clk_cpulp_cmplx_clr; /* _CLK_CPULP_CMPLX_CLR_0, 0x46c */
uint32_t cpu_cmplx_status; /* _CPU_CMPLX_STATUS_0, 0x470 */
uint32_t _0x474;
uint32_t intstatus; /* _INTSTATUS_0, 0x478 */
uint32_t intmask; /* _INTMASK_0, 0x47c */
uint32_t utmip_pll_cfg0; /* _UTMIP_PLL_CFG0_0, 0x480 */
uint32_t utmip_pll_cfg1; /* _UTMIP_PLL_CFG1_0, 0x484 */
uint32_t utmip_pll_cfg2; /* _UTMIP_PLL_CFG2_0, 0x488 */
uint32_t plle_aux; /* _PLLE_AUX_0, 0x48c */
uint32_t sata_pll_cfg0; /* _SATA_PLL_CFG0_0, 0x490 */
uint32_t sata_pll_cfg1; /* _SATA_PLL_CFG1_0, 0x494 */
uint32_t pcie_pll_cfg0; /* _PCIE_PLL_CFG0_0, 0x498 */
uint32_t prog_audio_dly_clk; /* _PROG_AUDIO_DLY_CLK_0, 0x49c */
uint32_t audio_sync_clk_i2s0; /* _AUDIO_SYNC_CLK_I2S0_0, 0x4a0 */
uint32_t audio_sync_clk_i2s1; /* _AUDIO_SYNC_CLK_I2S1_0, 0x4a4 */
uint32_t audio_sync_clk_i2s2; /* _AUDIO_SYNC_CLK_I2S2_0, 0x4a8 */
uint32_t audio_sync_clk_i2s3; /* _AUDIO_SYNC_CLK_I2S3_0, 0x4ac */
uint32_t audio_sync_clk_i2s4; /* _AUDIO_SYNC_CLK_I2S4_0, 0x4b0 */
uint32_t audio_sync_clk_spdif; /* _AUDIO_SYNC_CLK_SPDIF_0, 0x4b4 */
uint32_t plld2_base; /* _PLLD2_BASE_0, 0x4b8 */
uint32_t plld2_misc; /* _PLLD2_MISC_0, 0x4bc */
uint32_t utmip_pll_cfg3; /* _UTMIP_PLL_CFG3_0, 0x4c0 */
uint32_t pllrefe_base; /* _PLLREFE_BASE_0, 0x4c4 */
uint32_t pllrefe_misc; /* _PLLREFE_MISC_0, 0x4c8 */
uint32_t pllrefe_out; /* _PLLREFE_OUT_0, 0x4cc */
uint32_t cpu_finetrim_byp; /* _CPU_FINETRIM_BYP_0, 0x4d0 */
uint32_t cpu_finetrim_select; /* _CPU_FINETRIM_SELECT_0, 0x4d4 */
uint32_t cpu_finetrim_dr; /* _CPU_FINETRIM_DR_0, 0x4d8 */
uint32_t cpu_finetrim_df; /* _CPU_FINETRIM_DF_0, 0x4dc */
uint32_t cpu_finetrim_f; /* _CPU_FINETRIM_F_0, 0x4e0 */
uint32_t cpu_finetrim_r; /* _CPU_FINETRIM_R_0, 0x4e4 */
uint32_t pllc2_base; /* _PLLC2_BASE_0, 0x4e8 */
uint32_t pllc2_misc0; /* _PLLC2_MISC_0_0, 0x4ec */
uint32_t pllc2_misc1; /* _PLLC2_MISC_1_0, 0x4f0 */
uint32_t pllc2_misc2; /* _PLLC2_MISC_2_0, 0x4f4 */
uint32_t pllc2_misc3; /* _PLLC2_MISC_3_0, 0x4f8 */
uint32_t pllc3_base; /* _PLLC3_BASE_0, 0x4fc */
uint32_t pllc3_misc0; /* _PLLC3_MISC_0_0, 0x500 */
uint32_t pllc3_misc1; /* _PLLC3_MISC_1_0, 0x504 */
uint32_t pllc3_misc2; /* _PLLC3_MISC_2_0, 0x508 */
uint32_t pllc3_misc3; /* _PLLC3_MISC_3_0, 0x50c */
uint32_t pllx_misc1; /* _PLLX_MISC_1_0, 0x510 */
uint32_t pllx_misc2; /* _PLLX_MISC_2_0, 0x514 */
uint32_t pllx_misc3; /* _PLLX_MISC_3_0, 0x518 */
uint32_t xusbio_pll_cfg0; /* _XUSBIO_PLL_CFG0_0, 0x51c */
uint32_t xusbio_pll_cfg1; /* _XUSBIO_PLL_CFG0_1, 0x520 */
uint32_t plle_aux1; /* _PLLE_AUX1_0, 0x524 */
uint32_t pllp_reshift; /* _PLLP_RESHIFT_0, 0x528 */
uint32_t utmipll_hw_pwrdn_cfg0; /* _UTMIPLL_HW_PWRDN_CFG0_0, 0x52c */
uint32_t pllu_hw_pwrdn_cfg0; /* _PLLU_HW_PWRDN_CFG0_0, 0x530 */
uint32_t xusb_pll_cfg0; /* _XUSB_PLL_CFG0_0, 0x534 */
uint32_t _0x538;
uint32_t clk_cpu_misc; /* _CLK_CPU_MISC_0, 0x53c */
uint32_t clk_cpug_misc; /* _CLK_CPUG_MISC_0, 0x540 */
uint32_t clk_cpulp_misc; /* _CLK_CPULP_MISC_0, 0x544 */
uint32_t pllx_hw_ctrl_cfg; /* _PLLX_HW_CTRL_CFG_0, 0x548 */
uint32_t pllx_sw_ramp_cfg; /* _PLLX_SW_RAMP_CFG_0, 0x54c */
uint32_t pllx_hw_ctrl_status; /* _PLLX_HW_CTRL_STATUS_0, 0x550 */
uint32_t lvl2_clk_gate_ovre; /* _LVL2_CLK_GATE_OVRE, 0x554 */
uint32_t super_gr3d_clk_div; /* _SUPER_GR3D_CLK_DIVIDER_0, 0x558 */
uint32_t spare_reg0; /* _SPARE_REG0_0, 0x55c */
uint32_t audio_sync_clk_dmic1; /* _AUDIO_SYNC_CLK_DMIC1_0, 0x560 */
uint32_t audio_sync_clk_dmic2; /* _AUDIO_SYNC_CLK_DMIC2_0, 0x564 */
uint32_t _0x568[2];
uint32_t plld2_ss_cfg; /* _PLLD2_SS_CFG, 0x570 */
uint32_t plld2_ss_ctrl1; /* _PLLD2_SS_CTRL1_0, 0x574 */
uint32_t plld2_ss_ctrl2; /* _PLLD2_SS_CTRL2_0, 0x578 */
uint32_t _0x57c[5];
uint32_t plldp_base; /* _PLLDP_BASE, 0x590*/
uint32_t plldp_misc; /* _PLLDP_MISC, 0x594 */
uint32_t plldp_ss_cfg; /* _PLLDP_SS_CFG, 0x598 */
uint32_t plldp_ss_ctrl1; /* _PLLDP_SS_CTRL1_0, 0x59c */
uint32_t plldp_ss_ctrl2; /* _PLLDP_SS_CTRL2_0, 0x5a0 */
uint32_t pllc4_base; /* _PLLC4_BASE_0, 0x5a4 */
uint32_t pllc4_misc; /* _PLLC4_MISC_0, 0x5a8 */
uint32_t _0x5ac[6];
uint32_t clk_spare0; /* _CLK_SPARE0_0, 0x5c4 */
uint32_t clk_spare1; /* _CLK_SPARE1_0, 0x5c8 */
uint32_t gpu_isob_ctrl; /* _GPU_ISOB_CTRL_0, 0x5cc */
uint32_t pllc_misc2; /* _PLLC_MISC_2_0, 0x5d0 */
uint32_t pllc_misc3; /* _PLLC_MISC_3_0, 0x5d4 */
uint32_t plla_misc2; /* _PLLA_MISC2_0, 0x5d8 */
uint32_t _0x5dc[2];
uint32_t pllc4_out; /* _PLLC4_OUT_0, 0x5e4 */
uint32_t pllmb_base; /* _PLLMB_BASE_0, 0x5e8 */
uint32_t pllmb_misc1; /* _PLLMB_MISC1_0, 0x5ec */
uint32_t pllx_misc4; /* _PLLX_MISC_4_0, 0x5f0 */
uint32_t pllx_misc5; /* _PLLX_MISC_5_0, 0x5f4 */
uint32_t _0x5f8[2];
uint32_t clk_source_xusb_core_host; /* _CLK_SOURCE_XUSB_CORE_HOST_0, 0x600 */
uint32_t clk_source_xusb_falcon; /* _CLK_SOURCE_XUSB_FALCON_0, 0x604 */
uint32_t clk_source_xusb_fs; /* _CLK_SOURCE_XUSB_FS_0, 0x608 */
uint32_t clk_source_xusb_core_dev; /* _CLK_SOURCE_XUSB_CORE_DEV_0, 0x60c */
uint32_t clk_source_xusb_ss; /* _CLK_SOURCE_XUSB_SS_0, 0x610 */
uint32_t clk_source_cilab; /* _CLK_SOURCE_CILAB_0, 0x614 */
uint32_t clk_source_cilcd; /* _CLK_SOURCE_CILCD_0, 0x618 */
uint32_t clk_source_cilef; /* _CLK_SOURCE_CILEF_0, 0x61c */
uint32_t clk_source_dsia_lp; /* _CLK_SOURCE_DSIA_LP_0, 0x620 */
uint32_t clk_source_dsib_lp; /* _CLK_SOURCE_DSIB_LP_0, 0x624 */
uint32_t clk_source_entropy; /* _CLK_SOURCE_ENTROPY_0, 0x628 */
uint32_t clk_source_dvfs_ref; /* _CLK_SOURCE_DVFS_REF_0, 0x62c */
uint32_t clk_source_dvfs_soc; /* _CLK_SOURCE_DVFS_SOC_0, 0x630 */
uint32_t _0x634[3];
uint32_t clk_source_emc_latency; /* _CLK_SOURCE_EMC_LATENCY_0, 0x640 */
uint32_t clk_source_soc_therm; /* _CLK_SOURCE_SOC_THERM_0, 0x644 */
uint32_t _0x648;
uint32_t clk_source_dmic1; /* _CLK_SOURCE_DMIC1_0, 0x64c */
uint32_t clk_source_dmic2; /* _CLK_SOURCE_DMIC2_0, 0x650 */
uint32_t _0x654;
uint32_t clk_source_vi_sensor2; /* _CLK_SOURCE_VI_SENSOR2_0, 0x658 */
uint32_t clk_source_i2c6; /* _CLK_SOURCE_I2C6_0, 0x65c */
uint32_t clk_source_mipibif; /* _CLK_SOURCE_MIPIBIF_0, 0x660 */
uint32_t clk_source_emc_dll; /* _CLK_SOURCE_EMC_DLL_0, 0x664 */
uint32_t _0x668;
uint32_t clk_source_uart_fst_mipi_cal; /* _CLK_SOURCE_UART_FST_MIPI_CAL_0, 0x66c */
uint32_t _0x670[2];
uint32_t clk_source_vic; /* _CLK_SOURCE_VIC_0, 0x678 */
uint32_t pllp_outc; /* _PLLP_OUTC_0, 0x67c */
uint32_t pllp_misc1; /* _PLLP_MISC1_0, 0x680 */
uint32_t _0x684[2];
uint32_t emc_div_clk_shaper_ctrl; /* _EMC_DIV_CLK_SHAPER_CTRL_0, 0x68c */
uint32_t emc_pllc_shaper_ctrl; /* _EMC_PLLC_SHAPER_CTRL_0, 0x690 */
uint32_t clk_source_sdmmc_legacy_tm; /* _CLK_SOURCE_SDMMC_LEGACY_TM_0, 0x694 */
uint32_t clk_source_nvdec; /* _CLK_SOURCE_NVDEC_0, 0x698 */
uint32_t clk_source_nvjpg; /* _CLK_SOURCE_NVJPG_0, 0x69c */
uint32_t clk_source_nvenc; /* _CLK_SOURCE_NVENC_0, 0x6a0 */
uint32_t plla1_base; /* _PLLA1_BASE_0, 0x6a4 */
uint32_t plla1_misc0; /* _PLLA1_MISC_0_0, 0x6a8 */
uint32_t plla1_misc1; /* _PLLA1_MISC_1_0, 0x6ac */
uint32_t plla1_misc2; /* _PLLA1_MISC_2_0, 0x6b0 */
uint32_t plla1_misc3; /* _PLLA1_MISC_3_0, 0x6b4 */
uint32_t audio_sync_clk_dmic3; /* _AUDIO_SYNC_CLK_DMIC3_0, 0x6b8 */
uint32_t clk_source_dmic3; /* _CLK_SOURCE_DMIC3_0, 0x6bc */
uint32_t clk_source_ape; /* _CLK_SOURCE_APE_0, 0x6c0 */
uint32_t clk_source_qspi; /* _CLK_SOURCE_QSPI_0, 0x6c4 */
uint32_t clk_source_vi_i2c; /* _CLK_SOURCE_VI_I2C_0, 0x6c8 */
uint32_t clk_source_usb2_hsic_trk; /* _CLK_SOURCE_USB2_HSIC_TRK_0, 0x6cc */
uint32_t clk_source_pex_sata_usb_rx_byp; /* _CLK_SOURCE_PEX_SATA_USB_RX_BYP_0, 0x6d0 */
uint32_t clk_source_maud; /* _CLK_SOURCE_MAUD_0, 0x6d4 */
uint32_t clk_source_tsecb; /* _CLK_SOURCE_TSECB_0, 0x6d8 */
uint32_t clk_cpug_misc1; /* _CLK_CPUG_MISC1_0, 0x6dc */
uint32_t aclk_burst_policy; /* _ACLK_BURST_POLICY_0, 0x6e0 */
uint32_t super_aclk_divider; /* _SUPER_ACLK_DIVIDER_0, 0x6e4 */
uint32_t nvenc_super_clk_divider; /* _NVENC_SUPER_CLK_DIVIDER_0, 0x6e8 */
uint32_t vi_super_clk_divider; /* _VI_SUPER_CLK_DIVIDER_0, 0x6ec */
uint32_t vic_super_clk_divider; /* _VIC_SUPER_CLK_DIVIDER_0, 0x6f0 */
uint32_t nvdec_super_clk_divider; /* _NVDEC_SUPER_CLK_DIVIDER_0, 0x6f4 */
uint32_t isp_super_clk_divider; /* _ISP_SUPER_CLK_DIVIDER_0, 0x6f8 */
uint32_t ispb_super_clk_divider; /* _ISPB_SUPER_CLK_DIVIDER_0, 0x6fc */
uint32_t nvjpg_super_clk_divider; /* _NVJPG_SUPER_CLK_DIVIDER_0, 0x700 */
uint32_t se_super_clk_divider; /* _SE_SUPER_CLK_DIVIDER_0, 0x704 */
uint32_t tsec_super_clk_divider; /* _TSEC_SUPER_CLK_DIVIDER_0, 0x708 */
uint32_t tsecb_super_clk_divider; /* _TSECB_SUPER_CLK_DIVIDER_0, 0x70c */
uint32_t clk_source_uartape; /* _CLK_SOURCE_UARTAPE_0, 0x710 */
uint32_t clk_cpug_misc2; /* _CLK_CPUG_MISC2_0, 0x714 */
uint32_t clk_source_dbgapb; /* _CLK_SOURCE_DBGAPB_0, 0x718 */
uint32_t clk_ccplex_cc4_ret_clk_enb; /* _CLK_CCPLEX_CC4_RET_CLK_ENB_0, 0x71c */
uint32_t actmon_cpu_clk; /* _ACTMON_CPU_CLK_0, 0x720 */
uint32_t clk_source_emc_safe; /* _CLK_SOURCE_EMC_SAFE_0, 0x724 */
uint32_t sdmmc2_pllc4_out0_shaper_ctrl; /* _SDMMC2_PLLC4_OUT0_SHAPER_CTRL_0, 0x728 */
uint32_t sdmmc2_pllc4_out1_shaper_ctrl; /* _SDMMC2_PLLC4_OUT1_SHAPER_CTRL_0, 0x72c */
uint32_t sdmmc2_pllc4_out2_shaper_ctrl; /* _SDMMC2_PLLC4_OUT2_SHAPER_CTRL_0, 0x730 */
uint32_t sdmmc2_div_clk_shaper_ctrl; /* _SDMMC2_DIV_CLK_SHAPER_CTRL_0, 0x734 */
uint32_t sdmmc4_pllc4_out0_shaper_ctrl; /* _SDMMC4_PLLC4_OUT0_SHAPER_CTRL_0, 0x738 */
uint32_t sdmmc4_pllc4_out1_shaper_ctrl; /* _SDMMC4_PLLC4_OUT1_SHAPER_CTRL_0, 0x73c */
uint32_t sdmmc4_pllc4_out2_shaper_ctrl; /* _SDMMC4_PLLC4_OUT2_SHAPER_CTRL_0, 0x740 */
uint32_t sdmmc4_div_clk_shaper_ctrl; /* _SDMMC4_DIV_CLK_SHAPER_CTRL_0, 0x744 */
} tegra_car_t;
static inline volatile tegra_car_t *car_get_regs(void) {
return (volatile tegra_car_t *)CAR_BASE;
}
void clk_enable(CarDevice dev);
void clk_disable(CarDevice dev);
void rst_enable(CarDevice dev);
void rst_disable(CarDevice dev);
void clkrst_enable(CarDevice dev);
void clkrst_disable(CarDevice dev);
void clkrst_reboot(CarDevice dev);
void clkrst_enable_fuse_regs(bool enable);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,57 @@
/*
* (C) Copyright 1997-2002 ELTEC Elektronik AG
* Frank Gottschling <fgottschling@eltec.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef _VIDEO_FB_H_
#define _VIDEO_FB_H_
#define CONSOLE_BG_COL 0x00
#define CONSOLE_FG_COL 0xa0
/* Try using the small font */
#define CONFIG_VIDEO_FONT_SMALL
/*
* Graphic Data Format (GDF) bits for VIDEO_DATA_FORMAT
*/
#define GDF__8BIT_INDEX 0
#define GDF_15BIT_555RGB 1
#define GDF_16BIT_565RGB 2
#define GDF_32BIT_X888RGB 3
#define GDF_24BIT_888RGB 4
#define GDF__8BIT_332RGB 5
#define CONFIG_VIDEO_FB_LITTLE_ENDIAN
#define CONFIG_VIDEO_VISIBLE_COLS 720
#define CONFIG_VIDEO_VISIBLE_ROWS 1280
#define CONFIG_VIDEO_COLS 768
#define CONFIG_VIDEO_PIXEL_SIZE 4
#define CONFIG_VIDEO_DATA_FORMAT GDF_32BIT_X888RGB /* BGR actually, but w/e */
int video_get_col(void);
int video_get_row(void);
int video_init(void *fb);
int video_resume(void *fb, int row, int col);
void video_puts(const char *s);
#endif /*_VIDEO_FB_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1089
fusee/fusee-mtc/src/emc.h Normal file

File diff suppressed because it is too large Load Diff

260
fusee/fusee-mtc/src/fuse.c Normal file
View File

@@ -0,0 +1,260 @@
/*
* Copyright (c) 2018-2019 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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "car.h"
#include "fuse.h"
#include "timers.h"
/* Prototypes for internal commands. */
void fuse_make_regs_visible(void);
void fuse_enable_power(void);
void fuse_disable_power(void);
void fuse_wait_idle(void);
/* Initialize the fuse driver */
void fuse_init(void) {
fuse_make_regs_visible();
fuse_secondary_private_key_disable();
fuse_disable_programming();
/* TODO: Overrides (iROM patches) and various reads happen here */
}
/* Make all fuse registers visible */
void fuse_make_regs_visible(void) {
clkrst_enable_fuse_regs(true);
}
/* Enable power to the fuse hardware array */
void fuse_enable_power(void) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse->FUSE_PWR_GOOD_SW = 1;
udelay(1);
}
/* Disable power to the fuse hardware array */
void fuse_disable_power(void) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse->FUSE_PWR_GOOD_SW = 0;
udelay(1);
}
/* Wait for the fuse driver to go idle */
void fuse_wait_idle(void) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
uint32_t ctrl_val = 0;
/* Wait for STATE_IDLE */
while ((ctrl_val & (0xF0000)) != 0x40000)
{
udelay(1);
ctrl_val = fuse->FUSE_CTRL;
}
}
/* Read a fuse from the hardware array */
uint32_t fuse_hw_read(uint32_t addr) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse_wait_idle();
/* Program the target address */
fuse->FUSE_REG_ADDR = addr;
/* Enable read operation in control register */
uint32_t ctrl_val = fuse->FUSE_CTRL;
ctrl_val &= ~0x3;
ctrl_val |= 0x1; /* Set FUSE_READ command */
fuse->FUSE_CTRL = ctrl_val;
fuse_wait_idle();
return fuse->FUSE_REG_READ;
}
/* Write a fuse in the hardware array */
void fuse_hw_write(uint32_t value, uint32_t addr) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse_wait_idle();
/* Program the target address and value */
fuse->FUSE_REG_ADDR = addr;
fuse->FUSE_REG_WRITE = value;
/* Enable write operation in control register */
uint32_t ctrl_val = fuse->FUSE_CTRL;
ctrl_val &= ~0x3;
ctrl_val |= 0x2; /* Set FUSE_WRITE command */
fuse->FUSE_CTRL = ctrl_val;
fuse_wait_idle();
}
/* Sense the fuse hardware array into the shadow cache */
void fuse_hw_sense(void) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse_wait_idle();
/* Enable sense operation in control register */
uint32_t ctrl_val = fuse->FUSE_CTRL;
ctrl_val &= ~0x3;
ctrl_val |= 0x3; /* Set FUSE_SENSE command */
fuse->FUSE_CTRL = ctrl_val;
fuse_wait_idle();
}
/* Disables all fuse programming. */
void fuse_disable_programming(void) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse->FUSE_DIS_PGM = 1;
}
/* Unknown exactly what this does, but it alters the contents read from the fuse cache. */
void fuse_secondary_private_key_disable(void) {
volatile tegra_fuse_t *fuse = fuse_get_regs();
fuse->FUSE_PRIVATEKEYDISABLE = 0x10;
}
/* Read the SKU info register from the shadow cache */
uint32_t fuse_get_sku_info(void) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
return fuse_chip->FUSE_SKU_INFO;
}
/* Read the bootrom patch version from a register in the shadow cache */
uint32_t fuse_get_bootrom_patch_version(void) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
return fuse_chip->FUSE_SOC_SPEEDO_1;
}
/* Read a spare bit register from the shadow cache */
uint32_t fuse_get_spare_bit(uint32_t idx) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (idx >= 32) {
return 0;
}
return fuse_chip->FUSE_SPARE_BIT[idx];
}
/* Read a reserved ODM register from the shadow cache */
uint32_t fuse_get_reserved_odm(uint32_t idx) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (idx >= 8) {
return 0;
}
return fuse_chip->FUSE_RESERVED_ODM[idx];
}
/* Derive the Device ID using values in the shadow cache */
uint64_t fuse_get_device_id(void) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
uint64_t device_id = 0;
uint64_t y_coord = fuse_chip->FUSE_Y_COORDINATE & 0x1FF;
uint64_t x_coord = fuse_chip->FUSE_X_COORDINATE & 0x1FF;
uint64_t wafer_id = fuse_chip->FUSE_WAFER_ID & 0x3F;
uint32_t lot_code = fuse_chip->FUSE_LOT_CODE_0;
uint64_t fab_code = fuse_chip->FUSE_FAB_CODE & 0x3F;
uint64_t derived_lot_code = 0;
for (unsigned int i = 0; i < 5; i++) {
derived_lot_code = (derived_lot_code * 0x24) + ((lot_code >> (24 - 6*i)) & 0x3F);
}
derived_lot_code &= 0x03FFFFFF;
device_id |= y_coord << 0;
device_id |= x_coord << 9;
device_id |= wafer_id << 18;
device_id |= derived_lot_code << 24;
device_id |= fab_code << 50;
return device_id;
}
/* Get the DRAM ID using values in the shadow cache */
uint32_t fuse_get_dram_id(void) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
return (fuse_chip->FUSE_RESERVED_ODM[4] >> 3) & 0x7;
}
/* Derive the Hardware Type using values in the shadow cache */
uint32_t fuse_get_hardware_type(void) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
/* This function is very different between 4.x and < 4.x */
uint32_t hardware_type = ((fuse_chip->FUSE_RESERVED_ODM[4] >> 7) & 2) | ((fuse_chip->FUSE_RESERVED_ODM[4] >> 2) & 1);
/* TODO: choose; if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
static const uint32_t types[] = {0,1,4,3};
hardware_type |= (fuse_chip->FUSE_RESERVED_ODM[4] >> 14) & 0x3C;
hardware_type--;
return hardware_type > 3 ? 4 : types[hardware_type];
} else {*/
if (hardware_type >= 1) {
return hardware_type > 2 ? 3 : hardware_type - 1;
} else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) {
return 0;
} else {
return 3;
}
// }
}
/* Derive the Retail Type using values in the shadow cache */
uint32_t fuse_get_retail_type(void) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
/* Retail type = IS_RETAIL | UNIT_TYPE */
uint32_t retail_type = ((fuse_chip->FUSE_RESERVED_ODM[4] >> 7) & 4) | (fuse_chip->FUSE_RESERVED_ODM[4] & 3);
if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */
return 1;
} else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */
return 0;
}
return 2; /* IS_RETAIL | DEV_UNIT */
}
/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */
void fuse_get_hardware_info(void *dst) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
uint32_t hw_info[0x4];
uint32_t unk_hw_fuse = fuse_chip->_0x120 & 0x3F;
uint32_t y_coord = fuse_chip->FUSE_Y_COORDINATE & 0x1FF;
uint32_t x_coord = fuse_chip->FUSE_X_COORDINATE & 0x1FF;
uint32_t wafer_id = fuse_chip->FUSE_WAFER_ID & 0x3F;
uint32_t lot_code_0 = fuse_chip->FUSE_LOT_CODE_0;
uint32_t lot_code_1 = fuse_chip->FUSE_LOT_CODE_1 & 0x0FFFFFFF;
uint32_t fab_code = fuse_chip->FUSE_FAB_CODE & 0x3F;
uint32_t vendor_code = fuse_chip->FUSE_VENDOR_CODE & 0xF;
/* Hardware Info = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID */
hw_info[0] = (uint32_t)((lot_code_1 << 30) | (wafer_id << 24) | (x_coord << 15) | (y_coord << 6) | (unk_hw_fuse));
hw_info[1] = (uint32_t)((lot_code_0 << 26) | (lot_code_1 >> 2));
hw_info[2] = (uint32_t)((fab_code << 26) | (lot_code_0 >> 6));
hw_info[3] = (uint32_t)(vendor_code);
memcpy(dst, hw_info, 0x10);
}

213
fusee/fusee-mtc/src/fuse.h Normal file
View File

@@ -0,0 +1,213 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_FUSE_H
#define FUSEE_FUSE_H
#define FUSE_BASE 0x7000F800
#define FUSE_CHIP_BASE (FUSE_BASE + 0x100)
#define MAKE_FUSE_REG(n) MAKE_REG32(FUSE_BASE + n)
#define MAKE_FUSE_CHIP_REG(n) MAKE_REG32(FUSE_CHIP_BASE + n)
typedef struct {
uint32_t FUSE_CTRL;
uint32_t FUSE_REG_ADDR;
uint32_t FUSE_REG_READ;
uint32_t FUSE_REG_WRITE;
uint32_t FUSE_TIME_RD1;
uint32_t FUSE_TIME_RD2;
uint32_t FUSE_TIME_PGM1;
uint32_t FUSE_TIME_PGM2;
uint32_t FUSE_PRIV2INTFC;
uint32_t FUSE_FUSEBYPASS;
uint32_t FUSE_PRIVATEKEYDISABLE;
uint32_t FUSE_DIS_PGM;
uint32_t FUSE_WRITE_ACCESS;
uint32_t FUSE_PWR_GOOD_SW;
uint32_t _0x38[0x32];
} tegra_fuse_t;
typedef struct {
uint32_t FUSE_PRODUCTION_MODE;
uint32_t _0x4;
uint32_t _0x8;
uint32_t _0xC;
uint32_t FUSE_SKU_INFO;
uint32_t FUSE_CPU_SPEEDO_0;
uint32_t FUSE_CPU_IDDQ;
uint32_t _0x1C;
uint32_t _0x20;
uint32_t _0x24;
uint32_t FUSE_FT_REV;
uint32_t FUSE_CPU_SPEEDO_1;
uint32_t FUSE_CPU_SPEEDO_2;
uint32_t FUSE_SOC_SPEEDO_0;
uint32_t FUSE_SOC_SPEEDO_1;
uint32_t FUSE_SOC_SPEEDO_2;
uint32_t FUSE_SOC_IDDQ;
uint32_t _0x44;
uint32_t FUSE_FA;
uint32_t _0x4C;
uint32_t _0x50;
uint32_t _0x54;
uint32_t _0x58;
uint32_t _0x5C;
uint32_t _0x60;
uint32_t FUSE_PUBLIC_KEY[0x8];
uint32_t FUSE_TSENSOR_1;
uint32_t FUSE_TSENSOR_2;
uint32_t _0x8C;
uint32_t FUSE_CP_REV;
uint32_t _0x94;
uint32_t FUSE_TSENSOR_0;
uint32_t FUSE_FIRST_BOOTROM_PATCH_SIZE_REG;
uint32_t FUSE_SECURITY_MODE;
uint32_t FUSE_PRIVATE_KEY[0x4];
uint32_t FUSE_DEVICE_KEY;
uint32_t _0xB8;
uint32_t _0xBC;
uint32_t FUSE_RESERVED_SW;
uint32_t FUSE_VP8_ENABLE;
uint32_t FUSE_RESERVED_ODM[0x8];
uint32_t _0xE8;
uint32_t _0xEC;
uint32_t FUSE_SKU_USB_CALIB;
uint32_t FUSE_SKU_DIRECT_CONFIG;
uint32_t _0xF8;
uint32_t _0xFC;
uint32_t FUSE_VENDOR_CODE;
uint32_t FUSE_FAB_CODE;
uint32_t FUSE_LOT_CODE_0;
uint32_t FUSE_LOT_CODE_1;
uint32_t FUSE_WAFER_ID;
uint32_t FUSE_X_COORDINATE;
uint32_t FUSE_Y_COORDINATE;
uint32_t _0x11C;
uint32_t _0x120;
uint32_t FUSE_SATA_CALIB;
uint32_t FUSE_GPU_IDDQ;
uint32_t FUSE_TSENSOR_3;
uint32_t _0x130;
uint32_t _0x134;
uint32_t _0x138;
uint32_t _0x13C;
uint32_t _0x140;
uint32_t _0x144;
uint32_t FUSE_OPT_SUBREVISION;
uint32_t _0x14C;
uint32_t _0x150;
uint32_t FUSE_TSENSOR_4;
uint32_t FUSE_TSENSOR_5;
uint32_t FUSE_TSENSOR_6;
uint32_t FUSE_TSENSOR_7;
uint32_t FUSE_OPT_PRIV_SEC_DIS;
uint32_t FUSE_PKC_DISABLE;
uint32_t _0x16C;
uint32_t _0x170;
uint32_t _0x174;
uint32_t _0x178;
uint32_t _0x17C;
uint32_t FUSE_TSENSOR_COMMON;
uint32_t _0x184;
uint32_t _0x188;
uint32_t _0x18C;
uint32_t _0x190;
uint32_t _0x194;
uint32_t _0x198;
uint32_t FUSE_DEBUG_AUTH_OVERRIDE;
uint32_t _0x1A0;
uint32_t _0x1A4;
uint32_t _0x1A8;
uint32_t _0x1AC;
uint32_t _0x1B0;
uint32_t _0x1B4;
uint32_t _0x1B8;
uint32_t _0x1BC;
uint32_t _0x1D0;
uint32_t FUSE_TSENSOR_8;
uint32_t _0x1D8;
uint32_t _0x1DC;
uint32_t _0x1E0;
uint32_t _0x1E4;
uint32_t _0x1E8;
uint32_t _0x1EC;
uint32_t _0x1F0;
uint32_t _0x1F4;
uint32_t _0x1F8;
uint32_t _0x1FC;
uint32_t _0x200;
uint32_t FUSE_RESERVED_CALIB;
uint32_t _0x208;
uint32_t _0x20C;
uint32_t _0x210;
uint32_t _0x214;
uint32_t _0x218;
uint32_t FUSE_TSENSOR_9;
uint32_t _0x220;
uint32_t _0x224;
uint32_t _0x228;
uint32_t _0x22C;
uint32_t _0x230;
uint32_t _0x234;
uint32_t _0x238;
uint32_t _0x23C;
uint32_t _0x240;
uint32_t _0x244;
uint32_t _0x248;
uint32_t _0x24C;
uint32_t FUSE_USB_CALIB_EXT;
uint32_t _0x254;
uint32_t _0x258;
uint32_t _0x25C;
uint32_t _0x260;
uint32_t _0x264;
uint32_t _0x268;
uint32_t _0x26C;
uint32_t _0x270;
uint32_t _0x274;
uint32_t _0x278;
uint32_t _0x27C;
uint32_t FUSE_SPARE_BIT[0x20];
} tegra_fuse_chip_t;
static inline volatile tegra_fuse_t *fuse_get_regs(void) {
return (volatile tegra_fuse_t *)FUSE_BASE;
}
static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) {
return (volatile tegra_fuse_chip_t *)FUSE_CHIP_BASE;
}
void fuse_init(void);
uint32_t fuse_hw_read(uint32_t addr);
void fuse_hw_write(uint32_t value, uint32_t addr);
void fuse_hw_sense(void);
void fuse_disable_programming(void);
void fuse_secondary_private_key_disable(void);
uint32_t fuse_get_sku_info(void);
uint32_t fuse_get_spare_bit(uint32_t idx);
uint32_t fuse_get_reserved_odm(uint32_t idx);
uint32_t fuse_get_bootrom_patch_version(void);
uint64_t fuse_get_device_id(void);
uint32_t fuse_get_dram_id(void);
uint32_t fuse_get_hardware_type(void);
uint32_t fuse_get_retail_type(void);
void fuse_get_hardware_info(void *dst);
#endif

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2018-2019 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 <stdint.h>
#include <stddef.h>
#include <string.h>
#include <malloc.h>
#include <sys/iosupport.h>
#include "stage2.h"
#include "utils.h"
void __libc_init_array(void);
void __libc_fini_array(void);
extern uint8_t __bss_start__[], __bss_end__[];
extern uint8_t __heap_start__[], __heap_end__[];
extern char *fake_heap_start;
extern char *fake_heap_end;
int __program_argc;
void **__program_argv;
void __program_exit(int rc);
static void __program_parse_argc_argv(int argc, char *argdata);
static void __program_cleanup_argv(void);
static void __program_init_heap(void) {
fake_heap_start = (char*)__heap_start__;
fake_heap_end = (char*)__heap_end__;
}
static void __program_init_newlib_hooks(void) {
__syscalls.exit = __program_exit; /* For exit, etc. */
}
void __program_init(int argc, char *argdata) {
/* Zero-fill the .bss section */
memset(__bss_start__, 0, __bss_end__ - __bss_start__);
__program_init_heap();
__program_init_newlib_hooks();
__program_parse_argc_argv(argc, argdata);
__libc_init_array();
}
void __program_exit(int rc) {
__libc_fini_array();
__program_cleanup_argv();
}
static void __program_parse_argc_argv(int argc, char *argdata) {
__program_argc = argc;
__program_argv = malloc(argc * sizeof(void **));
if (__program_argv == NULL) {
generic_panic();
}
__program_argv[0] = malloc(sizeof(stage2_mtc_args_t));
if (__program_argv[0] == NULL) {
generic_panic();
}
memcpy(__program_argv[0], argdata, sizeof(stage2_mtc_args_t));
}
static void __program_cleanup_argv(void) {
for (int i = 0; i < __program_argc; i++) {
free(__program_argv[i]);
__program_argv[i] = NULL;
}
free(__program_argv);
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2018-2019 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 "log.h"
#include "../display/video_fb.h"
#include "vsprintf.h"
/* default log level for screen output */
ScreenLogLevel g_screen_log_level = SCREEN_LOG_LEVEL_NONE;
void log_set_log_level(ScreenLogLevel log_level) {
g_screen_log_level = log_level;
}
ScreenLogLevel log_get_log_level() {
return g_screen_log_level;
}
void log_to_uart(const char *message) {
/* TODO: add UART logging */
}
static void print_to_screen(ScreenLogLevel screen_log_level, char *message) {
/* don't print to screen if below log level */
if(screen_log_level > g_screen_log_level) return;
video_puts(message);
}
/**
* vprintk - logs a message and prints it to screen based on its screen_log_level
*
* If the level is below g_screen_log_level it will not be shown but logged to UART
* This text will not be colored or prefixed
* UART is TODO
*/
void vprint(ScreenLogLevel screen_log_level, const char *fmt, va_list args)
{
char buf[PRINT_MESSAGE_MAX_LENGTH];
vsnprintf(buf, PRINT_MESSAGE_MAX_LENGTH, fmt, args);
/* we don't need that flag here, but if it gets used, strip it so we print correctly */
screen_log_level &= ~SCREEN_LOG_LEVEL_NO_PREFIX;
/* log to UART */
log_to_uart(buf);
print_to_screen(screen_log_level, buf);
}
static void add_prefix(ScreenLogLevel screen_log_level, const char *fmt, char *buf) {
char typebuf[] = "[%s] %s";
/* apply prefix and append message format */
/* TODO: add coloring to the output */
switch(screen_log_level)
{
case SCREEN_LOG_LEVEL_ERROR:
snprintf(buf, PRINT_MESSAGE_MAX_LENGTH, typebuf, "ERROR", fmt);
break;
case SCREEN_LOG_LEVEL_WARNING:
snprintf(buf, PRINT_MESSAGE_MAX_LENGTH, typebuf, "WARNING", fmt);
break;
case SCREEN_LOG_LEVEL_MANDATORY:
snprintf(buf, PRINT_MESSAGE_MAX_LENGTH, "%s", fmt);
break;
case SCREEN_LOG_LEVEL_INFO:
snprintf(buf, PRINT_MESSAGE_MAX_LENGTH, typebuf, "INFO", fmt);
break;
case SCREEN_LOG_LEVEL_DEBUG:
snprintf(buf, PRINT_MESSAGE_MAX_LENGTH, typebuf, "DEBUG", fmt);
break;
default:
break;
}
}
/**
* print - logs a message and prints it to screen based on its screen_log_level
*
* If the level is below g_screen_log_level it will not be shown but logged to UART
* Use SCREEN_LOG_LEVEL_NO_PREFIX if you don't want a prefix to be added
* UART is TODO
*/
void print(ScreenLogLevel screen_log_level, const char * fmt, ...)
{
char buf[PRINT_MESSAGE_MAX_LENGTH] = {};
char message[PRINT_MESSAGE_MAX_LENGTH] = {};
/* TODO: make splash disappear if level > MANDATORY */
/* make prefix free messages with log_level possible */
if(screen_log_level & SCREEN_LOG_LEVEL_NO_PREFIX) {
/* remove the NO_PREFIX flag so the enum can be recognized later on */
screen_log_level &= ~SCREEN_LOG_LEVEL_NO_PREFIX;
snprintf(buf, PRINT_MESSAGE_MAX_LENGTH, "%s", fmt);
}
else {
add_prefix(screen_log_level, fmt, buf);
}
/* input arguments */
va_list args;
va_start(args, fmt);
vsnprintf(message, PRINT_MESSAGE_MAX_LENGTH, buf, args);
va_end(args);
/* log to UART */
log_to_uart(message);
print_to_screen(screen_log_level, message);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_LOG_H
#define FUSEE_LOG_H
#define PRINT_MESSAGE_MAX_LENGTH 512
#include <stdarg.h>
typedef enum {
SCREEN_LOG_LEVEL_NONE = 0,
SCREEN_LOG_LEVEL_ERROR = 1,
SCREEN_LOG_LEVEL_WARNING = 2,
SCREEN_LOG_LEVEL_MANDATORY = 3, /* no log prefix */
SCREEN_LOG_LEVEL_INFO = 4,
SCREEN_LOG_LEVEL_DEBUG = 5,
SCREEN_LOG_LEVEL_NO_PREFIX = 0x100 /* OR this to your LOG_LEVEL to prevent prefix creation */
} ScreenLogLevel;
extern ScreenLogLevel g_screen_log_level;
void log_set_log_level(ScreenLogLevel screen_log_level);
ScreenLogLevel log_get_log_level();
void log_to_uart(const char *message);
void vprint(ScreenLogLevel screen_log_level, const char *fmt, va_list args);
void print(ScreenLogLevel screen_log_level, const char* fmt, ...);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2011 Andrei Warkentin <andrey.warkentin@gmail.com>
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdarg.h>
#include <stdlib.h>
#ifndef VSPRINTF_H
#define VSPRINTF_H
struct va_format {
const char *fmt;
va_list *va;
};
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
int sprintf(char *buf, const char *fmt, ...);
int scnprintf(char *buf, size_t size, const char *fmt, ...);
int snprintf(char *buf, size_t size, const char *fmt, ...);
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
int sscanf(const char *buf, const char *fmt, ...);
#endif /* VSPRINTF_H */

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2018-2019 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 <string.h>
#include "mtc.h"
#include "stage2.h"
#include "display/video_fb.h"
static void *g_framebuffer;
static __attribute__((__aligned__(0x200))) stage2_mtc_args_t g_mtc_args_store;
static stage2_mtc_args_t *g_mtc_args;
/* Allow for main(int argc, void **argv) signature. */
#pragma GCC diagnostic ignored "-Wmain"
int main(int argc, void **argv) {
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
/* Check argc. */
if (argc != MTC_ARGC) {
return 1;
}
/* Extract arguments from argv. */
g_mtc_args = &g_mtc_args_store;
memcpy(g_mtc_args, (stage2_mtc_args_t *)argv[MTC_ARGV_ARGUMENT_STRUCT], sizeof(*g_mtc_args));
log_level = g_mtc_args->log_level;
/* Override the global logging level. */
log_set_log_level(log_level);
if (log_level != SCREEN_LOG_LEVEL_NONE) {
/* Set framebuffer address. */
g_framebuffer = (void *)0xC0000000;
/* Zero-fill the framebuffer and register it as printk provider. */
video_init(g_framebuffer);
}
/* Train DRAM. */
train_dram();
return 0;
}

167
fusee/fusee-mtc/src/mc.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 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 "mc.h"
#include "car.h"
#include "timers.h"
void mc_config_tsec_carveout(uint32_t bom, uint32_t size1mb, bool lock)
{
MAKE_MC_REG(MC_SEC_CARVEOUT_BOM) = bom;
MAKE_MC_REG(MC_SEC_CARVEOUT_SIZE_MB) = size1mb;
if (lock)
MAKE_MC_REG(MC_SEC_CARVEOUT_REG_CTRL) = 1;
}
void mc_config_carveout()
{
*(volatile uint32_t *)0x8005FFFC = 0xC0EDBBCC;
MAKE_MC_REG(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = 1;
MAKE_MC_REG(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0;
MAKE_MC_REG(MC_VIDEO_PROTECT_BOM) = 0;
MAKE_MC_REG(MC_VIDEO_PROTECT_SIZE_MB) = 0;
MAKE_MC_REG(MC_VIDEO_PROTECT_REG_CTRL) = 1;
mc_config_tsec_carveout(0, 0, true);
MAKE_MC_REG(MC_MTS_CARVEOUT_BOM) = 0;
MAKE_MC_REG(MC_MTS_CARVEOUT_SIZE_MB) = 0;
MAKE_MC_REG(MC_MTS_CARVEOUT_ADR_HI) = 0;
MAKE_MC_REG(MC_MTS_CARVEOUT_REG_CTRL) = 1;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_BOM) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_BOM_HI) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_BOM) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_BOM_HI) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR));
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = (BIT(CSR_GPUSRD2) | BIT(CSW_GPUSWR2));
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_BOM) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_BOM_HI) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_BOM) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_BOM_HI) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F;
}
void mc_config_carveout_finalize()
{
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR));
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = (BIT(CSR_GPUSRD2) | BIT(CSW_GPUSWR2));
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MAKE_MC_REG(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
}
void mc_enable_ahb_redirect()
{
volatile tegra_car_t *car = car_get_regs();
car->lvl2_clk_gate_ovrd = ((car->lvl2_clk_gate_ovrd & 0xFFF7FFFF) | 0x80000);
MAKE_MC_REG(MC_IRAM_BOM) = 0x40000000;
MAKE_MC_REG(MC_IRAM_TOM) = 0x4003F000;
}
void mc_disable_ahb_redirect()
{
volatile tegra_car_t *car = car_get_regs();
MAKE_MC_REG(MC_IRAM_BOM) = 0xFFFFF000;
MAKE_MC_REG(MC_IRAM_TOM) = 0;
car->lvl2_clk_gate_ovrd &= 0xFFF7FFFF;
}
void mc_enable()
{
volatile tegra_car_t *car = car_get_regs();
/* Set EMC clock source. */
car->clk_source_emc = ((car->clk_source_emc & 0x1FFFFFFF) | 0x40000000);
/* Enable MIPI CAL clock. */
car->clk_enb_h_set = ((car->clk_enb_h_set & 0xFDFFFFFF) | 0x2000000);
/* Enable MC clock. */
car->clk_enb_h_set = ((car->clk_enb_h_set & 0xFFFFFFFE) | 1);
/* Enable EMC DLL clock. */
car->clk_enb_x_set = ((car->clk_enb_x_set & 0xFFFFBFFF) | 0x4000);
/* Clear EMC and MC reset. */
car->rst_dev_h_set = 0x2000001;
udelay(5);
mc_disable_ahb_redirect();
}

605
fusee/fusee-mtc/src/mc.h Normal file
View File

@@ -0,0 +1,605 @@
/*
* Copyright (c) 2014, NVIDIA Corporation. All rights reserved.
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_MC_H_
#define FUSEE_MC_H_
#include <stdint.h>
#include <stdbool.h>
#define MC_BASE 0x70019000
#define MAKE_MC_REG(n) MAKE_REG32(MC_BASE + n)
#define MC_INTSTATUS 0x0
#define MC_INTMASK 0x4
#define MC_ERR_STATUS 0x8
#define MC_ERR_ADR 0xc
#define MC_SMMU_CONFIG 0x10
#define MC_SMMU_TLB_CONFIG 0x14
#define MC_SMMU_PTC_CONFIG 0x18
#define MC_SMMU_PTB_ASID 0x1c
#define MC_SMMU_PTB_DATA 0x20
#define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_ASID_SECURITY_1 0x3c
#define MC_SMMU_ASID_SECURITY_2 0x9e0
#define MC_SMMU_ASID_SECURITY_3 0x9e4
#define MC_SMMU_ASID_SECURITY_4 0x9e8
#define MC_SMMU_ASID_SECURITY_5 0x9ec
#define MC_SMMU_ASID_SECURITY_6 0x9f0
#define MC_SMMU_ASID_SECURITY_7 0x9f4
#define MC_SMMU_AFI_ASID 0x238
#define MC_SMMU_AVPC_ASID 0x23c
#define MC_SMMU_TSEC_ASID 0x294
#define MC_SMMU_PPCS1_ASID 0x298
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0
#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4
#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8
#define MC_PCFIFO_CLIENT_CONFIG3 0xddc
#define MC_PCFIFO_CLIENT_CONFIG4 0xde0
#define MC_EMEM_CFG 0x50
#define MC_EMEM_ADR_CFG 0x54
#define MC_EMEM_ADR_CFG_DEV0 0x58
#define MC_EMEM_ADR_CFG_DEV1 0x5c
#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60
#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64
#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68
#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c
#define MC_SECURITY_CFG0 0x70
#define MC_SECURITY_CFG1 0x74
#define MC_SECURITY_CFG3 0x9bc
#define MC_SECURITY_RSV 0x7c
#define MC_EMEM_ARB_CFG 0x90
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
#define MC_EMEM_ARB_TIMING_RCD 0x98
#define MC_EMEM_ARB_TIMING_RP 0x9c
#define MC_EMEM_ARB_TIMING_RC 0xa0
#define MC_EMEM_ARB_TIMING_RAS 0xa4
#define MC_EMEM_ARB_TIMING_FAW 0xa8
#define MC_EMEM_ARB_TIMING_RRD 0xac
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
#define MC_EMEM_ARB_TIMING_R2R 0xb8
#define MC_EMEM_ARB_TIMING_W2W 0xbc
#define MC_EMEM_ARB_TIMING_R2W 0xc0
#define MC_EMEM_ARB_TIMING_W2R 0xc4
#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0
#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4
#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0
#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4
#define MC_EMEM_ARB_DA_TURNS 0xd0
#define MC_EMEM_ARB_DA_COVERS 0xd4
#define MC_EMEM_ARB_MISC0 0xd8
#define MC_EMEM_ARB_MISC1 0xdc
#define MC_EMEM_ARB_MISC2 0xc8
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0
#define MC_EMEM_ARB_OVERRIDE 0xe8
#define MC_EMEM_ARB_RSV 0xec
#define MC_CLKEN_OVERRIDE 0xf4
#define MC_TIMING_CONTROL_DBG 0xf8
#define MC_TIMING_CONTROL 0xfc
#define MC_STAT_CONTROL 0x100
#define MC_STAT_STATUS 0x104
#define MC_STAT_EMC_CLOCK_LIMIT 0x108
#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c
#define MC_STAT_EMC_CLOCKS 0x110
#define MC_STAT_EMC_CLOCKS_MSBS 0x114
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c
#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0
#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0
#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120
#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160
#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128
#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168
#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c
#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c
#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130
#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170
#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134
#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88
#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174
#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c
#define MC_STAT_EMC_SET0_COUNT 0x138
#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c
#define MC_STAT_EMC_SET1_COUNT 0x178
#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c
#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140
#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144
#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180
#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184
#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148
#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c
#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188
#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c
#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150
#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190
#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8
#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc
#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8
#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc
#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0
#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0
#define MC_CLIENT_HOTRESET_CTRL 0x200
#define MC_CLIENT_HOTRESET_CTRL_1 0x970
#define MC_CLIENT_HOTRESET_STATUS 0x204
#define MC_CLIENT_HOTRESET_STATUS_1 0x974
#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208
#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c
#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210
#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214
#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94
#define MC_EMEM_ARB_HYSTERESIS_0 0x218
#define MC_EMEM_ARB_HYSTERESIS_1 0x21c
#define MC_EMEM_ARB_HYSTERESIS_2 0x220
#define MC_EMEM_ARB_HYSTERESIS_3 0x224
#define MC_EMEM_ARB_HYSTERESIS_4 0xb84
#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0
#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4
#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8
#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc
#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0
#define MC_EMEM_ARB_DHYST_CTRL 0xbcc
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec
#define MC_RESERVED_RSV 0x3fc
#define MC_DISB_EXTRA_SNAP_LEVELS 0x408
#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4
#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0
#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18
#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08
#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10
#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c
#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40
#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414
#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc
#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c
#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14
#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0
#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac
#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c
#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48
#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8
#define MC_USBX_EXTRA_SNAP_LEVELS 0x404
#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8
#define MC_SD_EXTRA_SNAP_LEVELS 0xa04
#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c
#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8
#define MC_GK_EXTRA_SNAP_LEVELS 0xa00
#define MC_VE2_EXTRA_SNAP_LEVELS 0x410
#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44
#define MC_VIDEO_PROTECT_BOM 0x648
#define MC_VIDEO_PROTECT_SIZE_MB 0x64c
#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978
#define MC_VIDEO_PROTECT_REG_CTRL 0x650
#define MC_ERR_VPR_STATUS 0x654
#define MC_ERR_VPR_ADR 0x658
#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418
#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590
#define MC_IRAM_BOM 0x65c
#define MC_IRAM_TOM 0x660
#define MC_IRAM_ADR_HI 0x980
#define MC_IRAM_REG_CTRL 0x964
#define MC_EMEM_CFG_ACCESS_CTRL 0x664
#define MC_TZ_SECURITY_CTRL 0x668
#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c
#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4
#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc
#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8
#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80
#define MC_SEC_CARVEOUT_BOM 0x670
#define MC_SEC_CARVEOUT_SIZE_MB 0x674
#define MC_SEC_CARVEOUT_ADR_HI 0x9d4
#define MC_SEC_CARVEOUT_REG_CTRL 0x678
#define MC_ERR_SEC_STATUS 0x67c
#define MC_ERR_SEC_ADR 0x680
#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684
#define MC_STUTTER_CONTROL 0x688
#define MC_RESERVED_RSV_1 0x958
#define MC_DVFS_PIPE_SELECT 0x95c
#define MC_AHB_PTSA_MIN 0x4e0
#define MC_AUD_PTSA_MIN 0x54c
#define MC_MLL_MPCORER_PTSA_RATE 0x44c
#define MC_RING2_PTSA_RATE 0x440
#define MC_USBD_PTSA_RATE 0x530
#define MC_USBX_PTSA_MIN 0x528
#define MC_USBD_PTSA_MIN 0x534
#define MC_APB_PTSA_MAX 0x4f0
#define MC_JPG_PTSA_RATE 0x584
#define MC_DIS_PTSA_MIN 0x420
#define MC_AVP_PTSA_MAX 0x4fc
#define MC_AVP_PTSA_RATE 0x4f4
#define MC_RING1_PTSA_MIN 0x480
#define MC_DIS_PTSA_MAX 0x424
#define MC_SD_PTSA_MAX 0x4d8
#define MC_MSE_PTSA_RATE 0x4c4
#define MC_VICPC_PTSA_MIN 0x558
#define MC_PCX_PTSA_MAX 0x4b4
#define MC_ISP_PTSA_RATE 0x4a0
#define MC_A9AVPPC_PTSA_MIN 0x48c
#define MC_RING2_PTSA_MAX 0x448
#define MC_AUD_PTSA_RATE 0x548
#define MC_HOST_PTSA_MIN 0x51c
#define MC_MLL_MPCORER_PTSA_MAX 0x454
#define MC_SD_PTSA_MIN 0x4d4
#define MC_RING1_PTSA_RATE 0x47c
#define MC_JPG_PTSA_MIN 0x588
#define MC_HDAPC_PTSA_MIN 0x62c
#define MC_AVP_PTSA_MIN 0x4f8
#define MC_JPG_PTSA_MAX 0x58c
#define MC_VE_PTSA_MAX 0x43c
#define MC_DFD_PTSA_MAX 0x63c
#define MC_VICPC_PTSA_RATE 0x554
#define MC_GK_PTSA_MAX 0x544
#define MC_VICPC_PTSA_MAX 0x55c
#define MC_SDM_PTSA_MAX 0x624
#define MC_SAX_PTSA_RATE 0x4b8
#define MC_PCX_PTSA_MIN 0x4b0
#define MC_APB_PTSA_MIN 0x4ec
#define MC_GK2_PTSA_MIN 0x614
#define MC_PCX_PTSA_RATE 0x4ac
#define MC_RING1_PTSA_MAX 0x484
#define MC_HDAPC_PTSA_RATE 0x628
#define MC_MLL_MPCORER_PTSA_MIN 0x450
#define MC_GK2_PTSA_MAX 0x618
#define MC_AUD_PTSA_MAX 0x550
#define MC_GK2_PTSA_RATE 0x610
#define MC_ISP_PTSA_MAX 0x4a8
#define MC_DISB_PTSA_RATE 0x428
#define MC_VE2_PTSA_MAX 0x49c
#define MC_DFD_PTSA_MIN 0x638
#define MC_FTOP_PTSA_RATE 0x50c
#define MC_A9AVPPC_PTSA_RATE 0x488
#define MC_VE2_PTSA_MIN 0x498
#define MC_USBX_PTSA_MAX 0x52c
#define MC_DIS_PTSA_RATE 0x41c
#define MC_USBD_PTSA_MAX 0x538
#define MC_A9AVPPC_PTSA_MAX 0x490
#define MC_USBX_PTSA_RATE 0x524
#define MC_FTOP_PTSA_MAX 0x514
#define MC_HDAPC_PTSA_MAX 0x630
#define MC_SD_PTSA_RATE 0x4d0
#define MC_DFD_PTSA_RATE 0x634
#define MC_FTOP_PTSA_MIN 0x510
#define MC_SDM_PTSA_RATE 0x61c
#define MC_AHB_PTSA_RATE 0x4dc
#define MC_SMMU_SMMU_PTSA_MAX 0x460
#define MC_RING2_PTSA_MIN 0x444
#define MC_SDM_PTSA_MIN 0x620
#define MC_APB_PTSA_RATE 0x4e8
#define MC_MSE_PTSA_MIN 0x4c8
#define MC_HOST_PTSA_RATE 0x518
#define MC_VE_PTSA_RATE 0x434
#define MC_AHB_PTSA_MAX 0x4e4
#define MC_SAX_PTSA_MIN 0x4bc
#define MC_SMMU_SMMU_PTSA_MIN 0x45c
#define MC_ISP_PTSA_MIN 0x4a4
#define MC_HOST_PTSA_MAX 0x520
#define MC_SAX_PTSA_MAX 0x4c0
#define MC_VE_PTSA_MIN 0x438
#define MC_GK_PTSA_MIN 0x540
#define MC_MSE_PTSA_MAX 0x4cc
#define MC_DISB_PTSA_MAX 0x430
#define MC_DISB_PTSA_MIN 0x42c
#define MC_SMMU_SMMU_PTSA_RATE 0x458
#define MC_VE2_PTSA_RATE 0x494
#define MC_GK_PTSA_RATE 0x53c
#define MC_PTSA_GRANT_DECREMENT 0x960
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4
#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8
#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0
#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698
#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec
#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0
#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8
#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0
#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4
#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c
#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4
#define MC_LATENCY_ALLOWANCE_SATA_0 0x350
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4
#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
#define MC_LATENCY_ALLOWANCE_HDA_0 0x318
#define MC_MIN_LENGTH_APE_0 0xb34
#define MC_MIN_LENGTH_DCB_2 0x8a8
#define MC_MIN_LENGTH_A9AVP_0 0x950
#define MC_MIN_LENGTH_TSEC_0 0x93c
#define MC_MIN_LENGTH_DC_1 0x898
#define MC_MIN_LENGTH_AXIAP_0 0x94c
#define MC_MIN_LENGTH_ISP2B_0 0x930
#define MC_MIN_LENGTH_VI2_0 0x944
#define MC_MIN_LENGTH_DCB_0 0x8a0
#define MC_MIN_LENGTH_DCB_1 0x8a4
#define MC_MIN_LENGTH_PPCS_1 0x8f4
#define MC_MIN_LENGTH_NVJPG_0 0xb3c
#define MC_MIN_LENGTH_HDA_0 0x8c4
#define MC_MIN_LENGTH_NVENC_0 0x8d4
#define MC_MIN_LENGTH_SDMMC_0 0xb18
#define MC_MIN_LENGTH_ISP2B_1 0x934
#define MC_MIN_LENGTH_HC_1 0x8c0
#define MC_MIN_LENGTH_DC_3 0xb20
#define MC_MIN_LENGTH_AVPC_0 0x890
#define MC_MIN_LENGTH_VIC_0 0x940
#define MC_MIN_LENGTH_ISP2_0 0x91c
#define MC_MIN_LENGTH_HC_0 0x8bc
#define MC_MIN_LENGTH_SE_0 0xb38
#define MC_MIN_LENGTH_NVDEC_0 0xb30
#define MC_MIN_LENGTH_SATA_0 0x8fc
#define MC_MIN_LENGTH_DC_0 0x894
#define MC_MIN_LENGTH_XUSB_1 0x92c
#define MC_MIN_LENGTH_DC_2 0x89c
#define MC_MIN_LENGTH_SDMMCAA_0 0xb14
#define MC_MIN_LENGTH_GPU_0 0xb04
#define MC_MIN_LENGTH_ETR_0 0xb44
#define MC_MIN_LENGTH_AFI_0 0x88c
#define MC_MIN_LENGTH_PPCS_0 0x8f0
#define MC_MIN_LENGTH_ISP2_1 0x920
#define MC_MIN_LENGTH_XUSB_0 0x928
#define MC_MIN_LENGTH_MPCORE_0 0x8cc
#define MC_MIN_LENGTH_TSECB_0 0xb48
#define MC_MIN_LENGTH_SDMMCA_0 0xb10
#define MC_MIN_LENGTH_GPU2_0 0xb40
#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c
#define MC_MIN_LENGTH_PTC_0 0x8f8
#define MC_EMEM_ARB_OVERRIDE_1 0x968
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988
#define MC_EMEM_ARB_STATS_0 0x990
#define MC_EMEM_ARB_STATS_1 0x994
#define MC_MTS_CARVEOUT_BOM 0x9a0
#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4
#define MC_MTS_CARVEOUT_ADR_HI 0x9a8
#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac
#define MC_ERR_MTS_STATUS 0x9b0
#define MC_ERR_MTS_ADR 0x9b4
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74
#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10
#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c
#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4
#define MC_SECURITY_CARVEOUT2_CFG0 0xc58
#define MC_SECURITY_CARVEOUT1_CFG0 0xc08
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68
#define MC_SECURITY_CARVEOUT3_BOM 0xcac
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60
#define MC_SECURITY_CARVEOUT3_CFG0 0xca8
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88
#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64
#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50
#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14
#define MC_SECURITY_CARVEOUT1_BOM 0xc0c
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c
#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8
#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60
#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80
#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc
#define MC_SECURITY_CARVEOUT4_BOM 0xcfc
#define MC_SECURITY_CARVEOUT5_CFG0 0xd48
#define MC_SECURITY_CARVEOUT2_BOM 0xc5c
#define MC_SECURITY_CARVEOUT5_BOM 0xd4c
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0
#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
#define MC_DA_CONFIG0 0x9dc
/* Memory Controller clients */
#define CLIENT_ACCESS_NUM_CLIENTS 32
typedef enum {
/* _ACCESS0 */
CSR_PTCR = (0 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAY0A = (1 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAY0AB = (2 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAY0B = (3 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAY0BB = (4 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAY0C = (5 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAY0CB = (6 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_AFIR = (14 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_AVPCARM7R = (15 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAYHC = (16 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_DISPLAYHCB = (17 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_HDAR = (21 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_HOST1XDMAR = (22 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_HOST1XR = (23 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_NVENCSRD = (28 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_PPCSAHBDMAR = (29 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_PPCSAHBSLVR = (30 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
CSR_SATAR = (31 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
/* _ACCESS1 */
CSR_VDEBSEVR = (34 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSR_VDEMBER = (35 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSR_VDEMCER = (36 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSR_VDETPER = (37 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSR_MPCORELPR = (38 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSR_MPCORER = (39 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_NVENCSWR = (43 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_AFIW = (49 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_AVPCARM7W = (50 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_HDAW = (53 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_HOST1XW = (54 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_MPCORELPW = (56 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_MPCOREW = (57 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_PPCSAHBDMAW = (59 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_PPCSAHBSLVW = (60 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_SATAW = (61 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_VDEBSEVW = (62 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
CSW_VDEDBGW = (63 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
/* _ACCESS2 */
CSW_VDEMBEW = (64 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_VDETPMW = (65 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_ISPRA = (68 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_ISPWA = (70 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_ISPWB = (71 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_XUSB_HOSTR = (74 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_XUSB_HOSTW = (75 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_XUSB_DEVR = (76 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_XUSB_DEVW = (77 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_ISPRAB = (78 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_ISPWAB = (80 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_ISPWBB = (81 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_TSECSRD = (84 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_TSECSWR = (85 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_A9AVPSCR = (86 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_A9AVPSCW = (87 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_GPUSRD = (88 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSW_GPUSWR = (89 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
CSR_DISPLAYT = (90 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
/* _ACCESS3 */
CSR_SDMMCRA = (96 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_SDMMCRAA = (97 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_SDMMCR = (98 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_SDMMCRAB = (99 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_SDMMCWA = (100 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_SDMMCWAA = (101 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_SDMMCW = (102 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_SDMMCWAB = (103 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_VICSRD = (108 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_VICSWR = (109 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_VIW = (114 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_DISPLAYD = (115 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_NVDECSRD = (120 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_NVDECSWR = (121 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_APER = (122 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_APEW = (123 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSR_NVJPGSRD = (126 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
CSW_NVJPGSWR = (127 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
/* _ACCESS4 */
CSR_SESRD = (128 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSW_SESWR = (129 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSR_AXIAPR = (130 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSW_AXIAPW = (131 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSR_ETRR = (132 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSW_ETRW = (133 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSR_TSECSRDB = (134 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSW_TSECSWRB = (135 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSR_GPUSRD2 = (136 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
CSW_GPUSWR2 = (137 - (CLIENT_ACCESS_NUM_CLIENTS * 4))
} McClient;
void mc_config_tsec_carveout(uint32_t bom, uint32_t size1mb, bool lock);
void mc_config_carveout();
void mc_config_carveout_finalize();
void mc_enable_ahb_redirect();
void mc_disable_ahb_redirect();
void mc_enable();
#endif

View File

@@ -3706,7 +3706,7 @@ static int train_one(int z_val, uint32_t next_rate, uint32_t current_rate, tegra
return 0; return 0;
} }
void train_dram() { void train_dram(void) {
volatile tegra_car_t *car = car_get_regs(); volatile tegra_car_t *car = car_get_regs();
tegra_emc_timing_t *timing_tables; tegra_emc_timing_t *timing_tables;

View File

@@ -754,6 +754,6 @@ enum {
}; };
/* Train all possible DRAM sequences. */ /* Train all possible DRAM sequences. */
void train_dram(); void train_dram(void);
#endif #endif

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_STAGE2_H
#define FUSEE_STAGE2_H
#include "lib/log.h"
#define MTC_ARGV_ARGUMENT_STRUCT 0
#define MTC_ARGC 1
typedef struct {
ScreenLogLevel log_level;
} stage2_mtc_args_t;
#endif

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.macro CLEAR_GPR_REG_ITER
mov r\@, #0
.endm
.section .text.start, "ax", %progbits
.arm
.align 5
.global _start
.type _start, %function
_start:
/* Switch to system mode, mask all interrupts, clear all flags */
msr cpsr_cxsf, #0xDF
/* Backup current stack pointer. */
mov r12, sp
/* Set the stack pointer */
ldr sp, =__stack_top__
mov fp, #0
/* Save context */
push {r12, lr}
/* Call init. */
bl __program_init
/* Set r0 to r12 to 0 (for debugging) & call main */
.rept 13
CLEAR_GPR_REG_ITER
.endr
ldr r0, =__program_argc
ldr r1, =__program_argv
ldr r0, [r0]
ldr r1, [r1]
bl main
/* Save result. */
push {r0}
/* Exit manually. */
bl __program_exit
/* Restore result. */
pop {r0}
/* Restore context */
pop {r12}
pop {lr}
/* Restore previous stack pointer. */
mov sp, r12
/* Return */
bx lr

View File

@@ -0,0 +1,94 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_TIMERS_H
#define FUSEE_TIMERS_H
#include "utils.h"
#define TIMERS_BASE 0x60005000
#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n)
#define TIMERUS_CNTR_1US_0 MAKE_TIMERS_REG(0x10)
#define TIMERUS_USEC_CFG_0 MAKE_TIMERS_REG(0x14)
#define SHARED_INTR_STATUS_0 MAKE_TIMERS_REG(0x1A0)
#define SHARED_TIMER_SECURE_CFG_0 MAKE_TIMERS_REG(0x1A4)
#define RTC_BASE 0x7000E000
#define MAKE_RTC_REG(n) MAKE_REG32(RTC_BASE + n)
#define RTC_SECONDS MAKE_RTC_REG(0x08)
#define RTC_SHADOW_SECONDS MAKE_RTC_REG(0x0C)
#define RTC_MILLI_SECONDS MAKE_RTC_REG(0x10)
typedef struct {
uint32_t CONFIG;
uint32_t STATUS;
uint32_t COMMAND;
uint32_t PATTERN;
} watchdog_timers_t;
#define GET_WDT(n) ((volatile watchdog_timers_t *)(TIMERS_BASE + 0x100 + 0x20 * n))
#define WDT_REBOOT_PATTERN 0xC45A
#define GET_WDT_REBOOT_CFG_REG(n) MAKE_REG32(TIMERS_BASE + 0x60 + 0x8 * n)
void wait(uint32_t microseconds);
static inline uint32_t get_time_s(void) {
return RTC_SECONDS;
}
static inline uint32_t get_time_ms(void) {
return (RTC_MILLI_SECONDS | (RTC_SHADOW_SECONDS << 10));
}
static inline uint32_t get_time_us(void) {
return TIMERUS_CNTR_1US_0;
}
/**
* Returns the time in microseconds.
*/
static inline uint32_t get_time(void) {
return get_time_us();
}
/**
* Returns the number of microseconds that have passed since a given get_time().
*/
static inline uint32_t get_time_since(uint32_t base) {
return get_time_us() - base;
}
/**
* Delays for a given number of microseconds.
*/
static inline void udelay(uint32_t usecs) {
uint32_t start = get_time_us();
while (get_time_us() - start < usecs);
}
/**
* Delays for a given number of milliseconds.
*/
static inline void mdelay(uint32_t msecs) {
uint32_t start = get_time_ms();
while (get_time_ms() - start < msecs);
}
__attribute__ ((noreturn)) void watchdog_reboot(void);
#endif

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2018-2019 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 <stdbool.h>
#include <stdarg.h>
#include "utils.h"
#include "lib/log.h"
__attribute__ ((noreturn)) void generic_panic(void) {
print(SCREEN_LOG_LEVEL_ERROR, "Panic raised!");
while (true) {
/* Lock. */
}
}
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
va_list args;
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
va_start(args, fmt);
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
va_end(args);
while (true) {
/* Lock. */
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-2019 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/>.
*/
#ifndef FUSEE_UTILS_H
#define FUSEE_UTILS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define BIT(n) (1u << (n))
#define BITL(n) (1ull << (n))
#define MASK(n) (BIT(n) - 1)
#define MASKL(n) (BITL(n) - 1)
#define MASK2(a,b) (MASK(a) & ~MASK(b))
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
#define ALIGN(m) __attribute__((aligned(m)))
#define PACKED __attribute__((packed))
#define ALINLINE __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
__attribute__((noreturn)) void generic_panic(void);
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
#endif

View File

@@ -25,7 +25,7 @@ static inline uint32_t get_clk_source_reg(CarDevice dev) {
case CARDEVICE_UARTC: return 0x1A0; case CARDEVICE_UARTC: return 0x1A0;
case CARDEVICE_I2C1: return 0x124; case CARDEVICE_I2C1: return 0x124;
case CARDEVICE_I2C5: return 0x128; case CARDEVICE_I2C5: return 0x128;
case CARDEVICE_UNK: return 0; case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0x42C; case CARDEVICE_SE: return 0x42C;
case CARDEVICE_HOST1X: return 0x180; case CARDEVICE_HOST1X: return 0x180;
case CARDEVICE_TSEC: return 0x1F4; case CARDEVICE_TSEC: return 0x1F4;
@@ -48,7 +48,7 @@ static inline uint32_t get_clk_source_val(CarDevice dev) {
case CARDEVICE_UARTC: return 0; case CARDEVICE_UARTC: return 0;
case CARDEVICE_I2C1: return 6; case CARDEVICE_I2C1: return 6;
case CARDEVICE_I2C5: return 6; case CARDEVICE_I2C5: return 6;
case CARDEVICE_UNK: return 0; case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0; case CARDEVICE_SE: return 0;
case CARDEVICE_HOST1X: return 4; case CARDEVICE_HOST1X: return 4;
case CARDEVICE_TSEC: return 0; case CARDEVICE_TSEC: return 0;
@@ -71,7 +71,7 @@ static inline uint32_t get_clk_source_div(CarDevice dev) {
case CARDEVICE_UARTC: return 0; case CARDEVICE_UARTC: return 0;
case CARDEVICE_I2C1: return 0; case CARDEVICE_I2C1: return 0;
case CARDEVICE_I2C5: return 0; case CARDEVICE_I2C5: return 0;
case CARDEVICE_UNK: return 0; case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0; case CARDEVICE_SE: return 0;
case CARDEVICE_HOST1X: return 3; case CARDEVICE_HOST1X: return 3;
case CARDEVICE_TSEC: return 2; case CARDEVICE_TSEC: return 2;

View File

@@ -42,7 +42,7 @@ typedef enum {
CARDEVICE_UARTC = ((1 << 5) | 0x17), CARDEVICE_UARTC = ((1 << 5) | 0x17),
CARDEVICE_I2C1 = ((0 << 5) | 0xC), CARDEVICE_I2C1 = ((0 << 5) | 0xC),
CARDEVICE_I2C5 = ((1 << 5) | 0xF), CARDEVICE_I2C5 = ((1 << 5) | 0xF),
CARDEVICE_UNK = ((3 << 5) | 0x1E), CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
CARDEVICE_SE = ((3 << 5) | 0x1F), CARDEVICE_SE = ((3 << 5) | 0x1F),
CARDEVICE_HOST1X = ((0 << 5) | 0x1C), CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
CARDEVICE_TSEC = ((2 << 5) | 0x13), CARDEVICE_TSEC = ((2 << 5) | 0x13),

View File

@@ -21,125 +21,66 @@
#include "gpio.h" #include "gpio.h"
#include "utils.h" #include "utils.h"
/** static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin) {
* Returns a GPIO bank object that corresponds to the given GPIO pin,
* which can be created using the TEGRA_GPIO macro or passed from the name macro.
*
* @param pin The GPIO to get the bank for.
* @return The GPIO bank object to use for working with the given bank.
*/
static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin)
{
volatile tegra_gpio_t *gpio = gpio_get_regs(); volatile tegra_gpio_t *gpio = gpio_get_regs();
uint32_t bank_number = pin >> GPIO_BANK_SHIFT; uint32_t bank_number = (pin >> GPIO_BANK_SHIFT);
return &gpio->bank[bank_number]; return &gpio->bank[bank_number];
} }
/** static volatile uint32_t gpio_get_port(uint32_t pin) {
* @return the port number for working with the given GPIO. return ((pin >> GPIO_PORT_SHIFT) & GPIO_PORT_MASK);
*/
static volatile uint32_t gpio_get_port(uint32_t pin)
{
return (pin >> GPIO_PORT_SHIFT) & GPIO_PORT_MASK;
} }
/** static volatile uint32_t gpio_get_mask(uint32_t pin) {
* @return a mask to be used to work with the given GPIO uint32_t pin_number = (pin & GPIO_PIN_MASK);
*/
static volatile uint32_t gpio_get_mask(uint32_t pin)
{
uint32_t pin_number = pin & GPIO_PIN_MASK;
return (1 << pin_number); return (1 << pin_number);
} }
/** static void gpio_simple_register_set(uint32_t pin, bool should_be_set, uint32_t offset) {
* Performs a simple GPIO configuration operation. /* Retrieve the register set that corresponds to the given pin and offset. */
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param should_be_set True iff the relevant bit should be set; or false if it should be cleared.
* @param offset The offset into a gpio_bank structure
*/
static void gpio_simple_register_set(uint32_t pin, bool should_be_set, uint32_t offset)
{
// Retrieve the register set that corresponds to the given pin and offset.
uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset; uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset;
uint32_t *cluster = (uint32_t *)cluster_addr; uint32_t *cluster = (uint32_t *)cluster_addr;
// Figure out the offset into the cluster, /* Figure out the offset into the cluster, and the mask to be used. */
// and the mask to be used.
uint32_t port = gpio_get_port(pin); uint32_t port = gpio_get_port(pin);
uint32_t mask = gpio_get_mask(pin); uint32_t mask = gpio_get_mask(pin);
// Set or clear the bit, as appropriate. /* Set or clear the bit, as appropriate. */
if (should_be_set) if (should_be_set)
cluster[port] |= mask; cluster[port] |= mask;
else else
cluster[port] &= ~mask; cluster[port] &= ~mask;
/* Dummy read. */
(void)cluster[port];
} }
/** static bool gpio_simple_register_get(uint32_t pin, uint32_t offset) {
* Performs a simple GPIO configuration operation. /* Retrieve the register set that corresponds to the given pin and offset. */
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param should_be_set True iff the relevant bit should be set; or false if it should be cleared.
* @param offset The offset into a gpio_bank structure
*/
static bool gpio_simple_register_get(uint32_t pin, uint32_t offset)
{
// Retrieve the register set that corresponds to the given pin and offset.
uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset; uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset;
uint32_t *cluster = (uint32_t *)cluster_addr; uint32_t *cluster = (uint32_t *)cluster_addr;
// Figure out the offset into the cluster, /* Figure out the offset into the cluster, and the mask to be used. */
// and the mask to be used.
uint32_t port = gpio_get_port(pin); uint32_t port = gpio_get_port(pin);
uint32_t mask = gpio_get_mask(pin); uint32_t mask = gpio_get_mask(pin);
// Convert the given value to a boolean. /* Convert the given value to a boolean. */
return !!(cluster[port] & mask); return !!(cluster[port] & mask);
} }
/** void gpio_configure_mode(uint32_t pin, uint32_t mode) {
* Configures a given pin as either GPIO or SFIO.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_configure_mode(uint32_t pin, uint32_t mode)
{
gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config)); gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config));
} }
/** void gpio_configure_direction(uint32_t pin, uint32_t dir) {
* Configures a given pin as either INPUT or OUPUT.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param direction The relevant direction.
*/
void gpio_configure_direction(uint32_t pin, uint32_t dir)
{
gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(tegra_gpio_bank_t, direction)); gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(tegra_gpio_bank_t, direction));
} }
/** void gpio_write(uint32_t pin, uint32_t value) {
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_write(uint32_t pin, uint32_t value)
{
gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(tegra_gpio_bank_t, out)); gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(tegra_gpio_bank_t, out));
} }
/** uint32_t gpio_read(uint32_t pin) {
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
uint32_t gpio_read(uint32_t pin)
{
return gpio_simple_register_get(pin, offsetof(tegra_gpio_bank_t, in)); return gpio_simple_register_get(pin, offsetof(tegra_gpio_bank_t, in));
} }

View File

@@ -96,8 +96,8 @@ static inline volatile tegra_gpio_t *gpio_get_regs(void)
((TEGRA_GPIO_PORT_##port * 8) + offset) ((TEGRA_GPIO_PORT_##port * 8) + offset)
/* Mode select */ /* Mode select */
#define GPIO_MODE_GPIO 0 #define GPIO_MODE_SFIO 0
#define GPIO_MODE_SFIO 1 #define GPIO_MODE_GPIO 1
/* Direction */ /* Direction */
#define GPIO_DIRECTION_INPUT 0 #define GPIO_DIRECTION_INPUT 0

View File

@@ -75,14 +75,9 @@ void config_gpios()
gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT); gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT);
gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT); gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT);
pinmux->gen1_i2c_scl = PINMUX_INPUT; i2c_config(I2C_1);
pinmux->gen1_i2c_sda = PINMUX_INPUT; i2c_config(I2C_5);
pinmux->pwr_i2c_scl = PINMUX_INPUT; uart_config(UART_A);
pinmux->pwr_i2c_sda = PINMUX_INPUT;
pinmux->uart1_rx = 0;
pinmux->uart1_tx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart1_rts = 0;
pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
/* Configure volume up/down as inputs. */ /* Configure volume up/down as inputs. */
gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO); gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO);
@@ -236,8 +231,8 @@ void nx_hwinit()
/* NOTE: [4.0.0+] This was removed. */ /* NOTE: [4.0.0+] This was removed. */
/* clkrst_reboot(CARDEVICE_SE); */ /* clkrst_reboot(CARDEVICE_SE); */
/* Reboot unknown device. */ /* Reboot TZRAM. */
clkrst_reboot(CARDEVICE_UNK); clkrst_reboot(CARDEVICE_TZRAM);
/* Initialize I2C1. */ /* Initialize I2C1. */
/* NOTE: [6.0.0+] This was moved to after the PMIC is configured. */ /* NOTE: [6.0.0+] This was moved to after the PMIC is configured. */

View File

@@ -17,19 +17,52 @@
#include "i2c.h" #include "i2c.h"
#include "utils.h" #include "utils.h"
#include "timers.h" #include "timers.h"
#include "pinmux.h"
/* Prototypes for internal commands. */ /* Prototypes for internal commands. */
volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id);
void i2c_load_config(volatile tegra_i2c_t *regs); void i2c_load_config(volatile tegra_i2c_t *regs);
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size);
bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size);
/* Configure I2C pinmux. */
void i2c_config(I2CDevice id) {
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
switch (id) {
case I2C_1:
pinmux->gen1_i2c_scl = PINMUX_INPUT;
pinmux->gen1_i2c_sda = PINMUX_INPUT;
break;
case I2C_2:
pinmux->gen2_i2c_scl = PINMUX_INPUT;
pinmux->gen2_i2c_sda = PINMUX_INPUT;
break;
case I2C_3:
pinmux->gen3_i2c_scl = PINMUX_INPUT;
pinmux->gen3_i2c_sda = PINMUX_INPUT;
break;
case I2C_4:
pinmux->cam_i2c_scl = PINMUX_INPUT;
pinmux->cam_i2c_sda = PINMUX_INPUT;
break;
case I2C_5:
pinmux->pwr_i2c_scl = PINMUX_INPUT;
pinmux->pwr_i2c_sda = PINMUX_INPUT;
break;
case I2C_6:
/* Unused. */
break;
default: break;
}
}
/* Initialize I2C based on registers. */ /* Initialize I2C based on registers. */
void i2c_init(unsigned int id) { void i2c_init(I2CDevice id) {
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
/* Setup divisor, and clear the bus. */ /* Setup divisor, and clear the bus. */
@@ -91,7 +124,7 @@ void i2c_set_ti_charger_bit_7(void) {
} }
/* Get registers pointer based on I2C ID. */ /* Get registers pointer based on I2C ID. */
volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) {
switch (id) { switch (id) {
case I2C_1: case I2C_1:
return I2C1_REGS; return I2C1_REGS;
@@ -126,7 +159,7 @@ void i2c_load_config(volatile tegra_i2c_t *regs) {
} }
/* Reads a register from a device over I2C, writes result to output. */ /* Reads a register from a device over I2C, writes result to output. */
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) {
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
uint32_t val = r; uint32_t val = r;
@@ -143,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst
} }
/* Writes a value to a register over I2C. */ /* Writes a value to a register over I2C. */
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) {
uint32_t val = r; uint32_t val = r;
if (src_size == 0) { if (src_size == 0) {
return true; return true;

View File

@@ -24,13 +24,6 @@
#define I2C1234_BASE 0x7000C000 #define I2C1234_BASE 0x7000C000
#define I2C56_BASE 0x7000D000 #define I2C56_BASE 0x7000D000
#define I2C_1 0
#define I2C_2 1
#define I2C_3 2
#define I2C_4 3
#define I2C_5 4
#define I2C_6 5
#define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_CPU_I2C_ADDR 0x1B
#define MAX77621_GPU_I2C_ADDR 0x1C #define MAX77621_GPU_I2C_ADDR 0x1C
#define MAX17050_I2C_ADDR 0x36 #define MAX17050_I2C_ADDR 0x36
@@ -38,6 +31,15 @@
#define MAX77620_RTC_I2C_ADDR 0x68 #define MAX77620_RTC_I2C_ADDR 0x68
#define BQ24193_I2C_ADDR 0x6B #define BQ24193_I2C_ADDR 0x6B
typedef enum {
I2C_1 = 0,
I2C_2 = 1,
I2C_3 = 2,
I2C_4 = 3,
I2C_5 = 4,
I2C_6 = 5,
} I2CDevice;
typedef struct { typedef struct {
uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CNFG_0;
uint32_t I2C_I2C_CMD_ADDR0_0; uint32_t I2C_I2C_CMD_ADDR0_0;
@@ -89,9 +91,11 @@ typedef struct {
#define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000)) #define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100)) #define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
void i2c_init(unsigned int id); void i2c_config(I2CDevice id);
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); void i2c_init(I2CDevice id);
bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
void i2c_send_pmic_cpu_shutdown_cmd(void); void i2c_send_pmic_cpu_shutdown_cmd(void);
bool i2c_query_ti_charger_bit_7(void); bool i2c_query_ti_charger_bit_7(void);

View File

@@ -322,3 +322,9 @@ R0.13b (April 07, 2018)
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)

View File

@@ -1,4 +1,4 @@
FatFs Module Source Files R0.13b FatFs Module Source Files R0.13c
FILES FILES
@@ -10,7 +10,6 @@ FILES
ff.h Common include file for FatFs and application module. ff.h Common include file for FatFs and application module.
diskio.h Common include file for FatFs and disk I/O 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. diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs.
ffunicode.c Optional Unicode utility functions. ffunicode.c Optional Unicode utility functions.
ffsystem.c An example of optional O/S related functions. ffsystem.c An example of optional O/S related functions.

View File

@@ -9,9 +9,11 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include "diskio.h" /* FatFs lower layer API */ #include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "../../fs_utils.h" #include "../../fs_utils.h"
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Get Drive Status */ /* Get Drive Status */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -63,6 +65,8 @@ DRESULT disk_read (
/* Write Sector(s) */ /* Write Sector(s) */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write ( DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */ const BYTE *buff, /* Data to be written */
@@ -78,6 +82,7 @@ DRESULT disk_write (
} }
} }
#endif
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/

View File

@@ -9,9 +9,6 @@
extern "C" { extern "C" {
#endif #endif
#include "integer.h"
/* Status of Disk Functions */ /* Status of Disk Functions */
typedef BYTE DSTATUS; typedef BYTE DSTATUS;

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module R0.13b / / FatFs - Generic FAT Filesystem Module R0.13c /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2018, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
@@ -31,11 +31,20 @@
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
#if FF_DEFINED != 63463 /* Revision ID */ #if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
/* Character code support macros */ /* Character code support macros */
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
#define IsLower(c) ((c) >= 'a' && (c) <= 'z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z')
@@ -45,18 +54,18 @@
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Additional file access control and file status flags for internal use */ /* Additional file access control and file status flags for internal use */
#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
#define FA_MODIFIED 0x40 /* File has been modified */ #define FA_MODIFIED 0x40 /* File has been modified */
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Name status flags in fn[11] */ /* Name status flags in fn[11] */
#define NSFLAG 11 /* Index of the name status byte */ #define NSFLAG 11 /* Index of the name status byte */
#define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LOSS 0x01 /* Out of 8.3 format */
@@ -69,13 +78,13 @@
#define NS_NONAME 0x80 /* Not followed */ #define NS_NONAME 0x80 /* Not followed */
/* Limits and boundaries */ /* exFAT directory entry types */
#define MAX_DIR 0x200000 /* Max size of FAT directory */ #define ET_BITMAP 0x81 /* Allocation bitmap */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ #define ET_UPCASE 0x82 /* Up-case table */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define ET_VLABEL 0x83 /* Volume label */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define ET_FILEDIR 0x85 /* File and directory */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ #define ET_STREAM 0xC0 /* Stream extension */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ #define ET_FILENAME 0xC1 /* Name extension */
/* FatFs refers the FAT structure as simple byte array instead of structure member /* FatFs refers the FAT structure as simple byte array instead of structure member
@@ -523,6 +532,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
#define CODEPAGE CodePage #define CODEPAGE CodePage
static WORD CodePage; /* Current code page */ static WORD CodePage; /* Current code page */
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct437[] = TBL_CT437;
static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct720[] = TBL_CT720;
static const BYTE Ct737[] = TBL_CT737; static const BYTE Ct737[] = TBL_CT737;
@@ -1095,7 +1105,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
if (res == FR_OK) { if (res == FR_OK) {
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
/* Create FSInfo structure */ /* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs)); mem_set(fs->win, 0, sizeof fs->win);
st_word(fs->win + BS_55AA, 0xAA55); st_word(fs->win + BS_55AA, 0xAA55);
st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_LeadSig, 0x41615252);
st_dword(fs->win + FSI_StrucSig, 0x61417272); st_dword(fs->win + FSI_StrucSig, 0x61417272);
@@ -1295,7 +1305,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D
if (clst >= fs->n_fatent - 2) clst = 0; if (clst >= fs->n_fatent - 2) clst = 0;
scl = val = clst; ctr = 0; scl = val = clst; ctr = 0;
for (;;) { for (;;) {
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
i = val / 8 % SS(fs); bm = 1 << (val % 8); i = val / 8 % SS(fs); bm = 1 << (val % 8);
do { do {
do { do {
@@ -1333,9 +1343,9 @@ static FRESULT change_bitmap (
clst -= 2; /* The first bit corresponds to cluster #2 */ clst -= 2; /* The first bit corresponds to cluster #2 */
sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
i = clst / 8 % SS(fs); /* Byte offset in the sector */ i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */ bm = 1 << (clst % 8); /* Bit mask in the byte */
for (;;) { for (;;) {
if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
do { do {
@@ -1408,7 +1418,7 @@ static FRESULT fill_last_frag (
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FFOBJID* obj, /* Corresponding object */ FFOBJID* obj, /* Corresponding object */
DWORD clst, /* Cluster to remove a chain from */ DWORD clst, /* Cluster to remove a chain from */
DWORD pclst /* Previous cluster of clst (0:entire chain) */ DWORD pclst /* Previous cluster of clst (0 if entire chain) */
) )
{ {
FRESULT res = FR_OK; FRESULT res = FR_OK;
@@ -1646,7 +1656,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */
if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
sect = clst2sect(fs, clst); /* Top of the cluster */ sect = clst2sect(fs, clst); /* Top of the cluster */
fs->winsect = sect; /* Set window to top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */
mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
/* Allocate a temporary buffer */ /* Allocate a temporary buffer */
for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
@@ -1730,7 +1740,8 @@ static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DEN
ofs = dp->dptr + SZDIRE; /* Next entry */ ofs = dp->dptr + SZDIRE; /* Next entry */
if (dp->sect == 0 || ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */
if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */
if (ofs % SS(fs) == 0) { /* Sector changed? */ if (ofs % SS(fs) == 0) { /* Sector changed? */
dp->sect++; /* Next sector */ dp->sect++; /* Next sector */
@@ -1875,7 +1886,7 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
if (wc != 0) { if (wc != 0) {
if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
return 0; /* Not matched */ return 0; /* Not matched */
} }
wc = uc; wc = uc;
@@ -1911,15 +1922,15 @@ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
if (wc != 0) { if (wc != 0) {
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */ lfnbuf[i++] = wc = uc; /* Store it */
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ if (uc != 0xFFFF) return 0; /* Check filler */
} }
} }
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
lfnbuf[i] = 0; lfnbuf[i] = 0;
} }
@@ -2155,33 +2166,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */
/* Load 85 entry */ /* Load file-directory entry */
res = move_window(dp->obj.fs, dp->sect); res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
/* Load C0 entry */ /* Load stream-extension entry */
res = dir_next(dp, 0); res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect); res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
/* Load C1 entries */ /* Load file-name entries */
i = 2 * SZDIRE; /* C1 offset to load */ i = 2 * SZDIRE; /* Name offset to load */
do { do {
res = dir_next(dp, 0); res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect); res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
} while ((i += SZDIRE) < sz_ent); } while ((i += SZDIRE) < sz_ent);
@@ -2286,16 +2297,16 @@ static void create_xdir (
WCHAR wc; WCHAR wc;
/* Create 85,C0 entry */ /* Create file-directory and stream-extension entry */
mem_set(dirb, 0, 2 * SZDIRE); mem_set(dirb, 0, 2 * SZDIRE);
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
/* Create C1 entries */ /* Create file-name entries */
i = SZDIRE * 2; /* Top of C1 entries */ i = SZDIRE * 2; /* Top of file_name entries */
nlen = nc1 = 0; wc = 1; nlen = nc1 = 0; wc = 1;
do { do {
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ dirb[i++] = ET_FILENAME; dirb[i++] = 0;
do { /* Fill name field */ do { /* Fill name field */
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
st_word(dirb + i, wc); /* Store it */ st_word(dirb + i, wc); /* Store it */
@@ -2319,8 +2330,8 @@ static void create_xdir (
/* Read an object from the directory */ /* Read an object from the directory */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#define dir_read_file(dp) dir_read(dp, 0) #define DIR_READ_FILE(dp) dir_read(dp, 0)
#define dir_read_label(dp) dir_read(dp, 1) #define DIR_READ_LABEL(dp) dir_read(dp, 1)
static FRESULT dir_read ( static FRESULT dir_read (
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
@@ -2329,7 +2340,7 @@ static FRESULT dir_read (
{ {
FRESULT res = FR_NO_FILE; FRESULT res = FR_NO_FILE;
FATFS *fs = dp->obj.fs; FATFS *fs = dp->obj.fs;
BYTE a, c; BYTE attr, b;
#if FF_USE_LFN #if FF_USE_LFN
BYTE ord = 0xFF, sum = 0xFF; BYTE ord = 0xFF, sum = 0xFF;
#endif #endif
@@ -2337,16 +2348,16 @@ static FRESULT dir_read (
while (dp->sect) { while (dp->sect) {
res = move_window(fs, dp->sect); res = move_window(fs, dp->sect);
if (res != FR_OK) break; if (res != FR_OK) break;
c = dp->dir[DIR_Name]; /* Test for the entry type */ b = dp->dir[DIR_Name]; /* Test for the entry type */
if (c == 0) { if (b == 0) {
res = FR_NO_FILE; break; /* Reached to end of the directory */ res = FR_NO_FILE; break; /* Reached to end of the directory */
} }
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
if (FF_USE_LABEL && vol) { if (FF_USE_LABEL && vol) {
if (c == 0x83) break; /* Volume label entry? */ if (b == ET_VLABEL) break; /* Volume label entry? */
} else { } else {
if (c == 0x85) { /* Start of the file entry block? */ if (b == ET_FILEDIR) { /* Start of the file entry block? */
dp->blk_ofs = dp->dptr; /* Get location of the block */ dp->blk_ofs = dp->dptr; /* Get location of the block */
res = load_xdir(dp); /* Load the entry block */ res = load_xdir(dp); /* Load the entry block */
if (res == FR_OK) { if (res == FR_OK) {
@@ -2358,19 +2369,19 @@ static FRESULT dir_read (
} else } else
#endif #endif
{ /* On the FAT/FAT32 volume */ { /* On the FAT/FAT32 volume */
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
#if FF_USE_LFN /* LFN configuration */ #if FF_USE_LFN /* LFN configuration */
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
ord = 0xFF; ord = 0xFF;
} else { } else {
if (a == AM_LFN) { /* An LFN entry is found */ if (attr == AM_LFN) { /* An LFN entry is found */
if (c & LLEF) { /* Is it start of an LFN sequence? */ if (b & LLEF) { /* Is it start of an LFN sequence? */
sum = dp->dir[LDIR_Chksum]; sum = dp->dir[LDIR_Chksum];
c &= (BYTE)~LLEF; ord = c; b &= (BYTE)~LLEF; ord = b;
dp->blk_ofs = dp->dptr; dp->blk_ofs = dp->dptr;
} }
/* Check LFN validity and capture it */ /* Check LFN validity and capture it */
ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
} else { /* An SFN entry is found */ } else { /* An SFN entry is found */
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
@@ -2379,7 +2390,7 @@ static FRESULT dir_read (
} }
} }
#else /* Non LFN configuration */ #else /* Non LFN configuration */
if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
break; break;
} }
#endif #endif
@@ -2419,7 +2430,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
UINT di, ni; UINT di, ni;
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */
#if FF_MAX_LFN < 255 #if FF_MAX_LFN < 255
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
#endif #endif
@@ -2498,17 +2509,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
res = dir_alloc(dp, nent); /* Allocate entries */ res = dir_alloc(dp, nent); /* Allocate directory entries */
if (res != FR_OK) return res; if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
if (dp->obj.stat & 4) { /* Has the directory been stretched? */ if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */
dp->obj.stat &= ~4; dp->obj.stat &= ~4;
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->obj.sclust != 0) { /* Is it a sub directory? */ if (dp->obj.sclust != 0) { /* Is it a sub-directory? */
DIR dj; DIR dj;
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
@@ -2640,6 +2651,7 @@ static void get_fileinfo (
{ {
UINT si, di; UINT si, di;
#if FF_USE_LFN #if FF_USE_LFN
BYTE lcf;
WCHAR wc, hs; WCHAR wc, hs;
FATFS *fs = dp->obj.fs; FATFS *fs = dp->obj.fs;
#else #else
@@ -2700,9 +2712,10 @@ static void get_fileinfo (
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
fno->fname[di++] = '?'; fno->fname[di++] = '?';
} else { } else {
for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
wc = (WCHAR)fno->altname[si]; wc = (WCHAR)fno->altname[si];
if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; if (wc == '.') lcf = NS_EXT;
if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;
fno->fname[di] = (TCHAR)wc; fno->fname[di] = (TCHAR)wc;
} }
} }
@@ -3256,7 +3269,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
#endif #endif
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
bsect = 0; bsect = 0;
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
@@ -3279,6 +3292,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fmt == 1) { if (fmt == 1) {
QWORD maxlba; QWORD maxlba;
DWORD so, cv, bcl;
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
@@ -3311,12 +3325,27 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
/* Check if bitmap location is in assumption (at the first cluster) */ /* Get bitmap location and check if it is contiguous (implementation assumption) */
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; so = i = 0;
for (i = 0; i < SS(fs); i += SZDIRE) { for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ if (i == 0) {
if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */
if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR;
so++;
}
if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
i = (i + SZDIRE) % SS(fs); /* Next entry */
} }
if (i == SS(fs)) return FR_NO_FILESYSTEM; bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM;
fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */
for (;;) { /* Check if bitmap is contiguous */
if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
if (cv == 0xFFFFFFFF) break; /* Last link? */
if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */
}
#if !FF_FS_READONLY #if !FF_FS_READONLY
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
#endif #endif
@@ -3666,7 +3695,7 @@ FRESULT f_open (
fp->fptr = 0; /* Set file pointer top of the file */ fp->fptr = 0; /* Set file pointer top of the file */
#if !FF_FS_READONLY #if !FF_FS_READONLY
#if !FF_FS_TINY #if !FF_FS_TINY
mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */
#endif #endif
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
fp->fptr = fp->obj.objsize; /* Offset to seek */ fp->fptr = fp->obj.objsize; /* Offset to seek */
@@ -4137,15 +4166,16 @@ FRESULT f_getcwd (
TCHAR *tp = buff; TCHAR *tp = buff;
#if FF_VOLUMES >= 2 #if FF_VOLUMES >= 2
UINT vl; UINT vl;
#endif
#if FF_STR_VOLUME_ID #if FF_STR_VOLUME_ID
const char *vp; const char *vp;
#endif
#endif #endif
FILINFO fno; FILINFO fno;
DEF_NAMBUF DEF_NAMBUF
/* Get logical drive */ /* Get logical drive */
buff[0] = 0; /* Set null string to get current volume */
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
if (res == FR_OK) { if (res == FR_OK) {
dj.obj.fs = fs; dj.obj.fs = fs;
@@ -4164,7 +4194,7 @@ FRESULT f_getcwd (
res = dir_sdi(&dj, 0); res = dir_sdi(&dj, 0);
if (res != FR_OK) break; if (res != FR_OK) break;
do { /* Find the entry links to the child directory */ do { /* Find the entry links to the child directory */
res = dir_read_file(&dj); res = DIR_READ_FILE(&dj);
if (res != FR_OK) break; if (res != FR_OK) break;
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
res = dir_next(&dj, 0); res = dir_next(&dj, 0);
@@ -4496,7 +4526,7 @@ FRESULT f_readdir (
res = dir_sdi(dp, 0); /* Rewind the directory object */ res = dir_sdi(dp, 0); /* Rewind the directory object */
} else { } else {
INIT_NAMBUF(fs); INIT_NAMBUF(fs);
res = dir_read_file(dp); /* Read an item */ res = DIR_READ_FILE(dp); /* Read an item */
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
if (res == FR_OK) { /* A valid entry is found */ if (res == FR_OK) { /* A valid entry is found */
get_fileinfo(dp, fno); /* Get the object information */ get_fileinfo(dp, fno); /* Get the object information */
@@ -4641,7 +4671,7 @@ FRESULT f_getfree (
UINT b; UINT b;
clst = fs->n_fatent - 2; /* Number of clusters */ clst = fs->n_fatent - 2; /* Number of clusters */
sect = fs->database; /* Assuming bitmap starts at cluster 2 */ sect = fs->bitbase; /* Bitmap sector */
i = 0; /* Offset in the sector */ i = 0; /* Offset in the sector */
do { /* Counts numbuer of bits with zero in the bitmap */ do { /* Counts numbuer of bits with zero in the bitmap */
if (i == 0) { if (i == 0) {
@@ -4804,7 +4834,7 @@ FRESULT f_unlink (
#endif #endif
res = dir_sdi(&sdj, 0); res = dir_sdi(&sdj, 0);
if (res == FR_OK) { if (res == FR_OK) {
res = dir_read_file(&sdj); /* Test if the directory is empty */ res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */
if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
} }
@@ -4842,73 +4872,69 @@ FRESULT f_mkdir (
{ {
FRESULT res; FRESULT res;
DIR dj; DIR dj;
FFOBJID sobj;
FATFS *fs; FATFS *fs;
BYTE *dir;
DWORD dcl, pcl, tm; DWORD dcl, pcl, tm;
DEF_NAMBUF DEF_NAMBUF
/* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
res = find_volume(&path, &fs, FA_WRITE);
if (res == FR_OK) { if (res == FR_OK) {
dj.obj.fs = fs; dj.obj.fs = fs;
INIT_NAMBUF(fs); INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */ res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ if (res == FR_OK) res = FR_EXIST; /* Name collision? */
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
res = FR_INVALID_NAME; res = FR_INVALID_NAME;
} }
if (res == FR_NO_FILE) { /* Can create a new directory */ if (res == FR_NO_FILE) { /* It is clear to create a new directory */
dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ sobj.fs = fs; /* New object id to create a new chain */
dj.obj.objsize = (DWORD)fs->csize * SS(fs); dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
res = FR_OK; res = FR_OK;
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
if (dcl == 1) res = FR_INT_ERR; if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
tm = GET_FATTIME(); tm = GET_FATTIME();
if (res == FR_OK) { /* Initialize the new directory table */
res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */
dir = fs->win;
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
dir[DIR_Name] = '.';
dir[DIR_Attr] = AM_DIR;
st_dword(dir + DIR_ModTime, tm);
st_clust(fs, dir, dcl);
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, dir + SZDIRE, pcl);
fs->wflag = 1;
}
}
if (res == FR_OK) { if (res == FR_OK) {
res = dir_register(&dj); /* Register the object to the directoy */ res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK) {
if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
fs->win[DIR_Name] = '.';
fs->win[DIR_Attr] = AM_DIR;
st_dword(fs->win + DIR_ModTime, tm);
st_clust(fs, fs->win, dcl);
mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, fs->win + SZDIRE, pcl);
fs->wflag = 1;
}
res = dir_register(&dj); /* Register the object to the parent directoy */
}
} }
if (res == FR_OK) { if (res == FR_OK) {
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */
st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */
st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */
st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */
st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs));
fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */
fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */
res = store_xdir(&dj); res = store_xdir(&dj);
} else } else
#endif #endif
{ {
dir = dj.dir; st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
st_dword(dir + DIR_ModTime, tm); /* Created time */ st_clust(fs, dj.dir, dcl); /* Table start cluster */
st_clust(fs, dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
dir[DIR_Attr] = AM_DIR; /* Attribute */
fs->wflag = 1; fs->wflag = 1;
} }
if (res == FR_OK) { if (res == FR_OK) {
res = sync_fs(fs); res = sync_fs(fs);
} }
} else { } else {
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */
} }
} }
FREE_NAMBUF(); FREE_NAMBUF();
@@ -5148,7 +5174,7 @@ FRESULT f_getlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0); res = dir_sdi(&dj, 0);
if (res == FR_OK) { if (res == FR_OK) {
res = dir_read_label(&dj); /* Find a volume label entry */ res = DIR_READ_LABEL(&dj); /* Find a volume label entry */
if (res == FR_OK) { if (res == FR_OK) {
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { if (fs->fs_type == FS_EXFAT) {
@@ -5293,7 +5319,7 @@ FRESULT f_setlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0); res = dir_sdi(&dj, 0);
if (res == FR_OK) { if (res == FR_OK) {
res = dir_read_label(&dj); /* Get volume label entry */ res = DIR_READ_LABEL(&dj); /* Get volume label entry */
if (res == FR_OK) { if (res == FR_OK) {
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
@@ -5315,7 +5341,7 @@ FRESULT f_setlabel (
if (res == FR_OK) { if (res == FR_OK) {
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */
dj.dir[XDIR_NumLabel] = (BYTE)di; dj.dir[XDIR_NumLabel] = (BYTE)di;
mem_cpy(dj.dir + XDIR_Label, dirvn, 22); mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
} else { } else {
@@ -5620,7 +5646,7 @@ FRESULT f_mkfs (
b_fat = b_vol + 32; /* FAT start at offset 32 */ b_fat = b_vol + 32; /* FAT start at offset 32 */
sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */
if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
@@ -5701,11 +5727,11 @@ FRESULT f_mkfs (
/* Initialize the root directory */ /* Initialize the root directory */
mem_set(buf, 0, szb_buf); mem_set(buf, 0, szb_buf);
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
@@ -6193,8 +6219,7 @@ typedef struct { /* Putchar output buffer and work area */
} putbuff; } putbuff;
static static void putc_bfd ( /* Buffered write with code conversion */
void putc_bfd ( /* Buffered write with code conversion */
putbuff* pb, putbuff* pb,
TCHAR c TCHAR c
) )
@@ -6305,7 +6330,7 @@ void putc_bfd ( /* Buffered write with code conversion */
#else /* Write it in ANSI/OEM */ #else /* Write it in ANSI/OEM */
if (hs != 0) return; if (hs != 0) return;
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
if (wc == 0) return;; if (wc == 0) return;
if (wc >= 0x100) { if (wc >= 0x100) {
pb->buf[i++] = (BYTE)(wc >> 8); nc++; pb->buf[i++] = (BYTE)(wc >> 8); nc++;
} }
@@ -6325,8 +6350,7 @@ void putc_bfd ( /* Buffered write with code conversion */
} }
static static int putc_flush ( /* Flush left characters in the buffer */
int putc_flush ( /* Flush left characters in the buffer */
putbuff* pb putbuff* pb
) )
{ {
@@ -6339,8 +6363,7 @@ int putc_flush ( /* Flush left characters in the buffer */
} }
static static void putc_init ( /* Initialize write buffer */
void putc_init ( /* Initialize write buffer */
putbuff* pb, putbuff* pb,
FIL* fp FIL* fp
) )

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13b / / FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2018, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
@@ -20,13 +20,12 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 63463 /* Revision ID */ #define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF #if FF_DEFINED != FFCONF_DEF
@@ -34,6 +33,30 @@ extern "C" {
#endif #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 uint16_t WCHAR; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
#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 short WCHAR; /* 16-bit unsigned integer */
typedef unsigned long DWORD; /* 32-bit unsigned integer */
#endif
/* Definitions of volume management */ /* Definitions of volume management */
@@ -85,6 +108,9 @@ typedef char TCHAR;
/* Type of file size variables */ /* Type of file size variables */
#if FF_FS_EXFAT #if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#endif
typedef QWORD FSIZE_t; typedef QWORD FSIZE_t;
#else #else
typedef DWORD FSIZE_t; typedef DWORD FSIZE_t;
@@ -95,8 +121,8 @@ typedef DWORD FSIZE_t;
/* Filesystem object structure (FATFS) */ /* Filesystem object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:N/A) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Physical drive number */ BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
@@ -133,6 +159,9 @@ typedef struct {
DWORD fatbase; /* FAT base sector */ DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */ DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */ DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */ DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS; } FATFS;
@@ -145,7 +174,7 @@ typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ 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) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT #if FF_FS_EXFAT
@@ -276,7 +305,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set 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_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_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_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */

View File

@@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - Configuration file / FatFs Functional Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 63463 /* Revision ID */ #define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@@ -232,7 +232,7 @@
#define FF_FS_EXFAT 1 #define FF_FS_EXFAT 1
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ / Note that enabling exFAT discards ANSI C (C89) compatibility. */
@@ -262,6 +262,7 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE #define FF_SYNC_t HANDLE
@@ -282,8 +283,6 @@
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */ / included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/ /*--- End of configuration options ---*/

View File

@@ -1,20 +1,19 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */ /* Sample Code of OS Dependent Functions for FatFs */
/* (C)ChaN, 2017 */ /* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include "ff.h" #include "ff.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Allocate a memory block */ /* Allocate a memory block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
@@ -27,7 +26,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do for null) */ void* mblock /* Pointer to the memory block to free (nothing to do if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block with POSIX API */
@@ -47,7 +46,7 @@ void ff_memfree (
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR. / When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/ */
//const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */ //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 */ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
@@ -74,7 +73,7 @@ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object
// return (int)(*sobj != NULL); // return (int)(*sobj != NULL);
/* CMSIS-RTOS */ /* CMSIS-RTOS */
// *sobj = osMutexCreate(Mutex + vol); // *sobj = osMutexCreate(&Mutex[vol]);
// return (int)(*sobj != NULL); // return (int)(*sobj != NULL);
} }

View File

@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13b */ /* Unicode handling functions for FatFs R0.13c */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the / /* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode / / FatFs is configured for LFN with DBCS. If the system has any Unicode /
@@ -25,9 +25,9 @@
#include "ff.h" #include "ff.h"
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */ #if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
#if FF_DEFINED != 63463 /* Revision ID */ #if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif

View File

@@ -1,36 +0,0 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef FF_INTEGER
#define FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
typedef unsigned long long QWORD;
#endif
#endif

View File

@@ -508,7 +508,7 @@ char *uuid_string(char *buf, char *end, const uint8_t *addr,
if (uc) { if (uc) {
p = uuid; p = uuid;
do { do {
*p = toupper(*p); *p = toupper((unsigned char)*p);
} while (*(++p)); } while (*(++p));
} }
@@ -1177,7 +1177,7 @@ do { \
case FORMAT_TYPE_PTR: case FORMAT_TYPE_PTR:
save_arg(void *); save_arg(void *);
/* skip all alphanumeric pointer suffixes */ /* skip all alphanumeric pointer suffixes */
while (isalnum(*fmt)) while (isalnum((unsigned char)*fmt))
fmt++; fmt++;
break; break;
@@ -1340,7 +1340,7 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const uint32_t *bin_buf
case FORMAT_TYPE_PTR: case FORMAT_TYPE_PTR:
str = pointer(fmt+1, str, end, get_arg(void *), spec); str = pointer(fmt+1, str, end, get_arg(void *), spec);
while (isalnum(*fmt)) while (isalnum((unsigned char)*fmt))
fmt++; fmt++;
break; break;
@@ -1577,10 +1577,10 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
digit = *(str + 1); digit = *(str + 1);
if (!digit if (!digit
|| (base == 16 && !isxdigit(digit)) || (base == 16 && !isxdigit((unsigned char)digit))
|| (base == 10 && !isdigit(digit)) || (base == 10 && !isdigit((unsigned char)digit))
|| (base == 8 && (!isdigit(digit) || digit > '7')) || (base == 8 && (!isdigit((unsigned char)digit) || digit > '7'))
|| (base == 0 && !isdigit(digit))) || (base == 0 && !isdigit((unsigned char)digit)))
break; break;
switch (qualifier) { switch (qualifier) {

View File

@@ -41,6 +41,7 @@ static char g_bct0_buffer[BCTO_MAX_SIZE];
"BCT0\n"\ "BCT0\n"\
"[stage1]\n"\ "[stage1]\n"\
"stage2_path = atmosphere/fusee-secondary.bin\n"\ "stage2_path = atmosphere/fusee-secondary.bin\n"\
"stage2_mtc_path = atmosphere/fusee-mtc.bin\n"\
"stage2_addr = 0xF0000000\n"\ "stage2_addr = 0xF0000000\n"\
"stage2_entrypoint = 0xF0000000\n" "stage2_entrypoint = 0xF0000000\n"
@@ -84,12 +85,9 @@ static int config_ini_handler(void *user, const char *section, const char *name,
return 1; return 1;
} }
static void setup_env(void) { static void setup_display(void) {
g_framebuffer = (void *)0xC0000000; g_framebuffer = (void *)0xC0000000;
/* Initialize hardware. */
nx_hwinit();
/* Zero-fill the framebuffer and register it as printk provider. */ /* Zero-fill the framebuffer and register it as printk provider. */
video_init(g_framebuffer); video_init(g_framebuffer);
@@ -102,6 +100,19 @@ static void setup_env(void) {
/* Turn on the backlight after initializing the lfb */ /* Turn on the backlight after initializing the lfb */
/* to avoid flickering. */ /* to avoid flickering. */
display_backlight(true); display_backlight(true);
}
static void cleanup_display(void) {
/* Turn off the backlight. */
display_backlight(false);
/* Terminate the display. */
display_end();
}
static void setup_env(void) {
/* Initialize hardware. */
nx_hwinit();
/* Set up the exception handlers. */ /* Set up the exception handlers. */
setup_exception_handlers(); setup_exception_handlers();
@@ -113,9 +124,6 @@ static void setup_env(void) {
static void cleanup_env(void) { static void cleanup_env(void) {
/* Unmount the SD card. */ /* Unmount the SD card. */
unmount_sd(); unmount_sd();
display_backlight(false);
display_end();
} }
static void exit_callback(int rc) { static void exit_callback(int rc) {
@@ -128,12 +136,9 @@ int main(void) {
const char *stage2_path; const char *stage2_path;
stage2_args_t *stage2_args; stage2_args_t *stage2_args;
uint32_t stage2_version = 0; uint32_t stage2_version = 0;
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_MANDATORY; ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
/* Override the global logging level. */ /* Initialize the boot environment. */
log_set_log_level(log_level);
/* Initialize the display, console, etc. */
setup_env(); setup_env();
/* Check for panics. */ /* Check for panics. */
@@ -147,8 +152,16 @@ int main(void) {
fatal_error("Failed to parse BCT.ini!\n"); fatal_error("Failed to parse BCT.ini!\n");
} }
/* Override the global logging level. */
log_set_log_level(log_level);
if (log_level != SCREEN_LOG_LEVEL_NONE) {
/* Initialize the display for debugging. */
setup_display();
}
/* Say hello. */ /* Say hello. */
print(SCREEN_LOG_LEVEL_MANDATORY, "Welcome to Atmosph\xe8re Fus\xe9" "e!\n"); print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, "Welcome to Atmosph\xe8re Fus\xe9" "e!\n");
print(SCREEN_LOG_LEVEL_DEBUG, "Using color linear framebuffer at 0x%p!\n", g_framebuffer); print(SCREEN_LOG_LEVEL_DEBUG, "Using color linear framebuffer at 0x%p!\n", g_framebuffer);
/* Load the loader payload into DRAM. */ /* Load the loader payload into DRAM. */
@@ -160,16 +173,20 @@ int main(void) {
stage2_args = (stage2_args_t *)(g_chainloader_arg_data + strlen(stage2_path) + 1); /* May be unaligned. */ stage2_args = (stage2_args_t *)(g_chainloader_arg_data + strlen(stage2_path) + 1); /* May be unaligned. */
memcpy(&stage2_args->version, &stage2_version, 4); memcpy(&stage2_args->version, &stage2_version, 4);
memcpy(&stage2_args->log_level, &log_level, sizeof(log_level)); memcpy(&stage2_args->log_level, &log_level, sizeof(log_level));
stage2_args->display_initialized = false;
strcpy(stage2_args->bct0, bct0); strcpy(stage2_args->bct0, bct0);
g_chainloader_argc = 2; g_chainloader_argc = 2;
/* Wait a while. */ /* Terminate the boot environment. */
mdelay(1000);
/* Deinitialize the display, console, etc. */
cleanup_env(); cleanup_env();
if (log_level != SCREEN_LOG_LEVEL_NONE) {
/* Wait a while for debugging. */
mdelay(1000);
/* Terminate the display for debugging. */
cleanup_display();
}
/* Finally, after the cleanup routines (__libc_fini_array, etc.) are called, jump to Stage2. */ /* Finally, after the cleanup routines (__libc_fini_array, etc.) are called, jump to Stage2. */
__program_exit_callback = exit_callback; __program_exit_callback = exit_callback;
return 0; return 0;

View File

@@ -37,6 +37,13 @@
#define MC_SMMU_TLB_FLUSH 0x30 #define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34 #define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38 #define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_ASID_SECURITY_1 0x3c
#define MC_SMMU_ASID_SECURITY_2 0x9e0
#define MC_SMMU_ASID_SECURITY_3 0x9e4
#define MC_SMMU_ASID_SECURITY_4 0x9e8
#define MC_SMMU_ASID_SECURITY_5 0x9ec
#define MC_SMMU_ASID_SECURITY_6 0x9f0
#define MC_SMMU_ASID_SECURITY_7 0x9f4
#define MC_SMMU_AFI_ASID 0x238 #define MC_SMMU_AFI_ASID 0x238
#define MC_SMMU_AVPC_ASID 0x23c #define MC_SMMU_AVPC_ASID 0x23c
#define MC_SMMU_TSEC_ASID 0x294 #define MC_SMMU_TSEC_ASID 0x294

View File

@@ -22,6 +22,7 @@
#include "utils.h" #include "utils.h"
#include "fs_utils.h" #include "fs_utils.h"
#include "lib/log.h" #include "lib/log.h"
#include "display/video_fb.h"
static uint32_t g_panic_code = 0; static uint32_t g_panic_code = 0;
@@ -56,6 +57,22 @@ static void _check_and_display_atmosphere_fatal_error(void) {
} }
{ {
/* Zero-fill the framebuffer and register it as printk provider. */
video_init((void *)0xC0000000);
/* Initialize the display. */
display_init();
/* Set the framebuffer. */
display_init_framebuffer((void *)0xC0000000);
/* Turn on the backlight after initializing the lfb */
/* to avoid flickering. */
display_backlight(true);
/* Override the global logging level. */
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
/* Copy fatal error context to the stack. */ /* Copy fatal error context to the stack. */
atmosphere_fatal_error_ctx ctx = *(ATMOSPHERE_FATAL_ERROR_CONTEXT); atmosphere_fatal_error_ctx ctx = *(ATMOSPHERE_FATAL_ERROR_CONTEXT);
@@ -79,6 +96,7 @@ static void _check_and_display_atmosphere_fatal_error(void) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n"); print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
} }
/* Wait for button and reboot. */
wait_for_button_and_reboot(); wait_for_button_and_reboot();
} }
@@ -87,11 +105,9 @@ void check_and_display_panic(void) {
_check_and_display_atmosphere_fatal_error(); _check_and_display_atmosphere_fatal_error();
/* We also handle our own panics. */ /* We also handle our own panics. */
/* In the case of our own panics, we assume that the display has already been initialized. */ bool has_panic = ((APBDEV_PMC_RST_STATUS_0 != 0) || (g_panic_code != 0));
bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0; uint32_t code = (g_panic_code == 0) ? APBDEV_PMC_SCRATCH200_0 : g_panic_code;
uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code; has_panic = has_panic && !((APBDEV_PMC_RST_STATUS_0 != 1) && (code == PANIC_CODE_SAFEMODE));
has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE);
if (has_panic) { if (has_panic) {
uint32_t color; uint32_t color;
@@ -134,11 +150,13 @@ void check_and_display_panic(void) {
break; break;
} }
if (g_panic_code == 0) { /* Initialize the display. */
display_init(); display_init();
}
/* Fill the screen. */
display_color_screen(color); display_color_screen(color);
/* Wait for button and reboot. */
wait_for_button_and_reboot(); wait_for_button_and_reboot();
} else { } else {
g_panic_code = 0; g_panic_code = 0;

View File

@@ -28,7 +28,6 @@
#define PANIC_CODE_SAFEMODE 0x00000020 #define PANIC_CODE_SAFEMODE 0x00000020
#define AMS_FATAL_ERROR_MAX_STACKTRACE 0x20 #define AMS_FATAL_ERROR_MAX_STACKTRACE 0x20
#define AMS_FATAL_ERROR_MAX_STACKDUMP 0x100 #define AMS_FATAL_ERROR_MAX_STACKDUMP 0x100

View File

@@ -32,6 +32,9 @@ static int stage2_ini_handler(void *user, const char *section, const char *name,
if (strcmp(name, STAGE2_NAME_KEY) == 0) { if (strcmp(name, STAGE2_NAME_KEY) == 0) {
strncpy(config->path, value, sizeof(config->path) - 1); strncpy(config->path, value, sizeof(config->path) - 1);
config->path[sizeof(config->path) - 1] = '\0'; config->path[sizeof(config->path) - 1] = '\0';
} else if (strcmp(name, STAGE2_MTC_NAME_KEY) == 0) {
strncpy(config->mtc_path, value, sizeof(config->mtc_path) - 1);
config->mtc_path[sizeof(config->mtc_path) - 1] = '\0';
} else if (strcmp(name, STAGE2_ADDRESS_KEY) == 0) { } else if (strcmp(name, STAGE2_ADDRESS_KEY) == 0) {
/* Read in load address as a hex string. */ /* Read in load address as a hex string. */
sscanf(value, "%x", &x); sscanf(value, "%x", &x);
@@ -52,6 +55,42 @@ static int stage2_ini_handler(void *user, const char *section, const char *name,
return 1; return 1;
} }
static bool run_mtc(const char *mtc_path, uintptr_t mtc_address) {
FILINFO info;
size_t size;
/* Check if the MTC binary is present. */
if (f_stat(mtc_path, &info) != FR_OK) {
print(SCREEN_LOG_LEVEL_WARNING, "Stage2's MTC binary not found!\n");
return false;
}
size = (size_t)info.fsize;
/* Try to read the MTC binary. */
if (read_from_file((void *)mtc_address, size, mtc_path) != size) {
print(SCREEN_LOG_LEVEL_WARNING, "Failed to read stage2's MTC binary (%s)!\n", mtc_path);
return false;
}
ScreenLogLevel mtc_log_level = log_get_log_level();
bool mtc_res = false;
int mtc_argc = 1;
char mtc_arg_data[CHAINLOADER_ARG_DATA_MAX_SIZE] = {0};
stage2_mtc_args_t *mtc_args = (stage2_mtc_args_t *)mtc_arg_data;
/* Setup argument data. */
memcpy(&mtc_args->log_level, &mtc_log_level, sizeof(mtc_log_level));
/* Run the MTC binary. */
mtc_res = (((int (*)(int, void *))mtc_address)(mtc_argc, mtc_arg_data) == 0);
/* Cleanup right away. */
memset((void *)mtc_address, 0, size);
return mtc_res;
}
void load_stage2(const char *bct0) { void load_stage2(const char *bct0) {
stage2_config_t config = {0}; stage2_config_t config = {0};
FILINFO info; FILINFO info;
@@ -80,9 +119,15 @@ void load_stage2(const char *bct0) {
print(SCREEN_LOG_LEVEL_DEBUG, "Stage 2 Config:\n"); print(SCREEN_LOG_LEVEL_DEBUG, "Stage 2 Config:\n");
print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " File Path: %s\n", config.path); print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " File Path: %s\n", config.path);
print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " MTC File Path: %s\n", config.mtc_path);
print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " Load Address: 0x%08x\n", config.load_address); print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " Load Address: 0x%08x\n", config.load_address);
print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " Entrypoint: 0x%p\n", config.entrypoint); print(SCREEN_LOG_LEVEL_DEBUG | SCREEN_LOG_LEVEL_NO_PREFIX, " Entrypoint: 0x%p\n", config.entrypoint);
/* Run the MTC binary. */
if (!run_mtc(config.mtc_path, config.load_address)) {
print(SCREEN_LOG_LEVEL_WARNING, "DRAM training failed! Continuing with untrained DRAM.\n");
}
if (f_stat(config.path, &info) != FR_OK) { if (f_stat(config.path, &info) != FR_OK) {
fatal_error("Failed to stat stage2 (%s)!\n", config.path); fatal_error("Failed to stat stage2 (%s)!\n", config.path);
} }
@@ -108,6 +153,7 @@ void load_stage2(const char *bct0) {
tmp_addr = config.load_address; tmp_addr = config.load_address;
} }
/* Try to read stage2. */
if (read_from_file((void *)tmp_addr, size, config.path) != size) { if (read_from_file((void *)tmp_addr, size, config.path) != size) {
fatal_error("Failed to read stage2 (%s)!\n", config.path); fatal_error("Failed to read stage2 (%s)!\n", config.path);
} }

View File

@@ -32,12 +32,15 @@
#define STAGE2_ARGC 2 #define STAGE2_ARGC 2
#define STAGE2_NAME_KEY "stage2_path" #define STAGE2_NAME_KEY "stage2_path"
#define STAGE2_MTC_NAME_KEY "stage2_mtc_path"
#define STAGE2_ADDRESS_KEY "stage2_addr" #define STAGE2_ADDRESS_KEY "stage2_addr"
#define STAGE2_ENTRYPOINT_KEY "stage2_entrypoint" #define STAGE2_ENTRYPOINT_KEY "stage2_entrypoint"
#define BCTO_MAX_SIZE 0x5800 #define BCTO_MAX_SIZE 0x5800
typedef struct { typedef struct {
char path[0x100]; char path[0x100];
char mtc_path[0x100];
uintptr_t load_address; uintptr_t load_address;
uintptr_t entrypoint; uintptr_t entrypoint;
} stage2_config_t; } stage2_config_t;
@@ -45,10 +48,13 @@ typedef struct {
typedef struct { typedef struct {
uint32_t version; uint32_t version;
ScreenLogLevel log_level; ScreenLogLevel log_level;
bool display_initialized;
char bct0[BCTO_MAX_SIZE]; char bct0[BCTO_MAX_SIZE];
} stage2_args_t; } stage2_args_t;
typedef struct {
ScreenLogLevel log_level;
} stage2_mtc_args_t;
const char *stage2_get_program_path(void); const char *stage2_get_program_path(void);
void load_stage2(const char *bct0); void load_stage2(const char *bct0);

View File

@@ -17,35 +17,98 @@
#include "uart.h" #include "uart.h"
#include "timers.h" #include "timers.h"
#include "pinmux.h"
static inline void uart_wait_cycles(uint32_t baud, uint32_t num)
{
udelay((num * 1000000 + 16 * baud - 1) / (16 * baud));
}
static inline void uart_wait_syms(uint32_t baud, uint32_t num)
{
udelay((num * 1000000 + baud - 1) / baud);
}
void uart_config(UartDevice dev) {
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
switch (dev) {
case UART_A:
pinmux->uart1_tx = 0;
pinmux->uart1_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart1_rts = 0;
pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_B:
pinmux->uart2_tx = 0;
pinmux->uart2_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart2_rts = 0;
pinmux->uart2_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_C:
pinmux->uart3_tx = 0;
pinmux->uart3_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart3_rts = 0;
pinmux->uart3_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_D:
pinmux->uart4_tx = 0;
pinmux->uart4_rx = (PINMUX_INPUT | PINMUX_PULL_UP);
pinmux->uart4_rts = 0;
pinmux->uart4_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_E:
/* Unused. */
break;
default: break;
}
}
void uart_init(UartDevice dev, uint32_t baud) { void uart_init(UartDevice dev, uint32_t baud) {
volatile tegra_uart_t *uart = uart_get_regs(dev); volatile tegra_uart_t *uart = uart_get_regs(dev);
/* Set baud rate. */ /* Wait for idle state. */
uint32_t rate = (8 * baud + 408000000) / (16 * baud); uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE);
uart->UART_LCR = UART_LCR_DLAB; /* Enable DLAB. */
uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
uart->UART_LCR = 0; /* Diable DLAB. */
/* Setup UART in fifo mode. */ /* Calculate baud rate, round to nearest. */
uint32_t rate = (8 * baud + 408000000) / (16 * baud);
/* Setup UART in FIFO mode. */
uart->UART_IER_DLAB = 0; uart->UART_IER_DLAB = 0;
uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Enable and clear TX and RX FIFOs. */
(void)uart->UART_LSR;
udelay(3 * ((baud + 999999) / baud));
uart->UART_LCR = UART_LCR_WD_LENGTH_8; /* Set word length 8. */
uart->UART_MCR = 0; uart->UART_MCR = 0;
uart->UART_MSR = 0; uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */
uart->UART_IRDA_CSR = 0; uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */ uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
uart->UART_MIE = 0; uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */
uart->UART_ASR = 0; uart->UART_SPR; /* Dummy read. */
uart_wait_syms(baud, 3); /* Wait for 3 symbols at the new baudrate. */
/* Enable FIFO with default settings. */
uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO;
uart->UART_SPR; /* Dummy read as mandated by TRM. */
uart_wait_cycles(baud, 3); /* Wait for 3 baud cycles, as mandated by TRM (erratum). */
/* Flush FIFO. */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); /* Make sure there's no data being written in TX FIFO (TRM). */
uart->UART_IIR_FCR |= UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Clear TX and RX FIFOs. */
uart_wait_cycles(baud, 32); /* Wait for 32 baud cycles (TRM, erratum). */
/* Wait for idle state (TRM). */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE);
} }
/* This function blocks until the UART device (dev) is in the desired state (status). Make sure the desired state can be reached! */ /* This function blocks until the UART device is in the desired state. */
void uart_wait_idle(UartDevice dev, UartVendorStatus status) { void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
while (!(uart_get_regs(dev)->UART_VENDOR_STATUS & status)) { volatile tegra_uart_t *uart = uart_get_regs(dev);
/* Wait */
if (status & UART_VENDOR_STATE_TX_IDLE) {
while (!(uart->UART_LSR & UART_LSR_TMTY)) {
/* Wait */
}
}
if (status & UART_VENDOR_STATE_RX_IDLE) {
while (uart->UART_LSR & UART_LSR_RDR) {
/* Wait */
}
} }
} }
@@ -53,8 +116,8 @@ void uart_send(UartDevice dev, const void *buf, size_t len) {
volatile tegra_uart_t *uart = uart_get_regs(dev); volatile tegra_uart_t *uart = uart_get_regs(dev);
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) { while (!(uart->UART_LSR & UART_LSR_THRE)) {
/* Wait until the TX FIFO isn't full */ /* Wait until it's possible to send data. */
} }
uart->UART_THR_DLAB = *((const uint8_t *)buf + i); uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
} }
@@ -64,8 +127,8 @@ void uart_recv(UartDevice dev, void *buf, size_t len) {
volatile tegra_uart_t *uart = uart_get_regs(dev); volatile tegra_uart_t *uart = uart_get_regs(dev);
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) { while (!(uart->UART_LSR & UART_LSR_RDR)) {
/* Wait until the RX FIFO isn't empty */ /* Wait until it's possible to receive data. */
} }
*((uint8_t *)buf + i) = uart->UART_THR_DLAB; *((uint8_t *)buf + i) = uart->UART_THR_DLAB;
} }

View File

@@ -157,6 +157,7 @@ typedef struct {
uint32_t UART_ASR; uint32_t UART_ASR;
} tegra_uart_t; } tegra_uart_t;
void uart_config(UartDevice dev);
void uart_init(UartDevice dev, uint32_t baud); void uart_init(UartDevice dev, uint32_t baud);
void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_wait_idle(UartDevice dev, UartVendorStatus status);
void uart_send(UartDevice dev, const void *buf, size_t len); void uart_send(UartDevice dev, const void *buf, size_t len);

View File

@@ -17,6 +17,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdarg.h> #include <stdarg.h>
#include "utils.h" #include "utils.h"
#include "di.h"
#include "se.h" #include "se.h"
#include "fuse.h" #include "fuse.h"
#include "pmc.h" #include "pmc.h"
@@ -24,8 +25,8 @@
#include "panic.h" #include "panic.h"
#include "car.h" #include "car.h"
#include "btn.h" #include "btn.h"
#include "lib/log.h" #include "lib/log.h"
#include "display/video_fb.h"
#include <inttypes.h> #include <inttypes.h>
@@ -97,12 +98,34 @@ __attribute__ ((noreturn)) void generic_panic(void) {
} }
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) { __attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
/* Forcefully initialize the screen if logging is disabled. */
if (log_get_log_level() == SCREEN_LOG_LEVEL_NONE) {
/* Zero-fill the framebuffer and register it as printk provider. */
video_init((void *)0xC0000000);
/* Initialize the display. */
display_init();
/* Set the framebuffer. */
display_init_framebuffer((void *)0xC0000000);
/* Turn on the backlight after initializing the lfb */
/* to avoid flickering. */
display_backlight(true);
/* Override the global logging level. */
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
}
/* Display fatal error. */
va_list args; va_list args;
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: "); print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
va_start(args, fmt); va_start(args, fmt);
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args); vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
va_end(args); va_end(args);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n"); print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
/* Wait for button and reboot. */
wait_for_button_and_reboot(); wait_for_button_and_reboot();
} }

View File

@@ -25,7 +25,7 @@ static inline uint32_t get_clk_source_reg(CarDevice dev) {
case CARDEVICE_UARTC: return 0x1A0; case CARDEVICE_UARTC: return 0x1A0;
case CARDEVICE_I2C1: return 0x124; case CARDEVICE_I2C1: return 0x124;
case CARDEVICE_I2C5: return 0x128; case CARDEVICE_I2C5: return 0x128;
case CARDEVICE_UNK: return 0; case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0x42C; case CARDEVICE_SE: return 0x42C;
case CARDEVICE_HOST1X: return 0x180; case CARDEVICE_HOST1X: return 0x180;
case CARDEVICE_TSEC: return 0x1F4; case CARDEVICE_TSEC: return 0x1F4;
@@ -48,7 +48,7 @@ static inline uint32_t get_clk_source_val(CarDevice dev) {
case CARDEVICE_UARTC: return 0; case CARDEVICE_UARTC: return 0;
case CARDEVICE_I2C1: return 6; case CARDEVICE_I2C1: return 6;
case CARDEVICE_I2C5: return 6; case CARDEVICE_I2C5: return 6;
case CARDEVICE_UNK: return 0; case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0; case CARDEVICE_SE: return 0;
case CARDEVICE_HOST1X: return 4; case CARDEVICE_HOST1X: return 4;
case CARDEVICE_TSEC: return 0; case CARDEVICE_TSEC: return 0;
@@ -71,7 +71,7 @@ static inline uint32_t get_clk_source_div(CarDevice dev) {
case CARDEVICE_UARTC: return 0; case CARDEVICE_UARTC: return 0;
case CARDEVICE_I2C1: return 0; case CARDEVICE_I2C1: return 0;
case CARDEVICE_I2C5: return 0; case CARDEVICE_I2C5: return 0;
case CARDEVICE_UNK: return 0; case CARDEVICE_TZRAM: return 0;
case CARDEVICE_SE: return 0; case CARDEVICE_SE: return 0;
case CARDEVICE_HOST1X: return 3; case CARDEVICE_HOST1X: return 3;
case CARDEVICE_TSEC: return 2; case CARDEVICE_TSEC: return 2;

View File

@@ -42,7 +42,7 @@ typedef enum {
CARDEVICE_UARTC = ((1 << 5) | 0x17), CARDEVICE_UARTC = ((1 << 5) | 0x17),
CARDEVICE_I2C1 = ((0 << 5) | 0xC), CARDEVICE_I2C1 = ((0 << 5) | 0xC),
CARDEVICE_I2C5 = ((1 << 5) | 0xF), CARDEVICE_I2C5 = ((1 << 5) | 0xF),
CARDEVICE_UNK = ((3 << 5) | 0x1E), CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
CARDEVICE_SE = ((3 << 5) | 0x1F), CARDEVICE_SE = ((3 << 5) | 0x1F),
CARDEVICE_HOST1X = ((0 << 5) | 0x1C), CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
CARDEVICE_TSEC = ((2 << 5) | 0x13), CARDEVICE_TSEC = ((2 << 5) | 0x13),

View File

@@ -97,26 +97,23 @@ static ssize_t decode_utf8(uint32_t *out, const uint8_t *in) {
} }
static void console_init_display(void) { static void console_init_display(void) {
if (!g_display_initialized) { /* Initialize the display. */
/* Initialize the display. */ display_init();
display_init();
}
/* Set the framebuffer. */ /* Set the framebuffer. */
display_init_framebuffer(g_framebuffer); display_init_framebuffer(g_framebuffer);
/* Turn on the backlight after initializing the lfb */ /* Turn on the backlight after initializing the lfb */
/* to avoid flickering. */ /* to avoid flickering. */
if (!g_display_initialized) { display_backlight(true);
display_backlight(true);
}
/* Display is initialized. */
g_display_initialized = true; g_display_initialized = true;
} }
static ssize_t console_write(struct _reent *r, void *fd, const char *ptr, size_t len) { static ssize_t console_write(struct _reent *r, void *fd, const char *ptr, size_t len) {
size_t i = 0; size_t i = 0;
if (!g_display_initialized) { if (!g_display_initialized && (g_framebuffer != NULL)) {
console_init_display(); console_init_display();
} }
while (i < len) { while (i < len) {
@@ -138,6 +135,8 @@ static int console_create(void) {
errno = EEXIST; errno = EEXIST;
return -1; return -1;
} }
/* Allocate memory for the framebuffer. */
g_framebuffer = memalign(0x1000, CONFIG_VIDEO_VISIBLE_ROWS * CONFIG_VIDEO_COLS * CONFIG_VIDEO_PIXEL_SIZE); g_framebuffer = memalign(0x1000, CONFIG_VIDEO_VISIBLE_ROWS * CONFIG_VIDEO_COLS * CONFIG_VIDEO_PIXEL_SIZE);
if (g_framebuffer == NULL) { if (g_framebuffer == NULL) {
@@ -154,9 +153,7 @@ static int console_create(void) {
return 0; return 0;
} }
int console_init(bool display_initialized) { int console_init(void) {
g_display_initialized = display_initialized;
if (console_create() == -1) { if (console_create() == -1) {
return -1; return -1;
} }
@@ -171,15 +168,15 @@ int console_init(bool display_initialized) {
return 0; return 0;
} }
void *console_get_framebuffer(bool enable_display) { void *console_get_framebuffer(void) {
if (g_framebuffer != NULL && enable_display) { if (!g_display_initialized && (g_framebuffer != NULL)) {
console_init_display(); console_init_display();
} }
return g_framebuffer; return g_framebuffer;
} }
int console_display(const void *framebuffer) { int console_display(const void *framebuffer) {
if (!g_display_initialized) { if (!g_display_initialized && (g_framebuffer != NULL)) {
console_init_display(); console_init_display();
} }
display_init_framebuffer((void *)framebuffer); display_init_framebuffer((void *)framebuffer);
@@ -187,7 +184,7 @@ int console_display(const void *framebuffer) {
} }
int console_resume(void) { int console_resume(void) {
if (!g_display_initialized) { if (!g_display_initialized && (g_framebuffer != NULL)) {
console_init_display(); console_init_display();
} else { } else {
display_init_framebuffer(g_framebuffer); display_init_framebuffer(g_framebuffer);
@@ -196,10 +193,15 @@ int console_resume(void) {
} }
int console_end(void) { int console_end(void) {
/* Deinitialize the framebuffer and display */
if (g_display_initialized) { if (g_display_initialized) {
/* Turn off the backlight. */
display_backlight(false); display_backlight(false);
/* Terminate the display. */
display_end(); display_end();
/* Display is terminated. */
g_display_initialized = false;
} }
free(g_framebuffer); free(g_framebuffer);
g_framebuffer = NULL; g_framebuffer = NULL;

View File

@@ -24,8 +24,8 @@
#include <malloc.h> #include <malloc.h>
#include <sys/iosupport.h> #include <sys/iosupport.h>
int console_init(bool display_initialized); int console_init(void);
void *console_get_framebuffer(bool enable_display); void *console_get_framebuffer(void);
int console_display(const void *framebuffer); /* Must be page-aligned */ int console_display(const void *framebuffer); /* Must be page-aligned */
int console_resume(void); int console_resume(void);
int console_end(void); int console_end(void);

View File

@@ -76,6 +76,9 @@ typedef enum {
FS_VER_8_1_0, FS_VER_8_1_0,
FS_VER_8_1_0_EXFAT, FS_VER_8_1_0_EXFAT,
FS_VER_9_0_0,
FS_VER_9_0_0_EXFAT,
FS_VER_MAX, FS_VER_MAX,
} emummc_fs_ver_t; } emummc_fs_ver_t;

View File

@@ -21,125 +21,66 @@
#include "gpio.h" #include "gpio.h"
#include "utils.h" #include "utils.h"
/** static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin) {
* Returns a GPIO bank object that corresponds to the given GPIO pin,
* which can be created using the TEGRA_GPIO macro or passed from the name macro.
*
* @param pin The GPIO to get the bank for.
* @return The GPIO bank object to use for working with the given bank.
*/
static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin)
{
volatile tegra_gpio_t *gpio = gpio_get_regs(); volatile tegra_gpio_t *gpio = gpio_get_regs();
uint32_t bank_number = pin >> GPIO_BANK_SHIFT; uint32_t bank_number = (pin >> GPIO_BANK_SHIFT);
return &gpio->bank[bank_number]; return &gpio->bank[bank_number];
} }
/** static volatile uint32_t gpio_get_port(uint32_t pin) {
* @return the port number for working with the given GPIO. return ((pin >> GPIO_PORT_SHIFT) & GPIO_PORT_MASK);
*/
static volatile uint32_t gpio_get_port(uint32_t pin)
{
return (pin >> GPIO_PORT_SHIFT) & GPIO_PORT_MASK;
} }
/** static volatile uint32_t gpio_get_mask(uint32_t pin) {
* @return a mask to be used to work with the given GPIO uint32_t pin_number = (pin & GPIO_PIN_MASK);
*/
static volatile uint32_t gpio_get_mask(uint32_t pin)
{
uint32_t pin_number = pin & GPIO_PIN_MASK;
return (1 << pin_number); return (1 << pin_number);
} }
/** static void gpio_simple_register_set(uint32_t pin, bool should_be_set, uint32_t offset) {
* Performs a simple GPIO configuration operation. /* Retrieve the register set that corresponds to the given pin and offset. */
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param should_be_set True iff the relevant bit should be set; or false if it should be cleared.
* @param offset The offset into a gpio_bank structure
*/
static void gpio_simple_register_set(uint32_t pin, bool should_be_set, uint32_t offset)
{
// Retrieve the register set that corresponds to the given pin and offset.
uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset; uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset;
uint32_t *cluster = (uint32_t *)cluster_addr; uint32_t *cluster = (uint32_t *)cluster_addr;
// Figure out the offset into the cluster, /* Figure out the offset into the cluster, and the mask to be used. */
// and the mask to be used.
uint32_t port = gpio_get_port(pin); uint32_t port = gpio_get_port(pin);
uint32_t mask = gpio_get_mask(pin); uint32_t mask = gpio_get_mask(pin);
// Set or clear the bit, as appropriate. /* Set or clear the bit, as appropriate. */
if (should_be_set) if (should_be_set)
cluster[port] |= mask; cluster[port] |= mask;
else else
cluster[port] &= ~mask; cluster[port] &= ~mask;
/* Dummy read. */
(void)cluster[port];
} }
/** static bool gpio_simple_register_get(uint32_t pin, uint32_t offset) {
* Performs a simple GPIO configuration operation. /* Retrieve the register set that corresponds to the given pin and offset. */
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param should_be_set True iff the relevant bit should be set; or false if it should be cleared.
* @param offset The offset into a gpio_bank structure
*/
static bool gpio_simple_register_get(uint32_t pin, uint32_t offset)
{
// Retrieve the register set that corresponds to the given pin and offset.
uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset; uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset;
uint32_t *cluster = (uint32_t *)cluster_addr; uint32_t *cluster = (uint32_t *)cluster_addr;
// Figure out the offset into the cluster, /* Figure out the offset into the cluster, and the mask to be used. */
// and the mask to be used.
uint32_t port = gpio_get_port(pin); uint32_t port = gpio_get_port(pin);
uint32_t mask = gpio_get_mask(pin); uint32_t mask = gpio_get_mask(pin);
// Convert the given value to a boolean. /* Convert the given value to a boolean. */
return !!(cluster[port] & mask); return !!(cluster[port] & mask);
} }
/** void gpio_configure_mode(uint32_t pin, uint32_t mode) {
* Configures a given pin as either GPIO or SFIO.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_configure_mode(uint32_t pin, uint32_t mode)
{
gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config)); gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config));
} }
/** void gpio_configure_direction(uint32_t pin, uint32_t dir) {
* Configures a given pin as either INPUT or OUPUT.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param direction The relevant direction.
*/
void gpio_configure_direction(uint32_t pin, uint32_t dir)
{
gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(tegra_gpio_bank_t, direction)); gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(tegra_gpio_bank_t, direction));
} }
/** void gpio_write(uint32_t pin, uint32_t value) {
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_write(uint32_t pin, uint32_t value)
{
gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(tegra_gpio_bank_t, out)); gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(tegra_gpio_bank_t, out));
} }
/** uint32_t gpio_read(uint32_t pin) {
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
uint32_t gpio_read(uint32_t pin)
{
return gpio_simple_register_get(pin, offsetof(tegra_gpio_bank_t, in)); return gpio_simple_register_get(pin, offsetof(tegra_gpio_bank_t, in));
} }

View File

@@ -96,8 +96,8 @@ static inline volatile tegra_gpio_t *gpio_get_regs(void)
((TEGRA_GPIO_PORT_##port * 8) + offset) ((TEGRA_GPIO_PORT_##port * 8) + offset)
/* Mode select */ /* Mode select */
#define GPIO_MODE_GPIO 0 #define GPIO_MODE_SFIO 0
#define GPIO_MODE_SFIO 1 #define GPIO_MODE_GPIO 1
/* Direction */ /* Direction */
#define GPIO_DIRECTION_INPUT 0 #define GPIO_DIRECTION_INPUT 0

View File

@@ -17,19 +17,52 @@
#include "i2c.h" #include "i2c.h"
#include "utils.h" #include "utils.h"
#include "timers.h" #include "timers.h"
#include "pinmux.h"
/* Prototypes for internal commands. */ /* Prototypes for internal commands. */
volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id);
void i2c_load_config(volatile tegra_i2c_t *regs); void i2c_load_config(volatile tegra_i2c_t *regs);
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size);
bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size);
/* Configure I2C pinmux. */
void i2c_config(I2CDevice id) {
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
switch (id) {
case I2C_1:
pinmux->gen1_i2c_scl = PINMUX_INPUT;
pinmux->gen1_i2c_sda = PINMUX_INPUT;
break;
case I2C_2:
pinmux->gen2_i2c_scl = PINMUX_INPUT;
pinmux->gen2_i2c_sda = PINMUX_INPUT;
break;
case I2C_3:
pinmux->gen3_i2c_scl = PINMUX_INPUT;
pinmux->gen3_i2c_sda = PINMUX_INPUT;
break;
case I2C_4:
pinmux->cam_i2c_scl = PINMUX_INPUT;
pinmux->cam_i2c_sda = PINMUX_INPUT;
break;
case I2C_5:
pinmux->pwr_i2c_scl = PINMUX_INPUT;
pinmux->pwr_i2c_sda = PINMUX_INPUT;
break;
case I2C_6:
/* Unused. */
break;
default: break;
}
}
/* Initialize I2C based on registers. */ /* Initialize I2C based on registers. */
void i2c_init(unsigned int id) { void i2c_init(I2CDevice id) {
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
/* Setup divisor, and clear the bus. */ /* Setup divisor, and clear the bus. */
@@ -91,7 +124,7 @@ void i2c_set_ti_charger_bit_7(void) {
} }
/* Get registers pointer based on I2C ID. */ /* Get registers pointer based on I2C ID. */
volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) {
switch (id) { switch (id) {
case I2C_1: case I2C_1:
return I2C1_REGS; return I2C1_REGS;
@@ -126,7 +159,7 @@ void i2c_load_config(volatile tegra_i2c_t *regs) {
} }
/* Reads a register from a device over I2C, writes result to output. */ /* Reads a register from a device over I2C, writes result to output. */
bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) {
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
uint32_t val = r; uint32_t val = r;
@@ -143,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst
} }
/* Writes a value to a register over I2C. */ /* Writes a value to a register over I2C. */
bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) {
uint32_t val = r; uint32_t val = r;
if (src_size == 0) { if (src_size == 0) {
return true; return true;

Some files were not shown because too many files have changed in this diff Show More