From f8c738e5e851c53ec8ad54bb022caf3b179f2db3 Mon Sep 17 00:00:00 2001 From: Lightos1 Date: Wed, 1 Oct 2025 22:26:21 +0200 Subject: [PATCH] BL fixing I think done correctly? idk --- .../loader/source/oc/mtc_timing_value.hpp | 116 +++-- .../loader/source/oc/pcv/pcv_erista.cpp | 459 +++++++++--------- .../loader/source/oc/pcv/pcv_mariko.cpp | 11 +- 3 files changed, 309 insertions(+), 277 deletions(-) diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp index 167f6492..472e01ac 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp @@ -58,66 +58,65 @@ // const u32 TIMING_PRESET_SIX = C.ramTimingPresetSix; // const u32 TIMING_PRESET_SEVEN = C.ramTimingPresetSeven; + // Burst Length + const u32 BL = 16; // Write Latency const u32 WL = 14 + C.mem_burst_latency; // Read Latency const u32 RL = 32 - C.mem_burst_latency; - // Burst Length - const u32 BL = 16; + // tRFCpb (refresh cycle time per bank) in ns for 8Gb density + const u32 tRFCpb = !C.t5_tRFC ? 140 : tRFC_values[C.t5_tRFC-1]; - // tRFCpb (refresh cycle time per bank) in ns for 8Gb density - const u32 tRFCpb = !C.t5_tRFC ? 140 : tRFC_values[C.t5_tRFC-1]; + // tRFCab (refresh cycle time all banks) in ns for 8Gb density + const u32 tRFCab = !C.t5_tRFC ? 280 : 2*tRFCpb; - // tRFCab (refresh cycle time all banks) in ns for 8Gb density - const u32 tRFCab = !C.t5_tRFC ? 280 : 2*tRFCpb; + // tRAS (row active time) in ns + const u32 tRAS = !C.t3_tRAS ? 42 : tRAS_values[C.t3_tRAS-1]; - // tRAS (row active time) in ns - const u32 tRAS = !C.t3_tRAS ? 42 : tRAS_values[C.t3_tRAS-1]; + // tRPpb (row precharge time per bank) in ns + const u32 tRPpb = !C.t2_tRP ? 18 : tRP_values[C.t2_tRP-1]; - // tRPpb (row precharge time per bank) in ns - const u32 tRPpb = !C.t2_tRP ? 18 : tRP_values[C.t2_tRP-1]; + // tRPab (row precharge time all banks) in ns + const u32 tRPab = !C.t2_tRP ? 21 : tRPpb + 3; - // tRPab (row precharge time all banks) in ns - const u32 tRPab = !C.t2_tRP ? 21 : tRPpb + 3; + // tRC (ACTIVATE-ACTIVATE command period same bank) in ns + const u32 tRC = tRPab + tRAS; - // tRC (ACTIVATE-ACTIVATE command period same bank) in ns - const u32 tRC = tRPab + tRAS; + const u32 tPPD = 4; - const u32 tPPD = 4; + const u32 tRTW = !C.t6_tRTW ? 10 : tWTR_values[C.t6_tRTW-1]; - const u32 tRTW = !C.t6_tRTW ? 10 : tWTR_values[C.t6_tRTW-1]; + // Write-to-Read delay + const u32 tWTR = !C.t7_tWTR ? 10 : tWTR_values[C.t7_tWTR-1]; - // Write-to-Read delay - const u32 tWTR = !C.t7_tWTR ? 10 : tWTR_values[C.t7_tWTR-1]; + // Internal READ-to-PRE-CHARGE command delay in ns + const double tRTP = !TIMING_PRESET_THREE ? 7.5 : tRTP_values[TIMING_PRESET_THREE-1]; - // Internal READ-to-PRE-CHARGE command delay in ns - const double tRTP = !TIMING_PRESET_THREE ? 7.5 : tRTP_values[TIMING_PRESET_THREE-1]; + // write recovery time + const u32 tWR = !TIMING_PRESET_THREE ? 18 : tWR_values[TIMING_PRESET_THREE-1]; - // write recovery time - const u32 tWR = !TIMING_PRESET_THREE ? 18 : tWR_values[TIMING_PRESET_THREE-1]; + // tRCD (RAS-CAS delay) in ns + const u32 tRCD = !C.t1_tRCD ? 18 : tRCD_values[C.t1_tRCD-1]; - // tRCD (RAS-CAS delay) in ns - const u32 tRCD = !C.t1_tRCD ? 18 : tRCD_values[C.t1_tRCD-1]; + // tRRD (Active bank-A to Active bank-B) in ns + const double tRRD = !C.t4_tRRD ? 10. : tRRD_values[C.t4_tRRD-1]; - // tRRD (Active bank-A to Active bank-B) in ns - const double tRRD = !C.t4_tRRD ? 10. : tRRD_values[C.t4_tRRD-1]; + // tREFpb (average refresh interval per bank) in ns for 8Gb density + const u32 tREFpb = !C.t8_tREFI ? 488 : tREFpb_values[C.t8_tREFI-1]; - // tREFpb (average refresh interval per bank) in ns for 8Gb density - const u32 tREFpb = !C.t8_tREFI ? 488 : tREFpb_values[C.t8_tREFI-1]; + // Exit power-down to next valid command delay + const double tXP = 7.5; - // Exit power-down to next valid command delay - const double tXP = 7.5; + // tXSR (SELF REFRESH exit to next valid command delay) in ns + const double tXSR = tRFCab + 7.5; - // tXSR (SELF REFRESH exit to next valid command delay) in ns - const double tXSR = tRFCab + 7.5; + // Minimum self refresh time (entry to exit) + const u32 tSR = 15; - // Minimum self refresh time (entry to exit) - const u32 tSR = 15; - - // tFAW (Four-bank Activate Window) in ns - const u32 tFAW = 40;// !TIMING_PRESET_TWO ? 40 : tFAW_values[TIMING_PRESET_TWO-1]; TOGO + // tFAW (Four-bank Activate Window) in ns + const u32 tFAW = 40;// !TIMING_PRESET_TWO ? 40 : tFAW_values[TIMING_PRESET_TWO-1]; TOGO // #_of_rows per die for 8Gb density const u32 numOfRows = 131072; @@ -128,13 +127,38 @@ const u32 REFRESH = MIN((u32)65472, u32(std::ceil((double(tREFpb) * C.marikoEmcMaxClock / numOfRows * 1.048 / 2 - 64))) / 4 * 4); const u32 REFBW = MIN((u32)65536, REFRESH+64); - namespace pcv::erista { - // tCK_avg (average clock period) in ns - const double tCK_avg = 1000'000. / C.eristaEmcMaxClock; - } + // DQS output access time from CK_t/CK_c + const double tDQSCK_min = 1.5; + const double tDQSCK_max = 3.5; + // Write preamble (tCK) + const double tWPRE = 1.8; + // Read postamble (tCK) + const double tRPST = 0.4; - namespace pcv::mariko { - // tCK_avg (average clock period) in ns - const double tCK_avg = 1000'000. / C.marikoEmcMaxClock; - } - } + namespace pcv::erista { + // tCK_avg (average clock period) in ns + const double tCK_avg = 1000'000. / C.eristaEmcMaxClock; + + // minimum number of cycles from any read command to any write command, irrespective of bank + const u32 R2W = CEIL (RL + CEIL(tDQSCK_max/tCK_avg) + BL/2 - WL + tWPRE + FLOOR(tRPST)) + 6; + + // Delay Time From WRITE-to-READ + const u32 W2R = WL + BL/2 + 1 + CEIL(tWTR/tCK_avg) - 6; + + // write-to-precharge time for commands to the same bank in cycles + const u32 WTP = WL + BL/2 + 1 + CEIL(tWR/tCK_avg) - 8; + } + + namespace pcv::mariko { + // tCK_avg (average clock period) in ns + const double tCK_avg = 1000'000. / C.marikoEmcMaxClock; + + const u32 R2W = CEIL (RL + CEIL(tDQSCK_max/tCK_avg) + BL/2 - WL + tWPRE + FLOOR(tRPST)) + 6; + + // Delay Time From WRITE-to-READ + const u32 W2R = WL + BL/2 + 1 + CEIL(tWTR/tCK_avg) - 6; + + // write-to-precharge time for commands to the same bank in cycles + const u32 WTP = WL + BL/2 + 1 + CEIL(tWR/tCK_avg) - 8; + } +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp index 91b2f8f5..8db2e304 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -21,271 +21,274 @@ #include "pcv.hpp" #include "../mtc_timing_value.hpp" - namespace ams::ldr::oc::pcv::erista { - Result CpuFreqVdd(u32* ptr) { - dvfs_rail* entry = reinterpret_cast(reinterpret_cast(ptr) - offsetof(dvfs_rail, freq)); +namespace ams::ldr::oc::pcv::erista { +Result CpuFreqVdd(u32* ptr) { + dvfs_rail* entry = reinterpret_cast(reinterpret_cast(ptr) - offsetof(dvfs_rail, freq)); - R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry()); - R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry()); - R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry()); - R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry()); + R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry()); + R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry()); + R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry()); + R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry()); - if (C.eristaCpuUV) { - if(!C.enableEristaCpuUnsafeFreqs) { - PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); - } else { - PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTableUnsafeFreqs)->freq); - } - } else { + if (C.eristaCpuUV) { + if(!C.enableEristaCpuUnsafeFreqs) { PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); + } else { + PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTableUnsafeFreqs)->freq); } + } else { + PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); + } + R_SUCCEED(); +} +Result GpuVmin(u32 *ptr) { + if (!C.eristaGpuVmin) + R_SKIP(); + PATCH_OFFSET(ptr, (int)C.eristaGpuVmin); R_SUCCEED(); - } - Result GpuVmin(u32 *ptr) { - if (!C.eristaGpuVmin) - R_SKIP(); - PATCH_OFFSET(ptr, (int)C.eristaGpuVmin); +} + Result CpuVoltRange(u32 *ptr) { + u32 min_volt_got = *(ptr - 1); + for (const auto &mv : CpuMinVolts) { + if (min_volt_got != mv) + continue; + + if (!C.eristaCpuMaxVolt) + R_SKIP(); + + PATCH_OFFSET(ptr, C.eristaCpuMaxVolt); R_SUCCEED(); + } + R_THROW(ldr::ResultInvalidCpuMinVolt()); } - Result CpuVoltRange(u32 *ptr) { - u32 min_volt_got = *(ptr - 1); - for (const auto &mv : CpuMinVolts) { - if (min_volt_got != mv) - continue; + Result CpuVoltDfll(u32* ptr) { + cvb_cpu_dfll_data *entry = reinterpret_cast(ptr); - if (!C.eristaCpuMaxVolt) - R_SKIP(); - - PATCH_OFFSET(ptr, C.eristaCpuMaxVolt); - R_SUCCEED(); - } - R_THROW(ldr::ResultInvalidCpuMinVolt()); - } - Result CpuVoltDfll(u32* ptr) { - cvb_cpu_dfll_data *entry = reinterpret_cast(ptr); - -// R_UNLESS(entry->tune0_low == 0x0000FFCF, ldr::ResultInvalidCpuVoltDfllEntry()); +// R_UNLESS(entry->tune0_low == 0x0000FFCF, ldr::ResultInvalidCpuVoltDfllEntry()); // R_UNLESS(entry->tune0_high == 0x00000000, ldr::ResultInvalidCpuVoltDfllEntry()); // R_UNLESS(entry->tune1_low == 0x012207FF, ldr::ResultInvalidCpuVoltDfllEntry()); // R_UNLESS(entry->tune1_high == 0x03FFF7FF, ldr::ResultInvalidCpuVoltDfllEntry()); - if(!C.eristaCpuUV) { - R_SKIP(); - } - PATCH_OFFSET(&(entry->dvco_calibration_max), 0x1C); - PATCH_OFFSET(&(entry->tune1_high), 0x10); - PATCH_OFFSET(&(entry->tune_high_margin_millivolts), 0xc); + if(!C.eristaCpuUV) { + R_SKIP(); + } + PATCH_OFFSET(&(entry->dvco_calibration_max), 0x1C); + PATCH_OFFSET(&(entry->tune1_high), 0x10); + PATCH_OFFSET(&(entry->tune_high_margin_millivolts), 0xc); - switch(C.eristaCpuUV) { - case 1: - PATCH_OFFSET(&(entry->tune0_low), 0x0000FFFF); //process_id 0 // EOS UV1 - PATCH_OFFSET(&(entry->tune1_low), 0x027007FF); - break; - case 2: - PATCH_OFFSET(&(entry->tune0_low), 0x0000EFFF); //process_id 1 // EOS Uv2 - PATCH_OFFSET(&(entry->tune1_low), 0x027407FF); - break; - case 3: - PATCH_OFFSET(&(entry->tune0_low), 0x0000DFFF); //process_id 0 // EOS UV3 - PATCH_OFFSET(&(entry->tune1_low), 0x027807FF); - break; - case 4: - PATCH_OFFSET(&(entry->tune0_low), 0x0000DFDF); //process_id 1 // EOS Uv4 - PATCH_OFFSET(&(entry->tune1_low), 0x027A07FF); - break; - case 5: - PATCH_OFFSET(&(entry->tune0_low), 0x0000CFDF); // EOS UV5 - PATCH_OFFSET(&(entry->tune1_low), 0x037007FF); - break; - default: - break; + switch(C.eristaCpuUV) { + case 1: + PATCH_OFFSET(&(entry->tune0_low), 0x0000FFFF); //process_id 0 // EOS UV1 + PATCH_OFFSET(&(entry->tune1_low), 0x027007FF); + break; + case 2: + PATCH_OFFSET(&(entry->tune0_low), 0x0000EFFF); //process_id 1 // EOS Uv2 + PATCH_OFFSET(&(entry->tune1_low), 0x027407FF); + break; + case 3: + PATCH_OFFSET(&(entry->tune0_low), 0x0000DFFF); //process_id 0 // EOS UV3 + PATCH_OFFSET(&(entry->tune1_low), 0x027807FF); + break; + case 4: + PATCH_OFFSET(&(entry->tune0_low), 0x0000DFDF); //process_id 1 // EOS Uv4 + PATCH_OFFSET(&(entry->tune1_low), 0x027A07FF); + break; + case 5: + PATCH_OFFSET(&(entry->tune0_low), 0x0000CFDF); // EOS UV5 + PATCH_OFFSET(&(entry->tune1_low), 0x037007FF); + break; + default: + break; + } + R_SUCCEED(); +} + + Result GpuFreqMaxAsm(u32 *ptr32) { + // Check if both two instructions match the pattern + u32 ins1 = *ptr32, ins2 = *(ptr32 + 1); + if (!(asm_compare_no_rd(ins1, asm_pattern[0]) && asm_compare_no_rd(ins2, asm_pattern[1]))) + R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); + + // Both instructions should operate on the same register + u8 rd = asm_get_rd(ins1); + if (rd != asm_get_rd(ins2)) + R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); + + u32 max_clock; + switch (C.eristaGpuUV) { + case 0: + max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; + break; + case 1: + max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq; + break; + case 2: + max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableHigh)->freq; + break; + case 3: + if(C.enableEristaGpuUnsafeFreqs) { + max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableUv3UnsafeFreqs)->freq; + } else { + max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; + } + break; + default: + max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; + break; } + u32 asm_patch[2] = { + asm_set_rd(asm_set_imm16(asm_pattern[0], max_clock), rd), + asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd)}; + PATCH_OFFSET(ptr32, asm_patch[0]); + PATCH_OFFSET(ptr32 + 1, asm_patch[1]); + R_SUCCEED(); } - Result GpuFreqMaxAsm(u32 *ptr32) { - // Check if both two instructions match the pattern - u32 ins1 = *ptr32, ins2 = *(ptr32 + 1); - if (!(asm_compare_no_rd(ins1, asm_pattern[0]) && asm_compare_no_rd(ins2, asm_pattern[1]))) - R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); + Result GpuFreqPllLimit(u32 *ptr) { + clk_pll_param *entry = reinterpret_cast(ptr); - // Both instructions should operate on the same register - u8 rd = asm_get_rd(ins1); - if (rd != asm_get_rd(ins2)) - R_THROW(ldr::ResultInvalidGpuFreqMaxPattern()); + // All zero except for freq + for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) { + R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry()); + } - u32 max_clock; - switch (C.eristaGpuUV) { - case 0: - max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; - break; - case 1: - max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq; - break; - case 2: - max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableHigh)->freq; - break; - case 3: - if(C.enableEristaGpuUnsafeFreqs) { - max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTableUv3UnsafeFreqs)->freq; - } else { - max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; - } - break; - default: - max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq; - break; - } - u32 asm_patch[2] = { - asm_set_rd(asm_set_imm16(asm_pattern[0], max_clock), rd), - asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd)}; - PATCH_OFFSET(ptr32, asm_patch[0]); - PATCH_OFFSET(ptr32 + 1, asm_patch[1]); + // Double the max clk simply + u32 max_clk = entry->freq * 2; + entry->freq = max_clk; + R_SUCCEED(); + } - R_SUCCEED(); - } + void MemMtcTableAutoAdjust(EristaMtcTable *table) { + if (C.mtcConf != AUTO_ADJ) + return; - Result GpuFreqPllLimit(u32 *ptr) { - clk_pll_param *entry = reinterpret_cast(ptr); +#define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \ + TABLE->burst_regs.PARAM = VALUE; \ + TABLE->shadow_regs_ca_train.PARAM = VALUE; \ + TABLE->shadow_regs_quse_train.PARAM = VALUE; \ + TABLE->shadow_regs_rdwr_train.PARAM = VALUE; - // All zero except for freq - for (size_t i = 1; i < sizeof(clk_pll_param) / sizeof(u32); i++) { - R_UNLESS(*(ptr + i) == 0, ldr::ResultInvalidGpuPllEntry()); - } +#define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg)) - // Double the max clk simply - u32 max_clk = entry->freq * 2; - entry->freq = max_clk; - R_SUCCEED(); - } + WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); + WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); + WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); + WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); + WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); + WRITE_PARAM_ALL_REG(table, emc_r2p, GET_CYCLE_CEIL(tRTP)); + WRITE_PARAM_ALL_REG(table, emc_r2w, R2W); + WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); + WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); + WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); + WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); + WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); + WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); + WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); + WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tXP)); + WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tXP)); + WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); + WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); + WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tSR)); + WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); + WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); + WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); - void MemMtcTableAutoAdjust(EristaMtcTable *table) { - if (C.mtcConf != AUTO_ADJ) - return; +#define WRITE_PARAM_BURST_MC_REG(TABLE, PARAM, VALUE) TABLE->burst_mc_regs.PARAM = VALUE; - #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \ - TABLE->burst_regs.PARAM = VALUE; \ - TABLE->shadow_regs_ca_train.PARAM = VALUE; \ - TABLE->shadow_regs_quse_train.PARAM = VALUE; \ - TABLE->shadow_regs_rdwr_train.PARAM = VALUE; + constexpr u32 MC_ARB_DIV = 4; + constexpr u32 MC_ARB_SFA = 2; + table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; + table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA; + table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1; + table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2; + table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1; + table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1; + //table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV); + //table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); + // table->burst_mc_regs.mc_emem_arb_timing_r2r = CEIL(table->burst_regs.emc_rext / MC_ARB_DIV) - 1 + MC_ARB_SFA; + // table->burst_mc_regs.mc_emem_arb_timing_w2w = CEIL(table->burst_regs.emc_wext / MC_ARB_DIV) - 1 + MC_ARB_SFA; +// table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(R2W / MC_ARB_DIV) - 1 + MC_ARB_SFA; +// table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; + table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV); + // table->burst_mc_regs.mc_emem_arb_timing_ccdmw = CEIL(tCCDMW / MC_ARB_DIV) -1 + MC_ARB_SFA; + } - #define GET_CYCLE_CEIL(PARAM) u32(CEIL(double(PARAM) / tCK_avg)) + Result MemFreqMtcTable(u32 *ptr) { + u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800}; + u32 khz_list_size = sizeof(khz_list) / sizeof(u32); - WRITE_PARAM_ALL_REG(table, emc_rc, GET_CYCLE_CEIL(tRC)); - WRITE_PARAM_ALL_REG(table, emc_rfc, GET_CYCLE_CEIL(tRFCab)); - WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb)); - WRITE_PARAM_ALL_REG(table, emc_ras, GET_CYCLE_CEIL(tRAS)); - WRITE_PARAM_ALL_REG(table, emc_rp, GET_CYCLE_CEIL(tRPpb)); - WRITE_PARAM_ALL_REG(table, emc_r2p, GET_CYCLE_CEIL(tRTP)); - WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); - WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); - WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD)); - WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); - WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); - WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tXP)); - WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tXP)); - WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); - WRITE_PARAM_ALL_REG(table, emc_txsrdll, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); - WRITE_PARAM_ALL_REG(table, emc_tckesr, GET_CYCLE_CEIL(tSR)); - WRITE_PARAM_ALL_REG(table, emc_tfaw, GET_CYCLE_CEIL(tFAW)); - WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); - WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); + // Generate list for mtc table pointers + EristaMtcTable *table_list[khz_list_size]; + for (u32 i = 0; i < khz_list_size; i++) { + u8 *table = reinterpret_cast(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable); + table_list[i] = reinterpret_cast(table); + R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable()); + R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable()); + } - #define WRITE_PARAM_BURST_MC_REG(TABLE, PARAM, VALUE) TABLE->burst_mc_regs.PARAM = VALUE; + if (C.eristaEmcMaxClock <= EmcClkOSLimit) + R_SKIP(); - constexpr u32 MC_ARB_DIV = 4; - constexpr u32 MC_ARB_SFA = 2; - table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; - table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1 + MC_ARB_SFA; - table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1; - table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2; - table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1; - table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1; - //table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(GET_CYCLE_CEIL(tRTP) / MC_ARB_DIV); - //table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(WTP / MC_ARB_DIV); - // table->burst_mc_regs.mc_emem_arb_timing_r2r = CEIL(table->burst_regs.emc_rext / MC_ARB_DIV) - 1 + MC_ARB_SFA; - // table->burst_mc_regs.mc_emem_arb_timing_w2w = CEIL(table->burst_regs.emc_wext / MC_ARB_DIV) - 1 + MC_ARB_SFA; - // table->burst_mc_regs.mc_emem_arb_timing_r2w = CEIL(R2W / MC_ARB_DIV) - 1 + MC_ARB_SFA; - // table->burst_mc_regs.mc_emem_arb_timing_w2r = CEIL(W2R / MC_ARB_DIV) - 1 + MC_ARB_SFA; - table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV); - // table->burst_mc_regs.mc_emem_arb_timing_ccdmw = CEIL(tCCDMW / MC_ARB_DIV) -1 + MC_ARB_SFA; - } + // Make room for new mtc table, discarding useless 40.8 MHz table + // 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0] not overwritten + for (u32 i = khz_list_size - 1; i > 0; i--) + std::memcpy(static_cast(table_list[i]), static_cast(table_list[i - 1]), sizeof(EristaMtcTable)); - Result MemFreqMtcTable(u32 *ptr) { - u32 khz_list[] = {1600000, 1331200, 1065600, 800000, 665600, 408000, 204000, 102000, 68000, 40800}; - u32 khz_list_size = sizeof(khz_list) / sizeof(u32); + MemMtcTableAutoAdjust(table_list[0]); + PATCH_OFFSET(ptr, C.eristaEmcMaxClock); - // Generate list for mtc table pointers - EristaMtcTable *table_list[khz_list_size]; - for (u32 i = 0; i < khz_list_size; i++) { - u8 *table = reinterpret_cast(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable); - table_list[i] = reinterpret_cast(table); - R_UNLESS(table_list[i]->rate_khz == khz_list[i], ldr::ResultInvalidMtcTable()); - R_UNLESS(table_list[i]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable()); - } + // Handle customize table replacement + // if (C.mtcConf == CUSTOMIZED_ALL) { + // MemMtcCustomizeTable(table_list[0], const_cast(C.eristaMtcTable)); + //} - if (C.eristaEmcMaxClock <= EmcClkOSLimit) - R_SKIP(); + R_SUCCEED(); + } - // Make room for new mtc table, discarding useless 40.8 MHz table - // 40800 overwritten by 68000, ..., 1331200 overwritten by 1600000, leaving table_list[0] not overwritten - for (u32 i = khz_list_size - 1; i > 0; i--) - std::memcpy(static_cast(table_list[i]), static_cast(table_list[i - 1]), sizeof(EristaMtcTable)); + Result MemFreqMax(u32 *ptr) { + if (C.eristaEmcMaxClock <= EmcClkOSLimit) + R_SKIP(); - MemMtcTableAutoAdjust(table_list[0]); - PATCH_OFFSET(ptr, C.eristaEmcMaxClock); + PATCH_OFFSET(ptr, C.eristaEmcMaxClock); - // Handle customize table replacement - // if (C.mtcConf == CUSTOMIZED_ALL) { - // MemMtcCustomizeTable(table_list[0], const_cast(C.eristaMtcTable)); - //} + R_SUCCEED(); + } - R_SUCCEED(); - } + void Patch(uintptr_t mapped_nso, size_t nso_size) { + u32 CpuCvbDefaultMaxFreq = static_cast(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq); + u32 GpuCvbDefaultMaxFreq = static_cast(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq); - Result MemFreqMax(u32 *ptr) { - if (C.eristaEmcMaxClock <= EmcClkOSLimit) - R_SKIP(); + PatcherEntry patches[] = { + {"CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit }, + {"CPU Freq Table", CpuFreqCvbTable, 1, nullptr, CpuCvbDefaultMaxFreq}, + {"CPU Volt Limit", &CpuVoltRange, 13, nullptr, CpuVoltOfficial }, + {"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF }, + {"GPU Freq Table", GpuFreqCvbTable, 1, nullptr, GpuCvbDefaultMaxFreq}, + {"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn}, + {"GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit}, + {"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit}, + {"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit}, + {"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit}, + {"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS}, + {"GPU Vmin", &GpuVmin, 0, nullptr, gpuVmin}, + }; - PATCH_OFFSET(ptr, C.eristaEmcMaxClock); + for (uintptr_t ptr = mapped_nso; + ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); + ptr += sizeof(u32)) { + u32 *ptr32 = reinterpret_cast(ptr); + for (auto &entry : patches) { + if (R_SUCCEEDED(entry.SearchAndApply(ptr32))) + break; + } + } - R_SUCCEED(); - } + for (auto &entry : patches) { + LOGGING("%s Count: %zu", entry.description, entry.patched_count); + if (R_FAILED(entry.CheckResult())) + CRASH(entry.description); + } + } - void Patch(uintptr_t mapped_nso, size_t nso_size) { - u32 CpuCvbDefaultMaxFreq = static_cast(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq); - u32 GpuCvbDefaultMaxFreq = static_cast(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq); - - PatcherEntry patches[] = { - {"CPU Freq Vdd", &CpuFreqVdd, 1, nullptr, CpuClkOSLimit }, - {"CPU Freq Table", CpuFreqCvbTable, 1, nullptr, CpuCvbDefaultMaxFreq}, - {"CPU Volt Limit", &CpuVoltRange, 13, nullptr, CpuVoltOfficial }, - {"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF }, - {"GPU Freq Table", GpuFreqCvbTable, 1, nullptr, GpuCvbDefaultMaxFreq}, - {"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn}, - {"GPU Freq PLL", &GpuFreqPllLimit, 1, nullptr, GpuClkPllLimit}, - {"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit}, - {"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit}, - {"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit}, - {"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS}, - {"GPU Vmin", &GpuVmin, 0, nullptr, gpuVmin}, - }; - - for (uintptr_t ptr = mapped_nso; - ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); - ptr += sizeof(u32)) { - u32 *ptr32 = reinterpret_cast(ptr); - for (auto &entry : patches) { - if (R_SUCCEEDED(entry.SearchAndApply(ptr32))) - break; - } - } - - for (auto &entry : patches) { - LOGGING("%s Count: %zu", entry.description, entry.patched_count); - if (R_FAILED(entry.CheckResult())) - CRASH(entry.description); - } - } - - } +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp index 048eba6a..06d1f832 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -272,10 +272,14 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table) { WRITE_PARAM_ALL_REG(table, emc_refresh, REFRESH); WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, REFRESH / 4); - /* Do not patch on micron. */ + WRITE_PARAM_ALL_REG(table, emc_r2w, R2W); + WRITE_PARAM_ALL_REG(table, emc_w2r, W2R); + WRITE_PARAM_ALL_REG(table, emc_w2p, WTP); + + /* May or may not have to be patched in Micron; let's skip for now. */ if (!IsMicron()) { - WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tXP)); // NOT on micron - WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tXP)); // NOT on micron + WRITE_PARAM_ALL_REG(table, emc_pdex2wr, GET_CYCLE_CEIL(tXP)); + WRITE_PARAM_ALL_REG(table, emc_pdex2rd, GET_CYCLE_CEIL(tXP)); } WRITE_PARAM_ALL_REG(table, emc_txsr, MIN(GET_CYCLE_CEIL(tXSR), (u32)0x3fe)); @@ -285,6 +289,7 @@ void MemMtcTableAutoAdjust(MarikoMtcTable* table) { WRITE_PARAM_ALL_REG(table, emc_trpab, GET_CYCLE_CEIL(tRPab)); WRITE_PARAM_ALL_REG(table, emc_trefbw, REFBW); + /* Worth replacing with l4t dumps at some point. */ // Burst MC Regs #define WRITE_PARAM_BURST_MC_REG(TABLE, PARAM, VALUE) TABLE->burst_mc_regs.PARAM = VALUE;