Compare commits
149 Commits
1.0.1
...
Fastfs_Tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b91c36d3fa | ||
|
|
a8e86c2de3 | ||
|
|
6934e1422f | ||
|
|
f49245e4ab | ||
|
|
9075f20854 | ||
|
|
6bc474a981 | ||
|
|
91536268ad | ||
|
|
b484dc11d8 | ||
|
|
14a3a39c01 | ||
|
|
6868ef3536 | ||
|
|
97810335ed | ||
|
|
43617ef511 | ||
|
|
19fe7f15a9 | ||
|
|
73ca98c6a8 | ||
|
|
12eecd2466 | ||
|
|
40cb293db3 | ||
|
|
f09a098c77 | ||
|
|
30f0e88d0a | ||
|
|
c4c5d57af3 | ||
|
|
00a58f12ec | ||
|
|
74ba5bb776 | ||
|
|
a9ea9725d4 | ||
|
|
9799e2b47e | ||
|
|
6681a35b2c | ||
|
|
22ecb34fec | ||
|
|
cb46e4bc40 | ||
|
|
6c2d0cf162 | ||
|
|
4907afd9f3 | ||
|
|
acb43b67db | ||
|
|
baac8dc2fb | ||
|
|
7add4b6b13 | ||
|
|
a146a38af7 | ||
|
|
c45be1258a | ||
|
|
b9776882fd | ||
|
|
b0f2ce4211 | ||
|
|
f9cf371cf9 | ||
|
|
b273b1e5ab | ||
|
|
0bf3b35582 | ||
|
|
2cac144ba8 | ||
|
|
0d98f65f99 | ||
|
|
83e6bf7090 | ||
|
|
4aca6e5fcf | ||
|
|
aa6d522c16 | ||
|
|
2cced5bdac | ||
|
|
9178813338 | ||
|
|
7ad77cffb0 | ||
|
|
12c3ffc2e4 | ||
|
|
305c372d8c | ||
|
|
931cbc829f | ||
|
|
87d4e4c5f1 | ||
|
|
6ee5c8cb5f | ||
|
|
a3d4636d84 | ||
|
|
52c6438e32 | ||
|
|
ab4e88f1de | ||
|
|
0c039e03c3 | ||
|
|
adc9d2e5bf | ||
|
|
317e4b2038 | ||
|
|
bd99e2a138 | ||
|
|
4c4a6511f3 | ||
|
|
2bbcf63bd9 | ||
|
|
78722d9a90 | ||
|
|
e24f8ad722 | ||
|
|
28fb01b155 | ||
|
|
b8b37e78ba | ||
|
|
82a4d03985 | ||
|
|
195d9797fe | ||
|
|
15e1210179 | ||
|
|
e892e69929 | ||
|
|
7e8e3ece66 | ||
|
|
b5a9d94d35 | ||
|
|
f95b6e399f | ||
|
|
6551930233 | ||
|
|
c2a2694baf | ||
|
|
03df13f34c | ||
|
|
070f9c676d | ||
|
|
7dc3500a17 | ||
|
|
97bbe2a333 | ||
|
|
a6eaa1ec51 | ||
|
|
f93cc0ff44 | ||
|
|
ee145ca9aa | ||
|
|
8832b240a4 | ||
|
|
744f90611a | ||
|
|
440a921980 | ||
|
|
d0799e3cd1 | ||
|
|
5b32937f8f | ||
|
|
f438827263 | ||
|
|
0e60746179 | ||
|
|
0e39c8dda9 | ||
|
|
45a732c388 | ||
|
|
034384622f | ||
|
|
9efbbc9317 | ||
|
|
30afcddd3a | ||
|
|
38f349618f | ||
|
|
33a64abfb0 | ||
|
|
c4783fc2ca | ||
|
|
887972d67c | ||
|
|
9aff029ee4 | ||
|
|
bfcdc2ffd5 | ||
|
|
e4ae9d9d7c | ||
|
|
d255dcf665 | ||
|
|
f1a4b05524 | ||
|
|
d5c23ebf96 | ||
|
|
4e1368faaf | ||
|
|
2d6411f60a | ||
|
|
7191743f5d | ||
|
|
9d36f741d9 | ||
|
|
ff618bc285 | ||
|
|
c60eb4b722 | ||
|
|
6aed4ad7b3 | ||
|
|
761ceb7dbe | ||
|
|
3f6d1b532c | ||
|
|
144dc3a3f5 | ||
|
|
5cb50722cf | ||
|
|
7c7dd7178f | ||
|
|
d93b50205a | ||
|
|
405cb46b77 | ||
|
|
7f7c2e65ee | ||
|
|
c2df3d80dd | ||
|
|
a3b876ea3e | ||
|
|
4309194a11 | ||
|
|
ae57cb1e63 | ||
|
|
a86294218c | ||
|
|
eecefd634c | ||
|
|
37ce49a31f | ||
|
|
ab061cf0b3 | ||
|
|
1a2fd158e9 | ||
|
|
eb8652c6ec | ||
|
|
9885308bce | ||
|
|
1410fa185f | ||
|
|
6724f364b5 | ||
|
|
008d3ab494 | ||
|
|
00bd1cd083 | ||
|
|
6af2bb63b8 | ||
|
|
02504c8a36 | ||
|
|
ef76834ef4 | ||
|
|
6d75aa688c | ||
|
|
225a17116c | ||
|
|
e1f4c24686 | ||
|
|
3e8cd67129 | ||
|
|
697fc3a086 | ||
|
|
6518f37b1c | ||
|
|
81e97fa820 | ||
|
|
12802bf371 | ||
|
|
d1678be654 | ||
|
|
2a78d3c924 | ||
|
|
d4010ba04d | ||
|
|
7b6c19f820 | ||
|
|
3274d18b83 | ||
|
|
472c0e293a |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: suchmememanyskill
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
36
.github/workflows/builder.yml
vendored
Normal file
36
.github/workflows/builder.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: TegraExplorer builder
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install devkitpro
|
||||||
|
run: |
|
||||||
|
wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb
|
||||||
|
sudo dpkg -i devkitpro-pacman.deb
|
||||||
|
sudo dkp-pacman -S switch-dev --noconfirm
|
||||||
|
sudo dkp-pacman -S devkitARM --noconfirm
|
||||||
|
|
||||||
|
- name: Build TegraExplorer
|
||||||
|
run: |
|
||||||
|
echo # SETTING PATH #
|
||||||
|
export DEVKITPRO=/opt/devkitpro
|
||||||
|
export DEVKITARM=${DEVKITPRO}/devkitARM
|
||||||
|
export DEVKITPPC=${DEVKITPRO}/devkitPPC
|
||||||
|
export PATH=${DEVKITPRO}/tools/bin:$PATH
|
||||||
|
echo # MAKE #
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: TegraExplorer
|
||||||
|
path: output/TegraExplorer.bin
|
||||||
6
Makefile
6
Makefile
@@ -8,10 +8,10 @@ include $(DEVKITARM)/base_rules
|
|||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
IPL_LOAD_ADDR := 0x40003000
|
IPL_LOAD_ADDR := 0x40008000
|
||||||
LPVERSION_MAJOR := 2
|
LPVERSION_MAJOR := 3
|
||||||
LPVERSION_MINOR := 0
|
LPVERSION_MINOR := 0
|
||||||
LPVERSION_BUGFX := 0
|
LPVERSION_BUGFX := 2
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
|||||||
51
README.md
51
README.md
@@ -1,25 +1,62 @@
|
|||||||
# TegraExplorer
|
# TegraExplorer
|
||||||
A payload-based file explorer for your switch!
|
A payload-based file explorer for your switch!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
1. Get your favorite payload injector
|
1. Get your favorite payload injector
|
||||||
2. Inject TegraExplorer as a payload
|
2. Inject TegraExplorer as a payload
|
||||||
|
|
||||||
Navigate around the menu's using the vol+, vol- and power buttons
|
Navigate around the menus using the joycons.
|
||||||
|
A: Select
|
||||||
|
B: Back
|
||||||
|
Left Joystick up/down (Dpad or joystick): navigate menus up/down
|
||||||
|
Right Joystick up/down: fast menu navigation up/down
|
||||||
|
Capture (Minerva only): Take a screenshot
|
||||||
|
L3/R3 (Press joysticks in): Recalibrate centerpoint
|
||||||
|
|
||||||
|
If you do not have your joycons connected:
|
||||||
|
Power -> A
|
||||||
|
Vol+ -> Left Joystick up
|
||||||
|
Vol- -> Left Joystick down
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
- Navigate the SD card
|
- Navigate the SD card
|
||||||
- Navigate the System partition of your sysnand
|
- Navigate the System partition of your sysmmc and emummc
|
||||||
- Interact with files
|
- Interact with files
|
||||||
- Deleting, copying or moving files
|
- Deleting, copying, renaming and moving files
|
||||||
- Launching payloads files
|
- Launching payloads files
|
||||||
- Viewing the hex data of a file
|
- Viewing the hex data of a file
|
||||||
|
- Launching special [TegraScript](https://github.com/suchmememanyskill/TegraScript) files
|
||||||
|
- Renaming files
|
||||||
|
- Interacting with folders
|
||||||
|
- Deleting, copying or renaming folders
|
||||||
|
- Creating folders
|
||||||
- Dumping your current firmware to sd
|
- Dumping your current firmware to sd
|
||||||
- Formatting the sd card
|
- Formatting the sd card
|
||||||
|
|
||||||
# Credits
|
*and more*
|
||||||
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus based on [Hekate](https://github.com/CTCaer/hekate)
|
|
||||||
|
|
||||||
Lots of help from:
|
## Support
|
||||||
|
|
||||||
|
For general CFW support, go to the [Nintendo Homebrew](https://discord.gg/C29hYvh) discord
|
||||||
|
|
||||||
|
For question specifically for TegraExplorer, go to [my discord](https://discord.gg/aH9rsuP)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate)
|
||||||
|
|
||||||
|
Awesome people who helped with this project:
|
||||||
- shchmue
|
- shchmue
|
||||||
- Denn
|
- Dennthecafebabe
|
||||||
|
|
||||||
|
Other awesome people:
|
||||||
|
- PhazonicRidley
|
||||||
|
- Dax
|
||||||
|
- Huhen
|
||||||
|
- Bleck9999
|
||||||
|
- Exelix
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Common Gfx Header
|
* Common Gfx Header
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
* Copyright (C) 2018 M4xw
|
* Copyright (c) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
* version 2, as published by the Free Software Foundation.
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Common Module Header
|
* Common Module Header
|
||||||
* Copyright (C) 2018 M4xw
|
* Copyright (c) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
//#define IPL_STACK_TOP 0x4003FF00
|
//#define IPL_STACK_TOP 0x4003FF00
|
||||||
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
|
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
|
||||||
/* --- IPL: 0x40003000 - 0x40028000 --- */
|
/* --- IPL: 0x40008000 - 0x40028000 --- */
|
||||||
#define IPL_LOAD_ADDR 0x40003000
|
#define IPL_LOAD_ADDR 0x40008000
|
||||||
#define IPL_SZ_MAX 0x20000 // 128KB.
|
#define IPL_SZ_MAX 0x20000 // 128KB.
|
||||||
//#define IRAM_LIB_ADDR 0x4002B000
|
//#define IRAM_LIB_ADDR 0x4002B000
|
||||||
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
|
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
|
||||||
@@ -28,60 +28,74 @@
|
|||||||
|
|
||||||
/* --- DRAM START --- */
|
/* --- DRAM START --- */
|
||||||
#define DRAM_START 0x80000000
|
#define DRAM_START 0x80000000
|
||||||
/* Do not write anything in this area */
|
#define HOS_RSVD 0x1000000 // Do not write anything in this area.
|
||||||
#define NYX_LOAD_ADDR 0x81000000
|
|
||||||
#define NYX_SZ_MAX 0x1000000
|
|
||||||
/* Stack theoretical max: 220MB */
|
|
||||||
#define IPL_STACK_TOP 0x90010000
|
|
||||||
#define IPL_HEAP_START 0x90020000
|
|
||||||
#define IPL_HEAP_SZ 0x24FE0000 // 592MB.
|
|
||||||
/* --- Gap: 0xB5000000 - 0xB5FFFFFF --- */
|
|
||||||
|
|
||||||
// SDMMC DMA buffers
|
#define NYX_LOAD_ADDR 0x81000000
|
||||||
#define SDXC_BUF_ALIGNED 0xB6000000
|
#define NYX_SZ_MAX 0x1000000 // 16MB
|
||||||
#define MIXD_BUF_ALIGNED 0xB7000000
|
/* --- Gap: 0x82000000 - 0x82FFFFFF --- */
|
||||||
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
|
|
||||||
#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used).
|
/* Stack theoretical max: 33MB */
|
||||||
#define SDMMC_UPPER_BUFFER 0xB8000000
|
#define IPL_STACK_TOP 0x83100000
|
||||||
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB.
|
#define IPL_HEAP_START 0x84000000
|
||||||
|
#define IPL_HEAP_SZ 0x20000000 // 512MB.
|
||||||
|
/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */
|
||||||
|
|
||||||
// Virtual disk / Chainloader buffers.
|
// Virtual disk / Chainloader buffers.
|
||||||
#define RAM_DISK_ADDR 0xC1000000
|
#define RAM_DISK_ADDR 0xA4000000
|
||||||
#define RAM_DISK_SZ 0x20000000
|
#define RAM_DISK_SZ 0x41000000 // 1040MB.
|
||||||
|
|
||||||
//#define DRAM_LIB_ADDR 0xE0000000
|
//#define DRAM_LIB_ADDR 0xE0000000
|
||||||
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
|
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
|
||||||
/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */
|
|
||||||
|
// SDMMC DMA buffers 1
|
||||||
|
#define SDMMC_UPPER_BUFFER 0xE5000000
|
||||||
|
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB.
|
||||||
|
|
||||||
// Nyx buffers.
|
// Nyx buffers.
|
||||||
#define NYX_STORAGE_ADDR 0xED000000
|
#define NYX_STORAGE_ADDR 0xED000000
|
||||||
#define NYX_RES_ADDR 0xEE000000
|
#define NYX_RES_ADDR 0xEE000000
|
||||||
|
#define NYX_RES_SZ 0x1000000 // 16MB.
|
||||||
|
|
||||||
// Framebuffer addresses.
|
// SDMMC DMA buffers 2
|
||||||
#define IPL_FB_ADDRESS 0xF0000000
|
#define SDXC_BUF_ALIGNED 0xEF000000
|
||||||
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
|
#define MIXD_BUF_ALIGNED 0xF0000000
|
||||||
#define LOG_FB_ADDRESS 0xF0400000
|
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
|
||||||
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4.
|
#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used).
|
||||||
#define NYX_FB_ADDRESS 0xF0800000
|
|
||||||
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
|
|
||||||
|
|
||||||
// Nyx LvGL buffers.
|
// Nyx LvGL buffers.
|
||||||
#define NYX_LV_VDB_ADR 0xF0C00000
|
#define NYX_LV_VDB_ADR 0xF1000000
|
||||||
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
|
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
|
||||||
#define NYX_LV_MEM_ADR 0xF1000000
|
#define NYX_LV_MEM_ADR 0xF1400000
|
||||||
#define NYX_LV_MEM_SZ 0x8000000
|
#define NYX_LV_MEM_SZ 0x6600000 // 70MB.
|
||||||
|
|
||||||
|
// Framebuffer addresses.
|
||||||
|
#define IPL_FB_ADDRESS 0xF5A00000
|
||||||
|
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
|
||||||
|
#define LOG_FB_ADDRESS 0xF5E00000
|
||||||
|
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4.
|
||||||
|
#define NYX_FB_ADDRESS 0xF6200000
|
||||||
|
#define NYX_FB2_ADDRESS 0xF6600000
|
||||||
|
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
|
||||||
|
|
||||||
|
#define DRAM_MEM_HOLE_ADR 0xF6A00000
|
||||||
|
#define DRAM_MEM_HOLE_SZ 0x8140000
|
||||||
|
/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */
|
||||||
|
#define DRAM_START2 0xFEB40000
|
||||||
|
|
||||||
// NX BIS driver sector cache.
|
// NX BIS driver sector cache.
|
||||||
#define NX_BIS_CACHE_ADDR 0xF9000000
|
#define NX_BIS_CACHE_ADDR 0xFEE00000
|
||||||
#define NX_BIS_CACHE_SZ 0x8800
|
#define NX_BIS_CACHE_SZ 0x8800
|
||||||
/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */
|
|
||||||
|
|
||||||
// #define EXT_PAYLOAD_ADDR 0xC03C0000
|
// USB buffers.
|
||||||
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
#define USBD_ADDR 0xFEF00000
|
||||||
// #define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
#define USB_DESCRIPTOR_ADDR 0xFEF40000
|
||||||
|
#define USB_EP_CONTROL_BUF_ADDR 0xFEF80000
|
||||||
|
#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000
|
||||||
|
#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000
|
||||||
|
#define USB_EP_BULK_OUT_MAX_XFER 0x800000
|
||||||
|
|
||||||
// NYX
|
|
||||||
// #define EXT_PAYLOAD_ADDR 0xC0000000
|
// #define EXT_PAYLOAD_ADDR 0xC0000000
|
||||||
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
||||||
// #define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
// #define COREBOOT_ADDR (0xD0000000 - rom_size)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
BIN
preview.png
Normal file
BIN
preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2019 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -23,26 +23,25 @@
|
|||||||
#include "../gfx/tui.h"
|
#include "../gfx/tui.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
#include "../utils/list.h"
|
#include "../utils/list.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
extern bool sd_mount();
|
|
||||||
extern void sd_unmount();
|
|
||||||
|
|
||||||
void set_default_configuration()
|
void set_default_configuration()
|
||||||
{
|
{
|
||||||
h_cfg.autoboot = 0;
|
h_cfg.autoboot = 0;
|
||||||
h_cfg.autoboot_list = 0;
|
h_cfg.autoboot_list = 0;
|
||||||
h_cfg.bootwait = 3;
|
h_cfg.bootwait = 3;
|
||||||
h_cfg.verification = 1;
|
|
||||||
h_cfg.se_keygen_done = 0;
|
h_cfg.se_keygen_done = 0;
|
||||||
h_cfg.sbar_time_keeping = 0;
|
h_cfg.sbar_time_keeping = 0;
|
||||||
h_cfg.backlight = 100;
|
h_cfg.backlight = 100;
|
||||||
h_cfg.autohosoff = 0;
|
h_cfg.autohosoff = 0;
|
||||||
h_cfg.autonogc = 1;
|
h_cfg.autonogc = 1;
|
||||||
|
h_cfg.updater2p = 0;
|
||||||
h_cfg.brand = NULL;
|
h_cfg.brand = NULL;
|
||||||
h_cfg.tagline = NULL;
|
h_cfg.tagline = NULL;
|
||||||
h_cfg.errors = 0;
|
h_cfg.errors = 0;
|
||||||
@@ -50,7 +49,7 @@ void set_default_configuration()
|
|||||||
h_cfg.rcm_patched = true;
|
h_cfg.rcm_patched = true;
|
||||||
h_cfg.emummc_force_disable = false;
|
h_cfg.emummc_force_disable = false;
|
||||||
|
|
||||||
sd_power_cycle_time_start = 0xFFFFFFF;
|
sd_power_cycle_time_start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_config_entry()
|
int create_config_entry()
|
||||||
@@ -96,9 +95,6 @@ int create_config_entry()
|
|||||||
f_puts("\nbootwait=", &fp);
|
f_puts("\nbootwait=", &fp);
|
||||||
itoa(h_cfg.bootwait, lbuf, 10);
|
itoa(h_cfg.bootwait, lbuf, 10);
|
||||||
f_puts(lbuf, &fp);
|
f_puts(lbuf, &fp);
|
||||||
f_puts("\nverification=", &fp);
|
|
||||||
itoa(h_cfg.verification, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nbacklight=", &fp);
|
f_puts("\nbacklight=", &fp);
|
||||||
itoa(h_cfg.backlight, lbuf, 10);
|
itoa(h_cfg.backlight, lbuf, 10);
|
||||||
f_puts(lbuf, &fp);
|
f_puts(lbuf, &fp);
|
||||||
@@ -108,6 +104,9 @@ int create_config_entry()
|
|||||||
f_puts("\nautonogc=", &fp);
|
f_puts("\nautonogc=", &fp);
|
||||||
itoa(h_cfg.autonogc, lbuf, 10);
|
itoa(h_cfg.autonogc, lbuf, 10);
|
||||||
f_puts(lbuf, &fp);
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nupdater2p=", &fp);
|
||||||
|
itoa(h_cfg.updater2p, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
if (h_cfg.brand)
|
if (h_cfg.brand)
|
||||||
{
|
{
|
||||||
f_puts("\nbrand=", &fp);
|
f_puts("\nbrand=", &fp);
|
||||||
@@ -281,10 +280,11 @@ void config_autoboot()
|
|||||||
LIST_INIT(ini_sections);
|
LIST_INIT(ini_sections);
|
||||||
|
|
||||||
u8 max_entries = 30;
|
u8 max_entries = 30;
|
||||||
|
u32 boot_text_size = 512;
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
|
||||||
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
||||||
char *boot_text = (char *)malloc(512 * max_entries);
|
char *boot_text = (char *)malloc(boot_text_size * max_entries);
|
||||||
|
|
||||||
for (u32 j = 0; j < max_entries; j++)
|
for (u32 j = 0; j < max_entries; j++)
|
||||||
boot_values[j] = j;
|
boot_values[j] = j;
|
||||||
@@ -330,12 +330,12 @@ void config_autoboot()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
|
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
|
||||||
boot_text[(i - 4) * 512] = ' ';
|
boot_text[(i - 4) * boot_text_size] = ' ';
|
||||||
|
|
||||||
else
|
else
|
||||||
boot_text[(i - 4) * 512] = '*';
|
boot_text[(i - 4) * boot_text_size] = '*';
|
||||||
strcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name);
|
strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name);
|
||||||
ments[i].caption = &boot_text[(i - 4) * 512];
|
ments[i].caption = &boot_text[(i - 4) * boot_text_size];
|
||||||
}
|
}
|
||||||
ments[i].type = ini_sec->type;
|
ments[i].type = ini_sec->type;
|
||||||
ments[i].data = &boot_values[i - 4];
|
ments[i].data = &boot_values[i - 4];
|
||||||
@@ -391,10 +391,11 @@ void config_bootdelay()
|
|||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
u32 delay_entries = 6;
|
u32 delay_entries = 6;
|
||||||
|
u32 delay_text_size = 32;
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
|
||||||
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
|
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
|
||||||
char *delay_text = (char *)malloc(32 * delay_entries);
|
char *delay_text = (char *)malloc(delay_text_size * delay_entries);
|
||||||
|
|
||||||
for (u32 j = 0; j < delay_entries; j++)
|
for (u32 j = 0; j < delay_entries; j++)
|
||||||
delay_values[j] = j;
|
delay_values[j] = j;
|
||||||
@@ -415,14 +416,14 @@ void config_bootdelay()
|
|||||||
for (i = 1; i < delay_entries; i++)
|
for (i = 1; i < delay_entries; i++)
|
||||||
{
|
{
|
||||||
if (h_cfg.bootwait != i)
|
if (h_cfg.bootwait != i)
|
||||||
delay_text[i * 32] = ' ';
|
delay_text[i * delay_text_size] = ' ';
|
||||||
else
|
else
|
||||||
delay_text[i * 32] = '*';
|
delay_text[i * delay_text_size] = '*';
|
||||||
delay_text[i * 32 + 1] = i + '0';
|
delay_text[i * delay_text_size + 1] = i + '0';
|
||||||
strcpy(delay_text + i * 32 + 2, " seconds");
|
strcpy(delay_text + i * delay_text_size + 2, " seconds");
|
||||||
|
|
||||||
ments[i + 2].type = MENT_DATA;
|
ments[i + 2].type = MENT_DATA;
|
||||||
ments[i + 2].caption = delay_text + i * 32;
|
ments[i + 2].caption = delay_text + (i * delay_text_size);
|
||||||
ments[i + 2].data = &delay_values[i];
|
ments[i + 2].data = &delay_values[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,69 +446,17 @@ void config_bootdelay()
|
|||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_verification()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
|
||||||
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
|
|
||||||
char *vr_text = (char *)malloc(64 * 3);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
vr_values[j] = j;
|
|
||||||
ments[j + 2].type = MENT_DATA;
|
|
||||||
ments[j + 2].data = &vr_values[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
strcpy(vr_text, " Disable (Fastest - Unsafe)");
|
|
||||||
strcpy(vr_text + 64, " Sparse (Fast - Safe)");
|
|
||||||
strcpy(vr_text + 128, " Full (Slow - Safe)");
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (h_cfg.verification != i)
|
|
||||||
vr_text[64 * i] = ' ';
|
|
||||||
else
|
|
||||||
vr_text[64 * i] = '*';
|
|
||||||
ments[2 + i].caption = vr_text + (i * 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[5], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_verification = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_verification != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.verification = *(u32 *)temp_verification;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(vr_values);
|
|
||||||
free(vr_text);
|
|
||||||
|
|
||||||
if (temp_verification == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_backlight()
|
void config_backlight()
|
||||||
{
|
{
|
||||||
gfx_clear_grey(0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
u32 bri_text_size = 8;
|
||||||
u32 bri_entries = 11;
|
u32 bri_entries = 11;
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
|
||||||
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
|
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
|
||||||
char *bri_text = (char *)malloc(8 * bri_entries);
|
char *bri_text = (char *)malloc(bri_text_size * bri_entries);
|
||||||
|
|
||||||
for (u32 j = 1; j < bri_entries; j++)
|
for (u32 j = 1; j < bri_entries; j++)
|
||||||
bri_values[j] = j * 10;
|
bri_values[j] = j * 10;
|
||||||
@@ -521,20 +470,20 @@ void config_backlight()
|
|||||||
for (i = 1; i < bri_entries; i++)
|
for (i = 1; i < bri_entries; i++)
|
||||||
{
|
{
|
||||||
if ((h_cfg.backlight / 20) != i)
|
if ((h_cfg.backlight / 20) != i)
|
||||||
bri_text[i * 32] = ' ';
|
bri_text[i * bri_text_size] = ' ';
|
||||||
else
|
else
|
||||||
bri_text[i * 32] = '*';
|
bri_text[i * bri_text_size] = '*';
|
||||||
|
|
||||||
if (i < 10)
|
if (i < 10)
|
||||||
{
|
{
|
||||||
bri_text[i * 32 + 1] = i + '0';
|
bri_text[i * bri_text_size + 1] = i + '0';
|
||||||
strcpy(bri_text + i * 32 + 2, "0%");
|
strcpy(bri_text + i * bri_text_size + 2, "0%");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
strcpy(bri_text + i * 32 + 1, "100%");
|
strcpy(bri_text + i * bri_text_size + 1, "100%");
|
||||||
|
|
||||||
ments[i + 1].type = MENT_DATA;
|
ments[i + 1].type = MENT_DATA;
|
||||||
ments[i + 1].caption = bri_text + i * 32;
|
ments[i + 1].caption = bri_text + (i * bri_text_size);
|
||||||
ments[i + 1].data = &bri_values[i];
|
ments[i + 1].data = &bri_values[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ typedef struct _hekate_config
|
|||||||
u32 autoboot;
|
u32 autoboot;
|
||||||
u32 autoboot_list;
|
u32 autoboot_list;
|
||||||
u32 bootwait;
|
u32 bootwait;
|
||||||
u32 verification;
|
|
||||||
u32 backlight;
|
u32 backlight;
|
||||||
u32 autohosoff;
|
u32 autohosoff;
|
||||||
u32 autonogc;
|
u32 autonogc;
|
||||||
|
u32 updater2p;
|
||||||
char *brand;
|
char *brand;
|
||||||
char *tagline;
|
char *tagline;
|
||||||
// Global temporary config.
|
// Global temporary config.
|
||||||
@@ -40,16 +40,10 @@ typedef struct _hekate_config
|
|||||||
u32 errors;
|
u32 errors;
|
||||||
} hekate_config;
|
} hekate_config;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
ERR_LIBSYS_LP0 = (1 << 0),
|
|
||||||
} hsysmodule_t;
|
|
||||||
|
|
||||||
void set_default_configuration();
|
void set_default_configuration();
|
||||||
int create_config_entry();
|
int create_config_entry();
|
||||||
void config_autoboot();
|
void config_autoboot();
|
||||||
void config_bootdelay();
|
void config_bootdelay();
|
||||||
void config_verification();
|
|
||||||
void config_backlight();
|
void config_backlight();
|
||||||
void config_auto_hos_poweroff();
|
void config_auto_hos_poweroff();
|
||||||
void config_nogc();
|
void config_nogc();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2019 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -44,7 +44,8 @@ static char *_strdup(char *str)
|
|||||||
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
// Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||||
|
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++)
|
||||||
;
|
;
|
||||||
lbuf[i] = 0;
|
lbuf[i] = 0;
|
||||||
|
|
||||||
@@ -54,19 +55,16 @@ u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
|||||||
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||||
{
|
{
|
||||||
if (csec)
|
if (csec)
|
||||||
{
|
|
||||||
list_append(dst, &csec->link);
|
list_append(dst, &csec->link);
|
||||||
csec = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
csec = (ini_sec_t *)calloc(sizeof(ini_sec_t), 1);
|
||||||
csec->name = _strdup(name);
|
csec->name = _strdup(name);
|
||||||
csec->type = type;
|
csec->type = type;
|
||||||
|
|
||||||
return csec;
|
return csec;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
|
||||||
{
|
{
|
||||||
u32 lblen;
|
u32 lblen;
|
||||||
u32 pathlen = strlen(ini_path);
|
u32 pathlen = strlen(ini_path);
|
||||||
@@ -75,6 +73,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
char *filelist = NULL;
|
char *filelist = NULL;
|
||||||
FIL fp;
|
FIL fp;
|
||||||
ini_sec_t *csec = NULL;
|
ini_sec_t *csec = NULL;
|
||||||
|
bool firstIniRun = true;
|
||||||
|
|
||||||
char *filename = (char *)malloc(256);
|
char *filename = (char *)malloc(256);
|
||||||
|
|
||||||
@@ -118,13 +117,20 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
if (firstIniRun){
|
||||||
|
firstIniRun = false;
|
||||||
|
strcpy(lbuf, "[Unknown]");
|
||||||
|
lblen = 9;
|
||||||
|
}
|
||||||
|
else {
|
||||||
// Fetch one line.
|
// Fetch one line.
|
||||||
lbuf[0] = 0;
|
lbuf[0] = 0;
|
||||||
f_gets(lbuf, 512, &fp);
|
f_gets(lbuf, 512, &fp);
|
||||||
lblen = strlen(lbuf);
|
lblen = strlen(lbuf);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove trailing newline.
|
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||||
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
|
if (lblen && lbuf[lblen - 1] == '\n')
|
||||||
lbuf[lblen - 1] = 0;
|
lbuf[lblen - 1] = 0;
|
||||||
|
|
||||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||||
@@ -134,28 +140,26 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||||
list_init(&csec->kvs);
|
list_init(&csec->kvs);
|
||||||
}
|
}
|
||||||
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.
|
||||||
{
|
{
|
||||||
_find_section_name(lbuf, lblen, '}');
|
_find_section_name(lbuf, lblen, '}');
|
||||||
|
|
||||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||||
csec->color = 0xFF0AB9E6;
|
csec->color = 0xFF0AB9E6;
|
||||||
}
|
}
|
||||||
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
else if (lblen > 2 && lbuf[0] == '#') // Create comment.
|
||||||
{
|
{
|
||||||
_find_section_name(lbuf, lblen, '\0');
|
|
||||||
|
|
||||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||||
}
|
}
|
||||||
else if (lblen < 2)
|
else if (lblen < 2) // Create empty line.
|
||||||
{
|
{
|
||||||
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||||
}
|
}
|
||||||
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
else if (csec && csec->type == INI_CHOICE) // Extract key/value.
|
||||||
{
|
{
|
||||||
u32 i = _find_section_name(lbuf, lblen, '=');
|
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||||
|
|
||||||
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
ini_kv_t *kv = (ini_kv_t *)calloc(sizeof(ini_kv_t), 1);
|
||||||
kv->key = _strdup(&lbuf[0]);
|
kv->key = _strdup(&lbuf[0]);
|
||||||
kv->val = _strdup(&lbuf[i + 1]);
|
kv->val = _strdup(&lbuf[i + 1]);
|
||||||
list_append(&csec->kvs, &kv->link);
|
list_append(&csec->kvs, &kv->link);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ typedef struct _ini_sec_t
|
|||||||
u32 color;
|
u32 color;
|
||||||
} ini_sec_t;
|
} ini_sec_t;
|
||||||
|
|
||||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
int ini_parse(link_t *dst, const char *ini_path, bool is_dir);
|
||||||
char *ini_check_payload_section(ini_sec_t *cfg);
|
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
233
source/exception_handlers.S
Normal file
233
source/exception_handlers.S
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Armv7tdmi Status register.
|
||||||
|
*
|
||||||
|
* bit0: Mode 0.
|
||||||
|
* bit1: Mode 1.
|
||||||
|
* bit2: Mode 2.
|
||||||
|
* bit3: Mode 3.
|
||||||
|
* bit4: Mode 4.
|
||||||
|
* bit5: Thumb state.
|
||||||
|
* bit6: FIQ disable.
|
||||||
|
* bit7: IRQ disable.
|
||||||
|
* bit8-27: Reserved.
|
||||||
|
* bit28: Overflow condition.
|
||||||
|
* bit29: Carry/Borrow/Extend condition.
|
||||||
|
* bit30: Zero condition.
|
||||||
|
* bit31: Negative/Less than condition.
|
||||||
|
*
|
||||||
|
* M[4:0] | Mode | Visible Thumb-state registers | Visible ARM-state registers
|
||||||
|
* 10000 | USER | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR
|
||||||
|
* 10001 | FIQ | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7, r8_fiq–r14_fiq, PC, CPSR, SPSR_fiq
|
||||||
|
* 10010 | IRQ | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq
|
||||||
|
* 10011 | SVC | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc
|
||||||
|
* 10111 | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt
|
||||||
|
* 11011 | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und
|
||||||
|
* 11111 | SYS | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EXCP_EN_ADDR 0x4003FFFC
|
||||||
|
#define EXCP_TYPE_ADDR 0x4003FFF8
|
||||||
|
#define EXCP_LR_ADDR 0x4003FFF4
|
||||||
|
|
||||||
|
#define EXCP_VEC_BASE 0x6000F000
|
||||||
|
#define EVP_COP_RESET_VECTOR 0x200
|
||||||
|
#define EVP_COP_UNDEF_VECTOR 0x204
|
||||||
|
#define EVP_COP_SWI_VECTOR 0x208
|
||||||
|
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
|
||||||
|
#define EVP_COP_DATA_ABORT_VECTOR 0x210
|
||||||
|
#define EVP_COP_RSVD_VECTOR 0x214
|
||||||
|
#define EVP_COP_IRQ_VECTOR 0x218
|
||||||
|
#define EVP_COP_FIQ_VECTOR 0x21C
|
||||||
|
|
||||||
|
#define MODE_USR 0x10
|
||||||
|
#define MODE_FIQ 0x11
|
||||||
|
#define MODE_IRQ 0x12
|
||||||
|
#define MODE_SVC 0x13
|
||||||
|
#define MODE_ABT 0x17
|
||||||
|
#define MODE_UDF 0x1B
|
||||||
|
#define MODE_SYS 0x1F
|
||||||
|
#define MODE_MASK 0x1F
|
||||||
|
|
||||||
|
#define FIQ 0x40
|
||||||
|
#define IRQ 0x80
|
||||||
|
|
||||||
|
.section .text._irq_setup
|
||||||
|
.arm
|
||||||
|
|
||||||
|
.extern ipl_main
|
||||||
|
.type ipl_main, %function
|
||||||
|
|
||||||
|
.extern svc_handler
|
||||||
|
.type svc_handler, %function
|
||||||
|
|
||||||
|
.extern irq_handler
|
||||||
|
.type irq_handler, %function
|
||||||
|
|
||||||
|
.extern fiq_setup
|
||||||
|
.type fiq_setup, %function
|
||||||
|
|
||||||
|
.extern fiq_handler
|
||||||
|
.type fiq_handler, %function
|
||||||
|
|
||||||
|
.globl _irq_setup
|
||||||
|
.type _irq_setup, %function
|
||||||
|
_irq_setup:
|
||||||
|
MRS R0, CPSR
|
||||||
|
BIC R0, R0, #MODE_MASK /* Clear mode bits */
|
||||||
|
ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */
|
||||||
|
MSR CPSR, R0
|
||||||
|
|
||||||
|
/* Setup IRQ stack pointer */
|
||||||
|
MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
|
||||||
|
LDR SP, =0x40040000
|
||||||
|
|
||||||
|
/* Setup SYS stack pointer */
|
||||||
|
MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
|
||||||
|
LDR SP, =0x4003FF00 /* Will be changed later to DRAM */
|
||||||
|
|
||||||
|
MOV LR, PC
|
||||||
|
BL setup_vectors
|
||||||
|
/*BL fiq_setup*/
|
||||||
|
|
||||||
|
/* Enable interrupts */
|
||||||
|
BL irq_enable_cpu_irq_exceptions
|
||||||
|
|
||||||
|
B ipl_main
|
||||||
|
B .
|
||||||
|
|
||||||
|
_reset:
|
||||||
|
LDR R0, =EXCP_EN_ADDR
|
||||||
|
LDR R1, =0x30505645 /* EVP0 */
|
||||||
|
STR R1, [R0] /* EVP0 in EXCP_EN_ADDR */
|
||||||
|
LDR R0, =EXCP_LR_ADDR
|
||||||
|
MOV R1, LR
|
||||||
|
STR R1, [R0] /* Save LR in EXCP_LR_ADDR */
|
||||||
|
LDR R0, =__bss_start
|
||||||
|
EOR R1, R1, R1
|
||||||
|
LDR R2, =__bss_end
|
||||||
|
SUB R2, R2, R0
|
||||||
|
BL memset
|
||||||
|
B _irq_setup
|
||||||
|
|
||||||
|
_reset_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x545352 /* RST */
|
||||||
|
STR R1, [R0] /* RST in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
_undefined_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x464455 /* UDF */
|
||||||
|
STR R1, [R0] /* UDF in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
_prefetch_abort_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x54424150 /* PABT */
|
||||||
|
STR R1, [R0] /* PABT in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
_data_abort_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x54424144 /* DABT */
|
||||||
|
STR R1, [R0] /* DABT in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
.globl irq_enable_cpu_irq_exceptions
|
||||||
|
.type irq_enable_cpu_irq_exceptions, %function
|
||||||
|
irq_enable_cpu_irq_exceptions:
|
||||||
|
MRS R12, CPSR
|
||||||
|
BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */
|
||||||
|
MSR CPSR, R12
|
||||||
|
BX LR
|
||||||
|
|
||||||
|
.globl irq_disable_cpu_irq_exceptions
|
||||||
|
.type irq_disable_cpu_irq_exceptions, %function
|
||||||
|
irq_disable_cpu_irq_exceptions:
|
||||||
|
MRS R12, CPSR
|
||||||
|
ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */
|
||||||
|
MSR CPSR, R12
|
||||||
|
BX LR
|
||||||
|
|
||||||
|
_irq_handler:
|
||||||
|
MOV R13, R0 /* Save R0 in R13_IRQ */
|
||||||
|
SUB R0, LR, #4 /* Put return address in R0_SYS */
|
||||||
|
MOV LR, R1 /* Save R1 in R14_IRQ (LR) */
|
||||||
|
MRS R1, SPSR /* Put the SPSR in R1_SYS */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
|
||||||
|
STMFD SP!, {R0, R1} /* SPSR and PC */
|
||||||
|
STMFD SP!, {R2-R3, R12, LR} /* AAPCS-clobbered registers */
|
||||||
|
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
|
||||||
|
SUB SP, SP, #8 /* Make room for stacking R0 and R1 */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */
|
||||||
|
STMFD R0!, {R13, R14} /* Finish saving the context (R0, R1) */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
|
||||||
|
LDR R12, =irq_handler
|
||||||
|
MOV LR, PC /* Copy the return address to link register */
|
||||||
|
BX R12 /* Call the C IRQ handler (ARM/THUMB) */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
|
||||||
|
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
|
||||||
|
ADD SP, SP, #32 /* Fake unstacking 8 registers from SP_SYS */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
|
||||||
|
MOV SP, R0 /* Copy SP_SYS to SP_IRQ */
|
||||||
|
LDR R0, [SP, #28] /* Load the saved SPSR from the stack */
|
||||||
|
MSR SPSR_cxsf, R0 /* Copy it into SPSR_IRQ */
|
||||||
|
|
||||||
|
LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */
|
||||||
|
NOP /* Cant access barked registers immediately */
|
||||||
|
LDR LR, [SP, #24] /* Load return address from the SYS stack */
|
||||||
|
MOVS PC, LR /* Return restoring CPSR from SPSR */
|
||||||
|
|
||||||
|
_fiq_handler:
|
||||||
|
BL fiq_handler
|
||||||
|
|
||||||
|
setup_vectors:
|
||||||
|
/* Setup vectors */
|
||||||
|
LDR R0, =EXCP_VEC_BASE
|
||||||
|
|
||||||
|
LDR R1, =_reset_handler
|
||||||
|
STR R1, [R0, #EVP_COP_RESET_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_undefined_handler
|
||||||
|
STR R1, [R0, #EVP_COP_UNDEF_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_reset_handler
|
||||||
|
STR R1, [R0, #EVP_COP_SWI_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_prefetch_abort_handler
|
||||||
|
STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_data_abort_handler
|
||||||
|
STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_reset_handler
|
||||||
|
STR R1, [R0, #EVP_COP_RSVD_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_irq_handler
|
||||||
|
STR R1, [R0, #EVP_COP_IRQ_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_fiq_handler
|
||||||
|
STR R1, [R0, #EVP_COP_FIQ_VECTOR]
|
||||||
|
|
||||||
|
BX LR
|
||||||
137
source/gfx/gfx.c
137
source/gfx/gfx.c
@@ -20,7 +20,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
|
||||||
|
gfx_ctxt_t gfx_ctxt;
|
||||||
|
gfx_con_t gfx_con;
|
||||||
|
|
||||||
static const u8 _gfx_font[] = {
|
static const u8 _gfx_font[] = {
|
||||||
|
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
|
||||||
|
0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file)
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
|
||||||
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
|
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
|
||||||
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
|
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
|
||||||
@@ -165,14 +170,14 @@ void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
|
|||||||
|
|
||||||
void gfx_con_getpos(u32 *x, u32 *y)
|
void gfx_con_getpos(u32 *x, u32 *y)
|
||||||
{
|
{
|
||||||
*x = gfx_con.x;
|
*x = YLEFT - gfx_con.y;
|
||||||
*y = gfx_con.y;
|
*y = gfx_con.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_con_setpos(u32 x, u32 y)
|
void gfx_con_setpos(u32 x, u32 y)
|
||||||
{
|
{
|
||||||
gfx_con.x = x;
|
gfx_con.x = y;
|
||||||
gfx_con.y = y;
|
gfx_con.y = YLEFT - x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_putc(char c)
|
void gfx_putc(char c)
|
||||||
@@ -181,14 +186,14 @@ void gfx_putc(char c)
|
|||||||
switch (gfx_con.fntsz)
|
switch (gfx_con.fntsz)
|
||||||
{
|
{
|
||||||
case 16:
|
case 16:
|
||||||
if (c >= 32 && c <= 126)
|
if (c >= 30 && c <= 126)
|
||||||
{
|
{
|
||||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 30)];
|
||||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||||
|
|
||||||
for (u32 i = 0; i < 16; i+=2)
|
for (u32 i = 0; i < 16; i+=2)
|
||||||
{
|
{
|
||||||
u8 v = *cbuf++;
|
u8 v = *cbuf;
|
||||||
for (u32 k = 0; k < 2; k++)
|
for (u32 k = 0; k < 2; k++)
|
||||||
{
|
{
|
||||||
for (u32 j = 0; j < 8; j++)
|
for (u32 j = 0; j < 8; j++)
|
||||||
@@ -196,50 +201,60 @@ void gfx_putc(char c)
|
|||||||
if (v & 1)
|
if (v & 1)
|
||||||
{
|
{
|
||||||
*fb = gfx_con.fgcol;
|
*fb = gfx_con.fgcol;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
*fb = gfx_con.fgcol;
|
*fb = gfx_con.fgcol;
|
||||||
}
|
}
|
||||||
else if (gfx_con.fillbg)
|
else if (gfx_con.fillbg)
|
||||||
{
|
{
|
||||||
*fb = gfx_con.bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
*fb = gfx_con.bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
}
|
}
|
||||||
fb += gfx_ctxt.stride - 16;
|
//fb += gfx_ctxt.stride - 16;
|
||||||
|
//fb = fbtop + 2;
|
||||||
|
fb += (gfx_ctxt.stride * 16) + 1;
|
||||||
v = *cbuf;
|
v = *cbuf;
|
||||||
}
|
}
|
||||||
|
cbuf++;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
gfx_con.x += 16;
|
gfx_con.x += 16;
|
||||||
if (gfx_con.x >= gfx_ctxt.width - 16) {
|
if (gfx_con.x >= gfx_ctxt.width - 16) {
|
||||||
gfx_con.x = 0;
|
gfx_con.x = 0;
|
||||||
gfx_con.y += 16;
|
gfx_con.y += 16;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
gfx_con.y -= 16;
|
||||||
|
if (gfx_con.y < 16){
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
|
gfx_con.x += 16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
gfx_con.x = 0;
|
gfx_con.y = YLEFT;
|
||||||
gfx_con.y +=16;
|
gfx_con.x += 16;
|
||||||
if (gfx_con.y > gfx_ctxt.height - 16)
|
if (gfx_con.x > gfx_ctxt.width - 16)
|
||||||
gfx_con.y = 0;
|
gfx_con.x = 0;
|
||||||
}
|
}
|
||||||
else if (c == '\e')
|
else if (c == '\e')
|
||||||
gfx_con.x = 672;
|
gfx_con.y = 575;
|
||||||
else if (c == '\a')
|
else if (c == '\a')
|
||||||
gfx_con.x = 608;
|
gfx_con.y = 639;
|
||||||
else if (c == '\r')
|
else if (c == '\r')
|
||||||
gfx_con.x = 0;
|
gfx_con.y = YLEFT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
default:
|
default:
|
||||||
if (c >= 32 && c <= 126)
|
if (c >= 30 && c <= 126)
|
||||||
{
|
{
|
||||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 30)];
|
||||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||||
for (u32 i = 0; i < 8; i++)
|
for (u32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
@@ -251,23 +266,31 @@ void gfx_putc(char c)
|
|||||||
else if (gfx_con.fillbg)
|
else if (gfx_con.fillbg)
|
||||||
*fb = gfx_con.bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
}
|
}
|
||||||
fb += gfx_ctxt.stride - 8;
|
fb += (gfx_ctxt.stride * 8) + 1;
|
||||||
}
|
}
|
||||||
gfx_con.x += 8;
|
|
||||||
if (gfx_con.x >= gfx_ctxt.width - 8) {
|
gfx_con.y -= 8;
|
||||||
gfx_con.x = 0;
|
if (gfx_con.y < 8){
|
||||||
gfx_con.y += 8;
|
gfx_con.y = YLEFT;
|
||||||
|
gfx_con.x += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
gfx_con.x = 0;
|
gfx_con.y = YLEFT;
|
||||||
gfx_con.y += 8;
|
gfx_con.x += 8;
|
||||||
if (gfx_con.y > gfx_ctxt.height - 8)
|
if (gfx_con.x > gfx_ctxt.width - 8)
|
||||||
gfx_con.y = 0;
|
gfx_con.x = 0;
|
||||||
}
|
}
|
||||||
|
else if (c == '\e')
|
||||||
|
gfx_con.y = 575;
|
||||||
|
else if (c == '\a')
|
||||||
|
gfx_con.y = 639;
|
||||||
|
else if (c == '\r')
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -329,15 +352,10 @@ void gfx_put_big_sep()
|
|||||||
gfx_con.fntsz = prevFontSize;
|
gfx_con.fntsz = prevFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_printf(const char *fmt, ...)
|
void gfx_vprintf(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
if (gfx_con.mute)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
int fill, fcnt;
|
int fill, fcnt;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
while(*fmt)
|
while(*fmt)
|
||||||
{
|
{
|
||||||
if(*fmt == '%')
|
if(*fmt == '%')
|
||||||
@@ -389,7 +407,7 @@ void gfx_printf(const char *fmt, ...)
|
|||||||
gfx_putc('%');
|
gfx_putc('%');
|
||||||
break;
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
goto out;
|
return;
|
||||||
default:
|
default:
|
||||||
gfx_putc('%');
|
gfx_putc('%');
|
||||||
gfx_putc(*fmt);
|
gfx_putc(*fmt);
|
||||||
@@ -400,8 +418,17 @@ void gfx_printf(const char *fmt, ...)
|
|||||||
gfx_putc(*fmt);
|
gfx_putc(*fmt);
|
||||||
fmt++;
|
fmt++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfx_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
if (gfx_con.mute)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
gfx_vprintf(fmt, ap);
|
||||||
|
|
||||||
out:
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,14 +535,34 @@ void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color){
|
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade){
|
||||||
int i = y0;
|
for (int y = (YLEFT - x0); y >= (YLEFT - x1); y--){
|
||||||
while(y1 >= i){
|
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + y0, shade, (y1 - y0 + 1) * 4);
|
||||||
gfx_line(x0, i, x1, i, color);
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
void gfx_boxGrey_old(int x0, int y0, int x1, int y1, u8 shade){
|
||||||
|
for (int y = y0; y <= y1; y++){
|
||||||
|
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + x0, shade, (x1 - x0) * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void gfx_box(int x0, int y0, int x1, int y1, u32 color){
|
||||||
|
for (int y = (YLEFT - x0); y >= (YLEFT - x1); y--){
|
||||||
|
for (int x = y0; x <= y1; x++){
|
||||||
|
gfx_set_pixel(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void gfx_box_old(int x0, int y0, int x1, int y1, u32 color){
|
||||||
|
for (int x = x0; x < x1 + 1; x++){
|
||||||
|
for (int y = y0; y < y1 + 1; y++){
|
||||||
|
gfx_set_pixel(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||||
{
|
{
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
|
|||||||
@@ -20,12 +20,15 @@
|
|||||||
#define _GFX_H_
|
#define _GFX_H_
|
||||||
|
|
||||||
#include "../../common/common_gfx.h"
|
#include "../../common/common_gfx.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||||
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||||
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||||
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||||
|
|
||||||
|
#define YLEFT 1279
|
||||||
|
|
||||||
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
|
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
|
||||||
void gfx_clear_grey(u8 color);
|
void gfx_clear_grey(u8 color);
|
||||||
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
|
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
|
||||||
@@ -37,6 +40,7 @@ void gfx_con_setpos(u32 x, u32 y);
|
|||||||
void gfx_putc(char c);
|
void gfx_putc(char c);
|
||||||
void gfx_puts(const char *s);
|
void gfx_puts(const char *s);
|
||||||
void gfx_printf(const char *fmt, ...);
|
void gfx_printf(const char *fmt, ...);
|
||||||
|
void gfx_vprintf(const char *fmt, va_list ap);
|
||||||
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
||||||
|
|
||||||
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
||||||
@@ -48,9 +52,16 @@ void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_
|
|||||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||||
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color);
|
void gfx_box(int x0, int y0, int x1, int y1, u32 color);
|
||||||
|
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade);
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define GFX_SETPOSCORRECTED(x, y) gfx_con_setpos(y - YLEFT, x)
|
||||||
|
#define GFX_BOXCORRECTED(x0, y0, x1, y1, color) gfx_box_old((y0 - YLEFT), x0, (y1 - YLEFT), x1, color)
|
||||||
|
#define GFX_BOXGREYCORRECTED(x0, y0, x1, y1, shade) gfx_boxGrey((y0 - YLEFT), x0, (y1 - YLEFT), x1, shade)
|
||||||
|
*/
|
||||||
|
|
||||||
// Global gfx console and context.
|
// Global gfx console and context.
|
||||||
gfx_ctxt_t gfx_ctxt;
|
extern gfx_ctxt_t gfx_ctxt;
|
||||||
gfx_con_t gfx_con;
|
extern gfx_con_t gfx_con;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
116
source/hid/hid.c
Normal file
116
source/hid/hid.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "hid.h"
|
||||||
|
#include "joycon.h"
|
||||||
|
#include "../utils/btn.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "../tegraexplorer/utils/utils.h"
|
||||||
|
|
||||||
|
static Inputs inputs = {0};
|
||||||
|
u16 LbaseX = 0, LbaseY = 0, RbaseX = 0, RbaseY = 0;
|
||||||
|
|
||||||
|
void hidInit(){
|
||||||
|
jc_init_hw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs *hidRead(){
|
||||||
|
jc_gamepad_rpt_t *controller = joycon_poll();
|
||||||
|
static bool errPrint = false;
|
||||||
|
|
||||||
|
if (controller->cap)
|
||||||
|
utils_takeScreenshot();
|
||||||
|
|
||||||
|
|
||||||
|
u8 btn = btn_read();
|
||||||
|
inputs.volp = (btn & BTN_VOL_UP) ? 1 : 0;
|
||||||
|
inputs.volm = (btn & BTN_VOL_DOWN) ? 1 : 0;
|
||||||
|
inputs.pow = (btn & BTN_POWER) ? 1 : 0;
|
||||||
|
|
||||||
|
inputs.a = controller->a;
|
||||||
|
inputs.b = controller->b;
|
||||||
|
inputs.x = controller->x;
|
||||||
|
inputs.y = controller->y;
|
||||||
|
inputs.r = controller->r;
|
||||||
|
inputs.l = controller->l;
|
||||||
|
inputs.zr = controller->zr;
|
||||||
|
inputs.zl = controller->zl;
|
||||||
|
inputs.minus = controller->minus;
|
||||||
|
inputs.plus = controller->plus;
|
||||||
|
inputs.home = controller->home;
|
||||||
|
inputs.cap = controller->cap;
|
||||||
|
|
||||||
|
if (controller->conn_l && controller->conn_r){
|
||||||
|
if (errPrint){
|
||||||
|
gfx_boxGrey(1008, 703, 1279, 719, 0xFF);
|
||||||
|
errPrint = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u32 x, y;
|
||||||
|
gfx_con_getpos(&x, &y);
|
||||||
|
gfx_con_setpos(1008, 703);
|
||||||
|
gfx_printf("%k%K%s %s MISS%k%K", COLOR_DEFAULT, COLOR_WHITE, (controller->conn_l) ? " " : "JOYL", (controller->conn_r) ? " " : "JOYR", COLOR_WHITE, COLOR_DEFAULT);
|
||||||
|
gfx_con_setpos(x, y);
|
||||||
|
errPrint = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller->conn_l){
|
||||||
|
if ((LbaseX == 0 || LbaseY == 0) || controller->l3){
|
||||||
|
LbaseX = controller->lstick_x;
|
||||||
|
LbaseY = controller->lstick_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.Lup = (controller->up || (controller->lstick_y > LbaseY + 500)) ? 1 : 0;
|
||||||
|
inputs.Ldown = (controller->down || (controller->lstick_y < LbaseY - 500)) ? 1 : 0;
|
||||||
|
inputs.Lleft = (controller->left || (controller->lstick_x < LbaseX - 500)) ? 1 : 0;
|
||||||
|
inputs.Lright = (controller->right || (controller->lstick_x > LbaseX + 500)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
inputs.Lup = inputs.volp;
|
||||||
|
inputs.Ldown = inputs.volm;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller->conn_r){
|
||||||
|
if ((RbaseX == 0 || RbaseY == 0) || controller->r3){
|
||||||
|
RbaseX = controller->rstick_x;
|
||||||
|
RbaseY = controller->rstick_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.Rup = (controller->rstick_y > RbaseY + 500) ? 1 : 0;
|
||||||
|
inputs.Rdown = (controller->rstick_y < RbaseY - 500) ? 1 : 0;
|
||||||
|
inputs.Rleft = (controller->rstick_x < RbaseX - 500) ? 1 : 0;
|
||||||
|
inputs.Rright = (controller->rstick_x > RbaseX + 500) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inputs.a = inputs.pow;
|
||||||
|
|
||||||
|
return &inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs *hidWaitMask(u32 mask){
|
||||||
|
Inputs *in = hidRead();
|
||||||
|
|
||||||
|
while (in->buttons & mask)
|
||||||
|
hidRead();
|
||||||
|
|
||||||
|
while (!(in->buttons & mask)){
|
||||||
|
hidRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs *hidWait(){
|
||||||
|
Inputs *in = hidRead();
|
||||||
|
|
||||||
|
while (in->buttons)
|
||||||
|
hidRead();
|
||||||
|
|
||||||
|
while (!(in->buttons))
|
||||||
|
hidRead();
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hidConnected(){
|
||||||
|
jc_gamepad_rpt_t *controller = joycon_poll();
|
||||||
|
return (controller->conn_l && controller->conn_r) ? 1 : 0;
|
||||||
|
}
|
||||||
59
source/hid/hid.h
Normal file
59
source/hid/hid.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define BIT(n) (1U << n)
|
||||||
|
#define KEY_A BIT(3)
|
||||||
|
#define KEY_B BIT(2)
|
||||||
|
#define KEY_Y BIT(0)
|
||||||
|
#define KEY_X BIT(1)
|
||||||
|
#define KEY_LUP BIT(18)
|
||||||
|
#define KEY_LDOWN BIT(17)
|
||||||
|
#define KEY_LRIGHT BIT(19)
|
||||||
|
#define KEY_LLEFT BIT(20)
|
||||||
|
#define KEY_RUP BIT(7)
|
||||||
|
#define KEY_RDOWN BIT(6)
|
||||||
|
#define KEY_VOLP BIT(14)
|
||||||
|
#define KEY_VOLM BIT(15)
|
||||||
|
#define KEY_POW BIT(16)
|
||||||
|
|
||||||
|
typedef struct _inputs {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
// Joy-Con (R).
|
||||||
|
u32 y:1;
|
||||||
|
u32 x:1;
|
||||||
|
u32 b:1;
|
||||||
|
u32 a:1;
|
||||||
|
u32 r:1;
|
||||||
|
u32 zr:1;
|
||||||
|
u32 Rdown:1;
|
||||||
|
u32 Rup:1;
|
||||||
|
u32 Rright:1;
|
||||||
|
u32 Rleft:1;
|
||||||
|
|
||||||
|
// Shared
|
||||||
|
u32 minus:1;
|
||||||
|
u32 plus:1;
|
||||||
|
u32 home:1;
|
||||||
|
u32 cap:1;
|
||||||
|
u32 volp:1;
|
||||||
|
u32 volm:1;
|
||||||
|
u32 pow:1;
|
||||||
|
|
||||||
|
// Joy-Con (L).
|
||||||
|
u32 Ldown:1;
|
||||||
|
u32 Lup:1;
|
||||||
|
u32 Lright:1;
|
||||||
|
u32 Lleft:1;
|
||||||
|
u32 l:1;
|
||||||
|
u32 zl:1;
|
||||||
|
};
|
||||||
|
u32 buttons;
|
||||||
|
};
|
||||||
|
} Inputs;
|
||||||
|
|
||||||
|
void hidInit();
|
||||||
|
Inputs *hidRead();
|
||||||
|
Inputs *hidWait();
|
||||||
|
Inputs *hidWaitMask(u32 mask);
|
||||||
|
bool hidConnected();
|
||||||
807
source/hid/joycon.c
Normal file
807
source/hid/joycon.c
Normal file
@@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* Joy-Con UART driver for Nintendo Switch
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "joycon.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../power/max17050.h"
|
||||||
|
#include "../power/regulator_5v.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
|
#include "../soc/clock.h"
|
||||||
|
#include "../soc/gpio.h"
|
||||||
|
#include "../soc/pinmux.h"
|
||||||
|
#include "../soc/uart.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
// For disabling driver when logging is enabled.
|
||||||
|
// #include "../libs/lvgl/lvgl.h"
|
||||||
|
|
||||||
|
#define JC_WIRED_CMD 0x91
|
||||||
|
#define JC_WIRED_HID 0x92
|
||||||
|
#define JC_WIRED_INIT_REPLY 0x94
|
||||||
|
#define JC_INIT_HANDSHAKE 0xA5
|
||||||
|
|
||||||
|
#define JC_WIRED_CMD_MAC 0x01
|
||||||
|
#define JC_WIRED_CMD_10 0x10
|
||||||
|
|
||||||
|
#define JC_HID_OUTPUT_RPT 0x01
|
||||||
|
#define JC_HID_RUMBLE_RPT 0x10
|
||||||
|
|
||||||
|
#define JC_HID_INPUT_RPT 0x30
|
||||||
|
#define JC_HID_SUBMCD_RPT 0x21
|
||||||
|
|
||||||
|
#define JC_HID_SUBCMD_HCI_STATE 0x06
|
||||||
|
#define HCI_STATE_SLEEP 0x00
|
||||||
|
#define HCI_STATE_RECONNECT 0x01
|
||||||
|
#define HCI_STATE_PAIR 0x02
|
||||||
|
#define HCI_STATE_HOME 0x04
|
||||||
|
#define JC_HID_SUBCMD_SPI_READ 0x10
|
||||||
|
#define JC_HID_SUBCMD_RUMBLE_CTL 0x48
|
||||||
|
#define JC_HID_SUBCMD_SND_RUMBLE 0xFF
|
||||||
|
|
||||||
|
#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status.
|
||||||
|
#define JC_BTN_MASK_R 0x76FF
|
||||||
|
|
||||||
|
#define JC_ID_L 1
|
||||||
|
#define JC_ID_R 2
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
JC_BATT_EMTPY = 0,
|
||||||
|
JC_BATT_CRIT = 2,
|
||||||
|
JC_BATT_LOW = 4,
|
||||||
|
JC_BATT_MID = 6,
|
||||||
|
JC_BATT_FULL = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_jc[] = {
|
||||||
|
0xA1, 0xA2, 0xA3, 0xA4
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_handshake[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||||
|
JC_INIT_HANDSHAKE, 0x02, // Wired cmd and wired subcmd.
|
||||||
|
0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_get_info[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||||
|
JC_WIRED_CMD, JC_WIRED_CMD_MAC, // Wired cmd and subcmd.
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_finilize[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||||
|
JC_WIRED_CMD, JC_WIRED_CMD_10, // Wired cmd and subcmd.
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 nx_pad_status[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x08, 0x00, // Uart header.
|
||||||
|
JC_WIRED_HID, 0x00, // Wired cmd and hid cmd.
|
||||||
|
0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _jc_uart_hdr_t
|
||||||
|
{
|
||||||
|
u8 magic[3];
|
||||||
|
u8 total_size_lsb;
|
||||||
|
u8 total_size_msb;
|
||||||
|
} jc_uart_hdr_t;
|
||||||
|
|
||||||
|
typedef struct _jc_wired_hdr_t
|
||||||
|
{
|
||||||
|
jc_uart_hdr_t uart_hdr;
|
||||||
|
u8 cmd;
|
||||||
|
u8 data[5];
|
||||||
|
u8 crc;
|
||||||
|
u8 payload[];
|
||||||
|
} jc_wired_hdr_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_out_rpt_t
|
||||||
|
{
|
||||||
|
u8 cmd;
|
||||||
|
u8 pkt_id;
|
||||||
|
u8 rumble[8];
|
||||||
|
u8 subcmd;
|
||||||
|
u8 subcmd_data[];
|
||||||
|
} jc_hid_out_rpt_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_out_spi_read_t
|
||||||
|
{
|
||||||
|
u32 addr;
|
||||||
|
u8 size;
|
||||||
|
} jc_hid_out_spi_read_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_in_rpt_t
|
||||||
|
{
|
||||||
|
u8 cmd;
|
||||||
|
u8 pkt_id;
|
||||||
|
u8 conn_info:4;
|
||||||
|
u8 batt_info:4;
|
||||||
|
u8 btn_right;
|
||||||
|
u8 btn_shared;
|
||||||
|
u8 btn_left;
|
||||||
|
u8 stick_h_left;
|
||||||
|
u8 stick_m_left;
|
||||||
|
u8 stick_v_left;
|
||||||
|
u8 stick_h_right;
|
||||||
|
u8 stick_m_right;
|
||||||
|
u8 stick_v_right;
|
||||||
|
u8 vib_decider;
|
||||||
|
u8 submcd_ack;
|
||||||
|
u8 subcmd;
|
||||||
|
u8 subcmd_data[];
|
||||||
|
} jc_hid_in_rpt_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_in_spi_read_t
|
||||||
|
{
|
||||||
|
u32 addr;
|
||||||
|
u8 size;
|
||||||
|
u8 data[];
|
||||||
|
} jc_hid_in_spi_read_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_in_pair_data_t
|
||||||
|
{
|
||||||
|
u8 magic;
|
||||||
|
u8 size;
|
||||||
|
u16 checksum;
|
||||||
|
u8 mac[6];
|
||||||
|
u8 ltk[16];
|
||||||
|
u8 pad0[10];
|
||||||
|
u8 bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported
|
||||||
|
u8 pad1;
|
||||||
|
} jc_hid_in_pair_data_t;
|
||||||
|
|
||||||
|
typedef struct _joycon_ctxt_t
|
||||||
|
{
|
||||||
|
u8 buf[0x100]; //FIXME: If heap is used, dumping breaks.
|
||||||
|
u8 uart;
|
||||||
|
u8 type;
|
||||||
|
u8 mac[6];
|
||||||
|
u32 hw_init_done;
|
||||||
|
u32 last_received_time;
|
||||||
|
u32 last_status_req_time;
|
||||||
|
u8 rumble_sent;
|
||||||
|
u8 connected;
|
||||||
|
} joycon_ctxt_t;
|
||||||
|
|
||||||
|
static joycon_ctxt_t jc_l;
|
||||||
|
static joycon_ctxt_t jc_r;
|
||||||
|
|
||||||
|
static bool jc_init_done = false;
|
||||||
|
static u32 hid_pkt_inc = 0;
|
||||||
|
|
||||||
|
static jc_gamepad_rpt_t jc_gamepad;
|
||||||
|
|
||||||
|
void jc_power_supply(u8 uart, bool enable);
|
||||||
|
|
||||||
|
void joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
|
||||||
|
{
|
||||||
|
uart_send(uart_port, buf, size);
|
||||||
|
uart_wait_idle(uart_port, UART_TX_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size)
|
||||||
|
{
|
||||||
|
out->uart_hdr.magic[0] = 0x19;
|
||||||
|
out->uart_hdr.magic[1] = 0x01;
|
||||||
|
out->uart_hdr.magic[2] = 0x3;
|
||||||
|
|
||||||
|
out->uart_hdr.total_size_lsb = 7;
|
||||||
|
out->uart_hdr.total_size_msb = 0;
|
||||||
|
out->cmd = wired_cmd;
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
memcpy(out->data, data, size);
|
||||||
|
|
||||||
|
out->crc = 0; // wired crc8ccit can be skipped.
|
||||||
|
|
||||||
|
return sizeof(jc_wired_hdr_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size)
|
||||||
|
{
|
||||||
|
u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0);
|
||||||
|
pkt_size += size;
|
||||||
|
|
||||||
|
rpt->uart_hdr.total_size_lsb += size;
|
||||||
|
rpt->data[0] = size >> 8;
|
||||||
|
rpt->data[1] = size & 0xFF;
|
||||||
|
|
||||||
|
if (payload)
|
||||||
|
memcpy(rpt->payload, payload, size);
|
||||||
|
|
||||||
|
return pkt_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size)
|
||||||
|
{
|
||||||
|
u8 rpt[0x50];
|
||||||
|
memset(rpt, 0, sizeof(rpt));
|
||||||
|
|
||||||
|
u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size);
|
||||||
|
|
||||||
|
joycon_send_raw(uart, rpt, rpt_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 jc_hid_pkt_id_incr()
|
||||||
|
{
|
||||||
|
u8 curr_id = hid_pkt_inc;
|
||||||
|
hid_pkt_inc++;
|
||||||
|
|
||||||
|
return (curr_id & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
|
||||||
|
{
|
||||||
|
u8 temp[0x30];
|
||||||
|
u8 rumble_neutral[8] = {0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40};
|
||||||
|
u8 rumble_init[8] = {0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72};
|
||||||
|
|
||||||
|
memset(temp, 0, sizeof(temp));
|
||||||
|
|
||||||
|
jc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp;
|
||||||
|
|
||||||
|
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
|
||||||
|
|
||||||
|
if (subcmd == JC_HID_SUBCMD_SND_RUMBLE)
|
||||||
|
{
|
||||||
|
bool send_r_rumble = jc_r.connected && !jc_r.rumble_sent;
|
||||||
|
bool send_l_rumble = jc_l.connected && !jc_l.rumble_sent;
|
||||||
|
|
||||||
|
// Enable rumble.
|
||||||
|
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
|
||||||
|
hid_pkt->subcmd_data[0] = 1;
|
||||||
|
if (send_r_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
|
||||||
|
if (send_l_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
|
||||||
|
|
||||||
|
// Send rumble.
|
||||||
|
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
|
||||||
|
if (send_r_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10);
|
||||||
|
if (send_l_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10);
|
||||||
|
|
||||||
|
msleep(15);
|
||||||
|
|
||||||
|
// Disable rumble.
|
||||||
|
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
|
||||||
|
hid_pkt->subcmd_data[0] = 0;
|
||||||
|
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
|
||||||
|
if (send_r_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
|
||||||
|
if (send_l_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
hid_pkt->subcmd = subcmd;
|
||||||
|
if (data)
|
||||||
|
memcpy(hid_pkt->subcmd_data, data, size);
|
||||||
|
|
||||||
|
u8 pkt_size = sizeof(jc_hid_out_rpt_t) + size;
|
||||||
|
|
||||||
|
if (subcmd != JC_HID_SUBCMD_SPI_READ)
|
||||||
|
jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, pkt_size);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, pkt_size);
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, pkt_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_charging_decider(u8 batt, u8 uart)
|
||||||
|
{
|
||||||
|
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000;
|
||||||
|
|
||||||
|
// Power supply control based on battery levels and charging.
|
||||||
|
if ((batt >> 1 << 1) < JC_BATT_LOW) // Level without checking charging.
|
||||||
|
jc_power_supply(uart, true);
|
||||||
|
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID)) // Addresses the charging bit.
|
||||||
|
jc_power_supply(uart, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
|
||||||
|
{
|
||||||
|
u32 btn_tmp;
|
||||||
|
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
|
||||||
|
|
||||||
|
switch (hid_pkt->cmd)
|
||||||
|
{
|
||||||
|
case JC_HID_INPUT_RPT:
|
||||||
|
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
|
||||||
|
|
||||||
|
if (jc->type & JC_ID_L)
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||||
|
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L);
|
||||||
|
|
||||||
|
jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8);
|
||||||
|
jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4);
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_l = hid_pkt->batt_info;
|
||||||
|
}
|
||||||
|
else if (jc->type & JC_ID_R)
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||||
|
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R);
|
||||||
|
|
||||||
|
jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8);
|
||||||
|
jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4);
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_r = hid_pkt->batt_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad.conn_l = jc_l.connected;
|
||||||
|
jc_gamepad.conn_r = jc_r.connected;
|
||||||
|
|
||||||
|
jc_charging_decider(hid_pkt->batt_info, jc->uart);
|
||||||
|
break;
|
||||||
|
case JC_HID_SUBMCD_RPT:
|
||||||
|
if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ)
|
||||||
|
{
|
||||||
|
jc_bt_conn_t *bt_conn;
|
||||||
|
|
||||||
|
if (jc->type & JC_ID_L)
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_l;
|
||||||
|
else
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_r;
|
||||||
|
|
||||||
|
jc_hid_in_spi_read_t *spi_info = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data;
|
||||||
|
jc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data;
|
||||||
|
|
||||||
|
// Check if we reply is pairing info.
|
||||||
|
if (spi_info->addr == 0x2000 && spi_info->size == 0x1A && pair_data->magic == 0x95)
|
||||||
|
{
|
||||||
|
bt_conn->type = jc->type;
|
||||||
|
|
||||||
|
memcpy(bt_conn->mac, jc->mac, 6);
|
||||||
|
memcpy(bt_conn->host_mac, pair_data->mac, 6);
|
||||||
|
for (u32 i = 16; i > 0; i--)
|
||||||
|
bt_conn->ltk[16 - i] = pair_data->ltk[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
jc->last_received_time = get_tmr_ms();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size)
|
||||||
|
{
|
||||||
|
switch (data[0])
|
||||||
|
{
|
||||||
|
case JC_WIRED_CMD_MAC:
|
||||||
|
for (int i = 12; i > 6; i--)
|
||||||
|
jc->mac[12 - i] = data[i];
|
||||||
|
jc->type = data[6];
|
||||||
|
jc->connected = true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_uart_pkt_parse(joycon_ctxt_t *jc, const u8* packet, size_t size)
|
||||||
|
{
|
||||||
|
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)packet;
|
||||||
|
switch (pkt->cmd)
|
||||||
|
{
|
||||||
|
case JC_WIRED_HID:
|
||||||
|
jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]);
|
||||||
|
break;
|
||||||
|
case JC_WIRED_INIT_REPLY:
|
||||||
|
jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_rcv_pkt(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6) && jc->uart == UART_C)
|
||||||
|
return;
|
||||||
|
else if (gpio_read(GPIO_PORT_H, GPIO_PIN_6) && jc->uart == UART_B)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if device stopped sending data.
|
||||||
|
u32 uart_irq = uart_get_IIR(jc->uart);
|
||||||
|
if ((uart_irq & 0x8) != 0x8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0);
|
||||||
|
|
||||||
|
// Check valid size and uart reply magic.
|
||||||
|
if (len > 7 && !memcmp(jc->buf, "\x19\x81\x03", 3))
|
||||||
|
{
|
||||||
|
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)(jc->buf);
|
||||||
|
|
||||||
|
jc_uart_pkt_parse(jc, jc->buf, pkt->uart_hdr.total_size_lsb + sizeof(jc_uart_hdr_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool jc_send_init_rumble(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
// Send init rumble or request nx pad status report.
|
||||||
|
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent))
|
||||||
|
{
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
|
||||||
|
|
||||||
|
if (jc_l.connected)
|
||||||
|
jc_l.rumble_sent = true;
|
||||||
|
if (jc_r.connected)
|
||||||
|
jc_r.rumble_sent = true;
|
||||||
|
|
||||||
|
if (jc->uart != UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_req_nx_pad_status(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
bool sent_rumble = jc_send_init_rumble(jc);
|
||||||
|
|
||||||
|
if (sent_rumble)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (jc->last_status_req_time > get_tmr_ms() || !jc->connected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Turn off Joy-Con detect.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status));
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
jc->last_status_req_time = get_tmr_ms() + 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad_rpt_t *jc_get_bt_pairing_info()
|
||||||
|
{
|
||||||
|
u8 retries;
|
||||||
|
jc_bt_conn_t *bt_conn;
|
||||||
|
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_l;
|
||||||
|
memset(bt_conn->host_mac, 0, 6);
|
||||||
|
memset(bt_conn->ltk, 0, 16);
|
||||||
|
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_r;
|
||||||
|
memset(bt_conn->host_mac, 0, 6);
|
||||||
|
memset(bt_conn->ltk, 0, 16);
|
||||||
|
|
||||||
|
while (jc_l.last_status_req_time > get_tmr_ms())
|
||||||
|
{
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_hid_in_spi_read_t subcmd_data;
|
||||||
|
subcmd_data.addr = 0x2000;
|
||||||
|
subcmd_data.size = 0x1A;
|
||||||
|
|
||||||
|
// Turn off Joy-Con detect.
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
bool jc_r_found = jc_r.connected ? false : true;
|
||||||
|
bool jc_l_found = jc_l.connected ? false : true;
|
||||||
|
|
||||||
|
u32 total_retries = 5;
|
||||||
|
retry:
|
||||||
|
retries = 10;
|
||||||
|
while (retries)
|
||||||
|
{
|
||||||
|
if (jc_l.last_status_req_time < get_tmr_ms())
|
||||||
|
{
|
||||||
|
jc_send_hid_cmd(0, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data, 5);
|
||||||
|
jc_l.last_status_req_time = get_tmr_ms() + 15;
|
||||||
|
jc_r.last_status_req_time = get_tmr_ms() + 15;
|
||||||
|
retries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jc_r_found)
|
||||||
|
{
|
||||||
|
memset(jc_r.buf, 0, 0x100);
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jc_l_found)
|
||||||
|
{
|
||||||
|
memset(jc_l.buf, 0, 0x100);
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jc_l.connected &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_l.ltk[0], "\x00\x00\x00\x00", 4) &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_l.ltk[8], "\x00\x00\x00\x00", 4))
|
||||||
|
jc_l_found = true;
|
||||||
|
|
||||||
|
if (jc_r.connected &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_r.ltk[0], "\x00\x00\x00\x00", 4) &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_r.ltk[8], "\x00\x00\x00\x00", 4))
|
||||||
|
jc_r_found = true;
|
||||||
|
|
||||||
|
if (total_retries && (!jc_l_found || !jc_r_found))
|
||||||
|
{
|
||||||
|
total_retries--;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
return &jc_gamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_deinit()
|
||||||
|
{
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
u8 data = HCI_STATE_SLEEP;
|
||||||
|
|
||||||
|
if (jc_r.connected)
|
||||||
|
{
|
||||||
|
jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1);
|
||||||
|
msleep(1);
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
}
|
||||||
|
if (jc_l.connected)
|
||||||
|
{
|
||||||
|
jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1);
|
||||||
|
msleep(1);
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_power_supply(UART_B, false);
|
||||||
|
jc_power_supply(UART_C, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_init_conn(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
if (((u32)get_tmr_ms() - jc->last_received_time) > 1000)
|
||||||
|
{
|
||||||
|
jc_power_supply(jc->uart, true);
|
||||||
|
|
||||||
|
// Turn off Joy-Con detect.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||||
|
jc_gamepad.conn_r = false;
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||||
|
jc_gamepad.conn_l = false;
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_init(jc->uart, 1000000);
|
||||||
|
uart_invert(jc->uart, true, UART_INVERT_TXD);
|
||||||
|
uart_set_IIR(jc->uart);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, init_jc, 4);
|
||||||
|
joycon_send_raw(jc->uart, init_handshake, sizeof(init_handshake));
|
||||||
|
|
||||||
|
msleep(5);
|
||||||
|
jc_rcv_pkt(jc);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, init_get_info, sizeof(init_get_info));
|
||||||
|
msleep(5);
|
||||||
|
jc_rcv_pkt(jc);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, init_finilize, sizeof(init_finilize));
|
||||||
|
msleep(5);
|
||||||
|
jc_rcv_pkt(jc);
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
jc->last_received_time = get_tmr_ms();
|
||||||
|
|
||||||
|
if (jc->connected)
|
||||||
|
jc_power_supply(jc->uart, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_conn_check()
|
||||||
|
{
|
||||||
|
// Check if a Joy-Con was disconnected.
|
||||||
|
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
{
|
||||||
|
jc_power_supply(UART_C, false);
|
||||||
|
|
||||||
|
hid_pkt_inc = 0;
|
||||||
|
|
||||||
|
jc_l.connected = false;
|
||||||
|
jc_l.rumble_sent = false;
|
||||||
|
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||||
|
jc_gamepad.conn_l = false;
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_l = 0;
|
||||||
|
jc_gamepad.bt_conn_l.type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
{
|
||||||
|
jc_power_supply(UART_B, false);
|
||||||
|
|
||||||
|
hid_pkt_inc = 0;
|
||||||
|
|
||||||
|
jc_r.connected = false;
|
||||||
|
jc_r.rumble_sent = false;
|
||||||
|
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||||
|
jc_gamepad.conn_r = false;
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_r = 0;
|
||||||
|
jc_gamepad.bt_conn_r.type = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_power_supply(u8 uart, bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
if (regulator_get_5v_dev_enabled(1 << uart))
|
||||||
|
return;
|
||||||
|
|
||||||
|
regulator_enable_5v(1 << uart);
|
||||||
|
|
||||||
|
if (jc_init_done)
|
||||||
|
{
|
||||||
|
if (uart == UART_C)
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
else
|
||||||
|
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uart == UART_C)
|
||||||
|
{
|
||||||
|
// Joy-Con(L) Charge Detect.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1;
|
||||||
|
gpio_config(GPIO_PORT_CC, GPIO_PIN_3, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Joy-Con(R) Charge Detect.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2;
|
||||||
|
gpio_config(GPIO_PORT_K, GPIO_PIN_3, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_K, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!regulator_get_5v_dev_enabled(1 << uart))
|
||||||
|
return;
|
||||||
|
|
||||||
|
regulator_disable_5v(1 << uart);
|
||||||
|
|
||||||
|
if (uart == UART_C)
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW);
|
||||||
|
else
|
||||||
|
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_init_hw()
|
||||||
|
{
|
||||||
|
jc_l.uart = UART_C;
|
||||||
|
jc_r.uart = UART_B;
|
||||||
|
|
||||||
|
#if (LV_LOG_PRINTF != 1)
|
||||||
|
jc_power_supply(UART_C, true);
|
||||||
|
jc_power_supply(UART_B, true);
|
||||||
|
|
||||||
|
// Joy-Con (R) IsAttached.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
|
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
// Joy-Con (L) IsAttached.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
|
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
// Configure pinmuxing for UART B and C.
|
||||||
|
pinmux_config_uart(UART_B);
|
||||||
|
pinmux_config_uart(UART_C);
|
||||||
|
|
||||||
|
// Ease the stress to APB.
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||||
|
|
||||||
|
// Enable UART B and C clocks.
|
||||||
|
clock_enable_uart(UART_B);
|
||||||
|
clock_enable_uart(UART_C);
|
||||||
|
|
||||||
|
// Restore OC.
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
jc_init_done = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad_rpt_t *joycon_poll()
|
||||||
|
{
|
||||||
|
if (!jc_init_done)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
jc_init_conn(&jc_r);
|
||||||
|
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
jc_init_conn(&jc_l);
|
||||||
|
|
||||||
|
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
jc_req_nx_pad_status(&jc_r);
|
||||||
|
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
jc_req_nx_pad_status(&jc_l);
|
||||||
|
|
||||||
|
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
|
||||||
|
jc_conn_check();
|
||||||
|
|
||||||
|
return &jc_gamepad;
|
||||||
|
}
|
||||||
98
source/hid/joycon.h
Normal file
98
source/hid/joycon.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __JOYCON_H_
|
||||||
|
#define __JOYCON_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define JC_BTNS_DIRECTION_PAD 0xF0000
|
||||||
|
#define JC_BTNS_PREV_NEXT 0x800080
|
||||||
|
#define JC_BTNS_ENTER 0x400008
|
||||||
|
#define JC_BTNS_ESC 0x4
|
||||||
|
|
||||||
|
#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC)
|
||||||
|
|
||||||
|
typedef struct _jc_bt_conn_t
|
||||||
|
{
|
||||||
|
u8 type;
|
||||||
|
u8 mac[6];
|
||||||
|
u8 host_mac[6];
|
||||||
|
u8 ltk[16];
|
||||||
|
} jc_bt_conn_t;
|
||||||
|
|
||||||
|
typedef struct _jc_gamepad_rpt_t
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
// Joy-Con (R).
|
||||||
|
u32 y:1;
|
||||||
|
u32 x:1;
|
||||||
|
u32 b:1;
|
||||||
|
u32 a:1;
|
||||||
|
u32 sr_r:1;
|
||||||
|
u32 sl_r:1;
|
||||||
|
u32 r:1;
|
||||||
|
u32 zr:1;
|
||||||
|
|
||||||
|
// Shared
|
||||||
|
u32 minus:1;
|
||||||
|
u32 plus:1;
|
||||||
|
u32 r3:1;
|
||||||
|
u32 l3:1;
|
||||||
|
u32 home:1;
|
||||||
|
u32 cap:1;
|
||||||
|
u32 pad:1;
|
||||||
|
u32 wired:1;
|
||||||
|
|
||||||
|
// Joy-Con (L).
|
||||||
|
u32 down:1;
|
||||||
|
u32 up:1;
|
||||||
|
u32 right:1;
|
||||||
|
u32 left:1;
|
||||||
|
u32 sr_l:1;
|
||||||
|
u32 sl_l:1;
|
||||||
|
u32 l:1;
|
||||||
|
u32 zl:1;
|
||||||
|
};
|
||||||
|
u32 buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
u16 lstick_x;
|
||||||
|
u16 lstick_y;
|
||||||
|
u16 rstick_x;
|
||||||
|
u16 rstick_y;
|
||||||
|
bool center_stick_l;
|
||||||
|
bool center_stick_r;
|
||||||
|
bool conn_l;
|
||||||
|
bool conn_r;
|
||||||
|
u8 batt_info_l;
|
||||||
|
u8 batt_info_r;
|
||||||
|
jc_bt_conn_t bt_conn_l;
|
||||||
|
jc_bt_conn_t bt_conn_r;
|
||||||
|
} jc_gamepad_rpt_t;
|
||||||
|
|
||||||
|
void jc_power_supply(u8 uart, bool enable);
|
||||||
|
void jc_init_hw();
|
||||||
|
void jc_deinit();
|
||||||
|
jc_gamepad_rpt_t *joycon_poll();
|
||||||
|
jc_gamepad_rpt_t *jc_get_bt_pairing_info();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
|
#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
|
||||||
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
|
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
|
||||||
#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
|
#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
|
||||||
#define HASH_ORDER_700_9xx {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
|
#define HASH_ORDER_700_10x {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
|
||||||
|
|
||||||
static const pkg1_id_t _pkg1_ids[] = {
|
static const pkg1_id_t _pkg1_ids[] = {
|
||||||
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
|
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
|
||||||
@@ -36,12 +36,13 @@ static const pkg1_id_t _pkg1_ids[] = {
|
|||||||
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
|
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
|
||||||
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
|
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
|
||||||
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
|
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
|
||||||
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.0
|
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.0
|
||||||
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1
|
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.1
|
||||||
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
|
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
|
||||||
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0
|
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.1.0
|
||||||
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
|
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
|
||||||
{ "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.1.0
|
{ "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.1.0
|
||||||
|
{ "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0
|
||||||
{ NULL } //End.
|
{ NULL } //End.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2019 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
* Copyright (c) 2018 Atmosphère-NX
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -31,6 +31,10 @@
|
|||||||
#define DEBUG_PRINTING*/
|
#define DEBUG_PRINTING*/
|
||||||
#define DPRINTF(...)
|
#define DPRINTF(...)
|
||||||
|
|
||||||
|
u32 pkg2_newkern_ini1_val;
|
||||||
|
u32 pkg2_newkern_ini1_start;
|
||||||
|
u32 pkg2_newkern_ini1_end;
|
||||||
|
|
||||||
static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
||||||
{
|
{
|
||||||
u32 size = sizeof(pkg2_kip1_t);
|
u32 size = sizeof(pkg2_kip1_t);
|
||||||
@@ -41,14 +45,34 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
|||||||
|
|
||||||
void pkg2_get_newkern_info(u8 *kern_data)
|
void pkg2_get_newkern_info(u8 *kern_data)
|
||||||
{
|
{
|
||||||
u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1);
|
u32 pkg2_newkern_ini1_off = 0;
|
||||||
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC.
|
pkg2_newkern_ini1_start = 0;
|
||||||
|
|
||||||
|
// Find static OP offset that is close to INI1 offset.
|
||||||
|
u32 counter_ops = 0x100;
|
||||||
|
while (counter_ops)
|
||||||
|
{
|
||||||
|
if (*(u32 *)(kern_data + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC)
|
||||||
|
{
|
||||||
|
pkg2_newkern_ini1_off = 0x100 - counter_ops + 12; // OP found. Add 12 for the INI1 offset.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter_ops -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset not found?
|
||||||
|
if (!counter_ops)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_off);
|
||||||
|
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + pkg2_newkern_ini1_off; // Parse ADR and PC.
|
||||||
|
|
||||||
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
|
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
|
||||||
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8);
|
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
||||||
{
|
{
|
||||||
u8 *ptr;
|
u8 *ptr;
|
||||||
// Check for new pkg2 type.
|
// Check for new pkg2 type.
|
||||||
@@ -56,6 +80,9 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
|||||||
{
|
{
|
||||||
pkg2_get_newkern_info(pkg2->data);
|
pkg2_get_newkern_info(pkg2->data);
|
||||||
|
|
||||||
|
if (!pkg2_newkern_ini1_start)
|
||||||
|
return false;
|
||||||
|
|
||||||
ptr = pkg2->data + pkg2_newkern_ini1_start;
|
ptr = pkg2->data + pkg2_newkern_ini1_start;
|
||||||
*new_pkg2 = true;
|
*new_pkg2 = true;
|
||||||
}
|
}
|
||||||
@@ -75,6 +102,8 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
|||||||
ptr += ki->size;
|
ptr += ki->size;
|
||||||
DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size);
|
DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018-2019 CTCaer
|
* Copyright (C) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -26,11 +26,11 @@
|
|||||||
#define PKG2_SEC_KERNEL 0
|
#define PKG2_SEC_KERNEL 0
|
||||||
#define PKG2_SEC_INI1 1
|
#define PKG2_SEC_INI1 1
|
||||||
|
|
||||||
#define PKG2_NEWKERN_GET_INI1 0x44
|
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
||||||
|
|
||||||
u32 pkg2_newkern_ini1_val;
|
extern u32 pkg2_newkern_ini1_val;
|
||||||
u32 pkg2_newkern_ini1_start;
|
extern u32 pkg2_newkern_ini1_start;
|
||||||
u32 pkg2_newkern_ini1_end;
|
extern u32 pkg2_newkern_ini1_end;
|
||||||
|
|
||||||
typedef struct _pkg2_hdr_t
|
typedef struct _pkg2_hdr_t
|
||||||
{
|
{
|
||||||
@@ -87,7 +87,7 @@ typedef struct _pkg2_kip1_info_t
|
|||||||
link_t link;
|
link_t link;
|
||||||
} pkg2_kip1_info_t;
|
} pkg2_kip1_info_t;
|
||||||
|
|
||||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
||||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||||
|
|
||||||
|
|||||||
@@ -18,21 +18,18 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "ianos.h"
|
#include "ianos.h"
|
||||||
#include "../utils/types.h"
|
|
||||||
#include "../libs/elfload/elfload.h"
|
|
||||||
#include "../../common/common_module.h"
|
#include "../../common/common_module.h"
|
||||||
#include "../mem/heap.h"
|
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../libs/elfload/elfload.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define IRAM_LIB_ADDR 0x4002B000
|
#define IRAM_LIB_ADDR 0x4002B000
|
||||||
#define DRAM_LIB_ADDR 0xE0000000
|
#define DRAM_LIB_ADDR 0xE0000000
|
||||||
|
|
||||||
extern heap_t _heap;
|
extern heap_t _heap;
|
||||||
|
|
||||||
extern void *sd_file_read(const char *path, u32 *fsize);
|
|
||||||
extern bool sd_mount();
|
|
||||||
extern void sd_unmount();
|
|
||||||
|
|
||||||
void *elfBuf = NULL;
|
void *elfBuf = NULL;
|
||||||
void *fileBuf = NULL;
|
void *fileBuf = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "../../sec/se.h"
|
#include "../../sec/se.h"
|
||||||
#include "../../storage/nx_emmc.h"
|
#include "../../storage/nx_emmc.h"
|
||||||
#include "../../storage/sdmmc.h"
|
#include "../../storage/sdmmc.h"
|
||||||
|
#include "../../storage/emummc.h"
|
||||||
|
|
||||||
extern sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
extern sdmmc_storage_t storage;
|
extern sdmmc_storage_t storage;
|
||||||
@@ -107,7 +108,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
|
|||||||
pdst += 0x10;
|
pdst += 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize);
|
se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
|
||||||
|
|
||||||
pdst = (u8 *)dst;
|
pdst = (u8 *)dst;
|
||||||
|
|
||||||
@@ -150,8 +151,8 @@ DRESULT disk_read (
|
|||||||
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||||
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||||
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
||||||
bool needs_cache_sector = false;
|
//bool needs_cache_sector = false;
|
||||||
|
/*
|
||||||
if (secindex == 0 || clear_sector_cache) {
|
if (secindex == 0 || clear_sector_cache) {
|
||||||
if (!sector_cache)
|
if (!sector_cache)
|
||||||
sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES);
|
sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES);
|
||||||
@@ -179,6 +180,7 @@ DRESULT disk_read (
|
|||||||
secindex++;
|
secindex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
//system_part (pdrv == 1) ? system_part_sys : system_part_usr
|
//system_part (pdrv == 1) ? system_part_sys : system_part_usr
|
||||||
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
|
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
|
||||||
u32 tweak_exp = 0;
|
u32 tweak_exp = 0;
|
||||||
@@ -195,10 +197,12 @@ DRESULT disk_read (
|
|||||||
|
|
||||||
// fatfs will never pull more than a cluster
|
// fatfs will never pull more than a cluster
|
||||||
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
|
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
|
||||||
|
/*
|
||||||
if (needs_cache_sector) {
|
if (needs_cache_sector) {
|
||||||
memcpy(sector_cache[s].cached_sector, buff, 0x200);
|
memcpy(sector_cache[s].cached_sector, buff, 0x200);
|
||||||
memcpy(sector_cache[s].tweak, tweak, 0x10);
|
memcpy(sector_cache[s].tweak, tweak, 0x10);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
prev_sector = sector + count - 1;
|
prev_sector = sector + count - 1;
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
@@ -209,20 +213,46 @@ DRESULT disk_read (
|
|||||||
|
|
||||||
DRESULT disk_write (
|
DRESULT disk_write (
|
||||||
BYTE pdrv, /* Physical drive number to identify the drive */
|
BYTE pdrv, /* Physical drive number to identify the drive */
|
||||||
const BYTE *buff, /* Data to be written */
|
BYTE *buff, /* Data to be written */
|
||||||
DWORD sector, /* Start sector in LBA */
|
DWORD sector, /* Start sector in LBA */
|
||||||
UINT count /* Number of sectors to write */
|
UINT count /* Number of sectors to write */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (pdrv == 1)
|
switch (pdrv){
|
||||||
return RES_WRPRT;
|
case 0:
|
||||||
|
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
|
||||||
|
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||||
|
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
||||||
|
memcpy(buf, buff, 512 * count);
|
||||||
|
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
||||||
|
return RES_OK;
|
||||||
|
return RES_ERROR;
|
||||||
|
case 1:;
|
||||||
|
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||||
|
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||||
|
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
||||||
|
u32 tweak_exp = 0;
|
||||||
|
bool regen_tweak = true;
|
||||||
|
|
||||||
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
|
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
|
||||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
prev_cluster = sector / 0x20;
|
||||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
tweak_exp = sector % 0x20;
|
||||||
memcpy(buf, buff, 512 * count);
|
} else if (sector > prev_sector) { // sector in same cluster and past last sector
|
||||||
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
tweak_exp = sector - prev_sector - 1;
|
||||||
return RES_OK;
|
regen_tweak = false;
|
||||||
|
} else { // sector in same cluster and before or same as last sector
|
||||||
|
tweak_exp = sector % 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_emmc_xts(9, 8, 1, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200)){
|
||||||
|
if (nx_emmc_part_write(&storage, system_part, sector, count, buff)){
|
||||||
|
prev_sector = sector + count - 1;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ typedef enum {
|
|||||||
DSTATUS disk_initialize (BYTE pdrv);
|
DSTATUS disk_initialize (BYTE pdrv);
|
||||||
DSTATUS disk_status (BYTE pdrv);
|
DSTATUS disk_status (BYTE pdrv);
|
||||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
DRESULT disk_write (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,11 @@
|
|||||||
#include "ff.h" /* Declarations of FatFs API */
|
#include "ff.h" /* Declarations of FatFs API */
|
||||||
#include "diskio.h" /* Declarations of device I/O functions */
|
#include "diskio.h" /* Declarations of device I/O functions */
|
||||||
#include "../../gfx/gfx.h"
|
#include "../../gfx/gfx.h"
|
||||||
|
#include "../../storage/sdmmc.h"
|
||||||
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
|
||||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
//#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||||
//#define EFSPRINTF(...)
|
#define EFSPRINTF(...)
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -4054,7 +4056,216 @@ FRESULT f_write (
|
|||||||
LEAVE_FF(fs, FR_OK);
|
LEAVE_FF(fs, FR_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FF_FASTFS
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Fast Read Aligned Sized File Without a Cache */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
#if FF_USE_FASTSEEK
|
||||||
|
FRESULT f_read_fast (
|
||||||
|
FIL* fp, /* Pointer to the file object */
|
||||||
|
const void* buff, /* Pointer to the data to be written */
|
||||||
|
UINT btr /* Number of bytes to read */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (btr % 65536 != 0)
|
||||||
|
return f_read(fp, buff, btr, NULL);
|
||||||
|
|
||||||
|
FRESULT res;
|
||||||
|
FATFS *fs;
|
||||||
|
UINT csize_bytes;
|
||||||
|
DWORD clst;
|
||||||
|
UINT count = 0;
|
||||||
|
FSIZE_t work_sector = 0;
|
||||||
|
FSIZE_t sector_base = 0;
|
||||||
|
BYTE *wbuff = (BYTE*)buff;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO support sector reading inside a cluster
|
||||||
|
|
||||||
|
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||||
|
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||||
|
EFSPRINTF("FOV");
|
||||||
|
LEAVE_FF(fs, res); /* Check validity */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||||
|
FSIZE_t remain = fp->obj.objsize - fp->fptr;
|
||||||
|
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
|
||||||
|
|
||||||
|
csize_bytes = fs->csize * SS(fs);
|
||||||
|
|
||||||
|
if (!fp->fptr) { /* On the top of the file? */
|
||||||
|
clst = fp->obj.sclust; /* Follow from the origin */
|
||||||
|
} else {
|
||||||
|
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
|
||||||
|
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
|
||||||
|
}
|
||||||
|
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
|
||||||
|
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
|
||||||
|
|
||||||
|
fp->clust = clst; /* Set working cluster */
|
||||||
|
|
||||||
|
sector_base = clst2sect(fs, fp->clust);
|
||||||
|
count += fs->csize;
|
||||||
|
btr -= csize_bytes;
|
||||||
|
fp->fptr += csize_bytes;
|
||||||
|
|
||||||
|
while (btr) {
|
||||||
|
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
|
||||||
|
|
||||||
|
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
|
||||||
|
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
|
||||||
|
|
||||||
|
fp->clust = clst;
|
||||||
|
|
||||||
|
work_sector = clst2sect(fs, fp->clust);
|
||||||
|
if ((work_sector - sector_base) == count) count += fs->csize;
|
||||||
|
else {
|
||||||
|
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||||
|
wbuff += count * SS(fs);
|
||||||
|
|
||||||
|
sector_base = work_sector;
|
||||||
|
count = fs->csize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp->fptr += MIN(btr, csize_bytes);
|
||||||
|
btr -= MIN(btr, csize_bytes);
|
||||||
|
|
||||||
|
// TODO: what about if data is smaller than cluster?
|
||||||
|
// Must read-write back that cluster.
|
||||||
|
|
||||||
|
if (!btr) { /* Final cluster/sectors read. */
|
||||||
|
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LEAVE_FF(fs, FR_OK);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FF_FASTFS
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Fast Write Aligned Sized File Without a Cache */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
#if FF_USE_FASTSEEK
|
||||||
|
FRESULT f_write_fast (
|
||||||
|
FIL* fp, /* Pointer to the file object */
|
||||||
|
const void* buff, /* Pointer to the data to be written */
|
||||||
|
UINT btw /* Number of bytes to write */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (btw % 65536 != 0)
|
||||||
|
return f_write(fp, buff, btw, NULL);
|
||||||
|
|
||||||
|
FRESULT res;
|
||||||
|
FATFS *fs;
|
||||||
|
UINT csize_bytes;
|
||||||
|
DWORD clst;
|
||||||
|
UINT count = 0;
|
||||||
|
FSIZE_t work_sector = 0;
|
||||||
|
FSIZE_t sector_base = 0;
|
||||||
|
const BYTE *wbuff = (const BYTE*)buff;
|
||||||
|
|
||||||
|
// TODO support sector writing inside a cluster
|
||||||
|
|
||||||
|
res = validate(&fp->obj, &fs); /* Check validity of the file object */
|
||||||
|
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
|
||||||
|
EFSPRINTF("FOV");
|
||||||
|
LEAVE_FF(fs, res); /* Check validity */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
|
||||||
|
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
|
||||||
|
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
|
||||||
|
btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
csize_bytes = fs->csize * SS(fs);
|
||||||
|
|
||||||
|
if (!fp->fptr) { /* On the top of the file? */
|
||||||
|
clst = fp->obj.sclust; /* Follow from the origin */
|
||||||
|
} else {
|
||||||
|
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
|
||||||
|
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
|
||||||
|
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
|
||||||
|
|
||||||
|
fp->clust = clst; /* Set working cluster */
|
||||||
|
|
||||||
|
sector_base = clst2sect(fs, fp->clust);
|
||||||
|
count += fs->csize;
|
||||||
|
btw -= csize_bytes;
|
||||||
|
fp->fptr += csize_bytes;
|
||||||
|
|
||||||
|
while (btw) {
|
||||||
|
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
|
||||||
|
|
||||||
|
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
|
||||||
|
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
|
||||||
|
|
||||||
|
fp->clust = clst;
|
||||||
|
|
||||||
|
work_sector = clst2sect(fs, fp->clust);
|
||||||
|
if ((work_sector - sector_base) == count) count += fs->csize;
|
||||||
|
else {
|
||||||
|
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||||
|
wbuff += count * SS(fs);
|
||||||
|
|
||||||
|
sector_base = work_sector;
|
||||||
|
count = fs->csize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp->fptr += MIN(btw, csize_bytes);
|
||||||
|
btw -= MIN(btw, csize_bytes);
|
||||||
|
|
||||||
|
// what about if data is smaller than cluster?
|
||||||
|
// Probably must read-write back that cluster.
|
||||||
|
if (!btw) { /* Final cluster/sectors write. */
|
||||||
|
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||||
|
fp->flag &= (BYTE)~FA_DIRTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fp->flag |= FA_MODIFIED; /* Set file change flag */
|
||||||
|
|
||||||
|
LEAVE_FF(fs, FR_OK);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FF_FASTFS
|
||||||
|
#if FF_USE_FASTSEEK
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Seek File Read/Write Pointer */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DWORD *f_expand_cltbl (
|
||||||
|
FIL* fp, /* Pointer to the file object */
|
||||||
|
UINT tblsz, /* Size of table */
|
||||||
|
FSIZE_t ofs /* File pointer from top of file */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */
|
||||||
|
if (!fp->cltbl) { /* Allocate memory for cluster link table */
|
||||||
|
fp->cltbl = (DWORD *)ff_memalloc(tblsz);
|
||||||
|
fp->cltbl[0] = tblsz;
|
||||||
|
}
|
||||||
|
if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */
|
||||||
|
ff_memfree(fp->cltbl);
|
||||||
|
fp->cltbl = NULL;
|
||||||
|
EFSPRINTF("CLTBLSZ");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
f_lseek(fp, 0);
|
||||||
|
|
||||||
|
return fp->cltbl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
@@ -4167,6 +4378,13 @@ FRESULT f_close (
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fp->cltbl != NULL){
|
||||||
|
ff_memfree(fp->cltbl);
|
||||||
|
fp->cltbl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5627,7 +5845,8 @@ FRESULT f_forward (
|
|||||||
}
|
}
|
||||||
#endif /* FF_USE_FORWARD */
|
#endif /* FF_USE_FORWARD */
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
#if FF_USE_MKFS && !FF_FS_READONLY
|
#if FF_USE_MKFS && !FF_FS_READONLY
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
@@ -6092,7 +6311,7 @@ FRESULT f_mkfs (
|
|||||||
LEAVE_MKFS(FR_OK);
|
LEAVE_MKFS(FR_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|
||||||
#if FF_MULTI_PARTITION
|
#if FF_MULTI_PARTITION
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
@@ -6105,17 +6324,16 @@ FRESULT f_fdisk (
|
|||||||
void* work /* Pointer to the working buffer (null: use heap memory) */
|
void* work /* Pointer to the working buffer (null: use heap memory) */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
|
UINT i, n, sz_cyl, tot_cyl, e_cyl;
|
||||||
BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
|
BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
|
||||||
DSTATUS stat;
|
DSTATUS stat;
|
||||||
DWORD sz_disk, sz_part, s_part;
|
DWORD sz_disk, p_sect, b_cyl, b_sect;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
|
|
||||||
stat = disk_initialize(pdrv);
|
stat = disk_initialize(pdrv);
|
||||||
if (stat & STA_NOINIT) return FR_NOT_READY;
|
if (stat & STA_NOINIT) return FR_NOT_READY;
|
||||||
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
|
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
|
||||||
if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
|
sz_disk = sd_storage.csd.capacity;
|
||||||
|
|
||||||
buf = (BYTE*)work;
|
buf = (BYTE*)work;
|
||||||
#if FF_USE_LFN == 3
|
#if FF_USE_LFN == 3
|
||||||
@@ -6132,20 +6350,25 @@ FRESULT f_fdisk (
|
|||||||
|
|
||||||
/* Create partition table */
|
/* Create partition table */
|
||||||
mem_set(buf, 0, FF_MAX_SS);
|
mem_set(buf, 0, FF_MAX_SS);
|
||||||
p = buf + MBR_Table; b_cyl = 0;
|
p = buf + MBR_Table; b_cyl = 0, b_sect = 0;
|
||||||
for (i = 0; i < 4; i++, p += SZ_PTE) {
|
for (i = 0; i < 4; i++, p += SZ_PTE) {
|
||||||
p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * (szt[i] / 100) : szt[i] / sz_cyl; /* Number of cylinders */
|
p_sect = szt[i]; /* Number of sectors */
|
||||||
if (p_cyl == 0) continue;
|
|
||||||
s_part = (DWORD)sz_cyl * b_cyl;
|
if (p_sect == 0)
|
||||||
sz_part = (DWORD)sz_cyl * p_cyl;
|
continue;
|
||||||
if (i == 0) { /* Exclude first track of cylinder 0 */
|
|
||||||
|
if (i == 0) { /* Exclude first 16MiB of sd */
|
||||||
s_hd = 1;
|
s_hd = 1;
|
||||||
s_part += 32768; sz_part -= 32768;
|
b_sect += 32768; p_sect -= 32768;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
s_hd = 0;
|
s_hd = 0;
|
||||||
}
|
|
||||||
e_cyl = b_cyl + p_cyl - 1; /* End cylinder */
|
b_cyl = b_sect / sz_cyl;
|
||||||
if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER);
|
e_cyl = ((b_sect + p_sect) / sz_cyl) - 1; /* End cylinder */
|
||||||
|
|
||||||
|
if (e_cyl >= tot_cyl)
|
||||||
|
LEAVE_MKFS(FR_INVALID_PARAMETER);
|
||||||
|
|
||||||
|
|
||||||
/* Set partition table */
|
/* Set partition table */
|
||||||
@@ -6156,10 +6379,15 @@ FRESULT f_fdisk (
|
|||||||
p[5] = e_hd; /* End head */
|
p[5] = e_hd; /* End head */
|
||||||
p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */
|
p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */
|
||||||
p[7] = (BYTE)e_cyl; /* End cylinder */
|
p[7] = (BYTE)e_cyl; /* End cylinder */
|
||||||
st_dword(p + 8, s_part); /* Start sector in LBA */
|
st_dword(p + 8, b_sect); /* Start sector in LBA */
|
||||||
st_dword(p + 12, sz_part); /* Number of sectors */
|
st_dword(p + 12, p_sect); /* Number of sectors */
|
||||||
/* Next partition */
|
/* Next partition */
|
||||||
b_cyl += p_cyl;
|
|
||||||
|
for (u32 cursect = 0; cursect < 512; cursect++){
|
||||||
|
disk_write(pdrv, buf + 0x4000, b_sect + (64 * cursect), 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_sect += p_sect;
|
||||||
}
|
}
|
||||||
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
|
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,10 @@ typedef enum {
|
|||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */
|
||||||
|
#ifdef FF_FASTFS
|
||||||
|
FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */
|
||||||
|
#endif
|
||||||
} FRESULT;
|
} FRESULT;
|
||||||
|
|
||||||
|
|
||||||
@@ -288,6 +291,11 @@ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
|||||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||||
|
#ifdef FF_FASTFS
|
||||||
|
FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */
|
||||||
|
FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */
|
||||||
|
DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */
|
||||||
|
#endif
|
||||||
|
|
||||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||||
#define f_error(fp) ((fp)->err)
|
#define f_error(fp) ((fp)->err)
|
||||||
@@ -321,6 +329,7 @@ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
|||||||
#endif
|
#endif
|
||||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||||
|
void* ff_memcalloc (UINT msize, UINT amount);
|
||||||
void ff_memfree (void* mblock); /* Free memory block */
|
void ff_memfree (void* mblock); /* Free memory block */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,13 @@
|
|||||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FASTFS 1
|
||||||
|
|
||||||
|
#ifdef FF_FASTFS
|
||||||
|
#define FF_USE_FASTSEEK 1
|
||||||
|
#else
|
||||||
#define FF_USE_FASTSEEK 0
|
#define FF_USE_FASTSEEK 0
|
||||||
|
#endif
|
||||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
@@ -287,3 +293,5 @@
|
|||||||
|
|
||||||
|
|
||||||
/*--- End of configuration options ---*/
|
/*--- End of configuration options ---*/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if no
|
|||||||
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* ff_memcalloc (UINT msize, UINT amount){
|
||||||
|
return calloc(amount, msize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
/* Free a memory block */
|
/* Free a memory block */
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ SECTIONS {
|
|||||||
.text : {
|
.text : {
|
||||||
*(.text._start);
|
*(.text._start);
|
||||||
*(._boot_cfg);
|
*(._boot_cfg);
|
||||||
|
*(.text._irq_setup);
|
||||||
*(.text*);
|
*(.text*);
|
||||||
}
|
}
|
||||||
.data : {
|
.data : {
|
||||||
|
|||||||
@@ -38,18 +38,21 @@
|
|||||||
#include "utils/dirlist.h"
|
#include "utils/dirlist.h"
|
||||||
#include "utils/sprintf.h"
|
#include "utils/sprintf.h"
|
||||||
#include "utils/util.h"
|
#include "utils/util.h"
|
||||||
#include "tegraexplorer/te.h"
|
#include "tegraexplorer/mainmenu.h"
|
||||||
|
#include "tegraexplorer/gfx/gfxutils.h"
|
||||||
|
#include "storage/nx_sd.h"
|
||||||
|
|
||||||
//#include "keys/keys.h"
|
//#include "keys/keys.h"
|
||||||
|
|
||||||
sdmmc_t sd_sdmmc;
|
//sdmmc_t sd_sdmmc;
|
||||||
sdmmc_storage_t sd_storage;
|
//sdmmc_storage_t sd_storage;
|
||||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
//__attribute__ ((aligned (16))) FATFS sd_fs;
|
||||||
static bool sd_mounted;
|
//bool sd_mounted, sd_inited;
|
||||||
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
||||||
hekate_config h_cfg;
|
hekate_config h_cfg;
|
||||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||||
|
|
||||||
|
/*
|
||||||
bool sd_mount()
|
bool sd_mount()
|
||||||
{
|
{
|
||||||
if (sd_mounted)
|
if (sd_mounted)
|
||||||
@@ -58,9 +61,11 @@ bool sd_mount()
|
|||||||
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
|
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
|
||||||
|
sd_inited = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
sd_inited = true;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = f_mount(&sd_fs, "sd:", 1);
|
res = f_mount(&sd_fs, "sd:", 1);
|
||||||
if (res == FR_OK)
|
if (res == FR_OK)
|
||||||
@@ -84,6 +89,7 @@ void sd_unmount()
|
|||||||
f_mount(NULL, "sd:", 1);
|
f_mount(NULL, "sd:", 1);
|
||||||
sdmmc_storage_end(&sd_storage);
|
sdmmc_storage_end(&sd_storage);
|
||||||
sd_mounted = false;
|
sd_mounted = false;
|
||||||
|
sd_inited = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,17 +134,20 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// This is a safe and unused DRAM region for our payloads.
|
// This is a safe and unused DRAM region for our payloads.
|
||||||
#define RELOC_META_OFF 0x7C
|
#define RELOC_META_OFF 0x7C
|
||||||
#define PATCHED_RELOC_SZ 0x94
|
#define PATCHED_RELOC_SZ 0x94
|
||||||
#define PATCHED_RELOC_STACK 0x40007000
|
#define PATCHED_RELOC_STACK 0x40007000
|
||||||
#define PATCHED_RELOC_ENTRY 0x40010000
|
#define PATCHED_RELOC_ENTRY 0x40010000
|
||||||
#define EXT_PAYLOAD_ADDR 0xC03C0000
|
#define EXT_PAYLOAD_ADDR 0xC0000000
|
||||||
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
||||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
#define COREBOOT_END_ADDR 0xD0000000
|
||||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||||
|
|
||||||
|
static void *coreboot_addr;
|
||||||
|
|
||||||
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||||
{
|
{
|
||||||
@@ -153,7 +162,7 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
|||||||
|
|
||||||
if (payload_size == 0x7000)
|
if (payload_size == 0x7000)
|
||||||
{
|
{
|
||||||
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
|
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); //Bootblock
|
||||||
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
|
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,7 +192,10 @@ int launch_payload(char *path)
|
|||||||
if (size < 0x30000)
|
if (size < 0x30000)
|
||||||
buf = (void *)RCM_PAYLOAD_ADDR;
|
buf = (void *)RCM_PAYLOAD_ADDR;
|
||||||
else
|
else
|
||||||
buf = (void *)COREBOOT_ADDR;
|
{
|
||||||
|
coreboot_addr = (void *)(COREBOOT_END_ADDR - size);
|
||||||
|
buf = coreboot_addr;
|
||||||
|
}
|
||||||
|
|
||||||
if (f_read(&fp, buf, size, NULL))
|
if (f_read(&fp, buf, size, NULL))
|
||||||
{
|
{
|
||||||
@@ -221,6 +233,7 @@ int launch_payload(char *path)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void launch_tools()
|
void launch_tools()
|
||||||
{
|
{
|
||||||
u8 max_entries = 61;
|
u8 max_entries = 61;
|
||||||
@@ -339,7 +352,7 @@ void dump_sysnand()
|
|||||||
{
|
{
|
||||||
h_cfg.emummc_force_disable = true;
|
h_cfg.emummc_force_disable = true;
|
||||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
//dump_keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_emunand()
|
void dump_emunand()
|
||||||
@@ -348,7 +361,7 @@ void dump_emunand()
|
|||||||
return;
|
return;
|
||||||
emu_cfg.enabled = 1;
|
emu_cfg.enabled = 1;
|
||||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
//dump_keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
ment_t ment_top[] = {
|
ment_t ment_top[] = {
|
||||||
@@ -395,9 +408,55 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) {
|
|||||||
free(pkg1);
|
free(pkg1);
|
||||||
ment_top[1].caption = emunand_label;
|
ment_top[1].caption = emunand_label;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#define IPL_STACK_TOP 0x90010000
|
#define EXCP_EN_ADDR 0x4003FFFC
|
||||||
#define IPL_HEAP_START 0x90020000
|
#define EXCP_MAGIC 0x30505645 // EVP0
|
||||||
|
#define EXCP_TYPE_ADDR 0x4003FFF8
|
||||||
|
#define EXCP_TYPE_RESET 0x545352 // RST
|
||||||
|
#define EXCP_TYPE_UNDEF 0x464455 // UDF
|
||||||
|
#define EXCP_TYPE_PABRT 0x54424150 // PABT
|
||||||
|
#define EXCP_TYPE_DABRT 0x54424144 // DABT
|
||||||
|
#define EXCP_LR_ADDR 0x4003FFF4
|
||||||
|
|
||||||
|
static void _show_errors(){
|
||||||
|
u32 *excp_enabled = (u32 *)EXCP_EN_ADDR;
|
||||||
|
u32 *excp_type = (u32 *)EXCP_TYPE_ADDR;
|
||||||
|
u32 *excp_lr = (u32 *)EXCP_LR_ADDR;
|
||||||
|
|
||||||
|
if (*excp_enabled == EXCP_MAGIC)
|
||||||
|
h_cfg.errors |= ERR_EXCEPT_ENB;
|
||||||
|
|
||||||
|
if (h_cfg.errors & ERR_EXCEPT_ENB){
|
||||||
|
gfx_clearscreen();
|
||||||
|
SWAPCOLOR(COLOR_ORANGE);
|
||||||
|
gfx_printf("\nAn exception has occured while running TegraExplorer!\n(LR %08X)\n\n", *excp_lr);
|
||||||
|
|
||||||
|
SWAPCOLOR(COLOR_VIOLET);
|
||||||
|
gfx_printf("Exception: ");
|
||||||
|
SWAPCOLOR(COLOR_YELLOW);
|
||||||
|
switch (*excp_type){
|
||||||
|
case EXCP_TYPE_RESET:
|
||||||
|
gfx_printf("Reset");
|
||||||
|
break;
|
||||||
|
case EXCP_TYPE_UNDEF:
|
||||||
|
gfx_printf("Undefined instruction");
|
||||||
|
break;
|
||||||
|
case EXCP_TYPE_PABRT:
|
||||||
|
gfx_printf("Prefetch abort");
|
||||||
|
break;
|
||||||
|
case EXCP_TYPE_DABRT:
|
||||||
|
gfx_printf("Data abort");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RESETCOLOR;
|
||||||
|
gfx_printf("\n\nPress vol+/- or power to continue");
|
||||||
|
|
||||||
|
*excp_enabled = 0;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern void pivot_stack(u32 stack_top);
|
extern void pivot_stack(u32 stack_top);
|
||||||
|
|
||||||
@@ -447,6 +506,8 @@ void ipl_main()
|
|||||||
tui_do_menu(&menu_top);
|
tui_do_menu(&menu_top);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
_show_errors();
|
||||||
|
|
||||||
te_main();
|
te_main();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
|
|||||||
1212
source/mem/emc.h
1212
source/mem/emc.h
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
* Copyright (c) 2018 M4xw
|
* Copyright (c) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -29,7 +30,7 @@ static void _heap_create(heap_t *heap, u32 start)
|
|||||||
// Node info is before node address.
|
// Node info is before node address.
|
||||||
static u32 _heap_alloc(heap_t *heap, u32 size)
|
static u32 _heap_alloc(heap_t *heap, u32 size)
|
||||||
{
|
{
|
||||||
hnode_t *node, *new;
|
hnode_t *node, *new_node;
|
||||||
|
|
||||||
// Align to cache line size.
|
// Align to cache line size.
|
||||||
size = ALIGN(size, sizeof(hnode_t));
|
size = ALIGN(size, sizeof(hnode_t));
|
||||||
@@ -49,22 +50,29 @@ static u32 _heap_alloc(heap_t *heap, u32 size)
|
|||||||
node = heap->first;
|
node = heap->first;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
// Check if there's available unused node.
|
||||||
if (!node->used && (size <= node->size))
|
if (!node->used && (size <= node->size))
|
||||||
{
|
{
|
||||||
|
// Size and offset of the new unused node.
|
||||||
u32 new_size = node->size - size;
|
u32 new_size = node->size - size;
|
||||||
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
|
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
|
||||||
|
|
||||||
// If there's aligned leftover space, create a new node.
|
// If there's aligned unused space from the old node,
|
||||||
|
// create a new one and set the leftover size.
|
||||||
if (new_size >= (sizeof(hnode_t) << 2))
|
if (new_size >= (sizeof(hnode_t) << 2))
|
||||||
{
|
{
|
||||||
new->size = new_size - sizeof(hnode_t);
|
new_node->size = new_size - sizeof(hnode_t);
|
||||||
new->used = 0;
|
new_node->used = 0;
|
||||||
new->next = node->next;
|
new_node->next = node->next;
|
||||||
new->next->prev = new;
|
|
||||||
new->prev = node;
|
// Check that we are not on first node.
|
||||||
node->next = new;
|
if (new_node->next)
|
||||||
|
new_node->next->prev = new_node;
|
||||||
|
|
||||||
|
new_node->prev = node;
|
||||||
|
node->next = new_node;
|
||||||
}
|
}
|
||||||
else
|
else // Unused node size is just enough.
|
||||||
size += new_size;
|
size += new_size;
|
||||||
|
|
||||||
node->size = size;
|
node->size = size;
|
||||||
@@ -72,20 +80,23 @@ static u32 _heap_alloc(heap_t *heap, u32 size)
|
|||||||
|
|
||||||
return (u32)node + sizeof(hnode_t);
|
return (u32)node + sizeof(hnode_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No unused node found, try the next one.
|
||||||
if (node->next)
|
if (node->next)
|
||||||
node = node->next;
|
node = node->next;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
|
// No unused node found, create a new one.
|
||||||
new->used = 1;
|
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
|
||||||
new->size = size;
|
new_node->used = 1;
|
||||||
new->prev = node;
|
new_node->size = size;
|
||||||
new->next = NULL;
|
new_node->prev = node;
|
||||||
node->next = new;
|
new_node->next = NULL;
|
||||||
|
node->next = new_node;
|
||||||
|
|
||||||
return (u32)new + sizeof(hnode_t);
|
return (u32)new_node + sizeof(hnode_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _heap_free(heap_t *heap, u32 addr)
|
static void _heap_free(heap_t *heap, u32 addr)
|
||||||
@@ -101,6 +112,7 @@ static void _heap_free(heap_t *heap, u32 addr)
|
|||||||
{
|
{
|
||||||
node->prev->size += node->size + sizeof(hnode_t);
|
node->prev->size += node->size + sizeof(hnode_t);
|
||||||
node->prev->next = node->next;
|
node->prev->next = node->next;
|
||||||
|
|
||||||
if (node->next)
|
if (node->next)
|
||||||
node->next->prev = node->prev;
|
node->next->prev = node->prev;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|||||||
@@ -463,4 +463,54 @@
|
|||||||
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
||||||
#define MC_DA_CONFIG0 0x9dc
|
#define MC_DA_CONFIG0 0x9dc
|
||||||
|
|
||||||
|
// MC_SECURITY_CARVEOUTX_CFG0
|
||||||
|
// Mode of LOCK_MODE.
|
||||||
|
#define PROTECT_MODE_SHIFT 0
|
||||||
|
#define SEC_CARVEOUT_CFG_SECURE (0 << PROTECT_MODE_SHIFT0)
|
||||||
|
#define SEC_CARVEOUT_CFG_TZ_SECURE (1 << PROTECT_MODE_SHIFT0)
|
||||||
|
// Enables PROTECT_MODE.
|
||||||
|
#define LOCK_MODE_SHIFT 1
|
||||||
|
#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_LOCKED (1 << LOCK_MODE_SHIFT)
|
||||||
|
|
||||||
|
#define ADDRESS_TYPE_SHIFT 2
|
||||||
|
#define SEC_CARVEOUT_CFG_ANY_ADDRESS (0 << ADDRESS_TYPE_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT)
|
||||||
|
|
||||||
|
#define READ_ACCESS_LEVEL_SHIFT 3
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_ALL (1 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_UNK (2 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define WRITE_ACCESS_LEVEL_SHIFT 7
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_ALL (1 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_UNK (2 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11)
|
||||||
|
|
||||||
|
#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L0 (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L1 (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L2 (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L3 (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L0 (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L1 (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L2 (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L3 (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU (1 << 22)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK (1 << 23)
|
||||||
|
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK (1 << 24)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH (1 << 25)
|
||||||
|
#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH (1 << 26)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_IS_WPR (1 << 27)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -27,24 +27,29 @@
|
|||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
|
||||||
extern volatile nyx_storage_t *nyx_str;
|
extern volatile nyx_storage_t *nyx_str;
|
||||||
|
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||||
|
|
||||||
u32 minerva_init()
|
u32 minerva_init()
|
||||||
{
|
{
|
||||||
u32 curr_ram_idx = 0;
|
u32 curr_ram_idx = 0;
|
||||||
|
|
||||||
|
minerva_cfg = NULL;
|
||||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||||
|
memset(mtc_cfg, 0, sizeof(mtc_config_t));
|
||||||
|
|
||||||
// Set table to nyx storage.
|
// Set table to nyx storage.
|
||||||
mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table;
|
mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table;
|
||||||
|
|
||||||
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||||
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
|
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
|
||||||
|
|
||||||
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
|
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
|
||||||
|
|
||||||
// Ensure that Minerva is new.
|
// Ensure that Minerva is new.
|
||||||
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
|
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
|
||||||
minerva_cfg = (void *)ep_addr;
|
minerva_cfg = (void *)ep_addr;
|
||||||
|
else
|
||||||
|
mtc_cfg->init_done = 0;
|
||||||
|
|
||||||
if (!minerva_cfg)
|
if (!minerva_cfg)
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ typedef enum
|
|||||||
FREQ_1600 = 1600000
|
FREQ_1600 = 1600000
|
||||||
} minerva_freq_t;
|
} minerva_freq_t;
|
||||||
|
|
||||||
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||||
u32 minerva_init();
|
u32 minerva_init();
|
||||||
void minerva_change_freq(minerva_freq_t freq);
|
void minerva_change_freq(minerva_freq_t freq);
|
||||||
void minerva_periodic_training();
|
void minerva_periodic_training();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
* Copyright (c) 2019 CTCaer
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
* 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 "mc.h"
|
#include "mc.h"
|
||||||
#include "emc.h"
|
#include "emc.h"
|
||||||
#include "sdram_param_t210.h"
|
#include "sdram_param_t210.h"
|
||||||
@@ -29,7 +31,7 @@
|
|||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
#define CONFIG_SDRAM_COMPRESS_CFG
|
#define CONFIG_SDRAM_KEEP_ALIVE
|
||||||
|
|
||||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||||
#include "../libs/compr/lz.h"
|
#include "../libs/compr/lz.h"
|
||||||
@@ -40,13 +42,57 @@
|
|||||||
|
|
||||||
static u32 _get_sdram_id()
|
static u32 _get_sdram_id()
|
||||||
{
|
{
|
||||||
u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3;
|
return ((fuse_read_odm(4) & 0x38) >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if id is proper.
|
static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)
|
||||||
if (sdram_id > 7)
|
{
|
||||||
sdram_id = 0;
|
bool err = true;
|
||||||
|
|
||||||
return sdram_id;
|
for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)
|
||||||
|
{
|
||||||
|
if (emc_channel)
|
||||||
|
{
|
||||||
|
if (emc_channel != 1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)
|
||||||
|
{
|
||||||
|
err = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)
|
||||||
|
{
|
||||||
|
err = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sdram_req_mrr_data(u32 data, bool dual_channel)
|
||||||
|
{
|
||||||
|
EMC(EMC_MRR) = data;
|
||||||
|
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);
|
||||||
|
if (dual_channel)
|
||||||
|
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);
|
||||||
|
}
|
||||||
|
|
||||||
|
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
|
||||||
|
{
|
||||||
|
emc_mr_data_t data;
|
||||||
|
_sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0);
|
||||||
|
data.dev0_ch0 = EMC(EMC_MRR) & 0xFF;
|
||||||
|
data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
|
||||||
|
_sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1);
|
||||||
|
data.dev1_ch0 = EMC(EMC_MRR) & 0xFF;
|
||||||
|
data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sdram_config(const sdram_params_t *params)
|
static void _sdram_config(const sdram_params_t *params)
|
||||||
@@ -73,10 +119,14 @@ static void _sdram_config(const sdram_params_t *params)
|
|||||||
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
|
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
|
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
|
||||||
|
|
||||||
// u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
|
#ifdef CONFIG_SDRAM_KEEP_ALIVE
|
||||||
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp;
|
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) =
|
||||||
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000;
|
(params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE;
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
|
#else
|
||||||
|
u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
u32 wait_end = get_tmr_us() + 300;
|
u32 wait_end = get_tmr_us() + 300;
|
||||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
|
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
|
||||||
@@ -91,7 +141,7 @@ break_nosleep:
|
|||||||
if (params->emc_clock_source_dll)
|
if (params->emc_clock_source_dll)
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
|
||||||
if (params->clear_clock2_mc1)
|
if (params->clear_clock2_mc1)
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1.
|
||||||
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
|
||||||
@@ -509,9 +559,9 @@ break_nosleep:
|
|||||||
// ZQ CAL setup (not actually issuing ZQ CAL now).
|
// ZQ CAL setup (not actually issuing ZQ CAL now).
|
||||||
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
||||||
{
|
{
|
||||||
if (params->memory_type == 2)
|
if (params->memory_type == MEMORY_TYPE_DDR3L)
|
||||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
|
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
|
||||||
if (params->memory_type == 3)
|
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
||||||
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
||||||
@@ -527,7 +577,7 @@ break_nosleep:
|
|||||||
|
|
||||||
// Set clock enable signal.
|
// Set clock enable signal.
|
||||||
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
||||||
if (params->memory_type == 2 || params->memory_type == 3)
|
if (params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
EMC(EMC_PIN) = pin_gpio_cfg;
|
EMC(EMC_PIN) = pin_gpio_cfg;
|
||||||
(void)EMC(EMC_PIN);
|
(void)EMC(EMC_PIN);
|
||||||
@@ -536,9 +586,9 @@ break_nosleep:
|
|||||||
(void)EMC(EMC_PIN);
|
(void)EMC(EMC_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params->memory_type == 3)
|
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
usleep(params->emc_pin_extra_wait + 2000);
|
usleep(params->emc_pin_extra_wait + 2000);
|
||||||
else if (params->memory_type == 2)
|
else if (params->memory_type == MEMORY_TYPE_DDR3L)
|
||||||
usleep(params->emc_pin_extra_wait + 500);
|
usleep(params->emc_pin_extra_wait + 500);
|
||||||
|
|
||||||
// Enable clock enable signal.
|
// Enable clock enable signal.
|
||||||
@@ -547,15 +597,15 @@ break_nosleep:
|
|||||||
usleep(params->emc_pin_program_wait);
|
usleep(params->emc_pin_program_wait);
|
||||||
|
|
||||||
// Send NOP (trigger just needs to be non-zero).
|
// Send NOP (trigger just needs to be non-zero).
|
||||||
if (params->memory_type != 3)
|
if (params->memory_type != MEMORY_TYPE_LPDDR4)
|
||||||
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
|
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
|
||||||
|
|
||||||
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
|
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
|
||||||
if (params->memory_type == 1)
|
if (params->memory_type == MEMORY_TYPE_LPDDR2)
|
||||||
usleep(params->emc_pin_extra_wait + 200);
|
usleep(params->emc_pin_extra_wait + 200);
|
||||||
|
|
||||||
// Init zq calibration,
|
// Init zq calibration,
|
||||||
if (params->memory_type == 3)
|
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
// Patch 6 using BCT spare variables.
|
// Patch 6 using BCT spare variables.
|
||||||
if (params->emc_bct_spare10)
|
if (params->emc_bct_spare10)
|
||||||
@@ -596,7 +646,7 @@ break_nosleep:
|
|||||||
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
|
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
|
||||||
|
|
||||||
// Start periodic ZQ calibration (LPDDRx only).
|
// Start periodic ZQ calibration (LPDDRx only).
|
||||||
if (params->memory_type - 1 <= 2)
|
if (params->memory_type && params->memory_type <= MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
|
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
|
||||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
||||||
@@ -641,18 +691,47 @@ break_nosleep:
|
|||||||
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
|
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
|
||||||
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
|
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
|
||||||
|
|
||||||
//Disable write access to a bunch of EMC registers.
|
// Disable write access to a bunch of EMC registers.
|
||||||
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
|
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SDRAM_COMPRESS_CFG
|
||||||
|
static void _sdram_patch_model_params(u32 dramid, u32 *params)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < sizeof(sdram_cfg_vendor_patches) / sizeof(sdram_vendor_patch_t); i++)
|
||||||
|
if (sdram_cfg_vendor_patches[i].dramid & DRAM_ID(dramid))
|
||||||
|
params[sdram_cfg_vendor_patches[i].addr] = sdram_cfg_vendor_patches[i].val;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
sdram_params_t *sdram_get_params()
|
sdram_params_t *sdram_get_params()
|
||||||
{
|
{
|
||||||
|
// Check if id is proper.
|
||||||
|
u32 dramid = _get_sdram_id();
|
||||||
|
if (dramid > 6)
|
||||||
|
dramid = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||||
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
|
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
|
||||||
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
|
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
|
||||||
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
|
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * dramid];
|
||||||
#else
|
#else
|
||||||
return _dram_cfgs[_get_sdram_id()];
|
sdram_params_t *buf = (sdram_params_t *)SDRAM_PARAMS_ADDR;
|
||||||
|
memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t));
|
||||||
|
switch (dramid)
|
||||||
|
{
|
||||||
|
case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH:
|
||||||
|
case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT:
|
||||||
|
break;
|
||||||
|
case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN:
|
||||||
|
case DRAM_4GB_COPPER_UNK_3:
|
||||||
|
case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH:
|
||||||
|
case DRAM_4GB_COPPER_UNK_5:
|
||||||
|
case DRAM_4GB_COPPER_UNK_6:
|
||||||
|
_sdram_patch_model_params(dramid, (u32 *)buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,7 +775,6 @@ sdram_params_t *sdram_get_params_patched()
|
|||||||
|
|
||||||
void sdram_init()
|
void sdram_init()
|
||||||
{
|
{
|
||||||
//TODO: sdram_id should be in [0,4].
|
|
||||||
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
||||||
|
|
||||||
// Set DRAM voltage.
|
// Set DRAM voltage.
|
||||||
|
|||||||
@@ -17,11 +17,13 @@
|
|||||||
#ifndef _SDRAM_H_
|
#ifndef _SDRAM_H_
|
||||||
#define _SDRAM_H_
|
#define _SDRAM_H_
|
||||||
|
|
||||||
|
#include "emc.h"
|
||||||
#include "sdram_param_t210.h"
|
#include "sdram_param_t210.h"
|
||||||
|
|
||||||
void sdram_init();
|
void sdram_init();
|
||||||
sdram_params_t *sdram_get_params();
|
sdram_params_t *sdram_get_params();
|
||||||
sdram_params_t *sdram_get_params_patched();
|
sdram_params_t *sdram_get_params_patched();
|
||||||
void sdram_lp0_save_params(const void *params);
|
void sdram_lp0_save_params(const void *params);
|
||||||
|
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -26,12 +26,12 @@
|
|||||||
#ifndef _SDRAM_PARAM_T210_H_
|
#ifndef _SDRAM_PARAM_T210_H_
|
||||||
#define _SDRAM_PARAM_T210_H_
|
#define _SDRAM_PARAM_T210_H_
|
||||||
|
|
||||||
#define MEMORY_TYPE_NONE 0
|
#define MEMORY_TYPE_NONE 0
|
||||||
#define MEMORY_TYPE_DDR 0
|
#define MEMORY_TYPE_DDR 0
|
||||||
#define MEMORY_TYPE_LPDDR 0
|
#define MEMORY_TYPE_LPDDR 0
|
||||||
#define MEMORY_TYPE_DDR2 0
|
#define MEMORY_TYPE_DDR2 0
|
||||||
#define MEMORY_TYPE_LPDDR2 1
|
#define MEMORY_TYPE_LPDDR2 1
|
||||||
#define MEMORY_TYPE_DDR3 2
|
#define MEMORY_TYPE_DDR3L 2
|
||||||
#define MEMORY_TYPE_LPDDR4 3
|
#define MEMORY_TYPE_LPDDR4 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
170
source/power/bq24193.c
Normal file
170
source/power/bq24193.c
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bq24193.h"
|
||||||
|
#include "../soc/i2c.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||||
|
{
|
||||||
|
u8 data;
|
||||||
|
|
||||||
|
switch (prop) {
|
||||||
|
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||||
|
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;
|
||||||
|
*value = 0;
|
||||||
|
*value += ((data >> 0) & 1) ? 80 : 0;
|
||||||
|
*value += ((data >> 1) & 1) ? 160 : 0;
|
||||||
|
*value += ((data >> 2) & 1) ? 320 : 0;
|
||||||
|
*value += ((data >> 3) & 1) ? 640 : 0;
|
||||||
|
*value += 3880;
|
||||||
|
break;
|
||||||
|
case BQ24193_InputCurrentLimit: // Input current limit (mA).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||||
|
data &= BQ24193_INCONFIG_INLIMIT_MASK;
|
||||||
|
switch (data)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
*value = 100;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*value = 150;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*value = 500;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*value = 900;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*value = 1200;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
*value = 1500;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*value = 2000;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
*value = 3000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig);
|
||||||
|
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
|
||||||
|
*value *= 100;
|
||||||
|
*value += 3000;
|
||||||
|
break;
|
||||||
|
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||||
|
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
|
||||||
|
*value = 0;
|
||||||
|
*value += ((data >> 0) & 1) ? 64 : 0;
|
||||||
|
*value += ((data >> 1) & 1) ? 128 : 0;
|
||||||
|
*value += ((data >> 2) & 1) ? 256 : 0;
|
||||||
|
*value += ((data >> 3) & 1) ? 512 : 0;
|
||||||
|
*value += ((data >> 4) & 1) ? 1024 : 0;
|
||||||
|
*value += ((data >> 5) & 1) ? 2048 : 0;
|
||||||
|
*value += 512;
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||||
|
data &= BQ24193_CHRGCURR_20PCT_MASK;
|
||||||
|
if (data)
|
||||||
|
*value = *value * 20 / 100; // Fast charge current limit is 20%.
|
||||||
|
break;
|
||||||
|
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||||
|
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
|
||||||
|
*value = 0;
|
||||||
|
*value += ((data >> 0) & 1) ? 16 : 0;
|
||||||
|
*value += ((data >> 1) & 1) ? 32 : 0;
|
||||||
|
*value += ((data >> 2) & 1) ? 64 : 0;
|
||||||
|
*value += ((data >> 3) & 1) ? 128 : 0;
|
||||||
|
*value += ((data >> 4) & 1) ? 256 : 0;
|
||||||
|
*value += ((data >> 5) & 1) ? 512 : 0;
|
||||||
|
*value += 3504;
|
||||||
|
break;
|
||||||
|
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||||
|
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||||
|
if (data)
|
||||||
|
*value = 300;
|
||||||
|
else
|
||||||
|
*value = 100;
|
||||||
|
break;
|
||||||
|
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_IRCompThermal);
|
||||||
|
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||||
|
switch (data)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
*value = 60;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*value = 80;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*value = 100;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*value = 120;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Status);
|
||||||
|
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
|
||||||
|
break;
|
||||||
|
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_FaultReg);
|
||||||
|
*value = data & BQ24193_FAULT_THERM_MASK;
|
||||||
|
break;
|
||||||
|
case BQ24193_DevID: // Dev ID.
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
|
||||||
|
*value = data & BQ24193_VENDORPART_DEV_MASK;
|
||||||
|
break;
|
||||||
|
case BQ24193_ProductNumber: // Product number.
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
|
||||||
|
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bq24193_fake_battery_removal()
|
||||||
|
{
|
||||||
|
u8 value;
|
||||||
|
|
||||||
|
// Disable watchdog to keep BATFET disabled.
|
||||||
|
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);
|
||||||
|
value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK;
|
||||||
|
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value);
|
||||||
|
|
||||||
|
// Force BATFET to disabled state. This disconnects the battery from the system.
|
||||||
|
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc);
|
||||||
|
value |= BQ24193_MISC_BATFET_DI_MASK;
|
||||||
|
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
119
source/power/bq24193.h
Normal file
119
source/power/bq24193.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BQ24193_H_
|
||||||
|
#define __BQ24193_H_
|
||||||
|
|
||||||
|
#define BQ24193_I2C_ADDR 0x6B
|
||||||
|
|
||||||
|
// REG 0 masks.
|
||||||
|
#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0)
|
||||||
|
#define BQ24193_INCONFIG_VINDPM_MASK 0x78
|
||||||
|
#define BQ24193_INCONFIG_HIZ_EN_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 1 masks.
|
||||||
|
#define BQ24193_PORCONFIG_BOOST_MASK (1<<0)
|
||||||
|
#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1)
|
||||||
|
#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4)
|
||||||
|
#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6)
|
||||||
|
#define BQ24193_PORCONFIG_RESET_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 2 masks.
|
||||||
|
#define BQ24193_CHRGCURR_20PCT_MASK (1<<0)
|
||||||
|
#define BQ24193_CHRGCURR_ICHG_MASK 0xFC
|
||||||
|
|
||||||
|
// REG 3 masks.
|
||||||
|
#define BQ24193_PRECHRG_ITERM 0x0F
|
||||||
|
#define BQ24193_PRECHRG_IPRECHG 0xF0
|
||||||
|
|
||||||
|
// REG 4 masks.
|
||||||
|
#define BQ24193_CHRGVOLT_VTHRES (1<<0)
|
||||||
|
#define BQ24193_CHRGVOLT_BATTLOW (1<<1)
|
||||||
|
#define BQ24193_CHRGVOLT_VREG 0xFC
|
||||||
|
|
||||||
|
// REG 5 masks.
|
||||||
|
#define BQ24193_CHRGTERM_ISET_MASK (1<<0)
|
||||||
|
#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1)
|
||||||
|
#define BQ24193_CHRGTERM_ENTIMER_MASK (1<<3)
|
||||||
|
#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4)
|
||||||
|
#define BQ24193_CHRGTERM_TERM_ST_MASK (1<<6)
|
||||||
|
#define BQ24193_CHRGTERM_TERM_EN_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 6 masks.
|
||||||
|
#define BQ24193_IRTHERMAL_THERM_MASK (3<<0)
|
||||||
|
#define BQ24193_IRTHERMAL_VCLAMP_MASK (7<<2)
|
||||||
|
#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5)
|
||||||
|
|
||||||
|
// REG 7 masks.
|
||||||
|
#define BQ24193_MISC_INT_MASK (3<<0)
|
||||||
|
#define BQ24193_MISC_VSET_MASK (1<<4)
|
||||||
|
#define BQ24193_MISC_BATFET_DI_MASK (1<<5)
|
||||||
|
#define BQ24193_MISC_TMR2X_EN_MASK (1<<6)
|
||||||
|
#define BQ24193_MISC_DPDM_EN_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 8 masks.
|
||||||
|
#define BQ24193_STATUS_VSYS_MASK (1<<0)
|
||||||
|
#define BQ24193_STATUS_THERM_MASK (1<<1)
|
||||||
|
#define BQ24193_STATUS_PG_MASK (1<<2)
|
||||||
|
#define BQ24193_STATUS_DPM_MASK (1<<3)
|
||||||
|
#define BQ24193_STATUS_CHRG_MASK (3<<4)
|
||||||
|
#define BQ24193_STATUS_VBUS_MASK (3<<6)
|
||||||
|
|
||||||
|
// REG 9 masks.
|
||||||
|
#define BQ24193_FAULT_THERM_MASK (7<<0)
|
||||||
|
#define BQ24193_FAULT_BATT_OVP_MASK (1<<3)
|
||||||
|
#define BQ24193_FAULT_CHARGE_MASK (3<<4)
|
||||||
|
#define BQ24193_FAULT_BOOST_MASK (1<<6)
|
||||||
|
#define BQ24193_FAULT_WATCHDOG_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG A masks.
|
||||||
|
#define BQ24193_VENDORPART_DEV_MASK (3<<0)
|
||||||
|
#define BQ24193_VENDORPART_PN_MASK (7<<3)
|
||||||
|
|
||||||
|
enum BQ24193_reg {
|
||||||
|
BQ24193_InputSource = 0x00,
|
||||||
|
BQ24193_PORConfig = 0x01,
|
||||||
|
BQ24193_ChrgCurr = 0x02,
|
||||||
|
BQ24193_PreChrgTerm = 0x03,
|
||||||
|
BQ24193_ChrgVolt = 0x04,
|
||||||
|
BQ24193_ChrgTermTimer = 0x05,
|
||||||
|
BQ24193_IRCompThermal = 0x06,
|
||||||
|
BQ24193_Misc = 0x07,
|
||||||
|
BQ24193_Status = 0x08,
|
||||||
|
BQ24193_FaultReg = 0x09,
|
||||||
|
BQ24193_VendorPart = 0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BQ24193_reg_prop {
|
||||||
|
BQ24193_InputVoltageLimit, // REG 0.
|
||||||
|
BQ24193_InputCurrentLimit, // REG 0.
|
||||||
|
BQ24193_SystemMinimumVoltage, // REG 1.
|
||||||
|
BQ24193_FastChargeCurrentLimit, // REG 2.
|
||||||
|
BQ24193_ChargeVoltageLimit, // REG 4.
|
||||||
|
BQ24193_RechargeThreshold, // REG 4.
|
||||||
|
BQ24193_ThermalRegulation, // REG 6.
|
||||||
|
BQ24193_ChargeStatus, // REG 8.
|
||||||
|
BQ24193_TempStatus, // REG 9.
|
||||||
|
BQ24193_DevID, // REG A.
|
||||||
|
BQ24193_ProductNumber, // REG A.
|
||||||
|
};
|
||||||
|
|
||||||
|
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
|
||||||
|
void bq24193_fake_battery_removal();
|
||||||
|
|
||||||
|
#endif /* __BQ24193_H_ */
|
||||||
@@ -46,6 +46,12 @@
|
|||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("Os")
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
static u32 battery_voltage = 0;
|
||||||
|
u32 max17050_get_cached_batt_volt()
|
||||||
|
{
|
||||||
|
return battery_voltage;
|
||||||
|
}
|
||||||
|
|
||||||
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||||
{
|
{
|
||||||
u16 data;
|
u16 data;
|
||||||
@@ -74,6 +80,7 @@ int max17050_get_property(enum MAX17050_reg reg, int *value)
|
|||||||
case MAX17050_VCELL: // Voltage now.
|
case MAX17050_VCELL: // Voltage now.
|
||||||
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
|
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
|
||||||
*value = data * 625 / 8 / 1000;
|
*value = data * 625 / 8 / 1000;
|
||||||
|
battery_voltage = *value;
|
||||||
break;
|
break;
|
||||||
case MAX17050_AvgVCELL: // Voltage avg.
|
case MAX17050_AvgVCELL: // Voltage avg.
|
||||||
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);
|
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2011 Samsung Electronics
|
* Copyright (c) 2011 Samsung Electronics
|
||||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
#ifndef __MAX17050_H_
|
#ifndef __MAX17050_H_
|
||||||
#define __MAX17050_H_
|
#define __MAX17050_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define MAX17050_STATUS_BattAbsent (1 << 3)
|
#define MAX17050_STATUS_BattAbsent (1 << 3)
|
||||||
#define MAX17050_DEFAULT_SNS_RESISTOR 10000
|
#define MAX17050_DEFAULT_SNS_RESISTOR 10000
|
||||||
|
|
||||||
@@ -96,14 +98,17 @@ enum MAX17050_reg {
|
|||||||
MAX17050_K_empty0 = 0x3B,
|
MAX17050_K_empty0 = 0x3B,
|
||||||
MAX17050_TaskPeriod = 0x3C,
|
MAX17050_TaskPeriod = 0x3C,
|
||||||
MAX17050_FSTAT = 0x3D,
|
MAX17050_FSTAT = 0x3D,
|
||||||
|
MAX17050_TIMER = 0x3E,
|
||||||
MAX17050_SHDNTIMER = 0x3F,
|
MAX17050_SHDNTIMER = 0x3F,
|
||||||
|
|
||||||
MAX17050_QRTbl30 = 0x42,
|
MAX17050_QRTbl30 = 0x42,
|
||||||
|
|
||||||
MAX17050_dQacc = 0x45,
|
MAX17050_dQacc = 0x45,
|
||||||
MAX17050_dPacc = 0x46,
|
MAX17050_dPacc = 0x46,
|
||||||
|
|
||||||
MAX17050_VFSOC0 = 0x48,
|
MAX17050_VFSOC0 = 0x48,
|
||||||
|
|
||||||
|
Max17050_QH0 = 0x4C,
|
||||||
MAX17050_QH = 0x4D,
|
MAX17050_QH = 0x4D,
|
||||||
MAX17050_QL = 0x4E,
|
MAX17050_QL = 0x4E,
|
||||||
|
|
||||||
@@ -111,6 +116,8 @@ enum MAX17050_reg {
|
|||||||
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
|
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
|
||||||
|
|
||||||
MAX17050_VFSOC0Enable = 0x60,
|
MAX17050_VFSOC0Enable = 0x60,
|
||||||
|
MAX17050_MODELEnable1 = 0x62,
|
||||||
|
MAX17050_MODELEnable2 = 0x63,
|
||||||
|
|
||||||
MAX17050_MODELChrTbl = 0x80,
|
MAX17050_MODELChrTbl = 0x80,
|
||||||
|
|
||||||
@@ -123,5 +130,6 @@ enum MAX17050_reg {
|
|||||||
|
|
||||||
int max17050_get_property(enum MAX17050_reg reg, int *value);
|
int max17050_get_property(enum MAX17050_reg reg, int *value);
|
||||||
int max17050_fix_configuration();
|
int max17050_fix_configuration();
|
||||||
|
u32 max17050_get_cached_batt_volt();
|
||||||
|
|
||||||
#endif /* __MAX17050_H_ */
|
#endif /* __MAX17050_H_ */
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ int max77620_regulator_enable(u32 id, int enable)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LDO only.
|
||||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
||||||
{
|
{
|
||||||
if (id > REGULATOR_MAX)
|
if (id > REGULATOR_MAX)
|
||||||
@@ -168,9 +169,9 @@ void max77620_config_default()
|
|||||||
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
|
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void max77620_low_battery_monitor_config()
|
void max77620_low_battery_monitor_config(bool enable)
|
||||||
{
|
{
|
||||||
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
|
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
|
||||||
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD |
|
MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) |
|
||||||
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
|
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||||
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||||
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
||||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
||||||
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
||||||
@@ -113,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv);
|
|||||||
int max77620_regulator_enable(u32 id, int enable);
|
int max77620_regulator_enable(u32 id, int enable);
|
||||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
||||||
void max77620_config_default();
|
void max77620_config_default();
|
||||||
void max77620_low_battery_monitor_config();
|
void max77620_low_battery_monitor_config(bool enable);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
76
source/power/regulator_5v.c
Normal file
76
source/power/regulator_5v.c
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../soc/gpio.h"
|
||||||
|
#include "../soc/pinmux.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
static u8 reg_5v_dev = 0;
|
||||||
|
|
||||||
|
void regulator_enable_5v(u8 dev)
|
||||||
|
{
|
||||||
|
// The power supply selection from battery or USB is automatic.
|
||||||
|
if (!reg_5v_dev)
|
||||||
|
{
|
||||||
|
// Fan and Rail power from internal 5V regulator (battery).
|
||||||
|
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1;
|
||||||
|
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH);
|
||||||
|
|
||||||
|
// Fan and Rail power from USB 5V VDD.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1;
|
||||||
|
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH);
|
||||||
|
|
||||||
|
// Make sure GPIO power is enabled.
|
||||||
|
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN;
|
||||||
|
// Override power detect for GPIO AO IO rails.
|
||||||
|
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN;
|
||||||
|
}
|
||||||
|
reg_5v_dev |= dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void regulator_disable_5v(u8 dev)
|
||||||
|
{
|
||||||
|
reg_5v_dev &= ~dev;
|
||||||
|
|
||||||
|
if (!reg_5v_dev)
|
||||||
|
{
|
||||||
|
// Rail power from internal 5V regulator (battery).
|
||||||
|
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW);
|
||||||
|
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_DISABLE);
|
||||||
|
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_SPIO);
|
||||||
|
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = PINMUX_PARKED | PINMUX_INPUT_ENABLE;
|
||||||
|
|
||||||
|
// Rail power from USB 5V VDD.
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);
|
||||||
|
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||||
|
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_SPIO);
|
||||||
|
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_PARKED | PINMUX_INPUT_ENABLE;
|
||||||
|
|
||||||
|
// GPIO AO IO rails.
|
||||||
|
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool regulator_get_5v_dev_enabled(u8 dev)
|
||||||
|
{
|
||||||
|
return (reg_5v_dev & dev);
|
||||||
|
}
|
||||||
34
source/power/regulator_5v.h
Normal file
34
source/power/regulator_5v.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REGULATOR_5V_H_
|
||||||
|
#define _REGULATOR_5V_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
REGULATOR_5V_FAN = (1 << 0),
|
||||||
|
REGULATOR_5V_JC_R = (1 << 1),
|
||||||
|
REGULATOR_5V_JC_L = (1 << 2),
|
||||||
|
REGULATOR_5V_ALL = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
void regulator_enable_5v(u8 dev);
|
||||||
|
void regulator_disable_5v(u8 dev);
|
||||||
|
bool regulator_get_5v_dev_enabled(u8 dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
* Copyright (c) 2019 shchmue
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -34,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
|||||||
// Get time.
|
// Get time.
|
||||||
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
||||||
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
|
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
|
||||||
|
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG);
|
||||||
|
time->hour = hour & 0x1F;
|
||||||
|
|
||||||
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
|
if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK))
|
||||||
|
|
||||||
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
|
|
||||||
time->hour = (time->hour & 0xF) + 12;
|
time->hour = (time->hour & 0xF) + 12;
|
||||||
|
|
||||||
// Get day of week. 1: Monday to 7: Sunday.
|
// Get day of week. 1: Monday to 7: Sunday.
|
||||||
@@ -75,3 +76,94 @@ void max77620_rtc_stop_alarm()
|
|||||||
// Update RTC clock from RTC regs.
|
// Update RTC clock from RTC regs.
|
||||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
|
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)
|
||||||
|
{
|
||||||
|
u32 tmp, edays, year, month, day;
|
||||||
|
|
||||||
|
// Set time.
|
||||||
|
time->sec = epoch % 60;
|
||||||
|
epoch /= 60;
|
||||||
|
time->min = epoch % 60;
|
||||||
|
epoch /= 60;
|
||||||
|
time->hour = epoch % 24;
|
||||||
|
epoch /= 24;
|
||||||
|
|
||||||
|
// Calculate base date values.
|
||||||
|
tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15);
|
||||||
|
tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2));
|
||||||
|
|
||||||
|
year = (20 * tmp - 2442) / 7305;
|
||||||
|
edays = tmp - 365 * year - (year >> 2);
|
||||||
|
month = edays * 1000 / 30601;
|
||||||
|
day = edays - month * 30 - month * 601 / 1000;
|
||||||
|
|
||||||
|
// Month/Year offset.
|
||||||
|
if(month < 14)
|
||||||
|
{
|
||||||
|
year -= 4716;
|
||||||
|
month--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
year -= 4715;
|
||||||
|
month -= 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set date.
|
||||||
|
time->year = year;
|
||||||
|
time->month = month;
|
||||||
|
time->day = day;
|
||||||
|
|
||||||
|
// Set weekday.
|
||||||
|
time->weekday = 0; //! TODO.
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding)
|
||||||
|
{
|
||||||
|
u32 year, month, epoch;
|
||||||
|
|
||||||
|
//Year
|
||||||
|
year = time->year;
|
||||||
|
//Month of year
|
||||||
|
month = time->month;
|
||||||
|
|
||||||
|
if (!hos_encoding)
|
||||||
|
{
|
||||||
|
// Month/Year offset.
|
||||||
|
if(month < 3)
|
||||||
|
{
|
||||||
|
month += 12;
|
||||||
|
year--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
year -= 2000;
|
||||||
|
month++;
|
||||||
|
|
||||||
|
// Month/Year offset.
|
||||||
|
if(month < 3)
|
||||||
|
{
|
||||||
|
month += 9;
|
||||||
|
year--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
month -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days.
|
||||||
|
|
||||||
|
if (!hos_encoding)
|
||||||
|
{
|
||||||
|
epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days.
|
||||||
|
epoch -= 719561; // Epoch time is 1/1/1970.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days.
|
||||||
|
|
||||||
|
epoch *= 86400; // Days to seconds.
|
||||||
|
epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds.
|
||||||
|
|
||||||
|
return epoch;
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,5 +71,7 @@ typedef struct _rtc_time_t {
|
|||||||
|
|
||||||
void max77620_rtc_get_time(rtc_time_t *time);
|
void max77620_rtc_get_time(rtc_time_t *time);
|
||||||
void max77620_rtc_stop_alarm();
|
void max77620_rtc_stop_alarm();
|
||||||
|
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);
|
||||||
|
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding);
|
||||||
|
|
||||||
#endif /* _MFD_MAX77620_RTC_H_ */
|
#endif /* _MFD_MAX77620_RTC_H_ */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
* Copyright (c) 2018 Atmosphère-NX
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
* Copyright (c) 2019 shchmue
|
* Copyright (c) 2019-2020 shchmue
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|||||||
@@ -70,27 +70,26 @@
|
|||||||
#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT)
|
#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT)
|
||||||
|
|
||||||
#define SE_RNG_CONFIG_REG_OFFSET 0x340
|
#define SE_RNG_CONFIG_REG_OFFSET 0x340
|
||||||
#define DRBG_MODE_SHIFT 0
|
#define RNG_MODE_SHIFT 0
|
||||||
#define DRBG_MODE_NORMAL 0
|
#define RNG_MODE_NORMAL 0
|
||||||
#define DRBG_MODE_FORCE_INSTANTION 1
|
#define RNG_MODE_FORCE_INSTANTION 1
|
||||||
#define DRBG_MODE_FORCE_RESEED 2
|
#define RNG_MODE_FORCE_RESEED 2
|
||||||
#define SE_RNG_CONFIG_MODE(x) (x << DRBG_MODE_SHIFT)
|
#define SE_RNG_CONFIG_MODE(x) (x << RNG_MODE_SHIFT)
|
||||||
|
#define RNG_SRC_SHIFT 2
|
||||||
|
#define RNG_SRC_NONE 0
|
||||||
|
#define RNG_SRC_ENTROPY 1
|
||||||
|
#define RNG_SRC_LFSR 2
|
||||||
|
#define SE_RNG_CONFIG_SRC(x) (x << RNG_SRC_SHIFT)
|
||||||
|
|
||||||
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344
|
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344
|
||||||
#define DRBG_RO_ENT_SRC_SHIFT 1
|
#define RNG_SRC_RO_ENT_SHIFT 1
|
||||||
#define DRBG_RO_ENT_SRC_ENABLE 1
|
#define RNG_SRC_RO_ENT_ENABLE 1
|
||||||
#define DRBG_RO_ENT_SRC_DISABLE 0
|
#define RNG_SRC_RO_ENT_DISABLE 0
|
||||||
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) (x << DRBG_RO_ENT_SRC_SHIFT)
|
#define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT)
|
||||||
#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0
|
#define RNG_SRC_RO_ENT_LOCK_SHIFT 0
|
||||||
#define DRBG_RO_ENT_SRC_LOCK_ENABLE 1
|
#define RNG_SRC_RO_ENT_LOCK_ENABLE 1
|
||||||
#define DRBG_RO_ENT_SRC_LOCK_DISABLE 0
|
#define RNG_SRC_RO_ENT_LOCK_DISABLE 0
|
||||||
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) (x << DRBG_RO_ENT_SRC_LOCK_SHIFT)
|
#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT)
|
||||||
|
|
||||||
#define DRBG_SRC_SHIFT 2
|
|
||||||
#define DRBG_SRC_NONE 0
|
|
||||||
#define DRBG_SRC_ENTROPY 1
|
|
||||||
#define DRBG_SRC_LFSR 2
|
|
||||||
#define SE_RNG_CONFIG_SRC(x) (x << DRBG_SRC_SHIFT)
|
|
||||||
|
|
||||||
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
|
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
|
||||||
|
|
||||||
@@ -119,6 +118,8 @@
|
|||||||
#define OP_DONE 1
|
#define OP_DONE 1
|
||||||
#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
|
#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
|
||||||
|
|
||||||
|
#define SE_CRYPTO_LAST_BLOCK 0x080
|
||||||
|
|
||||||
#define SE_CRYPTO_REG_OFFSET 0x304
|
#define SE_CRYPTO_REG_OFFSET 0x304
|
||||||
#define SE_CRYPTO_HASH_SHIFT 0
|
#define SE_CRYPTO_HASH_SHIFT 0
|
||||||
#define HASH_DISABLE 0
|
#define HASH_DISABLE 0
|
||||||
@@ -191,6 +192,7 @@
|
|||||||
#define SRK 6
|
#define SRK 6
|
||||||
|
|
||||||
#define RSA_KEYTABLE 1
|
#define RSA_KEYTABLE 1
|
||||||
|
#define AES_KEYTABLE 2
|
||||||
#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT)
|
#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT)
|
||||||
|
|
||||||
#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16
|
#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
|
|
||||||
kfuse_wait_ready();
|
kfuse_wait_ready();
|
||||||
|
|
||||||
//Configure Falcon.
|
// Configure Falcon.
|
||||||
TSEC(TSEC_DMACTL) = 0;
|
TSEC(TSEC_DMACTL) = 0;
|
||||||
TSEC(TSEC_IRQMSET) =
|
TSEC(TSEC_IRQMSET) =
|
||||||
TSEC_IRQMSET_EXT(0xFF) |
|
TSEC_IRQMSET_EXT(0xFF) |
|
||||||
@@ -102,7 +102,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load firmware or emulate memio environment for newer TSEC fw.
|
// Load firmware or emulate memio environment for newer TSEC fw.
|
||||||
if (kb == KB_FIRMWARE_VERSION_620)
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||||
else
|
else
|
||||||
@@ -126,7 +126,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
{
|
{
|
||||||
// Init SMMU translation for TSEC.
|
// Init SMMU translation for TSEC.
|
||||||
pdir = smmu_init_for_tsec();
|
pdir = smmu_init_for_tsec();
|
||||||
smmu_init(0x4002B000);
|
smmu_init(tsec_ctxt->secmon_base);
|
||||||
// Enable SMMU
|
// Enable SMMU
|
||||||
if (!smmu_is_used())
|
if (!smmu_is_used())
|
||||||
smmu_enable();
|
smmu_enable();
|
||||||
@@ -169,7 +169,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
iram = page_alloc(0x30);
|
iram = page_alloc(0x30);
|
||||||
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
||||||
// PKG1.1 magic offset.
|
// PKG1.1 magic offset.
|
||||||
pkg11_magic_off = (u32 *)(iram + (0x7000 / 4));
|
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
|
||||||
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||||
|
|
||||||
// Exception vectors
|
// Exception vectors
|
||||||
@@ -177,7 +177,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Execute firmware.
|
// Execute firmware.
|
||||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||||
TSEC(TSEC_STATUS) = 0;
|
TSEC(TSEC_STATUS) = 0;
|
||||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||||
@@ -254,7 +254,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fetch result.
|
// Fetch result.
|
||||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
||||||
u32 buf[4];
|
u32 buf[4];
|
||||||
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
||||||
@@ -274,7 +274,7 @@ out_free:;
|
|||||||
|
|
||||||
out:;
|
out:;
|
||||||
|
|
||||||
//Disable clocks.
|
// Disable clocks.
|
||||||
clock_disable_kfuse();
|
clock_disable_kfuse();
|
||||||
clock_disable_sor1();
|
clock_disable_sor1();
|
||||||
clock_disable_sor0();
|
clock_disable_sor0();
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ typedef struct _tsec_ctxt_t
|
|||||||
void *fw;
|
void *fw;
|
||||||
u32 size;
|
u32 size;
|
||||||
void *pkg1;
|
void *pkg1;
|
||||||
|
u32 pkg11_off;
|
||||||
|
u32 secmon_base;
|
||||||
} tsec_ctxt_t;
|
} tsec_ctxt_t;
|
||||||
|
|
||||||
typedef struct _tsec_key_data_t
|
typedef struct _tsec_key_data_t
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 CTCaer
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -22,56 +22,101 @@
|
|||||||
#include "../../common/memory_map.h"
|
#include "../../common/memory_map.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#define BPMP_MMU_CACHE_LINE_SIZE 0x20
|
||||||
|
|
||||||
#define BPMP_CACHE_CONFIG 0x0
|
#define BPMP_CACHE_CONFIG 0x0
|
||||||
#define CFG_ENABLE (1 << 0)
|
#define CFG_ENABLE_CACHE (1 << 0)
|
||||||
|
#define CFG_ENABLE_SKEW_ASSOC (1 << 1)
|
||||||
|
#define CFG_DISABLE_RANDOM_ALLOC (1 << 2)
|
||||||
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
||||||
|
#define CFG_NEVER_ALLOCATE (1 << 6)
|
||||||
|
#define CFG_ENABLE_INTERRUPT (1 << 7)
|
||||||
|
#define CFG_MMU_TAG_MODE(x) (x << 8)
|
||||||
|
#define TAG_MODE_PARALLEL 0
|
||||||
|
#define TAG_MODE_TAG_FIRST 1
|
||||||
|
#define TAG_MODE_MMU_FIRST 2
|
||||||
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
||||||
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
||||||
|
#define CFG_ENABLE_HANG_DETECT (1 << 12)
|
||||||
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
||||||
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
||||||
|
#define CFG_TAG_CHK_CLR_ERR (1 << 15)
|
||||||
|
#define CFG_DISABLE_SAMELINE (1 << 16)
|
||||||
|
#define CFG_OBS_BUS_EN (1 << 31)
|
||||||
|
|
||||||
#define BPMP_CACHE_LOCK 0x4
|
#define BPMP_CACHE_LOCK 0x4
|
||||||
|
#define LOCK_LINE(x) (1 << x)
|
||||||
|
|
||||||
#define BPMP_CACHE_SIZE 0xC
|
#define BPMP_CACHE_SIZE 0xC
|
||||||
#define BPMP_CACHE_LFSR 0x10
|
#define BPMP_CACHE_LFSR 0x10
|
||||||
|
|
||||||
#define BPMP_CACHE_TAG_STATUS 0x14
|
#define BPMP_CACHE_TAG_STATUS 0x14
|
||||||
|
#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0)
|
||||||
|
#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0
|
||||||
|
|
||||||
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
||||||
|
#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0)
|
||||||
|
#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1)
|
||||||
|
|
||||||
#define BPMP_CACHE_MAINT_ADDR 0x20
|
#define BPMP_CACHE_MAINT_ADDR 0x20
|
||||||
#define BPMP_CACHE_MAINT_DATA 0x24
|
#define BPMP_CACHE_MAINT_DATA 0x24
|
||||||
|
|
||||||
#define BPMP_CACHE_MAINT_REQ 0x28
|
#define BPMP_CACHE_MAINT_REQ 0x28
|
||||||
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
||||||
|
|
||||||
#define BPMP_CACHE_INT_MASK 0x40
|
#define BPMP_CACHE_INT_MASK 0x40
|
||||||
#define BPMP_CACHE_INT_CLEAR 0x44
|
#define BPMP_CACHE_INT_CLEAR 0x44
|
||||||
#define INT_CLR_MAINT_DONE (1 << 0)
|
|
||||||
|
|
||||||
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||||
#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
|
|
||||||
#define BPMP_CACHE_INT_STATUS 0x4C
|
#define BPMP_CACHE_INT_STATUS 0x4C
|
||||||
|
#define INT_MAINT_DONE (1 << 0)
|
||||||
|
#define INT_MAINT_ERROR (1 << 1)
|
||||||
|
|
||||||
#define BPMP_CACHE_RB_CFG 0x80
|
#define BPMP_CACHE_RB_CFG 0x80
|
||||||
#define BPMP_CACHE_WB_CFG 0x84
|
#define BPMP_CACHE_WB_CFG 0x84
|
||||||
|
|
||||||
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
|
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
|
||||||
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
|
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
|
||||||
|
|
||||||
#define BPMP_CACHE_MMU_CFG 0xAC
|
#define BPMP_CACHE_MMU_CFG 0xAC
|
||||||
|
#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0)
|
||||||
#define MMU_CFG_SEQ_EN (1 << 1)
|
#define MMU_CFG_SEQ_EN (1 << 1)
|
||||||
#define MMU_CFG_TLB_EN (1 << 2)
|
#define MMU_CFG_TLB_EN (1 << 2)
|
||||||
|
#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3)
|
||||||
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
||||||
|
#define MMU_CFG_CLR_ABORT (1 << 5)
|
||||||
|
|
||||||
#define BPMP_CACHE_MMU_CMD 0xB0
|
#define BPMP_CACHE_MMU_CMD 0xB0
|
||||||
#define MMU_CMD_NOP 0
|
#define MMU_CMD_NOP 0
|
||||||
#define MMU_CMD_INIT 1
|
#define MMU_CMD_INIT 1
|
||||||
#define MMU_CMD_COPY_SHADOW 2
|
#define MMU_CMD_COPY_SHADOW 2
|
||||||
|
|
||||||
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
|
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
|
||||||
|
#define ABORT_STAT_UNIT_MASK 0x7
|
||||||
|
#define ABORT_STAT_UNIT_NONE 0
|
||||||
|
#define ABORT_STAT_UNIT_CACHE 1
|
||||||
|
#define ABORT_STAT_UNIT_SEQ 2
|
||||||
|
#define ABORT_STAT_UNIT_TLB 3
|
||||||
|
#define ABORT_STAT_UNIT_SEG 4
|
||||||
|
#define ABORT_STAT_UNIT_FALLBACK 5
|
||||||
|
#define ABORT_STAT_OVERLAP (1 << 3)
|
||||||
|
#define ABORT_STAT_ENTRY (0x1F << 4)
|
||||||
|
#define ABORT_STAT_TYPE_MASK (3 << 16)
|
||||||
|
#define ABORT_STAT_TYPE_EXE (0 << 16)
|
||||||
|
#define ABORT_STAT_TYPE_RD (1 << 16)
|
||||||
|
#define ABORT_STAT_TYPE_WR (2 << 16)
|
||||||
|
#define ABORT_STAT_SIZE (3 << 18)
|
||||||
|
#define ABORT_STAT_SEQ (1 << 20)
|
||||||
|
#define ABORT_STAT_PROT (1 << 21)
|
||||||
|
|
||||||
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
||||||
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
||||||
|
|
||||||
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
||||||
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
||||||
#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0
|
#define MMU_EN_CACHED (1 << 0)
|
||||||
|
#define MMU_EN_EXEC (1 << 1)
|
||||||
#define MMU_EN_CACHED (1 << 0)
|
#define MMU_EN_READ (1 << 2)
|
||||||
#define MMU_EN_EXEC (1 << 1)
|
#define MMU_EN_WRITE (1 << 3)
|
||||||
#define MMU_EN_READ (1 << 2)
|
|
||||||
#define MMU_EN_WRITE (1 << 3)
|
|
||||||
|
|
||||||
bpmp_mmu_entry_t mmu_entries[] =
|
bpmp_mmu_entry_t mmu_entries[] =
|
||||||
{
|
{
|
||||||
@@ -81,15 +126,15 @@ bpmp_mmu_entry_t mmu_entries[] =
|
|||||||
|
|
||||||
void bpmp_mmu_maintenance(u32 op, bool force)
|
void bpmp_mmu_maintenance(u32 op, bool force)
|
||||||
{
|
{
|
||||||
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
|
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE;
|
||||||
|
|
||||||
// This is a blocking operation.
|
// This is a blocking operation.
|
||||||
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
||||||
|
|
||||||
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE))
|
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE))
|
||||||
;
|
;
|
||||||
|
|
||||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
||||||
@@ -104,8 +149,8 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
|||||||
|
|
||||||
if (entry->enable)
|
if (entry->enable)
|
||||||
{
|
{
|
||||||
mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK;
|
mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE);
|
||||||
mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK;
|
mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE);
|
||||||
mmu_entry->attr = entry->attr;
|
mmu_entry->attr = entry->attr;
|
||||||
|
|
||||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
|
||||||
@@ -117,7 +162,7 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
|||||||
|
|
||||||
void bpmp_mmu_enable()
|
void bpmp_mmu_enable()
|
||||||
{
|
{
|
||||||
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)
|
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Init BPMP MMU.
|
// Init BPMP MMU.
|
||||||
@@ -136,7 +181,8 @@ void bpmp_mmu_enable()
|
|||||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
|
||||||
|
|
||||||
// Enable cache.
|
// Enable cache.
|
||||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR;
|
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH |
|
||||||
|
CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR;
|
||||||
|
|
||||||
// HW bug. Invalidate cache again.
|
// HW bug. Invalidate cache again.
|
||||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
|
||||||
@@ -144,7 +190,7 @@ void bpmp_mmu_enable()
|
|||||||
|
|
||||||
void bpmp_mmu_disable()
|
void bpmp_mmu_disable()
|
||||||
{
|
{
|
||||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Clean and invalidate cache.
|
// Clean and invalidate cache.
|
||||||
@@ -154,7 +200,10 @@ void bpmp_mmu_disable()
|
|||||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 pllc4_divn[] = {
|
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
|
||||||
|
// I2C host, DC/DSI/DISP. UART gives extra stress.
|
||||||
|
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
|
||||||
|
const u8 pll_divn[] = {
|
||||||
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
|
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
|
||||||
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
|
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
|
||||||
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
|
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
|
||||||
@@ -165,6 +214,28 @@ const u8 pllc4_divn[] = {
|
|||||||
|
|
||||||
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||||
|
|
||||||
|
void bpmp_clk_rate_get()
|
||||||
|
{
|
||||||
|
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
|
||||||
|
|
||||||
|
if (clk_src_is_pllp)
|
||||||
|
bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bpmp_clock_set = BPMP_CLK_HIGH_BOOST;
|
||||||
|
|
||||||
|
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
|
||||||
|
for (u32 i = 1; i < sizeof(pll_divn); i++)
|
||||||
|
{
|
||||||
|
if (pll_divn[i] == pll_divn_curr)
|
||||||
|
{
|
||||||
|
bpmp_clock_set = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bpmp_clk_rate_set(bpmp_freq_t fid)
|
void bpmp_clk_rate_set(bpmp_freq_t fid)
|
||||||
{
|
{
|
||||||
if (fid > (BPMP_CLK_MAX - 1))
|
if (fid > (BPMP_CLK_MAX - 1))
|
||||||
@@ -179,37 +250,26 @@ void bpmp_clk_rate_set(bpmp_freq_t fid)
|
|||||||
{
|
{
|
||||||
// Restore to PLLP source during PLLC4 configuration.
|
// Restore to PLLP source during PLLC4 configuration.
|
||||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||||
// Wait a bit for clock source change.
|
msleep(1); // Wait a bit for clock source change.
|
||||||
msleep(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET;
|
// Configure and enable PLLC.
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1.
|
clock_enable_pllc(pll_divn[fid]);
|
||||||
|
|
||||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK))
|
// Set SCLK / HCLK / PCLK.
|
||||||
;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div.
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // Get divider out of reset.
|
|
||||||
|
|
||||||
// Wait a bit for PLLC4 to stabilize.
|
|
||||||
msleep(10);
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4.
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003323; // PLLC4_OUT3.
|
|
||||||
|
|
||||||
bpmp_clock_set = fid;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
|
||||||
|
msleep(1); // Wait a bit for clock source change.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
|
||||||
|
|
||||||
// Wait a bit for clock source change.
|
// Disable PLLC to save power.
|
||||||
msleep(10);
|
clock_disable_pllc();
|
||||||
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3.
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;
|
|
||||||
bpmp_clock_set = BPMP_CLK_NORMAL;
|
|
||||||
}
|
}
|
||||||
|
bpmp_clock_set = fid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following functions halt BPMP to reduce power while sleeping.
|
// The following functions halt BPMP to reduce power while sleeping.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 CTCaer
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -21,14 +21,24 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define BPMP_MMU_MAINT_CLEAN_WAY 17
|
typedef enum
|
||||||
#define BPMP_MMU_MAINT_INVALID_WAY 18
|
{
|
||||||
#define BPMP_MMU_MAINT_CLN_INV_WAY 19
|
BPMP_MMU_MAINT_NOP = 0,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_PHY = 1,
|
||||||
|
BPMP_MMU_MAINT_INVALID_PHY = 2,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_LINE = 9,
|
||||||
|
BPMP_MMU_MAINT_INVALID_LINE = 10,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_WAY = 17,
|
||||||
|
BPMP_MMU_MAINT_INVALID_WAY = 18,
|
||||||
|
BPMP_MMU_MAINT_CLN_INV_WAY = 19
|
||||||
|
} bpmp_maintenance_t;
|
||||||
|
|
||||||
typedef struct _bpmp_mmu_entry_t
|
typedef struct _bpmp_mmu_entry_t
|
||||||
{
|
{
|
||||||
u32 min_addr;
|
u32 start_addr;
|
||||||
u32 max_addr;
|
u32 end_addr;
|
||||||
u32 attr;
|
u32 attr;
|
||||||
u32 enable;
|
u32 enable;
|
||||||
} bpmp_mmu_entry_t;
|
} bpmp_mmu_entry_t;
|
||||||
@@ -49,6 +59,7 @@ void bpmp_mmu_maintenance(u32 op, bool force);
|
|||||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
|
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
|
||||||
void bpmp_mmu_enable();
|
void bpmp_mmu_enable();
|
||||||
void bpmp_mmu_disable();
|
void bpmp_mmu_disable();
|
||||||
|
void bpmp_clk_rate_get();
|
||||||
void bpmp_clk_rate_set(bpmp_freq_t fid);
|
void bpmp_clk_rate_set(bpmp_freq_t fid);
|
||||||
void bpmp_usleep(u32 us);
|
void bpmp_usleep(u32 us);
|
||||||
void bpmp_msleep(u32 ms);
|
void bpmp_msleep(u32 ms);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,6 +20,17 @@
|
|||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CLOCK Peripherals:
|
||||||
|
* L 0 - 31
|
||||||
|
* H 32 - 63
|
||||||
|
* U 64 - 95
|
||||||
|
* V 96 - 127
|
||||||
|
* W 128 - 159
|
||||||
|
* X 160 - 191
|
||||||
|
* Y 192 - 223
|
||||||
|
*/
|
||||||
|
|
||||||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||||
|
|
||||||
static const clock_t _clock_uart[] = {
|
static const clock_t _clock_uart[] = {
|
||||||
@@ -29,7 +41,7 @@ static const clock_t _clock_uart[] = {
|
|||||||
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
||||||
};
|
};
|
||||||
|
|
||||||
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0 FM_DIV: 26.
|
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26.
|
||||||
static const clock_t _clock_i2c[] = {
|
static const clock_t _clock_i2c[] = {
|
||||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
|
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
|
||||||
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
|
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
|
||||||
@@ -77,6 +89,10 @@ static clock_t _clock_pwm = {
|
|||||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
|
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static clock_t _clock_sdmmc_legacy_tm = {
|
||||||
|
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66
|
||||||
|
};
|
||||||
|
|
||||||
void clock_enable(const clock_t *clk)
|
void clock_enable(const clock_t *clk)
|
||||||
{
|
{
|
||||||
// Put clock into reset.
|
// Put clock into reset.
|
||||||
@@ -112,6 +128,29 @@ void clock_enable_uart(u32 idx)
|
|||||||
clock_enable(&_clock_uart[idx]);
|
clock_enable(&_clock_uart[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clock_disable_uart(u32 idx)
|
||||||
|
{
|
||||||
|
clock_disable(&_clock_uart[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UART_SRC_CLK_DIV_EN (1 << 24)
|
||||||
|
|
||||||
|
int clock_uart_use_src_div(u32 idx, u32 baud)
|
||||||
|
{
|
||||||
|
u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000;
|
||||||
|
|
||||||
|
if (baud == 1000000)
|
||||||
|
CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLOCK(_clock_uart[idx].source) = clk_src_div | 2;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void clock_enable_i2c(u32 idx)
|
void clock_enable_i2c(u32 idx)
|
||||||
{
|
{
|
||||||
clock_enable(&_clock_i2c[idx]);
|
clock_enable(&_clock_i2c[idx]);
|
||||||
@@ -228,6 +267,51 @@ void clock_disable_pwm()
|
|||||||
clock_disable(&_clock_pwm);
|
clock_disable(&_clock_pwm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clock_enable_pllc(u32 divn)
|
||||||
|
{
|
||||||
|
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
|
||||||
|
|
||||||
|
// Check if already enabled and configured.
|
||||||
|
if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Take PLLC out of reset and set basic misc parameters.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) =
|
||||||
|
((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM.
|
||||||
|
|
||||||
|
// Disable PLL and IDDQ in case they are on.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;
|
||||||
|
usleep(10);
|
||||||
|
|
||||||
|
// Set PLLC dividers.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1.
|
||||||
|
|
||||||
|
// Enable PLLC and wait for Phase and Frequency lock.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE;
|
||||||
|
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK))
|
||||||
|
;
|
||||||
|
|
||||||
|
// Disable PLLC_OUT1, enable reset and set div to 1.5.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8);
|
||||||
|
|
||||||
|
// Enable PLLC_OUT1 and bring it out of reset.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
|
||||||
|
msleep(1); // Wait a bit for PLL to stabilize.
|
||||||
|
}
|
||||||
|
|
||||||
|
void clock_disable_pllc()
|
||||||
|
{
|
||||||
|
// Disable PLLC and PLLC_OUT1.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET;
|
||||||
|
usleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
#define L_SWR_SDMMC1_RST (1 << 14)
|
#define L_SWR_SDMMC1_RST (1 << 14)
|
||||||
#define L_SWR_SDMMC2_RST (1 << 9)
|
#define L_SWR_SDMMC2_RST (1 << 9)
|
||||||
#define L_SWR_SDMMC4_RST (1 << 15)
|
#define L_SWR_SDMMC4_RST (1 << 15)
|
||||||
@@ -366,56 +450,78 @@ static void _clock_sdmmc_clear_enable(u32 id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 _clock_sdmmc_table[8] = { 0 };
|
static void _clock_sdmmc_config_legacy_tm()
|
||||||
|
{
|
||||||
|
clock_t *clk = &_clock_sdmmc_legacy_tm;
|
||||||
|
if (!(CLOCK(clk->enable) & (1 << clk->index)))
|
||||||
|
clock_enable(clk);
|
||||||
|
}
|
||||||
|
|
||||||
#define PLLP_OUT0 0x0
|
typedef struct _clock_sdmmc_t
|
||||||
static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val)
|
{
|
||||||
|
u32 clock;
|
||||||
|
u32 real_clock;
|
||||||
|
} clock_sdmmc_t;
|
||||||
|
|
||||||
|
static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 };
|
||||||
|
|
||||||
|
#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0
|
||||||
|
#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3
|
||||||
|
#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1
|
||||||
|
|
||||||
|
static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val)
|
||||||
{
|
{
|
||||||
u32 divisor = 0;
|
u32 divisor = 0;
|
||||||
u32 source = PLLP_OUT0;
|
u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0;
|
||||||
|
|
||||||
|
if (id > SDMMC_4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// Get IO clock divisor.
|
// Get IO clock divisor.
|
||||||
switch (val)
|
switch (val)
|
||||||
{
|
{
|
||||||
case 25000:
|
case 25000:
|
||||||
*pout = 24728;
|
*pclock = 24728;
|
||||||
divisor = 31; // 16.5 div.
|
divisor = 31; // 16.5 div.
|
||||||
break;
|
break;
|
||||||
case 26000:
|
case 26000:
|
||||||
*pout = 25500;
|
*pclock = 25500;
|
||||||
divisor = 30; // 16 div.
|
divisor = 30; // 16 div.
|
||||||
break;
|
break;
|
||||||
case 40800:
|
case 40800:
|
||||||
*pout = 40800;
|
*pclock = 40800;
|
||||||
divisor = 18; // 10 div.
|
divisor = 18; // 10 div.
|
||||||
break;
|
break;
|
||||||
case 50000:
|
case 50000:
|
||||||
*pout = 48000;
|
*pclock = 48000;
|
||||||
divisor = 15; // 8.5 div.
|
divisor = 15; // 8.5 div.
|
||||||
break;
|
break;
|
||||||
case 52000:
|
case 52000:
|
||||||
*pout = 51000;
|
*pclock = 51000;
|
||||||
divisor = 14; // 8 div.
|
divisor = 14; // 8 div.
|
||||||
break;
|
break;
|
||||||
case 100000:
|
case 100000:
|
||||||
*pout = 90667;
|
*pclock = 90667;
|
||||||
divisor = 7; // 4.5 div.
|
divisor = 7; // 4.5 div.
|
||||||
break;
|
break;
|
||||||
case 200000:
|
case 164000:
|
||||||
*pout = 163200;
|
*pclock = 163200;
|
||||||
divisor = 3; // 2.5 div.
|
divisor = 3; // 2.5 div.
|
||||||
break;
|
break;
|
||||||
case 208000:
|
case 200000:
|
||||||
*pout = 204000;
|
*pclock = 204000;
|
||||||
divisor = 2; // 2 div.
|
divisor = 2; // 2 div.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*pout = 24728;
|
*pclock = 24728;
|
||||||
divisor = 31; // 16.5 div.
|
divisor = 31; // 16.5 div.
|
||||||
}
|
}
|
||||||
|
|
||||||
_clock_sdmmc_table[2 * id] = val;
|
_clock_sdmmc_table[id].clock = val;
|
||||||
_clock_sdmmc_table[2 * id + 1] = *pout;
|
_clock_sdmmc_table[id].real_clock = *pclock;
|
||||||
|
|
||||||
|
// Set SDMMC legacy timeout clock.
|
||||||
|
_clock_sdmmc_config_legacy_tm();
|
||||||
|
|
||||||
// Set SDMMC clock.
|
// Set SDMMC clock.
|
||||||
switch (id)
|
switch (id)
|
||||||
@@ -437,70 +543,75 @@ static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val)
|
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val)
|
||||||
{
|
{
|
||||||
if (_clock_sdmmc_table[2 * id] == val)
|
if (_clock_sdmmc_table[id].clock == val)
|
||||||
{
|
{
|
||||||
*pout = _clock_sdmmc_table[2 * id + 1];
|
*pclock = _clock_sdmmc_table[id].real_clock;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int is_enabled = _clock_sdmmc_is_enabled(id);
|
int is_enabled = _clock_sdmmc_is_enabled(id);
|
||||||
if (is_enabled)
|
if (is_enabled)
|
||||||
_clock_sdmmc_clear_enable(id);
|
_clock_sdmmc_clear_enable(id);
|
||||||
_clock_sdmmc_config_clock_host(pout, id, val);
|
_clock_sdmmc_config_clock_host(pclock, id, val);
|
||||||
if (is_enabled)
|
if (is_enabled)
|
||||||
_clock_sdmmc_set_enable(id);
|
_clock_sdmmc_set_enable(id);
|
||||||
_clock_sdmmc_is_reset(id);
|
_clock_sdmmc_is_reset(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type)
|
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)
|
||||||
{
|
{
|
||||||
// Get Card clock divisor.
|
// Get Card clock divisor.
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 0:
|
case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz.
|
||||||
*pout = 26000;
|
*pclock = 26000;
|
||||||
*pdivisor = 66;
|
*pdivisor = 66;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case SDHCI_TIMING_MMC_LS26:
|
||||||
*pout = 26000;
|
*pclock = 26000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SDHCI_TIMING_MMC_HS52:
|
||||||
*pout = 52000;
|
*pclock = 52000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case SDHCI_TIMING_MMC_HS200:
|
||||||
case 4:
|
case SDHCI_TIMING_MMC_HS400:
|
||||||
case 11:
|
case SDHCI_TIMING_UHS_SDR104:
|
||||||
*pout = 200000;
|
*pclock = 200000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz.
|
||||||
*pout = 25000;
|
*pclock = 25000;
|
||||||
*pdivisor = 64;
|
*pdivisor = 64;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case SDHCI_TIMING_SD_DS12:
|
||||||
case 8:
|
case SDHCI_TIMING_UHS_SDR12:
|
||||||
*pout = 25000;
|
*pclock = 25000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case SDHCI_TIMING_SD_HS25:
|
||||||
*pout = 50000;
|
case SDHCI_TIMING_UHS_SDR25:
|
||||||
|
*pclock = 50000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 10:
|
case SDHCI_TIMING_UHS_SDR50:
|
||||||
*pout = 100000;
|
*pclock = 100000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 13:
|
case SDHCI_TIMING_UHS_SDR82:
|
||||||
*pout = 40800;
|
*pclock = 164000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 14:
|
case SDHCI_TIMING_UHS_DDR50:
|
||||||
*pout = 200000;
|
*pclock = 40800;
|
||||||
|
*pdivisor = 1;
|
||||||
|
break;
|
||||||
|
case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz.
|
||||||
|
*pclock = 200000;
|
||||||
*pdivisor = 2;
|
*pdivisor = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -513,15 +624,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id)
|
|||||||
|
|
||||||
void clock_sdmmc_enable(u32 id, u32 val)
|
void clock_sdmmc_enable(u32 id, u32 val)
|
||||||
{
|
{
|
||||||
u32 div = 0;
|
u32 clock = 0;
|
||||||
|
|
||||||
if (_clock_sdmmc_is_enabled(id))
|
if (_clock_sdmmc_is_enabled(id))
|
||||||
_clock_sdmmc_clear_enable(id);
|
_clock_sdmmc_clear_enable(id);
|
||||||
_clock_sdmmc_set_reset(id);
|
_clock_sdmmc_set_reset(id);
|
||||||
_clock_sdmmc_config_clock_host(&div, id, val);
|
_clock_sdmmc_config_clock_host(&clock, id, val);
|
||||||
_clock_sdmmc_set_enable(id);
|
_clock_sdmmc_set_enable(id);
|
||||||
_clock_sdmmc_is_reset(id);
|
_clock_sdmmc_is_reset(id);
|
||||||
usleep((100000 + div - 1) / div);
|
usleep((100000 + clock - 1) / clock);
|
||||||
_clock_sdmmc_clear_reset(id);
|
_clock_sdmmc_clear_reset(id);
|
||||||
_clock_sdmmc_is_reset(id);
|
_clock_sdmmc_is_reset(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -35,11 +36,19 @@
|
|||||||
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
|
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
|
||||||
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
|
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
|
||||||
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
|
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC_OUT 0x84
|
||||||
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
|
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C
|
||||||
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
|
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
|
||||||
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
|
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
|
||||||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||||
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC
|
||||||
|
#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC
|
||||||
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
||||||
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
|
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
|
||||||
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
|
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
|
||||||
@@ -49,6 +58,7 @@
|
|||||||
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
|
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
||||||
@@ -67,6 +77,7 @@
|
|||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
||||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||||
@@ -101,24 +112,32 @@
|
|||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430
|
||||||
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
|
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
|
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
||||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
||||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
|
||||||
|
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480
|
||||||
|
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484
|
||||||
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
|
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
|
||||||
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
|
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
|
||||||
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
|
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
|
||||||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||||
|
#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||||
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
||||||
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
|
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
|
||||||
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
|
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
|
||||||
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
|
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
|
||||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
||||||
@@ -127,16 +146,27 @@
|
|||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC
|
||||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
||||||
|
|
||||||
#define CLK_NO_SOURCE 0x0
|
#define CLK_NO_SOURCE 0x0
|
||||||
|
|
||||||
/*! PLL control and status bits */
|
/*! PLL control and status bits */
|
||||||
#define PLL_BASE_ENABLE (1 << 30)
|
#define PLLCX_BASE_ENABLE (1 << 30)
|
||||||
|
#define PLLCX_BASE_REF_DIS (1 << 29)
|
||||||
|
#define PLLCX_BASE_LOCK (1 << 27)
|
||||||
|
|
||||||
|
#define PLLA_BASE_IDDQ (1 << 25)
|
||||||
|
#define PLLA_OUT0_CLKEN (1 << 1)
|
||||||
|
#define PLLA_OUT0_RSTN_CLR (1 << 0)
|
||||||
|
|
||||||
|
#define PLLC_MISC_RESET (1 << 30)
|
||||||
|
#define PLLC_MISC1_IDDQ (1 << 27)
|
||||||
|
#define PLLC_OUT1_CLKEN (1 << 1)
|
||||||
|
#define PLLC_OUT1_RSTN_CLR (1 << 0)
|
||||||
|
|
||||||
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
||||||
#define PLLC4_BASE_LOCK (1 << 27)
|
|
||||||
#define PLLC4_BASE_IDDQ (1 << 18)
|
#define PLLC4_BASE_IDDQ (1 << 18)
|
||||||
#define PLLC4_OUT3_CLKEN (1 << 1)
|
#define PLLC4_OUT3_CLKEN (1 << 1)
|
||||||
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
||||||
@@ -159,6 +189,8 @@ void clock_disable(const clock_t *clk);
|
|||||||
/*! Clock control for specific hardware portions. */
|
/*! Clock control for specific hardware portions. */
|
||||||
void clock_enable_fuse(bool enable);
|
void clock_enable_fuse(bool enable);
|
||||||
void clock_enable_uart(u32 idx);
|
void clock_enable_uart(u32 idx);
|
||||||
|
void clock_disable_uart(u32 idx);
|
||||||
|
int clock_uart_use_src_div(u32 idx, u32 baud);
|
||||||
void clock_enable_i2c(u32 idx);
|
void clock_enable_i2c(u32 idx);
|
||||||
void clock_disable_i2c(u32 idx);
|
void clock_disable_i2c(u32 idx);
|
||||||
void clock_enable_se();
|
void clock_enable_se();
|
||||||
@@ -181,9 +213,11 @@ void clock_enable_coresight();
|
|||||||
void clock_disable_coresight();
|
void clock_disable_coresight();
|
||||||
void clock_enable_pwm();
|
void clock_enable_pwm();
|
||||||
void clock_disable_pwm();
|
void clock_disable_pwm();
|
||||||
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val);
|
void clock_enable_pllc(u32 divn);
|
||||||
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type);
|
void clock_disable_pllc();
|
||||||
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
|
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val);
|
||||||
|
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type);
|
||||||
|
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
|
||||||
void clock_sdmmc_enable(u32 id, u32 val);
|
void clock_sdmmc_enable(u32 id, u32 val);
|
||||||
void clock_sdmmc_disable(u32 id);
|
void clock_sdmmc_disable(u32 id);
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
#define FUSE_PRIVATE_KEY3 0x1B0
|
#define FUSE_PRIVATE_KEY3 0x1B0
|
||||||
#define FUSE_PRIVATE_KEY4 0x1B4
|
#define FUSE_PRIVATE_KEY4 0x1B4
|
||||||
#define FUSE_RESERVED_SW 0x1C0
|
#define FUSE_RESERVED_SW 0x1C0
|
||||||
|
#define FUSE_USB_CALIB 0x1F0
|
||||||
#define FUSE_SKU_DIRECT_CONFIG 0x1F4
|
#define FUSE_SKU_DIRECT_CONFIG 0x1F4
|
||||||
#define FUSE_OPT_VENDOR_CODE 0x200
|
#define FUSE_OPT_VENDOR_CODE 0x200
|
||||||
#define FUSE_OPT_FAB_CODE 0x204
|
#define FUSE_OPT_FAB_CODE 0x204
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
#define FUSE_OPT_X_COORDINATE 0x214
|
#define FUSE_OPT_X_COORDINATE 0x214
|
||||||
#define FUSE_OPT_Y_COORDINATE 0x218
|
#define FUSE_OPT_Y_COORDINATE 0x218
|
||||||
#define FUSE_GPU_IDDQ_CALIB 0x228
|
#define FUSE_GPU_IDDQ_CALIB 0x228
|
||||||
|
#define FUSE_USB_CALIB_EXT 0x350
|
||||||
|
|
||||||
/*! Fuse commands. */
|
/*! Fuse commands. */
|
||||||
#define FUSE_READ 0x1
|
#define FUSE_READ 0x1
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -14,81 +15,146 @@
|
|||||||
* 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 "../soc/gpio.h"
|
#include "gpio.h"
|
||||||
#include "../soc/t210.h"
|
#include "irq.h"
|
||||||
|
#include "t210.h"
|
||||||
|
|
||||||
static const u16 _gpio_cnf[31] = {
|
#define GPIO_BANK_IDX(port) (port >> 2)
|
||||||
0x000, 0x004, 0x008, 0x00C,
|
|
||||||
0x100, 0x104, 0x108, 0x10C,
|
|
||||||
0x200, 0x204, 0x208, 0x20C,
|
|
||||||
0x300, 0x304, 0x308, 0x30C,
|
|
||||||
0x400, 0x404, 0x408, 0x40C,
|
|
||||||
0x500, 0x504, 0x508, 0x50C,
|
|
||||||
0x600, 0x604, 0x608, 0x60C,
|
|
||||||
0x700, 0x704, 0x708
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u16 _gpio_oe[31] = {
|
#define GPIO_CNF_OFFSET(port) (0x00 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x010, 0x014, 0x018, 0x01C,
|
#define GPIO_OE_OFFSET(port) (0x10 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x110, 0x114, 0x118, 0x11C,
|
#define GPIO_OUT_OFFSET(port) (0x20 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x210, 0x214, 0x218, 0x21C,
|
#define GPIO_IN_OFFSET(port) (0x30 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x310, 0x314, 0x318, 0x31C,
|
#define GPIO_INT_STA_OFFSET(port) (0x40 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x410, 0x414, 0x418, 0x41C,
|
#define GPIO_INT_ENB_OFFSET(port) (0x50 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x510, 0x514, 0x518, 0x51C,
|
#define GPIO_INT_LVL_OFFSET(port) (0x60 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x610, 0x614, 0x618, 0x61C,
|
#define GPIO_INT_CLR_OFFSET(port) (0x70 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x710, 0x714, 0x718
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u16 _gpio_out[31] = {
|
#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x020, 0x024, 0x028, 0x02C,
|
#define GPIO_OE_MASKED_OFFSET(port) (0x90 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x120, 0x124, 0x128, 0x12C,
|
#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x220, 0x224, 0x228, 0x22C,
|
#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x320, 0x324, 0x328, 0x32C,
|
#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x420, 0x424, 0x428, 0x42C,
|
#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2))
|
||||||
0x520, 0x524, 0x528, 0x52C,
|
|
||||||
0x620, 0x624, 0x628, 0x62C,
|
|
||||||
0x720, 0x724, 0x728
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u16 _gpio_in[31] = {
|
static u8 gpio_bank_irq_ids[8] = {
|
||||||
0x030, 0x034, 0x038, 0x03C,
|
IRQ_GPIO1, IRQ_GPIO2, IRQ_GPIO3, IRQ_GPIO4,
|
||||||
0x130, 0x134, 0x138, 0x13C,
|
IRQ_GPIO5, IRQ_GPIO6, IRQ_GPIO7, IRQ_GPIO8
|
||||||
0x230, 0x234, 0x238, 0x23C,
|
|
||||||
0x330, 0x334, 0x338, 0x33C,
|
|
||||||
0x430, 0x434, 0x438, 0x43C,
|
|
||||||
0x530, 0x534, 0x538, 0x53C,
|
|
||||||
0x630, 0x634, 0x638, 0x63C,
|
|
||||||
0x730, 0x734, 0x738
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gpio_config(u32 port, u32 pins, int mode)
|
void gpio_config(u32 port, u32 pins, int mode)
|
||||||
{
|
{
|
||||||
|
u32 offset = GPIO_CNF_OFFSET(port);
|
||||||
|
|
||||||
if (mode)
|
if (mode)
|
||||||
GPIO(_gpio_cnf[port]) |= pins;
|
GPIO(offset) |= pins;
|
||||||
else
|
else
|
||||||
GPIO(_gpio_cnf[port]) &= ~pins;
|
GPIO(offset) &= ~pins;
|
||||||
(void)GPIO(_gpio_cnf[port]);
|
|
||||||
|
(void)GPIO(offset); // Commit the write.
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_output_enable(u32 port, u32 pins, int enable)
|
void gpio_output_enable(u32 port, u32 pins, int enable)
|
||||||
{
|
{
|
||||||
|
u32 port_offset = GPIO_OE_OFFSET(port);
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
GPIO(_gpio_oe[port]) |= pins;
|
GPIO(port_offset) |= pins;
|
||||||
else
|
else
|
||||||
GPIO(_gpio_oe[port]) &= ~pins;
|
GPIO(port_offset) &= ~pins;
|
||||||
(void)GPIO(_gpio_oe[port]);
|
|
||||||
|
(void)GPIO(port_offset); // Commit the write.
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_write(u32 port, u32 pins, int high)
|
void gpio_write(u32 port, u32 pins, int high)
|
||||||
{
|
{
|
||||||
|
u32 port_offset = GPIO_OUT_OFFSET(port);
|
||||||
|
|
||||||
if (high)
|
if (high)
|
||||||
GPIO(_gpio_out[port]) |= pins;
|
GPIO(port_offset) |= pins;
|
||||||
else
|
else
|
||||||
GPIO(_gpio_out[port]) &= ~pins;
|
GPIO(port_offset) &= ~pins;
|
||||||
(void)GPIO(_gpio_out[port]);
|
|
||||||
|
(void)GPIO(port_offset); // Commit the write.
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_read(u32 port, u32 pins)
|
int gpio_read(u32 port, u32 pins)
|
||||||
{
|
{
|
||||||
return (GPIO(_gpio_in[port]) & pins) ? 1 : 0;
|
u32 port_offset = GPIO_IN_OFFSET(port);
|
||||||
|
|
||||||
|
return (GPIO(port_offset) & pins) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _gpio_interrupt_clear(u32 port, u32 pins)
|
||||||
|
{
|
||||||
|
u32 port_offset = GPIO_INT_CLR_OFFSET(port);
|
||||||
|
|
||||||
|
GPIO(port_offset) |= pins;
|
||||||
|
|
||||||
|
(void)GPIO(port_offset); // Commit the write.
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_interrupt_status(u32 port, u32 pins)
|
||||||
|
{
|
||||||
|
u32 port_offset = GPIO_INT_STA_OFFSET(port);
|
||||||
|
u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins;
|
||||||
|
|
||||||
|
int status = ((GPIO(port_offset) & pins) && enabled) ? 1 : 0;
|
||||||
|
|
||||||
|
// Clear the interrupt status.
|
||||||
|
if (status)
|
||||||
|
_gpio_interrupt_clear(port, pins);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_interrupt_enable(u32 port, u32 pins, int enable)
|
||||||
|
{
|
||||||
|
u32 port_offset = GPIO_INT_ENB_OFFSET(port);
|
||||||
|
|
||||||
|
// Clear any possible stray interrupt.
|
||||||
|
_gpio_interrupt_clear(port, pins);
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
GPIO(port_offset) |= pins;
|
||||||
|
else
|
||||||
|
GPIO(port_offset) &= ~pins;
|
||||||
|
|
||||||
|
(void)GPIO(port_offset); // Commit the write.
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta)
|
||||||
|
{
|
||||||
|
u32 port_offset = GPIO_INT_LVL_OFFSET(port);
|
||||||
|
|
||||||
|
u32 val = GPIO(port_offset);
|
||||||
|
|
||||||
|
if (high)
|
||||||
|
val |= pins;
|
||||||
|
else
|
||||||
|
val &= ~pins;
|
||||||
|
|
||||||
|
if (edge)
|
||||||
|
val |= pins << 8;
|
||||||
|
else
|
||||||
|
val &= ~(pins << 8);
|
||||||
|
|
||||||
|
if (delta)
|
||||||
|
val |= pins << 16;
|
||||||
|
else
|
||||||
|
val &= ~(pins << 16);
|
||||||
|
|
||||||
|
GPIO(port_offset) = val;
|
||||||
|
|
||||||
|
(void)GPIO(port_offset); // Commit the write.
|
||||||
|
|
||||||
|
// Clear any possible stray interrupt.
|
||||||
|
_gpio_interrupt_clear(port, pins);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 gpio_get_bank_irq_id(u32 port)
|
||||||
|
{
|
||||||
|
u32 bank_idx = GPIO_BANK_IDX(port);
|
||||||
|
|
||||||
|
return gpio_bank_irq_ids[bank_idx];
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -21,10 +22,23 @@
|
|||||||
|
|
||||||
#define GPIO_MODE_SPIO 0
|
#define GPIO_MODE_SPIO 0
|
||||||
#define GPIO_MODE_GPIO 1
|
#define GPIO_MODE_GPIO 1
|
||||||
|
|
||||||
#define GPIO_OUTPUT_DISABLE 0
|
#define GPIO_OUTPUT_DISABLE 0
|
||||||
#define GPIO_OUTPUT_ENABLE 1
|
#define GPIO_OUTPUT_ENABLE 1
|
||||||
|
|
||||||
|
#define GPIO_IRQ_DISABLE 0
|
||||||
|
#define GPIO_IRQ_ENABLE 1
|
||||||
|
|
||||||
#define GPIO_LOW 0
|
#define GPIO_LOW 0
|
||||||
#define GPIO_HIGH 1
|
#define GPIO_HIGH 1
|
||||||
|
#define GPIO_FALLING 0
|
||||||
|
#define GPIO_RISING 1
|
||||||
|
|
||||||
|
#define GPIO_LEVEL 0
|
||||||
|
#define GPIO_EDGE 1
|
||||||
|
|
||||||
|
#define GPIO_CONFIGURED_EDGE 0
|
||||||
|
#define GPIO_ANY_EDGE_CHANGE 1
|
||||||
|
|
||||||
/*! GPIO pins (0-7 for each port). */
|
/*! GPIO pins (0-7 for each port). */
|
||||||
#define GPIO_PIN_0 (1 << 0)
|
#define GPIO_PIN_0 (1 << 0)
|
||||||
@@ -72,6 +86,10 @@
|
|||||||
void gpio_config(u32 port, u32 pins, int mode);
|
void gpio_config(u32 port, u32 pins, int mode);
|
||||||
void gpio_output_enable(u32 port, u32 pins, int enable);
|
void gpio_output_enable(u32 port, u32 pins, int enable);
|
||||||
void gpio_write(u32 port, u32 pins, int high);
|
void gpio_write(u32 port, u32 pins, int high);
|
||||||
int gpio_read(u32 port, u32 pins);
|
int gpio_read(u32 port, u32 pins);
|
||||||
|
int gpio_interrupt_status(u32 port, u32 pins);
|
||||||
|
void gpio_interrupt_enable(u32 port, u32 pins, int enable);
|
||||||
|
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta);
|
||||||
|
u32 gpio_get_bank_irq_id(u32 port);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2019 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "pinmux.h"
|
#include "pinmux.h"
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
#include "t210.h"
|
#include "t210.h"
|
||||||
|
#include "uart.h"
|
||||||
#include "../gfx/di.h"
|
#include "../gfx/di.h"
|
||||||
#include "../mem/mc.h"
|
#include "../mem/mc.h"
|
||||||
#include "../mem/minerva.h"
|
#include "../mem/minerva.h"
|
||||||
@@ -34,11 +35,12 @@
|
|||||||
#include "../power/max7762x.h"
|
#include "../power/max7762x.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
extern sdmmc_t sd_sdmmc;
|
|
||||||
extern boot_cfg_t b_cfg;
|
extern boot_cfg_t b_cfg;
|
||||||
|
extern volatile nyx_storage_t *nyx_str;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CLK_OSC - 38.4 MHz crystal.
|
* CLK_OSC - 38.4 MHz crystal.
|
||||||
@@ -78,8 +80,8 @@ void _config_gpios()
|
|||||||
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
||||||
|
|
||||||
// Set Joy-Con IsAttached direction.
|
// Set Joy-Con IsAttached direction.
|
||||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
|
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
|
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
|
|
||||||
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
|
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
|
||||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
||||||
@@ -100,7 +102,7 @@ void _config_gpios()
|
|||||||
|
|
||||||
pinmux_config_i2c(I2C_1);
|
pinmux_config_i2c(I2C_1);
|
||||||
pinmux_config_i2c(I2C_5);
|
pinmux_config_i2c(I2C_5);
|
||||||
pinmux_config_uart(0);
|
pinmux_config_uart(UART_A);
|
||||||
|
|
||||||
// Configure volume up/down as inputs.
|
// Configure volume up/down as inputs.
|
||||||
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
|
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||||
@@ -109,7 +111,7 @@ void _config_gpios()
|
|||||||
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
|
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
|
||||||
|
|
||||||
// Configure HOME as inputs.
|
// Configure HOME as inputs.
|
||||||
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE;
|
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
|
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ void _mbist_workaround()
|
|||||||
// Enable specific clocks and disable all others.
|
// Enable specific clocks and disable all others.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
|
||||||
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON.
|
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USBD ON.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
|
||||||
@@ -184,6 +186,9 @@ void _mbist_workaround()
|
|||||||
|
|
||||||
void _config_se_brom()
|
void _config_se_brom()
|
||||||
{
|
{
|
||||||
|
// Enable fuse clock.
|
||||||
|
clock_enable_fuse(true);
|
||||||
|
|
||||||
// Skip SBK/SSK if sept was run.
|
// Skip SBK/SSK if sept was run.
|
||||||
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
|
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
|
||||||
{
|
{
|
||||||
@@ -217,10 +222,19 @@ void _config_se_brom()
|
|||||||
|
|
||||||
void _config_regulators()
|
void _config_regulators()
|
||||||
{
|
{
|
||||||
|
// Disable low battery shutdown monitor.
|
||||||
|
max77620_low_battery_monitor_config(false);
|
||||||
|
|
||||||
|
// Disable SDMMC1 IO power.
|
||||||
|
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||||
|
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||||
|
sd_power_cycle_time_start = get_tmr_ms();
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
|
||||||
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
|
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
|
||||||
|
|
||||||
|
// Configure all Flexible Power Sequencers.
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
|
||||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
|
||||||
@@ -236,10 +250,10 @@ void _config_regulators()
|
|||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
|
||||||
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
|
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
|
||||||
|
|
||||||
// Set vdd_core voltage to 1.125V
|
// Set vdd_core voltage to 1.125V.
|
||||||
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||||
|
|
||||||
// Fix CPU/GPU after a Linux warmboot.
|
// Fix CPU/GPU after a L4T warmboot.
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
||||||
|
|
||||||
@@ -256,9 +270,6 @@ void _config_regulators()
|
|||||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||||
|
|
||||||
// Enable low battery shutdown monitor for < 2800mV.
|
|
||||||
max77620_low_battery_monitor_config();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_hw()
|
void config_hw()
|
||||||
@@ -284,6 +295,11 @@ void config_hw()
|
|||||||
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
|
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
|
||||||
_config_gpios();
|
_config_gpios();
|
||||||
|
|
||||||
|
#ifdef DEBUG_UART_PORT
|
||||||
|
clock_enable_uart(DEBUG_UART_PORT);
|
||||||
|
uart_init(DEBUG_UART_PORT, 115200);
|
||||||
|
#endif
|
||||||
|
|
||||||
clock_enable_cl_dvfs();
|
clock_enable_cl_dvfs();
|
||||||
|
|
||||||
clock_enable_i2c(I2C_1);
|
clock_enable_i2c(I2C_1);
|
||||||
@@ -303,7 +319,9 @@ void config_hw()
|
|||||||
sdram_init();
|
sdram_init();
|
||||||
|
|
||||||
bpmp_mmu_enable();
|
bpmp_mmu_enable();
|
||||||
mc_enable_ahb_redirect();
|
|
||||||
|
// Clear flags from PMC_SCRATCH0
|
||||||
|
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
||||||
@@ -312,10 +330,11 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
|||||||
bpmp_mmu_disable();
|
bpmp_mmu_disable();
|
||||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||||
minerva_change_freq(FREQ_204);
|
minerva_change_freq(FREQ_204);
|
||||||
|
nyx_str->mtc_cfg.init_done = 0;
|
||||||
|
|
||||||
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
|
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||||
|
|
||||||
if (extra_reconfig)
|
if (extra_reconfig)
|
||||||
{
|
{
|
||||||
@@ -338,7 +357,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
|||||||
if (magic == 0xBAADF00D)
|
if (magic == 0xBAADF00D)
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
||||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
|
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0);
|
||||||
clock_disable_cl_dvfs();
|
clock_disable_cl_dvfs();
|
||||||
|
|
||||||
msleep(200);
|
msleep(200);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
static u32 i2c_addrs[] = {
|
static const u32 i2c_addrs[] = {
|
||||||
0x7000C000, 0x7000C400, 0x7000C500,
|
0x7000C000, 0x7000C400, 0x7000C500,
|
||||||
0x7000C700, 0x7000D000, 0x7000D100
|
0x7000C700, 0x7000D000, 0x7000D100
|
||||||
};
|
};
|
||||||
@@ -37,21 +38,39 @@ static void _i2c_wait(vu32 *base)
|
|||||||
|
|
||||||
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
||||||
{
|
{
|
||||||
if (size > 4)
|
if (size > 8)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
u32 tmp = 0;
|
u32 tmp = 0;
|
||||||
memcpy(&tmp, buf, size);
|
|
||||||
|
|
||||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
|
||||||
|
if (size > 4)
|
||||||
|
{
|
||||||
|
memcpy(&tmp, buf, 4);
|
||||||
|
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||||
|
tmp = 0;
|
||||||
|
memcpy(&tmp, buf + 4, size - 4);
|
||||||
|
base[I2C_CMD_DATA2] = tmp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&tmp, buf, size);
|
||||||
|
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||||
|
}
|
||||||
|
|
||||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
||||||
_i2c_wait(base); //Kick transaction.
|
_i2c_wait(base); //Kick transaction.
|
||||||
|
|
||||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||||
|
|
||||||
|
u32 timeout = get_tmr_ms() + 1500;
|
||||||
while (base[I2C_STATUS] & 0x100)
|
while (base[I2C_STATUS] & 0x100)
|
||||||
;
|
{
|
||||||
|
if (get_tmr_ms() > timeout)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (base[I2C_STATUS] << 28)
|
if (base[I2C_STATUS] << 28)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -70,8 +89,13 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
|||||||
_i2c_wait(base); // Kick transaction.
|
_i2c_wait(base); // Kick transaction.
|
||||||
|
|
||||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||||
|
|
||||||
|
u32 timeout = get_tmr_ms() + 1500;
|
||||||
while (base[I2C_STATUS] & 0x100)
|
while (base[I2C_STATUS] & 0x100)
|
||||||
;
|
{
|
||||||
|
if (get_tmr_ms() > timeout)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (base[I2C_STATUS] << 28)
|
if (base[I2C_STATUS] << 28)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,7 +136,7 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
|||||||
{
|
{
|
||||||
u8 tmp[4];
|
u8 tmp[4];
|
||||||
|
|
||||||
if (size > 3)
|
if (size > 7)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
tmp[0] = y;
|
tmp[0] = y;
|
||||||
@@ -121,6 +145,11 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
|||||||
return _i2c_send_pkt(idx, x, tmp, size + 1);
|
return _i2c_send_pkt(idx, x, tmp, size + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x)
|
||||||
|
{
|
||||||
|
return _i2c_recv_pkt(idx, buf, size, x);
|
||||||
|
}
|
||||||
|
|
||||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
|
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
|
||||||
{
|
{
|
||||||
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
|
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
|
|
||||||
void i2c_init(u32 idx);
|
void i2c_init(u32 idx);
|
||||||
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
|
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
|
||||||
|
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x);
|
||||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
|
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
|
||||||
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
|
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
|
||||||
u8 i2c_recv_byte(u32 idx, u32 x, u32 y);
|
u8 i2c_recv_byte(u32 idx, u32 x, u32 y);
|
||||||
|
|||||||
263
source/soc/irq.c
Normal file
263
source/soc/irq.c
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* BPMP-Lite IRQ driver for Tegra X1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "irq.h"
|
||||||
|
#include "t210.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
|
||||||
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
|
#define DPRINTF(...)
|
||||||
|
|
||||||
|
extern void irq_disable();
|
||||||
|
extern void irq_enable_cpu_irq_exceptions();
|
||||||
|
extern void irq_disable_cpu_irq_exceptions();
|
||||||
|
|
||||||
|
typedef struct _irq_ctxt_t
|
||||||
|
{
|
||||||
|
u32 irq;
|
||||||
|
int (*handler)(u32 irq, void *data);
|
||||||
|
void *data;
|
||||||
|
u32 flags;
|
||||||
|
} irq_ctxt_t;
|
||||||
|
|
||||||
|
bool irq_init_done = false;
|
||||||
|
irq_ctxt_t irqs[IRQ_MAX_HANDLERS];
|
||||||
|
|
||||||
|
static void _irq_enable_source(u32 irq)
|
||||||
|
{
|
||||||
|
u32 ctrl_idx = irq >> 5;
|
||||||
|
u32 bit = irq % 32;
|
||||||
|
|
||||||
|
// Set as normal IRQ.
|
||||||
|
ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~(1 << bit);
|
||||||
|
|
||||||
|
// Enable IRQ source.
|
||||||
|
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _irq_disable_source(u32 irq)
|
||||||
|
{
|
||||||
|
u32 ctrl_idx = irq >> 5;
|
||||||
|
u32 bit = irq % 32;
|
||||||
|
|
||||||
|
// Disable IRQ source.
|
||||||
|
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _irq_disable_and_ack_all()
|
||||||
|
{
|
||||||
|
// Disable and ack all IRQ sources.
|
||||||
|
for (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++)
|
||||||
|
{
|
||||||
|
u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER);
|
||||||
|
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs;
|
||||||
|
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = enabled_irqs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _irq_ack_source(u32 irq)
|
||||||
|
{
|
||||||
|
u32 ctrl_idx = irq >> 5;
|
||||||
|
u32 bit = irq % 32;
|
||||||
|
|
||||||
|
// Force stop the interrupt as it's serviced here.
|
||||||
|
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_free(u32 irq)
|
||||||
|
{
|
||||||
|
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||||
|
{
|
||||||
|
if (irqs[idx].irq == irq && irqs[idx].handler)
|
||||||
|
{
|
||||||
|
irqs[idx].irq = 0;
|
||||||
|
irqs[idx].handler = NULL;
|
||||||
|
irqs[idx].data = NULL;
|
||||||
|
irqs[idx].flags = 0;
|
||||||
|
|
||||||
|
_irq_disable_source(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _irq_free_all()
|
||||||
|
{
|
||||||
|
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||||
|
{
|
||||||
|
if (irqs[idx].handler)
|
||||||
|
{
|
||||||
|
_irq_disable_source(irqs[idx].irq);
|
||||||
|
|
||||||
|
irqs[idx].irq = 0;
|
||||||
|
irqs[idx].handler = NULL;
|
||||||
|
irqs[idx].data = NULL;
|
||||||
|
irqs[idx].flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static irq_status_t _irq_handle_source(u32 irq)
|
||||||
|
{
|
||||||
|
int status = IRQ_NONE;
|
||||||
|
|
||||||
|
_irq_disable_source(irq);
|
||||||
|
_irq_ack_source(irq);
|
||||||
|
|
||||||
|
u32 idx;
|
||||||
|
for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||||
|
{
|
||||||
|
if (irqs[idx].irq == irq)
|
||||||
|
{
|
||||||
|
status = irqs[idx].handler(irqs[idx].irq, irqs[idx].data);
|
||||||
|
|
||||||
|
if (status == IRQ_HANDLED)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqs[idx].flags & IRQ_FLAG_ONE_OFF)
|
||||||
|
irq_free(irq);
|
||||||
|
else
|
||||||
|
_irq_enable_source(irq);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_handler()
|
||||||
|
{
|
||||||
|
// Get IRQ source.
|
||||||
|
u32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF;
|
||||||
|
|
||||||
|
if (!irq_init_done)
|
||||||
|
{
|
||||||
|
_irq_ack_source(irq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF("IRQ: %d\n", irq);
|
||||||
|
|
||||||
|
int err = _irq_handle_source(irq);
|
||||||
|
|
||||||
|
//TODO: disable if unhandhled.
|
||||||
|
if (err == IRQ_NONE)
|
||||||
|
gfx_printf("Unhandled IRQ: %d\n", irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _irq_init()
|
||||||
|
{
|
||||||
|
_irq_disable_and_ack_all();
|
||||||
|
memset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS);
|
||||||
|
irq_init_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_end()
|
||||||
|
{
|
||||||
|
_irq_free_all();
|
||||||
|
irq_disable_cpu_irq_exceptions();
|
||||||
|
irq_init_done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_wait_event(u32 irq)
|
||||||
|
{
|
||||||
|
irq_disable_cpu_irq_exceptions();
|
||||||
|
|
||||||
|
_irq_enable_source(irq);
|
||||||
|
|
||||||
|
// Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ.
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_STOP_UNTIL_IRQ;
|
||||||
|
|
||||||
|
_irq_disable_source(irq);
|
||||||
|
_irq_ack_source(irq);
|
||||||
|
|
||||||
|
irq_enable_cpu_irq_exceptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_disable_wait_event()
|
||||||
|
{
|
||||||
|
irq_enable_cpu_irq_exceptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags)
|
||||||
|
{
|
||||||
|
if (!irq_init_done)
|
||||||
|
_irq_init();
|
||||||
|
|
||||||
|
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
|
||||||
|
{
|
||||||
|
if (irqs[idx].handler == NULL ||
|
||||||
|
(irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE))
|
||||||
|
{
|
||||||
|
DPRINTF("Registered handler, IRQ: %d, Slot: %d\n", irq, idx);
|
||||||
|
DPRINTF("Handler: %08p, Flags: %x\n", (u32)handler, flags);
|
||||||
|
|
||||||
|
irqs[idx].irq = irq;
|
||||||
|
irqs[idx].handler = handler;
|
||||||
|
irqs[idx].data = data;
|
||||||
|
irqs[idx].flags = flags;
|
||||||
|
|
||||||
|
_irq_enable_source(irq);
|
||||||
|
|
||||||
|
return IRQ_ENABLED;
|
||||||
|
}
|
||||||
|
else if (irqs[idx].irq == irq)
|
||||||
|
return IRQ_ALREADY_REGISTERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_NO_SLOTS_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__ ((target("arm"))) fiq_setup()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
asm volatile("mrs r12, cpsr\n\t"
|
||||||
|
"bic r12, r12, #0x1F\n\t"
|
||||||
|
"orr r12, r12, #0x11\n\t"
|
||||||
|
"msr cpsr_c, r12\n\t");
|
||||||
|
|
||||||
|
register volatile char *text asm ("r8");
|
||||||
|
register volatile char *uart_tx asm ("r9");
|
||||||
|
register int len asm ("r10");
|
||||||
|
|
||||||
|
len = 5;
|
||||||
|
uart_tx = (char *)0x70006040;
|
||||||
|
memcpy((char *)text, "FIQ\r\n", len);
|
||||||
|
*uart_tx = 0;
|
||||||
|
|
||||||
|
asm volatile("mrs r12, cpsr\n"
|
||||||
|
"orr r12, r12, #0x1F\n"
|
||||||
|
"msr cpsr_c, r12");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__ ((target("arm"), interrupt ("FIQ"))) fiq_handler()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
register volatile char *text asm ("r8");
|
||||||
|
register volatile char *uart_tx asm ("r9");
|
||||||
|
register int len asm ("r10");
|
||||||
|
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
*uart_tx = *text++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
222
source/soc/irq.h
Normal file
222
source/soc/irq.h
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* BPMP-Lite IRQ driver for Tegra X1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IRQ_H
|
||||||
|
#define IRQ_H
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define IRQ_MAX_HANDLERS 16
|
||||||
|
|
||||||
|
/* Primary interrupt controller ids */
|
||||||
|
#define IRQ_TMR1 0
|
||||||
|
#define IRQ_TMR2 1
|
||||||
|
#define IRQ_RTC 2
|
||||||
|
#define IRQ_CEC 3
|
||||||
|
#define IRQ_SHR_SEM_INBOX_FULL 4
|
||||||
|
#define IRQ_SHR_SEM_INBOX_EMPTY 5
|
||||||
|
#define IRQ_SHR_SEM_OUTBOX_FULL 6
|
||||||
|
#define IRQ_SHR_SEM_OUTBOX_EMPTY 7
|
||||||
|
#define IRQ_NVJPEG 8
|
||||||
|
#define IRQ_NVDEC 9
|
||||||
|
#define IRQ_QUAD_SPI 10
|
||||||
|
#define IRQ_DPAUX_INT1 11
|
||||||
|
#define IRQ_SATA_RX_STAT 13
|
||||||
|
#define IRQ_SDMMC1 14
|
||||||
|
#define IRQ_SDMMC2 15
|
||||||
|
#define IRQ_VGPIO_INT 16
|
||||||
|
#define IRQ_VII2C_INT 17
|
||||||
|
#define IRQ_SDMMC3 19
|
||||||
|
#define IRQ_USB 20
|
||||||
|
#define IRQ_USB2 21
|
||||||
|
#define IRQ_SATA_CTL 23
|
||||||
|
#define IRQ_PMC_INT 24
|
||||||
|
#define IRQ_FC_INT 25
|
||||||
|
#define IRQ_APB_DMA_CPU 26
|
||||||
|
#define IRQ_ARB_SEM_GNT_COP 28
|
||||||
|
#define IRQ_ARB_SEM_GNT_CPU 29
|
||||||
|
#define IRQ_SDMMC4 31
|
||||||
|
|
||||||
|
/* Secondary interrupt controller ids */
|
||||||
|
#define IRQ_GPIO1 32
|
||||||
|
#define IRQ_GPIO2 33
|
||||||
|
#define IRQ_GPIO3 34
|
||||||
|
#define IRQ_GPIO4 35
|
||||||
|
#define IRQ_UARTA 36
|
||||||
|
#define IRQ_UARTB 37
|
||||||
|
#define IRQ_I2C 38
|
||||||
|
#define IRQ_USB3_HOST_INT 39
|
||||||
|
#define IRQ_USB3_HOST_SMI 40
|
||||||
|
#define IRQ_TMR3 41
|
||||||
|
#define IRQ_TMR4 42
|
||||||
|
#define IRQ_USB3_HOST_PME 43
|
||||||
|
#define IRQ_USB3_DEV_HOST 44
|
||||||
|
#define IRQ_ACTMON 45
|
||||||
|
#define IRQ_UARTC 46
|
||||||
|
#define IRQ_THERMAL 48
|
||||||
|
#define IRQ_XUSB_PADCTL 49
|
||||||
|
#define IRQ_TSEC 50
|
||||||
|
#define IRQ_EDP 51
|
||||||
|
#define IRQ_I2C5 53
|
||||||
|
#define IRQ_GPIO5 55
|
||||||
|
#define IRQ_USB3_DEV_SMI 56
|
||||||
|
#define IRQ_USB3_DEV_PME 57
|
||||||
|
#define IRQ_SE 58
|
||||||
|
#define IRQ_SPI1 59
|
||||||
|
#define IRQ_APB_DMA_COP 60
|
||||||
|
#define IRQ_CLDVFS 62
|
||||||
|
#define IRQ_I2C6 63
|
||||||
|
|
||||||
|
/* Tertiary interrupt controller ids */
|
||||||
|
#define IRQ_HOST1X_SYNCPT_COP 64
|
||||||
|
#define IRQ_HOST1X_SYNCPT_CPU 65
|
||||||
|
#define IRQ_HOST1X_GEN_COP 66
|
||||||
|
#define IRQ_HOST1X_GEN_CPU 67
|
||||||
|
#define IRQ_NVENC 68
|
||||||
|
#define IRQ_VI 69
|
||||||
|
#define IRQ_ISPB 70
|
||||||
|
#define IRQ_ISP 71
|
||||||
|
#define IRQ_VIC 72
|
||||||
|
#define IRQ_DISPLAY 73
|
||||||
|
#define IRQ_DISPLAYB 74
|
||||||
|
#define IRQ_SOR1 75
|
||||||
|
#define IRQ_SOR 76
|
||||||
|
#define IRQ_MC 77
|
||||||
|
#define IRQ_EMC 78
|
||||||
|
#define IRQ_TSECB 80
|
||||||
|
#define IRQ_HDA 81
|
||||||
|
#define IRQ_SPI2 82
|
||||||
|
#define IRQ_SPI3 83
|
||||||
|
#define IRQ_I2C2 84
|
||||||
|
#define IRQ_PMU_EXT 86
|
||||||
|
#define IRQ_GPIO6 87
|
||||||
|
#define IRQ_GPIO7 89
|
||||||
|
#define IRQ_UARTD 90
|
||||||
|
#define IRQ_I2C3 92
|
||||||
|
#define IRQ_SPI4 93
|
||||||
|
|
||||||
|
/* Quaternary interrupt controller ids */
|
||||||
|
#define IRQ_DTV 96
|
||||||
|
#define IRQ_PCIE_INT 98
|
||||||
|
#define IRQ_PCIE_MSI 99
|
||||||
|
#define IRQ_AVP_CACHE 101
|
||||||
|
#define IRQ_APE_INT1 102
|
||||||
|
#define IRQ_APE_INT0 103
|
||||||
|
#define IRQ_APB_DMA_CH0 104
|
||||||
|
#define IRQ_APB_DMA_CH1 105
|
||||||
|
#define IRQ_APB_DMA_CH2 106
|
||||||
|
#define IRQ_APB_DMA_CH3 107
|
||||||
|
#define IRQ_APB_DMA_CH4 108
|
||||||
|
#define IRQ_APB_DMA_CH5 109
|
||||||
|
#define IRQ_APB_DMA_CH6 110
|
||||||
|
#define IRQ_APB_DMA_CH7 111
|
||||||
|
#define IRQ_APB_DMA_CH8 112
|
||||||
|
#define IRQ_APB_DMA_CH9 113
|
||||||
|
#define IRQ_APB_DMA_CH10 114
|
||||||
|
#define IRQ_APB_DMA_CH11 115
|
||||||
|
#define IRQ_APB_DMA_CH12 116
|
||||||
|
#define IRQ_APB_DMA_CH13 117
|
||||||
|
#define IRQ_APB_DMA_CH14 118
|
||||||
|
#define IRQ_APB_DMA_CH15 119
|
||||||
|
#define IRQ_I2C4 120
|
||||||
|
#define IRQ_TMR5 121
|
||||||
|
#define IRQ_WDT_CPU 123
|
||||||
|
#define IRQ_WDT_AVP 124
|
||||||
|
#define IRQ_GPIO8 125
|
||||||
|
#define IRQ_CAR 126
|
||||||
|
|
||||||
|
/* Quinary interrupt controller ids */
|
||||||
|
#define IRQ_APB_DMA_CH16 128
|
||||||
|
#define IRQ_APB_DMA_CH17 129
|
||||||
|
#define IRQ_APB_DMA_CH18 130
|
||||||
|
#define IRQ_APB_DMA_CH19 131
|
||||||
|
#define IRQ_APB_DMA_CH20 132
|
||||||
|
#define IRQ_APB_DMA_CH21 133
|
||||||
|
#define IRQ_APB_DMA_CH22 134
|
||||||
|
#define IRQ_APB_DMA_CH23 135
|
||||||
|
#define IRQ_APB_DMA_CH24 136
|
||||||
|
#define IRQ_APB_DMA_CH25 137
|
||||||
|
#define IRQ_APB_DMA_CH26 138
|
||||||
|
#define IRQ_APB_DMA_CH27 139
|
||||||
|
#define IRQ_APB_DMA_CH28 140
|
||||||
|
#define IRQ_APB_DMA_CH29 141
|
||||||
|
#define IRQ_APB_DMA_CH30 142
|
||||||
|
#define IRQ_APB_DMA_CH31 143
|
||||||
|
#define IRQ_CPU0_PMU_INTR 144
|
||||||
|
#define IRQ_CPU1_PMU_INTR 145
|
||||||
|
#define IRQ_CPU2_PMU_INTR 146
|
||||||
|
#define IRQ_CPU3_PMU_INTR 147
|
||||||
|
#define IRQ_SDMMC1_SYS 148
|
||||||
|
#define IRQ_SDMMC2_SYS 149
|
||||||
|
#define IRQ_SDMMC3_SYS 150
|
||||||
|
#define IRQ_SDMMC4_SYS 151
|
||||||
|
#define IRQ_TMR6 152
|
||||||
|
#define IRQ_TMR7 153
|
||||||
|
#define IRQ_TMR8 154
|
||||||
|
#define IRQ_TMR9 155
|
||||||
|
#define IRQ_TMR0 156
|
||||||
|
#define IRQ_GPU_STALL 157
|
||||||
|
#define IRQ_GPU_NONSTALL 158
|
||||||
|
#define IRQ_DPAUX 159
|
||||||
|
|
||||||
|
/* Senary interrupt controller ids */
|
||||||
|
#define IRQ_MPCORE_AXIERRIRQ 160
|
||||||
|
#define IRQ_MPCORE_INTERRIRQ 161
|
||||||
|
#define IRQ_EVENT_GPIO_A 162
|
||||||
|
#define IRQ_EVENT_GPIO_B 163
|
||||||
|
#define IRQ_EVENT_GPIO_C 164
|
||||||
|
#define IRQ_FLOW_RSM_CPU 168
|
||||||
|
#define IRQ_FLOW_RSM_COP 169
|
||||||
|
#define IRQ_TMR_SHARED 170
|
||||||
|
#define IRQ_MPCORE_CTIIRQ0 171
|
||||||
|
#define IRQ_MPCORE_CTIIRQ1 172
|
||||||
|
#define IRQ_MPCORE_CTIIRQ2 173
|
||||||
|
#define IRQ_MPCORE_CTIIRQ3 174
|
||||||
|
#define IRQ_MSELECT_ERROR 175
|
||||||
|
#define IRQ_TMR10 176
|
||||||
|
#define IRQ_TMR11 177
|
||||||
|
#define IRQ_TMR12 178
|
||||||
|
#define IRQ_TMR13 179
|
||||||
|
|
||||||
|
typedef int (*irq_handler_t)(u32 irq, void *data);
|
||||||
|
|
||||||
|
typedef enum _irq_status_t
|
||||||
|
{
|
||||||
|
IRQ_NONE = 0,
|
||||||
|
IRQ_HANDLED = 1,
|
||||||
|
IRQ_ERROR = 2,
|
||||||
|
|
||||||
|
IRQ_ENABLED = 0,
|
||||||
|
IRQ_NO_SLOTS_AVAILABLE = 1,
|
||||||
|
IRQ_ALREADY_REGISTERED = 2
|
||||||
|
} irq_status_t;
|
||||||
|
|
||||||
|
typedef enum _irq_flags_t
|
||||||
|
{
|
||||||
|
IRQ_FLAG_NONE = 0,
|
||||||
|
IRQ_FLAG_ONE_OFF = (1 << 0),
|
||||||
|
IRQ_FLAG_REPLACEABLE = (1 << 1)
|
||||||
|
} irq_flags_t;
|
||||||
|
|
||||||
|
void irq_end();
|
||||||
|
void irq_free(u32 irq);
|
||||||
|
void irq_wait_event();
|
||||||
|
void irq_disable_wait_event();
|
||||||
|
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
|
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
|
||||||
#define PINMUX_AUX_LCD_BL_EN 0x200
|
#define PINMUX_AUX_LCD_BL_EN 0x200
|
||||||
#define PINMUX_AUX_LCD_RST 0x204
|
#define PINMUX_AUX_LCD_RST 0x204
|
||||||
|
#define PINMUX_AUX_LCD_GPIO1 0x208
|
||||||
#define PINMUX_AUX_LCD_GPIO2 0x20C
|
#define PINMUX_AUX_LCD_GPIO2 0x20C
|
||||||
#define PINMUX_AUX_TOUCH_INT 0x220
|
#define PINMUX_AUX_TOUCH_INT 0x220
|
||||||
#define PINMUX_AUX_MOTION_INT 0x224
|
#define PINMUX_AUX_MOTION_INT 0x224
|
||||||
|
|||||||
@@ -25,13 +25,23 @@
|
|||||||
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
||||||
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
||||||
#define APBDEV_PMC_NO_IOPOWER 0x44
|
#define APBDEV_PMC_NO_IOPOWER 0x44
|
||||||
|
#define PMC_NO_IOPOWER_GPIO_IO_EN (1 << 21)
|
||||||
|
#define PMC_NO_IOPOWER_AUDIO_HV (1 << 18)
|
||||||
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
|
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
|
||||||
#define APBDEV_PMC_SCRATCH0 0x50
|
#define APBDEV_PMC_SCRATCH0 0x50
|
||||||
|
#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
|
||||||
|
#define PMC_SCRATCH0_MODE_FASTBOOT (1 << 30)
|
||||||
|
#define PMC_SCRATCH0_MODE_PAYLOAD (1 << 29)
|
||||||
|
#define PMC_SCRATCH0_MODE_RCM (1 << 1)
|
||||||
|
#define PMC_SCRATCH0_MODE_WARMBOOT (1 << 0)
|
||||||
#define APBDEV_PMC_SCRATCH1 0x54
|
#define APBDEV_PMC_SCRATCH1 0x54
|
||||||
#define APBDEV_PMC_SCRATCH20 0xA0
|
#define APBDEV_PMC_SCRATCH20 0xA0
|
||||||
#define APBDEV_PMC_PWR_DET_VAL 0xE4
|
#define APBDEV_PMC_PWR_DET_VAL 0xE4
|
||||||
|
#define PMC_PWR_DET_GPIO_IO_EN (1 << 21)
|
||||||
|
#define PMC_PWR_DET_AUDIO_HV (1 << 18)
|
||||||
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
|
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
|
||||||
#define APBDEV_PMC_DDR_PWR 0xE8
|
#define APBDEV_PMC_DDR_PWR 0xE8
|
||||||
|
#define APBDEV_PMC_USB_AO 0xF0
|
||||||
#define APBDEV_PMC_CRYPTO_OP 0xF4
|
#define APBDEV_PMC_CRYPTO_OP 0xF4
|
||||||
#define PMC_CRYPTO_OP_SE_ENABLE 0
|
#define PMC_CRYPTO_OP_SE_ENABLE 0
|
||||||
#define PMC_CRYPTO_OP_SE_DISABLE 1
|
#define PMC_CRYPTO_OP_SE_DISABLE 1
|
||||||
@@ -39,6 +49,8 @@
|
|||||||
#define APBDEV_PMC_SCRATCH40 0x13C
|
#define APBDEV_PMC_SCRATCH40 0x13C
|
||||||
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
|
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
|
||||||
#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000
|
#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000
|
||||||
|
#define APBDEV_PMC_CLK_OUT_CNTRL 0x1A8
|
||||||
|
#define PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN (1 << 2)
|
||||||
#define APBDEV_PMC_RST_STATUS 0x1B4
|
#define APBDEV_PMC_RST_STATUS 0x1B4
|
||||||
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
||||||
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
||||||
|
|||||||
@@ -28,9 +28,11 @@
|
|||||||
#define VIC_BASE 0x54340000
|
#define VIC_BASE 0x54340000
|
||||||
#define TSEC_BASE 0x54500000
|
#define TSEC_BASE 0x54500000
|
||||||
#define SOR1_BASE 0x54580000
|
#define SOR1_BASE 0x54580000
|
||||||
|
#define ICTLR_BASE 0x60004000
|
||||||
#define TMR_BASE 0x60005000
|
#define TMR_BASE 0x60005000
|
||||||
#define CLOCK_BASE 0x60006000
|
#define CLOCK_BASE 0x60006000
|
||||||
#define FLOW_CTLR_BASE 0x60007000
|
#define FLOW_CTLR_BASE 0x60007000
|
||||||
|
#define AHBDMA_BASE 0x60008000
|
||||||
#define SYSREG_BASE 0x6000C000
|
#define SYSREG_BASE 0x6000C000
|
||||||
#define SB_BASE (SYSREG_BASE + 0x200)
|
#define SB_BASE (SYSREG_BASE + 0x200)
|
||||||
#define GPIO_BASE 0x6000D000
|
#define GPIO_BASE 0x6000D000
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
#define GPIO_8_BASE (GPIO_BASE + 0x700)
|
#define GPIO_8_BASE (GPIO_BASE + 0x700)
|
||||||
#define EXCP_VEC_BASE 0x6000F000
|
#define EXCP_VEC_BASE 0x6000F000
|
||||||
#define IPATCH_BASE 0x6001DC00
|
#define IPATCH_BASE 0x6001DC00
|
||||||
|
#define APBDMA_BASE 0x60020000
|
||||||
#define APB_MISC_BASE 0x70000000
|
#define APB_MISC_BASE 0x70000000
|
||||||
#define PINMUX_AUX_BASE 0x70003000
|
#define PINMUX_AUX_BASE 0x70003000
|
||||||
#define UART_BASE 0x70006000
|
#define UART_BASE 0x70006000
|
||||||
@@ -56,10 +59,16 @@
|
|||||||
#define SE_BASE 0x70012000
|
#define SE_BASE 0x70012000
|
||||||
#define MC_BASE 0x70019000
|
#define MC_BASE 0x70019000
|
||||||
#define EMC_BASE 0x7001B000
|
#define EMC_BASE 0x7001B000
|
||||||
|
#define EMC0_BASE 0x7001E000
|
||||||
|
#define EMC1_BASE 0x7001F000
|
||||||
#define MIPI_CAL_BASE 0x700E3000
|
#define MIPI_CAL_BASE 0x700E3000
|
||||||
#define CL_DVFS_BASE 0x70110000
|
#define CL_DVFS_BASE 0x70110000
|
||||||
#define I2S_BASE 0x702D1000
|
#define I2S_BASE 0x702D1000
|
||||||
|
#define ADMA_BASE 0x702E2000
|
||||||
#define TZRAM_BASE 0x7C010000
|
#define TZRAM_BASE 0x7C010000
|
||||||
|
#define USB_BASE 0x7D000000
|
||||||
|
#define USB_OTG_BASE USB_BASE
|
||||||
|
#define USB1_BASE 0x7D004000
|
||||||
|
|
||||||
#define _REG(base, off) *(vu32 *)((base) + (off))
|
#define _REG(base, off) *(vu32 *)((base) + (off))
|
||||||
|
|
||||||
@@ -70,10 +79,12 @@
|
|||||||
#define VIC(off) _REG(VIC_BASE, off)
|
#define VIC(off) _REG(VIC_BASE, off)
|
||||||
#define TSEC(off) _REG(TSEC_BASE, off)
|
#define TSEC(off) _REG(TSEC_BASE, off)
|
||||||
#define SOR1(off) _REG(SOR1_BASE, off)
|
#define SOR1(off) _REG(SOR1_BASE, off)
|
||||||
|
#define ICTLR(cidx, off) _REG(ICTLR_BASE + (0x100 * cidx), off)
|
||||||
#define TMR(off) _REG(TMR_BASE, off)
|
#define TMR(off) _REG(TMR_BASE, off)
|
||||||
#define CLOCK(off) _REG(CLOCK_BASE, off)
|
#define CLOCK(off) _REG(CLOCK_BASE, off)
|
||||||
#define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off)
|
#define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off)
|
||||||
#define SYSREG(off) _REG(SYSREG_BASE, off)
|
#define SYSREG(off) _REG(SYSREG_BASE, off)
|
||||||
|
#define AHB_GIZMO(off) _REG(SYSREG_BASE, off)
|
||||||
#define SB(off) _REG(SB_BASE, off)
|
#define SB(off) _REG(SB_BASE, off)
|
||||||
#define GPIO(off) _REG(GPIO_BASE, off)
|
#define GPIO(off) _REG(GPIO_BASE, off)
|
||||||
#define GPIO_1(off) _REG(GPIO_1_BASE, off)
|
#define GPIO_1(off) _REG(GPIO_1_BASE, off)
|
||||||
@@ -96,9 +107,14 @@
|
|||||||
#define SE(off) _REG(SE_BASE, off)
|
#define SE(off) _REG(SE_BASE, off)
|
||||||
#define MC(off) _REG(MC_BASE, off)
|
#define MC(off) _REG(MC_BASE, off)
|
||||||
#define EMC(off) _REG(EMC_BASE, off)
|
#define EMC(off) _REG(EMC_BASE, off)
|
||||||
|
#define EMC_CH0(off) _REG(EMC0_BASE, off)
|
||||||
|
#define EMC_CH1(off) _REG(EMC1_BASE, off)
|
||||||
#define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off)
|
#define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off)
|
||||||
#define I2S(off) _REG(I2S_BASE, off)
|
|
||||||
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
||||||
|
#define I2S(off) _REG(I2S_BASE, off)
|
||||||
|
#define ADMA(off) _REG(ADMA_BASE, off)
|
||||||
|
#define USB(off) _REG(USB_BASE, off)
|
||||||
|
#define USB1(off) _REG(USB1_BASE, off)
|
||||||
#define TEST_REG(off) _REG(0x0, off)
|
#define TEST_REG(off) _REG(0x0, off)
|
||||||
|
|
||||||
/* HOST1X registers. */
|
/* HOST1X registers. */
|
||||||
@@ -116,13 +132,40 @@
|
|||||||
#define EVP_COP_RSVD_VECTOR 0x214
|
#define EVP_COP_RSVD_VECTOR 0x214
|
||||||
#define EVP_COP_IRQ_VECTOR 0x218
|
#define EVP_COP_IRQ_VECTOR 0x218
|
||||||
#define EVP_COP_FIQ_VECTOR 0x21C
|
#define EVP_COP_FIQ_VECTOR 0x21C
|
||||||
|
#define EVP_COP_IRQ_STS 0x220
|
||||||
|
|
||||||
|
/*! Primary Interrupt Controller registers. */
|
||||||
|
#define PRI_ICTLR_FIR 0x14
|
||||||
|
#define PRI_ICTLR_FIR_SET 0x18
|
||||||
|
#define PRI_ICTLR_FIR_CLR 0x1C
|
||||||
|
#define PRI_ICTLR_CPU_IER 0x20
|
||||||
|
#define PRI_ICTLR_CPU_IER_SET 0x24
|
||||||
|
#define PRI_ICTLR_CPU_IER_CLR 0x28
|
||||||
|
#define PRI_ICTLR_CPU_IEP_CLASS 0x2C
|
||||||
|
#define PRI_ICTLR_COP_IER 0x30
|
||||||
|
#define PRI_ICTLR_COP_IER_SET 0x34
|
||||||
|
#define PRI_ICTLR_COP_IER_CLR 0x38
|
||||||
|
#define PRI_ICTLR_COP_IEP_CLASS 0x3C
|
||||||
|
|
||||||
|
/*! AHB Gizmo registers. */
|
||||||
|
#define AHB_ARBITRATION_PRIORITY_CTRL 0x8
|
||||||
|
#define ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE (1 << 6)
|
||||||
|
#define AHB_GIZMO_AHB_MEM 0x10
|
||||||
|
#define AHB_MEM_ENB_FAST_REARBITRATE (1 << 2)
|
||||||
|
#define AHB_GIZMO_USB 0x20
|
||||||
|
#define AHB_GIZMO_USB_IMMEDIATE (1 << 18)
|
||||||
|
#define AHB_AHB_MEM_PREFETCH_CFG1 0xF0
|
||||||
|
#define MEM_PREFETCH_ENABLE (1 << 31)
|
||||||
|
#define MEM_PREFETCH_AHB_MST_USB 6
|
||||||
|
|
||||||
/*! Misc registers. */
|
/*! Misc registers. */
|
||||||
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
|
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
|
||||||
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
|
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
|
||||||
#define APB_MISC_GP_HIDREV 0x804
|
#define APB_MISC_GP_HIDREV 0x804
|
||||||
|
#define APB_MISC_GP_AUD_MCLK_CFGPADCTRL 0x8F4
|
||||||
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
|
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
|
||||||
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
|
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
|
||||||
|
#define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL 0xA9C
|
||||||
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
|
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
|
||||||
#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC
|
#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC
|
||||||
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
|
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
|
||||||
@@ -170,9 +213,14 @@
|
|||||||
/*! TMR registers. */
|
/*! TMR registers. */
|
||||||
#define TIMERUS_CNTR_1US (0x10 + 0x0)
|
#define TIMERUS_CNTR_1US (0x10 + 0x0)
|
||||||
#define TIMERUS_USEC_CFG (0x10 + 0x4)
|
#define TIMERUS_USEC_CFG (0x10 + 0x4)
|
||||||
|
#define TIMER_TMR8_TMR_PTV 0x78
|
||||||
#define TIMER_TMR9_TMR_PTV 0x80
|
#define TIMER_TMR9_TMR_PTV 0x80
|
||||||
#define TIMER_EN (1 << 31)
|
#define TIMER_EN (1 << 31)
|
||||||
#define TIMER_PER_EN (1 << 30)
|
#define TIMER_PER_EN (1 << 30)
|
||||||
|
#define TIMER_TMR8_TMR_PCR 0x7C
|
||||||
|
#define TIMER_TMR9_TMR_PCR 0x8C
|
||||||
|
#define TIMER_INTR_CLR (1 << 30)
|
||||||
|
|
||||||
#define TIMER_WDT4_CONFIG (0x100 + 0x80)
|
#define TIMER_WDT4_CONFIG (0x100 + 0x80)
|
||||||
#define TIMER_SRC(TMR) (TMR & 0xF)
|
#define TIMER_SRC(TMR) (TMR & 0xF)
|
||||||
#define TIMER_PER(PER) ((PER & 0xFF) << 4)
|
#define TIMER_PER(PER) ((PER & 0xFF) << 4)
|
||||||
@@ -210,13 +258,15 @@
|
|||||||
|
|
||||||
/*! Flow controller registers. */
|
/*! Flow controller registers. */
|
||||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
||||||
#define HALT_COP_SEC (1 << 23)
|
#define HALT_COP_GIC_IRQ (1 << 9)
|
||||||
#define HALT_COP_MSEC (1 << 24)
|
#define HALT_COP_LIC_IRQ (1 << 11)
|
||||||
#define HALT_COP_USEC (1 << 25)
|
#define HALT_COP_SEC (1 << 23)
|
||||||
#define HALT_COP_JTAG (1 << 28)
|
#define HALT_COP_MSEC (1 << 24)
|
||||||
#define HALT_COP_WAIT_EVENT (1 << 30)
|
#define HALT_COP_USEC (1 << 25)
|
||||||
#define HALT_COP_WAIT_IRQ (1 << 31)
|
#define HALT_COP_JTAG (1 << 28)
|
||||||
#define HALT_COP_MAX_CNT 0xFF
|
#define HALT_COP_WAIT_EVENT (1 << 30)
|
||||||
|
#define HALT_COP_STOP_UNTIL_IRQ (1 << 31)
|
||||||
|
#define HALT_COP_MAX_CNT 0xFF
|
||||||
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
|
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
|
||||||
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
|
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
|
||||||
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
||||||
@@ -228,4 +278,9 @@
|
|||||||
#define FLOW_CTLR_RAM_REPAIR 0x40
|
#define FLOW_CTLR_RAM_REPAIR 0x40
|
||||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
||||||
|
|
||||||
|
/*! USB controller registers. */
|
||||||
|
#define USB1_UTMIP_BAT_CHRG_CFG0 0x830
|
||||||
|
#define BAT_CHRG_CFG0_OP_SRC_EN (1 << 3)
|
||||||
|
#define BAT_CHRG_CFG0_PWRDOWN_CHRG (1 << 0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
172
source/soc/uart.c
Normal file
172
source/soc/uart.c
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../soc/uart.h"
|
||||||
|
#include "../soc/clock.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
/* UART A, B, C, D and E. */
|
||||||
|
static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 };
|
||||||
|
|
||||||
|
void uart_init(u32 idx, u32 baud)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
|
||||||
|
// Make sure no data is being sent.
|
||||||
|
uart_wait_idle(idx, UART_TX_IDLE);
|
||||||
|
|
||||||
|
// Set clock.
|
||||||
|
bool clk_type = clock_uart_use_src_div(idx, baud);
|
||||||
|
|
||||||
|
// Misc settings.
|
||||||
|
u32 div = clk_type ? ((8 * baud + 408000000) / (16 * baud)) : 1; // DIV_ROUND_CLOSEST.
|
||||||
|
uart->UART_IER_DLAB = 0; // Disable interrupts.
|
||||||
|
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
|
||||||
|
uart->UART_THR_DLAB = (u8)div; // Divisor latch LSB.
|
||||||
|
uart->UART_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB.
|
||||||
|
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB.
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
|
||||||
|
// Setup and flush fifo.
|
||||||
|
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO;
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
usleep(20);
|
||||||
|
uart->UART_MCR = 0; // Disable hardware flow control.
|
||||||
|
usleep(96);
|
||||||
|
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
|
||||||
|
|
||||||
|
// Wait 3 symbols for baudrate change.
|
||||||
|
usleep(3 * ((baud + 999999) / baud));
|
||||||
|
uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_wait_idle(u32 idx, u32 which)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
if (UART_TX_IDLE & which)
|
||||||
|
{
|
||||||
|
while (!(uart->UART_LSR & UART_LSR_TMTY))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (UART_RX_IDLE & which)
|
||||||
|
{
|
||||||
|
while (uart->UART_LSR & UART_LSR_RDR)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_send(u32 idx, const u8 *buf, u32 len)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
|
||||||
|
for (u32 i = 0; i != len; i++)
|
||||||
|
{
|
||||||
|
while (!(uart->UART_LSR & UART_LSR_THRE))
|
||||||
|
;
|
||||||
|
uart->UART_THR_DLAB = buf[i];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 uart_recv(u32 idx, u8 *buf, u32 len)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
u32 timeout = get_tmr_us() + 1000;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; ; i++)
|
||||||
|
{
|
||||||
|
while (!(uart->UART_LSR & UART_LSR_RDR))
|
||||||
|
{
|
||||||
|
if (!len)
|
||||||
|
{
|
||||||
|
if (timeout < get_tmr_us())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (len < i)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (timeout < get_tmr_us())
|
||||||
|
break;
|
||||||
|
|
||||||
|
buf[i] = uart->UART_THR_DLAB;
|
||||||
|
timeout = get_tmr_us() + 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
return i ? (len ? (i - 1) : i) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_invert(u32 idx, bool enable, u32 invert_mask)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
uart->UART_IRDA_CSR |= invert_mask;
|
||||||
|
else
|
||||||
|
uart->UART_IRDA_CSR &= ~invert_mask;
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 uart_get_IIR(u32 idx)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
|
||||||
|
return uart->UART_IIR_FCR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_set_IIR(u32 idx)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
|
||||||
|
uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD;
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD;
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_empty_fifo(u32 idx, u32 which)
|
||||||
|
{
|
||||||
|
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||||
|
|
||||||
|
uart->UART_MCR = 0;
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
usleep(96);
|
||||||
|
|
||||||
|
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
|
||||||
|
(void)uart->UART_SPR;
|
||||||
|
usleep(18);
|
||||||
|
u32 tries = 0;
|
||||||
|
|
||||||
|
if (UART_IIR_FCR_TX_CLR & which)
|
||||||
|
{
|
||||||
|
while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY)
|
||||||
|
{
|
||||||
|
tries++;
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
tries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UART_IIR_FCR_RX_CLR & which)
|
||||||
|
{
|
||||||
|
while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR)
|
||||||
|
{
|
||||||
|
tries++;
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
source/soc/uart.h
Normal file
87
source/soc/uart.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UART_H_
|
||||||
|
#define _UART_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define UART_A 0
|
||||||
|
#define UART_B 1
|
||||||
|
#define UART_C 2
|
||||||
|
#define UART_D 3
|
||||||
|
#define UART_E 4
|
||||||
|
|
||||||
|
#define BAUD_115200 115200
|
||||||
|
|
||||||
|
#define UART_TX_IDLE 0x1
|
||||||
|
#define UART_RX_IDLE 0x2
|
||||||
|
|
||||||
|
#define UART_TX_FIFO_FULL 0x100
|
||||||
|
#define UART_RX_FIFO_EMPTY 0x200
|
||||||
|
|
||||||
|
#define UART_INVERT_RXD 0x01
|
||||||
|
#define UART_INVERT_TXD 0x02
|
||||||
|
#define UART_INVERT_CTS 0x04
|
||||||
|
#define UART_INVERT_RTS 0x08
|
||||||
|
|
||||||
|
#define UART_IER_DLAB_IE_EORD 0x20
|
||||||
|
|
||||||
|
#define UART_LCR_DLAB 0x80
|
||||||
|
#define UART_LCR_STOP 0x4
|
||||||
|
#define UART_LCR_WORD_LENGTH_8 0x3
|
||||||
|
|
||||||
|
#define UART_LSR_RDR 0x1
|
||||||
|
#define UART_LSR_THRE 0x20
|
||||||
|
#define UART_LSR_TMTY 0x40
|
||||||
|
#define UART_LSR_FIFOE 0x80
|
||||||
|
|
||||||
|
#define UART_IIR_FCR_TX_CLR 0x4
|
||||||
|
#define UART_IIR_FCR_RX_CLR 0x2
|
||||||
|
#define UART_IIR_FCR_EN_FIFO 0x1
|
||||||
|
|
||||||
|
#define UART_MCR_RTS 0x2
|
||||||
|
#define UART_MCR_DTR 0x1
|
||||||
|
|
||||||
|
typedef struct _uart_t
|
||||||
|
{
|
||||||
|
/* 0x00 */ vu32 UART_THR_DLAB;
|
||||||
|
/* 0x04 */ vu32 UART_IER_DLAB;
|
||||||
|
/* 0x08 */ vu32 UART_IIR_FCR;
|
||||||
|
/* 0x0C */ vu32 UART_LCR;
|
||||||
|
/* 0x10 */ vu32 UART_MCR;
|
||||||
|
/* 0x14 */ vu32 UART_LSR;
|
||||||
|
/* 0x18 */ vu32 UART_MSR;
|
||||||
|
/* 0x1C */ vu32 UART_SPR;
|
||||||
|
/* 0x20 */ vu32 UART_IRDA_CSR;
|
||||||
|
/* 0x24 */ vu32 UART_RX_FIFO_CFG;
|
||||||
|
/* 0x28 */ vu32 UART_MIE;
|
||||||
|
/* 0x2C */ vu32 UART_VENDOR_STATUS;
|
||||||
|
/* 0x30 */ u8 _pad_30[0xC];
|
||||||
|
/* 0x3C */ vu32 UART_ASR;
|
||||||
|
} uart_t;
|
||||||
|
|
||||||
|
void uart_init(u32 idx, u32 baud);
|
||||||
|
void uart_wait_idle(u32 idx, u32 which);
|
||||||
|
void uart_send(u32 idx, const u8 *buf, u32 len);
|
||||||
|
u32 uart_recv(u32 idx, u8 *buf, u32 len);
|
||||||
|
void uart_invert(u32 idx, bool enable, u32 invert_mask);
|
||||||
|
u32 uart_get_IIR(u32 idx);
|
||||||
|
void uart_set_IIR(u32 idx);
|
||||||
|
void uart_empty_fifo(u32 idx, u32 which);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
.extern memset
|
.extern memset
|
||||||
.type memset, %function
|
.type memset, %function
|
||||||
|
|
||||||
.extern ipl_main
|
.extern _irq_setup
|
||||||
.type ipl_main, %function
|
.type _irq_setup, %function
|
||||||
|
|
||||||
.globl _start
|
.globl _start
|
||||||
.type _start, %function
|
.type _start, %function
|
||||||
@@ -67,7 +67,7 @@ _real_start:
|
|||||||
LDR R2, =__bss_end
|
LDR R2, =__bss_end
|
||||||
SUB R2, R2, R0
|
SUB R2, R2, R0
|
||||||
BL memset
|
BL memset
|
||||||
BL ipl_main
|
BL _irq_setup
|
||||||
B .
|
B .
|
||||||
|
|
||||||
.globl pivot_stack
|
.globl pivot_stack
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ extern sdmmc_storage_t sd_storage;
|
|||||||
extern FATFS sd_fs;
|
extern FATFS sd_fs;
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
emummc_cfg_t emu_cfg;
|
||||||
|
|
||||||
extern bool sd_mount();
|
extern bool sd_mount();
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
@@ -47,7 +48,8 @@ bool emummc_load_cfg()
|
|||||||
emu_cfg.file_based_part_size = 0;
|
emu_cfg.file_based_part_size = 0;
|
||||||
emu_cfg.active_part = 0;
|
emu_cfg.active_part = 0;
|
||||||
emu_cfg.fs_ver = 0;
|
emu_cfg.fs_ver = 0;
|
||||||
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
if (!emu_cfg.emummc_file_based_path)
|
||||||
|
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||||
|
|
||||||
LIST_INIT(ini_sections);
|
LIST_INIT(ini_sections);
|
||||||
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
|
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
|
||||||
@@ -98,7 +100,7 @@ static int emummc_raw_get_part_off(int part_idx)
|
|||||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
||||||
{
|
{
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
|
|
||||||
@@ -139,7 +141,6 @@ out:
|
|||||||
|
|
||||||
int emummc_storage_end(sdmmc_storage_t *storage)
|
int emummc_storage_end(sdmmc_storage_t *storage)
|
||||||
{
|
{
|
||||||
sd_unmount();
|
|
||||||
sdmmc_storage_end(storage);
|
sdmmc_storage_end(storage);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ typedef struct _emummc_cfg_t
|
|||||||
int fs_ver;
|
int fs_ver;
|
||||||
} emummc_cfg_t;
|
} emummc_cfg_t;
|
||||||
|
|
||||||
emummc_cfg_t emu_cfg;
|
extern emummc_cfg_t emu_cfg;
|
||||||
|
|
||||||
bool emummc_load_cfg();
|
bool emummc_load_cfg();
|
||||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
|
|||||||
84
source/storage/mbr_gpt.h
Normal file
84
source/storage/mbr_gpt.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBR_GPT_H
|
||||||
|
#define MBR_GPT_H
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef struct _mbr_chs_t
|
||||||
|
{
|
||||||
|
u8 head;
|
||||||
|
u8 sector;
|
||||||
|
u8 cylinder;
|
||||||
|
} __attribute__((packed)) mbr_chs_t;
|
||||||
|
|
||||||
|
typedef struct _mbr_part_t
|
||||||
|
{
|
||||||
|
u8 status;
|
||||||
|
mbr_chs_t start_sct_chs;
|
||||||
|
u8 type;
|
||||||
|
mbr_chs_t end_sct_chs;
|
||||||
|
u32 start_sct;
|
||||||
|
u32 size_sct;
|
||||||
|
} __attribute__((packed)) mbr_part_t;
|
||||||
|
|
||||||
|
typedef struct _mbr_t
|
||||||
|
{
|
||||||
|
u8 bootstrap[0x1B8];
|
||||||
|
u32 signature;
|
||||||
|
u16 copy_protected;
|
||||||
|
mbr_part_t partitions[4];
|
||||||
|
u16 boot_signature;
|
||||||
|
} __attribute__((packed)) mbr_t;
|
||||||
|
|
||||||
|
typedef struct _gpt_entry_t
|
||||||
|
{
|
||||||
|
u8 type_guid[0x10];
|
||||||
|
u8 part_guid[0x10];
|
||||||
|
u64 lba_start;
|
||||||
|
u64 lba_end;
|
||||||
|
u64 attrs;
|
||||||
|
u16 name[36];
|
||||||
|
} gpt_entry_t;
|
||||||
|
|
||||||
|
typedef struct _gpt_header_t
|
||||||
|
{
|
||||||
|
u64 signature; // "EFI PART"
|
||||||
|
u32 revision;
|
||||||
|
u32 size;
|
||||||
|
u32 crc32;
|
||||||
|
u32 res1;
|
||||||
|
u64 my_lba;
|
||||||
|
u64 alt_lba;
|
||||||
|
u64 first_use_lba;
|
||||||
|
u64 last_use_lba;
|
||||||
|
u8 disk_guid[0x10];
|
||||||
|
u64 part_ent_lba;
|
||||||
|
u32 num_part_ents;
|
||||||
|
u32 part_ent_size;
|
||||||
|
u32 part_ents_crc32;
|
||||||
|
u8 res2[420]; // Used as first 3 partition entries backup for HOS.
|
||||||
|
} gpt_header_t;
|
||||||
|
|
||||||
|
typedef struct _gpt_t
|
||||||
|
{
|
||||||
|
gpt_header_t header;
|
||||||
|
gpt_entry_t entries[128];
|
||||||
|
} gpt_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
|
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
|
||||||
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
|
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
|
||||||
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
|
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
|
||||||
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
|
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
|
||||||
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
|
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
|
||||||
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
|
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
|
||||||
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
|
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
|
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
|
||||||
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
|
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
|
||||||
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
|
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
|
||||||
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
|
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
|
||||||
|
|
||||||
/* class 3 */
|
/* class 3 */
|
||||||
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
|
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mbr_gpt.h"
|
||||||
#include "nx_emmc.h"
|
#include "nx_emmc.h"
|
||||||
#include "emummc.h"
|
#include "emummc.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
@@ -23,28 +24,31 @@
|
|||||||
|
|
||||||
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
||||||
{
|
{
|
||||||
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
gpt_t *gpt_buf = (gpt_t *)calloc(NX_GPT_NUM_BLOCKS, NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf);
|
||||||
|
|
||||||
gpt_header_t *hdr = (gpt_header_t *)buf;
|
for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)
|
||||||
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
|
||||||
{
|
{
|
||||||
gpt_entry_t *ent = (gpt_entry_t *)(buf + (hdr->part_ent_lba - 1) * NX_EMMC_BLOCKSIZE + i * sizeof(gpt_entry_t));
|
emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1);
|
||||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
|
||||||
part->lba_start = ent->lba_start;
|
if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)
|
||||||
part->lba_end = ent->lba_end;
|
continue;
|
||||||
part->attrs = ent->attrs;
|
|
||||||
|
part->index = i;
|
||||||
|
part->lba_start = gpt_buf->entries[i].lba_start;
|
||||||
|
part->lba_end = gpt_buf->entries[i].lba_end;
|
||||||
|
part->attrs = gpt_buf->entries[i].attrs;
|
||||||
|
|
||||||
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
|
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
|
||||||
for (u32 i = 0; i < 36; i++)
|
for (u32 j = 0; j < 36; j++)
|
||||||
part->name[i] = ent->name[i];
|
part->name[j] = gpt_buf->entries[i].name[j];
|
||||||
part->name[36] = 0;
|
part->name[35] = 0;
|
||||||
|
|
||||||
list_append(gpt, &part->link);
|
list_append(gpt, &part->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(gpt_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nx_emmc_gpt_free(link_t *gpt)
|
void nx_emmc_gpt_free(link_t *gpt)
|
||||||
@@ -74,5 +78,5 @@ int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_o
|
|||||||
// The last LBA is inclusive.
|
// The last LBA is inclusive.
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
if (part->lba_start + sector_off > part->lba_end)
|
||||||
return 0;
|
return 0;
|
||||||
return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf);
|
return emummc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,38 +17,9 @@
|
|||||||
#ifndef _NX_EMMC_H_
|
#ifndef _NX_EMMC_H_
|
||||||
#define _NX_EMMC_H_
|
#define _NX_EMMC_H_
|
||||||
|
|
||||||
|
#include "sdmmc.h"
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
#include "../utils/list.h"
|
#include "../utils/list.h"
|
||||||
#include "sdmmc.h"
|
|
||||||
|
|
||||||
typedef struct _gpt_entry_t
|
|
||||||
{
|
|
||||||
u8 type_guid[0x10];
|
|
||||||
u8 part_guid[0x10];
|
|
||||||
u64 lba_start;
|
|
||||||
u64 lba_end;
|
|
||||||
u64 attrs;
|
|
||||||
u16 name[36];
|
|
||||||
} gpt_entry_t;
|
|
||||||
|
|
||||||
typedef struct _gpt_header_t
|
|
||||||
{
|
|
||||||
u64 signature;
|
|
||||||
u32 revision;
|
|
||||||
u32 size;
|
|
||||||
u32 crc32;
|
|
||||||
u32 res1;
|
|
||||||
u64 my_lba;
|
|
||||||
u64 alt_lba;
|
|
||||||
u64 first_use_lba;
|
|
||||||
u64 last_use_lba;
|
|
||||||
u8 disk_guid[0x10];
|
|
||||||
u64 part_ent_lba;
|
|
||||||
u32 num_part_ents;
|
|
||||||
u32 part_ent_size;
|
|
||||||
u32 part_ents_crc32;
|
|
||||||
u8 res2[420];
|
|
||||||
} gpt_header_t;
|
|
||||||
|
|
||||||
#define NX_GPT_FIRST_LBA 1
|
#define NX_GPT_FIRST_LBA 1
|
||||||
#define NX_GPT_NUM_BLOCKS 33
|
#define NX_GPT_NUM_BLOCKS 33
|
||||||
@@ -56,6 +27,7 @@ typedef struct _gpt_header_t
|
|||||||
|
|
||||||
typedef struct _emmc_part_t
|
typedef struct _emmc_part_t
|
||||||
{
|
{
|
||||||
|
u32 index;
|
||||||
u32 lba_start;
|
u32 lba_start;
|
||||||
u32 lba_end;
|
u32 lba_end;
|
||||||
u64 attrs;
|
u64 attrs;
|
||||||
|
|||||||
185
source/storage/nx_sd.c
Normal file
185
source/storage/nx_sd.c
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nx_sd.h"
|
||||||
|
#include "sdmmc.h"
|
||||||
|
#include "sdmmc_driver.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
|
||||||
|
bool sd_mounted = false, sd_inited = false;
|
||||||
|
static u32 sd_mode = SD_UHS_SDR82;
|
||||||
|
|
||||||
|
sdmmc_t sd_sdmmc;
|
||||||
|
sdmmc_storage_t sd_storage;
|
||||||
|
FATFS sd_fs;
|
||||||
|
|
||||||
|
u32 sd_get_mode()
|
||||||
|
{
|
||||||
|
return sd_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_init_retry(bool power_cycle)
|
||||||
|
{
|
||||||
|
u32 bus_width = SDMMC_BUS_WIDTH_4;
|
||||||
|
u32 type = SDHCI_TIMING_UHS_SDR82;
|
||||||
|
|
||||||
|
// Power cycle SD card.
|
||||||
|
if (power_cycle)
|
||||||
|
{
|
||||||
|
sd_mode--;
|
||||||
|
sdmmc_storage_end(&sd_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get init parameters.
|
||||||
|
switch (sd_mode)
|
||||||
|
{
|
||||||
|
case SD_INIT_FAIL: // Reset to max.
|
||||||
|
return 0;
|
||||||
|
case SD_1BIT_HS25:
|
||||||
|
bus_width = SDMMC_BUS_WIDTH_1;
|
||||||
|
type = SDHCI_TIMING_SD_HS25;
|
||||||
|
break;
|
||||||
|
case SD_4BIT_HS25:
|
||||||
|
type = SDHCI_TIMING_SD_HS25;
|
||||||
|
break;
|
||||||
|
case SD_UHS_SDR82:
|
||||||
|
type = SDHCI_TIMING_UHS_SDR82;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sd_mode = SD_UHS_SDR82;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sd_initialize(bool power_cycle)
|
||||||
|
{
|
||||||
|
if (power_cycle)
|
||||||
|
sdmmc_storage_end(&sd_storage);
|
||||||
|
|
||||||
|
int res = !sd_init_retry(false);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!res)
|
||||||
|
return true;
|
||||||
|
else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted.
|
||||||
|
{
|
||||||
|
sd_mode = SD_UHS_SDR82;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (sd_mode == SD_INIT_FAIL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
res = !sd_init_retry(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_storage_end(&sd_storage);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sd_mount()
|
||||||
|
{
|
||||||
|
if (sd_mounted)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
sd_inited = sd_initialize(false);
|
||||||
|
int res = !sd_inited;
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
gfx_con.mute = false;
|
||||||
|
EPRINTF("Failed to init SD card.");
|
||||||
|
if (!sdmmc_get_sd_inserted())
|
||||||
|
EPRINTF("Make sure that it is inserted.");
|
||||||
|
else
|
||||||
|
EPRINTF("SD Card Reader is not properly seated!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = f_mount(&sd_fs, "", 1);
|
||||||
|
if (res == FR_OK)
|
||||||
|
{
|
||||||
|
sd_mounted = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gfx_con.mute = false;
|
||||||
|
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sd_unmount()
|
||||||
|
{
|
||||||
|
sd_mode = SD_UHS_SDR82;
|
||||||
|
if (sd_mounted)
|
||||||
|
{
|
||||||
|
f_mount(NULL, "", 1);
|
||||||
|
sdmmc_storage_end(&sd_storage);
|
||||||
|
sd_mounted = false;
|
||||||
|
sd_inited = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *sd_file_read(const char *path, u32 *fsize)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
u32 size = f_size(&fp);
|
||||||
|
if (fsize)
|
||||||
|
*fsize = size;
|
||||||
|
|
||||||
|
void *buf = malloc(size);
|
||||||
|
|
||||||
|
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_save_to_file(void *buf, u32 size, const char *filename)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
u32 res = 0;
|
||||||
|
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_write(&fp, buf, size, NULL);
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
45
source/storage/nx_sd.h
Normal file
45
source/storage/nx_sd.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NX_SD_H
|
||||||
|
#define NX_SD_H
|
||||||
|
|
||||||
|
#include "sdmmc.h"
|
||||||
|
#include "sdmmc_driver.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SD_INIT_FAIL = 0,
|
||||||
|
SD_1BIT_HS25 = 1,
|
||||||
|
SD_4BIT_HS25 = 2,
|
||||||
|
SD_UHS_SDR82 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern sdmmc_t sd_sdmmc;
|
||||||
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
extern FATFS sd_fs;
|
||||||
|
|
||||||
|
u32 sd_get_mode();
|
||||||
|
int sd_init_retry(bool power_cycle);
|
||||||
|
bool sd_initialize(bool power_cycle);
|
||||||
|
bool sd_mount();
|
||||||
|
void sd_unmount();
|
||||||
|
void *sd_file_read(const char *path, u32 *fsize);
|
||||||
|
int sd_save_to_file(void *buf, u32 size, const char *filename);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -106,6 +106,11 @@
|
|||||||
#define SD_SET_CURRENT_LIMIT_600 2
|
#define SD_SET_CURRENT_LIMIT_600 2
|
||||||
#define SD_SET_CURRENT_LIMIT_800 3
|
#define SD_SET_CURRENT_LIMIT_800 3
|
||||||
|
|
||||||
|
#define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
|
||||||
|
#define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400)
|
||||||
|
#define SD_MAX_CURRENT_600 (1 << SD_SET_CURRENT_LIMIT_600)
|
||||||
|
#define SD_MAX_CURRENT_800 (1 << SD_SET_CURRENT_LIMIT_800)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SD_SWITCH mode
|
* SD_SWITCH mode
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
#include "mmc.h"
|
#include "mmc.h"
|
||||||
|
#include "nx_sd.h"
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
#include "../../common/memory_map.h"
|
#include "../../common/memory_map.h"
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
@@ -135,10 +136,12 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage)
|
|||||||
|
|
||||||
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
||||||
{
|
{
|
||||||
|
u32 tmp = 0;
|
||||||
sdmmc_cmd_t cmdbuf;
|
sdmmc_cmd_t cmdbuf;
|
||||||
|
sdmmc_req_t reqbuf;
|
||||||
|
|
||||||
sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);
|
sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);
|
||||||
|
|
||||||
sdmmc_req_t reqbuf;
|
|
||||||
reqbuf.buf = buf;
|
reqbuf.buf = buf;
|
||||||
reqbuf.num_sectors = num_sectors;
|
reqbuf.num_sectors = num_sectors;
|
||||||
reqbuf.blksize = 512;
|
reqbuf.blksize = 512;
|
||||||
@@ -148,7 +151,6 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
|||||||
|
|
||||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out))
|
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out))
|
||||||
{
|
{
|
||||||
u32 tmp = 0;
|
|
||||||
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
||||||
_sdmmc_storage_get_status(storage, &tmp, 0);
|
_sdmmc_storage_get_status(storage, &tmp, 0);
|
||||||
|
|
||||||
@@ -171,25 +173,42 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
|||||||
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
||||||
{
|
{
|
||||||
u8 *bbuf = (u8 *)buf;
|
u8 *bbuf = (u8 *)buf;
|
||||||
|
bool first_reinit = false;
|
||||||
while (num_sectors)
|
while (num_sectors)
|
||||||
{
|
{
|
||||||
u32 blkcnt = 0;
|
u32 blkcnt = 0;
|
||||||
//Retry 9 times on error.
|
// Retry 5 times if failed.
|
||||||
u32 retries = 10;
|
u32 retries = 5;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
reinit_try:
|
||||||
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write))
|
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write))
|
||||||
goto out;
|
goto out;
|
||||||
else
|
else
|
||||||
retries--;
|
retries--;
|
||||||
|
|
||||||
msleep(100);
|
msleep(50);
|
||||||
} while (retries);
|
} while (retries);
|
||||||
|
|
||||||
|
// Disk IO failure! Reinit SD Card to a lower speed.
|
||||||
|
if (storage->sdmmc->id == SDMMC_1)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
if (!first_reinit)
|
||||||
|
res = sd_initialize(true);
|
||||||
|
else
|
||||||
|
res = sd_init_retry(true);
|
||||||
|
|
||||||
|
retries = 3;
|
||||||
|
first_reinit = true;
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
goto reinit_try;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:;
|
out:
|
||||||
DPRINTF("readwrite: %08X\n", blkcnt);
|
DPRINTF("readwrite: %08X\n", blkcnt);
|
||||||
sector += blkcnt;
|
sector += blkcnt;
|
||||||
num_sectors -= blkcnt;
|
num_sectors -= blkcnt;
|
||||||
@@ -201,12 +220,34 @@ DPRINTF("readwrite: %08X\n", blkcnt);
|
|||||||
|
|
||||||
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||||
{
|
{
|
||||||
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
|
// Ensure that buffer resides in DRAM and it's DMA aligned.
|
||||||
|
if (((u32)buf >= DRAM_START) && !((u32)buf % 8))
|
||||||
|
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
|
||||||
|
|
||||||
|
if (num_sectors > (SDMMC_UP_BUF_SZ / 512))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||||
|
if (_sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 0))
|
||||||
|
{
|
||||||
|
memcpy(buf, tmp_buf, 512 * num_sectors);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||||
{
|
{
|
||||||
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
|
// Ensure that buffer resides in DRAM and it's DMA aligned.
|
||||||
|
if (((u32)buf >= DRAM_START) && !((u32)buf % 8))
|
||||||
|
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
|
||||||
|
|
||||||
|
if (num_sectors > (SDMMC_UP_BUF_SZ / 512))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||||
|
memcpy(tmp_buf, buf, 512 * num_sectors);
|
||||||
|
return _sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -401,7 +442,7 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
|
|||||||
if (check && !_sdmmc_storage_check_status(storage))
|
if (check && !_sdmmc_storage_check_status(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[MMC] switched to HS\n");
|
DPRINTF("[MMC] switched to HS\n");
|
||||||
@@ -418,10 +459,10 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
|
|||||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[MMC] switched to HS200\n");
|
DPRINTF("[MMC] switched to HS200\n");
|
||||||
@@ -435,7 +476,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||||||
if (!_mmc_storage_enable_HS200(storage))
|
if (!_mmc_storage_enable_HS200(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdmmc_get_venclkctl(storage->sdmmc);
|
sdmmc_set_tap_value(storage->sdmmc);
|
||||||
|
|
||||||
if (!_mmc_storage_enable_HS(storage, 0))
|
if (!_mmc_storage_enable_HS(storage, 0))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -446,7 +487,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[MMC] switched to HS400\n");
|
DPRINTF("[MMC] switched to HS400\n");
|
||||||
@@ -457,22 +498,20 @@ DPRINTF("[MMC] switched to HS400\n");
|
|||||||
|
|
||||||
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
||||||
{
|
{
|
||||||
//TODO: this should be a config item.
|
if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||||
// --v
|
|
||||||
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
||||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
|
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400)
|
||||||
return _mmc_storage_enable_HS400(storage);
|
return _mmc_storage_enable_HS400(storage);
|
||||||
|
|
||||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
||||||
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
|
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
|
||||||
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
|
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
|
||||||
&& (type == 4 || type == 3)))
|
&& (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)))
|
||||||
return _mmc_storage_enable_HS200(storage);
|
return _mmc_storage_enable_HS200(storage);
|
||||||
|
|
||||||
out:;
|
out:
|
||||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||||
return _mmc_storage_enable_HS(storage, 1);
|
return _mmc_storage_enable_HS(storage, 1);
|
||||||
|
|
||||||
@@ -487,13 +526,13 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
|
|||||||
return _sdmmc_storage_check_status(storage);
|
return _sdmmc_storage_check_status(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
|
||||||
{
|
{
|
||||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||||
storage->sdmmc = sdmmc;
|
storage->sdmmc = sdmmc;
|
||||||
storage->rca = 2; //TODO: this could be a config item.
|
storage->rca = 2; //TODO: this could be a config item.
|
||||||
|
|
||||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
|
if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[MMC] after init\n");
|
DPRINTF("[MMC] after init\n");
|
||||||
|
|
||||||
@@ -520,7 +559,7 @@ DPRINTF("[MMC] set relative addr\n");
|
|||||||
DPRINTF("[MMC] got csd\n");
|
DPRINTF("[MMC] got csd\n");
|
||||||
_mmc_storage_parse_csd(storage);
|
_mmc_storage_parse_csd(storage);
|
||||||
|
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 1))
|
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[MMC] after setup clock\n");
|
DPRINTF("[MMC] after setup clock\n");
|
||||||
|
|
||||||
@@ -544,35 +583,27 @@ DPRINTF("[MMC] set blocklen to 512\n");
|
|||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[MMC] switched buswidth\n");
|
DPRINTF("[MMC] switched buswidth\n");
|
||||||
|
|
||||||
u8 *ext_csd = (u8 *)malloc(512);
|
if (!_mmc_storage_get_ext_csd(storage, (u8 *)SDMMC_UPPER_BUFFER))
|
||||||
if (!_mmc_storage_get_ext_csd(storage, ext_csd))
|
|
||||||
{
|
|
||||||
free(ext_csd);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
free(ext_csd);
|
|
||||||
DPRINTF("[MMC] got ext_csd\n");
|
DPRINTF("[MMC] got ext_csd\n");
|
||||||
|
|
||||||
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
|
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
|
||||||
//gfx_hexdump(0, ext_csd, 512);
|
//gfx_hexdump(0, ext_csd, 512);
|
||||||
|
|
||||||
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
|
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
|
||||||
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
||||||
Additionally this works only when we put the device in idle mode which we don't after enabling it. */
|
Additionally this works only when we put the device in idle mode which we don't after enabling it. */
|
||||||
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
|
if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2))
|
||||||
{
|
{
|
||||||
_mmc_storage_enable_bkops(storage);
|
_mmc_storage_enable_bkops(storage);
|
||||||
DPRINTF("[MMC] BKOPS enabled\n");
|
DPRINTF("[MMC] BKOPS enabled\n");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINTF("[MMC] BKOPS disabled\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
|
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[MMC] succesfully switched to HS mode\n");
|
DPRINTF("[MMC] succesfully switched to HS mode\n");
|
||||||
|
|
||||||
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
|
sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -656,6 +687,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
|||||||
if (cond & SD_OCR_CCS)
|
if (cond & SD_OCR_CCS)
|
||||||
storage->has_sector_access = 1;
|
storage->has_sector_access = 1;
|
||||||
|
|
||||||
|
// Check if card supports 1.8V signaling.
|
||||||
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
||||||
{
|
{
|
||||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||||
@@ -804,34 +836,37 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group,
|
|||||||
return _sdmmc_storage_check_result(tmp);
|
return _sdmmc_storage_check_result(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf)
|
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf)
|
||||||
{
|
{
|
||||||
u32 pwr = SD_SET_CURRENT_LIMIT_800;
|
u32 pwr = SD_SET_CURRENT_LIMIT_200;
|
||||||
|
|
||||||
|
if (current_limit & SD_MAX_CURRENT_800)
|
||||||
|
pwr = SD_SET_CURRENT_LIMIT_800;
|
||||||
|
else if (current_limit & SD_MAX_CURRENT_600)
|
||||||
|
pwr = SD_SET_CURRENT_LIMIT_600;
|
||||||
|
else if (current_limit & SD_MAX_CURRENT_400)
|
||||||
|
pwr = SD_SET_CURRENT_LIMIT_400;
|
||||||
|
|
||||||
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
|
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
|
||||||
|
|
||||||
while (pwr > 0)
|
if (((buf[15] >> 4) & 0x0F) == pwr)
|
||||||
{
|
{
|
||||||
pwr--;
|
switch (pwr)
|
||||||
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
|
{
|
||||||
if (((buf[15] >> 4) & 0x0F) == pwr)
|
case SD_SET_CURRENT_LIMIT_800:
|
||||||
|
DPRINTF("[SD] power limit raised to 800mA\n");
|
||||||
break;
|
break;
|
||||||
}
|
case SD_SET_CURRENT_LIMIT_600:
|
||||||
|
|
||||||
switch (pwr)
|
|
||||||
{
|
|
||||||
case SD_SET_CURRENT_LIMIT_800:
|
|
||||||
DPRINTF("[SD] power limit raised to 800mA\n");
|
|
||||||
break;
|
|
||||||
case SD_SET_CURRENT_LIMIT_600:
|
|
||||||
DPRINTF("[SD] power limit raised to 600mA\n");
|
DPRINTF("[SD] power limit raised to 600mA\n");
|
||||||
break;
|
break;
|
||||||
case SD_SET_CURRENT_LIMIT_400:
|
case SD_SET_CURRENT_LIMIT_400:
|
||||||
DPRINTF("[SD] power limit raised to 800mA\n");
|
DPRINTF("[SD] power limit raised to 400mA\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case SD_SET_CURRENT_LIMIT_200:
|
case SD_SET_CURRENT_LIMIT_200:
|
||||||
DPRINTF("[SD] power limit defaulted to 200mA\n");
|
DPRINTF("[SD] power limit defaulted to 200mA\n");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,30 +874,33 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
|
|||||||
{
|
{
|
||||||
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] SD supports switch to (U)HS check\n");
|
DPRINTF("[SD] supports switch to (U)HS mode\n");
|
||||||
|
|
||||||
u32 type_out = buf[16] & 0xF;
|
u32 type_out = buf[16] & 0xF;
|
||||||
if (type_out != hs_type)
|
if (type_out != hs_type)
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] SD supports selected (U)HS mode\n");
|
DPRINTF("[SD] supports selected (U)HS mode\n");
|
||||||
|
|
||||||
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
|
||||||
|
DPRINTF("[SD] total max current: %d\n", total_pwr_consumption);
|
||||||
|
|
||||||
|
if (total_pwr_consumption <= 800)
|
||||||
{
|
{
|
||||||
if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type))
|
if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (type_out != (buf[16] & 0xF))
|
if (type_out != (buf[16] & 0xF))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
DPRINTF("[SD] card max current over limit\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
|
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
|
||||||
{
|
{
|
||||||
// Try to raise the current limit to let the card perform better.
|
|
||||||
_sd_storage_set_current_limit(storage, buf);
|
|
||||||
|
|
||||||
if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4)
|
if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -870,32 +908,55 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||||
|
|
||||||
|
u8 access_mode = buf[13];
|
||||||
|
u16 current_limit = buf[7] | buf[6] << 8;
|
||||||
|
|
||||||
|
// Try to raise the current limit to let the card perform better.
|
||||||
|
_sd_storage_set_current_limit(storage, current_limit, buf);
|
||||||
|
|
||||||
u32 hs_type = 0;
|
u32 hs_type = 0;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 11: // SDR104.
|
case SDHCI_TIMING_UHS_SDR104:
|
||||||
|
case SDHCI_TIMING_UHS_SDR82:
|
||||||
// Fall through if not supported.
|
// Fall through if not supported.
|
||||||
if (buf[13] & SD_MODE_UHS_SDR104)
|
if (access_mode & SD_MODE_UHS_SDR104)
|
||||||
{
|
{
|
||||||
type = 11;
|
|
||||||
hs_type = UHS_SDR104_BUS_SPEED;
|
hs_type = UHS_SDR104_BUS_SPEED;
|
||||||
DPRINTF("[SD] bus speed set to SDR104\n");
|
DPRINTF("[SD] bus speed set to SDR104\n");
|
||||||
storage->csd.busspeed = 104;
|
switch (type)
|
||||||
|
{
|
||||||
|
case SDHCI_TIMING_UHS_SDR104:
|
||||||
|
storage->csd.busspeed = 104;
|
||||||
|
break;
|
||||||
|
case SDHCI_TIMING_UHS_SDR82:
|
||||||
|
storage->csd.busspeed = 82;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 10: // SDR50.
|
case SDHCI_TIMING_UHS_SDR50:
|
||||||
if (buf[13] & SD_MODE_UHS_SDR50)
|
if (access_mode & SD_MODE_UHS_SDR50)
|
||||||
{
|
{
|
||||||
type = 10;
|
type = SDHCI_TIMING_UHS_SDR50;
|
||||||
hs_type = UHS_SDR50_BUS_SPEED;
|
hs_type = UHS_SDR50_BUS_SPEED;
|
||||||
DPRINTF("[SD] bus speed set to SDR50\n");
|
DPRINTF("[SD] bus speed set to SDR50\n");
|
||||||
storage->csd.busspeed = 50;
|
storage->csd.busspeed = 50;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 8: // SDR12.
|
case SDHCI_TIMING_UHS_SDR25:
|
||||||
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
if (access_mode & SD_MODE_UHS_SDR25)
|
||||||
|
{
|
||||||
|
type = SDHCI_TIMING_UHS_SDR25;
|
||||||
|
hs_type = UHS_SDR50_BUS_SPEED;
|
||||||
|
DPRINTF("[SD] bus speed set to SDR25\n");
|
||||||
|
storage->csd.busspeed = 25;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDHCI_TIMING_UHS_SDR12:
|
||||||
|
if (!(access_mode & SD_MODE_UHS_SDR12))
|
||||||
return 0;
|
return 0;
|
||||||
type = 8;
|
type = SDHCI_TIMING_UHS_SDR12;
|
||||||
hs_type = UHS_SDR12_BUS_SPEED;
|
hs_type = UHS_SDR12_BUS_SPEED;
|
||||||
DPRINTF("[SD] bus speed set to SDR12\n");
|
DPRINTF("[SD] bus speed set to SDR12\n");
|
||||||
storage->csd.busspeed = 12;
|
storage->csd.busspeed = 12;
|
||||||
@@ -907,11 +968,11 @@ DPRINTF("[SD] bus speed set to SDR12\n");
|
|||||||
|
|
||||||
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] SD card accepted UHS\n");
|
DPRINTF("[SD] card accepted UHS\n");
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] setup clock\n");
|
DPRINTF("[SD] setup clock\n");
|
||||||
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] config tuning\n");
|
DPRINTF("[SD] config tuning\n");
|
||||||
return _sdmmc_storage_check_status(storage);
|
return _sdmmc_storage_check_status(storage);
|
||||||
@@ -922,16 +983,23 @@ int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
|||||||
if (!_sd_storage_switch_get(storage, buf))
|
if (!_sd_storage_switch_get(storage, buf))
|
||||||
return 0;
|
return 0;
|
||||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||||
if (!(buf[13] & SD_MODE_HIGH_SPEED))
|
|
||||||
|
u8 access_mode = buf[13];
|
||||||
|
u16 current_limit = buf[7] | buf[6] << 8;
|
||||||
|
|
||||||
|
// Try to raise the current limit to let the card perform better.
|
||||||
|
_sd_storage_set_current_limit(storage, current_limit, buf);
|
||||||
|
|
||||||
|
if (!(access_mode & SD_MODE_HIGH_SPEED))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!_sdmmc_storage_check_status(storage))
|
if (!_sdmmc_storage_check_status(storage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||||
@@ -1055,6 +1123,23 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SDHCI_TIMING_UHS_SDR12:
|
||||||
|
case SDHCI_TIMING_UHS_SDR25:
|
||||||
|
case SDHCI_TIMING_UHS_SDR50:
|
||||||
|
case SDHCI_TIMING_UHS_SDR104:
|
||||||
|
case SDHCI_TIMING_UHS_SDR82:
|
||||||
|
case SDHCI_TIMING_UHS_DDR50:
|
||||||
|
if (bus_width == SDMMC_BUS_WIDTH_4)
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sdmmc_storage_init_wait_sd()
|
void sdmmc_storage_init_wait_sd()
|
||||||
{
|
{
|
||||||
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
|
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
|
||||||
@@ -1062,7 +1147,7 @@ void sdmmc_storage_init_wait_sd()
|
|||||||
msleep(100 - sd_poweroff_time);
|
msleep(100 - sd_poweroff_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
|
||||||
{
|
{
|
||||||
int is_version_1 = 0;
|
int is_version_1 = 0;
|
||||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||||
@@ -1073,7 +1158,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||||
storage->sdmmc = sdmmc;
|
storage->sdmmc = sdmmc;
|
||||||
|
|
||||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
|
if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] after init\n");
|
DPRINTF("[SD] after init\n");
|
||||||
|
|
||||||
@@ -1088,7 +1173,9 @@ DPRINTF("[SD] went to idle state\n");
|
|||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] after send if cond\n");
|
DPRINTF("[SD] after send if cond\n");
|
||||||
|
|
||||||
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11))
|
bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type);
|
||||||
|
|
||||||
|
if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] got op cond\n");
|
DPRINTF("[SD] got op cond\n");
|
||||||
|
|
||||||
@@ -1122,7 +1209,7 @@ DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
|
|||||||
|
|
||||||
if (!storage->is_low_voltage)
|
if (!storage->is_low_voltage)
|
||||||
{
|
{
|
||||||
if (!sdmmc_setup_clock(storage->sdmmc, 6))
|
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] after setup clock\n");
|
DPRINTF("[SD] after setup clock\n");
|
||||||
}
|
}
|
||||||
@@ -1165,18 +1252,26 @@ DPRINTF("[SD] SD does not support wide bus width\n");
|
|||||||
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
|
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] enabled UHS\n");
|
DPRINTF("[SD] enabled UHS\n");
|
||||||
|
|
||||||
|
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||||
}
|
}
|
||||||
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||||
{
|
{
|
||||||
if (!_sd_storage_enable_hs_high_volt(storage, buf))
|
if (!_sd_storage_enable_hs_high_volt(storage, buf))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DPRINTF("[SD] enabled HS\n");
|
DPRINTF("[SD] enabled HS\n");
|
||||||
storage->csd.busspeed = 25;
|
switch (bus_width)
|
||||||
|
{
|
||||||
|
case SDMMC_BUS_WIDTH_4:
|
||||||
|
storage->csd.busspeed = 25;
|
||||||
|
break;
|
||||||
|
case SDMMC_BUS_WIDTH_1:
|
||||||
|
storage->csd.busspeed = 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
|
||||||
|
|
||||||
// Parse additional card info from sd status.
|
// Parse additional card info from sd status.
|
||||||
if (_sd_storage_get_ssr(storage, buf))
|
if (_sd_storage_get_ssr(storage, buf))
|
||||||
{
|
{
|
||||||
@@ -1222,17 +1317,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
|||||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||||
storage->sdmmc = sdmmc;
|
storage->sdmmc = sdmmc;
|
||||||
|
|
||||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
|
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[gc] after init\n");
|
DPRINTF("[gc] after init\n");
|
||||||
|
|
||||||
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||||
|
|
||||||
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
|
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[gc] after tuning\n");
|
DPRINTF("[gc] after tuning\n");
|
||||||
|
|
||||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,17 @@
|
|||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
#include "sdmmc_driver.h"
|
#include "sdmmc_driver.h"
|
||||||
|
|
||||||
u32 sd_power_cycle_time_start;
|
extern u32 sd_power_cycle_time_start;
|
||||||
|
|
||||||
|
typedef enum _sdmmc_type
|
||||||
|
{
|
||||||
|
MMC_SD = 0,
|
||||||
|
MMC_EMMC = 1,
|
||||||
|
|
||||||
|
EMMC_GPP = 0,
|
||||||
|
EMMC_BOOT0 = 1,
|
||||||
|
EMMC_BOOT1 = 2
|
||||||
|
} sdmmc_type;
|
||||||
|
|
||||||
typedef struct _mmc_cid
|
typedef struct _mmc_cid
|
||||||
{
|
{
|
||||||
@@ -107,10 +117,10 @@ typedef struct _sdmmc_storage_t
|
|||||||
int sdmmc_storage_end(sdmmc_storage_t *storage);
|
int sdmmc_storage_end(sdmmc_storage_t *storage);
|
||||||
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
|
||||||
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||||
void sdmmc_storage_init_wait_sd();
|
void sdmmc_storage_init_wait_sd();
|
||||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
|
||||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -49,24 +50,158 @@
|
|||||||
#define SDMMC_MASKINT_NOERROR -1
|
#define SDMMC_MASKINT_NOERROR -1
|
||||||
#define SDMMC_MASKINT_ERROR -2
|
#define SDMMC_MASKINT_ERROR -2
|
||||||
|
|
||||||
/*! SDMMC host control 2 */
|
/*! SDMMC present state. */
|
||||||
#define SDHCI_CTRL_UHS_MASK 0xFFF8
|
#define SDHCI_CMD_INHIBIT 0x1
|
||||||
#define SDHCI_CTRL_VDD_330 0xFFF7
|
#define SDHCI_DATA_INHIBIT 0x2
|
||||||
#define SDHCI_CTRL_VDD_180 8
|
#define SDHCI_DOING_WRITE 0x100
|
||||||
#define SDHCI_CTRL_EXEC_TUNING 0x40
|
#define SDHCI_DOING_READ 0x200
|
||||||
#define SDHCI_CTRL_TUNED_CLK 0x80
|
#define SDHCI_SPACE_AVAILABLE 0x400
|
||||||
#define SDHCI_HOST_VERSION_4_EN 0x1000
|
#define SDHCI_DATA_AVAILABLE 0x800
|
||||||
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
|
#define SDHCI_CARD_PRESENT 0x10000
|
||||||
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
|
#define SDHCI_CD_STABLE 0x20000
|
||||||
|
#define SDHCI_CD_LVL 0x40000
|
||||||
|
#define SDHCI_WRITE_PROTECT 0x80000
|
||||||
|
#define SDHCI_DATA_LVL_MASK 0xF00000
|
||||||
|
#define SDHCI_DATA_0_LVL_MASK 0x100000
|
||||||
|
#define SDHCI_CMD_LVL 0x1000000
|
||||||
|
|
||||||
|
/*! SDMMC transfer mode. */
|
||||||
|
#define SDHCI_TRNS_DMA 0x01
|
||||||
|
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
||||||
|
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
||||||
|
#define SDHCI_TRNS_AUTO_CMD23 0x08
|
||||||
|
#define SDHCI_TRNS_AUTO_SEL 0x0C
|
||||||
|
#define SDHCI_TRNS_WRITE 0x00
|
||||||
|
#define SDHCI_TRNS_READ 0x10
|
||||||
|
#define SDHCI_TRNS_MULTI 0x20
|
||||||
|
|
||||||
|
/*! SDMMC command. */
|
||||||
|
#define SDHCI_CMD_RESP_MASK 0x3
|
||||||
|
#define SDHCI_CMD_RESP_NO_RESP 0x0
|
||||||
|
#define SDHCI_CMD_RESP_LEN136 0x1
|
||||||
|
#define SDHCI_CMD_RESP_LEN48 0x2
|
||||||
|
#define SDHCI_CMD_RESP_LEN48_BUSY 0x3
|
||||||
|
#define SDHCI_CMD_CRC 0x08
|
||||||
|
#define SDHCI_CMD_INDEX 0x10
|
||||||
|
#define SDHCI_CMD_DATA 0x20
|
||||||
|
#define SDHCI_CMD_ABORTCMD 0xC0
|
||||||
|
|
||||||
|
/*! SDMMC host control. */
|
||||||
|
#define SDHCI_CTRL_LED 0x01
|
||||||
|
#define SDHCI_CTRL_4BITBUS 0x02
|
||||||
|
#define SDHCI_CTRL_HISPD 0x04
|
||||||
|
#define SDHCI_CTRL_DMA_MASK 0x18
|
||||||
|
#define SDHCI_CTRL_SDMA 0x00
|
||||||
|
#define SDHCI_CTRL_ADMA1 0x08
|
||||||
|
#define SDHCI_CTRL_ADMA32 0x10
|
||||||
|
#define SDHCI_CTRL_ADMA64 0x18
|
||||||
|
#define SDHCI_CTRL_8BITBUS 0x20
|
||||||
|
#define SDHCI_CTRL_CDTEST_INS 0x40
|
||||||
|
#define SDHCI_CTRL_CDTEST_EN 0x80
|
||||||
|
|
||||||
|
/*! SDMMC host control 2. */
|
||||||
|
#define SDHCI_CTRL_UHS_MASK 0xFFF8
|
||||||
|
#define SDHCI_CTRL_VDD_180 8
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_B 0x00
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_A 0x10
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_C 0x20
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_D 0x30
|
||||||
|
#define SDHCI_CTRL_EXEC_TUNING 0x40
|
||||||
|
#define SDHCI_CTRL_TUNED_CLK 0x80
|
||||||
|
#define SDHCI_HOST_VERSION_4_EN 0x1000
|
||||||
|
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
|
||||||
|
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
|
||||||
|
|
||||||
|
/*! SDMMC power control. */
|
||||||
|
#define SDHCI_POWER_ON 0x01
|
||||||
|
#define SDHCI_POWER_180 0x0A
|
||||||
|
#define SDHCI_POWER_300 0x0C
|
||||||
|
#define SDHCI_POWER_330 0x0E
|
||||||
|
#define SDHCI_POWER_MASK 0xF1
|
||||||
|
|
||||||
|
// /*! SDMMC max current. */
|
||||||
|
// #define SDHCI_MAX_CURRENT_330_MASK 0xFF
|
||||||
|
// #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
|
||||||
|
// #define SDHCI_MAX_CURRENT_MULTIPLIER 4
|
||||||
|
|
||||||
|
/*! SDMMC clock control. */
|
||||||
|
#define SDHCI_DIVIDER_SHIFT 8
|
||||||
|
#define SDHCI_DIVIDER_HI_SHIFT 6
|
||||||
|
#define SDHCI_DIV_MASK 0xFF00
|
||||||
|
#define SDHCI_DIV_HI_MASK 0xC0
|
||||||
|
#define SDHCI_PROG_CLOCK_MODE 0x20
|
||||||
|
#define SDHCI_CLOCK_CARD_EN 0x4
|
||||||
|
#define SDHCI_CLOCK_INT_STABLE 0x2
|
||||||
|
#define SDHCI_CLOCK_INT_EN 0x1
|
||||||
|
|
||||||
|
/*! SDMMC software reset. */
|
||||||
|
#define SDHCI_RESET_ALL 0x01
|
||||||
|
#define SDHCI_RESET_CMD 0x02
|
||||||
|
#define SDHCI_RESET_DATA 0x04
|
||||||
|
|
||||||
|
/*! SDMMC interrupt status and control. */
|
||||||
|
#define SDHCI_INT_RESPONSE 0x1
|
||||||
|
#define SDHCI_INT_DATA_END 0x2
|
||||||
|
#define SDHCI_INT_BLK_GAP 0x4
|
||||||
|
#define SDHCI_INT_DMA_END 0x8
|
||||||
|
#define SDHCI_INT_SPACE_AVAIL 0x10
|
||||||
|
#define SDHCI_INT_DATA_AVAIL 0x20
|
||||||
|
#define SDHCI_INT_CARD_INSERT 0x40
|
||||||
|
#define SDHCI_INT_CARD_REMOVE 0x80
|
||||||
|
#define SDHCI_INT_CARD_INT 0x100
|
||||||
|
#define SDHCI_INT_RETUNE 0x1000
|
||||||
|
#define SDHCI_INT_CQE 0x4000
|
||||||
|
#define SDHCI_INT_ERROR 0x8000
|
||||||
|
|
||||||
|
/*! SDMMC error interrupt status and control. */
|
||||||
|
#define SDHCI_ERR_INT_TIMEOUT 0x1
|
||||||
|
#define SDHCI_ERR_INT_CRC 0x2
|
||||||
|
#define SDHCI_ERR_INT_END_BIT 0x4
|
||||||
|
#define SDHCI_ERR_INT_INDEX 0x8
|
||||||
|
#define SDHCI_ERR_INT_DATA_TIMEOUT 0x10
|
||||||
|
#define SDHCI_ERR_INT_DATA_CRC 0x20
|
||||||
|
#define SDHCI_ERR_INT_DATA_END_BIT 0x40
|
||||||
|
#define SDHCI_ERR_INT_BUS_POWER 0x80
|
||||||
|
#define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100
|
||||||
|
#define SDHCI_ERR_INT_ADMA_ERROR 0x200
|
||||||
|
|
||||||
|
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
|
||||||
|
(SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \
|
||||||
|
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
|
||||||
|
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
|
||||||
|
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
|
||||||
|
|
||||||
/*! SD bus speeds. */
|
/*! SD bus speeds. */
|
||||||
#define UHS_SDR12_BUS_SPEED 0
|
#define UHS_SDR12_BUS_SPEED 0
|
||||||
#define HIGH_SPEED_BUS_SPEED 1
|
#define HIGH_SPEED_BUS_SPEED 1
|
||||||
#define UHS_SDR25_BUS_SPEED 1
|
#define UHS_SDR25_BUS_SPEED 1
|
||||||
#define UHS_SDR50_BUS_SPEED 2
|
#define UHS_SDR50_BUS_SPEED 2
|
||||||
#define UHS_SDR104_BUS_SPEED 3
|
#define UHS_SDR104_BUS_SPEED 3
|
||||||
#define UHS_DDR50_BUS_SPEED 4
|
#define UHS_DDR50_BUS_SPEED 4
|
||||||
#define HS400_BUS_SPEED 5
|
#define HS400_BUS_SPEED 5
|
||||||
|
|
||||||
|
/*! SDMMC timmings. */
|
||||||
|
#define SDHCI_TIMING_MMC_ID 0
|
||||||
|
#define SDHCI_TIMING_MMC_LS26 1
|
||||||
|
#define SDHCI_TIMING_MMC_HS52 2
|
||||||
|
#define SDHCI_TIMING_MMC_HS200 3
|
||||||
|
#define SDHCI_TIMING_MMC_HS400 4
|
||||||
|
#define SDHCI_TIMING_SD_ID 5
|
||||||
|
#define SDHCI_TIMING_SD_DS12 6
|
||||||
|
#define SDHCI_TIMING_SD_HS25 7
|
||||||
|
#define SDHCI_TIMING_UHS_SDR12 8
|
||||||
|
#define SDHCI_TIMING_UHS_SDR25 9
|
||||||
|
#define SDHCI_TIMING_UHS_SDR50 10
|
||||||
|
#define SDHCI_TIMING_UHS_SDR104 11
|
||||||
|
#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock.
|
||||||
|
#define SDHCI_TIMING_UHS_DDR50 13
|
||||||
|
#define SDHCI_TIMING_MMC_DDR52 14
|
||||||
|
|
||||||
|
#define SDHCI_CAN_64BIT 0x10000000
|
||||||
|
|
||||||
|
/*! SDMMC Low power features. */
|
||||||
|
#define SDMMC_AUTO_CAL_DISABLE 0
|
||||||
|
#define SDMMC_AUTO_CAL_ENABLE 1
|
||||||
|
|
||||||
/*! Helper for SWITCH command argument. */
|
/*! Helper for SWITCH command argument. */
|
||||||
#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))
|
#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))
|
||||||
@@ -78,8 +213,8 @@ typedef struct _sdmmc_t
|
|||||||
u32 id;
|
u32 id;
|
||||||
u32 divisor;
|
u32 divisor;
|
||||||
u32 clock_stopped;
|
u32 clock_stopped;
|
||||||
int no_sd;
|
int auto_cal_enabled;
|
||||||
int sd_clock_enabled;
|
int card_clock_enabled;
|
||||||
int venclkctl_set;
|
int venclkctl_set;
|
||||||
u32 venclkctl_tap;
|
u32 venclkctl_tap;
|
||||||
u32 expected_rsp_type;
|
u32 expected_rsp_type;
|
||||||
@@ -108,19 +243,20 @@ typedef struct _sdmmc_req_t
|
|||||||
int is_auto_cmd12;
|
int is_auto_cmd12;
|
||||||
} sdmmc_req_t;
|
} sdmmc_req_t;
|
||||||
|
|
||||||
int sdmmc_get_voltage(sdmmc_t *sdmmc);
|
int sdmmc_get_io_power(sdmmc_t *sdmmc);
|
||||||
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc);
|
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc);
|
||||||
void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width);
|
void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width);
|
||||||
void sdmmc_get_venclkctl(sdmmc_t *sdmmc);
|
void sdmmc_set_tap_value(sdmmc_t *sdmmc);
|
||||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
|
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
|
||||||
void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd);
|
void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable);
|
||||||
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
|
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
|
||||||
int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd);
|
int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);
|
||||||
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
|
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
|
||||||
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd);
|
bool sdmmc_get_sd_inserted();
|
||||||
|
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable);
|
||||||
void sdmmc_end(sdmmc_t *sdmmc);
|
void sdmmc_end(sdmmc_t *sdmmc);
|
||||||
void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy);
|
void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy);
|
||||||
int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out);
|
int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out);
|
||||||
int sdmmc_enable_low_voltage(sdmmc_t *sdmmc);
|
int sdmmc_enable_low_voltage(sdmmc_t *sdmmc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,49 +20,14 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1
|
#define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000
|
||||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA
|
#define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000
|
||||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC
|
#define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000
|
||||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE
|
#define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000
|
||||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1
|
#define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0
|
||||||
|
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000
|
||||||
#define TEGRA_MMC_HOSTCTL_1BIT 0x00
|
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000
|
||||||
#define TEGRA_MMC_HOSTCTL_4BIT 0x02
|
#define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000
|
||||||
#define TEGRA_MMC_HOSTCTL_8BIT 0x20
|
|
||||||
|
|
||||||
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1
|
|
||||||
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2
|
|
||||||
#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4
|
|
||||||
#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20
|
|
||||||
|
|
||||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1
|
|
||||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2
|
|
||||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4
|
|
||||||
|
|
||||||
#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1
|
|
||||||
#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2
|
|
||||||
#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4
|
|
||||||
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0
|
|
||||||
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10
|
|
||||||
#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20
|
|
||||||
|
|
||||||
#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8
|
|
||||||
#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10
|
|
||||||
#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20
|
|
||||||
|
|
||||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3
|
|
||||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0
|
|
||||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1
|
|
||||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2
|
|
||||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3
|
|
||||||
|
|
||||||
#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1
|
|
||||||
#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2
|
|
||||||
#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8
|
|
||||||
#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000
|
|
||||||
#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000
|
|
||||||
|
|
||||||
#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20
|
|
||||||
|
|
||||||
typedef struct _t210_sdmmc_t
|
typedef struct _t210_sdmmc_t
|
||||||
{
|
{
|
||||||
@@ -77,56 +43,66 @@ typedef struct _t210_sdmmc_t
|
|||||||
vu32 rspreg3;
|
vu32 rspreg3;
|
||||||
vu32 bdata;
|
vu32 bdata;
|
||||||
vu32 prnsts;
|
vu32 prnsts;
|
||||||
vu8 hostctl;
|
vu8 hostctl;
|
||||||
vu8 pwrcon;
|
vu8 pwrcon;
|
||||||
vu8 blkgap;
|
vu8 blkgap;
|
||||||
vu8 wakcon;
|
vu8 wakcon;
|
||||||
vu16 clkcon;
|
vu16 clkcon;
|
||||||
vu8 timeoutcon;
|
vu8 timeoutcon;
|
||||||
vu8 swrst;
|
vu8 swrst;
|
||||||
vu16 norintsts;
|
vu16 norintsts;
|
||||||
vu16 errintsts;
|
vu16 errintsts;
|
||||||
vu16 norintstsen;
|
vu16 norintstsen; // Enable irq status.
|
||||||
vu16 errintstsen;
|
vu16 errintstsen; // Enable irq status.
|
||||||
vu16 norintsigen;
|
vu16 norintsigen; // Enable irq signal to LIC/GIC.
|
||||||
vu16 errintsigen;
|
vu16 errintsigen; // Enable irq signal to LIC/GIC.
|
||||||
vu16 acmd12errsts;
|
vu16 acmd12errsts;
|
||||||
vu16 hostctl2;
|
vu16 hostctl2;
|
||||||
vu32 capareg;
|
vu32 capareg;
|
||||||
vu32 capareg_1;
|
vu32 capareg_1;
|
||||||
vu32 maxcurr;
|
vu32 maxcurr;
|
||||||
vu8 res3[4];
|
vu8 rsvd0[4]; // 4C-4F reserved for more max current.
|
||||||
vu16 setacmd12err;
|
vu16 setacmd12err;
|
||||||
vu16 setinterr;
|
vu16 setinterr;
|
||||||
vu8 admaerr;
|
vu8 admaerr;
|
||||||
vu8 res4[3];
|
vu8 rsvd1[3]; // 55-57 reserved.
|
||||||
vu32 admaaddr;
|
vu32 admaaddr;
|
||||||
vu32 admaaddr_hi;
|
vu32 admaaddr_hi;
|
||||||
vu8 res5[156];
|
vu8 rsvd2[156]; // 60-FB reserved.
|
||||||
vu16 slotintstatus;
|
vu16 slotintsts;
|
||||||
vu16 hcver;
|
vu16 hcver;
|
||||||
vu32 venclkctl;
|
vu32 venclkctl;
|
||||||
vu32 venspictl;
|
vu32 vensysswctl;
|
||||||
vu32 venspiintsts;
|
vu32 venerrintsts;
|
||||||
vu32 venceatactl;
|
vu32 vencapover;
|
||||||
vu32 venbootctl;
|
vu32 venbootctl;
|
||||||
vu32 venbootacktout;
|
vu32 venbootacktout;
|
||||||
vu32 venbootdattout;
|
vu32 venbootdattout;
|
||||||
vu32 vendebouncecnt;
|
vu32 vendebouncecnt;
|
||||||
vu32 venmiscctl;
|
vu32 venmiscctl;
|
||||||
vu32 res6[34];
|
vu32 maxcurrover;
|
||||||
|
vu32 maxcurrover_hi;
|
||||||
|
vu32 unk0[32]; // 0x12C
|
||||||
vu32 veniotrimctl;
|
vu32 veniotrimctl;
|
||||||
vu32 vendllcal;
|
vu32 vendllcalcfg;
|
||||||
vu8 res7[8];
|
vu32 vendllctl0;
|
||||||
vu32 dllcfgstatus;
|
vu32 vendllctl1;
|
||||||
|
vu32 vendllcalcfgsts;
|
||||||
vu32 ventunctl0;
|
vu32 ventunctl0;
|
||||||
vu32 field_1C4;
|
vu32 ventunctl1;
|
||||||
vu8 field_1C8[24];
|
vu32 ventunsts0;
|
||||||
|
vu32 ventunsts1;
|
||||||
|
vu32 venclkgatehystcnt;
|
||||||
|
vu32 venpresetval0;
|
||||||
|
vu32 venpresetval1;
|
||||||
|
vu32 venpresetval2;
|
||||||
vu32 sdmemcmppadctl;
|
vu32 sdmemcmppadctl;
|
||||||
vu32 autocalcfg;
|
vu32 autocalcfg;
|
||||||
vu32 autocalintval;
|
vu32 autocalintval;
|
||||||
vu32 autocalsts;
|
vu32 autocalsts;
|
||||||
vu32 iospare;
|
vu32 iospare;
|
||||||
|
vu32 mcciffifoctl;
|
||||||
|
vu32 timeoutwcoal;
|
||||||
} t210_sdmmc_t;
|
} t210_sdmmc_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
118
source/tegraexplorer/common/common.h
Normal file
118
source/tegraexplorer/common/common.h
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
extern const char *gfx_file_size_names[];
|
||||||
|
extern const char *menu_sd_states[];
|
||||||
|
extern const char *emmc_fs_entries[];
|
||||||
|
extern const char *utils_err_codes[];
|
||||||
|
//extern const char *pkg2names[];
|
||||||
|
extern const char *mainmenu_credits;
|
||||||
|
|
||||||
|
enum utils_err_codes_te_call {
|
||||||
|
ERR_SAME_LOC = 50,
|
||||||
|
ERR_DISK_WRITE_FAILED,
|
||||||
|
ERR_EMPTY_CLIPBOARD,
|
||||||
|
ERR_FOLDER_ROOT = 54,
|
||||||
|
ERR_DEST_PART_OF_SRC,
|
||||||
|
ERR_PART_NOT_FOUND,
|
||||||
|
ERR_BISKEY_DUMP_FAILED,
|
||||||
|
ERR_MEM_ALLOC_FAILED,
|
||||||
|
ERR_EMMC_READ_FAILED,
|
||||||
|
ERR_EMMC_WRITE_FAILED,
|
||||||
|
ERR_FILE_TOO_BIG_FOR_DEST,
|
||||||
|
ERR_SD_EJECTED,
|
||||||
|
ERR_SCRIPT_LOOKUP_FAIL,
|
||||||
|
ERR_CANNOT_COPY_FILE_TO_FS_PART,
|
||||||
|
ERR_NO_DESTINATION,
|
||||||
|
ERR_INI_PARSE_FAIL,
|
||||||
|
ERR_IN_FUNC
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char *utils_err_codes_te[];
|
||||||
|
|
||||||
|
enum mainmenu_main_return {
|
||||||
|
MAIN_SDCARD = 0,
|
||||||
|
MAIN_EMMC_SAF,
|
||||||
|
MAIN_EMMC_SYS,
|
||||||
|
MAIN_EMMC_USR,
|
||||||
|
MAIN_EMUMMC_SAF,
|
||||||
|
MAIN_EMUMMC_SYS,
|
||||||
|
MAIN_EMUMMC_USR,
|
||||||
|
MAIN_MOUNT_SD,
|
||||||
|
MAIN_TOOLS,
|
||||||
|
MAIN_SD_FORMAT,
|
||||||
|
MAIN_CREDITS,
|
||||||
|
MAIN_EXIT
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry mainmenu_main[];
|
||||||
|
|
||||||
|
enum mainmenu_shutdown_return {
|
||||||
|
SHUTDOWN_REBOOT_RCM = 1,
|
||||||
|
SHUTDOWN_REBOOT_NORMAL,
|
||||||
|
SHUTDOWN_POWER_OFF,
|
||||||
|
SHUTDOWN_HEKATE,
|
||||||
|
SHUTDOWN_AMS
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry mainmenu_shutdown[];
|
||||||
|
|
||||||
|
enum mainmenu_tools_return {
|
||||||
|
TOOLS_DISPLAY_INFO = 1,
|
||||||
|
TOOLS_DISPLAY_GPIO,
|
||||||
|
TOOLS_DUMPFIRMWARE
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry mainmenu_tools[];
|
||||||
|
|
||||||
|
enum mainmenu_format_return {
|
||||||
|
FORMAT_ALL_FAT32 = 1,
|
||||||
|
FORMAT_EMUMMC
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry mainmenu_format[];
|
||||||
|
|
||||||
|
enum mmc_types {
|
||||||
|
SYSMMC = 1,
|
||||||
|
EMUMMC
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry utils_mmcChoice[];
|
||||||
|
|
||||||
|
enum fs_menu_file_return {
|
||||||
|
FILE_COPY = 4,
|
||||||
|
FILE_MOVE,
|
||||||
|
FILE_RENAME,
|
||||||
|
FILE_DELETE,
|
||||||
|
FILE_PAYLOAD,
|
||||||
|
FILE_SCRIPT,
|
||||||
|
FILE_HEXVIEW,
|
||||||
|
FILE_DUMPBIS,
|
||||||
|
FILE_SIGN
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry fs_menu_file[];
|
||||||
|
|
||||||
|
enum fs_menu_folder_return {
|
||||||
|
DIR_EXITFOLDER = 2,
|
||||||
|
DIR_COPYFOLDER,
|
||||||
|
DIR_DELETEFOLDER,
|
||||||
|
DIR_RENAME,
|
||||||
|
DIR_CREATE
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry fs_menu_folder[];
|
||||||
|
|
||||||
|
enum fs_menu_startdir_return {
|
||||||
|
FILEMENU_RETURN = 0,
|
||||||
|
FILEMENU_CLIPBOARD,
|
||||||
|
FILEMENU_CURFOLDER
|
||||||
|
};
|
||||||
|
|
||||||
|
extern menu_entry fs_menu_startdir[];
|
||||||
|
|
||||||
|
extern gpt_entry_rule gpt_fs_rules[];
|
||||||
|
|
||||||
|
extern menu_entry mmcmenu_start[];
|
||||||
|
|
||||||
|
extern menu_entry mmcmenu_filemenu[];
|
||||||
69
source/tegraexplorer/common/strings.c
Normal file
69
source/tegraexplorer/common/strings.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
const char *gfx_file_size_names[] = {
|
||||||
|
"B ",
|
||||||
|
"KB",
|
||||||
|
"MB",
|
||||||
|
"GB"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *menu_sd_states[] = {
|
||||||
|
"\nUnmount SD",
|
||||||
|
"\nMount SD"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *emmc_fs_entries[] = {
|
||||||
|
"SAFE",
|
||||||
|
"SYSTEM",
|
||||||
|
"USER"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *utils_err_codes[] = {
|
||||||
|
"OK",
|
||||||
|
"I/O ERROR",
|
||||||
|
"NO DISK",
|
||||||
|
"NOT READY",
|
||||||
|
"NO FILE",
|
||||||
|
"NO PATH",
|
||||||
|
"PATH INVALID",
|
||||||
|
"ACCESS DENIED",
|
||||||
|
"ACCESS DENIED",
|
||||||
|
"INVALID PTR",
|
||||||
|
"PROTECTED",
|
||||||
|
"INVALID DRIVE",
|
||||||
|
"NO MEM",
|
||||||
|
"NO FAT",
|
||||||
|
"MKFS ABORT"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *utils_err_codes_te[] = { // these start at 50
|
||||||
|
"SAME LOC",
|
||||||
|
"DISK WRITE FAILED",
|
||||||
|
"EMPTY CLIPBOARD",
|
||||||
|
"DEFENITION OF INSANITY",
|
||||||
|
"FOLDER ROOT",
|
||||||
|
"DEST PART OF SRC",
|
||||||
|
"PART NOT FOUND",
|
||||||
|
"BISKEY DUMP FAILED",
|
||||||
|
"MEM ALLOC FAILED",
|
||||||
|
"EMMC READ FAILED",
|
||||||
|
"EMMC WRITE FAILED",
|
||||||
|
"FILE TOO BIG FOR DEST",
|
||||||
|
"SD EJECTED",
|
||||||
|
"FUNC LOOKUP FAIL",
|
||||||
|
"CANNOT COPY FILE TO FS PART",
|
||||||
|
"NO DESTINATION",
|
||||||
|
"INI PARSE FAIL",
|
||||||
|
"ERR IN FUNC"
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
const char *pkg2names[] = {
|
||||||
|
"BCPKG2-1-Normal-Main",
|
||||||
|
"BCPKG2-2-Normal-Sub",
|
||||||
|
"BCPKG2-3-SafeMode-Main",
|
||||||
|
"BCPKG2-4-SafeMode-Sub",
|
||||||
|
"BCPKG2-5-Repair-Main",
|
||||||
|
"BCPKG2-6-Repair-Sub"
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
const char *mainmenu_credits = "\nTegraexplorer, made by:\nSuch Meme, Many Skill\n\nProject based on:\nLockpick_RCM\nHekate\n\nCool people:\nshchmue\ndennthecafebabe\nDax";
|
||||||
95
source/tegraexplorer/common/structs.c
Normal file
95
source/tegraexplorer/common/structs.c
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
menu_entry mainmenu_main[] = {
|
||||||
|
{"[SD:/] SD CARD", COLOR_GREEN, {ISMENU}},
|
||||||
|
{"[EMMC:/] EMMC", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"[EMMC:/] EMUMMC", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"\nMount/Unmount SD", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"Tools", COLOR_VIOLET, {ISMENU}},
|
||||||
|
{"SD format", COLOR_VIOLET, {ISMENU}},
|
||||||
|
{"\nCredits", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"Exit", COLOR_WHITE, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry mainmenu_shutdown[] = {
|
||||||
|
{"Back", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"\nReboot to RCM", COLOR_VIOLET, {ISMENU}},
|
||||||
|
{"Reboot normally", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"Power off\n", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"Reboot to Hekate", COLOR_GREEN, {ISMENU}},
|
||||||
|
{"Reboot to Atmosphere", COLOR_GREEN, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry mainmenu_tools[] = {
|
||||||
|
{"Back", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"\nDisplay Console Info", COLOR_GREEN, {ISMENU}},
|
||||||
|
{"Display GPIO pins", COLOR_VIOLET, {ISMENU}},
|
||||||
|
{"Dump Firmware", COLOR_BLUE, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry mainmenu_format[] = {
|
||||||
|
{"Back\n", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"Format entire SD to FAT32", COLOR_RED, {ISMENU}},
|
||||||
|
{"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry utils_mmcChoice[] = {
|
||||||
|
{"Back\n", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"SysMMC", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"EmuMMC", COLOR_BLUE, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry fs_menu_file[] = {
|
||||||
|
{NULL, COLOR_GREEN, {ISMENU | ISSKIP}},
|
||||||
|
{NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
|
||||||
|
{NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
|
||||||
|
{"\n\n\nBack", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"\nCopy to clipboard", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"Move to clipboard", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"Rename file", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"\nDelete file\n", COLOR_RED, {ISMENU}},
|
||||||
|
{"Launch Payload", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"Launch Script", COLOR_YELLOW, {ISMENU}},
|
||||||
|
{"View Hex", COLOR_GREEN, {ISMENU}},
|
||||||
|
{"\nExtract BIS", COLOR_YELLOW, {ISMENU}},
|
||||||
|
{"Sign Save", COLOR_ORANGE, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry fs_menu_folder[] = {
|
||||||
|
{NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
|
||||||
|
{"\nBack", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"Return to main menu\n", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"Copy to clipboard", COLOR_VIOLET, {ISMENU}},
|
||||||
|
{"Delete folder\n", COLOR_RED, {ISMENU}},
|
||||||
|
{"Rename folder", COLOR_BLUE, {ISMENU}},
|
||||||
|
{"Create folder", COLOR_BLUE, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry fs_menu_startdir[] = {
|
||||||
|
{"Folder -> previous folder ", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"Clipboard -> Current folder", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"Current folder menu ", COLOR_ORANGE, {ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
gpt_entry_rule gpt_fs_rules[] = {
|
||||||
|
{"PRODINFOF", 0 | isFS},
|
||||||
|
{"SAFE", 1 | isFS },
|
||||||
|
{"SYSTEM", 2 | isFS},
|
||||||
|
{"USER", 3 | isFS},
|
||||||
|
{NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry mmcmenu_start[] = {
|
||||||
|
{"Back", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"Dump File Partitions", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"Clipboard -> Partition\n", COLOR_ORANGE, {ISMENU}},
|
||||||
|
{"BOOT0/1", COLOR_BLUE, {ISNULL | ISMENU}}
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_entry mmcmenu_filemenu[] = {
|
||||||
|
{"Part:", COLOR_ORANGE, {ISSKIP | ISMENU}},
|
||||||
|
{NULL, COLOR_VIOLET, {ISSKIP | ISMENU}},
|
||||||
|
{"\nBack", COLOR_WHITE, {ISMENU}},
|
||||||
|
{"Dump to SD", COLOR_YELLOW, {ISMENU}}
|
||||||
|
};
|
||||||
61
source/tegraexplorer/common/types.h
Normal file
61
source/tegraexplorer/common/types.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
|
#define BIT(n) (1U << n)
|
||||||
|
|
||||||
|
#define ISDIR BIT(0)
|
||||||
|
#define ISMENU BIT(1)
|
||||||
|
#define SETSIZE(x) (x << 2)
|
||||||
|
#define ISNULL BIT(4)
|
||||||
|
#define ISHIDE BIT(5)
|
||||||
|
#define ISSKIP BIT(6)
|
||||||
|
|
||||||
|
#define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift))
|
||||||
|
|
||||||
|
/* Bit table for property as a file:
|
||||||
|
0000 0001: Directory bit
|
||||||
|
0000 0010: Archive bit (or hideme)
|
||||||
|
0001 0000: Size component is a Byte
|
||||||
|
0010 0000: Size component is a KiloByte
|
||||||
|
0100 0000: Size component is a MegaByte
|
||||||
|
1000 0000: Size component is a GigaByte : note that this won't surpass gigabytes, but i don't expect people to have a single file that's a terrabyte big
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define COPY_MODE_PRINT 0x1
|
||||||
|
#define COPY_MODE_CANCEL 0x2
|
||||||
|
#define BUFSIZE 65536 //32768
|
||||||
|
|
||||||
|
#define OPERATIONCOPY 0x2
|
||||||
|
#define OPERATIONMOVE 0x4
|
||||||
|
|
||||||
|
#define PART_BOOT 0x1
|
||||||
|
#define PART_PKG2 0x2
|
||||||
|
|
||||||
|
#define BOOT0_ARG 0x80
|
||||||
|
#define BOOT1_ARG 0x40
|
||||||
|
#define BCPKG2_1_ARG 0x20
|
||||||
|
#define BCPKG2_3_ARG 0x10
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
u32 storage;
|
||||||
|
union {
|
||||||
|
u8 property;
|
||||||
|
struct {
|
||||||
|
u8 isDir:1;
|
||||||
|
u8 isMenu:1;
|
||||||
|
u8 size:2;
|
||||||
|
u8 isNull:1;
|
||||||
|
u8 isHide:1;
|
||||||
|
u8 isSkip:1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} menu_entry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
u8 property;
|
||||||
|
} gpt_entry_rule;
|
||||||
|
|
||||||
|
#define isFS 0x80
|
||||||
|
#define isBOOT 0x2
|
||||||
@@ -1,34 +1,41 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../mem/heap.h"
|
|
||||||
#include "gfx.h"
|
|
||||||
#include "fs.h"
|
|
||||||
#include "emmc.h"
|
#include "emmc.h"
|
||||||
#include "../utils/types.h"
|
#include "../../mem/heap.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../../utils/types.h"
|
||||||
#include "../utils/sprintf.h"
|
#include "../../libs/fatfs/ff.h"
|
||||||
#include "../utils/btn.h"
|
#include "../../utils/sprintf.h"
|
||||||
#include "../gfx/gfx.h"
|
#include "../../gfx/gfx.h"
|
||||||
#include "../utils/util.h"
|
#include "../../utils/util.h"
|
||||||
#include "../hos/pkg1.h"
|
#include "../../hos/pkg1.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../../storage/sdmmc.h"
|
||||||
#include "../storage/nx_emmc.h"
|
#include "../../storage/nx_emmc.h"
|
||||||
#include "../sec/tsec.h"
|
#include "../../sec/tsec.h"
|
||||||
#include "../soc/t210.h"
|
#include "../../soc/t210.h"
|
||||||
#include "../soc/fuse.h"
|
#include "../../soc/fuse.h"
|
||||||
#include "../mem/mc.h"
|
#include "../../mem/mc.h"
|
||||||
#include "../sec/se.h"
|
#include "../../sec/se.h"
|
||||||
#include "../soc/hw_init.h"
|
#include "../../soc/hw_init.h"
|
||||||
#include "../mem/emc.h"
|
#include "../../mem/emc.h"
|
||||||
#include "../mem/sdram.h"
|
#include "../../mem/sdram.h"
|
||||||
|
#include "../../storage/emummc.h"
|
||||||
|
#include "../../config/config.h"
|
||||||
|
#include "../common/common.h"
|
||||||
|
#include "../gfx/gfxutils.h"
|
||||||
|
#include "../../utils/list.h"
|
||||||
|
#include "../../mem/heap.h"
|
||||||
|
|
||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
emmc_part_t *system_part;
|
emmc_part_t *system_part;
|
||||||
sdmmc_t sdmmc;
|
sdmmc_t sdmmc;
|
||||||
|
extern hekate_config h_cfg;
|
||||||
__attribute__ ((aligned (16))) FATFS emmc;
|
__attribute__ ((aligned (16))) FATFS emmc;
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(sys_gpt);
|
||||||
|
LIST_INIT(emu_gpt);
|
||||||
|
|
||||||
u8 bis_key[4][32];
|
u8 bis_key[4][32];
|
||||||
short pkg1ver;
|
pkg1_info pkg1inf = {-1, ""};
|
||||||
|
short currentlyMounted = -1;
|
||||||
|
|
||||||
|
|
||||||
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
||||||
|
|
||||||
@@ -44,38 +51,79 @@ static void _generate_kek(u32 ks, const void *key_source, void *master_key, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
void print_biskeys(){
|
void print_biskeys(){
|
||||||
gfx_printf("\n");
|
gfx_printf("Bis_Key_00\n");
|
||||||
gfx_hexdump(0, bis_key[0], 32);
|
gfx_hexdump(0, bis_key[0], 32);
|
||||||
|
gfx_printf("Bis_Key_01\n");
|
||||||
gfx_hexdump(0, bis_key[1], 32);
|
gfx_hexdump(0, bis_key[1], 32);
|
||||||
|
gfx_printf("Bis_Key_02 & 03\n");
|
||||||
gfx_hexdump(0, bis_key[2], 32);
|
gfx_hexdump(0, bis_key[2], 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mount_emmc(char *partition, int biskeynumb){
|
pkg1_info returnpkg1info(){
|
||||||
f_unmount("emmc:");
|
return pkg1inf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connect_part(const char *partition){
|
||||||
|
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
|
||||||
|
system_part = nx_emmc_part_find(selectGpt(currentlyMounted), partition);
|
||||||
|
if (!system_part) {
|
||||||
|
gfx_errDisplay("connect_mmc_part", ERR_PART_NOT_FOUND, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_mmc(const char *partition, const int biskeynumb){
|
||||||
|
int res;
|
||||||
|
f_unmount("emmc:");
|
||||||
|
|
||||||
se_aes_key_set(8, bis_key[biskeynumb] + 0x00, 0x10);
|
se_aes_key_set(8, bis_key[biskeynumb] + 0x00, 0x10);
|
||||||
se_aes_key_set(9, bis_key[biskeynumb] + 0x10, 0x10);
|
se_aes_key_set(9, bis_key[biskeynumb] + 0x10, 0x10);
|
||||||
|
|
||||||
system_part = nx_emmc_part_find(&gpt, partition);
|
if (connect_part(partition))
|
||||||
if (!system_part) {
|
return 1;
|
||||||
gfx_printf("Failed to locate %s partition.", partition);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f_mount(&emmc, "emmc:", 1)) {
|
if ((res = f_mount(&emmc, "emmc:", 1))) {
|
||||||
gfx_printf("Mount failed of %s.", partition);
|
gfx_errDisplay("mount_mmc", res, 0);
|
||||||
return -1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
short returnpkg1ver(){
|
void connect_mmc(short mmctype){
|
||||||
return pkg1ver;
|
if (mmctype != currentlyMounted){
|
||||||
|
disconnect_mmc();
|
||||||
|
h_cfg.emummc_force_disable = 0;
|
||||||
|
switch (mmctype){
|
||||||
|
case SYSMMC:
|
||||||
|
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||||
|
h_cfg.emummc_force_disable = 1;
|
||||||
|
currentlyMounted = SYSMMC;
|
||||||
|
break;
|
||||||
|
case EMUMMC:
|
||||||
|
if (emummc_storage_init_mmc(&storage, &sdmmc)){
|
||||||
|
h_cfg.emummc_force_disable = 0;
|
||||||
|
currentlyMounted = EMUMMC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnect_emmc(){
|
void disconnect_mmc(){
|
||||||
sdmmc_storage_end(&storage);
|
f_unmount("emmc:");
|
||||||
|
switch (currentlyMounted){
|
||||||
|
case SYSMMC:
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
break;
|
||||||
|
case EMUMMC:
|
||||||
|
emummc_storage_end(&storage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentlyMounted = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dump_biskeys(){
|
int dump_biskeys(){
|
||||||
@@ -84,12 +132,13 @@ int dump_biskeys(){
|
|||||||
|
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
connect_mmc(SYSMMC);
|
||||||
|
|
||||||
// Read package1.
|
// Read package1.
|
||||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||||
|
strncpy(pkg1inf.id, pkg1 + 0x10, 14);
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||||
if (!pkg1_id) {
|
if (!pkg1_id) {
|
||||||
EPRINTF("Unknown pkg1 version.");
|
EPRINTF("Unknown pkg1 version.");
|
||||||
@@ -166,44 +215,44 @@ int dump_biskeys(){
|
|||||||
memcpy(bis_key[3], bis_key[2], 0x20);
|
memcpy(bis_key[3], bis_key[2], 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
//sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||||
// Parse eMMC GPT.
|
//nx_emmc_gpt_parse(&sys_gpt, &storage);
|
||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
|
||||||
/*
|
|
||||||
char part_name[37] = "SYSTEM";
|
|
||||||
|
|
||||||
// todo: menu selection for this
|
|
||||||
|
|
||||||
u32 bis_key_index = 0;
|
|
||||||
if (strcmp(part_name, "PRODINFOF") == 0)
|
|
||||||
bis_key_index = 0;
|
|
||||||
else if (strcmp(part_name, "SAFE") == 0)
|
|
||||||
bis_key_index = 1;
|
|
||||||
else if (strcmp(part_name, "SYSTEM") == 0)
|
|
||||||
bis_key_index = 2;
|
|
||||||
else if (strcmp(part_name, "USER") == 0)
|
|
||||||
bis_key_index = 3;
|
|
||||||
else {
|
|
||||||
gfx_printf("Partition name %s unrecognized.", part_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
|
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
|
||||||
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
|
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
|
||||||
|
|
||||||
|
pkg1inf.ver = pkg1_id->kb;
|
||||||
|
strcpy(pkg1inf.id, pkg1_id->id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
void dumpGpt(){
|
||||||
system_part = nx_emmc_part_find(&gpt, "SYSTEM");
|
connect_mmc(SYSMMC);
|
||||||
if (!system_part) {
|
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||||
gfx_printf("Failed to locate SYSTEM partition.");
|
nx_emmc_gpt_parse(&sys_gpt, &storage);
|
||||||
return -1;
|
|
||||||
|
if (emu_cfg.enabled){
|
||||||
|
connect_mmc(EMUMMC);
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
nx_emmc_gpt_parse(&emu_gpt, &storage);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (f_mount(&emmc_sys, "system:", 1)) {
|
link_t *selectGpt(short mmcType){
|
||||||
gfx_printf("Mount failed of SYSTEM.");
|
switch(mmcType){
|
||||||
return -1;
|
case SYSMMC:
|
||||||
|
return &sys_gpt;
|
||||||
|
case EMUMMC:
|
||||||
|
return &emu_gpt;
|
||||||
}
|
}
|
||||||
*/
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
pkg1ver = pkg1_id->kb;
|
int checkGptRules(char *in){
|
||||||
|
for (int i = 0; gpt_fs_rules[i].name != NULL; i++){
|
||||||
|
if (!strcmp(in, gpt_fs_rules[i].name))
|
||||||
|
return gpt_fs_rules[i].property;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
#include "../../utils/list.h"
|
||||||
|
|
||||||
|
typedef struct _pkg1_info {
|
||||||
|
short ver;
|
||||||
|
char id[16];
|
||||||
|
} pkg1_info;
|
||||||
|
|
||||||
//int mount_emmc_partition(const char *part, int logicnumb);
|
//int mount_emmc_partition(const char *part, int logicnumb);
|
||||||
int dump_biskeys();
|
int dump_biskeys();
|
||||||
void print_biskeys();
|
void print_biskeys();
|
||||||
int mount_emmc(char *partition, int biskeynumb);
|
pkg1_info returnpkg1info();
|
||||||
short returnpkg1ver();
|
|
||||||
void disconnect_emmc();
|
int mount_mmc(const char *partition, const int biskeynumb);
|
||||||
|
void connect_mmc(short mmctype);
|
||||||
|
void disconnect_mmc();
|
||||||
|
int connect_part(const char *partition);
|
||||||
|
void dumpGpt();
|
||||||
|
link_t *selectGpt(short mmcType);
|
||||||
|
int checkGptRules(char *in);
|
||||||
|
|
||||||
static const u8 zeros[0x10] = {0};
|
static const u8 zeros[0x10] = {0};
|
||||||
|
|
||||||
@@ -40,4 +53,11 @@ static const u8 bis_key_source[3][0x20] = {
|
|||||||
{
|
{
|
||||||
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
||||||
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
|
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum mmc_types {
|
||||||
|
SYSMMC = 0,
|
||||||
|
EMUMMC
|
||||||
|
};
|
||||||
|
*/
|
||||||
183
source/tegraexplorer/emmc/emmcdumppart.c
Normal file
183
source/tegraexplorer/emmc/emmcdumppart.c
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "emmcoperations.h"
|
||||||
|
#include "../../gfx/gfx.h"
|
||||||
|
#include "../gfx/gfxutils.h"
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
#include "emmc.h"
|
||||||
|
#include "../../storage/emummc.h"
|
||||||
|
#include "../common/common.h"
|
||||||
|
#include "../../libs/fatfs/ff.h"
|
||||||
|
#include "../../utils/sprintf.h"
|
||||||
|
#include "../../mem/heap.h"
|
||||||
|
#include "../../storage/nx_emmc.h"
|
||||||
|
#include "../common/types.h"
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
#include "../fs/fsutils.h"
|
||||||
|
|
||||||
|
extern sdmmc_storage_t storage;
|
||||||
|
extern emmc_part_t *system_part;
|
||||||
|
|
||||||
|
int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
|
||||||
|
FIL fp;
|
||||||
|
u8 *buf;
|
||||||
|
u32 lba_curr = part->lba_start;
|
||||||
|
u32 bytesWritten = 0;
|
||||||
|
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||||
|
u64 totalSize = (u64)((u64)totalSectors << 9);
|
||||||
|
u32 num = 0;
|
||||||
|
u32 pct = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
gfx_printf("Initializing\r");
|
||||||
|
buf = calloc(BUFSIZE, sizeof(u8));
|
||||||
|
|
||||||
|
if (!buf){
|
||||||
|
gfx_errDisplay("dump_emmc_part", ERR_MEM_ALLOC_FAILED, 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = f_open(&fp, path, FA_CREATE_ALWAYS | FA_WRITE))){
|
||||||
|
gfx_errDisplay("dump_emmc_part", res, 2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_lseek(&fp, totalSize);
|
||||||
|
f_lseek(&fp, 0);
|
||||||
|
|
||||||
|
while (totalSectors > 0){
|
||||||
|
num = MIN(totalSectors, 128);
|
||||||
|
if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){
|
||||||
|
gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((res = f_write(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
|
||||||
|
gfx_errDisplay("dump_emmc_part", res, 4);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||||
|
gfx_printf("Progress: %d%%\r", pct);
|
||||||
|
|
||||||
|
lba_curr += num;
|
||||||
|
totalSectors -= num;
|
||||||
|
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||||
|
}
|
||||||
|
gfx_printf(" \r");
|
||||||
|
f_close(&fp);
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int existsCheck(char *path){
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (fsutil_checkfile(path)){
|
||||||
|
gfx_printf("File already exists! Overwrite?\nBto cancel\n");
|
||||||
|
res = gfx_makewaitmenu("A to continue", 3);
|
||||||
|
gfx_printf("\r \r");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int dump_emmc_parts(u16 parts, u8 mmctype){
|
||||||
|
char *path;
|
||||||
|
char basepath[] = "sd:/tegraexplorer/partition_dumps";
|
||||||
|
f_mkdir("sd:/tegraexplorer");
|
||||||
|
f_mkdir("sd:/tegraexplorer/partition_dumps");
|
||||||
|
|
||||||
|
connect_mmc(mmctype);
|
||||||
|
gfx_clearscreen();
|
||||||
|
|
||||||
|
if (parts & PART_BOOT){
|
||||||
|
emmc_part_t bootPart;
|
||||||
|
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||||
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
|
|
||||||
|
bootPart.lba_start = 0;
|
||||||
|
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++){
|
||||||
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
bootPart.name[4] = (u8)('0' + i);
|
||||||
|
bootPart.name[5] = 0;
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, i + 1);
|
||||||
|
utils_copystring(fsutil_getnextloc(basepath, bootPart.name), &path);
|
||||||
|
|
||||||
|
if (!existsCheck(path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gfx_printf("Dumping %s\n", bootPart.name);
|
||||||
|
|
||||||
|
dump_emmc_part(path, &storage, &bootPart);
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts & PART_PKG2){
|
||||||
|
for (int i = 0; i < 6; i++){
|
||||||
|
utils_copystring(fsutil_getnextloc(basepath, pkg2names[i]), &path);
|
||||||
|
gfx_printf("Dumping %s\n", pkg2names[i]);
|
||||||
|
|
||||||
|
emmcDumpSpecific(pkg2names[i], path);
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("\nDone!");
|
||||||
|
btn_wait();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int emmcDumpBoot(char *basePath){
|
||||||
|
emmc_part_t bootPart;
|
||||||
|
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||||
|
char *path;
|
||||||
|
memset(&bootPart, 0, sizeof(emmc_part_t));
|
||||||
|
|
||||||
|
bootPart.lba_start = 0;
|
||||||
|
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++){
|
||||||
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
bootPart.name[4] = (u8)('0' + i);
|
||||||
|
bootPart.name[5] = 0;
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, i + 1);
|
||||||
|
utils_copystring(fsutil_getnextloc(basePath, bootPart.name), &path);
|
||||||
|
|
||||||
|
if (!existsCheck(path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SWAPCOLOR(COLOR_BLUE);
|
||||||
|
gfx_printf("Dumping %s\n", bootPart.name);
|
||||||
|
RESETCOLOR;
|
||||||
|
|
||||||
|
emmcDumpPart(path, &storage, &bootPart);
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emmcDumpSpecific(char *part, char *path){
|
||||||
|
if (!existsCheck(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
if (connect_part(part)){
|
||||||
|
gfx_errDisplay("dump_emmc_specific", ERR_PART_NOT_FOUND, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWAPCOLOR(COLOR_VIOLET);
|
||||||
|
gfx_printf("Dumping %s\n", part);
|
||||||
|
RESETCOLOR;
|
||||||
|
emmcDumpPart(path, &storage, system_part);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
176
source/tegraexplorer/emmc/emmcmenu.c
Normal file
176
source/tegraexplorer/emmc/emmcmenu.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "emmc.h"
|
||||||
|
#include "../../mem/heap.h"
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
#include "../../libs/fatfs/ff.h"
|
||||||
|
#include "../../hid/hid.h"
|
||||||
|
#include "../../gfx/gfx.h"
|
||||||
|
#include "../../utils/util.h"
|
||||||
|
#include "../../storage/nx_emmc.h"
|
||||||
|
#include "../../mem/mc.h"
|
||||||
|
#include "../../mem/emc.h"
|
||||||
|
#include "../../storage/emummc.h"
|
||||||
|
#include "../../config/config.h"
|
||||||
|
#include "../common/common.h"
|
||||||
|
#include "../gfx/gfxutils.h"
|
||||||
|
#include "../../utils/list.h"
|
||||||
|
#include "../../mem/heap.h"
|
||||||
|
#include "emmcmenu.h"
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
#include "../gfx/menu.h"
|
||||||
|
#include "../fs/fsmenu.h"
|
||||||
|
#include "emmcoperations.h"
|
||||||
|
#include "../fs/fsutils.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
|
||||||
|
menu_entry *mmcMenuEntries = NULL;
|
||||||
|
extern sdmmc_storage_t storage;
|
||||||
|
extern emmc_part_t *system_part;
|
||||||
|
extern char *clipboard;
|
||||||
|
extern u8 clipboardhelper;
|
||||||
|
|
||||||
|
|
||||||
|
void addEntry(emmc_part_t *part, u8 property_GPT, int spot){
|
||||||
|
u32 storage = 0;
|
||||||
|
u8 property = 0;
|
||||||
|
|
||||||
|
if (property_GPT & isFS){
|
||||||
|
storage = (u32)(property_GPT & 0x7F);
|
||||||
|
property = ISDIR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u64 size = 0;
|
||||||
|
u32 sizes = 0;
|
||||||
|
|
||||||
|
size = (u64)(part->lba_end + 1 - part->lba_start);
|
||||||
|
size *= (u64)NX_EMMC_BLOCKSIZE;
|
||||||
|
|
||||||
|
while (size > 1024){
|
||||||
|
size /= 1024;
|
||||||
|
sizes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizes > 3)
|
||||||
|
sizes = 3;
|
||||||
|
|
||||||
|
property |= SETSIZE(sizes);
|
||||||
|
storage = (u32)size;
|
||||||
|
}
|
||||||
|
|
||||||
|
mu_copySingle(part->name, storage, property, &mmcMenuEntries[spot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fillMmcMenu(short mmcType){
|
||||||
|
int count = 4, i;
|
||||||
|
|
||||||
|
if (mmcMenuEntries != NULL)
|
||||||
|
mu_clearObjects(&mmcMenuEntries);
|
||||||
|
|
||||||
|
link_t *gpt = selectGpt(mmcType);
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
mu_createObjects(count, &mmcMenuEntries);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
mu_copySingle(mmcmenu_start[i].name, mmcmenu_start[i].storage, mmcmenu_start[i].property, &mmcMenuEntries[i]);
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){
|
||||||
|
addEntry(part, checkGptRules(part->name), i++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handleEntries(short mmcType, menu_entry part){
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (part.property & ISDIR){
|
||||||
|
if (returnpkg1info().ver < 0){
|
||||||
|
gfx_errDisplay("emmcMakeMenu", ERR_BISKEY_DUMP_FAILED, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!mount_mmc(part.name, part.storage))
|
||||||
|
fileexplorer("emmc:/", 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
if (mmcmenu_filemenu[1].name != NULL)
|
||||||
|
free(mmcmenu_filemenu[1].name);
|
||||||
|
|
||||||
|
utils_copystring(part.name, &mmcmenu_filemenu[1].name);
|
||||||
|
*/
|
||||||
|
|
||||||
|
mu_copySingle(part.name, mmcmenu_filemenu[1].storage, mmcmenu_filemenu[1].property, &mmcmenu_filemenu[1]);
|
||||||
|
|
||||||
|
if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
f_mkdir("sd:/tegraexplorer");
|
||||||
|
f_mkdir("sd:/tegraexplorer/partition_dumps");
|
||||||
|
|
||||||
|
gfx_clearscreen();
|
||||||
|
|
||||||
|
if (part.isNull){
|
||||||
|
res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//gfx_printf("Dumping %s...\n", part.name);
|
||||||
|
res = emmcDumpSpecific(part.name, fsutil_getnextloc("sd:/tegraexplorer/partition_dumps", part.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res){
|
||||||
|
gfx_printf("\nDone!");
|
||||||
|
hidWait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int makeMmcMenu(short mmcType){
|
||||||
|
int count, selection;
|
||||||
|
count = fillMmcMenu(mmcType);
|
||||||
|
connect_mmc(mmcType);
|
||||||
|
while (1){
|
||||||
|
selection = menu_make(mmcMenuEntries, count, (mmcType == SYSMMC) ? "-- SYSMMC --" : "-- EMUMMC --");
|
||||||
|
|
||||||
|
switch(selection){
|
||||||
|
case -1:
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
gfx_clearscreen();
|
||||||
|
f_mkdir("sd:/tegraexplorer");
|
||||||
|
f_mkdir("sd:/tegraexplorer/partition_dumps");
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++){
|
||||||
|
if (mmcMenuEntries[i].property & (ISMENU | ISDIR))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name);
|
||||||
|
emmcDumpSpecific(mmcMenuEntries[i].name, fsutil_getnextloc("sd:/tegraexplorer/partition_dumps", mmcMenuEntries[i].name));
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("\nDone!");
|
||||||
|
hidWait();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){
|
||||||
|
gfx_clearscreen();
|
||||||
|
if (!mmcFlashFile(clipboard, mmcType, true)){
|
||||||
|
gfx_printf("\nDone!");
|
||||||
|
hidWait();
|
||||||
|
}
|
||||||
|
clipboardhelper = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gfx_errDisplay("mmcMenu", ERR_EMPTY_CLIPBOARD, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
handleEntries(mmcType, mmcMenuEntries[selection]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
source/tegraexplorer/emmc/emmcmenu.h
Normal file
3
source/tegraexplorer/emmc/emmcmenu.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int makeMmcMenu(short mmcType);
|
||||||
10
source/tegraexplorer/emmc/emmcoperations.h
Normal file
10
source/tegraexplorer/emmc/emmcoperations.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
#include "../../storage/nx_emmc.h"
|
||||||
|
|
||||||
|
int emmcDumpSpecific(char *part, char *path);
|
||||||
|
int emmcDumpBoot(char *basePath);
|
||||||
|
int mmcFlashFile(char *path, short mmcType, bool warnings);
|
||||||
|
|
||||||
|
int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part);
|
||||||
|
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part, bool warnings);
|
||||||
228
source/tegraexplorer/emmc/emmcrestorepart.c
Normal file
228
source/tegraexplorer/emmc/emmcrestorepart.c
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "emmcoperations.h"
|
||||||
|
#include "../../gfx/gfx.h"
|
||||||
|
#include "../gfx/gfxutils.h"
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
#include "emmc.h"
|
||||||
|
#include "../../storage/emummc.h"
|
||||||
|
#include "../common/common.h"
|
||||||
|
#include "../../libs/fatfs/ff.h"
|
||||||
|
#include "../../utils/sprintf.h"
|
||||||
|
#include "../../mem/heap.h"
|
||||||
|
#include "../../storage/nx_emmc.h"
|
||||||
|
#include "../common/types.h"
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
#include "../fs/fsutils.h"
|
||||||
|
|
||||||
|
extern sdmmc_storage_t storage;
|
||||||
|
extern emmc_part_t *system_part;
|
||||||
|
|
||||||
|
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part, bool warnings){
|
||||||
|
FIL fp;
|
||||||
|
FILINFO fno;
|
||||||
|
u8 *buf;
|
||||||
|
u32 lba_curr = part->lba_start;
|
||||||
|
u64 bytesWritten = 0;
|
||||||
|
u32 totalSectorsDest = part->lba_end - part->lba_start + 1;
|
||||||
|
u64 totalSizeDest = (u64)((u64)totalSectorsDest << 9);
|
||||||
|
u64 totalSize;
|
||||||
|
u32 num = 0;
|
||||||
|
u32 pct = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
gfx_printf("Initializing\r");
|
||||||
|
|
||||||
|
buf = calloc(BUFSIZE, sizeof(u8));
|
||||||
|
|
||||||
|
if (!buf){
|
||||||
|
gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = f_stat(path, &fno))){
|
||||||
|
gfx_errDisplay("restore_emmc_part", res, 2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalSize = fno.fsize;
|
||||||
|
u64 totalSectors = totalSize / NX_EMMC_BLOCKSIZE;
|
||||||
|
|
||||||
|
if (totalSize > totalSizeDest){
|
||||||
|
gfx_errDisplay("restore_emmc_part", ERR_FILE_TOO_BIG_FOR_DEST, 3);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("Flashing %s\n", part->name);
|
||||||
|
|
||||||
|
if (totalSize < totalSizeDest && warnings){
|
||||||
|
SWAPCOLOR(COLOR_ORANGE);
|
||||||
|
gfx_printf("File is too small for destination.\nDo you want to flash it anyway?\n\nB to Cancel\n");
|
||||||
|
u32 btnres = gfx_makewaitmenu(
|
||||||
|
"A to Confirm",
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
RESETCOLOR;
|
||||||
|
|
||||||
|
if (!btnres){
|
||||||
|
gfx_printf("\nCancelled: %s\n\n", part->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gfx_printf("\nFlashing %s\n", part->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = f_open(&fp, path, FA_OPEN_ALWAYS | FA_READ))){
|
||||||
|
gfx_errDisplay("restore_emmc_part", res, 4);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (totalSectors > 0){
|
||||||
|
num = MIN(totalSectors, 128);
|
||||||
|
|
||||||
|
if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
|
||||||
|
gfx_errDisplay("restore_emmc_part", res, 5);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emummc_storage_write(mmcstorage, lba_curr, num, buf)){
|
||||||
|
gfx_errDisplay("restore_emmc_part", ERR_EMMC_WRITE_FAILED, 2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lba_curr += num;
|
||||||
|
totalSectors -= num;
|
||||||
|
bytesWritten += (u64)(num * NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
|
pct = (u64)(bytesWritten * (u64)100) / (u64)(fno.fsize);
|
||||||
|
gfx_printf("Progress: %d%%\r", pct);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf(" \r");
|
||||||
|
f_close(&fp);
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// function replaced by new mmc implementation. Will be removed at some point
|
||||||
|
/*
|
||||||
|
int restore_emmc_file(char *path, const char *target, u8 partition, u8 mmctype){
|
||||||
|
connect_mmc(mmctype);
|
||||||
|
|
||||||
|
if (partition){
|
||||||
|
emmc_part_t bootPart;
|
||||||
|
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||||
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
|
|
||||||
|
bootPart.lba_start = 0;
|
||||||
|
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||||
|
|
||||||
|
strcpy(bootPart.name, target);
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, partition);
|
||||||
|
restore_emmc_part(path, &storage, &bootPart);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (connect_part(target)){
|
||||||
|
gfx_errDisplay("restore_emmc_part", ERR_PART_NOT_FOUND, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
restore_emmc_part(path, &storage, system_part);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_bis_using_file(char *path, u8 mmctype){
|
||||||
|
f_mkdir("sd:/tegraexplorer");
|
||||||
|
f_mkdir("sd:/tegraexplorer/bis");
|
||||||
|
gfx_clearscreen();
|
||||||
|
|
||||||
|
if (extract_bis_file(path, "sd:/tegraexplorer/bis"))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
SWAPBGCOLOR(COLOR_RED);
|
||||||
|
SWAPCOLOR(COLOR_DEFAULT);
|
||||||
|
gfx_printf("\nAre you sure you want to flash these files\nThis could leave your switch unbootable!\nTarget is SysMMC\n\nVol +/- to cancel\n");
|
||||||
|
if (!gfx_makewaitmenu(
|
||||||
|
"Power to confirm",
|
||||||
|
10
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
RESETCOLOR;
|
||||||
|
|
||||||
|
gfx_printf("\nRestoring BIS...\n\n");
|
||||||
|
|
||||||
|
restore_emmc_file("sd:/tegraexplorer/bis/BOOT0.bin", "BOOT0", 1, mmctype);
|
||||||
|
restore_emmc_file("sd:/tegraexplorer/bis/BOOT1.bin", "BOOT1", 2, mmctype);
|
||||||
|
restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-1-Normal-Main", pkg2names[0], 0, mmctype);
|
||||||
|
restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-1-Normal-Main", pkg2names[1], 0, mmctype);
|
||||||
|
restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-3-SafeMode-Main", pkg2names[2], 0, mmctype);
|
||||||
|
restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-3-SafeMode-Main", pkg2names[3], 0, mmctype);
|
||||||
|
|
||||||
|
gfx_printf("\n\nDone!\nPress any button to return");
|
||||||
|
btn_wait();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
emmc_part_t *mmcFindPart(char *path, short mmcType){
|
||||||
|
char *filename, *extention, *path_local;
|
||||||
|
emmc_part_t *part;
|
||||||
|
|
||||||
|
utils_copystring(path, &path_local);
|
||||||
|
filename = strrchr(path_local, '/') + 1;
|
||||||
|
extention = strrchr(path_local, '.');
|
||||||
|
|
||||||
|
if (extention != NULL)
|
||||||
|
*extention = '\0';
|
||||||
|
|
||||||
|
if (checkGptRules(filename)){
|
||||||
|
gfx_errDisplay("mmcFindPart", ERR_CANNOT_COPY_FILE_TO_FS_PART, 1);
|
||||||
|
free(path_local);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
part = nx_emmc_part_find(selectGpt(mmcType), filename);
|
||||||
|
|
||||||
|
if (part != NULL){
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
free(path_local);
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(filename, "BOOT0") || !strcmp(filename, "BOOT1")){
|
||||||
|
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||||
|
part = calloc(1, sizeof(emmc_part_t));
|
||||||
|
|
||||||
|
part->lba_start = 0;
|
||||||
|
part->lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||||
|
|
||||||
|
strcpy(part->name, filename);
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, (!strcmp(filename, "BOOT0")) ? 1 : 2);
|
||||||
|
free(path_local);
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
|
||||||
|
//gfx_printf("Path: %s\nFilename: %s", path, filename);
|
||||||
|
//btn_wait();
|
||||||
|
gfx_errDisplay("mmcFindPart", ERR_NO_DESTINATION, 2);
|
||||||
|
free(path_local);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mmcFlashFile(char *path, short mmcType, bool warnings){
|
||||||
|
emmc_part_t *part;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
part = mmcFindPart(path, mmcType);
|
||||||
|
if (part != NULL){
|
||||||
|
res = emmcRestorePart(path, &storage, part, warnings);
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -1,394 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "../mem/heap.h"
|
|
||||||
#include "gfx.h"
|
|
||||||
#include "fs.h"
|
|
||||||
#include "../utils/types.h"
|
|
||||||
#include "../libs/fatfs/ff.h"
|
|
||||||
#include "../utils/sprintf.h"
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../utils/util.h"
|
|
||||||
|
|
||||||
fs_entry fileobjects[500];
|
|
||||||
char rootpath[10] = "";
|
|
||||||
char *currentpath = "";
|
|
||||||
char *clipboard = "";
|
|
||||||
u8 clipboardhelper = 0;
|
|
||||||
extern const char sizevalues[4][3];
|
|
||||||
extern int launch_payload(char *path);
|
|
||||||
|
|
||||||
menu_item explfilemenu[9] = {
|
|
||||||
{"-- File Menu --", COLOR_BLUE, -1, 0},
|
|
||||||
{"FILE", COLOR_GREEN, -1, 0},
|
|
||||||
{"\nSIZE", COLOR_VIOLET, -1, 0},
|
|
||||||
{"\n\n\nBack", COLOR_WHITE, -1, 1},
|
|
||||||
{"\nCopy to clipboard", COLOR_BLUE, COPY, 1},
|
|
||||||
{"Move to clipboard", COLOR_BLUE, MOVE, 1},
|
|
||||||
{"\nDelete file\n", COLOR_RED, DELETE, 1},
|
|
||||||
{"Launch Payload", COLOR_ORANGE, PAYLOAD, 1},
|
|
||||||
{"View Hex", COLOR_GREEN, HEXVIEW, 1}
|
|
||||||
};
|
|
||||||
|
|
||||||
void writecurpath(const char *in){
|
|
||||||
if (currentpath != NULL)
|
|
||||||
free(currentpath);
|
|
||||||
|
|
||||||
size_t len = strlen(in) + 1;
|
|
||||||
currentpath = (char*) malloc (len);
|
|
||||||
strcpy(currentpath, in);
|
|
||||||
|
|
||||||
strcpy(currentpath, in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeclipboard(const char *in, bool move, bool folder){
|
|
||||||
if (clipboard != NULL)
|
|
||||||
free(clipboard);
|
|
||||||
|
|
||||||
clipboardhelper = 0;
|
|
||||||
|
|
||||||
if (move)
|
|
||||||
clipboardhelper |= (OPERATIONMOVE);
|
|
||||||
else
|
|
||||||
clipboardhelper |= (OPERATIONCOPY);
|
|
||||||
|
|
||||||
if (folder)
|
|
||||||
clipboardhelper |= (ISDIR);
|
|
||||||
|
|
||||||
size_t len = strlen(in) + 1;
|
|
||||||
clipboard = (char*) malloc (len);
|
|
||||||
strcpy(clipboard, in);
|
|
||||||
|
|
||||||
strcpy(clipboard, in);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *getnextloc(char *current, char *add){
|
|
||||||
char *ret;
|
|
||||||
size_t size = strlen(current) + strlen(add) + 1;
|
|
||||||
ret = (char*) malloc (size);
|
|
||||||
if (!strcmp(rootpath, current))
|
|
||||||
sprintf(ret, "%s%s", current, add);
|
|
||||||
else
|
|
||||||
sprintf(ret, "%s/%s", current, add);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *getprevloc(char *current){
|
|
||||||
char *ret, *temp;
|
|
||||||
size_t size = strlen(current) + 1;
|
|
||||||
|
|
||||||
ret = (char*) malloc (size);
|
|
||||||
strcpy(ret, current);
|
|
||||||
|
|
||||||
temp = strrchr(ret, '/');
|
|
||||||
memset(temp, '\0', 1);
|
|
||||||
|
|
||||||
if (strlen(rootpath) > strlen(ret))
|
|
||||||
strcpy(ret, rootpath);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs_entry getfileobj(int spot){
|
|
||||||
return fileobjects[spot];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool checkfile(char* path){
|
|
||||||
FRESULT fr;
|
|
||||||
FILINFO fno;
|
|
||||||
|
|
||||||
fr = f_stat(path, &fno);
|
|
||||||
|
|
||||||
if (fr & FR_NO_FILE)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void viewbytes(char *path){
|
|
||||||
FIL in;
|
|
||||||
u8 print[2048];
|
|
||||||
u32 size;
|
|
||||||
QWORD offset = 0;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
clearscreen();
|
|
||||||
res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING);
|
|
||||||
if (res != FR_OK){
|
|
||||||
message("File Opening Failed", COLOR_RED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
msleep(200);
|
|
||||||
|
|
||||||
while (1){
|
|
||||||
f_lseek(&in, offset * 16);
|
|
||||||
|
|
||||||
res = f_read(&in, &print, 2048 * sizeof(u8), &size);
|
|
||||||
if (res != FR_OK){
|
|
||||||
message("Reading Failed", COLOR_RED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printbytes(print, size, offset * 16);
|
|
||||||
res = btn_read();
|
|
||||||
|
|
||||||
if (!res)
|
|
||||||
res = btn_wait();
|
|
||||||
|
|
||||||
if (res & BTN_VOL_DOWN && 2048 * sizeof(u8) == size)
|
|
||||||
offset++;
|
|
||||||
if (res & BTN_VOL_UP && offset > 0)
|
|
||||||
offset--;
|
|
||||||
if (res & BTN_POWER)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f_close(&in);
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy(const char *locin, const char *locout, bool print){
|
|
||||||
FIL in, out;
|
|
||||||
u64 sizeoffile, sizecopied = 0, totalsize;
|
|
||||||
UINT temp1, temp2;
|
|
||||||
u8 *buff;
|
|
||||||
unsigned int x, y, i = 0;
|
|
||||||
|
|
||||||
gfx_con_getpos(&x, &y);
|
|
||||||
|
|
||||||
if (!strcmp(locin, locout)){
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f_open(&in, locin, FA_READ | FA_OPEN_EXISTING)){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f_open(&out, locout, FA_CREATE_ALWAYS | FA_WRITE)){
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
buff = malloc (BUFSIZE);
|
|
||||||
sizeoffile = f_size(&in);
|
|
||||||
totalsize = sizeoffile;
|
|
||||||
|
|
||||||
while (sizeoffile > 0){
|
|
||||||
if (f_read(&in, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp1))
|
|
||||||
return 3;
|
|
||||||
if (f_write(&out, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp2))
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
if (temp1 != temp2)
|
|
||||||
return 5;
|
|
||||||
|
|
||||||
sizeoffile -= temp1;
|
|
||||||
sizecopied += temp1;
|
|
||||||
|
|
||||||
if (print && 10 > i++){
|
|
||||||
gfx_printf("%k[%d%%/100%%]%k", COLOR_GREEN, ((sizecopied * 100) / totalsize) ,COLOR_WHITE);
|
|
||||||
gfx_con_setpos(x, y);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
if (btn_read() & BTN_VOL_DOWN){
|
|
||||||
f_unlink(locout);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f_close(&in);
|
|
||||||
f_close(&out);
|
|
||||||
free(buff);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copyfile(const char *path, const char *outfolder){
|
|
||||||
char *filename = strrchr(path, '/');
|
|
||||||
char *outstring;
|
|
||||||
size_t outstringsize = strlen(filename) + strlen(outfolder) + 2;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
clearscreen();
|
|
||||||
|
|
||||||
outstring = (char*) malloc (outstringsize);
|
|
||||||
|
|
||||||
if (strcmp(rootpath, outfolder))
|
|
||||||
sprintf(outstring, "%s/%s", outfolder, filename + 1);
|
|
||||||
else
|
|
||||||
sprintf(outstring, "%s%s", outfolder, filename + 1);
|
|
||||||
|
|
||||||
gfx_printf("Note:\nTo stop the transfer hold Vol-\n\n%s\nProgress: ", outstring);
|
|
||||||
|
|
||||||
if (clipboardhelper & OPERATIONMOVE){
|
|
||||||
if (strcmp(rootpath, "emmc:/"))
|
|
||||||
f_rename(path, outstring);
|
|
||||||
else
|
|
||||||
message("\nMoving in emummc is not allowed!", COLOR_RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (clipboardhelper & OPERATIONCOPY) {
|
|
||||||
res = copy(path, outstring, true);
|
|
||||||
if (res){
|
|
||||||
gfx_printf("\n\n%kSomething went wrong while copying!\n\nErrcode: %d%k", COLOR_RED, res, COLOR_WHITE);
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
message("\nClipboard is empty!", COLOR_RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
free (outstring);
|
|
||||||
clipboardhelper = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 getfilesize(char *path){
|
|
||||||
FILINFO fno;
|
|
||||||
f_stat(path, &fno);
|
|
||||||
return fno.fsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addobject(char* name, int spot, bool isfol, bool isarc){
|
|
||||||
size_t length = strlen(name) + 1;
|
|
||||||
u64 size = 0;
|
|
||||||
int sizes = 0;
|
|
||||||
fileobjects[spot].property = 0;
|
|
||||||
|
|
||||||
if (fileobjects[spot].name != NULL){
|
|
||||||
free(fileobjects[spot].name);
|
|
||||||
fileobjects[spot].name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileobjects[spot].name = (char*) malloc (length);
|
|
||||||
strlcpy(fileobjects[spot].name, name, length);
|
|
||||||
|
|
||||||
if (isfol)
|
|
||||||
fileobjects[spot].property |= (ISDIR);
|
|
||||||
else {
|
|
||||||
size = getfilesize(getnextloc(currentpath, name));
|
|
||||||
|
|
||||||
while (size > 1024){
|
|
||||||
size /= 1024;
|
|
||||||
sizes++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sizes > 3)
|
|
||||||
sizes = 0;
|
|
||||||
|
|
||||||
fileobjects[spot].property |= (1 << (4 + sizes));
|
|
||||||
fileobjects[spot].size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isarc)
|
|
||||||
fileobjects[spot].property |= (ISARC);
|
|
||||||
}
|
|
||||||
|
|
||||||
int readfolder(const char *path){
|
|
||||||
DIR dir;
|
|
||||||
FILINFO fno;
|
|
||||||
int folderamount = 0, res;
|
|
||||||
|
|
||||||
if (res = f_opendir(&dir, path)){
|
|
||||||
char errmes[50] = "";
|
|
||||||
sprintf(errmes, "Error during f_opendir: %d", res);
|
|
||||||
message(errmes, COLOR_RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!f_readdir(&dir, &fno) && fno.fname[0] && folderamount < 500){
|
|
||||||
addobject(fno.fname, folderamount++, (fno.fattrib & AM_DIR), (fno.fattrib & AM_ARC));
|
|
||||||
}
|
|
||||||
|
|
||||||
f_closedir(&dir);
|
|
||||||
return folderamount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int delfile(const char *path, const char *filename){
|
|
||||||
char *tempmessage;
|
|
||||||
size_t tempmessagesize = strlen(filename) + 65;
|
|
||||||
tempmessage = (char*) malloc (tempmessagesize);
|
|
||||||
|
|
||||||
sprintf(tempmessage, "Are you sure you want to delete:\n%s\n\nPress vol+/- to cancel\n", filename);
|
|
||||||
if (makewaitmenu(tempmessage, "Press power to delete", 3)){
|
|
||||||
f_unlink(path);
|
|
||||||
return readfolder(currentpath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void filemenu(const char *startpath){
|
|
||||||
int amount, res, tempint;
|
|
||||||
char temp[100];
|
|
||||||
strcpy(rootpath, startpath);
|
|
||||||
writecurpath(startpath);
|
|
||||||
amount = readfolder(currentpath);
|
|
||||||
|
|
||||||
if (strcmp(rootpath, "emmc:/"))
|
|
||||||
explfilemenu[5].property = 1;
|
|
||||||
else
|
|
||||||
explfilemenu[5].property = -1;
|
|
||||||
|
|
||||||
while (1){
|
|
||||||
res = makefilemenu(fileobjects, amount, currentpath);
|
|
||||||
if (res < 1){
|
|
||||||
if (res == -2){
|
|
||||||
if (!strcmp(rootpath, currentpath))
|
|
||||||
break;
|
|
||||||
else {
|
|
||||||
writecurpath(getprevloc(currentpath));
|
|
||||||
amount = readfolder(currentpath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res == -1){
|
|
||||||
copyfile(clipboard, currentpath);
|
|
||||||
amount = readfolder(currentpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (fileobjects[res - 1].property & ISDIR){
|
|
||||||
writecurpath(getnextloc(currentpath, fileobjects[res - 1].name));
|
|
||||||
amount = readfolder(currentpath);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strlcpy(explfilemenu[1].name, fileobjects[res - 1].name, 43);
|
|
||||||
|
|
||||||
for (tempint = 4; tempint < 8; tempint++)
|
|
||||||
if ((fileobjects[res - 1].property & (1 << tempint)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
sprintf(temp, "\nSize: %d %s", fileobjects[res - 1].size, sizevalues[tempint - 4]);
|
|
||||||
strcpy(explfilemenu[2].name, temp);
|
|
||||||
|
|
||||||
if (strstr(fileobjects[res - 1].name, ".bin") != NULL)
|
|
||||||
explfilemenu[7].property = 1;
|
|
||||||
else
|
|
||||||
explfilemenu[7].property = -1;
|
|
||||||
|
|
||||||
tempint = makemenu(explfilemenu, 9);
|
|
||||||
|
|
||||||
switch (tempint){
|
|
||||||
case COPY:
|
|
||||||
writeclipboard(getnextloc(currentpath, fileobjects[res - 1].name), false, false);
|
|
||||||
break;
|
|
||||||
case MOVE:
|
|
||||||
writeclipboard(getnextloc(currentpath, fileobjects[res - 1].name), true, false);
|
|
||||||
break;
|
|
||||||
case DELETE:
|
|
||||||
if ((tempint = delfile(getnextloc(currentpath, fileobjects[res - 1].name), fileobjects[res - 1].name)) != -1)
|
|
||||||
amount = tempint;
|
|
||||||
break;
|
|
||||||
case PAYLOAD:
|
|
||||||
launch_payload(getnextloc(currentpath, fileobjects[res - 1].name));
|
|
||||||
break;
|
|
||||||
case HEXVIEW:
|
|
||||||
viewbytes(getnextloc(currentpath, fileobjects[res - 1].name));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../utils/types.h"
|
|
||||||
|
|
||||||
#define ISDIR (1 << 0)
|
|
||||||
#define ISARC (1 << 1)
|
|
||||||
|
|
||||||
#define ISGB (1 << 7)
|
|
||||||
#define ISMB (1 << 6)
|
|
||||||
#define ISKB (1 << 5)
|
|
||||||
#define ISB (1 << 4)
|
|
||||||
|
|
||||||
#define OPERATIONCOPY (1 << 1)
|
|
||||||
#define OPERATIONMOVE (1 << 2)
|
|
||||||
|
|
||||||
#define BUFSIZE 32768
|
|
||||||
|
|
||||||
/* Bit table for property:
|
|
||||||
0000 0001: Directory bit
|
|
||||||
0000 0010: Archive bit
|
|
||||||
0001 0000: Size component is a Byte
|
|
||||||
0010 0000: Size component is a KiloByte
|
|
||||||
0100 0000: Size component is a MegaByte
|
|
||||||
1000 0000: Size component is a GigaByte : note that this won't surpass gigabytes, but i don't expect people to have a single file that's a terrabyte big
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct _fs_entry {
|
|
||||||
char* name;
|
|
||||||
u16 size;
|
|
||||||
u8 property;
|
|
||||||
} fs_entry;
|
|
||||||
|
|
||||||
enum filemenuoptions {
|
|
||||||
COPY = 1,
|
|
||||||
MOVE,
|
|
||||||
DELETE,
|
|
||||||
PAYLOAD,
|
|
||||||
HEXVIEW
|
|
||||||
};
|
|
||||||
|
|
||||||
int readfolder(const char *path);
|
|
||||||
void filemenu();
|
|
||||||
bool checkfile(char* path);
|
|
||||||
u64 getfilesize(char *path);
|
|
||||||
int copy(const char *locin, const char *locout, bool print);
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user