Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::diag {
|
||||
|
||||
NORETURN void AbortImpl() {
|
||||
AMS_SECMON_LOG("AbortImpl was called\n");
|
||||
AMS_LOG_FLUSH();
|
||||
reg::Write(0x4, 0xAAAAAAAA);
|
||||
|
||||
/* TODO: Reboot */
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
#include <exosphere/diag/diag_detailed_assertion_impl.inc>
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.section .crt0.text.start, "ax", %progbits
|
||||
.align 6
|
||||
.global _start
|
||||
_start:
|
||||
/* Set the stack pointer to a temporary location. */
|
||||
ldr x20, =0x1F00FC000
|
||||
mov sp, x20
|
||||
|
||||
/* Save any arguments we may have. */
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
/* Initialize all memory to expected state. */
|
||||
ldr x0, =__bss_start__
|
||||
ldr x1, =__bss_end__
|
||||
bl _ZN3ams6secmon5fatal10InitializeEmm
|
||||
|
||||
/* Restore any arguments we may have. */
|
||||
ldp x0, x1, [sp], #16
|
||||
|
||||
/* Jump to the fatal program. */
|
||||
ldr x16, =_ZN3ams6secmon5fatal4MainEv
|
||||
br x16
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
extern "C" void __libc_init_array();
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void Initialize(uintptr_t bss_start, size_t bss_end) {
|
||||
/* Clear bss. */
|
||||
std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start);
|
||||
|
||||
/* Call init array. */
|
||||
__libc_init_array();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Definitions. */
|
||||
constexpr size_t PageDirectorySize = mmu::PageSize;
|
||||
constexpr size_t PageTableSize = mmu::PageSize;
|
||||
static_assert(PageDirectorySize == mmu::PageSize);
|
||||
|
||||
using DeviceVirtualAddress = u64;
|
||||
|
||||
constexpr size_t AsidCount = 0x80;
|
||||
constexpr size_t PhysicalAddressBits = 34;
|
||||
constexpr size_t PhysicalAddressMask = (1ul << PhysicalAddressBits) - 1ul;
|
||||
constexpr size_t DeviceVirtualAddressBits = 34;
|
||||
constexpr size_t DeviceVirtualAddressMask = (1ul << DeviceVirtualAddressBits) - 1ul;
|
||||
|
||||
constexpr size_t DevicePageBits = 12;
|
||||
constexpr size_t DevicePageSize = (1ul << DevicePageBits);
|
||||
static_assert(DevicePageSize == mmu::PageSize);
|
||||
|
||||
constexpr size_t DeviceLargePageBits = 22;
|
||||
constexpr size_t DeviceLargePageSize = (1ul << DeviceLargePageBits);
|
||||
static_assert(DeviceLargePageSize % DevicePageSize == 0);
|
||||
|
||||
constexpr size_t DeviceRegionBits = 32;
|
||||
constexpr size_t DeviceRegionSize = (1ul << DeviceRegionBits);
|
||||
static_assert(DeviceRegionSize % DeviceLargePageSize == 0);
|
||||
|
||||
constexpr const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
|
||||
|
||||
constexpr size_t TableCount = (1ul << DeviceVirtualAddressBits) / DeviceRegionSize;
|
||||
|
||||
consteval u32 EncodeAsidRegisterValue(u8 asid) {
|
||||
u32 value = 0x80000000u;
|
||||
for (size_t t = 0; t < TableCount; t++) {
|
||||
value |= (asid << (BITSIZEOF(u8) * t));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr u8 SdmmcAsid = 1;
|
||||
constexpr u8 DcAsid = 2;
|
||||
|
||||
constexpr u32 SdmmcAsidRegisterValue = EncodeAsidRegisterValue(SdmmcAsid);
|
||||
constexpr u32 DcAsidRegisterValue = EncodeAsidRegisterValue(DcAsid);
|
||||
|
||||
constexpr dd::PhysicalAddress DcL0PageTablePhysical = MemoryRegionPhysicalDramDcL0DevicePageTable.GetAddress();
|
||||
constexpr dd::PhysicalAddress SdmmcL0PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L0DevicePageTable.GetAddress();
|
||||
constexpr dd::PhysicalAddress SdmmcL1PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L1DevicePageTable.GetAddress();
|
||||
|
||||
/* Types. */
|
||||
class EntryBase {
|
||||
protected:
|
||||
enum Bit : u32 {
|
||||
Bit_Table = 28,
|
||||
Bit_NonSecure = 29,
|
||||
Bit_Writeable = 30,
|
||||
Bit_Readable = 31,
|
||||
};
|
||||
private:
|
||||
u32 m_value;
|
||||
protected:
|
||||
constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const {
|
||||
return (m_value & (1u << n));
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
|
||||
return this->SelectBit(n) != 0;
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 EncodeBit(Bit n, bool en) {
|
||||
return en ? (1u << n) : 0;
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 EncodeValue(bool r, bool w, bool ns, dd::PhysicalAddress addr, bool t) {
|
||||
return EncodeBit(Bit_Readable, r) | EncodeBit(Bit_Writeable, w) | EncodeBit(Bit_NonSecure, ns) | EncodeBit(Bit_Table, t) | static_cast<u32>(addr >> DevicePageBits);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SetValue(u32 v) {
|
||||
/* Prevent re-ordering around entry modifications. */
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
m_value = v;
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
}
|
||||
public:
|
||||
static constexpr ALWAYS_INLINE u32 EncodePtbDataValue(dd::PhysicalAddress addr) {
|
||||
return EncodeValue(true, true, true, addr, false);
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); }
|
||||
constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); }
|
||||
constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); }
|
||||
constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); }
|
||||
|
||||
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); }
|
||||
|
||||
constexpr ALWAYS_INLINE dd::PhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; }
|
||||
|
||||
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
|
||||
};
|
||||
|
||||
class PageDirectoryEntry : public EntryBase {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBit(Bit_Table); }
|
||||
|
||||
ALWAYS_INLINE void SetTable(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
|
||||
AMS_ASSERT(util::IsAligned(addr, DevicePageSize));
|
||||
this->SetValue(EncodeValue(r, w, ns, addr, true));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SetLargePage(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
|
||||
AMS_ASSERT(util::IsAligned(addr, DeviceLargePageSize));
|
||||
this->SetValue(EncodeValue(r, w, ns, addr, false));
|
||||
}
|
||||
};
|
||||
|
||||
class PageTableEntry : public EntryBase {
|
||||
public:
|
||||
ALWAYS_INLINE void SetPage(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
|
||||
AMS_ASSERT(util::IsAligned(addr, DevicePageSize));
|
||||
this->SetValue(EncodeValue(r, w, ns, addr, true));
|
||||
}
|
||||
};
|
||||
|
||||
/* Memory controller access functionality. */
|
||||
void WriteMcRegister(size_t offset, u32 value) {
|
||||
reg::Write(MC + offset, value);
|
||||
}
|
||||
|
||||
u32 ReadMcRegister(size_t offset) {
|
||||
return reg::Read(MC + offset);
|
||||
}
|
||||
|
||||
/* Memory controller utilities. */
|
||||
void SmmuSynchronizationBarrier() {
|
||||
ReadMcRegister(MC_SMMU_CONFIG);
|
||||
}
|
||||
|
||||
void InvalidatePtc() {
|
||||
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0);
|
||||
}
|
||||
|
||||
void InvalidatePtc(dd::PhysicalAddress address) {
|
||||
WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast<u64>(address) >> 32));
|
||||
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (address & 0xFFFFFFF0u) | 1u);
|
||||
}
|
||||
|
||||
enum TlbFlushVaMatch : u32 {
|
||||
TlbFlushVaMatch_All = 0,
|
||||
TlbFlushVaMatch_Section = 2,
|
||||
TlbFlushVaMatch_Group = 3,
|
||||
};
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 EncodeTlbFlushValue(bool match_asid, u8 asid, dd::PhysicalAddress address, TlbFlushVaMatch match) {
|
||||
return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match);
|
||||
}
|
||||
|
||||
void InvalidateTlb() {
|
||||
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All));
|
||||
}
|
||||
|
||||
void InvalidateTlb(u8 asid) {
|
||||
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All));
|
||||
}
|
||||
|
||||
void InvalidateTlbSection(u8 asid, dd::PhysicalAddress address) {
|
||||
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section));
|
||||
}
|
||||
|
||||
void SetTable(u8 asid, dd::PhysicalAddress address) {
|
||||
/* Write the table address. */
|
||||
{
|
||||
WriteMcRegister(MC_SMMU_PTB_ASID, asid);
|
||||
WriteMcRegister(MC_SMMU_PTB_DATA, EntryBase::EncodePtbDataValue(address));
|
||||
|
||||
SmmuSynchronizationBarrier();
|
||||
}
|
||||
|
||||
/* Ensure consistency. */
|
||||
InvalidatePtc();
|
||||
InvalidateTlb(asid);
|
||||
SmmuSynchronizationBarrier();
|
||||
}
|
||||
|
||||
void MapImpl(dd::PhysicalAddress phys_addr, size_t size, DeviceVirtualAddress address, u8 asid, void *l0_table, dd::PhysicalAddress l0_phys, void *l1_table, dd::PhysicalAddress l1_phys) {
|
||||
/* Validate L0. */
|
||||
AMS_ABORT_UNLESS(l0_table != nullptr);
|
||||
AMS_ABORT_UNLESS(l0_phys != 0);
|
||||
|
||||
/* Cache permissions. */
|
||||
const bool read = true;
|
||||
const bool write = true;
|
||||
|
||||
/* Walk the directory. */
|
||||
u64 remaining = size;
|
||||
while (remaining > 0) {
|
||||
const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize;
|
||||
const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize;
|
||||
|
||||
/* Get and validate l1. */
|
||||
PageDirectoryEntry *l1 = static_cast<PageDirectoryEntry *>(l0_table);
|
||||
AMS_ASSERT(l1 != nullptr);
|
||||
|
||||
/* Setup an l1 table/entry, if needed. */
|
||||
if (!l1[l1_index].IsTable()) {
|
||||
/* Check that an entry doesn't already exist. */
|
||||
AMS_ASSERT(!l1[l1_index].IsValid());
|
||||
|
||||
/* If we can make an l1 entry, do so. */
|
||||
if (l2_index == 0 && util::IsAligned(phys_addr, DeviceLargePageSize) && remaining >= DeviceLargePageSize) {
|
||||
/* Set the large page. */
|
||||
l1[l1_index].SetLargePage(read, write, true, phys_addr);
|
||||
hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
|
||||
|
||||
/* Synchronize. */
|
||||
InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry));
|
||||
InvalidateTlbSection(asid, address);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Advance. */
|
||||
phys_addr += DeviceLargePageSize;
|
||||
address += DeviceLargePageSize;
|
||||
remaining -= DeviceLargePageSize;
|
||||
continue;
|
||||
} else {
|
||||
/* Make an l1 table. */
|
||||
AMS_ABORT_UNLESS(l1_table != nullptr);
|
||||
AMS_ABORT_UNLESS(l1_phys != 0);
|
||||
|
||||
/* Clear the l1 table. */
|
||||
std::memset(l1_table, 0, mmu::PageSize);
|
||||
hw::FlushDataCache(l1_table, mmu::PageSize);
|
||||
|
||||
/* Set the l1 table. */
|
||||
l1[l1_index].SetTable(true, true, true, l1_phys);
|
||||
hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
|
||||
|
||||
/* Synchronize. */
|
||||
InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry));
|
||||
InvalidateTlbSection(asid, address);
|
||||
SmmuSynchronizationBarrier();
|
||||
}
|
||||
}
|
||||
|
||||
/* If we get to this point, l1 must be a table. */
|
||||
AMS_ASSERT(l1[l1_index].IsTable());
|
||||
AMS_ABORT_UNLESS(l1_table != nullptr);
|
||||
AMS_ABORT_UNLESS(l1_phys != 0);
|
||||
|
||||
/* Map l2 entries. */
|
||||
{
|
||||
PageTableEntry *l2 = static_cast<PageTableEntry *>(l1_table);
|
||||
|
||||
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
||||
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
||||
|
||||
/* Set the entries. */
|
||||
for (size_t i = 0; i < map_count; ++i) {
|
||||
AMS_ASSERT(!l2[l2_index + i].IsValid());
|
||||
l2[l2_index + i].SetPage(read, write, true, phys_addr + DevicePageSize * i);
|
||||
}
|
||||
hw::FlushDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
|
||||
|
||||
/* Invalidate the page table cache. */
|
||||
for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) {
|
||||
InvalidatePtc(l1_phys + i * sizeof(PageTableEntry));
|
||||
}
|
||||
|
||||
/* Synchronize. */
|
||||
InvalidateTlbSection(asid, address);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Advance. */
|
||||
phys_addr += map_count * DevicePageSize;
|
||||
address += map_count * DevicePageSize;
|
||||
remaining -= map_count * DevicePageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeDevicePageTableForSdmmc1() {
|
||||
/* Configure sdmmc to use our new page table. */
|
||||
WriteMcRegister(MC_SMMU_SDMMC1A_ASID, SdmmcAsidRegisterValue);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Ensure consistency. */
|
||||
InvalidatePtc();
|
||||
InvalidateTlb();
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Clear the L0 Page Table. */
|
||||
std::memset(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize);
|
||||
hw::FlushDataCache(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), mmu::PageSize);
|
||||
|
||||
/* Set the page table for the sdmmc asid. */
|
||||
SetTable(SdmmcAsid, SdmmcL0PageTablePhysical);
|
||||
|
||||
/* Map the appropriate region into the asid. */
|
||||
MapImpl(MemoryRegionPhysicalDramSdmmcMappedData.GetAddress(), MemoryRegionPhysicalDramSdmmcMappedData.GetSize(), MemoryRegionVirtualDramSdmmcMappedData.GetAddress(),
|
||||
SdmmcAsid,
|
||||
MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), SdmmcL0PageTablePhysical,
|
||||
MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer<void>(), SdmmcL1PageTablePhysical);
|
||||
}
|
||||
|
||||
void InitializeDevicePageTableForDc() {
|
||||
/* Configure dc to use our new page table. */
|
||||
WriteMcRegister(MC_SMMU_DC_ASID, DcAsidRegisterValue);
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Ensure consistency. */
|
||||
InvalidatePtc();
|
||||
InvalidateTlb();
|
||||
SmmuSynchronizationBarrier();
|
||||
|
||||
/* Clear the L0 Page Table. */
|
||||
std::memset(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize);
|
||||
hw::FlushDataCache(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), mmu::PageSize);
|
||||
|
||||
/* Set the page table for the dc asid. */
|
||||
SetTable(DcAsid, DcL0PageTablePhysical);
|
||||
|
||||
/* Map the appropriate region into the asid. */
|
||||
static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetAddress(), DeviceLargePageSize));
|
||||
static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetSize(), DeviceLargePageSize));
|
||||
|
||||
MapImpl(MemoryRegionDramDcFramebuffer.GetAddress(), MemoryRegionDramDcFramebuffer.GetSize(), MemoryRegionDramDcFramebuffer.GetAddress(),
|
||||
DcAsid,
|
||||
MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), DcL0PageTablePhysical,
|
||||
nullptr, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void InitializeDevicePageTableForSdmmc1();
|
||||
void InitializeDevicePageTableForDc();
|
||||
|
||||
}
|
||||
@@ -1,602 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_device_page_table.hpp"
|
||||
#include "fatal_registers_di.hpp"
|
||||
#include "fatal_display.hpp"
|
||||
#include "fatal_print.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
#include "fatal_display_config.inc"
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* Helpful defines. */
|
||||
constexpr int DsiWaitForCommandMilliSecondsMax = 250;
|
||||
constexpr int DsiWaitForCommandCompletionMilliSeconds = 5;
|
||||
constexpr int DsiWaitForHostControlMilliSecondsMax = 150;
|
||||
|
||||
constexpr inline int I2cAddressMax77620Pmic = 0x3C;
|
||||
|
||||
constexpr size_t GPIO_PORT3_CNF_0 = 0x200;
|
||||
constexpr size_t GPIO_PORT3_OE_0 = 0x210;
|
||||
constexpr size_t GPIO_PORT3_OUT_0 = 0x220;
|
||||
|
||||
constexpr size_t GPIO_PORT6_CNF_1 = 0x504;
|
||||
constexpr size_t GPIO_PORT6_OE_1 = 0x514;
|
||||
constexpr size_t GPIO_PORT6_OUT_1 = 0x524;
|
||||
|
||||
/* Globals. */
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionVirtualDevicePmc .GetAddress();
|
||||
constexpr inline const uintptr_t g_disp1_regs = secmon::MemoryRegionVirtualDeviceDisp1 .GetAddress();
|
||||
constexpr inline const uintptr_t g_dsi_regs = secmon::MemoryRegionVirtualDeviceDsi .GetAddress();
|
||||
constexpr inline const uintptr_t g_clk_rst_regs = secmon::MemoryRegionVirtualDeviceClkRst .GetAddress();
|
||||
constexpr inline const uintptr_t g_gpio_regs = secmon::MemoryRegionVirtualDeviceGpio .GetAddress();
|
||||
constexpr inline const uintptr_t g_apb_misc_regs = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress();
|
||||
constexpr inline const uintptr_t g_mipi_cal_regs = secmon::MemoryRegionVirtualDeviceMipiCal.GetAddress();
|
||||
|
||||
constinit u32 *g_frame_buffer = nullptr;
|
||||
|
||||
inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
reg::Write(base_address + reg_writes[i].offset, reg_writes[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) {
|
||||
switch (GetSocType()) {
|
||||
case fuse::SocType_Erista: DoRegisterWrites(base_address, reg_writes_erista, num_writes_erista); break;
|
||||
case fuse::SocType_Mariko: DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
inline void DoSleepOrRegisterWrites(uintptr_t base_address, const SleepOrRegisterWrite *reg_writes, size_t num_writes) {
|
||||
for (size_t i = 0; i < num_writes; i++) {
|
||||
switch (reg_writes[i].kind) {
|
||||
case SleepOrRegisterWriteKind_Write:
|
||||
reg::Write(base_address + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value);
|
||||
break;
|
||||
case SleepOrRegisterWriteKind_Sleep:
|
||||
util::WaitMicroSeconds(reg_writes[i].offset * UINT64_C(1000));
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaitDsiTrigger() {
|
||||
const u32 timeout = util::GetMicroSeconds() + (DsiWaitForCommandMilliSecondsMax * 1000u);
|
||||
|
||||
while (true) {
|
||||
if (util::GetMicroSeconds() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
util::WaitMicroSeconds(DsiWaitForCommandCompletionMilliSeconds * 1000u);
|
||||
}
|
||||
|
||||
void WaitDsiHostControl() {
|
||||
const u32 timeout = util::GetMicroSeconds() + (DsiWaitForHostControlMilliSecondsMax * 1000u);
|
||||
|
||||
while (true) {
|
||||
if (util::GetMicroSeconds() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EnableBacklightForVendor2050ForAula(int brightness) {
|
||||
/* Enable FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 2);
|
||||
|
||||
/* Configure DSI_LINE_TYPE as FOUR */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 9);
|
||||
|
||||
/* Set and wait for FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ }
|
||||
|
||||
/* Configure display brightness. */
|
||||
const u32 brightness_val = ((0x7FF * brightness) / 100);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, (brightness_val & 0x700) | ((brightness_val & 0xFF) << 16) | 0x51);
|
||||
|
||||
/* Set and wait for FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ }
|
||||
|
||||
/* Set client sync point block reset. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 1);
|
||||
util::WaitMicroSeconds(300'000ul);
|
||||
|
||||
/* Clear client sync point block resest. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 0);
|
||||
util::WaitMicroSeconds(300'000ul);
|
||||
|
||||
/* Clear DSI_LINE_TYPE config. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0);
|
||||
|
||||
/* Disable FRAME_END_INT */
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 0);
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2);
|
||||
}
|
||||
|
||||
void EnableBacklightForGeneric(int brightness) {
|
||||
AMS_UNUSED(brightness);
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
}
|
||||
|
||||
#define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes))
|
||||
#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko))
|
||||
#define DO_SLEEP_OR_REGISTER_WRITES(base_address, writes) DoSleepOrRegisterWrites(base_address, writes, util::size(writes))
|
||||
|
||||
void InitializeFrameBuffer() {
|
||||
if (g_frame_buffer != nullptr) {
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
} else {
|
||||
/* Clear the frame buffer. */
|
||||
g_frame_buffer = secmon::MemoryRegionDramDcFramebuffer.GetPointer<u32>();
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Attach the frame buffer to DC. */
|
||||
InitializeDevicePageTableForDc();
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] void FinalizeFrameBuffer() {
|
||||
/* We don't actually support finalizing the framebuffer, so do nothing here. */
|
||||
}
|
||||
|
||||
constexpr const char *GetErrorDescription(u32 error_desc) {
|
||||
switch (error_desc) {
|
||||
case 0x100:
|
||||
return "Instruction Abort";
|
||||
case 0x101:
|
||||
return "Data Abort";
|
||||
case 0x102:
|
||||
return "PC Misalignment";
|
||||
case 0x103:
|
||||
return "SP Misalignment";
|
||||
case 0x104:
|
||||
return "Trap";
|
||||
case 0x106:
|
||||
return "SError";
|
||||
case 0x301:
|
||||
return "Bad SVC";
|
||||
case 0xF00:
|
||||
return "Kernel Panic";
|
||||
case 0xFFD:
|
||||
return "Stack overflow";
|
||||
case 0xFFE:
|
||||
return "std::abort() called";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintSuggestedErrorFix(const ams::impl::FatalErrorContext *f_ctx) {
|
||||
/* Try to recognize certain errors automatically, and suggest fixes for them. */
|
||||
const char *suggestion = nullptr;
|
||||
|
||||
constexpr u64 ProgramIdAmsMitm = UINT64_C(0x010041544D530000);
|
||||
constexpr u64 ProgramIdBoot = UINT64_C(0x0100000000000005);
|
||||
if (f_ctx->error_desc == 0xFFE) {
|
||||
if (f_ctx->program_id == ProgramIdAmsMitm) {
|
||||
/* When a user has archive bits set improperly, attempting to create an automatic backup will fail */
|
||||
/* to create the file path with error 0x202 */
|
||||
if (f_ctx->gprs[0] == fs::ResultPathNotFound().GetValue()) {
|
||||
/* When the archive bit error is occurring, it manifests as failure to create automatic backup. */
|
||||
/* Thus, we can search the stack for the automatic backups path. */
|
||||
const char * const automatic_backups_prefix = "automatic_backups/X" /* ..... */;
|
||||
const int prefix_len = std::strlen(automatic_backups_prefix);
|
||||
|
||||
for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) {
|
||||
if (std::memcmp(f_ctx->stack_dump + i, automatic_backups_prefix, prefix_len) == 0) {
|
||||
suggestion = "The atmosphere directory may improperly have archive bits set.\n"
|
||||
"Please try running an archive bit fixer tool (for example, the one in Hekate).\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (f_ctx->gprs[0] == fs::ResultExFatUnavailable().GetValue()) {
|
||||
/* When a user installs non-exFAT firm but has an exFAT formatted SD card, this error will */
|
||||
/* be returned on attempt to access the SD card. */
|
||||
suggestion = "Your console has non-exFAT firmware installed, but your SD card\n"
|
||||
"is formatted as exFAT. Format your SD card as FAT32, or manually\n"
|
||||
"flash exFAT firmware to package2.\n";
|
||||
}
|
||||
} else if (f_ctx->program_id == ProgramIdBoot) {
|
||||
/* 9.x -> 10.x updated the API for SvcQueryIoMapping. */
|
||||
/* This can cause the kernel to reject incorrect-ABI calls by boot when a partial update is applied */
|
||||
/* (older kernel in package2, for some reason). */
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
if (f_ctx->gprs[i] == svc::ResultNotFound().GetValue()) {
|
||||
suggestion = "A partial update may have been improperly performed.\n"
|
||||
"To fix, try manually flashing latest package2 to MMC.\n"
|
||||
"\n"
|
||||
"For help doing this, seek support in the ReSwitched or\n"
|
||||
"Nintendo Homebrew discord servers.\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (f_ctx->error_desc == 0xF00) { /* Kernel Panic */
|
||||
suggestion = "Please contact SciresM#0524 on Discord, or create an issue on the Atmosphere\n"
|
||||
"GitHub issue tracker. Thank you very much for helping to test mesosphere.\n";
|
||||
}
|
||||
|
||||
/* If we found a suggestion, print it. */
|
||||
if (suggestion != nullptr) {
|
||||
Print("%s", suggestion);
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeDisplay() {
|
||||
/* TODO: What other configuration is needed, if any? */
|
||||
|
||||
/* Configure LCD pinmux tristate + passthrough. */
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
|
||||
if (fuse::GetHardwareType() == fuse::HardwareType_Aula) {
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4);
|
||||
} else {
|
||||
/* Configure LCD power, VDD. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
|
||||
}
|
||||
|
||||
/* Disable the LCD backlight. */
|
||||
if (GetLcdVendor() == 0x2050) {
|
||||
/* TODO: We're not sure display is alive. How to manage this? */
|
||||
/* This is probably incorrect backlight disable for hw-type 5. */
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
} else {
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
|
||||
}
|
||||
|
||||
/* Disable backlight RST/Voltage. */
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
if (GetLcdVendor() == 0x2050) {
|
||||
util::WaitMicroSeconds(30'000ul);
|
||||
} else {
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
}
|
||||
|
||||
/* Cut clock to DSI. */
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_MIPI_CAL_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_DSI_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_MIPI_CAL, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_DSI, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_HOST1X_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_DISP1_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_HOST1X, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_DISP1, ENABLE));
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_PAD_CONTROL_0, (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF)));
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeDisplay() {
|
||||
/* Ensure that the display is finalized. */
|
||||
FinalizeDisplay();
|
||||
|
||||
/* Setup the framebuffer. */
|
||||
InitializeFrameBuffer();
|
||||
|
||||
/* Get the hardware type. */
|
||||
const auto hw_type = fuse::GetHardwareType();
|
||||
|
||||
/* Turn on DSI/voltage rail. */
|
||||
{
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A);
|
||||
}
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x23, 0xD0);
|
||||
}
|
||||
|
||||
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_MIPI_CAL_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_DSI_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_MIPI_CAL, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_DSI, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_HOST1X_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_DISP1_RST, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_HOST1X, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_DISP1, ENABLE));
|
||||
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_SET_SET_CLK_ENB_UART_FST_MIPI_CAL, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_DIVISOR, 10),
|
||||
CLK_RST_REG_BITS_ENUM (CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_SRC, PLLP_OUT3));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DSIA_LP, ENABLE));
|
||||
|
||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_DIVISOR, 10),
|
||||
CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_SRC, PLLP_OUT0));
|
||||
|
||||
/* Set IO_DPD_REQ to DPD_OFF. */
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD_REQ, PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_OFF));
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD2_REQ, PMC_REG_BITS_ENUM(IO_DPD2_REQ_CODE, DPD_OFF));
|
||||
|
||||
/* Configure LCD pinmux tristate + passthrough. */
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||
|
||||
if (hw_type == fuse::HardwareType_Aula) {
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4);
|
||||
} else {
|
||||
/* Configure LCD power, VDD. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Configure LCD backlight. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
|
||||
}
|
||||
|
||||
/* Configure display interface and display. */
|
||||
reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0);
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0);
|
||||
reg::Write(g_apb_misc_regs + APB_MISC_GP_DSI_PAD_CONTROL, 0);
|
||||
}
|
||||
|
||||
/* Execute configs. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init03);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init04);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init05);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init06);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init07);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Enable backlight reset. */
|
||||
reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
|
||||
util::WaitMicroSeconds(60'000ul);
|
||||
|
||||
if (hw_type == fuse::HardwareType_Aula) {
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x40103);
|
||||
} else {
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204);
|
||||
}
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
WaitDsiTrigger();
|
||||
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC);
|
||||
WaitDsiHostControl();
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
|
||||
/* Parse LCD vendor. */
|
||||
{
|
||||
u32 host_response[3];
|
||||
for (size_t i = 0; i < util::size(host_response); i++) {
|
||||
host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA);
|
||||
}
|
||||
|
||||
/* The last word from host response is:
|
||||
Bits 0-7: FAB
|
||||
Bits 8-15: REV
|
||||
Bits 16-23: Minor REV
|
||||
*/
|
||||
u32 lcd_vendor;
|
||||
if ((host_response[2] & 0xFF) == 0x10) {
|
||||
lcd_vendor = 0;
|
||||
} else {
|
||||
lcd_vendor = (host_response[2] >> 8) & 0xFF00;
|
||||
}
|
||||
lcd_vendor = (lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF);
|
||||
|
||||
AMS_ASSERT(lcd_vendor == GetLcdVendor());
|
||||
}
|
||||
|
||||
/* LCD vendor specific configuration. */
|
||||
switch (GetLcdVendor()) {
|
||||
case 0x10: /* Japan Display Inc screens. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificInit01);
|
||||
break;
|
||||
case 0xF20: /* Innolux first revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(180'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0xF30: /* AUO first revision screens. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(180'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0x2050: /* Unknown (hardware type 5) screen. */
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(180'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xA015);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x205315);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x51);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(5'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
case 0x1020: /* Innolux second revision screen. */
|
||||
case 0x1030: /* AUO second revision screen. */
|
||||
case 0x1040: /* Unknown second revision screen. */
|
||||
default:
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
util::WaitMicroSeconds(120'000ul);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
|
||||
reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
|
||||
break;
|
||||
}
|
||||
util::WaitMicroSeconds(20'000ul);
|
||||
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld02);
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init08);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09);
|
||||
|
||||
reg::Write(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4));
|
||||
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10);
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Configure MIPI CAL. */
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal01);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
if (GetSocType() == fuse::SocType_Mariko) {
|
||||
/* On Mariko the above configurations are executed twice, for some reason. */
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11);
|
||||
DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03);
|
||||
DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04);
|
||||
}
|
||||
util::WaitMicroSeconds(10'000ul);
|
||||
|
||||
/* Write DISP1, FrameBuffer config. */
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc02);
|
||||
DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigFrameBuffer);
|
||||
if (GetLcdVendor() != 0x2050) {
|
||||
util::WaitMicroSeconds(35'000ul);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) {
|
||||
/* Initialize the console. */
|
||||
InitializeConsole(g_frame_buffer);
|
||||
{
|
||||
Print("%s\n", "A fatal error occurred when running Atmosph\xe8re.");
|
||||
Print("Program ID: %016" PRIx64 "\n", f_ctx->program_id);
|
||||
Print("Error Desc: %s (0x%x)\n", GetErrorDescription(f_ctx->error_desc), f_ctx->error_desc);
|
||||
Print("\n");
|
||||
|
||||
if (R_SUCCEEDED(save_result)) {
|
||||
Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin", f_ctx->report_identifier);
|
||||
} else {
|
||||
Print("Failed to save report to the SD card! (%08x)\n", save_result.GetValue());
|
||||
}
|
||||
|
||||
PrintSuggestedErrorFix(f_ctx);
|
||||
|
||||
Print("\nPress POWER to reboot.\n");
|
||||
}
|
||||
|
||||
/* Ensure the device will see consistent data. */
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
|
||||
/* Enable backlight. */
|
||||
constexpr auto DisplayBrightness = 100;
|
||||
if (GetLcdVendor() == 0x2050) {
|
||||
EnableBacklightForVendor2050ForAula(DisplayBrightness);
|
||||
} else {
|
||||
EnableBacklightForGeneric(DisplayBrightness);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
constexpr inline size_t FrameBufferHeight = 768;
|
||||
constexpr inline size_t FrameBufferWidth = 1280;
|
||||
constexpr inline size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
||||
|
||||
void InitializeDisplay();
|
||||
void ShowDisplay();
|
||||
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result);
|
||||
|
||||
}
|
||||
@@ -1,682 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct RegisterWrite {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum SleepOrRegisterWriteKind : u16 {
|
||||
SleepOrRegisterWriteKind_Write = 0,
|
||||
SleepOrRegisterWriteKind_Sleep = 1,
|
||||
};
|
||||
|
||||
struct SleepOrRegisterWrite {
|
||||
SleepOrRegisterWriteKind kind;
|
||||
u16 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld01Erista[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld01Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDc01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_REG_ACT_CONTROL, 0x54},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DC_MCCIF_FIFOCTRL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{SleepOrRegisterWriteKind_Write, 0x4E4, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init01[] = {
|
||||
{sizeof(u32) * DSI_WR_DATA, 0x0},
|
||||
{sizeof(u32) * DSI_INT_ENABLE, 0x0},
|
||||
{sizeof(u32) * DSI_INT_STATUS, 0x0},
|
||||
{sizeof(u32) * DSI_INT_MASK, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_0, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_1, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_2, 0x0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init02Erista[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init02Mariko[] = {
|
||||
{sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init03[] = {
|
||||
{sizeof(u32) * DSI_DCS_CMDS, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_LO, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_0_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_1_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_2_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_3_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_4_HI, 0},
|
||||
{sizeof(u32) * DSI_PKT_SEQ_5_HI, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init04Erista[] = {
|
||||
/* No register writes. */
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init04Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init05[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_CD, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 0x18},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_0_1, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_2_3, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_4_5, 0},
|
||||
{sizeof(u32) * DSI_PKT_LEN_6_7, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init06[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init07[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsiPhyTimingErista[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsiPhyTimingMariko[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1939},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAA},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1BD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2739},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2BD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x6D915},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1105},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Sleep, 180, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2905},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld02Erista[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigPlld02Mariko[] = {
|
||||
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
|
||||
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init08[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDsi01Init09[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_2, 0x30172},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_BTA_TIMING, 0x190A14},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TO_TALLY, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_0_LO, 0x40000208},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_2_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_4_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_1_LO, 0x40000308},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_LO, 0x3F3B2B08},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_HI, 0x2CC},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_LO, 0x3F3B2B08},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_HI, 0x2CC},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_0_1, 0xCE0000},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_2_3, 0x87001A2},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_4_5, 0x190},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_6_7, 0x190},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_HOST_CONTROL, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init10[] = {
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_SOL_DELAY, 6},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init11Erista[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0}
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Init11Mariko[] = {
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_2, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_3, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_4, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0x77777},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal01[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG0, 1},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal02Erista[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal02Mariko[] = {
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010},
|
||||
{MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal03Erista[] = {
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200},
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal03Mariko[] = {
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006},
|
||||
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000},
|
||||
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigMipiCal04[] = {
|
||||
{MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0},
|
||||
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0},
|
||||
{MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigDc02[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
/* Setup default YUV colorspace conversion coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0},
|
||||
/* End of color coefficients */
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0},
|
||||
{SleepOrRegisterWriteKind_Write, 0x4E4, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
/* Set Display timings */
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_TIMING_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1.
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_SYNC_WIDTH, 0x10048},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_BACK_PORCH, 0x90048},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_ACTIVE, 0x50002D0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
|
||||
/* End of Display timings */
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_ENABLE(1), 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
|
||||
};
|
||||
|
||||
constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000;
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigFrameBuffer[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_POSITION, 0}, //(0,0)
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_H_INITIAL_DDA, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_V_INITIAL_DDA, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_BUFFER_CONTROL, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_START_ADDR, DisplayConfigFrameBufferAddress}, //Framebuffer address.
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0},
|
||||
{SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
|
||||
{SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
|
||||
{SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDc01Fini01[] = {
|
||||
{sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088},
|
||||
{sizeof(u32) * DC_CMD_INT_MASK, 0},
|
||||
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
|
||||
{sizeof(u32) * DC_CMD_INT_ENABLE, 0},
|
||||
{sizeof(u32) * DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Fini01[] = {
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, 0},
|
||||
{sizeof(u32) * DSI_PAD_CONTROL_1, 0},
|
||||
};
|
||||
|
||||
constexpr const RegisterWrite DisplayConfigDsi01Fini02[] = {
|
||||
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
|
||||
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
|
||||
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
|
||||
{sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
|
||||
{sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
|
||||
{sizeof(u32) * DSI_TO_TALLY, 0},
|
||||
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
|
||||
{sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
|
||||
{sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
|
||||
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x40},
|
||||
{sizeof(u32) * DSI_TRIGGER, 0},
|
||||
{sizeof(u32) * DSI_TX_CRC, 0},
|
||||
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificFini01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2139},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x4F0F41B1},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF179A433},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2D81},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
};
|
||||
|
||||
constexpr const SleepOrRegisterWrite DisplayConfigAuoRev1SpecificFini01[] = {
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D6},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x711148B1},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x71143209},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x114D31},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9},
|
||||
{SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
|
||||
{SleepOrRegisterWriteKind_Sleep, 5, 0},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_sdmmc.hpp"
|
||||
#include "fatal_save_context.hpp"
|
||||
#include "fatal_sound.hpp"
|
||||
#include "fatal_display.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int I2cAddressMax77620Pmic = 0x3C;
|
||||
|
||||
ALWAYS_INLINE const ams::impl::FatalErrorContext *GetFatalErrorContext() {
|
||||
return MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<ams::impl::FatalErrorContext>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Main() {
|
||||
/* Set library register addresses. */
|
||||
actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress());
|
||||
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
|
||||
flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress());
|
||||
fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress());
|
||||
gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress());
|
||||
i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress());
|
||||
i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress());
|
||||
pinmux::SetRegisterAddress(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress());
|
||||
pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress());
|
||||
se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress(), MemoryRegionVirtualDeviceSecurityEngine2.GetAddress());
|
||||
uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress());
|
||||
wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
|
||||
util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
|
||||
|
||||
/* Ensure that the log library is initialized. */
|
||||
log::Initialize();
|
||||
|
||||
AMS_SECMON_LOG("%s\n", "Fatal start.");
|
||||
|
||||
/* Save the fatal error context. */
|
||||
const auto *f_ctx = GetFatalErrorContext();
|
||||
Result result = SaveFatalErrorContext(f_ctx);
|
||||
if (R_SUCCEEDED(result)) {
|
||||
AMS_SECMON_LOG("Saved fatal error context to /atmosphere/fatal_reports/report_%016" PRIx64 ".bin!\n", f_ctx->report_identifier);
|
||||
} else {
|
||||
AMS_SECMON_LOG("Failed to save fatal error context: %08x\n", result.GetValue());
|
||||
}
|
||||
|
||||
/* Ensure that i2c-1/i2c-5 are usable for communicating with the audio device/pmic. */
|
||||
clkrst::EnableI2c1Clock();
|
||||
clkrst::EnableI2c5Clock();
|
||||
i2c::Initialize(i2c::Port_1);
|
||||
i2c::Initialize(i2c::Port_5);
|
||||
|
||||
/* Shut down audio. */
|
||||
{
|
||||
StopSound();
|
||||
}
|
||||
|
||||
/* Display the fatal error. */
|
||||
{
|
||||
AMS_SECMON_LOG("Showing Display, LCD Vendor = %04x\n", GetLcdVendor());
|
||||
InitializeDisplay();
|
||||
ShowDisplay(f_ctx, result);
|
||||
}
|
||||
|
||||
/* Ensure we have nothing waiting to be logged. */
|
||||
AMS_LOG_FLUSH();
|
||||
|
||||
/* Wait for power button to be pressed. */
|
||||
while (!pmic::IsPowerButtonPressed()) {
|
||||
util::WaitMicroSeconds(100);
|
||||
}
|
||||
|
||||
/* Reboot. */
|
||||
pmic::ShutdownSystem(true);
|
||||
|
||||
/* Wait for our reboot to complete. */
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_display.hpp"
|
||||
#include "fatal_print.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
#include "fatal_font.inc"
|
||||
|
||||
constexpr inline const u32 TextColor = 0xFFA0A0A0;
|
||||
|
||||
constexpr inline const size_t ConsoleWidth = FrameBufferWidth / FontWidth;
|
||||
constexpr inline const size_t ConsoleHeight = FrameBufferHeight / FontHeight;
|
||||
|
||||
constinit u32 *g_frame_buffer = nullptr;
|
||||
constinit size_t g_col = 1;
|
||||
constinit size_t g_row = 0;
|
||||
|
||||
void SetPixel(size_t x, size_t y, u32 color) {
|
||||
g_frame_buffer[(FrameBufferWidth - x) * FrameBufferHeight + y] = color;
|
||||
}
|
||||
|
||||
void PutCarriageReturn() {
|
||||
g_col = 1;
|
||||
}
|
||||
|
||||
void PutNewLine() {
|
||||
g_col = 1;
|
||||
++g_row;
|
||||
|
||||
/* TODO: Support scrolling? */
|
||||
}
|
||||
|
||||
void PutCharImpl(const char c) {
|
||||
/* Get the character data for the font. */
|
||||
const u8 * cdata = FontData + c * (FontHeight * util::DivideUp(FontWidth, BITSIZEOF(u8)));
|
||||
|
||||
/* Determine where to start drawing. */
|
||||
const size_t x = g_col * FontWidth;
|
||||
const size_t y = g_row * FontHeight;
|
||||
|
||||
for (size_t cur_y = 0; cur_y < FontHeight; ++cur_y) {
|
||||
size_t cur_x = 0;
|
||||
int wbits = FontWidth;
|
||||
while (wbits > 0) {
|
||||
const auto bits = *(cdata++);
|
||||
|
||||
SetPixel(x + cur_x + 0, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][0] & TextColor);
|
||||
SetPixel(x + cur_x + 1, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][1] & TextColor);
|
||||
SetPixel(x + cur_x + 2, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][2] & TextColor);
|
||||
SetPixel(x + cur_x + 3, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][3] & TextColor);
|
||||
SetPixel(x + cur_x + 4, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][0] & TextColor);
|
||||
SetPixel(x + cur_x + 5, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][1] & TextColor);
|
||||
SetPixel(x + cur_x + 6, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][2] & TextColor);
|
||||
SetPixel(x + cur_x + 7, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][3] & TextColor);
|
||||
|
||||
cur_x += BITSIZEOF(u8);
|
||||
wbits -= BITSIZEOF(u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PutChar(const char c) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
PutCarriageReturn();
|
||||
break;
|
||||
case '\n':
|
||||
PutNewLine();
|
||||
break;
|
||||
default:
|
||||
PutCharImpl(c);
|
||||
if ((++g_col) >= ConsoleWidth) {
|
||||
PutNewLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeConsole(u32 *frame_buffer) {
|
||||
/* Setup the console variables. */
|
||||
g_frame_buffer = frame_buffer;
|
||||
g_col = 1;
|
||||
g_row = 0;
|
||||
|
||||
/* Clear the console. */
|
||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||
}
|
||||
|
||||
void Print(const char *fmt, ...) {
|
||||
/* Generate the string. */
|
||||
char log_str[1_KB];
|
||||
{
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
util::TVSNPrintf(log_str, sizeof(log_str), fmt, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
/* Print each character. */
|
||||
const size_t len = std::strlen(log_str);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
PutChar(log_str[i]);
|
||||
}
|
||||
|
||||
/* Flush the console. */
|
||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void InitializeConsole(u32 *frame_buffer);
|
||||
void Print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
|
||||
|
||||
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
|
||||
#define SYNCPT_CNTRL_NO_STALL (1 << 8)
|
||||
#define SYNCPT_CNTRL_SOFT_RESET (1 << 0)
|
||||
|
||||
#define DC_CMD_CONT_SYNCPT_VSYNC 0x28
|
||||
#define SYNCPT_VSYNC_ENABLE (1 << 8)
|
||||
|
||||
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
|
||||
|
||||
#define DC_CMD_DISPLAY_COMMAND 0x32
|
||||
#define DISP_CTRL_MODE_STOP (0 << 5)
|
||||
#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
|
||||
#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
|
||||
#define DISP_CTRL_MODE_MASK (3 << 5)
|
||||
|
||||
#define DC_CMD_DISPLAY_POWER_CONTROL 0x36
|
||||
#define PW0_ENABLE (1 << 0)
|
||||
#define PW1_ENABLE (1 << 2)
|
||||
#define PW2_ENABLE (1 << 4)
|
||||
#define PW3_ENABLE (1 << 6)
|
||||
#define PW4_ENABLE (1 << 8)
|
||||
#define PM0_ENABLE (1 << 16)
|
||||
#define PM1_ENABLE (1 << 18)
|
||||
|
||||
#define DC_CMD_INT_STATUS 0x37
|
||||
#define DC_CMD_INT_MASK 0x38
|
||||
#define DC_CMD_INT_ENABLE 0x39
|
||||
|
||||
#define DC_CMD_STATE_ACCESS 0x40
|
||||
#define READ_MUX (1 << 0)
|
||||
#define WRITE_MUX (1 << 2)
|
||||
|
||||
#define DC_CMD_STATE_CONTROL 0x41
|
||||
#define GENERAL_ACT_REQ (1 << 0)
|
||||
#define WIN_A_ACT_REQ (1 << 1)
|
||||
#define WIN_B_ACT_REQ (1 << 2)
|
||||
#define WIN_C_ACT_REQ (1 << 3)
|
||||
#define CURSOR_ACT_REQ (1 << 7)
|
||||
#define GENERAL_UPDATE (1 << 8)
|
||||
#define WIN_A_UPDATE (1 << 9)
|
||||
#define WIN_B_UPDATE (1 << 10)
|
||||
#define WIN_C_UPDATE (1 << 11)
|
||||
#define CURSOR_UPDATE (1 << 15)
|
||||
#define NC_HOST_TRIG (1 << 24)
|
||||
|
||||
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42
|
||||
#define WINDOW_A_SELECT (1 << 4)
|
||||
#define WINDOW_B_SELECT (1 << 5)
|
||||
#define WINDOW_C_SELECT (1 << 6)
|
||||
|
||||
#define DC_CMD_REG_ACT_CONTROL 0x043
|
||||
|
||||
#define DC_COM_CRC_CONTROL 0x300
|
||||
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
|
||||
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
|
||||
|
||||
#define DC_COM_DSC_TOP_CTL 0x33E
|
||||
|
||||
#define DC_DISP_DISP_WIN_OPTIONS 0x402
|
||||
#define HDMI_ENABLE (1 << 30)
|
||||
#define DSI_ENABLE (1 << 29)
|
||||
#define SOR1_TIMING_CYA (1 << 27)
|
||||
#define SOR1_ENABLE (1 << 26)
|
||||
#define SOR_ENABLE (1 << 25)
|
||||
#define CURSOR_ENABLE (1 << 16)
|
||||
|
||||
#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
|
||||
#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
|
||||
#define DC_DISP_DISP_TIMING_OPTIONS 0x405
|
||||
#define DC_DISP_REF_TO_SYNC 0x406
|
||||
#define DC_DISP_SYNC_WIDTH 0x407
|
||||
#define DC_DISP_BACK_PORCH 0x408
|
||||
#define DC_DISP_ACTIVE 0x409
|
||||
#define DC_DISP_FRONT_PORCH 0x40A
|
||||
|
||||
#define DC_DISP_DISP_CLOCK_CONTROL 0x42E
|
||||
#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
|
||||
#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
|
||||
#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
|
||||
|
||||
#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F
|
||||
#define DISP_DATA_FORMAT_DF1P1C (0 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0)
|
||||
#define DISP_DATA_FORMAT_DF2S (4 << 0)
|
||||
#define DISP_DATA_FORMAT_DF3S (5 << 0)
|
||||
#define DISP_DATA_FORMAT_DFSPI (6 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0)
|
||||
#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0)
|
||||
#define DISP_ALIGNMENT_MSB (0 << 8)
|
||||
#define DISP_ALIGNMENT_LSB (1 << 8)
|
||||
#define DISP_ORDER_RED_BLUE (0 << 9)
|
||||
#define DISP_ORDER_BLUE_RED (1 << 9)
|
||||
|
||||
#define DC_DISP_DISP_COLOR_CONTROL 0x430
|
||||
#define DITHER_CONTROL_MASK (3 << 8)
|
||||
#define DITHER_CONTROL_DISABLE (0 << 8)
|
||||
#define DITHER_CONTROL_ORDERED (2 << 8)
|
||||
#define DITHER_CONTROL_ERRDIFF (3 << 8)
|
||||
#define BASE_COLOR_SIZE_MASK (0xf << 0)
|
||||
#define BASE_COLOR_SIZE_666 (0 << 0)
|
||||
#define BASE_COLOR_SIZE_111 (1 << 0)
|
||||
#define BASE_COLOR_SIZE_222 (2 << 0)
|
||||
#define BASE_COLOR_SIZE_333 (3 << 0)
|
||||
#define BASE_COLOR_SIZE_444 (4 << 0)
|
||||
#define BASE_COLOR_SIZE_555 (5 << 0)
|
||||
#define BASE_COLOR_SIZE_565 (6 << 0)
|
||||
#define BASE_COLOR_SIZE_332 (7 << 0)
|
||||
#define BASE_COLOR_SIZE_888 (8 << 0)
|
||||
|
||||
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
|
||||
#define SC1_H_QUALIFIER_NONE (1 << 16)
|
||||
#define SC0_H_QUALIFIER_NONE (1 << 0)
|
||||
|
||||
#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
|
||||
#define DE_SELECT_ACTIVE_BLANK (0 << 0)
|
||||
#define DE_SELECT_ACTIVE (1 << 0)
|
||||
#define DE_SELECT_ACTIVE_IS (2 << 0)
|
||||
#define DE_CONTROL_ONECLK (0 << 2)
|
||||
#define DE_CONTROL_NORMAL (1 << 2)
|
||||
#define DE_CONTROL_EARLY_EXT (2 << 2)
|
||||
#define DE_CONTROL_EARLY (3 << 2)
|
||||
#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
|
||||
|
||||
#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
|
||||
#define DC_DISP_SD_BL_PARAMETERS 0x4D7
|
||||
#define DC_DISP_SD_BL_CONTROL 0x4DC
|
||||
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
|
||||
|
||||
#define DC_WIN_CSC_YOF 0x611
|
||||
#define DC_WIN_CSC_KYRGB 0x612
|
||||
#define DC_WIN_CSC_KUR 0x613
|
||||
#define DC_WIN_CSC_KVR 0x614
|
||||
#define DC_WIN_CSC_KUG 0x615
|
||||
#define DC_WIN_CSC_KVG 0x616
|
||||
#define DC_WIN_CSC_KUB 0x617
|
||||
#define DC_WIN_CSC_KVB 0x618
|
||||
#define DC_WIN_AD_WIN_OPTIONS 0xB80
|
||||
#define DC_WIN_BD_WIN_OPTIONS 0xD80
|
||||
#define DC_WIN_CD_WIN_OPTIONS 0xF80
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER).
|
||||
#define DC_WIN_WIN_OPTIONS 0x700
|
||||
#define H_DIRECTION (1 << 0)
|
||||
#define V_DIRECTION (1 << 2)
|
||||
#define SCAN_COLUMN (1 << 4)
|
||||
#define COLOR_EXPAND (1 << 6)
|
||||
#define CSC_ENABLE (1 << 18)
|
||||
#define WIN_ENABLE (1 << 30)
|
||||
|
||||
#define DC_WIN_COLOR_DEPTH 0x703
|
||||
#define WIN_COLOR_DEPTH_P1 0x0
|
||||
#define WIN_COLOR_DEPTH_P2 0x1
|
||||
#define WIN_COLOR_DEPTH_P4 0x2
|
||||
#define WIN_COLOR_DEPTH_P8 0x3
|
||||
#define WIN_COLOR_DEPTH_B4G4R4A4 0x4
|
||||
#define WIN_COLOR_DEPTH_B5G5R5A 0x5
|
||||
#define WIN_COLOR_DEPTH_B5G6R5 0x6
|
||||
#define WIN_COLOR_DEPTH_AB5G5R5 0x7
|
||||
#define WIN_COLOR_DEPTH_B8G8R8A8 0xC
|
||||
#define WIN_COLOR_DEPTH_R8G8B8A8 0xD
|
||||
#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE
|
||||
#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF
|
||||
#define WIN_COLOR_DEPTH_YCbCr422 0x10
|
||||
#define WIN_COLOR_DEPTH_YUV422 0x11
|
||||
#define WIN_COLOR_DEPTH_YCbCr420P 0x12
|
||||
#define WIN_COLOR_DEPTH_YUV420P 0x13
|
||||
#define WIN_COLOR_DEPTH_YCbCr422P 0x14
|
||||
#define WIN_COLOR_DEPTH_YUV422P 0x15
|
||||
#define WIN_COLOR_DEPTH_YCbCr422R 0x16
|
||||
#define WIN_COLOR_DEPTH_YUV422R 0x17
|
||||
#define WIN_COLOR_DEPTH_YCbCr422RA 0x18
|
||||
#define WIN_COLOR_DEPTH_YUV422RA 0x19
|
||||
|
||||
#define DC_WIN_BUFFER_CONTROL 0x702
|
||||
#define DC_WIN_POSITION 0x704
|
||||
|
||||
#define DC_WIN_SIZE 0x705
|
||||
#define H_SIZE(x) (((x) & 0x1fff) << 0)
|
||||
#define V_SIZE(x) (((x) & 0x1fff) << 16)
|
||||
|
||||
#define DC_WIN_PRESCALED_SIZE 0x706
|
||||
#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0)
|
||||
#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16)
|
||||
|
||||
#define DC_WIN_H_INITIAL_DDA 0x707
|
||||
#define DC_WIN_V_INITIAL_DDA 0x708
|
||||
|
||||
#define DC_WIN_DDA_INC 0x709
|
||||
#define H_DDA_INC(x) (((x) & 0xffff) << 0)
|
||||
#define V_DDA_INC(x) (((x) & 0xffff) << 16)
|
||||
|
||||
#define DC_WIN_LINE_STRIDE 0x70A
|
||||
#define LINE_STRIDE(x) (x)
|
||||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||
#define DC_WIN_DV_CONTROL 0x70E
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
|
||||
#define DC_WINBUF_START_ADDR 0x800
|
||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||
#define DC_WINBUF_SURFACE_KIND 0x80B
|
||||
#define PITCH (0 << 0)
|
||||
#define TILED (1 << 0)
|
||||
#define BLOCK (2 << 0)
|
||||
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
|
||||
|
||||
/*! Display serial interface registers. */
|
||||
#define _DSIREG(reg) ((reg) * 4)
|
||||
|
||||
#define DSI_INCR_SYNCPT_CNTRL 0x1
|
||||
|
||||
#define DSI_RD_DATA 0x9
|
||||
#define DSI_WR_DATA 0xA
|
||||
|
||||
#define DSI_POWER_CONTROL 0xB
|
||||
#define DSI_POWER_CONTROL_ENABLE 1
|
||||
|
||||
#define DSI_INT_ENABLE 0xC
|
||||
#define DSI_INT_STATUS 0xD
|
||||
#define DSI_INT_MASK 0xE
|
||||
|
||||
#define DSI_HOST_CONTROL 0xF
|
||||
#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21)
|
||||
#define DSI_HOST_CONTROL_CRC_RESET (1 << 20)
|
||||
#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12)
|
||||
#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12)
|
||||
#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12)
|
||||
#define DSI_HOST_CONTROL_RAW (1 << 6)
|
||||
#define DSI_HOST_CONTROL_HS (1 << 5)
|
||||
#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4)
|
||||
#define DSI_HOST_CONTROL_IMM_BTA (1 << 3)
|
||||
#define DSI_HOST_CONTROL_PKT_BTA (1 << 2)
|
||||
#define DSI_HOST_CONTROL_CS (1 << 1)
|
||||
#define DSI_HOST_CONTROL_ECC (1 << 0)
|
||||
|
||||
#define DSI_CONTROL 0x10
|
||||
#define DSI_CONTROL_HS_CLK_CTRL (1 << 20)
|
||||
#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16)
|
||||
#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12)
|
||||
#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8)
|
||||
#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4)
|
||||
#define DSI_CONTROL_DCS_ENABLE (1 << 3)
|
||||
#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2)
|
||||
#define DSI_CONTROL_VIDEO_ENABLE (1 << 1)
|
||||
#define DSI_CONTROL_HOST_ENABLE (1 << 0)
|
||||
|
||||
#define DSI_SOL_DELAY 0x11
|
||||
#define DSI_MAX_THRESHOLD 0x12
|
||||
|
||||
#define DSI_TRIGGER 0x13
|
||||
#define DSI_TRIGGER_HOST (1 << 1)
|
||||
#define DSI_TRIGGER_VIDEO (1 << 0)
|
||||
|
||||
#define DSI_TX_CRC 0x14
|
||||
#define DSI_STATUS 0x15
|
||||
#define DSI_INIT_SEQ_CONTROL 0x1A
|
||||
#define DSI_INIT_SEQ_DATA_0 0x1B
|
||||
#define DSI_INIT_SEQ_DATA_1 0x1C
|
||||
#define DSI_INIT_SEQ_DATA_2 0x1D
|
||||
#define DSI_INIT_SEQ_DATA_3 0x1E
|
||||
#define DSI_PKT_SEQ_0_LO 0x23
|
||||
#define DSI_PKT_SEQ_0_HI 0x24
|
||||
#define DSI_PKT_SEQ_1_LO 0x25
|
||||
#define DSI_PKT_SEQ_1_HI 0x26
|
||||
#define DSI_PKT_SEQ_2_LO 0x27
|
||||
#define DSI_PKT_SEQ_2_HI 0x28
|
||||
#define DSI_PKT_SEQ_3_LO 0x29
|
||||
#define DSI_PKT_SEQ_3_HI 0x2A
|
||||
#define DSI_PKT_SEQ_4_LO 0x2B
|
||||
#define DSI_PKT_SEQ_4_HI 0x2C
|
||||
#define DSI_PKT_SEQ_5_LO 0x2D
|
||||
#define DSI_PKT_SEQ_5_HI 0x2E
|
||||
#define DSI_DCS_CMDS 0x33
|
||||
#define DSI_PKT_LEN_0_1 0x34
|
||||
#define DSI_PKT_LEN_2_3 0x35
|
||||
#define DSI_PKT_LEN_4_5 0x36
|
||||
#define DSI_PKT_LEN_6_7 0x37
|
||||
#define DSI_PHY_TIMING_0 0x3C
|
||||
#define DSI_PHY_TIMING_1 0x3D
|
||||
#define DSI_PHY_TIMING_2 0x3E
|
||||
#define DSI_BTA_TIMING 0x3F
|
||||
|
||||
#define DSI_TIMEOUT_0 0x44
|
||||
#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16)
|
||||
#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0)
|
||||
|
||||
#define DSI_TIMEOUT_1 0x45
|
||||
#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16)
|
||||
#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0)
|
||||
|
||||
#define DSI_TO_TALLY 0x46
|
||||
|
||||
#define DSI_PAD_CONTROL_0 0x4B
|
||||
#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24)
|
||||
#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_CD 0x4c
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
|
||||
#define DSI_PAD_CONTROL_1 0x4F
|
||||
#define DSI_PAD_CONTROL_2 0x50
|
||||
|
||||
#define DSI_PAD_CONTROL_3 0x51
|
||||
#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12)
|
||||
#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8)
|
||||
#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4)
|
||||
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_4 0x52
|
||||
#define DSI_PAD_CONTROL_5_MARIKO 0x53
|
||||
#define DSI_PAD_CONTROL_6_MARIKO 0x54
|
||||
#define DSI_PAD_CONTROL_7_MARIKO 0x55
|
||||
#define DSI_INIT_SEQ_DATA_15 0x5F
|
||||
|
||||
#define DSI_INIT_SEQ_DATA_15_MARIKO 0x62
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_save_context.hpp"
|
||||
#include "fatal_sdmmc.hpp"
|
||||
#include "fs/fatal_fs_api.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx) {
|
||||
/* Initialize the sdmmc driver. */
|
||||
R_TRY(InitializeSdCard());
|
||||
|
||||
/* Get the connection status. */
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
{
|
||||
sdmmc::SpeedMode speed_mode;
|
||||
sdmmc::BusWidth bus_width;
|
||||
R_TRY(CheckSdCardConnection(std::addressof(speed_mode), std::addressof(bus_width)));
|
||||
AMS_SECMON_LOG("Sd Card Connection:\n");
|
||||
AMS_SECMON_LOG(" Speed Mode: %u\n", static_cast<u32>(speed_mode));
|
||||
AMS_SECMON_LOG(" Bus Width: %u\n", static_cast<u32>(bus_width));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Mount the SD card. */
|
||||
R_UNLESS(fs::MountSdCard(), fs::ResultPartitionNotFound());
|
||||
|
||||
/* Unmount the SD card once we're done. */
|
||||
ON_SCOPE_EXIT { fs::UnmountSdCard(); };
|
||||
|
||||
/* Create and open the file. */
|
||||
fs::FileHandle file;
|
||||
{
|
||||
/* Generate the file path. */
|
||||
char path[0x40];
|
||||
util::TSNPrintf(path, sizeof(path), "/atmosphere/fatal_errors/report_%016" PRIx64 ".bin", ctx->report_identifier);
|
||||
|
||||
/* Create the file. */
|
||||
R_TRY(fs::CreateFile(path, sizeof(*ctx)));
|
||||
|
||||
/* Open the file. */
|
||||
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_ReadWrite));
|
||||
}
|
||||
|
||||
/* Ensure we close the file when done with it. */
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
/* Write the context to the file. */
|
||||
R_TRY(fs::WriteFile(file, 0, ctx, sizeof(*ctx), fs::WriteOption::Flush));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx);
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_device_page_table.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline auto Port = sdmmc::Port_SdCard0;
|
||||
|
||||
ALWAYS_INLINE u8 *GetSdCardWorkBuffer() {
|
||||
return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>() + MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetSdCardDmaBuffer() {
|
||||
return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>();
|
||||
}
|
||||
|
||||
constexpr inline size_t SdCardDmaBufferSize = MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize;
|
||||
constexpr inline size_t SdCardDmaBufferSectors = SdCardDmaBufferSize / sdmmc::SectorSize;
|
||||
static_assert(util::IsAligned(SdCardDmaBufferSize, sdmmc::SectorSize));
|
||||
|
||||
}
|
||||
|
||||
Result InitializeSdCard() {
|
||||
/* Map main memory for the sdmmc device. */
|
||||
InitializeDevicePageTableForSdmmc1();
|
||||
|
||||
/* Initialize sdmmc library. */
|
||||
sdmmc::Initialize(Port);
|
||||
|
||||
sdmmc::SetSdCardWorkBuffer(Port, GetSdCardWorkBuffer(), sdmmc::SdCardWorkBufferSize);
|
||||
|
||||
//sdmmc::Deactivate(Port);
|
||||
R_TRY(sdmmc::Activate(Port));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) {
|
||||
R_RETURN(sdmmc::CheckSdCardConnection(out_sm, out_bw, Port));
|
||||
}
|
||||
|
||||
Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||
/* Validate that our buffer is valid. */
|
||||
AMS_ASSERT(size >= sector_count * sdmmc::SectorSize);
|
||||
AMS_UNUSED(size);
|
||||
|
||||
/* Repeatedly read sectors. */
|
||||
u8 *dst_u8 = static_cast<u8 *>(dst);
|
||||
void * const dma_buffer = GetSdCardDmaBuffer();
|
||||
while (sector_count > 0) {
|
||||
/* Read sectors into the DMA buffer. */
|
||||
const size_t cur_sectors = std::min(sector_count, SdCardDmaBufferSectors);
|
||||
const size_t cur_size = cur_sectors * sdmmc::SectorSize;
|
||||
R_TRY(sdmmc::Read(dma_buffer, cur_size, Port, sector_index, cur_sectors));
|
||||
|
||||
/* Copy data from the DMA buffer to the output. */
|
||||
std::memcpy(dst_u8, dma_buffer, cur_size);
|
||||
|
||||
/* Advance. */
|
||||
dst_u8 += cur_size;
|
||||
sector_index += cur_sectors;
|
||||
sector_count -= cur_sectors;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
/* Validate that our buffer is valid. */
|
||||
AMS_ASSERT(size >= sector_count * sdmmc::SectorSize);
|
||||
AMS_UNUSED(size);
|
||||
|
||||
/* Repeatedly read sectors. */
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
void * const dma_buffer = GetSdCardDmaBuffer();
|
||||
while (sector_count > 0) {
|
||||
/* Copy sectors into the DMA buffer. */
|
||||
const size_t cur_sectors = std::min(sector_count, SdCardDmaBufferSectors);
|
||||
const size_t cur_size = cur_sectors * sdmmc::SectorSize;
|
||||
std::memcpy(dma_buffer, src_u8, cur_size);
|
||||
|
||||
/* Write sectors to the sd card. */
|
||||
R_TRY(sdmmc::Write(Port, sector_index, cur_sectors, dma_buffer, cur_size));
|
||||
|
||||
/* Advance. */
|
||||
src_u8 += cur_size;
|
||||
sector_index += cur_sectors;
|
||||
sector_count -= cur_sectors;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
Result InitializeSdCard();
|
||||
Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw);
|
||||
Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count);
|
||||
Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size);
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_sdmmc_c.h"
|
||||
#include "fatal_sdmmc.hpp"
|
||||
|
||||
bool sdmmc_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||
return R_SUCCEEDED(ams::secmon::fatal::ReadSdCard(dst, size, sector_index, sector_count));
|
||||
}
|
||||
|
||||
bool sdmmc_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
return R_SUCCEEDED(ams::secmon::fatal::WriteSdCard(sector_index, sector_count, src, size));
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool sdmmc_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count);
|
||||
bool sdmmc_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fatal_sound.hpp"
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int I2cAddressMaxAlc5639 = 0x1C;
|
||||
|
||||
constexpr inline uintptr_t GPIO = secmon::MemoryRegionVirtualDeviceGpio.GetAddress();
|
||||
|
||||
constexpr size_t GPIO_PORT7_CNF_1 = 0x604;
|
||||
constexpr size_t GPIO_PORT7_OE_1 = 0x614;
|
||||
constexpr size_t GPIO_PORT7_OUT_1 = 0x624;
|
||||
|
||||
void WriteAlc5639Register(int r, u16 val) {
|
||||
i2c::Send(i2c::Port_1, I2cAddressMaxAlc5639, r, std::addressof(val), sizeof(val));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StopSound() {
|
||||
/* Mute output to the speaker, setting left/right volume to 0 DB. */
|
||||
WriteAlc5639Register(0x01, 0xC8C8);
|
||||
|
||||
/* Mute output to headphones, setting left/right volume to 0 DB. */
|
||||
WriteAlc5639Register(0x02, 0xC8C8);
|
||||
|
||||
/* Clear all Power Management Control registers by writing 0x0000 to them. */
|
||||
for (int r = 0x61; r <= 0x66; ++r) {
|
||||
WriteAlc5639Register(r, 0x0000);
|
||||
}
|
||||
|
||||
/* Configure CodecLdoEn as GPIO. */
|
||||
reg::SetBits(GPIO + GPIO_PORT7_CNF_1, (1u << 4));
|
||||
|
||||
/* Configure CodecLdoEn as Output. */
|
||||
reg::SetBits(GPIO + GPIO_PORT7_OE_1, (1u << 4));
|
||||
|
||||
/* Wait 200 milliseconds for config to take effect. */
|
||||
util::WaitMicroSeconds(200'000ul);
|
||||
|
||||
/* Pull CodecLdoEn low. */
|
||||
reg::ClearBits(GPIO + GPIO_PORT7_OUT_1, (1u << 4));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::secmon::fatal {
|
||||
|
||||
void StopSound();
|
||||
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
----------------------------------------------------------------------------
|
||||
Revision history of FatFs module
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
R0.00 (February 26, 2006)
|
||||
|
||||
Prototype.
|
||||
|
||||
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
|
||||
The first release.
|
||||
|
||||
|
||||
|
||||
R0.02 (June 01, 2006)
|
||||
|
||||
Added FAT12 support.
|
||||
Removed unbuffered mode.
|
||||
Fixed a problem on small (<32M) partition.
|
||||
|
||||
|
||||
|
||||
R0.02a (June 10, 2006)
|
||||
|
||||
Added a configuration option (_FS_MINIMUM).
|
||||
|
||||
|
||||
|
||||
R0.03 (September 22, 2006)
|
||||
|
||||
Added f_rename().
|
||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||
|
||||
|
||||
|
||||
R0.03a (December 11, 2006)
|
||||
|
||||
Improved cluster scan algorithm to write files fast.
|
||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||
|
||||
|
||||
|
||||
R0.04 (February 04, 2007)
|
||||
|
||||
Added f_mkfs().
|
||||
Supported multiple drive system.
|
||||
Changed some interfaces for multiple drive system.
|
||||
Changed f_mountdrv() to f_mount().
|
||||
|
||||
|
||||
|
||||
R0.04a (April 01, 2007)
|
||||
|
||||
Supported multiple partitions on a physical drive.
|
||||
Added a capability of extending file size to f_lseek().
|
||||
Added minimization level 3.
|
||||
Fixed an endian sensitive code in f_mkfs().
|
||||
|
||||
|
||||
|
||||
R0.04b (May 05, 2007)
|
||||
|
||||
Added a configuration option _USE_NTFLAG.
|
||||
Added FSINFO support.
|
||||
Fixed DBCS name can result FR_INVALID_NAME.
|
||||
Fixed short seek (<= csize) collapses the file object.
|
||||
|
||||
|
||||
|
||||
R0.05 (August 25, 2007)
|
||||
|
||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||
|
||||
|
||||
|
||||
R0.05a (February 03, 2008)
|
||||
|
||||
Added f_truncate() and f_utime().
|
||||
Fixed off by one error at FAT sub-type determination.
|
||||
Fixed btr in f_read() can be mistruncated.
|
||||
Fixed cached sector is not flushed when create and close without write.
|
||||
|
||||
|
||||
|
||||
R0.06 (April 01, 2008)
|
||||
|
||||
Added fputc(), fputs(), fprintf() and fgets().
|
||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||
|
||||
|
||||
|
||||
R0.07 (April 01, 2009)
|
||||
|
||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||
Added long file name feature. (_USE_LFN)
|
||||
Added multiple code page feature. (_CODE_PAGE)
|
||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||
Added auto cluster size selection to f_mkfs().
|
||||
Added rewind option to f_readdir().
|
||||
Changed result code of critical errors.
|
||||
Renamed string functions to avoid name collision.
|
||||
|
||||
|
||||
|
||||
R0.07a (April 14, 2009)
|
||||
|
||||
Septemberarated out OS dependent code on reentrant cfg.
|
||||
Added multiple sector size feature.
|
||||
|
||||
|
||||
|
||||
R0.07c (June 21, 2009)
|
||||
|
||||
Fixed f_unlink() can return FR_OK on error.
|
||||
Fixed wrong cache control in f_lseek().
|
||||
Added relative path feature.
|
||||
Added f_chdir() and f_chdrive().
|
||||
Added proper case conversion to extended character.
|
||||
|
||||
|
||||
|
||||
R0.07e (November 03, 2009)
|
||||
|
||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||
Fixed name matching error on the 13 character boundary.
|
||||
Added a configuration option, _LFN_UNICODE.
|
||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||
|
||||
|
||||
|
||||
R0.08 (May 15, 2010)
|
||||
|
||||
Added a memory configuration option. (_USE_LFN = 3)
|
||||
Added file lock feature. (_FS_SHARE)
|
||||
Added fast seek feature. (_USE_FASTSEEK)
|
||||
Changed some types on the API, XCHAR->TCHAR.
|
||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||
String functions support UTF-8 encoding files on Unicode cfg.
|
||||
|
||||
|
||||
|
||||
R0.08a (August 16, 2010)
|
||||
|
||||
Added f_getcwd(). (_FS_RPATH = 2)
|
||||
Added sector erase feature. (_USE_ERASE)
|
||||
Moved file lock semaphore table from fs object to the bss.
|
||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||
|
||||
|
||||
|
||||
R0.08b (January 15, 2011)
|
||||
|
||||
Fast seek feature is also applied to f_read() and f_write().
|
||||
f_lseek() reports required table size on creating CLMP.
|
||||
Extended format syntax of f_printf().
|
||||
Ignores duplicated directory separators in given path name.
|
||||
|
||||
|
||||
|
||||
R0.09 (September 06, 2011)
|
||||
|
||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||
Added f_fdisk().
|
||||
|
||||
|
||||
|
||||
R0.09a (August 27, 2012)
|
||||
|
||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||
Changed option name _FS_SHARE to _FS_LOCK.
|
||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||
|
||||
|
||||
|
||||
R0.09b (January 24, 2013)
|
||||
|
||||
Added f_setlabel() and f_getlabel().
|
||||
|
||||
|
||||
|
||||
R0.10 (October 02, 2013)
|
||||
|
||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||
Added f_closedir().
|
||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||
Added forced mount feature with changes of f_mount().
|
||||
Improved behavior of volume auto detection.
|
||||
Improved write throughput of f_puts() and f_printf().
|
||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
||||
|
||||
|
||||
|
||||
R0.10a (January 15, 2014)
|
||||
|
||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||
Fixed f_close() invalidates the file object without volume lock.
|
||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10c (November 09, 2014)
|
||||
|
||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||
Changed option name _USE_ERASE to _USE_TRIM.
|
||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||
Fixed a potential problem of FAT access that can appear on disk error.
|
||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||
|
||||
|
||||
|
||||
R0.11 (February 09, 2015)
|
||||
|
||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.11a (September 05, 2015)
|
||||
|
||||
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12 (April 12, 2016)
|
||||
|
||||
Added support for exFAT file system. (_FS_EXFAT)
|
||||
Added f_expand(). (_USE_EXPAND)
|
||||
Changed some members in FINFO structure and behavior of f_readdir().
|
||||
Added an option _USE_CHMOD.
|
||||
Removed an option _WORD_ACCESS.
|
||||
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12a (July 10, 2016)
|
||||
|
||||
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||
f_forward() is available regardless of _FS_TINY.
|
||||
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||
|
||||
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.13 (May 21, 2017)
|
||||
|
||||
Changed heading character of configuration keywords "_" to "FF_".
|
||||
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
|
||||
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
|
||||
Improved cluster allocation time on stretch a deep buried cluster chain.
|
||||
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
|
||||
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
|
||||
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
|
||||
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
|
||||
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
|
||||
|
||||
|
||||
|
||||
R0.13a (October 14, 2017)
|
||||
|
||||
Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2)
|
||||
Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF).
|
||||
Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk().
|
||||
Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09)
|
||||
Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c)
|
||||
Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.13b (April 07, 2018)
|
||||
|
||||
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
|
||||
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
|
||||
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
|
||||
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)
|
||||
|
||||
|
||||
|
||||
R0.13c (October 14, 2018)
|
||||
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
|
||||
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
|
||||
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
|
||||
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
|
||||
|
||||
|
||||
|
||||
R0.14 (October 14, 2019)
|
||||
Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1)
|
||||
Changed some API functions, f_mkfs() and f_fdisk().
|
||||
Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters.
|
||||
Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters.
|
||||
Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12)
|
||||
Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
FatFs Module Source Files R0.14
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
ffunicode.c Optional Unicode utility functions.
|
||||
ffsystem.c An example of optional O/S related functions.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You need to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* If a working storage control module is available, it should be */
|
||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||
/* This is an example of glue functions to attach various exsisting */
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "ff.h" /* Obtains integer types */
|
||||
#include "diskio.h" /* Declarations of disk functions */
|
||||
#include "ffconf.h"
|
||||
|
||||
#include "../fatal_sdmmc_c.h"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case 0:
|
||||
return sdmmc_read_sd_card(buff, count * 512, sector, count) ? RES_OK : RES_ERROR;
|
||||
default:
|
||||
return RES_PARERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case 0:
|
||||
return sdmmc_write_sd_card(sector, count, buff, count * 512) ? RES_OK : RES_ERROR;
|
||||
default:
|
||||
return RES_PARERR;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,426 +0,0 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.14 /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2019, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 86606 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* Integer types used for FatFs API */
|
||||
|
||||
#if defined(_WIN32) /* Main development platform */
|
||||
#define FF_INTDEF 2
|
||||
#include <windows.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
|
||||
#define FF_INTDEF 2
|
||||
#include <stdint.h>
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef uint16_t WORD; /* 16-bit unsigned integer */
|
||||
typedef uint32_t DWORD; /* 32-bit unsigned integer */
|
||||
typedef uint64_t QWORD; /* 64-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#else /* Earlier than C99 */
|
||||
#define FF_INTDEF 1
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef unsigned short WORD; /* 16-bit unsigned integer */
|
||||
typedef unsigned long DWORD; /* 32-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#endif
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
|
||||
#endif
|
||||
|
||||
#if FF_STR_VOLUME_ID
|
||||
#ifndef FF_VOLUME_STRS
|
||||
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#ifndef _INC_TCHAR
|
||||
#define _INC_TCHAR
|
||||
|
||||
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) u8 ## x
|
||||
#define _TEXT(x) u8 ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
|
||||
typedef DWORD TCHAR;
|
||||
#define _T(x) U ## x
|
||||
#define _TEXT(x) U ## x
|
||||
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
|
||||
#error Wrong FF_LFN_UNICODE setting
|
||||
#else /* ANSI/OEM code in SBCS/DBCS */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of file size and LBA variables */
|
||||
|
||||
#if FF_FS_EXFAT
|
||||
#if FF_INTDEF != 2
|
||||
#error exFAT feature wants C99 or later
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#if FF_LBA64
|
||||
typedef QWORD LBA_t;
|
||||
#else
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
#else
|
||||
#if FF_LBA64
|
||||
#error exFAT needs to be enabled when enable 64-bit LBA
|
||||
#endif
|
||||
typedef DWORD FSIZE_t;
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Associated physical drive */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
WORD id; /* Volume mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if FF_USE_LFN
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if FF_FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||
#endif
|
||||
#if FF_FS_REENTRANT
|
||||
FF_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !FF_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if FF_FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||
#endif
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||
DWORD fsize; /* Size of an FAT [sectors] */
|
||||
LBA_t volbase; /* Volume base sector */
|
||||
LBA_t fatbase; /* FAT base sector */
|
||||
LBA_t dirbase; /* Root directory base sector/cluster */
|
||||
LBA_t database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
LBA_t bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
LBA_t winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||
#endif
|
||||
#if FF_FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} FFOBJID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !FF_FS_READONLY
|
||||
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
LBA_t sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if FF_USE_LFN
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if FF_USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
FSIZE_t fsize; /* File size */
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if FF_USE_LFN
|
||||
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
|
||||
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[12 + 1]; /* File name */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* Format parameter structure (MKFS_PARM) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
|
||||
BYTE n_fat; /* Number of FATs */
|
||||
UINT align; /* Data area alignment (sector) */
|
||||
UINT n_root; /* Number of root directory entries */
|
||||
DWORD au_size; /* Cluster size (byte) */
|
||||
} MKFS_PARM;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
||||
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
#define f_unmount(path) f_mount(0, path, 0)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !FF_FS_READONLY && !FF_FS_NORTC
|
||||
DWORD get_fattime (void);
|
||||
#endif
|
||||
|
||||
/* LFN support functions */
|
||||
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
|
||||
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
|
||||
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
||||
#endif
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if FF_FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access mode and open method flags (3rd argument of f_open) */
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
/* Fast seek controls (2nd argument of f_lseek) */
|
||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||
|
||||
/* Format options (2nd argument of f_mkfs) */
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_EXFAT 0x04
|
||||
#define FM_ANY 0x07
|
||||
#define FM_SFD 0x08
|
||||
|
||||
/* Filesystem type (FATFS.fs_type) */
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FF_DEFINED */
|
||||
@@ -1,298 +0,0 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs Functional Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FFCONF_DEF 86606 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define FF_FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: Basic functions are fully enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||
/ are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define FF_USE_STRFUNC 2
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
||||
#define FF_USE_MKFS 0
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FASTSEEK 0
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_EXPAND 1
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define FF_USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_CODE_PAGE 850
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect code page setting can cause a file open failure.
|
||||
/
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 771 - KBL
|
||||
/ 775 - Baltic
|
||||
/ 850 - Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 860 - Portuguese
|
||||
/ 861 - Icelandic
|
||||
/ 862 - Hebrew
|
||||
/ 863 - Canadian French
|
||||
/ 864 - Arabic
|
||||
/ 865 - Nordic
|
||||
/ 866 - Russian
|
||||
/ 869 - Greek 2
|
||||
/ 932 - Japanese (DBCS)
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
/ 0 - Include all code pages above and configured by f_setcp()
|
||||
*/
|
||||
|
||||
|
||||
#define FF_USE_LFN 1
|
||||
#define FF_MAX_LFN 255
|
||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||
/
|
||||
/ 0: Disable LFN. FF_MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
|
||||
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
|
||||
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
|
||||
/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
|
||||
/ specification.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */
|
||||
|
||||
|
||||
#define FF_LFN_UNICODE 2
|
||||
/* This option switches the character encoding on the API when LFN is enabled.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP (TCHAR = char)
|
||||
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
|
||||
/ 2: Unicode in UTF-8 (TCHAR = char)
|
||||
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
|
||||
/
|
||||
/ Also behavior of string I/O functions will be affected by this option.
|
||||
/ When LFN is not enabled, this option has no effect. */
|
||||
|
||||
|
||||
#define FF_LFN_BUF 255
|
||||
#define FF_SFN_BUF 12
|
||||
/* This set of options defines size of file name members in the FILINFO structure
|
||||
/ which is used to read out directory items. These values should be suffcient for
|
||||
/ the file names to read. The maximum possible length of the read file name depends
|
||||
/ on character encoding. When LFN is not enabled, these options have no effect. */
|
||||
|
||||
|
||||
#define FF_STRF_ENCODE 3
|
||||
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
|
||||
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
|
||||
/ This option selects assumption of character encoding ON THE FILE to be
|
||||
/ read/written via those functions.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP
|
||||
/ 1: Unicode in UTF-16LE
|
||||
/ 2: Unicode in UTF-16BE
|
||||
/ 3: Unicode in UTF-8
|
||||
*/
|
||||
|
||||
|
||||
#define FF_FS_RPATH 0
|
||||
/* This option configures support for relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_VOLUMES 1
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define FF_STR_VOLUME_ID 0
|
||||
#define FF_VOLUME_STRS "sdmc"
|
||||
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
|
||||
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
|
||||
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
||||
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
|
||||
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
|
||||
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
|
||||
/ not defined, a user defined volume string table needs to be defined as:
|
||||
/
|
||||
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
|
||||
*/
|
||||
|
||||
|
||||
#define FF_MULTI_PARTITION 0
|
||||
/* This option switches support for multiple volumes on the physical drive.
|
||||
/ By default (0), each logical drive number is bound to the same physical drive
|
||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||
/ When this function is enabled (1), each logical drive number can be bound to
|
||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||
/ funciton will be available. */
|
||||
|
||||
|
||||
#define FF_MIN_SS 512
|
||||
#define FF_MAX_SS 512
|
||||
/* This set of options configures the range of sector size to be supported. (512,
|
||||
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
|
||||
/ for variable sector size mode and disk_ioctl() function needs to implement
|
||||
/ GET_SECTOR_SIZE command. */
|
||||
|
||||
|
||||
#define FF_LBA64 0
|
||||
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
|
||||
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
|
||||
|
||||
|
||||
#define FF_MIN_GPT 0x100000000
|
||||
/* Minimum number of sectors to switch GPT format to create partition in f_mkfs and
|
||||
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
|
||||
|
||||
|
||||
#define FF_USE_TRIM 0
|
||||
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
|
||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define FF_FS_EXFAT 1
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2019
|
||||
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
|
||||
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
|
||||
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
|
||||
/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */
|
||||
|
||||
|
||||
#define FF_FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
#define FF_FS_LOCK 0
|
||||
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
/* #include <somertos.h> // O/S definitions */
|
||||
#define FF_FS_REENTRANT 0
|
||||
#define FF_FS_TIMEOUT 1000
|
||||
#define FF_SYNC_t HANDLE
|
||||
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this function.
|
||||
/
|
||||
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||
/ function, must be added to the project. Samples are available in
|
||||
/ option/syscall.c.
|
||||
/
|
||||
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
@@ -1,170 +0,0 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample Code of OS Dependent Functions for FatFs */
|
||||
/* (C)ChaN, 2018 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
|
||||
)
|
||||
{
|
||||
free(mblock); /* Free the memory block with POSIX API */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if FF_FS_REENTRANT /* Mutal exclusion */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object for the volume, such as semaphore and mutex.
|
||||
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
|
||||
|
||||
|
||||
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
|
||||
BYTE vol, /* Corresponding volume (logical drive number) */
|
||||
FF_SYNC_t* sobj /* Pointer to return the created sync object */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
*sobj = CreateMutex(NULL, FALSE, NULL);
|
||||
return (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||
|
||||
/* uITRON */
|
||||
// T_CSEM csem = {TA_TPRI,1,1};
|
||||
// *sobj = acre_sem(&csem);
|
||||
// return (int)(*sobj > 0);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// *sobj = OSMutexCreate(0, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// *sobj = xSemaphoreCreateMutex();
|
||||
// return (int)(*sobj != NULL);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// *sobj = osMutexCreate(&Mutex[vol]);
|
||||
// return (int)(*sobj != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
|
||||
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)CloseHandle(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(del_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// vSemaphoreDelete(sobj);
|
||||
// return 1;
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexDelete(sobj) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
FF_SYNC_t sobj /* Sync object to wait */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(wai_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant (
|
||||
FF_SYNC_t sobj /* Sync object to be signaled */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
ReleaseMutex(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// sig_sem(sobj);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OSMutexPost(sobj);
|
||||
|
||||
/* FreeRTOS */
|
||||
// xSemaphoreGive(sobj);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// osMutexRelease(sobj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "../fatfs/ff.h"
|
||||
#include "fatal_fs_api.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t MaxFiles = 8;
|
||||
|
||||
constinit bool g_is_sd_mounted = false;
|
||||
|
||||
FATFS g_sd_fs;
|
||||
|
||||
constinit FIL g_files[MaxFiles] = {};
|
||||
constinit bool g_files_opened[MaxFiles] = {};
|
||||
constinit int g_open_modes[MaxFiles] = {};
|
||||
|
||||
Result TranslateFatFsError(FRESULT res) {
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
R_SUCCEED();
|
||||
case FR_DISK_ERR:
|
||||
R_THROW(fs::ResultMmcAccessFailed());
|
||||
case FR_INT_ERR:
|
||||
R_THROW(fs::ResultPreconditionViolation());
|
||||
case FR_NOT_READY:
|
||||
R_THROW(fs::ResultMmcAccessFailed());
|
||||
case FR_NO_FILE:
|
||||
R_THROW(fs::ResultPathNotFound());
|
||||
case FR_NO_PATH:
|
||||
R_THROW(fs::ResultPathNotFound());
|
||||
case FR_INVALID_NAME:
|
||||
R_THROW(fs::ResultInvalidPath());
|
||||
case FR_DENIED:
|
||||
R_THROW(fs::ResultPermissionDenied());
|
||||
case FR_EXIST:
|
||||
R_THROW(fs::ResultPathAlreadyExists());
|
||||
case FR_INVALID_OBJECT:
|
||||
R_THROW(fs::ResultInvalidArgument());
|
||||
case FR_WRITE_PROTECTED:
|
||||
R_THROW(fs::ResultWriteNotPermitted());
|
||||
case FR_INVALID_DRIVE:
|
||||
R_THROW(fs::ResultInvalidMountName());
|
||||
case FR_NOT_ENABLED:
|
||||
R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */
|
||||
case FR_NO_FILESYSTEM:
|
||||
R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */
|
||||
case FR_TIMEOUT:
|
||||
R_THROW(fs::ResultTargetLocked()); /* BAD/TODO */
|
||||
case FR_LOCKED:
|
||||
R_THROW(fs::ResultTargetLocked());
|
||||
case FR_NOT_ENOUGH_CORE:
|
||||
R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */
|
||||
case FR_TOO_MANY_OPEN_FILES:
|
||||
R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */
|
||||
case FR_INVALID_PARAMETER:
|
||||
R_THROW(fs::ResultInvalidArgument());
|
||||
default:
|
||||
R_THROW(fs::ResultInternal());
|
||||
}
|
||||
}
|
||||
|
||||
int TranslateToFatFsMode(int mode) {
|
||||
int fmode = FA_OPEN_EXISTING;
|
||||
if ((mode & OpenMode_Read) != 0) {
|
||||
fmode |= FA_READ;
|
||||
}
|
||||
if ((mode & OpenMode_Write) != 0) {
|
||||
fmode |= FA_WRITE;
|
||||
}
|
||||
if ((mode & OpenMode_AllowAppend) != 0) {
|
||||
fmode |= FA_OPEN_APPEND;
|
||||
}
|
||||
return fmode;
|
||||
}
|
||||
|
||||
FIL *GetInternalFile(FileHandle handle) {
|
||||
return static_cast<FIL *>(handle._handle);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE size_t GetFileIndex(FIL *fp) {
|
||||
const size_t file_index = (fp - g_files);
|
||||
AMS_ASSERT(file_index < MaxFiles);
|
||||
return file_index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MountSdCard() {
|
||||
AMS_ASSERT(!g_is_sd_mounted);
|
||||
g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "sdmc", 1) == FR_OK;
|
||||
return g_is_sd_mounted;
|
||||
}
|
||||
|
||||
void UnmountSdCard() {
|
||||
AMS_ASSERT(g_is_sd_mounted);
|
||||
f_unmount("sdmc");
|
||||
g_is_sd_mounted = false;
|
||||
}
|
||||
|
||||
Result CreateFile(const char *path, s64 size) {
|
||||
/* Create the file. */
|
||||
FIL fp;
|
||||
R_TRY(TranslateFatFsError(f_open(std::addressof(fp), path, FA_CREATE_NEW | FA_READ | FA_WRITE)));
|
||||
|
||||
/* Ensure that we close the file when we're done with it. */
|
||||
ON_SCOPE_EXIT { f_close(std::addressof(fp)); };
|
||||
|
||||
/* Expand the file. */
|
||||
R_TRY(TranslateFatFsError(f_expand(std::addressof(fp), size, 1)));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CreateDirectory(const char *path) {
|
||||
R_RETURN(TranslateFatFsError(f_mkdir(path)));
|
||||
}
|
||||
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode) {
|
||||
/* Find a free file. */
|
||||
for (size_t i = 0; i < MaxFiles; ++i) {
|
||||
if (!g_files_opened[i]) {
|
||||
/* Open the file. */
|
||||
FIL *fp = std::addressof(g_files[i]);
|
||||
R_TRY(TranslateFatFsError(f_open(fp, path, TranslateToFatFsMode(mode))));
|
||||
|
||||
/* Set the output. */
|
||||
out_file->_handle = fp;
|
||||
g_files_opened[i] = true;
|
||||
g_open_modes[i] = mode;
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
R_THROW(fs::ResultOpenCountLimit());
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
/* Option is unused. */
|
||||
AMS_UNUSED(option);
|
||||
|
||||
/* Seek to the offset we're reading at. */
|
||||
R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset)));
|
||||
|
||||
/* Read the data. */
|
||||
u32 br;
|
||||
R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br))));
|
||||
|
||||
/* Check that we read the correct amount. */
|
||||
R_UNLESS(br == size, fs::ResultOutOfRange());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
R_RETURN(ReadFile(handle, offset, buffer, size, fs::ReadOption::None));
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
/* Option is unused. */
|
||||
AMS_UNUSED(option);
|
||||
|
||||
/* Seek to the offset we're reading at. */
|
||||
R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset)));
|
||||
|
||||
/* Read the data. */
|
||||
u32 br;
|
||||
R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br))));
|
||||
|
||||
/* Set the output size. */
|
||||
*out = br;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
R_RETURN(ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None));
|
||||
}
|
||||
|
||||
Result GetFileSize(s64 *out, FileHandle handle) {
|
||||
FIL *fp = GetInternalFile(handle);
|
||||
*out = f_size(fp);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result FlushFile(FileHandle handle) {
|
||||
R_RETURN(TranslateFatFsError(f_sync(GetInternalFile(handle))));
|
||||
}
|
||||
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
|
||||
/* Seek to the offset we're writing at. */
|
||||
R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset)));
|
||||
|
||||
/* Write the data. */
|
||||
u32 bw;
|
||||
R_TRY(TranslateFatFsError(f_write(GetInternalFile(handle), buffer, size, std::addressof(bw))));
|
||||
|
||||
/* Check that we wrote the correct amount. */
|
||||
R_UNLESS(bw == size, fs::ResultOutOfRange());
|
||||
|
||||
/* If we should, flush the file. */
|
||||
if (option.HasFlushFlag()) {
|
||||
R_TRY(FlushFile(handle));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetFileSize(FileHandle handle, s64 size) {
|
||||
FIL *fp = GetInternalFile(handle);
|
||||
|
||||
/* Check if we have nothing to do. */
|
||||
const size_t fsize = f_size(fp);
|
||||
R_SUCCEED_IF(static_cast<FSIZE_t>(size) == fsize);
|
||||
|
||||
/* NOTE/TODO: This may not preserve file data. Do this in a way that does? */
|
||||
|
||||
/* Truncate the file. */
|
||||
R_TRY(TranslateFatFsError(f_truncate(fp)));
|
||||
|
||||
/* Expand the file. */
|
||||
R_TRY(TranslateFatFsError(f_expand(fp, size, 1)));
|
||||
|
||||
/* Ensure the file is synchronized. */
|
||||
R_TRY(FlushFile(handle));
|
||||
|
||||
/* Check that our expansion succeeded. */
|
||||
AMS_ASSERT(f_size(fp) == static_cast<FSIZE_t>(size));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
int GetFileOpenMode(FileHandle handle) {
|
||||
return g_open_modes[GetFileIndex(GetInternalFile(handle))];
|
||||
}
|
||||
|
||||
void CloseFile(FileHandle handle) {
|
||||
const size_t index = GetFileIndex(GetInternalFile(handle));
|
||||
f_close(std::addressof(g_files[index]));
|
||||
g_open_modes[index] = 0;
|
||||
g_files_opened[index] = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
enum OpenMode {
|
||||
OpenMode_Read = (1 << 0),
|
||||
OpenMode_Write = (1 << 1),
|
||||
OpenMode_AllowAppend = (1 << 2),
|
||||
|
||||
OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write),
|
||||
OpenMode_All = (OpenMode_ReadWrite | OpenMode_AllowAppend),
|
||||
};
|
||||
|
||||
struct ReadOption {
|
||||
u32 _value;
|
||||
|
||||
static const ReadOption None;
|
||||
};
|
||||
|
||||
inline constexpr const ReadOption ReadOption::None = {0};
|
||||
|
||||
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
|
||||
return lhs._value == rhs._value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
|
||||
|
||||
struct WriteOption {
|
||||
u32 _value;
|
||||
|
||||
constexpr inline bool HasFlushFlag() const {
|
||||
return _value & 1;
|
||||
}
|
||||
|
||||
static const WriteOption None;
|
||||
static const WriteOption Flush;
|
||||
};
|
||||
|
||||
inline constexpr const WriteOption WriteOption::None = {0};
|
||||
inline constexpr const WriteOption WriteOption::Flush = {1};
|
||||
|
||||
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
|
||||
return lhs._value == rhs._value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
static_assert(util::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32));
|
||||
|
||||
struct FileHandle {
|
||||
void *_handle;
|
||||
};
|
||||
|
||||
bool MountSdCard();
|
||||
void UnmountSdCard();
|
||||
|
||||
Result CreateFile(const char *path, s64 size);
|
||||
Result CreateDirectory(const char *path);
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode);
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option);
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size);
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option);
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size);
|
||||
Result GetFileSize(s64 *out, FileHandle handle);
|
||||
Result FlushFile(FileHandle handle);
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option);
|
||||
Result SetFileSize(FileHandle handle, s64 size);
|
||||
int GetFileOpenMode(FileHandle handle);
|
||||
void CloseFile(FileHandle handle);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user